With the exhaustion of IPv4 address space looming sometime in 2012; probably earlier rather than later, it makes sense to ease on into IPv6 land. Without straying into tunnel broking and endpoint shenanigans 6to4 is a method of wrapping up IPv6 inside of IPv4.
6to4 performs three functions:
- Allocates an IPv6 address block to any host/network that has a global IPv4 address.
- Wraps up IPv6 packets inside IPv4 packets for transmission over IPv4 using 6in4 (traffic is sent over IPv4 inside IPv4 packets whose IP headers have the IP protocol number set to 41; IPv6-in-IPv4. ) 6to4 makes use of IP protocol 41 too, but instead of static endpoints, the endpoint IPv4 address is sourced from IPv6 addresses within the IPv6 packet header.
- Routes traffic between 6to4 and “native” IPv6 networks.
As such its pretty easy to implement, especially on our good friend Debian (and its better looking cousin Ubuntu).
I am going to step through setting up a Debian host at Linode.
Step 1 Check your Kernel
Now, the first caveat is that you must be running a 2.6.20+ kernel (At the time of writing the latest linode kernel for Debian was : 2.6 Paravirt (2.6.34-x86_64-linode)). The default ‘Etch’ release kernel (2.6.18) supports IPv6 but woefully implements IPv6 stateful connection tracking, which is just not good enough for a decent firewall. If you have a look under your Linode Configuration Profile you can see what Kernel you are running, and change it to one that is supported; obviously a reboot would be in order if you change it. The linode kernels have IPV6 support compiled in.
But here is the quick way to check whether IPV6 is compiled in, if the following fails IPv6 is either not compiled in or the module has not been loaded:
$ cat /proc/net/if_inet6
00000000000000000000000000000001 01 80 10 80 lo
fe80000000000000fcfd4afffecff19f 02 40 20 80 eth0
WARNING UBUNTU Pre 10.04LTS !!!
Modprobe is kind of janky and will stop your interfaces coming up if you follow this guide to the letter. You will need to do this first:
As root/sudo divert the old modprobe, this means that any subsequent upgrade won’t blow away your script
dpkg-divert --add --rename --divert /sbin/modprobe.real /sbin/modprobe
Create a replacement /sbin/modprobe script:
if [ "$1" == "-Q" ] ; then
Step 2 Calculate your new IPv6 address
Any IPv6 address that begins with the 2002::/16 prefix is known as a 6to4 address, as opposed to a native IPv6 address which does not use that prefix. The Internet Assigned Numbers Authority (IANA: www.iana.org) has set aside this address space just for 6to4. IPv6 addresses are assigned based upon your IPv4 address; for instance, 18.104.22.168 would become 2002:4acf:fe10::/48
We need some tools to help us calculate our IPV6 address, luckily there is a package for this
$ sudo apt-get install ipv6calc
Now its a matter of plugging in your IPv4 address into ipv6calc to determine your reserved IPv6 address range.
$ ipv6calc -q --action conv6to4 --in ipv4 22.214.171.124 --out ipv6
and voila your IPv6 address range appears:
You get given an address range with a prefix length of 48 bits, which leaves room for a 16-bit subnet field and a 64 bit host address within the subnet.
Step 3 Update your interface configuration
You now need to edit your network configuration file /etc/network/interfaces file
auto tun6to4 # make sure this interface comes up on boot
iface tun6to4 inet6 v4tunnel
address 2002:4acf:fe10::1 #first host in this address range
gateway ::126.96.36.199 #special anycast address for 6to4 (2002:c058:6301::)
mtu 1472 #The MTU is therefore the normal Ethernet MTU (1500) minus the headers used on the tunnel.
Restart your interfaces (not recommended):
$sudo /etc/init.d/networking restart
If you want to be a little but more careful and not wipe out all networking if something goes wrong (eg you are using Ubuntu or IPv6 is not available), you could just bring up the new interface:
$sudo ifup tun6to4
Step 4 Update IPv6 Firewall script/rules
Now it’s fairly important (read as critical) to firewall IPv6 stuff as it is with IPv4. Here is a small sample of a firewall that will at the very least not leave you hanging in the breeze. Needless to say you can add your own rules and make this as complex as you need.
# Initialize all the chains by removing all the rules
iptables -t nat --flush
iptables -t mangle --flush
ip6tables -t mangle --flush
# The loopback interface should accept all traffic
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
#Allow IPV6 packets to come over the tunnel
iptables -A INPUT -p ipv6 -i eth0 -j ACCEPT
iptables -A OUTPUT -p ipv6 -o eth0 -j ACCEPT
# Allow outbound DNS queries from the FW and the replies too
iptables -A OUTPUT -p udp -o eth0 --dport 53 --sport 1024:65535 -j ACCEPT
iptables -A INPUT -p udp -i eth0 --sport 53 --dport 1024:65535 -j ACCEPT
ip6tables -A OUTPUT -p udp -o tun6to4 --dport 53 --sport 1024:65535 -j ACCEPT
ip6tables -A INPUT -p udp -i tun6to4 --sport 53 --dport 1024:65535 -j ACCEPT
# Accept and reply to ICMP ping
iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# IMPORTANT!!!! Allow all icmpv6 because they make IPV6 work
ip6tables -A OUTPUT -p icmpv6 -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j ACCEPT
# Allow previously established connections
iptables -A OUTPUT -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
ip6tables -A OUTPUT -o tun6to4 -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow port 80 (www) and 51515 (SSH) connections to the firewall
iptables -A INPUT -p tcp -i eth0 --dport 51515 --sport 1024:65535 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 443 --sport 1024:65535 -m state --state NEW -j ACCEPT
iptables -A INPUT -p tcp -i eth0 --dport 80 --sport 1024:65535 -m state --state NEW -j ACCEPT
ip6tables -A INPUT -p tcp -i tun6to4 --dport 51515 --sport 1024:65535 -m state --state NEW -j ACCEPT
ip6tables -A INPUT -p tcp -i tun6to4 --dport 443 --sport 1024:65535 -m state --state NEW -j ACCEPT
ip6tables -A INPUT -p tcp -i tun6to4 --dport 80 --sport 1024:65535 -m state --state NEW -j ACCEPT
# Allow port 80 (www) and 443 (https) connections from the firewall
iptables -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED -o eth0 -p tcp -m multiport --dport 51515,80,443 -m multiport --sport 1024:65535
ip6tables -A OUTPUT -j ACCEPT -m state --state NEW,ESTABLISHED,RELATED -o tun6to4 -p tcp -m multiport --dport 51515,80,443 -m multiport --sport 1024:65535
# Allow previously established connections
iptables -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED -i eth0 -p tcp
ip6tables -A INPUT -j ACCEPT -m state --state ESTABLISHED,RELATED -i tun6to4 -p tcp
# The policy should be to drop it
iptables -A INPUT -j DROP
iptables -A OUTPUT -j DROP
iptables -A FORWARD -j DROP
ip6tables -A INPUT -j DROP
ip6tables -A OUTPUT -j DROP
ip6tables -A FORWARD -j DROP
I usually create a directory called /etc/iptables (owner root:root / permissions 750) and drop firewall up and down scripts in there.
Then it is a simple matter of adding the following scripts to the bottom of your eth0 interface definition stanza in /etc/network/interfaces to invoke them on boot or whenever:
IMPORTANT: Just a quick note don’t block icmpv6 because it is the glue that holds IPv6 together.
Step 5 Setup Forward DNS
I am not going to over explain this one because everyone has an opinion on how to setup DNS but in essence you need to add a line like this to your zone file. There are plenty of articles outlining this stuff.
hyosine AAAA 2002:4acf:fe10::1
Step 6 Setup Reverse DNS
You now need to setup reverse DNS for your address, so using our example of 2002:4acf:fe10 you will have to configure the zone of “0.0.0.0.0.1.e.f.f.c.a.188.8.131.52.2.ip6.arpa” in your name servers. The zone should have PTR records for your hosts just like an in-addr.arpa zone for IPv4, but with hex digits of the IPv6 address backwards, separated by dots. Using our example, the 6to4 host will have a ::1 suffix, so a reverse DNS record looks like:
184.108.40.206.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.e.f.f.c.a.220.127.116.11.2.ip6.arpa. PTR hyosine.openquery.com.
You will need to register this zone and its servers with the 6to4 reverse zone authority. eg https://6to4.nro.net/
Step 7 Test
The ping6 utility is probably best to test whether your host is now working. It’s probably best to try the IPv6 address first:
$ ping6 2002:4acf:fe10::1
PING 2002:4acf:fe10::1(2002:4acf:fe10::1) 56 data bytes
64 bytes from 2002:4acf:fe10::1: icmp_seq=1 ttl=60 time=1.59 ms
64 bytes from 2002:4acf:fe10::1: icmp_seq=2 ttl=60 time=1.42 ms
Now you can try with the DNS name you just setup.
$ ping6 hyosine.openquery.com
PING hyosine.openquery.com(2002:4acf:fe10::1) 56 data bytes
64 bytes from 2002:4acf:fe10::1: icmp_seq=1 ttl=60 time=1.41 ms
64 bytes from 2002:4acf:fe10::1: icmp_seq=2 ttl=60 time=1.34 ms