> Home > News Index

2008-08-25 - Configuring IPv6 using AARNet's free broker

You can obtain IPv6 connectivity in Australia using the AARNet IPv6 Migration Broker if your ISP does not already provide IPv6. As at August 2008, only Internode is known to provide consumer level IPv6 access.

For Australian users who cannot obtain IPv6 through your ISP, the AARNet IPv6 tunnel is probably the next lowest latency choice. These instructions describe setting up IPv6 with linux over a consumer DSL connection with a dynamic IPv4 address (i.e. every time you connect you get a different IP address) and NAT (Network Address Translation) on the DSL modem.

With IPv6 you can get a static address (well, 2^64 or more static addresses) and it's quite useful if you run a home network and want to provide access to devices within the network, from outside. That is, so long as the outside client has IPv6 (the chicken-and-egg problem).

Certain assumptions are made in this document - like installed software or an IPv6 enabled kernel. If these instructions don't work for you, drop me an email at nick at nick-andrew.net.

Preparation - Kernel and Software

Make sure your kernel has IPv6 support. Do "ifconfig eth0" and check for a line like this in the output:

          inet6 addr: fe80::212:34ff:fe56:789a/64 Scope:Link

You may need to load the "ipv6" module.

Check that you have the commands "ip6tables" and "ip".

Preparation - Firewall

It's good for security to setup the IPv6 firewall before you even start configuring it. Although you may have an IPv4 firewall already in place, that won't stop any IPv6 packets. I'll assume you want to make connections out, but block all connections in, which is the standard functionality you get with NAT, and useful for a client. For a server you will need to allow connections in for the server ports.

ip6tables setup

I use a shell script with a function alias, to set the firewall.
#!/bin/bash
#    Simple IPv6 firewall rules

doCmd6() {
        /sbin/ip6tables $*
        rc=$?
        if [ $rc != 0 ] ; then
                echo Error $rc doing ip6tables $*
        fi
}

doCmd6 -P INPUT DROP
doCmd6 -P FORWARD DROP

doCmd6 -F
doCmd6 -X

doCmd6 -N 6_log_drop
doCmd6 -N 6_icmp
doCmd6 -N 6_tcp

doCmd6 -A 6_log_drop -j LOG --log-prefix "ipv6:"
doCmd6 -A 6_log_drop -j DROP

#enable ssh in   doCmd6 -A 6_tcp -p tcp -d ::/0 --dport 22 -j ACCEPT
doCmd6 -A 6_tcp -j 6_log_drop

doCmd6 -F 6_icmp
doCmd6 -A 6_icmp -j ACCEPT


doCmd6 -A INPUT -i lo -j ACCEPT
doCmd6 -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
doCmd6 -A INPUT -p icmpv6 -j 6_icmp
doCmd6 -A INPUT -p tcp -j 6_tcp
doCmd6 -A INPUT -j 6_log_drop

This set of rules will allow you to make outbound IPv6 connections and will block inbound except for ICMP (your address can be pinged) and you can uncomment a line to enable ssh connections in.

Preparation - DSL modem

Assuming your DSL modem has a firewall, you will need to enable two things:

UDP port 3653 is used by the AARNet tunnel broker. Protocol 41 is used by 6to4 tunneling, which I will describe now.

Alternate access - 6to4 tunnel

Although this document is about obtaining IPv6 through AARNet's migration broker, there's a quicker way to get started on IPv6 using your dynamic IPv4 address. You will need the "curl" command installed. Run this script:

#!/bin/bash
#  Sets up an ipv6 tunnel through the nearest public gateway.
#  Automatically learns current ipv4 address.

ipv4=$(curl -s http://www.whatismyip.com/automation/n09230945.asp)
ipv6=$(printf "2002:%02x%02x:%02x%02x::1" $(echo $ipv4 | tr "." " " ) )

echo ipv4 is $ipv4 and ipv6 is $ipv6

ifconfig sit0 up
ifconfig sit0 add $ipv6/16
route -A inet6 add 2000::/3 gw ::192.88.99.1 dev sit0

192.88.99.1 is an address which routes to the nearest public IPv6 gateway. Unfortunately for us Australians, that's probably in the USA. But it's easy to setup, as you can see.

This technique has some advantages and disadvantages. On the positive side, you have 2^80 addresses to use. That should be enough for anyone. On the negative side, these addresses are as dynamic as your IPv4 address because they are derived from it. Also, you may be able to make outbound connections but not accept inbound connections, depending on what functionality your DSL modem provides. My DSL modem allows me to open up protocol 41 traffic, but it doesn't provide a configuration option to forward all incoming protocol 41 connections to my linux box. So my box can only accept inbound connections while there's a working outbound connection (this is standard NAT functionality).

So 6to4 is a good technique to get started with IPv6 if you want to, say, browse ipv6 websites. But it's not so useful for servers.

Testing - IPv6 using commands

"ping6" and "telnet" are your friends.

$ ping6 ipv6.l.google.com
PING ipv6.l.google.com(2001:4860:0:2001::68) 56 data bytes
64 bytes from 2001:4860:0:2001::68: icmp_seq=1 ttl=52 time=308 ms
64 bytes from 2001:4860:0:2001::68: icmp_seq=2 ttl=52 time=335 ms
64 bytes from 2001:4860:0:2001::68: icmp_seq=3 ttl=52 time=321 ms
$ telnet luyer.net 80
Trying 2001:470:1f05:14d::1...
Connected to luyer.net.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 200 OK
Date: Mon, 25 Aug 2008 00:38:50 GMT
Server: Apache/2.2.3 (Debian) PHP/4.4.4-8+etch6 mod_ssl/2.2.3
OpenSSL/0.9.8c
[ ... etc ... ]

You can also install the netcat6 package (the command is "nc6") to connect out or listen for incoming connections. To test if your web browser is using IPv6 correctly, try these sites:

Registering with AARNet

You'll need to create a username on the AARNet IPv6 Migration Broker and then associate that username with a tunnel.

  1. Create User Account
  2. Request Tunnel

The "Request Tunnel" CGI hangs for me, I don't know why. I assume it created a tunnel correctly because I'm getting one.

Installation of TSPC

Install the "tspc" package. I'm using Debian, so it's just "apt-get install tspc".

When Debian installs tspc, it automatically configures it to obtain an anonymous IPv6 tunnel from freenet6.net. Although that's great and easy, it's not what we need in Australia. So after installation, stop the daemon with "/etc/init.d/tspc stop".

Configuring the AARNet tunnel broker

To be continued ... no time to write the rest of the document today.

In brief, you need to use the v6udpv4 method and all traffic will be tunneled through a UDP connection. 30 second keepalive messages (I believe it's an ipv6 ping?) will keep NAT working. Your config file should look like this:

auth_method=any
userid=YOURUSERID
passwd=YOURPASSWORD

server=broker.aarnet.net.au
tunnel_mode=v6udpv4
host_type=router
prefixlen=64

client_v4=auto
if_prefix=eth0
if_tunnel_v6udpv4=tun
if_tunnel_v6v4=sit1

keepalive_interval=30
keepalive=yes

proxy_client=no
retry_delay=30
template=setup

Note that AARNet assigns a /56 even though this config asks for a /64.

Monitoring the IPv6 tunnel

AARNet's broker seems a bit flaky. It sometimes ignores the UDP packets so you may need to start the daemon a few times before it connects properly. As I mentioned, the CGI to request a tunnel hangs for me. If it doesn't hang, it may return a shell script, which you can ignore.

It's possible you don't even need to use the "Request Tunnel" CGI, maybe it will assign a permanent tunnel when tspc connects for the first time.

Also AARNet reboot the server at 03:00 every morning. The tspc daemon will try to reconnect if the tunnel fails, but perhaps not forever.

In any case, you want IPv6 to be always available, which means monitoring it. If the tspc daemon stops, you will need to restart it manually. I wrote this simple perl script which just logs whenever IPv6 stops working. It doesn't monitor the process or interface at all (you'd want to monitor the process itself if you change the script to restart a failed process).

#!/usr/bin/perl -w
#       @(#) $Id$
#       vim:sw=4:ts=4:

use Date::Format qw(time2str);
use Getopt::Std qw(getopts);

use vars qw($opt_h);

$| = 1;
getopts('h:');

$opt_h || die "Need option -h hostname";

# Initial and current state
my $state = 'down';

while (1) {
        my $now = time();
        my $newstate = getPingState($opt_h);

        if ($newstate ne $state) {
                open(OF, ">>ipv6-state.log");
                my $ts = time2str('%Y-%m-%d %T', $now);
                print OF "$ts $opt_h $newstate\n";
                close(OF);

                $state = $newstate;
        }

        my $to_wait = 60 - ($now % 60);
        print '.';
        sleep($to_wait);
}

# NOTREACHED
exit(0);

# ------------------------------------------------------------------------
# ping6 a host, and figure out if it is up
# ------------------------------------------------------------------------

sub getPingState {
        my $host = shift;

        my $rc = system("ping6 -c 2 -q -W 8 $host >/dev/null");
        if ($rc == 0) {
                return 'up';
        }

        return 'down';
}

I just run it like this: "check-ipv6.pl ipv6.l.google.com" and it pings once a minute (on the minute) and logs whenever the calculated state of the IPv6 connectivity changes.

For production use you'd want to change the 'sleep' to sleep(60) since it's not friendly to google for many sites to ping in synchronisation (i.e. always at :00). Of course you could always ping6 to broker.aarnet.net.au instead ...

64 bytes from 2001:388:1:5001:2a0:a5ff:fe4b:ae3: icmp_seq=1 ttl=64 time=52.8 ms
64 bytes from 2001:388:1:5001:2a0:a5ff:fe4b:ae3: icmp_seq=2 ttl=64 time=51.6 ms
64 bytes from 2001:388:1:5001:2a0:a5ff:fe4b:ae3: icmp_seq=3 ttl=64 time=51.1 ms