IPv6 addresses not available at boot

One of things that’s always bugged me regarding Linux and IPv6 is the
behaviour that’s exhibited during boot time. Specifically, the short delay before IPv6 addresses transition from their “tentative” state on an interface to being fully available for use by various daemons and services. With IPv4, you can be pretty much guaranteed that you can bind to any of the configured addresses at boot time, under normal circumstances.

With IPv6 on Linux, things aren’t so straightforward. Duplicate Address Detection (DAD), which basically does what it says on the tin, introduces a short delay before addresses are fully configured, the address has been added to the network interface, but not really.

I recently came across this whilst attempting to get BIND to listen on some secondary service addresses on a particular machine. BIND would not er, bind, to the IPv6 addresses at boot, failing with messages like this:

bind9 could not listen on UDP socket: address not available

Modifying /etc/init.d/bind9 to print the output of “ip addr show” to a file at the time BIND attempted to start up showed the tell-tale “tentative” flag on each IPv6 address being added to eth0. Since the addresses are in this state, BIND or other daemons will refuse to listen on them.

The problem has become very noticeable since parallel boot systems such as Upstart have become the default in quite a few Linux distros. Daemons will often fire up before the network is fully ready and in some extreme cases network filesystems that reference hostnames may fail to mount if you are using an IPv6 DNS resolver. Of course this isn’t the case across the board, some daemons and services appear to handle the unavailability of an IPv6 address somewhat gracefully, backing off and trying again a short time later rather than simply giving up on the first go.

Anyway, a simple “hairy hack” to get over this problem is to add something like the following to your startup script:

sleep 5

Yes, a one line sleep command to make the daemon wait a short while before actually starting. This seems to ensure that the IPv6 address has moved out of the tentative state, but it’s still somewhat silly..

First steps towards DNSSEC

I recently began deploying DNSSEC within HEAnet. Things are at an early stage, but I’m hoping to have some signed zones up and running in the next few months.

For testing, I wanted to find a practical application of DNSSEC, rather than simply stating “now our zones are secure against attack A, B and C”.

RFC4255 provides exactly this, with automatic verification and trusting of SSH host keys through a combination of the SSHFP record type and DNSSEC validation. This removes the need to maintain a known_hosts file on each client, key fingerprints can simply be distributed through DNS.

I started by generating our zone signing key (ZSK) and key signing key (KSK) for the secure zone, login.heanet.ie. These are 1024bit RSASHA1 keypairs.

 mkdir /etc/bind/keys
 cd !$
 dnssec-keygen -r /dev/random -a RSASHA1 \
  -b 1024 -n ZONE login.heanet.ie
 dnssec-keygen -r /dev/random -f KSK \ 
  -a RSASHA1 -b 1024 -n ZONE login.heanet.ie

Then, I imported the trust anchor (KSK public part) for the zone into the DNS resolver. We are using Unbound but BIND etc. configuration is somewhat similar.

cp Klogin.heanet.ie.+005+61342.key /etc/unbound/anchors/login.heanet.ie.anchor
vi /etc/unbound/unbound.conf
# login.heanet.ie test signed zone - robertg@heanet.ie 20090309
trust-anchor-file: "/etc/unbound/anchors/login.heanet.ie.anchor"

To prepare the zone for signing, I published the ZSK and KSK public keys at the apex of the zone, ie: after NS records but before any other records are defined.

@                       IN      NS      ns.heanet.ie.

; DNSSEC public keys
$INCLUDE                /etc/bind/keys/Klogin.heanet.ie.+005+01530.key  ;ZSK
$INCLUDE                /etc/bind/keys/Klogin.heanet.ie.+005+61342.key  ;KSK

; hosts
charlene                IN      A
charlene                IN      AAAA    2001:770:18:2::
charlene                IN      SSHFP   1 1 d343493a92fdd26281dddc26e90440e5504c3b1a
charlene                IN      SSHFP   2 1 4fad90afa04a6b62371091662f88685822b07ebb

Now, to actually sign the zone! I signed the RRsets in the zone with dnssec-signzone and the ZSK and KSK keypairs we generated earlier. This produces a signed version of the zonefile, of the form zonefile.signed. The KSK (61342) is used to sign the keys we entered at the apex of the zone earlier, and the ZSK (01530) is used to sign all the other records in the zone.

dnssec-signzone -r /dev/random -o login.heanet.ie \
-k /etc/bind/keys/Klogin.heanet.ie.+005+61342.key \
login.heanet.ie /etc/bind/keys/Klogin.heanet.ie.+005+01530.key

Then, I loaded the .signed file into the authoritative nameserver.

zone "login.heanet.ie" {
        type master;
        file "pz/forward/login.heanet.ie.signed";

After doing this, it’s a good idea to check for any errors in name server log.

As a first test, I made a DNSSEC query to the resolvers. It should follow the chain of trust and securely resolve the query. The “ad” – authenticated data – flag in the flags: section of the dig output confirms that the zone data is signed and has been verified as authentic. The +dnssec option sets the DO (DNSSEC OK) bit on the query and the +multiline option is simply used for readability purposes.

dig @resolver0.heanet.ie charlene.login.heanet.ie +dnssec +multiline

; <<>> DiG 9.5.0-P2 <<>> @resolver0.heanet.ie charlene.login.heanet.ie +dnssec +multiline
; (2 servers found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42200
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 1

; EDNS: version: 0, flags: do; udp: 4096
;charlene.login.heanet.ie. IN A

charlene.login.heanet.ie. 3600 IN A
charlene.login.heanet.ie. 3600 IN RRSIG	A 5 4 3600 20090429144034 (
				20090330144034 1530 login.heanet.ie.
				P8FyONy88cyy5OqTattjzz8bBtMevZo4wN/KfQs= )

login.heanet.ie.	3600 IN	NS ns.heanet.ie.
login.heanet.ie.	3600 IN	RRSIG NS 5 3 3600 20090429144034 (
				20090330144034 1530 login.heanet.ie.
				rw/ZgOrVkBnWiGYNRe4BWtIhkHbcVYZ6roWXlo8= )

;; Query time: 2 msec
;; SERVER: 2001:770:f8::c101:ba02#53(2001:770:f8::c101:ba02)
;; WHEN: Wed Apr  1 17:07:12 2009
;; MSG SIZE  rcvd: 436

Now to test the signed SSHFP records. On the client, I added the following to resolv.conf.

options edns0

Also, I edited ~/.ssh/config and added this line in the Host section

VerifyHostKeyDNS yes

When ssh'ing to a the machine with signed SSHFP records, the user should not be prompted to accept the host key, even if it is "unknown".

ssh -v heanet@charlene.login.heanet.ie
OpenSSH_5.1, OpenSSL 0.9.7j 04 May 2006
debug1: found 2 secure fingerprints in DNS
debug1: matching host key fingerprint found in DNS
debug1: ssh_rsa_verify: signature correct  

Presto! No known_hosts file. Profit! etc.. No need to maintain host keys across multiple clients, simply distribute your SSH fingerprints through DNS.

$ ls -al /home/rob/.ssh/                                                       
total 16
drwx------  2 rob  users  512 Mar 31 14:35 .
drwxr-xr-x  3 rob  users  512 Mar 31 14:15 ..
-rw-------  1 rob  users  613 Mar 31 17:23 authorized_keys
-rw-r--r--  1 rob  users  120 Mar 31 14:35 config

Of course there are a number of issues. I haven't gone through the required key rollover and resigning processes, however these are reasonably straightforward and can be automated with freely available tools.

Wireless Death Star

OK this thing is a bit mad. If it’s real that is..



It’s called the Slurpr and it’s capable of combining up to six wireless networks into a single channel, effectively giving you one phat connection that hoses any open wireless in the vicinity. Of course these have to be unsecured networks – but the Slupr’s 266mhz processor and onboard memory opens up the possibility of cracking encryption such as WEP on the fly. Badass.

The BBC would love this.