IPv6 on FreeBSD


How easy is it to get an ipv6 website up and running on FreeBSD? Surprisingly this takes only a few minutes and all the we need to have ready are 1) an IPv6 allocation and 2) an AAAA record for the domain in question. It's well known that the current supply of IPv4 addresses is fast running out. Some suggest that by the end of 2011 the supply of IPv4 addresses will be exhausted, although even if no more are available there is no doubt IPv4 will continue for many years to come. The supply is becoming ever more diminished as the number of new IP-based devices and services continues to grow. In the meantime, to get any website up and running on IPv6 takes little effort. Home broadband users are limited in the availablity of IPv6. For example there is no support here in the UK for IPv6 enabled routers by most broadband suppliers. A similar situation exists in most other countries. Most users still require a tunnel broker to access IPv6 services, and this is typically an easy point-and-click setup. One example of this is the service offered by SixXS.net.

This example will be a complete setup: we start with a request for an IPv6 allocation and by the end will have a fully functional website running on FreeBSD.

As this website is run on a server at Leaseweb's Evoswitch datacenter I emailed a request to Leaseweb's support department for an IP alloction. Their reply only took a few minutes and provided the details:


We have assigned the prefix 2001:1AF8:4100:A00C::/64 on the interface you are connected to. Your gateway is 2001:1AF8:4100:A00C::1. You may use all IP's within 2001:1AF8:4100:A00C:1::/112, that is from 2001:1AF8:4100:A00C:1:: to 2001:1AF8:4100:A00C:1::FFFF, of course each one with the netmask /64.

Now, as I like to start from 1, I decided to use 2001:1AF8:4100:A00C:1::1 for the AAAA record. Next it was over to dnsmadeeasy.com who handle my DNS, and in no time at all I had AAAA records created for hostwurx.com and www.hostwurx.com, both set to 2001:1AF8:4100:A00C:1::1.

Now on to the server itself, I edited /etc/rc.conf and added:

ipv6_enable="YES"
ipv6_defaultrouter="2001:1AF8:4100:A00C::1"
ipv6_ifconfig_em0="2001:1AF8:4100:A00C:1::1 prefixlen 64"

If I wanted to add an additional IP address, I would add another line like:

ipv6_ifconfig_em0_alias0="2001:1AF8:4100:A00C:1::2 prefixlen 64"


Now I have to make some changes to my PF firewall rules - I'll make these fairly general, but at least they will work. I keep my rules in /etc/pf.rules whereas the default file location is usually /etc/pf.conf - I always worry in case this would get overwritten, hence I use a different file. Edit this and add:

# allow DNS requests to go out
pass out on $IF inet6 proto udp from any to any port=domain keep state
# all TCP request allowed out
pass out on $IF inet6 proto tcp from any to any keep state
# all ping request allowed out
pass out on $IF inet6 proto icmp6 all icmp6-type {echoreq, echorep} keep state
# ND solicitation out
pass out on $IF inet6 proto icmp6 all icmp6-type {neighbradv, neighbrsol}
# ND advertisement in
pass in on $IF inet6 proto icmp6 all icmp6-type {neighbradv, neighbrsol}
#router advertisement out
pass out on $IF inet6 proto icmp6 all icmp6-type routeradv
# router solicitation in
pass in on $IF inet6 proto icmp6 all icmp6-type routersol
# all ping request allowed in
pass in on $IF inet6 proto icmp6 all icmp6-type {echoreq, echorep} keep state
#allow incoming connection to WWW server
pass in on $IF inet6 proto tcp from any to any port=www keep state
#all reply from WWW server (is not really necessary)
pass in on $IF inet6 proto tcp from any port=www to any keep state
# traceroute (is not really necessary)
pass in on $IF inet6 proto udp from any to any port 33433 >< 33626 keep state
pass out on $IF inet6 proto udp from any to any port 33433 >< 33626 keep state
# ssh
pass in on $IF inet6 proto tcp from $cluster6 to any port ssh flags S/SA keep state


Now all I have to do is reload my firewall rules, and start the network - I don't need to reboot to do this, but it could be done as I have updated rc.conf anyway. What I did was:

pfctl -F rules && pfctl -f /etc/pf.rules
/etc/rc.d/network_ipv6 restart


Now to view newly assigned IP address:

$ ifconfig | grep inet6
inet6 2001:1af8:4100:a00c:1::1 prefixlen 64
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x3
inet6 ::1 prefixlen 128

and to test our IPv6 networking connectivity:

$ ping6 -c 1 ipv6.google.com
PING6(56=40+8+8 bytes) 2001:1af8:4100:a00c:1::1 --> 2a00:1450:8002::6a
16 bytes from 2a00:1450:8002::6a, icmp_seq=0 hlim=56 time=12.783 ms

--- ipv6.l.google.com ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 12.783/12.783/12.783/0.000 ms

So that's all working fine.

Now I need to update my apache configuration. As I'll be running IPv4 and IPv6 websites together, and I've already quite a few IPv4 websites on this server, I will need to have Listen, NameVirtualHost and VirtualHost directives for everything. If we just look at this website running on both IPv4 and IPv6 we will need:

Listen 85.17.139.225:80
Listen [2001:1AF8:4100:A00C:1::1]:80


NameVirtualHost 85.17.139.225:80
NameVirtualHost [2001:1AF8:4100:A00C:1::1]:80

We need to make sure that the IP address and port in the VirtualHost entries are identical to those in the corresponding NameVirtualHost entries so the complete VirtualHost entry for our IPv6 version of hostwurx.com is then:

<VirtualHost [2001:1AF8:4100:A00C:1::1]:80>
DocumentRoot /home/hostwurx/htdocs
ServerName www.hostwurx.com
ServerAlias www.hostwurx.com hostwurx.com
ErrorLog /var/log/httpd/hostwurx.com.ipv6/error.log
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
CustomLog /var/log/httpd/hostwurx.com.ipv6/access.log combined
<Directory /home/hostwurx/htdocs>
Options +Includes -Indexes
Order Deny,Allow
Allow from all
DirectoryIndex index.php
</Directory>
</VirtualHost>

I have changed the location of the log files I would normally use as I can then keep these separate from any IPv4 log files.

Now all we need to do is restart httpd or just reload the configuration files:

/usr/local/etc/rc.d/apache22 restart

All done. Now anyone can retrieve the website over IPv6. It's that simple. There are also external tools which you can use to test, for example those available at lg.consulintel.euro6ix.org/ - if we make a few checks using our domain, we get:

#ping6 -c 5 hostwurx.com

PING hostwurx.com(2001:1af8:4100:a00c:1::1) 56 data bytes
64 bytes from 2001:1af8:4100:a00c:1::1: icmp_seq=1 ttl=57 time=91.2 ms
64 bytes from 2001:1af8:4100:a00c:1::1: icmp_seq=2 ttl=57 time=73.2 ms
64 bytes from 2001:1af8:4100:a00c:1::1: icmp_seq=3 ttl=57 time=72.9 ms
64 bytes from 2001:1af8:4100:a00c:1::1: icmp_seq=4 ttl=57 time=97.4 ms
64 bytes from 2001:1af8:4100:a00c:1::1: icmp_seq=5 ttl=57 time=76.0 ms

--- hostwurx.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4034ms
rtt min/avg/max/mdev = 72.983/82.177/97.412/10.171 ms


#traceroute6 -w 3 -m 25 hostwurx.com

1 gr2000.consulintel.es (2a01:48:1::ff0) 0.775 ms 1.739 ms 0.902 ms
2 neosky-consulintel.consulintel.es (2a01:48::d5ac:227d) 10.94 ms 6.193 ms 8.121 ms
3 tunnel105.tserv17.lon1.ipv6.he.net (2001:470:14:69::1) 55.105 ms 51.68 ms 34.982 ms
4 gige-g4-18.core1.lon1.he.net (2001:470:0:a3::1) 52.177 ms 41.682 ms 42.069 ms
5 2001:7f8:4::3f89:1 (2001:7f8:4::3f89:1) 72.868 ms 76.947 ms 64.062 ms
6 te0-1-0-3.crs.tc2.leaseweb.net (2001:1af8::2) 67.867 ms 69.924 ms 82.098 ms
7 po80.sr2.evo.leaseweb.net (2001:1af8::42) 72.393 ms 82.463 ms 70.549 ms
8 2001:1af8:4100:a00c:1::1 (2001:1af8:4100:a00c:1::1) 93.758 ms 74.498 ms 65.204 ms