From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-yh0-x233.google.com (mail-yh0-x233.google.com [IPv6:2607:f8b0:4002:c01::233]) (using TLSv1 with cipher RC4-SHA (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by huchra.bufferbloat.net (Postfix) with ESMTPS id 0335C21F224 for ; Mon, 24 Mar 2014 13:27:58 -0700 (PDT) Received: by mail-yh0-f51.google.com with SMTP id f10so5729743yha.10 for ; Mon, 24 Mar 2014 13:27:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type; bh=WQN9IV3NS0letnWV/rAc2SQ6i4hZuh/Fs9aqwY12YuU=; b=h9Fh9pZsKjlKzg6YCWfAsy98SL+pEACj4LztwE3iYP3NGQI9IW981RxVdJrMYcheit hB4t4X8DF378GOHJ5167rJN7T5fEAVKtfW4Cwsm15JteFBgUs9rzfSU4rmXYJryfQ5rU ZJmauYUeBpnwft42eExHbaTU0lpEKEFxzc8mMlPVN94GCc6zZ6Ixqi3BR+QbzidDS6BQ tU7NnBf53tZtzvyORqamE0Uw6LcITL9CxF5ZJPSmt4/RbRDrv8u7rPdBsw6SxdbtoSeg oKie9jWnqsE/aDD3y6+vQbXGrFg8mIUEpg8wnOWb97IJ9yZ+8soJ1Ll0ndzI/ParIdgp K55A== X-Received: by 10.236.26.72 with SMTP id b48mr62145892yha.59.1395692877801; Mon, 24 Mar 2014 13:27:57 -0700 (PDT) MIME-Version: 1.0 Received: by 10.170.47.78 with HTTP; Mon, 24 Mar 2014 13:27:37 -0700 (PDT) In-Reply-To: <20140324191203.GA78098@redoubt.spodhuis.org> References: <20140324191203.GA78098@redoubt.spodhuis.org> From: David Personette Date: Mon, 24 Mar 2014 16:27:37 -0400 Message-ID: To: Joseph Swick , "cerowrt-devel@lists.bufferbloat.net" Content-Type: multipart/alternative; boundary=089e01495296326e8104f56012ed Subject: Re: [Cerowrt-devel] DNSSEC & NTP Bootstrapping X-BeenThere: cerowrt-devel@lists.bufferbloat.net X-Mailman-Version: 2.1.13 Precedence: list List-Id: Development issues regarding the cerowrt test router project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 24 Mar 2014 20:27:59 -0000 --089e01495296326e8104f56012ed Content-Type: text/plain; charset=UTF-8 Phil, With the exception of the extra dependencies (dig and python), I like this. I would suggest that if DNSSEC will be enabled, that nslookup (I think that's the only command line resolver included by CeroWRT/OpenWRT base installs) be extended to have a similar option as dig, to resolve without DNSSEC. The only other issue I see is if the router is brought online before internet access is available. If I read your code correctly, it will try 4 times per defined server (with and without DNSSEC for IPv4 and IPv6), then exit. It either needs to keep trying until it succeeds, or be called every time a connection comes up (shutting down NTPd prior and restarting after). Thanks. -- David P. On Mon, Mar 24, 2014 at 3:12 PM, Phil Pennock < cerowrt-devel+phil@spodhuis.org> wrote: > On 2014-03-21 at 23:33 -0400, Joseph Swick wrote: > > I've been lurking for several months now on the list and I remember some > > discussion about trying to find acceptable methods for bootstrapping the > > local system time so that DNSSEC would work. > > I raised this on the ntp-pool mailing-lists last year, looking for a > solution because of the chicken/egg bootstrap, with suggested approaches > and some trial scripts. Eg: > > http://lists.ntp.org/pipermail/pool/2013-July/006569.html > > For context, I'm currently running OpenWRT; attached is the > /etc/init.d/ntpdate which I'm using. It relies upon having Python and > dig installed, as I haven't gotten around to building a small C utility > to do just this task, but perhaps the approach is useful enough that > someone else might do so? > > In summary: if the current time is less than the timestamp on the > unbound-maintained copy of the root zone trust anchors, then bump the > time up at least that far, because we must be at >= that timestamp, and > this increases the odds that DNSSEC will validate if we haven't been > off-line for too long. > > Then, for each hostname in the $STEP_SERVERS list (which could be > taken from ntp.conf or uci config or whatever, but here is just > hardcoded), I try to resolve IPv4 then IPv6, first with DNSSEC left > enabled, and then with DNSSEC disabled via `dig +cd`. The first dig > command to return results is the one which is used. > > The idea is to minimize the potential vulnerability of syncing to a bad > timesource, by using DNSSEC if it's available and works, after making > sure it has a reasonable chance of working if we've just rebooted, and > only if we've been off-line for some time do we fall back to insecure > DNS. > > Make sure that the START value is appropriate for your systems; I've > found the OpenWRT defaults to be sufficiently broken that I stomp on > them on reinstall. I run ntpdate once the network and firewall are up, > but just before ntpd and both of those well before other network > services which might depend upon time. > > Regards, > -Phil > > #!/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 > } > > _______________________________________________ > Cerowrt-devel mailing list > Cerowrt-devel@lists.bufferbloat.net > https://lists.bufferbloat.net/listinfo/cerowrt-devel > > --089e01495296326e8104f56012ed Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
Phil,

With the exception of th= e extra dependencies (dig and python), I like this. I would suggest that if= DNSSEC will be enabled, that nslookup (I think that's the only command= line resolver included by CeroWRT/OpenWRT base installs) be extended to ha= ve a similar option as dig, to resolve without DNSSEC.

The only other issue I see is if the router is brought online bef= ore internet access is available. If I read your code correctly, it will tr= y 4 times per defined server (with and without DNSSEC for IPv4 and IPv6), t= hen exit. It either needs to keep trying until it succeeds, or be called ev= ery time a connection comes up (shutting down NTPd prior and restarting aft= er).

Thanks.
--
David P.



On Mon, Mar 24, 2014 at 3:12 PM, Phi= l Pennock <cerowrt-devel+phil@spodhuis.org> wr= ote:
On 2014-03-21 at 23:33 -0400= , Joseph Swick wrote:
> I've been lurking for several months now on the list and I remembe= r some
> discussion about trying to find acceptable methods for bootstrapping t= he
> local system time so that DNSSEC would work.

I raised this on the ntp-pool mailing-lists last year, looking for a<= br> solution because of the chicken/egg bootstrap, with suggested approaches and some trial scripts. =C2=A0Eg:

=C2=A0 http://lists.ntp.org/pipermail/pool/2013-July/006569.ht= ml

For context, I'm currently running OpenWRT; attached is the
/etc/init.d/ntpdate which I'm using. =C2=A0It relies upon having Python= and
dig installed, as I haven't gotten around to building a small C utility=
to do just this task, but perhaps the approach is useful enough that
someone else might do so?

In summary: if the current time is less than the timestamp on the
unbound-maintained copy of the root zone trust anchors, then bump the
time up at least that far, because we must be at >=3D that timestamp, an= d
this increases the odds that DNSSEC will validate if we haven't been off-line for too long.

Then, for each hostname in the $STEP_SERVERS list (which could be
taken from ntp.conf or uci config or whatever, but here is just
hardcoded), I try to resolve IPv4 then IPv6, first with DNSSEC left
enabled, and then with DNSSEC disabled via `dig +cd`. =C2=A0The first dig command to return results is the one which is used.

The idea is to minimize the potential vulnerability of syncing to a bad
timesource, by using DNSSEC if it's available and works, after making sure it has a reasonable chance of working if we've just rebooted, and<= br> only if we've been off-line for some time do we fall back to insecure DNS.

Make sure that the START value is appropriate for your systems; I've found the OpenWRT defaults to be sufficiently broken that I stomp on
them on reinstall. =C2=A0I run ntpdate once the network and firewall are up= ,
but just before ntpd and both of those well before other network
services which might depend upon time.

Regards,
-Phil

#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2008 OpenWrt.org
# Copyright (C) 2013 Phil Pennock

START=3D60

STEP_SERVERS=3D"0.openwrt.pool.ntp.org 1.openwrt.pool.ntp.org 2.openwrt.pool.ntp.org"
TIMEOUT=3D"2" # in seconds
PRESEED_TIMESTAMP_FN=3D"/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 tim= e
# to be able to resolve DNS.
#
# We break out of this "Catch 22" situation by _trying_ normal DN= S resolution,
# IPv4 and then IPv6, and only if those fail do we forcibly disable DNSSEC<= br> # by using dig(1)'s +cd flag ("checking disabled"); trying no= rmally 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. =C2=A0There is a DoS+hijack attack p= ath
# 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.<= br> # Unbound updates the file on every refresh, so it's not too far off.
preseed_approximate_time() {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # Unfortunately, date(1) on OpenWRT can't p= arse the timestamp
=C2=A0 =C2=A0 =C2=A0 =C2=A0 # output from ls.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 python -c '
import os, time, sys
fn=3Dsys.argv[1]
min_time=3Dos.stat(fn).st_ctime
if time.time() < min_time:
=C2=A0 want=3Dtime.strftime("%Y%m%d%H%M.%S", time.gmtime(min_time= ))
=C2=A0 os.system("date -u -s %s" % want)' "$PRESEED_TIME= STAMP_FN" > /dev/null
}

resolve_hostname_v4() {
# we use the grep both to filter out cname referrals and to detect empty # results
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local hn=3D"$1"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 shift
=C2=A0 =C2=A0 =C2=A0 =C2=A0 dig +nodnssec +short "$@" -t a "= $hn" | grep '^[0-9][0-9.]*$'
}

resolve_hostname_v6() {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local hn=3D"$1"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 shift
=C2=A0 =C2=A0 =C2=A0 =C2=A0 dig +nodnssec +short "$@" -t aaaa &qu= ot;$hn" | grep -i '^[0-9a-f][0-9a-f.:]*$'
}

resolve_one_server() {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local hn=3D"$1"
=C2=A0 =C2=A0 =C2=A0 =C2=A0 resolve_hostname_v4 $hn && return
=C2=A0 =C2=A0 =C2=A0 =C2=A0 resolve_hostname_v6 $hn && return
=C2=A0 =C2=A0 =C2=A0 =C2=A0 resolve_hostname_v4 $hn +cd && return =C2=A0 =C2=A0 =C2=A0 =C2=A0 resolve_hostname_v6 $hn +cd && return }

resolve_step_servers() {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 local server ips
=C2=A0 =C2=A0 =C2=A0 =C2=A0 for server in $STEP_SERVERS ; do
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 resolve_one_server = $server
=C2=A0 =C2=A0 =C2=A0 =C2=A0 done
}

start() {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 preseed_approximate_time
=C2=A0 =C2=A0 =C2=A0 =C2=A0 for s in $(resolve_step_servers) ; do
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /usr/sbin/ntpdate -= s -b -u -t "$TIMEOUT" "$s" && break
=C2=A0 =C2=A0 =C2=A0 =C2=A0 done
}

_______________________________________________
Cerowrt-devel mailing list
Cerowrt-devel@lists.= bufferbloat.net
https://lists.bufferbloat.net/listinfo/cerowrt-devel


--089e01495296326e8104f56012ed--