With IPv6 slowly becoming more visible, it was time to get to grips with it. While absolutely not essential (yet!) it seemed like a fun idea: my ADSL provider offers native IPv6 in parallel with IPv4, and my hosting provider is running an IPv6 beta. So I can do native IPv6 end to end between my home and a remote host. “Home” in this case consists of a Linux firewall running iptables, fronted by shorewall. Two ethernet ports: one to the ADSL modem (my “external” interface) and one to the house infrastructure (“internal”)
The Ubuntu server distribution in use is, like most Linux distros, fully IPv6 ready. For example, do an ifconfig and we see
Now I may not know much about IPv6 on Linux yet, but I can see that I’ve got a line beginning “inet addr” which looks kinda IPv6-ish. Good start. Let’s go…
[EDIT: Had to obfuscate parts of addresses below… Sorry, makes reading a tad harder in places…]
IPv4 – today
As it stands, my home firewall performs the following functions:
- It acts as a DHCP client on its external interface, in order to pick up from the ISP the IPv4 address, plus the DNS server(s) being offered. In fact my IPv4 address is fixed, so strictly speaking I don’t need to act as a DHCP client on this interface, but it’s no real effort to do so and it means I get the DNS servers automatically.
- It acts as a DHCP server on its internal interface, in order to supply IP addresses to the many and various client devices within the house, along with DNS information. (I actually use dnsmasq for this purpose – tremendous piece of software)
- It performs NAT between the internal devices and the Internet, courtesy of iptables.
- It acts as a firewall between the internal devices and the Internet, again courtesy of iptables.
Since no one in their right mind writes “raw” iptables configs of any complexity, I use shorewall to administer the NAT and firewall functions – mostly using the shorewall cli, sometimes using the shorewall GUI within Webmin.
To top things off, I also have a VPN tunnel running between the firewall and a host machine, using OpenVPN.
So what do I need to know even before I think of starting with IPv6?
So as far as I know all the raw elements are available to me: ISP support, host support and all the bit ‘n bobs that Linux offers. So how do I string them together? In fact, hang on a sec before that: Just what is my goal?? The engineer in me frankly just wants to have a damn good play with IPv6, but it’s still good to have an initial goal to provide some sort of framework and direction.
Hence I set myself the somewhat arbitrary goals as follows:
- Between my firewall and my remote host enable simple IPv6 connectivity. ping, ssh, etc.
- Between my firewall and my remote host enable VPN connectivity (i.e. shift the existing IPv4 tunnel to IPv6)
- While leaving the rest of the household blissfully ignorant (and hence unaffected) by IPv6, enable two specific workstations (one Windows, one Linux) to have dual IPv4/IPv6 stacks such that they default to using IPv4 except for traffic destined to the remote host or some other IPv6 end-point, which will go IPv6 end-to-end (i.e. workstation <–> firewall <–> host)
Note that there are a lot of things that I am not yet trying to do. Specifically I am not setting up any gateways to allow IPv4 <–> IPv6 inter-working. For now I will have all my existing IPv4 functionality, with an entirely optional layer of IPv6 for those clients who (a) can talk native IPv6 and (b) have an IPv6 end-point to which they wish to connect. The inter-working side of things is a level of complication that in the first instance I want to avoid. Start simple and build up.
Before anything else there are some IPv6 “basics” that need a little explanation and clarification. As with any technology, the problem is not with finding information. The problem is with finding out which information is useful and which is entirely irrelevant.
The one thing everyone knows about IPv6 is that it’s got funny looking, and rather large, addresses. Where once we had stuff like good old 192.168.0.1, now I might have fe80::240:63ff:fef5:f93c/64. And that’s one of the shorter ones…!
So what do I really need to know about IPv6 addresses, leaving aside the stuff that’s not required? Here goes.
IPv6 addresses consist of 128 bits. Why? Simple: to provide enough addresses that we’re not likely to run out, as we are perilously close to doing with IPv4. Just how big is “128 bits”? In decimal terms, such numbers have up to 39 digits. Here’s one:
In order to make things more manageable, IPv6 addresses are not written as long, decimal numbers. Instead they are written in hexadecimal, broken up in to 16-bit fields by colons. Here’s an IPv6 address lifted from the official IPv6 HowTo:
To further simplify things, leading zeros can be omitted. Also, contiguous blocks of zeros can also be omitted. For example:
can be reduced down to
The most extreme example of this is when the localhost address is considered (analogous to IPv4’s 127.0.0.1) and can be condensed down from
Note, however, that the use of ‘::’ and leading-zero suppression is purely a shorthand. All IPv6 addresses are 128-bits in length – these are just cosmetic tricks to make the writing and typing of them a little more friendly.
Just as IPv4 addresses have netmasks, so with IPv6 addresses. More of that when we look specifically at routing later on.
Also, normally we find that the upper 64 bits are considered to be “network” bits and the lower 64 bits are “host” bits.
The leading 16 bits of the network portion of an IPv6 address are “special” in so far as some values are reserved as having special meaning. I am not here going to define all the possible values in use. I am confining myself to what matters within the context of the exercise at hand. And for those purposes the two values might be seen.
Local link addresses prefix
fecx (where x is any hex digit, but is normally 0) – Such addresses are local link addresses. Under Linux, when an IPv6-capable interface is enabled, such an address “automatically” appears. It is used solely to talk with other devices on the same link: hi, anything there? anyone looking for a router? Note that such addresses are not used for “normal” data – they are purely for local link management. And now we know where that IPv6-looking address came from in my original ifconfig command:
inet6 addr: fe80::240:63ff:fef5:XXX/64 Scope:Link
(and notice that friendly Linux even puts the “Link” there to remind you that it’s a link address)
Global unicast address prefix
2xxx and 3xxx – These are so-called “global unicast” addresses, analogous to IPv4 “normal” addresses (i.e. not private, not multicast, etc.)
The bottom 64 bits of an IPv6 address are, essentially, whatever you want them to be. They can be manually defined or, more often, are computed by using the interfaces MAC address (if it has one).
So here’s a simple enough address:
Given the 2001:prefix, so we know it’s a global unicast address from an ISP. And the bottom 64 bits consists of just ‘1’ (all the zeros are magic’ed away by the ‘::’)
But what of this “computed from the MAC address”? Recalling the ifconfig I showed back at the start:
Note the hardware MAC address: 00:40:63:f5:f9:3c (and remember that those digits and colons are nothing at all to do with IPv6 notation – they are bog-standard, traditional L2 MAC address format)
Now look at the last part of the IPv6 link address: you will see that there is more than a passing resemblance between them – although also note that they are not identical either. The details of how one is morphed in to the other is not of direct concern to us – all we need to know here is that one follows from the other.
A complete example
Here’s one I prepared earlier….. 🙂 This is the output from ifconfig on my host system, after the main interface has been fully configured and all addresses allocated:
What have we got? The interesting parts break down as follows:
- The interface has a L2 MAC address of 00:16:3e:2e:50:36
- The IPv4 addressing is as it always has been – No change there.
- We have a Link address of fe80::216:3eff:fe2e:XXX which should now look familiar: the fe80: prefix and the appearance of the L2 MAC address.
- And we now have a Global address of 2001:XXX:41::d946:bf36:54 which is familiar at least in so much as it has a prefix of 2001: The rest of the address’s derivation is not of direct concern here. (In fact, after the ISP-specific part, other elements of it are derived from VLAN addresses and other such stuff. No matter.)
Goodbye ifconfig, hello ip
Since time immemorial Linux users have been familiar with the command ifconfig. Thus far in this document I’ve used it too, for the sake of familiarity. But dear ifconfig has actually been deprecated now for many years. It lives on, and we all still use it, but with the advent of IPv6 it does now seem an appropriate moment to bid it goodbye. It’s time to use the ip command, in its many forms. While it’s true that ifconfig can still achieve most of what is required, it sometimes falls short. Also, using ip let’s us more clearly and easily distinguish between IPv4 and IPv6, which is maybe not a bad thing!
Compare the ifconfig output from above with a couple of examples of the ip command:
This is analogous to the simple ifconfig: we’ve got L2 MAC, IPv4, and a couple of IPv6 addresses showing.
Look how much neater that is, even just for IPv4: no L2 MAC, no IPv6, just the IPv4-related information.
And similarly here: we just get IPv6-related information, and nothing else.
alias ip6=’ip -6′
and then you can just enter:
which is quite neat.
The last part of this IPv6 Basics section is to introduce the functional building blocks within Linux which seem to get mentioned in connection with IPv6.
We now know about IPv6 addresses types that matter to us, we have met the command(s) we will use to inspect and manipulate things such as interfaces, routes and so on. We have also assumed that there is something similar to IPv4 iptables (and we’ll come back to that in some detail later as to how we actually use iptables under IPv6). However what subsystems such as DHCP exist and are of interest to us? When reading up on IPv6 Linux implementation one comes across the following mentioned frequently, and you may quickly form the impression that they are three important elements in an IPv6 firewall/router. They are:
dhcp6c is a Linux DHCP IPv6 client. It is directly comparable to the IPv4 dhclient or dhclient3. It will, for a nominated interface, call out and ask for an IPv6 address which it can allocate to that interface. It may also, optionally, pick up other information, typically DNS-related.
dhcp6s is a Linux DHCP IPv6 server. It is comparable to the IPv4 dhcpd or, in my network, dnsmasq. Just as in the IPv4 environment, it hands out addresses to other devices and, optionally, other information such as DNS data.
radvd is a Router Advertisement Daemon. This is less easy to directly compare to the IPv4 environment. It can hand out, to requesting devices, an IPv6 prefix (not a full address…) and a default route to be used. From this the receiving device can then automatically decide upon a host portion to add to the prefix to give it a full IPv6 address. So at first sight, it seems to be a rather inadequate imitation of a DHCP server!
One might very easily conclude that all three are required. After all, we may well use a DHCP client on the Internet side, and a DHCP server for the private network sounds pretty much essential. And a router advertisement daemon? Not entirely sure what it is, but gets a lot of mentions so I probably need that too! In actual fact the only one of these you are likely to need is readvd. You might need any combination of them, depending upon your precise circumstances. But probably not.
DHCP client I get, but what’s with DHCP server versus radvd?
This is an area of considerable confusion! When bouncing around Google trying to find information on setting up IPv6 one minute we appear to be required to use DHCP server, the next minute we appear to need radvd. Which is which and when do I use them? Do I need both?
Well, the answer to the last question, “Do I need both of them?”, it “Probably not, but you might…”
Coming from familiarity with the world of IPv4 one instinctively tends to feel comfortable with the concept of dhcp6s – and while it can be used, radvd may well be simpler and easier in practice. Or, maybe, both… The attraction of rad is that the server does not need to concern itself with any state: no records of addresses allocated – since it does not allocate any. It just says “Hey, this is the prefix, work the rest out for yourelf.” which is attractively simple! The DHCP server alternative has to remember which address is where and when. The case where you might want both would be where you want to have rad handle the job of initiating address allocation, and then have DHCP pick up to add some icing on the cake: DNS information being the common case.
And us here? We’re going to go with the simpler case, and have radvd handle the job of responding to IPv6-capable devices within our internal network and tell them just enough to allocate addresses themselves and use a default route.
So it actually seems to come down to a pair of subsystems being required:
- dhcp6c talks out to the ISP to handle “outside” IPv6 addressing.
- radvd talks internally to all devices to handle “inside” IPv6 addressing.
Well, maybe… But in these early days of IPv6 there is far from a standard view of how these things are to work. And, as I discovered, your ISP may not actually themselves offer an IPv6 DHCP server at all! In my case that was the situation, although I have little doubt that as time progresses and IPv6 implementations mature such services will become more standard.
But for now, my implementation will be reduced down to simply running radvd on the firewall, with the IPv6 configuration on Internet side being handled semi-statically.
Just one subsystem to be used: radvd. No DHCP client. No DHCP server. Who said IPv6 was complicated?!?
Setting up the firewall box
So at last we get to the actual practicalities of getting IPv6 up and running on the home firewall. The system in question is a Ubuntu-based device. The differences for another Linux system should be fairly negligible (package names maybe, some config file locations, etc.)
Packages to install
All we need to install is radvd if its not already present. Under Ubuntu something like:
sudo apt-get install radvd
should do the job.
And already we come to potentially our first issue!!! Once radvd is up and running on the firewall it will, potentially, start chatting to devices on the home network which are, by default, on the look out for IPv6 routers. Whether it does this by default depends upon the installed configuration file used, and which interface points where, but it’s a real possibility. And that may not be entirely a good thing. Be on the look out for workstations suddenly getting really really slow when, for example, browsing the web. I would suggest disabling IPv6 on any devices which may be susceptible to it. There are numerous ways to do that. On Windows in all its flavours? I have not the faintest idea. Under Linux? Here are some suggestions. Depending upon what is on your home network this may not be required, but if you do run in to the “slow web” issue, be alert to it.
Technical note: for the curious, if you do hit the IPv6 crawl of death issue, it’s actually due to certain services on clients stations being IPv6 aware and thus trying to resolve DNS requests via IPv6. They try, take an age to fail, and eventually fall back to IPv4. But it’s ugly. I wish I could say that I foresaw the issue and planned accordingly. More truthful would be to say that during my diddling around with radvd I got loud complaints from another user on the home network… 🙂
Setting up the connection towards the Internet… no hang on, actually not yet…
The first task is to get the public (in my case eth0) interface up and running IPv6. Before actually doing that we need to pause for a moment and consider the implications of what might happen if we indeed succeed in bringing up the IPv6 ISP-connected interface! We are then wide-open to the world, and just asking to be attacked. The only sensible thing to do is to first set up an IPv6 firewall to provide some level of protection before we throw ourselves open.
Sorry. But that’s life. Of course if your public-side connection is already protected via some firewall, then you can skip this. But it probably isn’t, so pay attention. With IPv4 most home networks make use of, by necessity, NAT. While not done for reasons of security it does nonetheless provide as a side-effect a modest level of security in so far as it tends to block unsolicited incoming connections. So even with a poorly configured firewall under IPv4, the use of NAT hides a multitude of nasties from us. But in the brave new world of IPv6 one hugely important difference from IPv4, but one that everyone seems to gloss over, is that NAT is not required. And indeed since not required, it does not exist. All IPv6 devices on the “inside” network will have, in effect, public addresses. No port-forwarding, no NAT, none of that. And while that’s actually a very refreshing thing in general (NAT and large firewalls are a real pain) it does means we can no longer rely on the default level of safety that NAT provides. A tightly configured firewall is absolutely essential.
To drive IPv6 iptables I use shorewall6. I highly recommend it. Here I am going to run through, without too much explanation, the steps to set up a very basic “block almost everything except a bit of stuff for testing” IPv6 firewall on the system. Here goes.
Install the package:
apt-get install shorewall6
The basic level of configuration then has to take place. Navigate to the configuration files:
Set up the following files in a similar manner as shown here:
# Allow only ping – for testing
Within shorewall6.conf ensure these lines as as follows:
What we have there is a minimal firewall configuration, which blocks absolutely everything except pings to and from the firewall box itself.
Start up the firewall with e.g.:
shorewall6 show config
should give you a pretty lengthy IPv6 iptables config.
So, with precautions now in place, we may proceed.
[EDIT: shorewall6 and logging may or may not be an issue… See my article here: http://www.ipsidixit.net/2010/02/25/231/]
OK, finally setting up the connection towards the Internet…
Here is the starting point, with an automatically assigned, MAC-derived, link address:
Configuring the addressing
My ISP is free.fr (a French ISP) From them I have a fixed IPv4 address and a fixed IPv6 address. My IPv6 address prefix is 2a01:XXX:8b25:7ea0::/64 which looks pretty random but of course is not.
The part 2a01:xx is, from previous knowledge, a global unicast prefix (the 2xxx: indicates that) and the full form 2a01:xx is the RIPE-allocated prefix used by Free. The next part, 58 b2 57 ea? Well, I write is deliberately in that format to show that it breaks down to (decimal): 88 XXX XXX XXX. This, by no coincidence at all, is my current IPv4 address! Of course Free mapping subscribers’ IPv4 addresses into their IPv6 prefix is entirely arbitrary on their part. It indeed seems like a good idea, but is absolutely not required. In the future, for example, IPv4 addresses will not be used in the first place, so no such mapping would be possible.
Of course their network prefix is, as per standard IPv6, 64 bits in length. So the second 64 bits (the host portion) is entirely mine to use as I see fit. That is a seriously large amount of address space, all globally routable, and all entirely mine to use as I wish.
Since my ISP themselves run radvd (or some equivalent) on their routers, when everything is IPv6 enabled on my firewall system, the Internet-facing interface, eth0, should automatically pick up the required prefix and use it. However in addition to the ISP-prefix + MAC-derived host portion I also want a simplified address on the interface. It’s absolutely not required, but I want it to make my life slightly easier.
So prior to the reboot I edit
and add a section as follows:
[EDIT 2 Aug 2011: A booboo… the “netmask 64” previously on my eth0 config (and resulting displays) is unlikely to be what you want! If this was a single interface machine, that’d be fine (although pedantically incorrect). But given that eth0 here is the WAN port, and there’s “the rest” of that IPv6 network behind eth1, the eth0 interface static address should be defined as a full 128 bit mask, while the eth1 should be (probably – your mileage may vary…) the 64 bit one. Otherwise you end up with 2 equal routes for the same network, one out of each interface. Very very unlikely to be what you want!!!!!)
With this I am specifying that in addition to any automatic address the interface picks up, I also want to statically assign a PREFIX+::1 address to the interface.
After the boot I inspect the results and see:
Excellent! We see the link address that was there previously. And now we have two global addresses. The one marked dynamic which is clearly the MAC-derived address (notice how the prefix is as expected – this was picked up not from any of our config but from a remotely received router advertisement from the ISP) and the one marked tentative which is as manually configured by me.
When we set up the shorewall6 firewall, everything was marked as blocked except for ipv6-icmp. Ostensibly this was to permit what we are about to do now, a ping test, which makes use of ICMP. However it was also in the knowledge that the Router Advertisements which we picked up from the ISP, and which gave us the prefix to be used for the dynamic address, are also, coincidentally, ICMP6. Two birds with one stone: we allow pings to go in and out, and also allow IPv6 Router Advertisements to pass unhindered.
So, to test our interface, let’s try something:
Which is great, but where’s the routing and so forth that is being used here? Let’s look at that too:
That’s kind of like our IPv4 ARP table: where is, in Layer 2 terms, the next hop? And we see it at the given link address, with a corresponding MAC address, and a marker of REACHABLE. That REACHABLE can change as entries get set up and then age out, and values such as DELAY or STALE might also be seen.
Note that the default route is, automatically, via the adjacent router we learned about from the router advertisement.
So at this point we now know that we have basic IPv6 connectivity in and out of the firewall.
What we’ve done here, after a quick recap of IPv6 addressing techniques, is to:
- Enable a default “block almost everything” IPv6 firewall.
- Understand the three major subsystems which might b used on an IPv6 router/firewall (dhcp6c, dhcp6s, radvd)
- Understand that we possibly only need radvd and to install it on the firewall.
- Assign an automatic address to our Internet-facing interface, based upon a received router advertsiement.
- Assign a static address to the same interface, in addition to the automatic address.
- See how we can examine IPv6 information relating to interfaces, route tables and neighbours.
- Monitor IPv6 activity for troubleshooting purposes.
- Do a simple ping test to confirm that we have basic IPv6 connectivity from the firewall out to the IPv6-Internet.
In the next part I will look at extending IPv6 inside the private network, and examining options for moving the VPN to a native IPv6 implementation.