Thursday, 15 December 2011

Enabling IPv6 Privacy Addresses

At the last UDS, we once again discussed the state of IPv6 support in Ubuntu. We're in the process of making Ubuntu really rock with IPv6, and this comes with decisions and hard work.

One of these decisions was to enable IPv6 Privacy Extensions by default. In other words, rather than having an IPv6 address that is derived directly from your network device's MAC address, you'll now have that, but supplemented with time-based temporary addresses, randomly created, used to establish outgoing connections to systems. This leads to higher privacy; because it makes it harder for an eavesdropper to identify whether different addresses really refer to the same node (that's because the *prefix*, which network you come from, would change, but never the last part of the address, unless using privext). How all of this works is described in more details in RFC 4941.

And leading to this, the hard work. We've recently enabled IPv6 privacy extensions through a new file shipped by procps: /etc/sysctl.d/10-ipv6-privacy.conf. Sysctls are parsed early on in the boot process, but perhaps not early enough; which lead to an issue: on some systems, one would see some interfaces with privext enabled, and some others without. This appears to be because some interfaces (eth0 on my system) are initialized early enough in the boot process that it comes up before the sysctl settings are applied.

With this, another issue: there are three types of sysctl settings for ipv6: default, all, and per-interface entries. According to kernel documentation and help strings; default is meant as the ... default for future interfaces that would get created. At least, that's how I get it. Per-interface entries are obvious: you're just changing the setting for that particular interface. But what about all?

Well, it turns out net.ipv6.conf.all.anything doesn't really do anything, except for forwarding and disable_ipv6. These two options are already handled specially by kernel code. The particular setting that interested me was use_tempaddr though, and isn't being propagated (to the per-interface entries) or use globally to enable privacy addresses on all interfaces; which is something you'll likely want if you are looking to enable privacy extensions at all. Take this example: if you're using a mobile system, you might have wired and wireless connected at the same time, and may want to get up, unplug wired, and move around to a different spot, with or without suspending. While NetworkManager will in time allow toggling privacy extensions per connection, you shouldn't need to manually change this for a default install, on a typical, mobile worker day.

So I started writing my first ever kernel patch: having the net.ipv6.conf.all.use_tempaddr sysctl propagate its value to all the other interfaces already present on the system when the value is changed. It's currently being reviewed before I work towards having it included in the kernel proper. Reviews for that patch are welcome on the kernel-team mailing list.

I've now tested that this solves the issue of applying that particular sysctl at boot time; much like it appears to be expected to work by just about everyone if I'm to believe research I've done on the web on that subject. If there are brave souls wanting to test this, head over to my NM PPA. You'll need to be running Precise, and the package you'll want is linux 3.2.0-4.11~mtrudel2. Since this is a custom hacked up kernel package (but I tried hard to follow the Kernel Team's procedures), standard warnings of caution and the usual "if your system gets broken you get to keep both pieces" apply... but I'm running that package too ;)