IPv6 at home – a guide to getting started

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

Link encap:Ethernet  HWaddr 00:40:63:f5:f9:3c
inet addr:88.XXX.XX.XXX  Bcast:88.XXX.XXX.255  Mask:
inet6 addr: fe80::240:63ff:fef5:XXX/64 Scope:Link
RX packets:14086899 errors:0 dropped:0 overruns:0 frame:0
TX packets:15607323 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1837525573 (1.8 GB)  TX bytes:666354591 (666.3 MB)
Interrupt:16 Base address:0x8000

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.

IPv6 Basics

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.

IPv6 Addresses

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, 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 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.

Network 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.)

Host bits

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:

Link encap:Ethernet  HWaddr 00:40:63:f5:f9:3c
inet addr:88.XXX.XX.XXX  Bcast:88.XXX.XXX.255  Mask:
inet6 addr: fe80::240:63ff:fef5:XXX/64 Scope:Link
RX packets:14086899 errors:0 dropped:0 overruns:0 frame:0
TX packets:15607323 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1837525573 (1.8 GB)  TX bytes:666354591 (666.3 MB)
Interrupt:16 Base address:0x8000

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:

Link encap:Ethernet  HWaddr 00:16:3e:2e:50:36
inet addr:217.XXX.XXX.XXX  Bcast:217.XXX.XXX.255  Mask:
inet6 addr: fe80::216:3eff:fe2e:XXX/64 Scope:Link
inet6 addr: 2001:XXX:41::d946:bf36:54/128 Scope:Global
RX packets:122352 errors:0 dropped:0 overruns:0 frame:0
TX packets:68714 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:34644771 (34.6 MB)  TX bytes:62489400 (62.4 MB)

What have we got? The interesting parts break down as follows:

  1. The interface has a L2 MAC address of 00:16:3e:2e:50:36
  2. The IPv4 addressing is as it always has been – No change there.
  3. 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.
  4. 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:

ip addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
link/ether 00:16:3e:2e:50:36 brd ff:ff:ff:ff:ff:ff
inet 217.XXX.XXX.XXX/22 brd 217.XXX.XXX.255 scope global eth0
inet6 2001:XXX:41::d946:bf36:54/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::216:3eff:fe2e:XXX/64 scope link
valid_lft forever preferred_lft forever

This is analogous to the simple ifconfig: we’ve got L2 MAC, IPv4, and a couple of IPv6 addresses showing.

ip -4 addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000
inet 217.XXX.XXX.XXX/22 brd 217.XXX.XXX.255 scope global eth0

Look how much neater that is, even just for IPv4: no L2 MAC, no IPv6, just the IPv4-related information.

ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2001:XXX:41::d946:bf36:54/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::216:3eff:fe2e:XXX/64 scope link
valid_lft forever preferred_lft forever

And similarly here: we just get IPv6-related information, and nothing else.

It may take a little effort to get used to it, but it’s worth the effort. And feel free to make use of alias to make life even easier. If you tire of typing -6 after each invocation of IP, then do something like:

alias ip6=’ip -6′

and then you can just enter:

ip6 addr show

which is quite neat.

Key subsystems

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
  • dhcp6s
  • radvd


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.

Careful now….

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:

cd /etc/shorewall6/

Set up the following files in a similar manner as shown here:

ext     eth0     –
int     eth1     –
int     ipv6
ext     ipv6
fwall   firewall
#Source  Dest    Policy     Log     Burst/Limit
fwall     all     DROP
int       all     DROP
ext       all     DROP
all       all     DROP

# Allow only ping – for testing

ACCEPT     ext     fwall     ipv6-icmp
ACCEPT     fwall     ext     ipv6-icmp

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.:

/etc/init.d/shorewall6 start

And then

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:

ip6 add show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 fe80::240:63ff:fef5:XXX/64 scope link
valid_lft forever preferred_lft forever

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:

iface eth0 inet6 static
address 2a01:XXX:8b25:7ea0::1
netmask 128

[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:

ip6 addr show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
inet6 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c/128 scope global dynamic
valid_lft 86369sec preferred_lft 86369sec
inet6 2a01:XXX:8b25:7ea0::1/128 scope global tentative
valid_lft forever preferred_lft forever
inet6 fe80::240:63ff:fef5:XXX/64 scope link
valid_lft forever preferred_lft forever

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:

ping6 ipv6.google.com
PING ipv6.google.com(2a00:1450:8006::69) 56 data bytes
64 bytes from 2a00:1450:8006::69: icmp_seq=1 ttl=54 time=39.4 ms
64 bytes from 2a00:1450:8006::69: icmp_seq=2 ttl=54 time=38.4 ms
64 bytes from 2a00:1450:8006::69: icmp_seq=3 ttl=54 time=35.6 ms

It works!!

Which is great, but where’s the routing and so forth that is being used here? Let’s look at that too:

ip6 neigh show
fe80::XXX:cbff:fea5:1a68 dev eth0 lladdr 00:07:cb:a5:1a:68 router REACHABLE

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.

ip6 route show
2a01:XXX:8b25:7ea0::/128 dev eth0  proto kernel  metric 256  expires 85889sec mtu 1480 advmss 1420 hoplimit 0
fe80::/64 dev eth1  proto kernel  metric 256  mtu 1500 advmss 1440 hoplimit 0
fe80::/64 dev eth0  proto kernel  metric 256  mtu 1480 advmss 1420 hoplimit 0
default via fe80::XXX:cbff:fea5:1a68 dev eth0  proto kernel  metric 1024  expires 1283sec mtu 1480 advmss 1420 hoplimit 64

Note that the default route is, automatically, via the adjacent router we learned about from the router advertisement.

ip6 monitor dev eth1 lladdr 00:18:8b:86:f3:52 STALE
ff02::1:fff5:f93c via ff02::1:fff5:f93c dev eth0  metric 0
cache  mtu 1480 advmss 1420 hoplimit 0
fe80::XXX:cbff:fea5:1a68 dev eth0 lladdr 00:07:cb:a5:1a:68 router REACHABLE dev eth1 lladdr 00:18:8b:86:f3:52 STALE
fe80::XXX:cbff:fea5:1a68 dev eth0 lladdr 00:07:cb:a5:1a:68 router STALE
The monitor command is quite interesting. It shows the significant state changes as they occur. Here we can see IPv4 ARP entries aging out, and IPv6 neighbors becoming active and then stale.
And of course to really shine a light on what’s happening, we could do something like:
tcpdump ip6 -i eth0
16:00:58.856832 IP6 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c > 2a00:1450:8006::6a: ICMP6, echo request, seq 1, length 64
16:00:58.897135 IP6 fe80::207:cbff:fea5:XXX > ff02::1:fff5:f93c: ICMP6, neighbor solicitation, who has 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c, length 32
16:00:58.897305 IP6 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c > fe80::207:cbff:fea5:1a68: ICMP6, neighbor advertisement, tgt is 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c, length 32
16:00:58.897664 IP6 2a00:XXX:8006::6a > 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c: ICMP6, echo reply, seq 1, length 64
16:00:59.856858 IP6 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c > 2a00:1450:8006::6a: ICMP6, echo request, seq 2, length 64
16:00:59.892915 IP6 2a00:XXX:8006::6a > 2a01:XXX:8b25:7ea0:240:63ff:fef5:f93c: ICMP6, echo reply, seq 2, length 64


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.

8 comments to IPv6 at home – a guide to getting started

  • Here’s another article where I tackle the issue of IPv6 firewall logging: http://www.ipsidixit.net/2010/02/25/231/

  • Once IPv6 is set up and working, prior to us becoming a fully-fledged router we need to enable forwarding. This is covered, along with the problems it then brings, in this post here.

  • I’ve rather glossed over the whole question of DNS… Since we’re choosing to not implement IPv6 DHCP server, how do clients machine pick up the DNS? Sure, they get the address prefix from RADVD, but what about anything else?

    In the first instance all my client will be dual-stack IPv4 & IPv6. They already have the IPv4 DNS known and active so we will let them continue to use that. Of course if IPv4 does one day disappear, and we run as single-stack IPv6, this would need to be addressed.

  • J. Grizzard

    You imply above that the only reason you allow ICMPv6 through your firewall is so that pings will work for testing (and thus could be removed after testing). This is a very bad thing to teach people, because it has the potential to be destructive in the IPv6 world. You need to let several different types of ICMPv6 messages through, for things to work correctly.

    In particular, type 2 datagrams (“packet too big”) are used for path MTU discovery. IPv6 does not support packet fragmentation — if your MTU is too big for something in your path, that traffic will get dropped, and the sending system will never know that it needs to back off on packet sizes. This type of problem can be *very* difficult to debug… it appears as a problem with an upstream connection, even though the problem is actually right there on your firewall.

    Some type 1, type 3, and type 4 codes should also be allowed, no matter what.

    RFC 4890 (http://www.ietf.org/rfc/rfc4890.txt) has a more thorough discussion of ICMPv6 filtering requirements and recommendations.

    • Thanks for those thoughts. Absolutely good points all. However I think my omission is actually that I have not defined just *what* it is that this IPv6 box/firewall/router/VPN/younameit is actually ultimately going to be used for!!! Thus far, as this incremental project has progressed, all my IPv6 has terminated (in various manners) on the firewall box itself. (Note to purists: Yes, the firewall should NOT be the same device as the router/server/younnameit box… but it usually is!) When (if? No when, it will happen eventually…) I have this firewall actually routing traffic to/from the internal networks, then such matters as mentioned here need closer attention.

      The RFC link is good for those in to RFCs…. But for those who have led an unblemished life, free from the taint of data comms RFCs, I advise caution. They drive you mad if treated without care. 😉

      Anyway, good information. One day when I write further articles about my IPv6 project, I’ll be sure to refer folks back to your comment here!! Thanks!

  • […] Hurricane Electric – Tunnel Broker Easy Config for Linux Router Building a IPv6 Gateway anyweb sample configurations IPv6 – Ubuntu Wiki Ubuntu UFW Firewall Private Class B Network Address Neighbor Discovery for IP Version 6 Radvd config manpage Enabling IPv6 Privacy Extensions on Ubuntu Linux IPv6 at home – A guide to getting started […]

  • Andrew J. Leer

    Thanks for writing this tutorial! I am enjoying it greatly.

    There’s a spelling mistake (no big deal I’m sure) but if you want to correct it I’m letting you know in the “DHCP client I get, but what’s with DHCP server versus radvd?” it reads “since it dos not allocate any” instead of “since it does not allocate any”

    You can delete my comment if you like, I just wanted to let you know about it.