Before I go into the well-worn reasons why nobody cares about IPv6, I’ll tell you the one absolutely compelling reason why you should care: IPv6 comes pre-enabled on a lot of devices you have on your network right now.
When services are enabled without your knowledge, that’s just dangerous. If I wrote malware, one of the ways I’d avoid detection would be to use IPv6 to spread between systems inside your network—because I’d know you aren’t watching that channel, and because IPv6 security tools are less mature.
One way to ensure you are watching that channel is to turn it on, let it flow, and enable good controls over it. Before you do, let’s take a look at some of the background and theory of IPv6 that are important to implementing it well.
Why IPv6 adoption has been slow
IPv6 was invented in 1998 to prevent the imminent death of the Internet through the exhaustion of existing 32-bit IPv4 addresses. It’s now 2015 and the Internet is still hobbling along on 32-bit addresses.
We’ve managed to avoid our fate through heavy use of Network Address Translation (NAT). Everybody uses private addresses (10.x.x.x, 172.16-31.x.x, and 192.168.x.x) inside their networks, and only keeps a small number of globally accessible public addresses for things like Internet connections. It mostly works.
There are, however, a few places where NAT doesn’t work very well. Some protocols don’t cope well with NAT because they include IP address information in the payload as well as the headers of packets. The device sending the packet doesn’t, in general, know what address the receiver will know it by, so including locally relevant IP addresses is dangerous.
The usual workaround is to have the device doing the NAT also rewrite internal information inside the packet payload. But even this isn’t always possible because the payload could be encrypted or the NAT device might not understand the protocol well enough to find and change information in the packet payload.
The other place where universal NAT has problems is in networks that have too many devices. Suppose you’re using the 10.x.x.x network for internal routing. That gives you a theoretical maximum of 2^24, or 16 million, distinct internal addresses (though practically speaking, it’s less than that because we lose a bunch to subnetting).
Sixteen million addresses is plenty if you can do some sort of geographical division with additional internal NAT boundaries. But it’s not plenty if you’re trying to facilitate seamless roaming of hundreds of millions of cellphones. It’s hard to roam across a NAT boundary.
I expect we’ll continue to hobble along as we’ve been doing until somebody either mandates IPv6 or offers a highly desirable service exclusively to IPv6 destination devices. So far, neither of these has happened—but they could.
But, as I said earlier, just the fact that IPv6 is already there on your devices and your network is enough reason to shine a light on it.
Understanding IPv6 addresses
Where IPv4 uses 32-bit addresses, usually written as a set of four decimal numbers separated by dots, IPv6 uses 128-bit addresses. IPv6 addresses are usually written as eight sets of four-character hexadecimal numbers separated by colons.
Hexadecimal means base 16 (numbers from 0 to 15). A four-digit hexadecimal number has 16 bits (2^4=16). To designate a base-16 number with a single character, it’s customary to use the digits from 0 through 9 followed by the letters A through F. And to make it clear that a particular digit is hexadecimal instead of a normal decimal number, you put “0x” in front of it.
0x1 = 1 0x2 = 2 … 0x9 = 9 0xa = 10 0xb = 11 0xc = 12 0xd = 13 0xe = 14 0xf = 15
There are eight four-digit blocks of numbers in a full IPv6 address. Here’s a real example. (I found it from my own Windows computer by typing “ipconfig /all”. Try it.)
That’s rather long and awkward to write, so there are some useful rules for shortening the address notation. First, we can suppress all leading 0s. So 03e8 is the same as 3e8 and all those strings of 0000 can be written simply as 0.
A really useful second rule is that you can replace two or more blocks of 0000 in succession with ::. So our example address can be shortened to this:
That’s somewhat better. The second rule is a little bit sneaky though. If the address has more than one string of zeroes, you can only replace the longest one with the double colon. So an address like this one:
would be rewritten like this:
Just as IPv4 has several special addresses and special ranges of addresses (like 10.x.x.x for private addresses and 127.0.0.1 for your loopback), IPv6 does too.
In the above examples, the first block is fe80. It’s a very important block of addresses that you’ll run into everywhere. It’s called link-local, and I’ll explain what that means in a moment.
A good example of an efficiently shortened address is the standard IPv6 loopback address ::1/128. It’s the IPv6 equivalent of the IPv4 address 127.0.0.1/32, which every device uses to refer to itself.
Quite frequently, you’ll also see 2001 in the first block. This range includes several reserved ranges.
IPv6 uses the slash notation for subnet masks. Slash is also used in IPv4, but in IPv4 we have the additional confusion of also writing subnet masks using numbers like 255.255.255.0.
The slash notation is actually much easier once you get used to it. The number after the / indicates the number of bits in the network portion of the IP address.
An IPv4 address has 32 bits, so the number after the / must be between 1 and 32. An IPv6 address has 128 bits, so the number after the slash must be between 1 and 128. However, just as the most common IPv4 mask is /24, the most common IPv6 value is /64.
Link-local, global addresses, and autoconfiguration
Link-local addresses are generated automatically. They’re only valid on the local LAN segment. When my computer joins the network, it creates a link-local address for itself and uses that for communicating with the nearest router, negotiating its IP address and so forth. It never uses the link-local address for sending packets to other networks. Before it can do that, the computer needs a global address.
In IPv4 networks, the only way for a new device to automatically discover its local network and start communicating is to use Dynamic Host Configuration Protocol (DHCP). The IPv4 process involves broadcasting a DHCP packet onto the network and requesting information about the local network, the default gateway, the DNS servers, and so on.
IPv6 has two different methods for automatically configuring devices:
- stateful autoconfiguration using DHCPv6, and
- stateless autoconfiguration, known as Neighbor Discovery Protocol (NDP).
How Neighbor Discovery Protocol works
NDP is a simple protocol that IPv6 devices use to figure out what address they should use, as well as how to find the router that will forward their packets to the rest of the world. It’s based on the IPv6 version of ICMP, a protocol that should be familiar to IPv4 users who use it with the common ping utility.
Network devices can send an IPv6 neighbor discovery router solicitation (RS) packet to the default multicast address that all routers always listen to. Any router on the segment that receives it will respond with an IPv6 neighbor discovery router advertisement (RA). The RA tells it how to forward packets to destinations that aren’t on the same segment.
Similarly, IPv6 uses the IPv6 neighbor discovery neighbor solicitation (NS) multicast to discover the MAC address of another host on the same segment. The neighboring device responds with a neighbor advertisement packet. This is the IPv6 analog to Address Resolution Protocol (ARP).
How addressing works with stateless autoconfiguration
IPv6 has a built-in feature called stateless autoconfiguration that allows new devices to join a network and start working with zero information and without a DHCP server. In general, though, you’ll probably want to use DHCP as well.
When a new device joins the network, the first thing it does is generate a link-local address from the range mentioned above. It always sets the first part of the address to fe80. Then it sets the last 64 bits according to a standard set of rules, defined uniquely from the device’s Ethernet MAC address. All of the other digits in the address are zeroes.
That address is supposed to be unique, but there’s always a chance that something went wrong. So the next thing it does is use a neighbor solicitation message to try to find any other devices on the same segment that might already be using the address. If the address isn’t in use, then it’s safe to start using it. However, the protocol doesn’t actually define what the device should do next if it does encounter a conflict.
Then the device uses its link-local address to contact the router for the segment. It sends a router solicitation message and waits for a router advertisement in response that will tell it how to reach the rest of the world.
But it still can’t reach the rest of the world because it doesn’t have a globally unique address. To automatically generate the global IPv6 address, the device takes the first 64 bits of the router’s address, which it learned from the router advertisement, and the last 64 bits from its own link-local address.
This addressing is important to remember. When you use stateless autoconfiguration, devices assume they’re operating on a /64 subnet. If you need to use a different subnet masking scheme, you must configure the addressing either statically or via DHCPv6.
IPv6 multicasts are more efficient
Another important way that IPv6 differs from IPv4 is its use of multicast. In IPv4, we use broadcast messages quite frequently. When a new host needs to find out its IP address, it sends out a DHCP broadcast. When it needs to communicate with a destination IP address but doesn’t know the corresponding Ethernet MAC address, it sends out an ARP broadcast.
The trouble with broadcasts is that every device on the same network has to pay attention to every broadcast packet. Those broadcast packets are received by the host’s NIC and passed up the protocol stack, taking up CPU and memory resources on every system. Broadcasts are not a very efficient way to use the network. So IPv6 uses multicast instead.
In multicast, the sending device transmits a packet with a special IP address and a special Ethernet MAC address. Any other device on the network that’s taking part in that particular multicast protocol picks it up and processes it, but everybody else can ignore it.
Making things even better, if the switches are configured correctly, they can keep track of which devices are interested in which multicast protocols. Then the switch only forwards those multicast packets to the interested devices. This helps reduce network congestion.
IPv6 has lots of headers
So far, our whole discussion has been a comparison between IPv6 and IPv4, but the differences are even bigger than I’ve implied. IPv6 is not just IPv4 with a longer address. It really is a completely different protocol.
The protocols that it carries, like HTTP and SMTP, are the same. But the IP part of the packet—the IP headers—are different. IPv4 only has one type of packet header. IPv6 has lots of them. And in IPv6 you build them up recursively.
Every packet has to have the standard IPv6 header with source and destination addresses. This header also includes a field called next header. It contains a number that defines what type of header comes next. And that nested header has its own next header field, which could point to yet another header.
The original intention of IPv6 was that these nested headers would allow for various protocol extensions. There are extension headers that support IPsec encryption and authentication, for example. There are also extension headers that define hop-by-hop forwarding characteristics in a way that’s considerably more precise and more general than the Quality of Service formalism that comes with IPv4.
It’s too bad NAT is missing from IPv6
One of the features of IPv6 that I dislike is that it doesn’t include NAT. Now, remember the reason IPv6 was invented in the first place was to provide enough addresses so that every device could be globally unique. So it makes sense that the protocol designers would want to keep NAT out of the picture. But the problem is that there are a lot of good reasons for doing NAT that have nothing to do with address exhaustion issues.
For example, I often like to use NAT in IPv4 to simplify server routing tables. If a server has two or more interfaces, one of which is intended to service generic Internet users, then I want to attach the default route to that interface.
But if the internal devices that communicate with this server through its other interface are located on many different subnets, that means I generally have to manually configure each of the subnets into the server’s routing table. This quickly becomes difficult to manage.
A common solution is to use NAT to make all of the devices appear to be on the same subnet as the internal-facing server interface. Then I only need a single default route on the server.
And, of course, NAT is also used extensively for privacy reasons. I don’t want the entire Internet to be able to uniquely track my every move from my IP address. IPv6 has built-in IPsec encapsulation, but it doesn’t help hide my metadata for common web browsing, even if everything uses HTTPS.
NAT isn’t prohibited in IPv6, it’s just not supported or encouraged. So I expect that, as IPv6 adoption increases, we’ll see de facto IPv6 NAT standards emerge.
I don’t strongly advocate a push to IPv6 migration. IPv4 is really just fine for most current requirements. But most of your devices are already turning IPv6 on by default, so it makes sense to at least start making the network ready as well.
In a future blog post, I’ll show you how to implement some of this IPv6 learning on Cisco devices.