How to setup an IPv6-only network with NAT64, DNS64 and Shorewall

Goal

The goal of this article is to help people to set up a network that is IPv6 Only (except for the gateway) and does allow the users to access IPv4 servers beyond the gateway.

Overview

If you follow the news surrounding the IPv4 exhaustion, you will now that IPv4 is running out of space rapidly (currently Ripe is allocating the last /8 address space). So, it’s time to start thinking about moving to IPv6.

I have been using a 6-in-4 tunnel from Sixxs for a couple of years now, using this i have set up a dual stack network with my own /48 subnet. This setup is fun and made it possible for me to test IPv6 in real life.

I’ve been using this setup for a while now, and thou it’s an improvement on getting ready for IPv6, it still has an IPv4 network as well. The ultimate goal should be to use only IPv6 in my internal network. The downside of such a network is the fact that i would be unable to reach ‘old’ IPv4 servers which haven’t got an IPv6 address.

To solve this, i decided to configure an IPv6 only network in a test environment, using NAT64 and DNS64. DNS64 basically provides IPv6 addresses for hostnames which only return an IPv4 address, using a prefix. NAT64 accepts connections to those special IPv6 addresses and translates the connection to a IPv4 connection. It’s doing the same thing as normal NAT, translating IP addresses, just across different IP versions.

I’m using this guide as a form of documentation. I might go a bit fast through a couple of sections, but that’s mainly because i assume you are able to configure a basic Bind9 server or Shorewall setup.

It’s also important to note that i will not provide exact commands to install a package, but all of the packages should be available in most package systems (aptitude/apt, yum, …).

Initial setup

Lets start with making an overview of my setup, and what information you should need to set this up.

My gateway is a Ubuntu 12.04 LTS server which is connected to 2 networks and has a Sixxs connection using AICCU, which is configured to start at boot. In total this gives me 3 interfaces (and loopback, but we’ll disregard that).

Interfaces configurations:

List of software used. This contains only daemons specific for this guide:

I’ll assume that your gateway is able to connect to the internet using DHCP on the eth0 interface, which provides you with an IP(v4) from your ISP and that your Sixxs tunnel is configured.

Bind9

Configure bind9 as you like, just make sure you have configured forwarders that can be used and recursion is enabled.

Shorewall

Make sure IP_FORWARDING=On. Here are my basic configuration files:

Zones

#ZONE   TYPE    OPTIONS         IN OPTIONS              OUT OPTIONS
fw      firewall
net     ipv4

Interfaces

#ZONE    INTERFACE      BROADCAST       OPTIONS
net      eth0           detect          dhcp,tcpflags,routefilter,nosmurfs,logmartians

No need to add eth1, as it does not have a IPv4 address.

Policy

###########################################################################
#SOURCE         DEST            POLICY          LOG             LIMIT:BURST
#                                               LEVEL
net             $FW             DROP            info
$FW             net             ACCEPT
# CATCH ALL
all             all             REJECT          info

For security reasons i drop everything coming in from the dangerous internet…

Shorewall6

As with Shorewall, make sure IP_FORWARDING=On. The purpose of this configuration is to block all IPv6 traffic coming in from the internet, but allow clients connected to the gateway through the internal network, to access the internet through the Sixxs tunnel.

Basic configuration files:

Zones

#ZONE                   DISPLAY         COMMENTS
fw                      firewall
net                     ipv6
loc                     ipv6

Interfaces

#ZONE    INTERFACE      BROADCAST       OPTIONS
net      sixxs           detect          tcpflags,nosmurfs,forward=1
loc      eth1            detect          tcpflags,forward=1

Policy

###########################################################################
#SOURCE         DEST            POLICY          LOG             LIMIT:BURST
#                                               LEVEL
$FW             net             ACCEPT
$FW             loc             ACCEPT
loc             net             ACCEPT
loc             $FW             ACCEPT
net             $FW             DROP            info
net             loc             DROP            info
# CATCH ALL
all             all             REJECT          info

Again i block everything coming in from the dangerous internet.

radvd

radvd is used to provide stateless configuration for IPv6 interfaces. After you acquired your subnet from Sixxs and have configured your tunnel, you can setup radvd to provide your clients with the information they need to access the IPv6 network.

My configuration:

interface eth0
{
        AdvSendAdvert on;
        prefix 2001:1d3:7f2:10::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr on;
        };
};

Configuring DNS64

Configuring DNS64 is not that hard, you just need to tell Bind  that it has to return a special AAAA-record if a client from a specific range requests the IP address of a hostname that has no AAAA record. This AAAA-record is constructed by bind, using a prefix. When a client tries to connect to an IP starting with the prefix, it will be forwarded (through routing) to the NAT64 setup.

Prefix

First of, you should decide on a prefix to use. This prefix must be part of your personal /48 subnet (so it doesn’t interfere with other possible real IP addresses). You must at least commit a /96 subnet to this prefix.

As 2001:1d3:7f2::/48 is the subnet provided by Sixxs to me, i decided to use 2001:1d3:7f2:ffff::/96 as my prefix.

radvd configuration

We need to make the clients on the network aware of the IPv6 DNS server on the network, so change your /etc/radvd.conf  and add the RDNSS option :

interface eth0
{
        AdvSendAdvert on;
        prefix 2001:1d3:7f2:10::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr on;
        };
        RDNSS 2001:1d3:7f2:10::1
        {
        };
};

Bind configuration

Now we need to change named.conf.options to contain the following section (inside options, for instance after your forwarders):

        dns64 2001:1d3:7f2:ffff::/96 {
                clients {
                       2001:1d3:7f2:10::/64;
                };
        };

The clients option makes sure that only clients on the network connected to eth0 can use the DNS64 service.

Configuring NAT64

To configure NAT64, you have to install an extra daemon: Tayga. Tayga creates a new interface on your server which basically is an internal tunnel through which connections to your prefix network are routed and translated to IPv4 connections. This means both firewalls (Shorewall and Shorewall6) need to be aware of this interface.

Tayga configuration

You will have to make some changes in the Tayga configuration (/etc/tayga.conf), here are the settings i have changed and use:

tun-device nat64
ipv4-addr 192.168.10.1
prefix 2001:1d3:7f2:ffff::/96
dynamic-pool 192.168.10.0/24

Tayga needs an IPv4 IP address as it needs to communicate with the IPv4 network, it also needs an IPv6 address, but it determines that itself.

The dynamic-pool option is used to select IP addresses for the IPv6 clients. So each IPv6 client that wants to connect to an IPv4 server gets an IPv4 address linked to it in Tayga (so not on the client, only for internal NAT purposes). If you use a /24 subnet, you can basically have 254 clients connecting to IPv4 servers simultaneously. If you need more, you are allowed to use bigger subnets. Just make sure you use the ranges specified by Ripe for internal use.

Shorewall configuration

I choose to configure shorewall in a similar fashion as with the IPv4 trafic, so all traffic from internet is blocked, all traffic to the internet is allowed. You need to make Shorewall aware of the nat64 interface, as it needs to allow IPv4 traffic to go to and from it, otherwise the translation won’t work.

These are the changes i made to the Shorewall (IPv4) configurations:

Zones

#ZONE   TYPE    OPTIONS         IN OPTIONS              OUT OPTIONS
fw      firewall
net     ipv4
nat64   ipv4

Interfaces

#ZONE    INTERFACE      BROADCAST       OPTIONS
net      eth0           detect          dhcp,tcpflags,routefilter,nosmurfs,logmartians
nat64    nat64          detect          dhcp,tcpflags,routefilter,nosmurfs,logmartians,routeback

No need to add eth1, as it does not have a IPv4 address.

Policy

###########################################################################
#SOURCE         DEST            POLICY          LOG             LIMIT:BURST
#                                               LEVEL
net             $FW             DROP            info
net             nat64           DROP            info
$FW             net             ACCEPT
$FW             nat64           ACCEPT
nat64           net             ACCEPT
nat64           $FW             ACCEPT
# CATCH ALL
all             all             REJECT          info

Shorewall6 configuration

You need to make Shorewall6 aware of the nat64 interface, as IPv6 traffic needs to go to and from it.

These are the changes i made to the Shorewall6 (IPv6) configurations:

Zones

#ZONE                   DISPLAY         COMMENTS
fw                      firewall
net                     ipv6
loc                     ipv6
nat64                   ipv6

Interfaces

#ZONE    INTERFACE      BROADCAST       OPTIONS
net      sixxs           detect          tcpflags,nosmurfs,forward=1
loc      eth1            detect          tcpflags,forward=1
nat64    nat64           detect          tcpflags,forward=1

Policy

###########################################################################
#SOURCE         DEST            POLICY          LOG             LIMIT:BURST
#                                               LEVEL
$FW             net             ACCEPT
$FW             loc             ACCEPT
$FW             nat64           ACCEPT
loc             net             ACCEPT
loc             $FW             ACCEPT
loc             nat64           ACCEPT
nat64           net             ACCEPT
nat64           $FW             ACCEPT
nat64           loc             ACCEPT
net             $FW             DROP            info
net             loc             DROP            info
net             nat64           DROP            info
# CATCH ALL
all             all             REJECT          info

That should do it. If you restart the services (bind9, radvd, tayga, shorewall and shorewall6), your gateway is ready to provide a IPv6 only network with connectivity to internet, both IPv6 (through the Sixxs tunnel) and IPv4 (through your ISP’s connection).

Clients

You do need to prepare your clients to work on this network. This setup has been created with Linux clients in mind, but i’ll try and give an overview of what needs to be changed if you want to support Windows (7/8) and Mac OS X.

Linux clients

Linux clients need to install the RDNSSD daemon. This daemon will use the RDNSS information provided by radvd and change the /etc/resolv.conf file to include it. This way you won’t need to configure the resolv.conf yourself.

If you do not want to use the RDNSSD daemon, you will have to change your setup and use DHCPv6, which would mean you have to install the DHCPv6 daemon on the gateway and configure it, and install the DHCPv6 client on the client (which is in most cases part of the standard DHCP client of your distribution).

Mac OS X

From Mac OS X Lion on, Mac OS X is able to accept the RDNSS information from radvd. DHCPv6 is also supported. So there is no need for further configuration.

Windows

Windows Vista, 7 & 8 do not have support for RDNSS, you can provide this by installing rdnssd-win32. They do support DHCPv6, however, so it might be easier to just configure that.

Windows XP is just unable to use IPv6 without installing Dibbler. This tool provides Windows XP with DHCPv6 support.

Final thoughts

I kept my configuration simple on purpose, so if you’d like to add complex rules and policies to Shorewall(6) to protect your network, you can do so as you normally would. The only thing to remember is the flow of traffic for IPv6-Only clients to a IPv4-Only server:

Client IPv6 -> DNS call target (IPv4-only) hostname -> GW IPv6
GW IPv6 -> DNS result (IPv6 address linked to IPv4 target server) -> Client IPv6
Client IPv6 -> packet -> GW IPv6 
GW IPv6 -> routes to NAT64 -> GW NAT64 IPv6
GW NAT64 IPv6 -> NAT64 processing -> GW NAT64 IPv4
GW NAT64 IPv4 -> uses standard NAT -> GW IPv4 (external)
GW IPv4 (external) -> packet -> Target IPv4
Target IPv4 -> reply -> GW IPv4 (external)
GW IPv4 (external) -> Reverses NAT -> GW NAT64 IPv4
GW NAT64 IPv4 -> reverse NAT64 processing -> GW NAT64 IPv6
GW NAT64 IPv6 -> routes to GW (internal interface) -> GW IPv6
GW IPv6 -> packet -> Client IPv6

You need to remember that flow, restricting any traffic between (in this articles case) eth0 and nat64 and eth1 and net64 can break your nat64 setup.