IPv6 Part 5: Stateful DHCPv6

Using DHCP to manage IPv6 addresses is known as stateful DHCPv6, because the DHCP server maintains the state of IP address leases centrally. In the last post we looked at its limitations, as opposed to SLAAC. Why would you use DHCPv6 to manage IPv6 addresses? Well the main reason is accountability. One of the most important aspects of this is host DNS registration: having your hosts registered in DNS and available for reverse DNS lookup is the most basic way of tracking them. If you use DHCPv6 for address assignment then the DHCP server will register the host with DNS (typically the two services run on the same server). If you are using SLAAC then hosts themselves are responsible for registering themselves in DNS : this is inherently less reliable.

In fact DHCPv6 has made DNS registration more robust than under IPv4. With IPv4, it’s a simple model: each MAC address is a separate entity, and each interface makes its own independent registration in DHCP. This can cause problems with DNS registration when a host has multiple interfaces, as is increasingly the case where laptops are connected both to the office wired LAN and to a wireless network. If the host is registered in DNS under one interface, then depending on how things are configured the second interface may not be registered in DNS at all. Alternatively the second interface may supersede the DNS registration of the first interface.

DHCPv6 introduces the concept of the DHCP Unique Identifier (DUID). The DUID is a persistent identifier of the host rather than any specific interface. IP addresses are actually assigned to Interface Associations (IAs) which identify the individual interfaces. Thus DHCPv6 understands that hosts can have multiple interfaces and DNS hostname registrations can be done according to the DUID rather than the IA.

Another reason that you might want to use DHCP to manage addresses is to make it easier to find out an interface’s MAC address from its IP address. Take the example of a security alert you receive from your intrusion prevention system or DNS firewall: an IP address is trying to contact a known botnet command and control (C2) server. You want to disconnect that IP address from the network as quickly as possible, preferably automatically. Under DHCPv4 it’s possible by looking up the IP address in the DHCP server and extracting the MAC address, and then using whatever tools your network may provide to track down the specific network port that that MAC address is connected to. You can then disable the port.

Sadly, the way that DHCPv6 works makes this much harder. Although the DUID of a host usually contains a MAC address, it is typically generated at install time from the MAC address of any interface on the system. That interface can in fact be removed from the host after the DUID has been generated and the DUID will stay the same. The Interface Association Identifier (IAID) is generated in an arbitrary way by the host, and may have no relation to the physical MAC address of the interface. If the DHCP server is not on the same subnet as the client, and is receiving the DHCP request via a relay, then the server has no visibility of the client’s MAC address. Thus there can be no way of building a centralised mapping of IP addresses to MAC addresses. RFC 6939 does provide a mechanism for DHCP relays to forward the client’s MAC address to the DHCPv6 server, but this is quite a recent proposal. So, one step forward, one step back.

Next post I’ll summarise the SLAAC vs stateful DHCPv6 debate.

IPv6 Part 4: SLAAC history

As I explained in the last post, IPv6 SLAAC addressing derives the host portion of the routeable address from the interface MAC address, and discovers the network portion from the network itself. Those of you who have been in the IT business long enough will find this familiar: it’s similar to the way that Novell’s IPX protocol worked. In fact, IPX was based on Xerox’s XNS protocol, which goes back to the late 1970s. In both cases, the host portion of the address was 48 bits long, the length of the MAC address: MAC addresses are globally unique, thus ensuring no local address clashes.

Novell introduced the Service Advertising Protocol (SAP), whereby servers advertised their services via broadcasts to routers. By querying their local router, clients could then choose which service to connect to from a dynamically compiled list. Thus service discovery was decentralised, in a way that was consistent with the decentralised way that clients obtained their addresses. When NetWare 5 moved to running over TCP/IP, Novell migrated to the open Service Location Protocol. Microsoft’s networking had similar distributed methods of advertising resources.

DHCP was already in existence when SLAAC was developed. SLAAC’s big advantage over DHCP was its simplicity: it didn’t require the administrative overhead of DHCP. SLAAC as originally conceived did one job and it did it very well: it assigned an address in a simple, scalable way. However what if you weren’t using a network protocol like NetWare or Microsoft that advertised the available resources? Specifically, how did clients configure their DNS servers and DNS search domains? The answer was to use a combination of SLAAC for address assignment and (stateless) DHCP for the other parameters. So you still needed to set up DHCP servers; however the configuration information that they distributed was relatively static.

So you couldn’t avoid DHCP completely. However, it’s difficult to manage addresses from DHCP servers in a way that’s scalable and resilient. Microsoft’s DHCP server was (and is) probably the most widely used DHCP server for IPv4, and to provide load-balancing and redundancy the typical method was to configure “split scopes” on multiple DHCP servers. Each server would assign addresses from a different chunk of the same subnet’s address range. Clients would receive their address from whichever DHCP server responded first. Clients would continue to renew their address leases from the same server, until or unless it became unavailable; they would take a while to realise that a server was unavailable, and wouldn’t use it again once recovered until they were forced to release their addresses and begin the whole address assignment process again.

Things got really messy if you used DHCP address reservations. There was no automatic replication of reservations across the servers, so each reservation had to be copied from server to server manually. Inevitably this was error-prone: if you needed specific hosts to always get the same address, for example for firewall rules, then things could often get broken.

Microsoft’s DHCP implementation has gradually improved. Windows Server 2012 introduced DHCP failover for IPv4, with dynamic replication of DHCP address state. However, this won’t manage IPv6 addresses: the assumption is that you will use SLAAC for that. In addition, DNS, DHCP and IP Address Management (DDI) systems like Infoblox and Efficient IP have emerged that dynamically replicate DHCP address state, for IPv6 as well as IPv4, in an effective and resilient way. The DDI systems come with a price tag however, as opposed to Microsoft DHCP which comes bundled with Windows Server. So why would you use DHCP to manage IPv6 addresses? In the next post, I’ll take a look at why you might want to.

IPv6 Part 3: Address auto-configuration

In the previous post I explained that network prefixes in IPv6 are nearly always a fixed 64 bits in length, with a few exceptions. Strictly speaking, it’s actually the interface ID that’s fixed at 64 bits, which means that because IPv6 addresses are 128 bits long the network prefix has to be 64 bits too. The reason for this is to meet the needs of address auto-configuration, which is a new feature of IPv6 that supports:

  • link-local address auto-configuration (so-called plug-and-play)
  • stateless address auto-configuration (SLAAC, for global addresses)

Link-local addressing is pretty fundamental to IPv6. It enables a host to communicate with other nodes on the same network without the need for manual configuration or a DHCP server. The process is as follows:

  1. In the conventional method the host generates a 64-bit identifier for the interface by taking its 48-bit MAC address and inserting the string fffe into the middle. Then it “flips” bit 7 of the address from 0 to 1, so that the MAC address:

    00:cd:fe:12:34:56

    generates the interface ID:

    2cd:feff:fe12:3456.

    This is what’s known as a Modified EUI-64 identifier (there are other methods but I will cover those in a later post).

  2. The host prefixes this identifier with the link-local network prefix fe80::/64, so that our example MAC address generates the link-local address:

    fe80::2cd:feff:fe12:3456.

  3. The host then tests this address for uniqueness on the local subnet by sending a Neighbor Solicitation message (ICMPv6 type 135) to the generated address. If it gets a Neighbor Advertisement message (ICMPv6 type 136) in reply then the process halts.
  4. If there is no response then the link-local address is assigned to the interface.

IPv6 link-local addressing

You can find more detail on this at Packetlife.

Once the link-local address is configured, the host sends a Router Solicitation message (ICMPv6 type 133) to the All Local Routers multicast address ff02::2. If there’s a local IPv6 router it will respond with a Router Advertisement message (ICMPv6 type 134). If that tells the host that it should auto-configure a global address then:

  1. The host will take the 64-bit global prefix advertised by the router and combine it with the 64-bit interface identifier previously generated to create a global address, so if the prefix is:

    2001:db8:1234:5678

    then our example interface ID generates the global address:

    2001:db8:1234:5678:2cd:feff:fe12:3456.

  2. It will test for uniqueness on the local subnet as for the link-local address
  3. If there is no response then the global address is assigned to the interface.

IPv6 SLAAC

The whole set of messages and processes, together with other ancilliary messages and processes, is known as Neighbor Discovery. In principle other methods of global addressing (manual, DHCP) could use a variable-length prefix. However the address architecture RFC (RFC 4291) stipulates a 64-bit interface ID regardless of the configuration method. RFC 5375 warns against straying from the /64 prefix:

Using a subnet prefix length other than a /64 will break many features of IPv6, including Neighbor Discovery (ND), Secure Neighbor Discovery (SEND) [RFC3971], privacy extensions [RFC4941], parts of Mobile IPv6 [RFC4866], Protocol Independent Multicast – Sparse Mode (PIM-SM) with Embedded-RP [RFC3956], and Site Multihoming by IPv6 Intermediation (SHIM6) [SHIM6], among others.

In fact it’s specifically the SLAAC component of Neighbor Discovery that would be broken by a global network prefix other than /64, because of the way that the interface ID is generated.

In the next post, I’ll delve more into the background of SLAAC.

Yes it’s a lot of bits but…

Let’s take a look at the structure of an IPv6 Global Unicast address (GUA), a globally-routeable address:

IPv6 addresses, like IPv4 addresses, are Big Endian, that is, the most significant bits come first. That’s similar to decimal numbers, where thousands come before hundreds and so on. The most significant bits (the “high-order” bits) at the beginning of a GUA form the global routeing prefix. This is used by Internet Service Providers (ISPs) to route traffic through the global Internet.

The standard IPv6 global routeing prefix assigned to a single-site enterprise is a /48. RFC 3177 specified /48 as the standard prefix for all sites, even home users, but subsequently RFC 6177 recommended longer prefixes for small enterprises and home users. With IPv4 an enterprise may only be assigned a /24, if that. That means that ISPs have (very) roughly 16 million times the address space to work with (248 versus 224); in fact 48 bits provides about 280 trillion prefixes, or roughly 38,000 prefixes for every human on the planet.

It’s the structure at the local end of an IPv6 address that’s surprising for someone like me who has worked with IPv4 all through their career. The network prefix (what in IPv4 is called the subnet mask) is a fixed /64 in length, as opposed to the variable-length subnet masking (VLSM) of IPv4. That means that the interface ID (broadly the IPv6 equivalent of the host ID) is also 64 bits long. In other words there’s enough address space on each subnet for 264 hosts, i.e. 18446744073709551616, or enough M&Ms to fill the Great Lakes.

Now that’s a huge number. With current networking technology it’s difficult to imagine it being practical to have more than, say, 10000 hosts on a single subnet. That only requires 14 bits, so the other (most significant) 50 bits are effectively redundant, in other words 18446744073709535232 addresses or 99.99999999999991%. In practice there is likely to be parallel running of IPv4 and IPv6 on the same subnets for some time, and IPv4 subnets are typically much smaller, say, 256 hosts, so the redundancy will be greater still.

The consequence of this fixed /64 network prefix is that the subnet ID, which is the local part of the network prefix, is typically only sixteen bits. For IPv4, most enterprises use private RFC 1918 addressing combined with Network Address Translation. They often utilise the 10/8 private prefix subnetted down to a /24 for individual subnets, which also provides a 16-bit subnet addressing space. So in practice IPv6 doesn’t provide any additional subnet address space for many enterprises compared to IPv4.

Sixteen bits is still a large number, equivalent to 65536 addresses, and it would be very generous if enterprises used those sixteen bits as a completely flat address space. However they usually structure the local subnet space hierarchically, in order to aggregate routes efficiently and minimise internal routeing tables (just as the global routeing address space is structured). IPv6 does have the advantage for network administrators that addresses are represented in hex rather than IPv4’s decimal; each hex character represents four bits (a “nibble”) as opposed to the 8-bit components of an IPv4 address (an “octet”). This means that the subnet space can be divided conveniently into 4-bit chunks in a way that’s easy to read, and so less prone to error. It is generally recommended (by Coffeen 2014 for example) to follow this practice when designing your IPv6 subnetting structure.

Nevertheless creating a hierarchical structure in this way means that there will be inevitably some inefficiency in the use of the address space. For example, take a site that has 20 buildings with 20 subnets per building. Each nibble can encompass only 16 objects, so you would need to assign two nibbles to the site level of the hierarchy and two to the building level of the hierarchy, thus using up the available subnet space, with quite a lot of redundancy. This is almost a worse-case scenario, but it shows how the address space for local subnetting is not that generous, and looks positively stingy compared to the address space for interfaces.

In summary, IPv6 uses a roughly 48-bit address space for global routeing, That’s a huge amount of prefixes, and to be fair it does deliver the original goal of IPv6, which was to increase the global address space. However, the way that the local part of IPv6 addresses is structured means that there is no useable expansion of address space at the local end. That stuff about galaxies and light-years is (mostly) hype.

In the next post I’ll take a look at why IPv6 addresses are structured in this way.

That’s a lot of bits

Nanobots
© XKCD 2016

Up to now in my career I’ve been able to avoid IPv6, but I guess it’s time I faced the inevitable. IPv4 address exhaustion is upon us, and IPv6 adoption is creeping up: Google’s stats show a gradual increase in IPv6 connectivity, although IPv6 traffic is still very low. I live in Belgium, which at the time of writing has the highest level of IPv6 capability on the planet.

The original motivation for IPv6 was to expand the address space: in place of IPv4’s 32-bit addresses, IPv6 addresses are 128 bits, providing 2128 addresses, that’s 340282366920938463463374607431768211456, or about 340 trillion trillion trillion. That’s enough for an entire IPv4 Internet for every star in the universe, or an IPv6 address for every atom on the surface of the earth (and more than a hundred other planets) or if every address was a picometer (1 trillionth of a meter) then the whole address space would stretch 34 billion light years (while the furthest visible object in the universe is 13 billion light years away).

Let’s take a look at how IPv6 addresses are represented. Here’s an example of an IPv6 address:

2001:db8:1234:5678:9012:3456:7890:1234

The 128 bits are represented in hex, separated into eight groups of sixteen bits by colons. Sometimes the groups of sixteen bits are referred to as “quartets” (e.g. Writing IPv6 Addresses – Presented by Cricket Liu) and sometimes as “hextets” (e.g. Coffeen 2014, Chapter 2). I’ll follow Tom Coffeen’s practice and refer to them as hextets.

In the example address that I gave you’ll notice that there are only three hex digits in the second hextet. Leading zeroes within a hextet may be omitted, so that “:db8:” stands for “:0db8:”. A single hextet of all zeroes i.e. “:0000:” can be represented as a single zero “:0:”. A sequence of consecutive all-zero hextets can be represented as “::”, so that:

2001:0db8:0000:0000:0000:0000:0000:0001

is represented as:

2001:db8::1

Since we know that an IPv6 address is 128 bits long, we can work out that there are five missing hextets that have been condensed down to a single “::”. At one point you could also condense a single hextet of all zeroes to “::” but RFC 5952 mandates the “:0:” format.

Things get more complicated if there are more than one sequence of consecutive all-zero hextets in the same IPv6 address. Here’s another address:

2001:0db8:0000:0000:0001:0000:0000:0001

You can’t contract both sequences because you might end up with an ambiguous address: how many hextets would be represented by each “::”? Earlier RFCs didn’t document how you should handle this. RFC 5952 stipulated that you should condense the longest sequence of all-zero hextets, and if the two sequences are the same length then you should condense the first one, so the above example address would be condensed to:

2001:db8::1:0:0:1

RFC 5952 makes the rules on condensing all-zero hextets mandatory, and also specifies that systems should display IPv6 addresses with lower-case letters. It advises humans to follow the same rules.

IPv6 prefixes are represented in much the same way as IPv4 prefixes in CIDR notation, so that:

2001:db8::/32

represents every address from:

2001:db8::

to:

2001:db8:ffff:ffff:ffff:ffff:ffff:ffff

In the next post I’ll take a look at the way IPv6 addresses are structured.