On a fairly vanilla install of Ubuntu 12.04 (i.e. current) in an environment with full IPv4 and IPv6 connectivity one may seem some (at first sight) strange things concerning the IPv6 addresses in use.
The network has a single gateway router/server, and provides full IPv6 to the devices in the house using radvd and npd6. Any device on the house network which is IPv6 capable will be able to make full use of IPv6 and IPv4 for Internet access.
On one of those PCs, which has a single ethernet interface, I do a
and see this (bold added by me):
eth0 Link encap:Ethernet HWaddr 00:18:8b:86:f3:52Â
inet addr:192.168.0.3 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: 2a01:e35:8b25:aaaa:2c3f:dfa6:f982:157a/64 Scope:Global
inet6 addr: 2a01:e35:8b25:aaaa:d0c3:1874:60e7:98ae/64 Scope:Global
inet6 addr: 2a01:e35:8b25:aaaa:e5bd:10da:e98d:e06a/64 Scope:Global
inet6 addr: 2a01:e35:8b25:aaaa:218:8bff:fe86:f352/64 Scope:Global
inet6 addr: fe80::218:8bff:fe86:f352/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:364957 errors:0 dropped:0 overruns:0 frame:0
TX packets:12414 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000Â
RX bytes:124450596 (124.4 MB) TX bytes:1833074 (1.8 MB)
Interrupt:19
And I ask myself “What on earth are all those IPv6 addresses doing there….?”
Let’s find out…
Recap of radvd, SLAAC, etc.
Other articles cover the basics of IPv6 in a home network. And here I wrote a bit about radvd.
To briefly recap: with IPv4 devices can have either statically (pre)configured addresses or, very commonly, get their addresses using DHCP. The PC wakes up and calls out “Hi! Any DHCP servers out there?” And one replies and says “Sure – here, use this as your address: 10.10.0.188, and use me as your default gateway and DNS from now on. OK? Good. Come back in 24 hours and check again with me.”
And with IPv6 one can use DHCP6 to do much the same thing. However there is an alternative approach, which to date is more commonly used, at least in smaller networks: SLAAC. Stateless Address Autoconfiguration. Here is not the place to cover the merits of one over the other, nor the sometimes subtle differences. Suffice to say that with SLAAC (in Linux most likely met by way of radvd) a central server or router periodically calls out to any device which cares to listen: “Here is this network’s IPv6 prefix……” (likely a 64-bit prefix) and any device listening can take the prefix and, using the SLAAC rules, create it’s own full 128-bit IPv6 address.
What sort of address gets generated when using SLAAC?
In a simple form, a workstation will take the advertised prefix and tack on a final 64 bits based upon its own network MAC address. Why? Mainly because we know that a MAC address will be globally (and I mean globally as in “the whole world”!) unique and hence any resulting IPv6 address will also be unique, even in the (unlikely) event that the prefix itself was not already.
Here’s an example:
- My router running radvd advertises a 64 bit prefix of 2a01:e35:8b25:aaaa:
- The Ethernet MAC address of that interface is 00:18:8b:86:f3:52
- A PC on my network sees this and configures an address on its interface of 2a01:e35:8b25:aaaa:218:8bff:fe86:f352
The lower 64 bits of the address (0218:8bff:fe86:f352) are what is called an EUI-64 and, together with a 64 bit prefix give us a very nice and usable globally valid IPv6 address.
And indeed if you look back to the output from ifconfig eth0 at the top of this article, of the four global addresses I found on my interface I do indeed see this as one of them. Which all makes sense until I then ask myself where the otherthree global addresses come from.
Privacy
IPv4, as a protocol, Â was never comfortable with the idea of a single interface having more than one address.There were all sorts of ways to allow it to happen of a fashion, but it was always slightly “bolted on”. IPv6 had, from the start, the concept of multiple addresses on an interface being permitted. There are several reasons why this is useful, and here we meet one of them.
Privacy. IPv4, if only by accident, gave us a level of privacy. The need to use NAT so often meant that individual devices in, say, your home network were not directly “visible”.
In the ifconfig eth0 above, the PC has an IPv4 address of 192.168.0.3. There’s a pretty good chance that very many home networks have devices which start 192.168.0…. If you go to an internet-connected device and type
there is no chance at all that you will reach the device on my network though. Those 192.168.x.x addresses are all “private” (there are other ranges too) and only exist behind a public IP address. So from the Internet you cannot reach that PC on my network using simple IPv4 addressing. Which is nice if I don’t want you to reach it.
Similarly, when I connect out from that PC to, say, a web-site, the web site sees the traffic coming only from the public IP address of my network, and not the individual PC’s address (pace HTML cookies and so forth… let’s confine this discussion to IP…)
However with IPv6 we suddenly see that NAT is no longer required. (That’s not to say that it’s not possible – but for our purposes here we can assume it’s “gone”) Indeed this has long been one of the oft-mentioned benefits of IPv6. “No NAT required any more!” Suddenly each device in my home network which has an IPv6 address is “visible” to the world. I can (and should) firewall any network so that it’s protected, but even then, my device is still “visible” to a degree: where previously all the devices on the IPv4 net would be seen on web-sites as coming from the same (NATted) address, now we have a situation where at the IP addressing level each device on my network can be uniquely recognised.
So does this matter? It’s technically and legally subjective. However to a lot of folks the answer is “Yes, it matters.”
Hence the desire to offer some of the privacy that we used to have (albeit as a bit of an unplanned side-effect) with IPv4 NAT, without resorting to the need for NAT itself.
IPv6 Privacy
And so was born so called IPv6 Temporary Addresses. To skip over a lot of technical detail, the concept is:
- Obtain a (64 bit) prefix from somewhere (e.g. radvd sends it out)
- Create a random 64-bit suffix.
- Check that no one else is using the same suffix on my local network.
- Glue them together to give me a semi-random 128-bit IPv6 address.
- Use this for a short period (maybe a few hours or days) and then change it for another one.
Functionally, that’s what and how Temporary Addresses are used in an IPv6Â environment.
Temporary Addresses
So we might now correctly guess that those additional addresses from ifconfig eth0 are actually such Temporary Addresses. And indeed we also remind ourselves that we really really should stop using ifconfig when we’re working with IPv6 (and IPv4 too….. but we never will) and instead so something like this instead:
Which will display something like this:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2a01:e35:8b25:aaaa:d0c3:1874:60e7:98ae/64 scope global temporary dynamicÂ
valid_lft 86211sec preferred_lft 14211sec
inet6 2a01:e35:8b25:aaaa:2c3f:dfa6:f982:157a/64 scope global temporary deprecated dynamicÂ
valid_lft 86211sec preferred_lft 0sec
inet6 2a01:e35:8b25:aaaa:e5bd:10da:e98d:e06a/64 scope global temporary deprecated dynamicÂ
valid_lft 86211sec preferred_lft 0sec
inet6 2a01:e35:8b25:aaaa:218:8bff:fe86:f352/64 scope global dynamicÂ
valid_lft 86211sec preferred_lft 14211sec
inet6 fe80::218:8bff:fe86:f352/64 scope linkÂ
valid_lft forever preferred_lft forever
And indeed we see very clearly that three of those addresses are shown as “temporary“.
Which is nice. But of course we now ask ourselves:
- Why three of them?
- And why are two of them deprecated?
- And all that valid_lft and preferred_lft stuff?
- And, whatever the _lft stuff is, the values keep changing… they decrease, then increase again?
Multiple temporary addresses
First to tackle the “Why more than one?” issue. This will merge into the following “Lifetimes” section, but let’s look at the general situation. Back with DHCP and IPv4 we would periodically (hours or days) check back with the DHCP server and almost always we would be told to keep using the same IPv4 address we already have. So we have to change… nothing. And things carry on happily. In the unlikely event that the IPv4 DHCP server told us to use a different address, it’s messy: we have to, in effect, take down the interface, terminate any connections using it, and bring it up with a new address. Not at all smooth and seamless.
But with IPv6, SLAAC and privacy, we want to use a different address every few hours/days. That’s the whole idea! So rather than disrupt communication every time we wish to use a new IPv6 address we have the concept of multiple addresses. If my system is configured to change the IPv6 address every 24 hours I add a new additional IPv6 global address to the interface every 24 hours. And I then make sure I use it for all new communication, while keeping the old address(es) operating for any connections which are already using them. Hence making the introduction of a new address seamless and non-disruptive. Neat eh?
Lifetimes
Once we are OK with the concept of multiple addresses, and them being deprecated we can probably guess what the valid_lft and preferred_lft values do. We notice that for deprecated addresses the preferred_lft seems to always be zero.Which seems reasonable and logical (i.e. it’s got no “preferred lifetime” left – it’s deprecated – please do not use). And the valid lifetime value? We think a bit and conclude that while the addresses is deprecated and “not preferred” it must stay valid for any existing connection which use it. And hence has  non-zero valid lifetime value. All seems good.
But hang on, there’s something worrying me
Yeah, well, I mentioned it above in passing… Those timer values. The values seems to tick down nicely for a while, as you’d expect, and then increase again for no apparent reason! Oh, and while we’re worrying about stuff, you could also worry about accumulating a vast number of temporary addresses on the interface. If the system stays up for a year will we have hundreds of them configured on the interface…?
Here’s the quick version, then below I’ll go into some nitty grity details for those who want it. The quick version:
- there’s a limit to how many temporary addresses can be created. Probably about 16 (depends on the system). After that the oldest get removed (if not before)
- the increasing (and more intuitive deceasing) timers: when required, they eventually do decrease to zero over the longer term. Basically, they are meant to do what you are seeing. Don’t sweat it.
Technicals!
As ever with such issues, the best source of information are the relevant RFCs. While of course there are dozens which cover different elements of IPv6, the one which most concerns us here is RFC 4941 (note that this RFC supercedes RFC 3041 – and the changes are very pertinent to us here)
RFC 4941 is emminently readable and I suggest doing just that. (BTW I particularly recommend reading section 3.6 Deployment Considerations… Points out that using Temporary Addresses is not always a very good idea at all!) The part of most interest to the “changing timers” is section 3.3. It’s well described in a comment inside the Linux kernel source:
 RFC 4941 section 3.3:
If a received option will extend the lifetime of a public address, the lifetimes of temporary addresses should be extended, subject to the overall constraint that no temporary addresses should ever remain “valid” or “preferred” for a time longer than (TEMP_VALID_LIFETIME) or (TEMP_PREFERRED_LIFETIME – DESYNC_FACTOR), respectively.
The only point which may need clarification there is where it mentions “a received option”. Here it is referring to the periodic router advertisements which the system may receive from e.g. radvd onthe gateway router/server device.
Terms like desync factor are also covered in the RFC – it’s a kind of “fuzz factor” to ensure that systems do not all do address changes at the same time.
So to finish, let’s look at how we check (or, if brave/foolish) change some of these things on a Linux system.
All the good stuff is viewable and changeable via the /proc filesystem (or of course the same things via sysctl). For example:
root@fred:/proc/sys/net/ipv6/conf/eth0# ls accept_dad accept_source_route hop_limit router_probe_interval accept_ra autoconf max_addresses router_solicitation_delay accept_ra_defrtr dad_transmits max_desync_factor router_solicitation_interval accept_ra_pinfo disable_ipv6 mc_forwarding router_solicitations accept_ra_rt_info_max_plen force_mld_version mtu temp_prefered_lft accept_ra_rtr_pref force_tllao proxy_ndp temp_valid_lft accept_redirects forwarding regen_max_retry use_tempaddr
And we see such entries as:
- use_tempaddr
- temp_prefered_lft (n.b. the kernel has spelling errors in it!)
- temp_valid_lft
- max_desync_factor
The key ones of intrerest here are:
Name | Default | Description |
use_tempaddr | System dependent (seems to be 2 on Ubuntu these days…) | We might expect that this is a simple on/off value to enable use of temporary addresses. Yet when we cat it on this system it has the value ‘2’.
|
temp_prefered_lft | 86400 (one day) | Essentially how often we want to change to a new temporary address (with a bit of variation in there…) |
temp_valid_lft | 604800 (seven days) | More or less how long to keep the “old” temporary addresses in use. |
max_addresses | 16 | If set to 0 it disables any limit on the number of temporary addresses. So it is probably a bad idea to set this to zero, or to a high value. |
regen_max_retry | 5 | Number of attempts to generate a temporary address before failing. Goodness knows how you would exceed this in practice. I suppose if you had a very very long prefix in use, and a lot of active devices, then the DAD (duplicate address detection) mechanism might spot a duplicate more times than this value… But lord knows you’d have to try hard to contrive such a network! |
The IPv6 protocol for the Windows Server 2003 family does not create temporary addresses for global address prefixes by default. You can modify this default setting with the netsh interface ipv6 set privacy state=enabled command. For more information, see Netsh commands for Interface IPv6 .