2011-07-07: Enabling IPv6

Posted at 2011-07-07 23:33:21 by SHD

It's not something many people will notice, as most of the difficult bits will have to be handled by the ISPs, but it's going to get more and more important for web developers and hosting providers to allow IPv6 access to their services. We've effectively run out of IPv4 addresses. As more and more people bring more and more devices online every day the common technique to share IPv4 addresses, NAT, even carrier-grade NAT which share a single IPv4 address among a large part of a provider's customer base, is not a sustainable solution. In the future, there will be people who can access the internet solely through IPv6. At first, it will be in the areas with the fastest-growing number of people online, particularly Asia. If you want those people to be able to access your website and services, make sure your servers respond to IPv6 traffic.

Network
AMS IX @ EU Networks photograph © 2008 by mattdork

Today, I've enabled IPv6 connectivity on this site. There shouldn't be any noticeable difference to visitors, but developers have a few things they need to take into account when making their systems work properly with IPv6. If you're interested in knowing a bit more about IPv6 configuration from the sys admin side, check below. Be sure not to ignore some basic security measures either. But first, let's have a look at what software developers have to deal with.

Check your code

Most servers primarily run web services these days, often coded in a scripting language such as PHP. As that is my primary development language, I shall list some issues that you may encounter when accessing scripts through IPv6. You'll need to be able to handle IPv6 addresses in addition to IPv4 ones in many cases. As IPv4 addresses are 32-bit integers, often represented as four 8-bit values separated by periods, their string representation cannot exceed 15 characters. This server presently has the IPv4 address 82.214.89.27. An IPv6 address is a 128-bit integer, which can be represented as 16-bit values separated by colons. This server has the IPv6 address 2a01:0238:42f9:4900:80e1:ffe2:7670:692f. While a (single) run of zeroes can be shortened using a double colon, the maximum length of the a true IPv6 address is 39 characters. As there exists a kludge to encode IPv4 addresses as IPv6 ones, the real maximum length is 45 characters.

  • Access checks by IP address: If you blacklisted or whitelisted certain IP addresses, a user connecting through IPv6 might circumvent the blacklist as they now have a different IP address, or get locked out because the whitelist doesn't recognise their IPv6 address.
  • Database fields: IP addresses are often logged in databases for analytics, for security or as an aid in identifying users. Many databases schemas were designed with IPv4 addresses in mind, using CHAR(15) or UNSIGNED INTEGER column sizes for the address. Make this into CHAR(45) (or VARCHAR, if you prefer) or BINARY(16) as not even MySQL's BIGINT datatype will hold the numeric value, being only a measly 64 bits in size.
  • Geolocation: Many services determine the location of their users through the IP address, to show localised content to these users. Make sure your geolocator service supports IPv6 addresses. There are even free services.
  • IP arithmetic: In most networks, devices will have addresses in the so-called "private" IP ranges and access the outside world through a NAT'ing router and gateway. Those IP addresses can be checked for by masking the bit patterns to known values. With IPv6, this is no longer needed, but the functions that operate on the addresses will choke on IPv6 input. This includes ip2long and conversely ip2long. For alternatives, check out inet_pton and inet_ntop respectively.
  • DNS functions: Not too many scripts need to make use of the dns... and gethost...functions available in PHP, but it should be pretty obvious that any code that deals with the translation of hostnames to IP addresses and vice versa should be thoroughly checked and tested for IPv6 support.
  • Binding to specific addresses: Apparently, it is not possible to bind a listening socket to a specific IP address if you have more than one on your server. It's an all or nothing deal, whereas IPv4 allowed listening on a single IP address. This make it possible to have multiple addresses assigned to the same server (even the same network card) and have, for example, Apache listening to port 80 on one and Tomcat listening to port 80 on another. No can do!

There may be other issues that I'm not aware of, but as developers we have to test our code to be ready to deal with the first IPv6-only customers. They will come! I'm using this, my personal site, as a testing ground to make sure that the services and sites I create work properly. I can highly recommend that other web developers do something similar, lest they be caught with their pants down.

At home

To be able to test access to IPv6 enabled services properly, you will need to have IPv6 enabled in your client systems as well. An easy way to check is to see whether you can access Google IPv6 in your browser. While modern operating systems have had support for IPv6 for a decade or so. ISPs are only just getting around to implementing it for consumers. Unfortunately, my ISP is one of the slower ones. Even if your provider offers IPv6 connectivity, you may still need to replace routers as even fairly recent ones, especially cheaper models, frequently do not support IPv6. A firmware update may be available if you're lucky, but most manufacturers would rather sell you a new router. If your provider cannot offer you IPv6 connectivity yet or your local network doesn't support it, tunnelling is a suitable stop-gap measure.

Server configuration

My hosting provider is one of those providers that have upgraded their infrastructure to handle IPv6 traffic. Getting an IPv6 address assigned to my server was a cinch, just pressing a single button in the web admin panel. AskBadger your hosting provider for more information on how to get IPv6 connectivity. Mine is an openSUSE based Linux machine, but for the majority of Linux distributions, the configuration steps will be similar.

Connectivity on Linux

First, check whether your kernel supports IPv6. An easy way to do this is by checking the virtual file /proc/net/if_inet6 for existence. If you cat it to the screen, it will show a list of IPv6 addresses assigned to your system, which should at least include the ::1 loopback address (the IPv6 equivalent of 127.0.0.1). It should look a bit like this: # cat /proc/net/if_inet6
fe80000000000000021bb9fffea36286 02 40 20 80 eth0
00000000000000000000000000000001 01 80 10 80 lo
#
If the file doesn't exist, your kernel does not support IPv6 (yet). All is not last, though, as this probably simply means the appropriate kernel module has not been loaded. This is easy enough to do with the command # modprobe ipv6 If that works, you will probably want to load the module at system boot time, which can be done by adding the line alias net-pf-10 ipv6 to your /etc/modprobe.conf file (or change the alias if it is currently set to "off"). If the module hasn't been compiled into the kernel and can't be loaded separately, either because it doesn't exist or because the kernel has been configured not to allow loadable modules, you may need to compile a new kernel or even upgrade your distribution.

Your hosting provider may have set up a DHCPv6 server that will allow you to have the IPv6 address and other settings, such as the default gateway assigned automatically to your server. In other cases, you may need to edit the network configuration files according to your hosting provider's instructions. In addition to those, another useful resource can be found at the Linux IPv6 HOWTO, in particular, the chapters on configuring interfaces and configuring addresses.

Be careful!

Hackers are everywhere and it seems they're especially active, hacking into major services recently. It's tough (maybe even impossible) to defend against a good hacker, but you can at least make an effort by not leaving the front door wide open. That's what firewalls are for. You may have set up some good firewall rules, but will they work with IPv6 traffic? The answer is no, not unless you configure those rules for IPv6 too, separately. The ubiquitous iptables packet filter handles only IPv4 network traffic. Fortunately, it has an IPv6 twin: ip6tables. Since I want to accept only web traffic and ping, I allowed external access only to port 80 (http). # ip6tables -F INPUT
# ip6tables -P INPUT DROP
# ip6tables -A INPUT -i lo -j ACCEPT
# ip6tables -A INPUT -p icmpv6 -j ACCEPT
# ip6tables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT*
# ip6tables -A INPUT -p tcp --dport 80 -j ACCEPT
# ip6tables -A INPUT -j DROP
The first line flushes the INPUT ruleset for IPv6 traffic. The second allows full access for the loopback interface. The third sets the policy to drop any non-matched packets. The fourth accepts the IPv6 version of the ICMP protocol (necessary to be able to ping). The fifth allows incoming data from established connections. The sixth enables access to web services at port 80. The last line is not strictly necessary as it should be handled by the policy, but just there as an extra safety net, because people can and do make mistakes.

If you get an error message about being unable to load libip6t_state.so, you need to upgrade to ip6tables 1.3.5 or higher and kernel 2.6.16 or higher, with CONFIG_NF_CONNTRACK_IPV6 enabled. If this is not feasible, set up rules to handle the SYN flag instead. You can do this by removing the marked line and adding another one, just before the final "DROP" line: # ip6tables -A INPUT -i eth0 -p tcp ! --syn -j ACCEPT though this is less secure than the proper connection tracking and cannot be recommended.

You will probably want to add such lines (be sure not to type in the # — it is a prompt, but would turn the command into a comment if typed in) to your firewall script.

If and only if your host has set up a static (commonly link-local) default route, you will want to prevent the processing of router advertisements to lessen the area of attack. To do this, add the line net.ipv6.conf.all.accept_ra = 0 to /etc/sysctl.conf. Then run # sysctl -p to activate the setting. But, make sure you add the route to your routing configuration. In my case, this was # route -A inet6 add ::/0 gw fe80::1 dev eth0You should, of course, substitute fe80::1 for the default route and eth0 for your IPv6 enabled network device.

Pingbacks

Comments

No comments, yet...

Post a comment

Note: HTML is not permitted, URLs will be linked automatically. Spam comments will result in a permanent ban.
Type these 4 symbols into the edit field