nat64

NAT64/DNS64 in Gentoo

It was interesting when I posted a news article to the WIA regarding IPv6, how quickly it got shot down by “experts”.

A recent addition to our network was a 2008-model Apple MacBook, which I have dual-booting Gentoo and MacOS X 10.6.7 nicely.  One quirk of this particular laptop though, is that it will, when running its native OS, intermittently drop off the IPv4-only network.

The first tip-off to this is usually things like Skype ceasing to work.  Then I’ll notice DNS isn’t resolving (DNS is IPv6-accessible, but not many systems support RDNSS).

As a work-around to the problem, and also for my own self-education, I decided I’d have a crack at getting NAT64 and DNS64 to work.  What are they exactly?

NAT64 as the name suggests, is a variant of NAT that translates IPv6 to IPv4.  In doing so, allowing my MacBook that’s just disappeared from the face of the IPv4-only world, to still access the IPv4-part of the Internet.

DNS64 is a service that synthesizes AAAA records for host names that do not provide one.

The two work together to provide Internet access to an IPv6 only host.

What you will need to know

Make sure you have the following information on-hand.  I’ll use the following examples:

  • Your server’s IPv4 address on the local network: e.g. 192.168.0.1/24
  • IPv4 NAT address pool: This must not overlap with your existing networks.
    Examples use 192.168.255.0/24, I used 172.16.24.0/24
  • TAYGA’s tunnel IPv4 address: This will be the first address in the above subnet (i.e. 172.16.24.1)
  • Your network’s IPv6 subnet: e.g. 2001:dead:beef:1200::/56
  • IPv6 NAT address pool: This needs to be a non-overlapping portion of your address space.  In my case, I’m borrowing a /56 from AARNet, and I used a /64 for this, setting the lower 8-bits of the prefix to 0x64.  It only needs to be /96 in size.
    Example used: 2001:dead:beef:1264::/96

NAT64 setup

To get NAT64 working; start by installing TAYGA.  This is a userspace daemon uses the TUN device to route between IPv4 and IPv6.  On Gentoo, begin by running emerge tayga.  (You may need to keyword it.)

This installs the binary, but crucially, it comes with no init scripts.  You will need to create one yourself like this:

#!/sbin/runscript
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/sys-libs/gpm/files/gpm.rc6,v 1.12 2004/07/15 01:02:02 agriffis Exp $

depend() {
    need gw6c net.nat64
}

start() {
    ebegin "Starting tayga"
    start-stop-daemon --start --quiet -p /var/run/tayga.pid \
        --exec /usr/sbin/tayga -- \
        -u nobody -g nogroup \
        --pidfile /var/run/tayga.pid
    eend ${?}
}

stop() {
    ebegin "Stopping tayga"
    start-stop-daemon --stop --quiet --pidfile /var/run/tayga.pid
    eend ${?}
}

Now, edit /etc/tayga.conf, using /etc/tayga.conf.example as a guide.  There are comments provided.  The following are the settings I used (with the above addresses):

#
# TAYGA's IPv4 address.  This is NOT your router's IPv4 address!  TAYGA
# requires its own address because it acts as an IPv4 and IPv6 router, and
# needs to be able to send ICMP messages.  TAYGA will also respond to ICMP
# echo requests (ping) at this address.
#
# This address can safely be located inside the dynamic-pool prefix.
#
# Mandatory.
#
ipv4-addr 172.16.24.1
# ... etc ...
#
# The NAT64 prefix.  The IPv4 address space is mapped into the IPv6 address
# space by prepending this prefix to the IPv4 address.  Using a /96 prefix is
# recommended in most situations, but all lengths specified in RFC 6052 are
# supported.
#
# This must be a prefix selected from your organization's IPv6 address space
# or the Well-Known Prefix 64:ff9b::/96.  Note that using the Well-Known
# Prefix will prohibit IPv6 hosts from contacting IPv4 hosts that have private
# (RFC1918) addresses, per RFC 6052.
#
# The NAT64 prefix need not be specified if all required address mappings are
# listed in `map' directives.  (See below.)
#
# Optional.
#
prefix 2001:dead:beef:1264::/96
#
# Dynamic pool prefix.  IPv6 hosts which send traffic through TAYGA (and do
# not correspond to a static map or an IPv4-translatable address in the NAT64
# prefix) will be assigned an IPv4 address from the dynamic pool.  Dynamic
# maps are valid for 124 minutes after the last matching packet is seen.
#
# If no unassigned addresses remain in the dynamic pool (or no dynamic pool is
# configured), packets from unknown IPv6 hosts will be rejected with an ICMP
# unreachable error.
#
# Optional.
#
dynamic-pool 172.16.24.0/24
# ... etc ...

Now, having done this… you just need to make sure the nat64 device gets created and initialised by openrc.  In /etc/conf.d/net:

# NAT64 configuration for TAYGA
config_nat64=(
   "192.168.0.1/24"
   "2001:dead:beef:1264::1/64"
)
routes_nat64=(
        "172.16.24.0/24"
        "2001:dead:beef:1264::/96"
)

preup() {
        case ${IFACE} in
                nat64)
                        /usr/sbin/tayga --mktun
                        ;;
        esac
}

Now, symlink /etc/init.d/net.lo to /etc/init.d/net.nat64, start the tayga service, and you should find that you can ping e.g. 2001:dead:beef:1264::8.8.8.8 (8.8.8.8 is Google DNS).

DNS64 setup

All good and well if you know the IP addresses, but most people don’t.  Now emerge totd.  Use /usr/share/doc/totd-VERSION/totd.conf.sample.bz2 as an example for configuring /etc/totd.conf:

; $Id: totd.conf.sample,v 1.9 2003/09/17 15:56:20 dillema Exp $
; Totd sample configuration file
; you can have multiple forwarders, totd will always prefer
; forwarders listed early and only use forwarders listed later
; if the first ones are unresponsive.
forwarder 2001:dead:beef:1234::1 port 65053
forwarder 127.0.0.1 port 65053
forwarder 8.8.8.8 port 53
forwarder 8.8.4.4 port 53

; you can have multiple prefixes or even no prefixes at all
; totd uses them in round-robin fashion
prefix 2001:dead:beef:1264::
; the port totd listens on for incoming requests
port 53
; the pidfile to use (default: /var/run/totd.pid)
pidfile /var/run/totd.pid
; interfaces totd listens on (UDP only for now and not on Linux)
; If left out totd will only open wildcard sockets.
;interfaces br0
; 6to4 reverse lookup
stf

In my case, I have a local caching name-server (BIND), which I’ve moved to port 65053. The trick-or-treat daemon now sits on port 53 where the rest of the network expects it. You can now start the totd service, point your /etc/resolv.conf files to it, and everything should Just Work.

Testing

Easiest way is to shut off IPv4, and set up /etc/resolv.conf on your client with the IPv6 address of your server running totd.  You should now be able to browse IPv4-only sites as if IPv4 were running.  I achieved this test by plugging into Ethernet, turning off wicd (it kept wanting to start-up dhcpcd), then manually bringing the interface up and configuring /etc/resolv.conf.