Using IPv6 On A Home Network

Overview

These are my notes on setting on IPv6 on my home network. It's not complete and it's not a tutorial, but I thought I'd post it in case it's helpful.

Recently I noticed that my Time Warner, my ISP, had given my an IPv6 address. Without any special configuration if I google "my ip address" I'm told my IPv6 address. so getting IPv6 to work on the system connected directly to the Internet is easy, but getting IPv6 setup on an internal network such that that internal network has access to the Internet via IPv6 is challenging. That is connection sharing with IPv6 is challenging.

Ways Of Sharing Connections

With IPv6 there is one common way of sharing an Internet connection is with computers on an internal network - NAT (Network Address Translation). NAT uses a table in the kernel of the multi-NIC system that bridges the internal network and the Internet to translate between internal addresses and external addresses. With IPv6 there is more than one way of sharing a connection. Some possible ways:

  • Subnet - An IPV6 subnet prefix from the ISP.
  • NPT - Network Prefix Translation.
  • NAT - Network Address Translation

In those cases where it is feasible to do so the the approach most liked by the IPv6 community is to request a 64 bit subnet from the ISP and to then pick addresses with that prefix. However, I had trouble getting it to work in part because of a limitation where NetworkManager won't pass the "-P" option to dhclient in order to enable prefix delegation and in part because and part because I couldn't get Time Warner to give me a prefix, a problem that other people have had as well.

NPT is a compromise between NAT and subnet in that although it is type of translation at least it is stateless. However, as far as I can tell NPT is not used much on Linux so I did not pursue it.

This left me with plain old NAT, which is somewhat frowned on by the IPv6 community.

NAT Configuration

One advantage of NAT that with regard to iptables firewall rules it works exactly the same way with IPv4 and IPv6. If you use the Firewall tool (the GUI front end to fierwalld) the "Masquerading" tab indicates that it only applies to IPv4. However, you can do exactly the same thing for IPv6 by clicking the "Rich Rules" tab selecting "ipv6" for the family and then "masquerade" for the element.

radvd And DHCPv6

When configuring and IPv6 network for the first time it's surprising that the DHCPv6 server does not have a means of configuring a default gateway. With IPv6 assuming functionality beyond configuring systems with stateless addresses is needed the configuration normally done by DHCP in IPv4 is divided between the radvd service and the DHCPv6 service. When using DHCPv6 one way of configuring the radvd service so that it doesn't offer the stateless IPv6 address ("AdvAutonomous off") but instead tells the client to get that information from the DHCPv6 service ("AdvManagedFlag on" and "AdvOtherConfigFlag on"). Here's my radvd.conf:

#    Deleted default values other than M*RtrAdvInterval
interface p4p1
{
    AdvManagedFlag on;
    AdvOtherConfigFlag on;
    AdvSendAdvert on;
    MinRtrAdvInterval 30;
    MaxRtrAdvInterval 100;
    prefix 4567::/64
    {
        AdvAutonomous off;
    };
};

Selecting An IPv6 Prefix

It may be tempting to use a ULA (Unique Local Address) which has prefix fc00::/7. However, one challenge with ULA addresses are often treated specially such that the interfaces IPv4 address is preferred over the IPv6 address. Consider the labels in /etc/gai.conf (configuration file for getaddrinfo()):

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

The documentation for gai.conf is hard to understand, but my understanding, which is based on reading the source code, is that it does the following:

  • The destination IPv6 address is determined.
  • The source IPv6 address that goes with destination IPv6 address is determined.
  • The labels of the source and destination IPv6 addresses are determined by considered the table in gai.conf shown above.
  • If the source an destination have the same label they are considered to be the same type of address, which is preferred.
  • If the destination address is not preferred the system may try to use IPv4 address instead.

Presumably the reasoning is that routing from an IPv6 address of one type to another is likely to have problems. However, this makes it so that ULA addresses are unlikely to be used even when NAT has been setup such that they really are routable to the outside world. It helps somewhat to edit /etc/gai.conf, but some some software, such as Google Chrome, seem to have the logic hard coded regardless of /etc/gai.conf.

In order to avoid the issues I picked a prefix that is currently reserved. I choose 4567::/64. It won't collide until addresses are allocated from 4000::/16, which is currently reserved. An address that begins with precisely 4567:0000:0000:0000 would have to be allocated for it to collide with my internal network.

Ideally there would be a address range like the current ULA except that it would net be treated specially by any software.

Selecting An IPv6 Suffix

For ULA address it's recommended to use random bytes for the suffix in order to avoid collisions when and if networks are combined. However, since I'm not likely to combine my network with another simplicity took precedence over that concern for me. I simply took the last octet from my 10.11.12.0/24 IPv4 network and I used that for my suffix. For example, here are the addreseses for one of my systems:

p4p1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    inet 10.11.12.11  netmask 255.255.255.0  broadcast 10.11.12.255
    inet6 4567::11  prefixlen 64  scopeid 0x0<global>

Miscellaneous

I noticed that with Linux systems in my IPv6 network update /etc/resolv.conf more frequently via NetworkManager possible in response to router advertisements. This normally would not be a problem since NetworkManager effectively owns /etc/resolv.conf. However, VPN clients, such as openconnect, also attempt to write to /etc/resolv.conf . So, the name servers written by the VPN client get overwritten. For lack for a better solution I set the SELinux type of /etc/resolv.con so that NetworkManager can't write to /etc/resolv.conf while the VPN client is running. The relevant portion of my wrapper script for my VPN client looks like this:

function cleanup()
{
    echo "Restoring type of /etc/resolv.conf"
    restorecon /etc/resolv.conf
}
trap cleanup EXIT
 
# Set the type to something NetworkManager can't change.
chcon -t etc_t /etc/resolv.conf
 
openconnect ...