Ubuntu – Static IPv6 address advertising and IPv6 autoconfig in Debian/Ubuntu

debianipv6networkingUbuntu

I have a network that advertises IPv6 addresses through IPv6 autoconfig. To allow DNS lookups and to have fancy IP addresses, we setup "static" IPv6 addresses through /etc/network/interfaces:

auto eth0
iface eth0 inet dhcp
iface eth0 inet6 static
    address a:b:c:d:e::f 
    netmask 64

Whenever we now connect through IPv6 Linux uses the IPv6 autoconfig address:

 a:b:c:d:21d:60ff:fe4a:479

and not the static IPv6 address:

 a:b:c:d:e::f

A server on the other side only sees the autoconfig address.

Is there a way to force linux (Debian/Ubuntu) to use the static address for outgoing packets? This is especially interesting for reverse DNS and firewall settings.

I don't want to disable the IPv6 autoconfig since I don't have control over the settings the router advertises.

Best Answer

Of course the easiest way to prevent the autoconf addresses from getting used is to prevent the kernel from creating them by doing something like this:

echo 0 >/proc/sys/net/ipv6/conf/eth0/autoconf

Notice how this doesn't require you to reconfigure the router so that it stops emiting advertisements for the prefix.

NOTE in the comments, you talk about /etc/gai.conf, but this is not applicable. This is a configuration file of glibc, not the kernel, and it influences the destination address selection, not the source address selection.

If you still want to have the autoconf addresses present but you don't want them to get used, then read on...

For communications between hosts on the same network

I couldn't find a good way to force the address selection to prefer the static address over the autoconf one. By looking at all of the rules of RFC 3484 none of them were really helpful.

You can try to change the /64 route in your routing table for the connected subnet so that it has a "src" attribute, but it is autogenerated by the kernel when any of the addresses in the subnet are added to the interface and I was unsuccessful in editing it after the fact.

For communications with hosts on the rest of the internet

There are several ways you could influence the address selection for outbound connections. The most obvious is to use the src attribute on routes. For example:

ip route add ::/0 via <gateway> src <desired-source-IP-address>

But maybe your default route comes from a router advertisement message and is automatically inserted by the kernel. In that case it is impossible for you to give a "src" attribute for the route. So here is another method, based on configuring address labels.

By default, in Linux, the kernel's address label table looks like this:

prefix ::1/128 label 0
prefix ::/96 label 3
prefix ::ffff:0.0.0.0/96 label 4
prefix 2001::/32 label 6
prefix 2001:10::/28 label 7
prefix 2002::/16 label 2
prefix fc00::/7 label 5
prefix ::/0 label 1

The idea is that, when initiating a packet to a destination address with label x, the kernel prefers to use a source address with the same label x. So for example, if you send a packet to a host with a 6to4 address (that's an address in 2002::/16), the label for that is 2, and the kernel will prefer to select a 6to4 source address for the outgoing packet, if there is one available.

General IPv6 destinations get label 1 (::/0, which matches everything). Here's what you want to do:

  • Override the label assignment for the local subnet so that addresses on the local subnet get a "martian" label (a label that is not used by anything else). This rule will match the whole subnet so it will be /64.
  • Re-override the label assignment for the desired static address to set it back to 1 (that is, the same label as the rest of the Internet addresses get). This rule is going to match just the specific desired address so it will be /128.

This way, all of those autoconf addresses on the local subnet will get a martian label that won't match up with the label of anything else on the internet, so they will not be preferred, while the label for the desired source address will be 1, so it will match up with the destination address and get chosen.

If your prefix is 2001:db8::/64 and your chosen static address is 2001:db8::aaaa/128 then:

ip addrlabel add prefix 2001:db8::/64 label 99
ip addrlabel add prefix 2001:db8::aaaa/128 label 1

You could add these two commands as up commands in /etc/network/interfaces so that they get executed every time the interface comes up.