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 ;)


6 comments:

Drew said...

I'm still trying to figure out IPv6 but I do know that in Fedora and openSUSE before I could browse the internet I had to go and turn off or blacklist IPv6. Ubuntu was the only one that didn't initially have this set so I was able to go online out-of-the-box.

So whatever is done, please don't make it so we have to jump through hoops to get a browser (and other online services) working!

Matt Trudel said...

Drew,

Well, the issue there might be caused by your router, unfortunately. Some models have been known to cause issues in the past with IPv6, maybe it's still the case. The jist of the problem was that DNS resolution would be affected (requests would be dropped).

However, if you're now on Oneiric, you should already see this being a problem if it's the cause. Oneiric already has IPv6 enabled by default in NetworkManager, all I'm talking about here is enabling a special function that increases privacy.

Normally, IPv6 shouldn't make a difference on a healthy, well-designed network: we've roughly proven that by the fact that really nothing much happened on IPv6 day, last June. So if you're already running Oneiric and running into issues... Please let us know about them; bug reports are great for that. And if you want to help out with testing, it's obvious that running an virtual machine with Precise (or a live CD) if you can get IPv6 connectivity is great help. Either way, we want to know if you run into issues ;)

Drew said...

Naw, 11.10 is the only one of the latest batch of updates (the "batch" including Fedora 14-16 and openSUSE 12.1) that DIDN'T have any problems (and I hope it stays that way) ;)

Vincent Bernat said...

This is not how "all" and "default" settings work. "default" is the value used when a new interface appears. "all" is not propagated to existing interfaces but the actual value for an interface is the value of the interface AND/OR/MAX the value of "all". For example, for rp_filter, this is max(interface, all). You can see this is include/linux/inetdevice.h. For IPv6, there seems to have something different.

Matt Trudel said...

@Drew, great, good to hear ;)

@Vincent Bernat: Right, I had gotten that part for IPv4, but IPv6 does seem to be handled differently. What's for sure is that this behaviour would be consistent with that of at least net.ipv6.conf.all.disable_ipv6, for what that's worth. It also doesn't seem to be using the values from ....all.* in any way, really, if I read net/ipv6/addrconf.c right. My point is, there has to be something that works; and right now, neither option does. See also the message I sent on linux-netdev to that effect (I never got any response...): http://marc.info/?l=linux-netdev&m=132285083905998&w=4

Unknown said...

Last time I tried to use temporary addresses in Ubuntu (10.10?), my problem was with inbound connections: let's say you have sshd enabled, at first, everything was right. But in some time, I was unable to connect because the client was using a new temporary address which the server was not listening on. What's the planning to solve this kind of issues in Precise? (maybe was misconfiguration from my part)

Thanks!