Validation…

Following on from my post about the new key being added to the zone, the required 30 days have passed and if your resolver is RFC5011 compliant, it should now trust the key.

You can check this as follows:

BIND

$ cat /var/named/managed-keys.bind
$ORIGIN .
$TTL 0  ; 0 seconds
@                       IN SOA  . . (
                                1904       ; serial
                                0          ; refresh (0 seconds)
                                0          ; retry (0 seconds)
                                0          ; expire (0 seconds)
                                0          ; minimum (0 seconds)
                                )
                        KEYDATA 20170425142612 20170210095625 19700101000000 257 3 8 (
                                AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQ
                                bSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh
                                /RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWA
                                JQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXp
                                oY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3
                                LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGO
                                Yl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGc
                                LmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=
                                ) ; KSK; alg = RSASHA256; key id = 19036
                                ; next refresh: Tue, 25 Apr 2017 14:26:12 GMT
                                ; trusted since: Fri, 10 Feb 2017 09:56:25 GMT
2017-03-12.automated-ksk-test.research.icann.org KEYDATA 20170424152612 20170317172529 19700101000000 257 3 8 (
                                AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWL
                                hE4VxSEIBz9IuCA4w4ssSrClZ59seNc76ltDFcKJv3X9
                                jDjzRtBLjenIgV4n/3GpKrAAnRlYbUtpBEdlk4mxoL3B
                                lX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/eePc9HpZb
                                WxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0
                                tfG2YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1h8I
                                Yo0PF98vqjAp3NVRZvKKdgyF/bZ/iJtAZFytXvXU6Gwa
                                5tOm1wgP6wuKupscP8KHBluZyOSKw4RMTk6YBdE=
                                ) ; KSK; alg = RSASHA256; key id = 3934
                                ; next refresh: Mon, 24 Apr 2017 15:26:12 GMT
                                ; trusted since: Fri, 17 Mar 2017 17:25:29 GMT
                        KEYDATA 20170424152612 20170418002534 19700101000000 257 3 8 (
                                AwEAAfUtjasCuLysD4MbjG3v4Kyu0vvVJ/0cIreP6flt
                                MeZmwQ5SRta/mB+eFVjau+6YKra2UeTKxojBovHH2lZr
                                w7NNejL44/Xps4gR3LSVMnCdwras+yvj4en64ghRGWYO
                                uB+Icb0AqrCUhLFWR8yx41UkfaA2vzFnM2xTx0N0+o6R
                                6UciWuwJResomQupOjNUy2ZAi81Y3pb0x3Lw4POjpcSJ
                                zrK4aZ/5UPymplqhLEU2DsoQmyFlM5RNTt0YXR8XM4Yw
                                su/scxg0u00IF1GC8xcyZUTMc1Rz98AY1VUo5QqUp9Vb
                                Aed5Aw1nNYfjLTj+zOykedgmjms1iNgh9EY111c=
                                ) ; KSK; alg = RSASHA256; key id = 19741
                                ; next refresh: Mon, 24 Apr 2017 15:26:12 GMT
                                ; trusted since: Tue, 18 Apr 2017 00:25:34 GMT

We can see in the output above that the new key, keytag 19741, is now trusted.

Unbound

$ cat /var/lib/unbound/2017-03-12.automated-ksk-test.research.icann.org.ds
; autotrust trust anchor file
;;id: 2017-03-12.automated-ksk-test.research.icann.org. 1
;;last_queried: 1493044058 ;;Mon Apr 24 14:27:38 2017
;;last_success: 1493044058 ;;Mon Apr 24 14:27:38 2017
;;next_probe_time: 1493047519 ;;Mon Apr 24 15:25:19 2017
;;query_failed: 0
;;query_interval: 3600
;;retry_time: 3600
2017-03-12.automated-ksk-test.research.icann.org.       60      IN      DNSKEY  257 3 8 AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWLhE4VxSEIBz9IuCA4w4ssSrClZ59seNc76ltDFcKJv3X9jDjzRtBLjenIgV4n/3GpKrAAnRlYbUtpBEdlk4mxoL3BlX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/eePc9HpZbWxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0tfG2YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1h8IYo0PF98vqjAp3NVRZvKKdgyF/bZ/iJtAZFytXvXU6Gwa5tOm1wgP6wuKupscP8KHBluZyOSKw4RMTk6YBdE= ;{id = 3934 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1489997718 ;;Mon Mar 20 08:15:18 2017
2017-03-12.automated-ksk-test.research.icann.org.       60      IN      DNSKEY  257 3 8 AwEAAfUtjasCuLysD4MbjG3v4Kyu0vvVJ/0cIreP6fltMeZmwQ5SRta/mB+eFVjau+6YKra2UeTKxojBovHH2lZrw7NNejL44/Xps4gR3LSVMnCdwras+yvj4en64ghRGWYOuB+Icb0AqrCUhLFWR8yx41UkfaA2vzFnM2xTx0N0+o6R6UciWuwJResomQupOjNUy2ZAi81Y3pb0x3Lw4POjpcSJzrK4aZ/5UPymplqhLEU2DsoQmyFlM5RNTt0YXR8XM4Ywsu/scxg0u00IF1GC8xcyZUTMc1Rz98AY1VUo5QqUp9VbAed5Aw1nNYfjLTj+zOykedgmjms1iNgh9EY111c= ;{id = 19741 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1492590342 ;;Wed Apr 19 08:25:42 2017

Similarly, for unbound, we can see above that the status is now VALID.

Wiper Relay

 

Recently, the wipers have started to play up on my 2010 BMW E60 LCI

I booked it in to North Oxford BMW last Saturday morning, as it’d been there for services and I’m happy with the work and the customer care.

Of course, sod’s law jumped in, and on the Friday night on the way home from work, the wipers worked fine. Grr.

I took it along to BMW anyway, and thankfully the wipers played up for the technician, and the computer had logged helpful fault codes.

The motor was declared as fine, and a replacement relay was recommended.

They had none in stock, and so I ordered one to collect; I’m quite competent and can swap a relay.

In the mean time I checked the handbook; no mention of relays, just fuses. OK; off to google we go.

The relays are in the “e-box” which is under one of the cabin air intake filters. A helpful Youtube video showed how to get to it.

I picked the relay up this morning, and as the weather was nice, set about replacing it this afternoon.

I undid the clips etc on the drivers side cabin air filter, and fiddled with the surround, before, eventually, the lower part came off, revealing…

…no, not the e-box as expected…

I was faced with the brake servo, which immediately made perfect sense; I immediately realised I’d watched a US video.

So I put it all back together, and started taking the passenger side apart.

BMW_1
Untouched, before disassembly…

Undo that clip along the left edge of the cover, and there’s a clip you can undo with a 13mm socket on the lower right corner (as pictured). Lift it off.

Then, you need to unclip the seal (pictured) – it just lifts off. There’s a clip on plastic cover in the middle below the windscreen, just visible in the left of the picture above; it just slides to the right and comes off.

Once that’s done, you can undo the screw (centre, bottom, next to the red battery terminal, in the picture above) and 3 more of the hex 13mm to be undone with the socket.

You can remove an odd little plastic cover that fits around the right hand bonnet stay with a bit of a wiggle, and then the cover comes off revealing…

BMW_2

Undo the alan screws holding the lid on, and…

BMW_3BMW_4

That browny-beige relay is the wiper relay.

The invoice says it’s a B61.36.8.384.505.

Hope this helps someone.

A New Key…

Further to my post on ICANN’s automated KSK testlab, ICANN generated a new key on the 19th, and added it to the test zone that we’re using, and we can see it below:

$ dig +multiline @::1 2017-03-12.automated-ksk-test.research.icann.org dnskey

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> +multiline @::1 2017-03-12.automated-ksk-test.research.icann.org dnskey
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 36605
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;2017-03-12.automated-ksk-test.research.icann.org. IN DNSKEY

;; ANSWER SECTION:
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	DNSKEY 257 3 8 (
				AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWL
				hE4VxSEIBz9IuCA4w4ssSrClZ59seNc76ltDFcKJv3X9
				jDjzRtBLjenIgV4n/3GpKrAAnRlYbUtpBEdlk4mxoL3B
				lX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/eePc9HpZb
				WxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0
				tfG2YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1h8I
				Yo0PF98vqjAp3NVRZvKKdgyF/bZ/iJtAZFytXvXU6Gwa
				5tOm1wgP6wuKupscP8KHBluZyOSKw4RMTk6YBdE=
				) ; KSK; alg = RSASHA256; key id = 3934
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	DNSKEY 256 3 8 (
				AwEAAbqImB5UsfE5J/sx3L3uQxjSY5HIPjrlTFKA+cxE
				R8SmU1wWGo21nrNBm3pOIYoC3zhiaCq1Jo6XrTcg+In+
				62g7PeXBO+2QBoHzCBxqbFMPoGpHph7D/OebWOvw5Akz
				MFqus2/JxZtvJOgkBws1EbzOw/lKbJUZVStUiCOZ8wFP
				Xd3X7nQMjVTOu6Cb2uGAVrgBRsARo+2CdcXNEtzNTHU1
				c+VxH9G/t/2VCrueDmr/epUP1adkyNUmXoYaG3eMrdGr
				ml8Dr7OMrt40vlWFp6i3TxltDXG/navXdEmL/w6f+pA6
				Dt9KVw/iEUxB08+4VY6jMkxfWJAD6t5XwCVcKH8=
				) ; ZSK; alg = RSASHA256; key id = 19401
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	DNSKEY 257 3 8 (
				AwEAAfUtjasCuLysD4MbjG3v4Kyu0vvVJ/0cIreP6flt
				MeZmwQ5SRta/mB+eFVjau+6YKra2UeTKxojBovHH2lZr
				w7NNejL44/Xps4gR3LSVMnCdwras+yvj4en64ghRGWYO
				uB+Icb0AqrCUhLFWR8yx41UkfaA2vzFnM2xTx0N0+o6R
				6UciWuwJResomQupOjNUy2ZAi81Y3pb0x3Lw4POjpcSJ
				zrK4aZ/5UPymplqhLEU2DsoQmyFlM5RNTt0YXR8XM4Yw
				su/scxg0u00IF1GC8xcyZUTMc1Rz98AY1VUo5QqUp9Vb
				Aed5Aw1nNYfjLTj+zOykedgmjms1iNgh9EY111c=
				) ; KSK; alg = RSASHA256; key id = 19741

;; Query time: 285 msec
;; SERVER: ::1#53(::1)
;; WHEN: Tue Mar 21 20:17:12 GMT 2017
;; MSG SIZE  rcvd: 905

Key 19741 is a new KSK in the zone.

If you look in managed-keys.bind (I’m running Debian, and so that’s in /var/cache/bind/) you’ll now see the new key is visible while BIND is observing the new key. RFC5011 defines the period that the resolver must observe the new key for as either at least two times the TTL of the keyset containing the new key, or 30 days; whichever is the longer.

I’m cheating, slightly, and taking a look at managed-keys.bind from a different server, because my Debian box is running BIND 9.9.5, whereas I have access to a 9.11 box; you’ll see why below:

$ cat /var/named/managed-keys.bind
$ORIGIN .
$TTL 0	; 0 seconds
@			IN SOA	. . (
				284        ; serial
				0          ; refresh (0 seconds)
				0          ; retry (0 seconds)
				0          ; expire (0 seconds)
				0          ; minimum (0 seconds)
				)
			KEYDATA	20170322222551 20170210095625 19700101000000 257 3 8 (
				AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQ
				bSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh
				/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWA
				JQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXp
				oY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3
				LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGO
				Yl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGc
				LmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0=
				) ; KSK; alg = RSASHA256; key id = 19036
				; next refresh: Wed, 22 Mar 2017 22:25:51 GMT
				; trusted since: Fri, 10 Feb 2017 09:56:25 GMT
2017-03-12.automated-ksk-test.research.icann.org KEYDATA 20170321232551 20170317172529 19700101000000 257 3 8 (
				AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWL
				hE4VxSEIBz9IuCA4w4ssSrClZ59seNc76ltDFcKJv3X9
				jDjzRtBLjenIgV4n/3GpKrAAnRlYbUtpBEdlk4mxoL3B
				lX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/eePc9HpZb
				WxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0
				tfG2YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1h8I
				Yo0PF98vqjAp3NVRZvKKdgyF/bZ/iJtAZFytXvXU6Gwa
				5tOm1wgP6wuKupscP8KHBluZyOSKw4RMTk6YBdE=
				) ; KSK; alg = RSASHA256; key id = 3934
				; next refresh: Tue, 21 Mar 2017 23:25:51 GMT
				; trusted since: Fri, 17 Mar 2017 17:25:29 GMT
			KEYDATA	20170321232551 20170418002534 19700101000000 257 3 8 (
				AwEAAfUtjasCuLysD4MbjG3v4Kyu0vvVJ/0cIreP6flt
				MeZmwQ5SRta/mB+eFVjau+6YKra2UeTKxojBovHH2lZr
				w7NNejL44/Xps4gR3LSVMnCdwras+yvj4en64ghRGWYO
				uB+Icb0AqrCUhLFWR8yx41UkfaA2vzFnM2xTx0N0+o6R
				6UciWuwJResomQupOjNUy2ZAi81Y3pb0x3Lw4POjpcSJ
				zrK4aZ/5UPymplqhLEU2DsoQmyFlM5RNTt0YXR8XM4Yw
				su/scxg0u00IF1GC8xcyZUTMc1Rz98AY1VUo5QqUp9Vb
				Aed5Aw1nNYfjLTj+zOykedgmjms1iNgh9EY111c=
				) ; KSK; alg = RSASHA256; key id = 19741
				; next refresh: Tue, 21 Mar 2017 23:25:51 GMT
				; trust pending: Tue, 18 Apr 2017 00:25:34 GMT

On my 9.9.5 server, I don’t have the helpful comments. We can see, helpfully, that the root key (19036), and our original testlab key (3934) are trusted. We can also see that the server observing key 19741 because the instead of trusted since we can see trust pending

If you remember from the original post, whereas BIND keeps a track in managed-keys.bind, Unbound tracks the metadata in the external file we specified with auto-trust-anchor-file:. The file has been updated in a similar way to BIND’s:

$ cat /var/lib/unbound/2017-03-12.automated-ksk-test.research.icann.org.ds
; autotrust trust anchor file
;;id: 2017-03-12.automated-ksk-test.research.icann.org. 1
;;last_queried: 1490135144 ;;Tue Mar 21 22:25:44 2017
;;last_success: 1490135144 ;;Tue Mar 21 22:25:44 2017
;;next_probe_time: 1490138421 ;;Tue Mar 21 23:20:21 2017
;;query_failed: 0
;;query_interval: 3600
;;retry_time: 3600
2017-03-12.automated-ksk-test.research.icann.org.	60	IN	DNSKEY	257 3 8
AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWLhE4VxSEIBz9IuCA4w4ssSrClZ59seNc76ltDFcKJv3X
9jDjzRtBLjenIgV4n/3GpKrAAnRlYbUtpBEdlk4mxoL3BlX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/eePc9Hp
ZbWxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0tfG2YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1
h8IYo0PF98vqjAp3NVRZvKKdgyF/bZ/iJtAZFytXvXU6Gwa5tOm1wgP6wuKupscP8KHBluZyOSKw4RMTk6YBdE=
;{id = 3934 (ksk), size = 2048b} ;;state=2 [  VALID  ] ;;count=0 ;;lastchange=1489997718 ;;Mon Mar 20 08:15:18 2017

2017-03-12.automated-ksk-test.research.icann.org.	60	IN	DNSKEY	257 3 8
AwEAAfUtjasCuLysD4MbjG3v4Kyu0vvVJ/0cIreP6fltMeZmwQ5SRta/mB+eFVjau+6YKra2UeTKxojBovHH2lZ
rw7NNejL44/Xps4gR3LSVMnCdwras+yvj4en64ghRGWYOuB+Icb0AqrCUhLFWR8yx41UkfaA2vzFnM2xTx0N0+o
6R6UciWuwJResomQupOjNUy2ZAi81Y3pb0x3Lw4POjpcSJzrK4aZ/5UPymplqhLEU2DsoQmyFlM5RNTt0YXR8XM
4Ywsu/scxg0u00IF1GC8xcyZUTMc1Rz98AY1VUo5QqUp9VbAed5Aw1nNYfjLTj+zOykedgmjms1iNgh9EY111c=
;{id = 19741 (ksk), size = 2048b} ;;state=1 [ ADDPEND ] ;;count=34 ;;lastchange=1489997718 ;;Mon Mar 20 08:15:18 2017

In line 15, we see the original key (3934) with a status of VALID, whereas in line 22 we see the newly spotted key 19741 is ADDPEND.

What’s next…?

Now we wait; 30 days, and as long as the key is observed throughout, the key should become trusted at the end of this…

Rolling, rolling, rolling…

Introduction

In October 2017, ICANN are going to roll the key signing key in the root of the DNS.

If you’re not technical and don’t know what I just said, this post isn’t for you.

If, however, you run a validating recursive resolver, read on…

In October (the 11th to be exact), the key will roll and you’ll need to have done one of two things…

  1. Update your root trust anchor manually
  2. Check your resolver is RFC5011 compliant.

But first, a little…

Background…

So you know how DNSSEC works…

…you sign a zone. More specifically, you generate two keys, a key to sign the zone (ZSK), and a key to sign the keys (KSK). The zone gets bigger because for each record set, a signature is generated and added (RRSIG records). The public part of the keyset is also added to the zone (DNSKEY records). Some form of proof of non-existance is added (NSEC or NSEC3).

Next, once the keys and signatures have made it to all of the nameservers for the zone, you generate a delegated signer record (DS) from the KSK, and you publish that in the parent. The parent then signs the DS record, and hey presto, your chain of trust is made.

So, where’s the DS record for the root… To make this chain of trust work, resolvers that want to validate the DNSSEC chain of trust need a starting point in the root…

Your resolver has a trust anchor for the root. Depending on what you’re using for a resolver, this will either be the DS of the root KSK, or the public part of the KSK.

Your resolver will have this built in, but then, if configured correctly, will use an automatic mechanism to keep that key up to date and roll it when required.

RFC5011

RFC5011 defines how a resolver can automatically update a trust anchor for a zone.

So that you can check whether your resolver will follow this process, ICANN have an automated testbed for the KSK roll, which I encourage you to look at.

ICANN’s Automated Test

Each week, they create a new zone, and they sign it with a set of newly generated keys. Purposefully broken DS records are published in the parent zone, so that a normal validating resolver will SERVFAIL (because validation fails).

By adding a trust anchor to your resolver, the zone will validate.

If correctly configured, your resolver will now look for new key signing keys, and will observe them, and use them as per RFC5011.

So, lets take a look at this. Before I add a trust anchor, I can check that the zone doesn’t validate:


$ dig @::1 2017-03-12.automated-ksk-test.research.icann.org soa

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> @::1 2017-03-12.automated-ksk-test.research.icann.org soa
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 39100
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;2017-03-12.automated-ksk-test.research.icann.org. IN SOA

;; Query time: 1908 msec
;; SERVER: ::1#53(::1)
;; WHEN: Mon Mar 20 13:22:57 GMT 2017
;; MSG SIZE  rcvd: 77

We can see in line 7, that we have a SERVFAIL response.

This server is running BIND. So, first we check that the server is configured manage keys using RFC5011:

options {
    ...
    dnssec-validation auto;
    ...
};

If you’re just adding this, don’t forget to rndc reconfig

Trust Anchor

Now, we need to add a trust anchor:

BIND

managed-keys {
  2017-03-12.automated-ksk-test.research.icann.org initial-key 257 3 8
  "AwEAAa9qsSLDI+H0keqE3Yzdr6XuhqhBQVWw5xdgNoWLhE4VxSEIBz9I
  uCA4w4ssSrClZ59seNc76ltDFcKJv3X9jDjzRtBLjenIgV4n/3GpKrAA
  nRlYbUtpBEdlk4mxoL3BlX8pfLg7RQfTlWaxOUga1+CChcVieFF/si/e
  ePc9HpZbWxHZRLCAE8dlDa0aa0tfVAZWOnaifpmbTvhDK3tdvMU0tfG2
  YfsOYcFB9z2KWmCDYwCONNKtls3p6wMwolun1h8IYo0PF98vqjAp3NVR
  ZvKKdgyF/bZ/iJtAZFytXvXU6Gwa5tOm1wgP6wuKupscP8KHBluZyOSK
  w4RMTk6YBdE=";
};

This is added in your named.conf file.

Once again, don’t forget to rndc reconfig

Unbound

If you’re running Unbound, then you can add the DNSKEY or DS records to a file in a location that Unbound can read and write to (so, somewhere like /var/lib/unbound/ and then add a auto-trust-anchor-file line in the server: section of your unbound.conf file.

cat /var/lib/unbound/2017-03-12.automated-ksk-test.research.icann.org.ds
2017-03-12.automated-ksk-test.research.icann.org. IN DS 3934 8 1 47AA8AAF4D75B3D9C58448F241F793EBC4977821
2017-03-12.automated-ksk-test.research.icann.org. IN DS 3934 8 2 0D27F2E6EA9CA548F1896A71FB07CED86074D3462F2A720D6177F3C5CEC15F0D

Note; the file doesn’t look like this once you’ve told Unbound about it, as it uses the file to store metadata related to the RFC5011 process.

server:
    ...
    auto-trust-anchor-file: "/var/lib/unbound/2017-03-12.automated-ksk-test.research.icann.org.ds"
    ...

After adding those, you’ll want to unbound-control reload to pick up the changes.

Testing

$ dig @::1 2017-03-12.automated-ksk-test.research.icann.org soa

; <<>> DiG 9.9.5-9+deb8u6-Debian <<>> @::1 2017-03-12.automated-ksk-test.research.icann.org soa
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30413
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 3

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;2017-03-12.automated-ksk-test.research.icann.org. IN SOA

;; ANSWER SECTION:
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	SOA ns1.research.icann.org. automated-ksk-test.research.icann.org. 1489968062 3600 600 86400 60

;; AUTHORITY SECTION:
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	NS ns2.research.icann.org.
2017-03-12.automated-ksk-test.research.icann.org. 60 IN	NS ns1.research.icann.org.

;; ADDITIONAL SECTION:
ns1.research.icann.org.	3600	IN	A	192.0.34.56
ns2.research.icann.org.	3600	IN	A	192.0.45.56

;; Query time: 428 msec
;; SERVER: ::1#53(::1)
;; WHEN: Mon Mar 20 13:44:24 GMT 2017
;; MSG SIZE  rcvd: 181

This time, we can see that on line 7, we have a NOERROR response, and on line 8, we can see that we have ad in the flags.

What’s next…

Now, we wait. The next step is that ICANN’s automated test lab will generate and publish a new KSK into the zone on the 19th.

Anycasting DNS

Introduction…

I wanted to have a tinker with anycasting, and DNS seemed a sensible place to start, and easy to test and muck about with. So, I spun up a couple of DNS resolvers, and decided what my anycasted IP addresses would be. They need to be outside of the subnets I’m using on the rest of my network, as I want to route traffic to them. I’ve put the underlying machine’s unicast addresses in this subnet too, but you wouldn’t have to, depending on your set up.

Servers…

The nameservers are, essentially, identical to servers that’d deal with unicast traffic, except for the following changes. I’m using BIND, but it really doesn’t matter what you use.

We need to bind up the anycast addresses so that the O/S will deal with their traffic…

In my case, my anycasted addresses will be 10.1.53.1 and 10.1.53.2, and I’m using Debian, so my additions to /etc/network/interfaces are:

auto lo:1
iface lo:1 inet static
address 10.1.53.1
netmask 255.255.255.255

auto lo:2
iface lo:2 inet static
address 10.1.53.2
netmask 255.255.255.255

We need to stop the machine responding to ARP for these. Actually, we tell it to stop responding to ARP requests unless the interface the ARP arrives on matches the ARP’d for IP, so because we’ve bound them up to the loopback, we don’t want the machine to respond via eth0, for example, so I added the following to /etc/sysctl.conf:

net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.eth0.arp_announce = 2

BGP & Load Balancing…

Now we need to advertise the anycast addresses to our router. In this case, we’ll use BGP to do this. To do that, we’ll use ExaBGP. Grab that and install it on the server, and then the config looks something like this. My router is 10.1.53.254, and my two nameservers live in 10.1.53.0/24

neighbor 10.1.53.254 {
  router-id 10.1.53.11;
  local-address 10.1.53.11;
  local-as 64601;
  peer-as 64601;
  hold-time 10;

  process watch-nameserver {
    run /usr/local/bin/nameserver_watchdog;
  }

  static {
    route 10.1.53.1/32 next-hop 10.1.53.11 watchdog anycastdns withdraw;
    route 10.1.53.2/32 next-hop 10.1.53.11 watchdog anycastdns withdraw;
    route xxxx.xxxx.xxxx:53::1/128 next-hop xxxx.xxxx.xxxx:53::11 watchdog anycastdns withdraw;
    route xxxx.xxxx.xxxx:53::2/128 next-hop xxxx.xxxx.xxxx:53::11 watchdog anycastdns withdraw;
  }
}

I withdraw the routes from the outset, so that the watchdog will announce them upon successful testing.

The router’s BGP config looks like this (it’s JunOS):

# show protocols bgp group dns-anycast
local-address 10.1.53.254;
hold-time 10;
family inet {
    unicast;
}
family inet6 {
    unicast;
}
peer-as 64601;
local-as 64601;
multipath;
neighbor 10.1.53.11;
neighbor 10.1.53.12;

I’m going to equally load balance between the two servers, but you could set a localpref on each server, for example, and have server1 handle .1 primarily with server2 taking over in the event of failure, and vice versa.

Don’t fall for JunOS’ misleading ‘per packet’ configuration item; this will, despite appearances, load balance per flow based on a hashing algorithm.

# show routing-options forwarding-table
export dns-anycast-loadbalance;

# show policy-options policy-statement dns-anycast-loadbalance
then {
    load-balance per-packet;
}

Monitoring and Health…

We’ve included a watchdog in the ExaBGP config. Without this, clearly if the nameserver fails entirely, then the BGP session will be torn down, and the traffic directed to the other host. However, if the nameserver daemon fails, then the BGP session will remain, and traffic will be disrupted. Therefore, there’s a watchdog that’ll check that the nameserver daemon is listening, and will perform a lookup against it, announcing the anycast address(es) while it’s up, and withdrawing them in the event of failure. The watchdog looks like this:

#!/usr/bin/perl

use strict;

my $debug = 0;

unless($debug) {
	$SIG{'INT'} = sub {};
}
select STDOUT;
$| = 1;

use IO::Socket;
use Net::DNS;

my $state = 'init';

my $ip;
my $domain;
if(open(C,"/etc/nameserver_watchdog.conf")) {
	chomp(($ip, $domain) = split /:/, <C>);
	close C;
} else {
	$ip = '127.0.0.1';
	$domain = 'localdomain';
}
print "checking $ip for $domain\n" if $debug;

while(1) {
	eval {
		local $SIG{ALRM} = sub { die 'Timed Out'; };
		alarm 2;
		print "attempting connect... state is [$state]\n" if $debug;
		my $socket = IO::Socket::INET->new(Proto=>'tcp', PeerAddr=>$ip, PeerPort=>53, Timeout=>2);
		if($socket && $socket->connected() && do_lookup($ip, $domain)) {
			print "announce watchdog anycastdns\n" if $state ne 'up';
			$socket->close();
			alarm 0;
			$state = 'up';
			print "state set to up\n" if $debug;
		} else {
			print "withdraw watchdog anycastdns\n" if $state ne 'down';
			$state = 'down';
			print "state set to down\n" if $debug;
		}
	};
	if($@) {
		print "state is [$state]\n" if $debug;
		print "withdraw watchdog anycastdns\n" if $state ne 'down';
		$state = 'down';
		print "state set to down in barf\n" if $debug;
	}
	alarm 0;
	sleep 10;
}

sub do_lookup {
	my $ip = shift;
	my $domain = shift;
	my $r = Net::DNS::Resolver->new;
	$r->nameservers($ip);
	$r->tcp_timeout(5);
	$r->udp_timeout(5);
	my $q = $r->query($domain,'SOA');
	my $found = 0;
	print "Answer: ".($q->answer)[0]->serial."\n" if $debug;
	$found++ if ($q->answer)[0]->serial =~ m/^\d+$/;
	if($debug > 1) {
		require Data::Dumper;
		print Data::Dumper::Dumper($q)."\n\n";
	}
	return 1 if $q && $found;
	print "Error:\n" if $debug;
	print $r->errorstring if $debug;
	print "\n===\n" if $debug;
	return 0;
}

/etc/nameserver_watchdog.conf contains lines of the format ip.ad.dr.ess:domain.com.

It’ll announce the address in the event that a tcp connection succeeds as well as a DNS lookup that you’d expect the server should answer or be permitted to recurse for you. If the DNS daemon stops responding the watchdog will withdraw the routes; if the server fails, the BGP session will fail, and the route will be withdrawn anyway.

Live Electricity Usage

So, following on from my recent post on updating my Currentcost code I now have every update coming from the Currentcost unit popping directly into the database, every 6 seconds.

I had become aware of the Highcharts charts javascript and when reading through their Live Charts Demo decided that this was just waiting to be played with.

I now have essentially the same graph that they have in that demo, and the page HTML is very similar. The difference is obviously to call my code instead, and also a change to refresh every 6 seconds:

function requestData() {
    $.ajax({
        url: '/power/latest.php',
        success: function(point) {
            var series = chart.series[0],
                shift = series.data.length > 60; // shift if the series is longer than 20

            // add the point
            chart.series[0].addPoint(eval(point), true, shift);

            // call it again after one second
            setTimeout(requestData, 6000);
        },
        cache: false
    });
}

My AJAX call is also to some PHP, but mine looks up the latest data from the database with a simple SQL statement:

select unix_timestamp(time) as time,data_value from data order by time desc limit 1

I quickly realised that this would slap the database, and more so if more than one person was viewing the page. That would be unnecessary, and so I installed memcached and the php5 memcached module.

<?php header("Content-type: text/json"); $m = new Memcached(); $m->addServer('127.0.0.1', 11211);

if(!($row = $m->get('leccy'))) {
        //echo "didn't get from memcache\n";
        $row = get_from_db();
        $m->set('leccy', $row, 6);
}
else if(time() - $row['time'] > 5) {
        //echo "got, but is old\n";
        $row = get_from_db();
        $m->set('leccy', $row, 6);
}

// x is JS time which is unixtime x 1000
$x = $row['time'] * 1000;

// y is the value at that point
$y = $row['data_value'] * 1;

$ret = array($x, $y);

echo json_encode($ret);

function get_from_db() {
        mysql_connect("db server","db user","db passwd") or die("cannot connect: ".mysql_error());
        mysql_select_db("db name");
        $sql = 'select unix_timestamp(time) as time,data_value from data order by time desc limit 1';
        $sth = mysql_query($sql) or die("no query: ".mysql_error());
        $row = mysql_fetch_assoc($sth);
        mysql_close();
        return $row;
}

?>

Edit: Slight tweak to the code, as there was some obvious lazyness that I tidied up.

Enjoy.

live_graph

CurrentCost Update

For a while now, I’ve been using a Current Cost CC128 to monitor my electricity usage.

I hacked together a munin plugin to monitor both the electricty usage, and as the unit is in my lounge and coughs up temperature, it also provides the temperature reading.

For a number of reasons, the munin plugin doesn’t read the device directly. Only one device can open the serial port at a time, and there were a couple of things I wanted to do with the data, so didn’t want them fighting. I had a small piece of code grab the XML once a minute and dump it in a file instead.

Talking to a friend recently, they quite rightly pointed out (reminding me) that this method takes an instantaneous value for both the temperature and the electricity usage.

Whilst not a problem for the former as it won’t vary greatly within the 5 minute polling periods, the electricity usage clearly will. Think about boiling a kettle; if you were (un)? lucky enough to time the kettle just right, you could be between polls and not record the increased usage at all.

So, I’ve modified the way in which I record the data and write the files for the various things including munin to use.

As you’ll probably be aware, the CC128 outputs it’s data once every 6 seconds, so there’s clearly more data to make use of than just the single reading every 5 minutes.

I have a small daemon written in perl that listens on the serial port and every time it gets a full string of XML, it records the data to a database. Rather than re-write the munin plugin at the moment, along with anything else that uses the data file, I have a small bit of perl that runs from cron each minute that populates the expected XML into the file using averages of the values collected in the preceding 5 minute period. You could, of course, make this 95th percentile or whatever tickles your fancy.

So, the SQL table looks like this:

mysql> describe data;
+------------+------------------+------+-----+-------------------+-----------------------------+
| Field      | Type             | Null | Key | Default           | Extra                       |
+------------+------------------+------+-----+-------------------+-----------------------------+
| id         | int(10) unsigned | NO   | PRI | NULL              | auto_increment              |
| dsb        | int(10) unsigned | YES  |     | NULL              |                             |
| time       | timestamp        | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| tmpr       | decimal(6,4)     | YES  |     | NULL              |                             |
| sensor     | int(10) unsigned | YES  |     | NULL              |                             |
| unit_id    | int(10) unsigned | YES  |     | NULL              |                             |
| type       | int(10) unsigned | YES  |     | NULL              |                             |
| channel    | int(10) unsigned | YES  |     | NULL              |                             |
| data_units | varchar(128)     | YES  |     | NULL              |                             |
| data_value | int(10) unsigned | YES  |     | NULL              |                             |
+------------+------------------+------+-----+-------------------+-----------------------------+
create or replace view averages as
select sensor,dsb,unit_id,type,channel,data_units,avg(tmpr) as tmpr,avg(data_value) as value,now() as now,
from_unixtime(300 * floor(unix_timestamp()/300)-300) as start,from_unixtime(300 * floor(unix_timestamp()/300)) as end 
from data 
where time between from_unixtime(300 * floor(unix_timestamp()/300)-300) and from_unixtime(300 * floor(unix_timestamp()/300)) 
group by unit_id,sensor,channel;

I should credit http://larig.wordpress.com/2012/02/08/time-rounded-to-five-minutes-in-mysql/ for the sql to round time to the current 5 minute window.

The bit that writes the XML file looks like this:

#!/usr/bin/perl

use strict;

use DBI;

my $dsn = "DBI:mysql:database=<removed>;host=<removed>;port=3306";
my $dbh = DBI->connect($dsn, '<removed>', '<removed>');

my $sql = 'select * from averages';

my $sth = $dbh->prepare($sql) || die "cannot prepare sql\n$sql\n$DBI::errstr\n";

$sth->execute() || die "cannot execute sql\n$sql\n$DBI::errstr\n";

if($sth->rows > 0) {
	my $r;
	print "<msg>\n";
	while(my $row = $sth->fetchrow_hashref) {
		print "  <ch$row->{channel}>\n";
		print "    <$row->{data_units}>$row->{value}</$row->{data_units}>\n";
		print "  </ch$row->{channel}>\n";
		$r = $row;
	}
	print "  <sensor>$r->{sensor}</sensor>\n";
	print "  <id>$r->{unit_id}</id>\n";
	print "  <dsb>$r->{dsb}</dsb>\n";
	print "  <tmpr>$r->{tmpr}</tmpr>\n";
	print "  <type>$r->{type}</type>\n";
	print "  <time>$r->{now}</time>\n";
	print "</msg>\n";
} else {
	die "no rows returned!\n";
}

$sth->finish;
$dbh->disconnect;

…and lastly, the bit that grabs the stuff and chucks it into the database looks like this (and also writes a backward compatible version of the XML file with the instantaneous values…:

#!/usr/bin/perl

$|++;

use strict;

use File::Copy qw/move/;
use Device::SerialPort qw/:PARAM :STAT 0.07/;
use XML::Simple;
use DBI;
use Data::Dumper;

my $debug = $ENV{DEBUG} || 0;

use Proc::PID::File;
if(Proc::PID::File->running()) {
	print "Already running\n" if $debug;
	exit;
}

my $port = $ENV{port} || '/dev/ttyUSB0';
my $baud = $ENV{baud} || 57600;

my $debug = $ENV{DEBUG} || 0;

my $cc = Device::SerialPort->new($port) || die "unable to open port: $!\n";
$cc->baudrate($baud);
$cc->read_char_time(0);
$cc->read_const_time(1000);
$cc->write_settings;

my $dsn = "DBI:mysql:database=<removed>;host=<removed>;port=3306";
my $dbh = DBI->connect($dsn, '<removed>', '<removed>');
my $sql = 'insert into data (dsb,tmpr,sensor,unit_id,type,channel,data_units,data_value) values (?,?,?,?,?,?,?,?)';
my $sth = $dbh->prepare($sql) || die "cannot prepare sql\n$sql\n$DBI::errstr\n";

while(1) {
	my $timeout = 10;
	my $chars = 0;
	my $buffer;
	LOOP: while($timeout > 0) {
		my($count, $saw) = $cc->read(255);
		if($count > 0) {
			$chars += $count;
			$buffer .= $saw;
			chomp $buffer;
			print "added\n$saw\nnow have\n$buffer\n" if $debug;
			if($buffer =~ m|<msg>.*?</msg>|) {
				print "Buffer contains XML\n\n" if $debug;
				do_xml($buffer);
				last LOOP;
			}
			elsif($buffer =~ m|</msg>|) {
				print "Caught the end of the XML\n" if $debug;
				undef $buffer;
			}
		} else {
			print "." if $debug;
			$timeout--;
		}
	
		print "Waited $timeout and never saw what I was looking for\n" if $timeout == 0 && $debug;
	
	}
}

sub do_xml {
	my $xmls = shift;
	if($xmls =~ "<hist>.*?</hist>") {
		return;
	} else {
		$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
		my $xml;
		eval { $xml = XMLin($xmls); };
		return undef if $@;
		print Dumper($xml) if $debug;
		for(keys %$xml) {
			if(m/^ch(\d+)$/) {
				my $channel = $1;
				my $name = 'ch'.$channel;
				for(keys %{$xml->{$name}}) {
					my $unit = $_;
					my $value = $xml->{$name}->{$unit};
					printf("dsb[%s] tmpr[%s] sensor[%s] id[%s] type[%s] ch[%s] units[%s] val[%s]\n",$xml->{dsb},$xml->{tmpr},$xml->{sensor},$xml->{id},$xml->{type},$channel,$unit,$value) if $debug;
					$sth->execute($xml->{dsb},$xml->{tmpr},$xml->{sensor},$xml->{id},$xml->{type},$channel,$unit,$value) || die "cannot execute sql\n$sql\n$DBI::errstr\n";
				}
			}
		}
		open(XML,'>/tmp/currentcost.snapshot.xml.tmp') || die "cannot open file: $!\n";
		print XML $xmls || die "cannot write to file: $!\n";
		close XML || die "cannot close file: $!\n";
		move('/tmp/currentcost.snapshot.xml.tmp', '/tmp/currentcost.snapshot.xml') || die "unable to move file: $!\n";
	}
}

I restart that from cron periodically, incase it dies. If it’s already running, it simply exits silently. It’s a quick hacky way to make it restart in the event something horrible happens. I did at least put the XML parse in an eval in case it barfs 🙂

As usual, this blog post is as much for my personal notes of how I did it than anything else. Some of the code if awful, but it’s not life or death and so I’ve often been lazy with it. There’s no doubt this could be done prettier and less hacky if I had more time 🙂

Cost Effective Temperature Monitoring

I’d been thinking about some temperature monitoring at home for a while, particularly in the nursery, so I can see if it’s getting too hot or cold in there while I’m asleep.

When my Raspberry Pi arrived, I decided to put it to work.

temp-day

After quite a bit of googling & reading, I found that the one wire file system stuff was easy to install, and had been done by others (See references below).

Whilst it’s possible to go and buy the individual components, and I’m quite capable with a soldering iron, I have to admit to taking the lazy route and purchased some bits from Sheepwalk Electronics

I wanted to monitor temperature in the garage, outside, the loft, the front bedroom, and the small bedroom on the back of the house (currently, the nursery).

I also monitor temperature in the lounge, but that comes from the Current Cost unit that I also monitor electricity usage with.

So, I’d need a host adaptor, and a sensor for each of the places to be monitored.

The Sheepwalk sensor modules are made up, or kit form, and include RJ45 sockets to ease putting together a network with standard cat5 cable. The sensors can either be parasitic and pull power from the bus, or can have power supplied. I’ve set mine up as parasitic, and it’s working OK so far.

One wire is best suited to a linear network of devices strung together, but seems quite robust, and is working in a star arrangement.

I purchased Sheepwalk’s SWE2+SWE0 pack which comes with an SWE2 (basically, a sensor plus 6 RJ45 sockets) and four SWE0 (a basic sensor on the end of 2m of cat5). I also purchased a USB host adaptor, and the RJ11 to RJ45 cable, although this would be simple to make up. Lastly, I picked up some RJ45 couplers, as they’re a good price and I’d be sure to need some!

I installed Raspbian (the official/recommended linux distro for the Raspberry Pi) on the SD card and booted the Raspberry. I gave it a static IP on my network so I could probe it from the Munin instance later on without fear of the IP changing.

After inserting the USB adaptor, I installed OWFS

kdyson@rpi1 ~ $ apt-get install owfs

There’s no init script for owfs itself, only for the supporting services, but Neil Baldwin’s page that I’d been reading had one, which saved me the hassle of writing one.

With that started, I plugged in the RJ11 to RJ45 lead, and plugged the SWE2 into the end. A fresh ls -al /mnt/1wire/ showed the new sensor, and

kdyson@rpi1 ~ $ cat /mnt/1wire/28.873AC4030000/temperature
31.5625
kdyson@rpi1 ~ $

I tested the rest of the sensors, before hooking them up where I wanted them. I was a little concerned that the cable length might be a problem to the furthest sensor – the sensor in the loft is about 25m of cable from the SWE2, and is strung off the SWE1 that provides the “Front Bedroom” sensor.

Lastly, I hacked up a munin plugin. All I needed was the munin-node package (apt-get install munin-node) as my remote munin instance would be collecting the data and producing the graphs (it’s already doing things like the already mentioned temperature in the lounge, electricity usage, and more mundane things like the SNR & sync rate of my ADSL line from my router).

So, in summary:

  • Raspberry Pi + SD Card + Raspbian + OWFS + Munin-Node
    • USB Host Adaptor + RJ11 to RJ45 Lead
      • SWE2 (Garage)
        • SWE0 (Garage Outside)
        • SWE1 (Front Bedroom)
          • SWE0 (Loft)
        • SWE0 (Small Bedroom)

Code Snippets

First up is the munin plugin. I took a chunk of inspiration from http://err.no/personal/blog/2010/Nov/02 but the perl OWNet module was playing up for me, and given it was 10pm, I took the lazy route and hacked it about to just look around the file system. You can tell how lazy I was, because you can see I used glob() instead of opendir() etc. I’m not proud of it, but it’s working.

You’d need to drop this either directly in /etc/munin/plugins or someplace else and symlink it to there. I did the latter.

#!/usr/bin/perl

#%# family=auto
#%# capabilities=autoconf

use strict;
use warnings;
use utf8;

my $debug = 0;

chdir "/mnt/1wire/bus.0";

my @buses = grep { /bus./ } glob("*");

print "got buses ".join(", ", @buses)."\n" if $debug;

my %sensors;
my %sensor_names;
for my $bus (@buses) {
  for my $sensor (glob($bus."/*")) {
    print "got sensor $sensor\n" if $debug;
    my $p = $sensor;
    $sensor =~ s|^bus.\d+/||;
    my $sensor_name = $sensor;
    $sensor_name =~ s|\.||;
    next if $sensor =~ /(interface|alarm|simultaneous)/;
    next unless $sensor =~ /^28\./;
    $sensors{$sensor} = $p;
    $sensor_names{$sensor} = $sensor_name;
  }
}

my %labels;
if(open(A, '/etc/owfs-aliases')) {
  while(<a>) {
    chomp;
    print "got label $_\n" if $debug;
    my($s,$l) = m/^([\da-zA-Z\.]+)\s*=\s*(.+)$/;
    $labels{$s} = $l;
  }
  close A;
}

use Data::Dumper;
print Dumper(\%sensors)."\n" if $debug;
print Dumper(\%labels)."\n" if $debug;

if (defined $ARGV[0]) {
  if ($ARGV[0] eq 'autoconf') {
    if (-d "/mnt/1wire/bus.0") {
      print "yes\n";
      exit 0;
    }
    print "no\n";
    exit 1;
  } elsif ($ARGV[0] eq 'config') {
    print "graph_title Temperature\n";
    print "graph_args --base 1000\n";
    print "graph_vlabel Temp in °C\n";
    print "graph_category sensors\n";
    print "graph_info This graph shows the temperature in degrees Celsius of the sensors on the network.\n";
    print "$sensor_names{$_}.label $labels{$_}\n" foreach (keys %sensors);
    exit 0;
  }
}

for my $sensor (keys %sensors) {
  print "sensor is $sensor\n" if $debug;
  if ($0 =~ /ow_([\w\.]+)/) {
    print "1 is $1\n" if $debug;
    next unless ($1 eq $sensor || $1 eq $labels{$sensor});
  }
  my $file = "/mnt/1wire/bus.0/".$sensors{$sensor}."/temperature";
  my $temp = `cat $file`;
  chomp $temp;
  printf "%s.value %.4f\n", $sensor_names{$sensor}, $temp;
}

exit 0;

Next up, the aliases file /etc/owfs-aliases – again, it was late, owfs aliases didn’t appear to be working quite how I was expecting, and so I hacked the plugin to use this file:

28.5086C4030000 = Front_Bedroom
28.7D61C4030000 = Garage
28.684EC4030000 = Garage_Outside
28.873AC4030000 = Loft
28.C786C4030000 = Small_Bedroom

References

http://err.no/personal/blog/2010/Nov/02
http://neilbaldwin.net/blog/weather/raspberry-pi-data-logger/

IPv6 Privacy Extensions

Introduction

If you’ve switched on IPv6, whether via a tunnel, or natively, your machine is likely to have stepped out from behind NAT and now has a globally routable address.

Whilst NAT is not security, and inbound connections to your machine are likely behind a firewall, that doesn’t change one thing: in many cases your IPv6 address is made up automatically by auto-configuration.

It’s made up of two parts, the last 64 bits are put together partly from the MAC address of your network interface, and the rest comes from the network prefix.

This makes your machine globally identifiable, and therefore, trackable by third parties, such as web sites.

To this end, RFC3041, superseded by RFC 4941 defines privacy extensions.

When enabled, your machine still has the auto-configuration address, but now also has a randomised additional address that changes periodically and is used for outbound connections.

On many linux distributions this is disabled by default. Windows XP is the same. Windows Vista enables it by default, and I believe newer versions of Windows also enable it by default.

I don’t have access to any Windows Server installations with IPv6, so I’m unsure if the server editions do this too.

I mention servers, as you probably don’t want this on a server. Imagine, for example, a mail server making an outbound connection from a random and short lived IP address. It’s unlikely to have a valid PTR, for example, and many, not all I grant you, but many MTAs will not like that.

Enabling it on Linux

Enabling it on linux distributions is quite straight forward:

as root:

echo 2 > /proc/sys/net/ipv6/conf/all/use_tempaddr

You can automate this at boot in the normal way; edit /etc/sysctl.conf and add the line:
net.ipv6.conf.all.use_tempaddr=2
You can swap all for a specific IPv6 enabled interface, such as eth0 if you require.

Enabling it on OS X

OS X has it disabled by default. I believe you can add to, or create /etc/sysctl.conf with the following:

net.ipv6.conf.all.use_tempaddr=1

Don’t quote me on that last one; I’ve not tested it!

[edit 21/Mar/2017]: MacOS Sierra seems to have it enabled by default…