IPv6-only network at home

01 Dec 2015

v6 only setup using EdgeOS, Debian, TAYGA and PowerDNS

This post describes how I got a IPv6-only network up and running in my home network. Some details are left out for clarity (VLANs for example), but all essential info should be here.

Topology

For sake of overview, a rough sketch of what the network looks like. Key here is the fact that my server is doing the DNS64+NAT64, and not my router/gateway (which is a Ubiquiti EdgeRouter PoE). So even if you don't have an EdgeRouter, or something similar (think Vyatta/VyOS, or a Linux box doing all your gateway things), you should be able to get a setup like mine in working order.

The LAN node is an abstraction of a Unifi UAP-Pro, connected to the ERPoE.

     Internet
        |
        |
        ERPoE <---> LAN
      radvd         /  \
      dhcpd3       /    \
                  /      \
              server    clients
            pdns
            tayga

The remainder of this post is ordered according to 'if I do things in this order I hopefully break the least number of things'. Maybe.

PowerDNS with the power of LUA

First, get DNS64 up. As your clients will only be aware of v6 things, they will always request AAAA records. DNS64 will translate those AAAA into A requests if there is no AAAA available. The answer will be special v6 address within your specified range, which will be leading into the NAT64. Again, in this setup the DNS64 is running on the server, not on the gateway.

Credits to the PowerDNS guys for making things easy using lua. This is copied directly from their documentation:

function nodata ( remoteip, domain, qtype, records )
         if qtype ~= pdns.AAAA then return pdns.PASS, {} end  --  only AAAA records
         setvariable()
         return "getFakeAAAARecords", domain, "2001:db8:1000:64::"
end

Make sure you load it in recursor.conf:

lua-dns-script=/etc/powerdns/scripts/dns64.lua

Now start PowerDNS via systemctl start pdns-recursor (you did upgrade to Jessie didn't you?) and test with a v4-only domain:

$ dig AAAA ipv4.whatismyv6.com +short @ip-of-your-server
2001:db8:1000:64::4275:2fd6

Hooray, now move on.

NAT64 using TAYGA

Also on the server, install and configure TAYGA to do the NAT64 translation. An example /etc/tayga.conf that works in conjuction with the DNS64 configuration above, could look like this:

tun-device nat64
ipv4-addr 10.64.0.1
prefix 2001:db8:1000:64::/96
dynamic-pool 10.64.0.0/24
data-dir /var/spool/tayga

Now starting tayga via systemctl start tayga should set up an interface called nat64 and some routes:

$ ip route:
    (...)
    10.64.0.0/24 dev nat64  scope link 
    (...)

$ ip -6 route:
    (...)
    2001:db8:1000:64::/96 dev nat64  metric 1024 
    (...)

Think about how far we are now, and notice we miss one crucial thing on the server for this specific topology. Requests to v4-domains will be translated into the 4-in-6 address in your defined 2001:db8:1000:64::/96 range, and the server will translate those into real v4 and use its dual-stack capabilities and send it out over v4 towards the gateway. If tayga was running on the gateway, you would MASQUERADE it there, but now we need to do that on the server. Otherwise, the return traffic will not end up at our server, where it should go into the nat64 interface, to be translated back into v6 again. Also, make sure that forwarding is enabled. You might opt for a less rigorous approach instead of conf/all, but this depends on your exact setup.

N.B.: the 192.168.10.10 here is the LAN IPv4 address of the server on its interface eth0.

# iptables -t nat -A POSTROUTING -o eth0 --source 10.64.0.0/24  -j SNAT --to-source 192.168.10.10
# echo 1 >  /proc/sys/net/ipv4/conf/all/forwarding
# echo 1 >  /proc/sys/net/ipv6/conf/all/forwarding

Static routes in the EdgeRouter

Traffic from the clients heading towards the NAT64 needs to end up at the server running that NAT64, so the router needs some (static) routes to get the packets out via the right interface. In your EdgeRouter, add a static route for the NAT64-prefix, and set the next-hop to the IPv6 address of the server:

set protocols static route6 '2001:db8:1000:64::/64' next-hop '2001:db8:1000:1::10' distance 1

Finally, Stateless DHCPv6 + SLAAC

If everything is in place, you can provide your clients with a prefix (via Router Advertisements, so SLAAC), and information about the nameserver (via stateless DHCPv6). For EdgeOS, the following should do, although a bug(?) currently causes some unexpected behaviour:

set interfaces ethernet eth1 address '2001:db8:1000:1::1/64'
set interfaces ethernet eth1 ipv6 router-advert prefix '2001:db8:1000:1::/64' autonomous-flag true
set interfaces ethernet eth1 ipv6 router-advert managed-flag false
set interfaces ethernet eth1 ipv6 router-advert other-config-flag true
set interfaces ethernet eth1 ipv6 router-advert send-advert true

So, give the interface an IPv6 address, and enable Router Advertisements on it. Make sure it plays nicely with the stateless DHCPv6, so don't forget to set the right flags.

set service dhcpv6-server shared-network-name WLAN name-server '2001:db8:1000:1::10'
set service dhcpv6-server shared-network-name WLAN subnet '2001:db8:1000:1::1/128' domain-search local

Point to the server as being the name-server, as PowerDNS is running overthere. Furthermore, make sure the dhcpv6 process will be listening on the right interface by specifying the /128. The domain-search local is possibly misplaced in the resulting config file: please keep an eye on this thread for further info.

Now get connected

An example netctl profile on Arch Linux could look like this:

Interface=wlp3s0
Connection=wireless
Security=wpa

ESSID=my-cool-v6-only-network
Key=hunter64

IP=no
IP6=dhcp-noaddr
DHCP6Client=dhclient # dhcpcd doesn't support dhcp-noaddr
TimeoutDAD=10
TimeoutDHCP=30

Maybe it takes a few tries and some tweaks for your specific setup, but once you think it's working, you could use the SixOrNot pugin for Firefox (or something similar) to check whether websites are being served over native v6, or your NAT64 range. Enjoy your v6-only network! Unfortunately, it's still a good idea to have a back-up dual-stack config at hand, as some applications use hard-coded IPv4 literals, and those will simply not work.

Some final notes

While switching between the dual-stack network and the v6-only one, I ended up in a situation where my laptop (running Arch Linux) did not generate a link-local v6 address upon interface up. The dhcp client needs a link-local address, so things broke. I've not been able to reproduce this behaviour yet.