Running IPv6 in practice

Posted by gribozavr on Wed 3 Feb 2010 at 08:39

Many articles tell us about about initial setup of IPv6 and are completely silent about what to do next. Thus, I wanted to share my own experience.

Register a tunnel

Go to Hurricane Electric and register. Enter your external IPv4 address and choose a tunnel endpoint close to you. You will be allocated a /64 IPv6 address block for the tunnel that has two special addresses: 1 is server, 2 is client.

If you have a LAN and you want to configure IPv6 on each computer in LAN, request a routed /64 IPv6 block. If you have multiple LANs behind your router, then request a routed /48 block. All allocated networks will be routed through your router.

Configure IPv6

Now you need to configure a tunnel interface he-ipv6 (you can choose any name). Append the following stanza to /etc/network/interfaces (in place of the variables put your external IPv4 and tunnel IPv6 addresses):

auto he-ipv6
iface he-ipv6 inet6 v4tunnel
        address $CLIENT_IPv6
        netmask 64
        endpoint $SERVER_IPv4
        local $CLIENT_IPv4
        gateway $SERVER_IPv6
        ttl 64

Now bring the interface up and test the connection:

# ifup he-ipv6
# ping -n

DNS and Google

Unfortunately, is the Google domain that has AAAA records in public DNS. Because of too many misconfigured computers out there people could experience delays while using Google's services. The delay appears when a misconfigured client waits for a reply from an unreachable IPv6 server.

But for ISPs that have deployed IPv6 and are "capable enough" Google can provide a DNS server with AAAA records. Hurricane Electric has made the required arrangements. Their DNS server is 2001:470:20::2. You can either add that server to /etc/resolv.conf or configure a caching DNS server, such as bind and win a bit of speed.

I recommend doing the latter. There are two approaches to configure bind in this situation: you can either resolve only Google's domains through HE's server (and other domains through you ISP's server) or you can use HE's server for everything. I don't have a list of Google's domains, so we'll set up HE's server as a forwarder for bind.

Install package bind9 and edit /etc/bind/named.conf.options:

acl mynetworks {
  localhost;;           // your LAN via IPv4
  2001:XXXX:XXXX:XXXX::/64; // your tunnel IPv6 /64
  2001:XXXX:XXXX:XXXX::/64; // your routed IPv6 /64
  2001:XXXX:XXXX::/48;      // your routed IPv6 /48, if it exists

options {
  directory "/var/cache/bind";

  allow-query { mynetworks; };

  forwarders {

  auth-nxdomain no;
  listen-on-v6 { any; };

Restart bind and test it:

# dig +short @::1 AAAA
And configure your system to use it: enter in /etc/resolv.conf:
nameserver ::1

If you don't have a LAN, skip to firewall configuration section.


It is easiest to use stateless autoconfigutation to set up IPv6 on LAN. It is like DHCP, but the server doesn't keep track of addresses that were given out. The idea is the same: you give a server a /64 IPv6 net and the server offers clients to configure themselves for this network. Clients will get unique addresses based on their hardware Ethernet address.

Let eth0 be LAN interface and eth1 -- ISP interface. So far only he-ip6 interface has a global IPv6 address. eth0 also needs an IPv6 address so that clients would be able to talk to server. We could make a bridge of he-ipv6 and eth0 and use a single tunnel /64 network for everything, but that would be a more complex configuration than we can achieve. Or we could split a /64 into two /65's, but then stateless autoconfiguration won't work (and it is forbidden by RFC to have prefixes longer than 64 in global unicast address space, although it would technically work). That's why you've requested an additional routed /64 network -- it will be used on LAN. Let the routed /64 network be 2001:XXXX:YYYY:ZZZZ::/64.

If you have multiple LANs behind your router, then you should have requested a /48 network. CIDR principles apply to IPv6 the same way as in IPv4. You can subnet your /48 into 65536 /64's. That is, if you were assigned 2001:XXXX:YYYY::/48, then you can use 2001:XXXX:YYYY:1::/64, 2001:XXXX:YYYY:2::/64 and so on for every subnet. It is trivial to modify the following example to work in a multiple-LAN situation, so I won't discuss this further.

So, 1 LAN behind your router and its network subnet is 2001:XXXX:YYYY:ZZZZ::/64. Append to /etc/network/interfaces:

iface eth0 inet6 static
        address 2001:XXXX:YYYY:ZZZZ::1
        netmask 64

Install radvd package (stateless autoconfiguration daemon) and create its configuration file /etc/radvd.conf:

interface eth0
  AdvSendAdvert on;
  MaxRtrAdvInterval 30;

  prefix 2001:XXXX:YYYY:ZZZZ::1/64
    AdvOnLink on;
    AdvAutonomous on;
    AdvRouterAddr off;
    AdvValidLifetime 300;
    AdvPreferredLifetime 120;

Turn on forwarding for IPv6 in /etc/sysctl.conf:

And load new settings:
# sysctl -p

Now restart radvd:

# invoke-rc.d radvd restart
After this, all IPv6-capable computers on LAN will get an IPv6 address and gateway automatically (of course, if accepting route advertisements is enabled, but that is default). You can monitor the process on server with
# radvdump
and on client with
$ ip -6 addr

Stateless autoconfiguration does not deal with DNS settings, so you'll have to configure the resolver on clients manually (or via DHCP for IPv4, you should probably have that already).


Automatically configured IPv6 addresses are based on hardware Ethernet addresses and look like this: 2001:db8:d4b6:1:215:f2ff:fe55:2d85 -- hard to work with, impossible to remember. Multicast DNS comes to the rescue. Avahi is an open-source implementation of multicast DNS.

Install avahi-daemon and avahi-utils on every computer in LAN. Ensure that /etc/avahi/avahi-daemon.conf has the following lines to make Avahi will care about IPv6:

Restart avahi-daemon if needed. After that all computers in LAN will get names based on their hostnames, like hostname.local. But, by default these names will resolve into IPv4 addresses. To make IPv6 default, edit resolver configuration file /etc/nsswitch.conf. Replace line
hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4
hosts: files mdns_minimal [NOTFOUND=return] dns mdns

You can list all "records" in multicast DNS with:

$ avahi-browse -r -a

Squid and IPv6

If you were using squid, of course you'll want it to work properly with IPv6 sites, too. Squid got proper IPv6 support only around 3.1.0.x version. Currently 3.1 is beta, so you can find it in experimental. For me it works great for 4 months already, and I hope it will for you too. Just add all your allocated IPv6 blocks to ACLs as you did with IPv4.

IPv6 firewall

In IPv4 days NAT was enough to protect unsuspecting client computers from bad guys on the Internet. But now all client computers have got global routable IPv6 addresses and they need to be protected. The protection boils down to rejecting all incoming connections to the client subnet except a to few allowed ports.

ip6tables is not much that different from iptables, it is even easier: no NAT, no port forwarding. Nevertheless, after I started writing a second firewall script I felt that I'm doing duplicate work. I tried to combine IPv4 and IPv6 rules in a single script that calls both iptables and ip6tables.

The script itself is targeted at a very common network configuration with a single Internet connection and a single LAN behind the router. IPv4: packet filtering for the firewall host itself, NAT, port forwarding. IPv6: packet filtering for the firewall host and the LAN. Here's the result: rc.firewall (there is local copy here too).

This article can be found online at the Debian Administration website at the following bookmarkable URL (along with associated comments):

This article is copyright 2010 gribozavr - please ask for permission to republish or translate.