#!/bin/sh

status() { echo "[$(date)]" "$@"; }
warning() { status "$@" 1>&2; }
fail() { warning "$@"; exit 1; }

exec >>"/tmp/resolv.log" 2>&1

# This needs to point to a DNS server that blocks "roku.com" domains.
# Without this, system firmware updates (or even sneaky channel updates)
# can disable the persistent root jailbreak.
CUSTOM_DNS="dns.rootmyroku.com"

# Lock down the /tmp/resolv.conf file before anything else can modify it.
# This file is automatically generated once we connect to a network,
# but the process that handles it runs as the app user.
# By setting the ownership to root and disabling writes, we can prevent
# the application from overwriting our DNS settings.
touch "/tmp/resolv.conf"
chown root:root "/tmp/resolv.conf"
chmod 644 "/tmp/resolv.conf"

# If we have a `resolv.conf` saved from a previous boot,
# restore it while we check for an updated IP address.
if [[ -s "/nvram/resolv.conf" ]]; then
    last_resolv=$(cat "/nvram/resolv.conf")
    cp "/nvram/resolv.conf" "/tmp/resolv.conf"
    status "Restored previous DNS settings:"
    cat "/tmp/resolv.conf"
    ls -al "/tmp/resolv.conf"
    chown root:root "/tmp/resolv.conf"
    chmod 644 "/tmp/resolv.conf"
else
    last_resolv=""
fi

# In a perfect world we'd be able to put our custom DNS server's
# DNS name into /etc/resolv.conf and have it magically work.
# Instead, we'll ask a known-good DNS server the IP address of
# our custom DNS server so we can use that instead.
failing=0
while :; do
    if ! resp=$(nslookup "${CUSTOM_DNS}" "1.1.1.1"); then
        # This has a short retry delay so don't spam the logs.
        if [[ "${failing}" -ne 1 ]]; then
            warning "Failed to resolve ${CUSTOM_DNS}"
            failing=1
        fi
        sleep 3
        continue
    fi
    failing=0

    resolv=$(
        echo "${resp}" | sed -n '/^Name/,$p' | awk '/^Address/ { print "nameserver " $3; }'
    )
    if [[ -z "${resolv}" ]]; then
        warning "Resolved ${CUSTOM_DNS}, but found no addresses"
        sleep $(( 10 + RANDOM % 30 ))
        continue
    fi

    if [[ "${resolv}" != "${last_resolv}" ]]; then
        echo "${resolv}" > "/tmp/resolv.conf"
        cp "/tmp/resolv.conf" "/nvram/resolv.conf"
        last_resolv="${resolv}"

        status "DNS settings updated:"
        cat "/tmp/resolv.conf"
    fi

    # Network condition changes can cause the resolv.conf file to be reset.
    # Monitor the file to ensure the contents don't revert.
    delay=$(( 300 + RANDOM % 600 ))
    while [[ "${delay}" -gt 0 ]]; do
      if [[ "$(cat /tmp/resolv.conf)" != "${resolv}" ]]; then
          status "Refreshing resolv.conf"
          echo "${resolv}" > "/tmp/resolv.conf"
      fi
      sleep 3
      delay=$(( delay - 3 ))
    done
done
