#!/bin/sh /etc/rc.common # Copyright (C) 2006-2008 OpenWrt.org # Copyright (C) 2013 Phil Pennock START=60 STEP_SERVERS="0.openwrt.pool.ntp.org 1.openwrt.pool.ntp.org 2.openwrt.pool.ntp.org" TIMEOUT="2" # in seconds PRESEED_TIMESTAMP_FN="/etc/unbound/runtime/root.autokey" # The core problem is that with DNSSEC, an invalid time prevents resolution # of DNS, but we need DNS to be able to find time-servers to get a good time # to be able to resolve DNS. # # We break out of this "Catch 22" situation by _trying_ normal DNS resolution, # IPv4 and then IPv6, and only if those fail do we forcibly disable DNSSEC # by using dig(1)'s +cd flag ("checking disabled"); trying normally first # protects us against malicious DNS trying to point us to bad time-servers, # if we've enough state that we _should_ already be protected. # # The "insecure" approach we regress to, as a last resort, is the same way # the Internet functioned for decades. There is a DoS+hijack attack path # here, but if we don't have a good battery-backed clock to protect us, we # don't have a better solution. # Also, per a suggestion from Doug Calvert, we can use the timestamp of # modification of the unbound root.key file itself as an approximate time. # Unbound updates the file on every refresh, so it's not too far off. preseed_approximate_time() { # Unfortunately, date(1) on OpenWRT can't parse the timestamp # output from ls. python -c ' import os, time, sys fn=sys.argv[1] min_time=os.stat(fn).st_ctime if time.time() < min_time: want=time.strftime("%Y%m%d%H%M.%S", time.gmtime(min_time)) os.system("date -u -s %s" % want)' "$PRESEED_TIMESTAMP_FN" > /dev/null } resolve_hostname_v4() { # we use the grep both to filter out cname referrals and to detect empty # results local hn="$1" shift dig +nodnssec +short "$@" -t a "$hn" | grep '^[0-9][0-9.]*$' } resolve_hostname_v6() { local hn="$1" shift dig +nodnssec +short "$@" -t aaaa "$hn" | grep -i '^[0-9a-f][0-9a-f.:]*$' } resolve_one_server() { local hn="$1" resolve_hostname_v4 $hn && return resolve_hostname_v6 $hn && return resolve_hostname_v4 $hn +cd && return resolve_hostname_v6 $hn +cd && return } resolve_step_servers() { local server ips for server in $STEP_SERVERS ; do resolve_one_server $server done } start() { preseed_approximate_time for s in $(resolve_step_servers) ; do /usr/sbin/ntpdate -s -b -u -t "$TIMEOUT" "$s" && break done }