In the 1990s it became clear that the world would run out of IP addresses. A new version of the Internet Protocol was developed, known as IP version 6, or IPv6 for short. It was published as a draft in 1998, and vendors began to implement it. RFC 5211, An Internet Transition Plan (2008), called for a switch over to IPv6 between January 2010 and December 2011.

In 2011 World IPv6 Day was held to mark the final year of the planned transition period. Also that year, the world ran out of IPv4 addresses. Unfortunately, even in 2026 IPv6 deployment is a long way from complete. Around 47% of Google users have IPv6, but the percentage varies a lot between countries — France has 85% coverage, but Spain has less than 12%.

You might have IPv6 Internet; you can find out by going to https://test-ipv6.com. If your computer has a globally routable address it will be in the 2000::/3 range. Some address blocks in that range are reserved for special purposes, however. Whether you have a global IPv6 address or not, you almost certainly have IPv6 on your local network. In addition, all mobile Internet in the US is exclusively IPv6 — IPv4 support is provided by tunneling it over IPv6 using short-lived IPv4 addresses. It’s therefore worth learning how IPv6 works.

When IPv6 was developed it was designed with completely new mechanisms for obtaining an IP address. They are still unfamiliar to many people who operate networks, and they have also changed in recent years; there are now over two dozen RFCs that relate to the process. This article attempts to summarize how it works today.

First, though, a brief summary of the problem.

The address assignment problem

In the early years of TCP/IP there was no mechanism to automatically assign IP addresses to computers and other network devices. Instead, each node on the network would be configured with a static IP address. It would be up to the network administrator to track address assignments and ensure no two systems had the same address. As local area networks were deployed more widely and more devices were added to them, it quickly became clear that a better more automated solution was needed, and several were introduced.

The first attempt to tackle the problem of IP address assignment was RFC 903, A Reverse Address Resolution Protocol (1984). In this scheme, a client computer connecting to the network would send out a broadcast Ethernet packet with the standard ARP EtherType of ADDRESS_RESOLUTION (0x0806), and an opcode of 03. A RARP server somewhere on the network would see the packet, look up the MAC address of the source, and respond directly to the client with another ARP packet, opcode 4. This packet would contain the hardware address and IP address of the server, and the hardware address and IP address for the client.

RARP sequence diagram

RARP was typically set up by having a rarpd server with a list of machines in the /etc/ethers configuration file:

bf:0a:fa:5f:45:20  192.168.1.101
5c:bd:c4:4f:f3:8f  192.168.1.103

Maintaining this file was still a manual process, but it did at least avoid the need to manually configure each network node. Unfortunately the use of Ethernet packets meant that it only worked on Ethernet networks, and that a separate RARP server was needed for every subnet.

RARP was quickly followed by BOOTP, the Bootstrap Protocol, defined in RFC 951, Bootstrap Protocol (1985). This replaced the raw Ethernet packets used in RARP with UDP packets, so that a single server could provide addresses across multiple subnets. The packet used two reserved port numbers, 67 for the server and 68 for the client. The reply contained the client’s assigned IP address, the server’s IP address, and the client’s MAC.

BOOTP sequence diagram

In cases where the client knew its IP address and/or the server’s IP address (perhaps from a previous BOOTP query), unicast packets could be used in place of broadcast.

BOOTP had additional fields to allow for additional functionality. For example, it allowed the server to provide a named boot image to the client, to allow machines to boot an operating system provided by the network. The protocol quickly got extended to supply other information client machines would need, such as DNS server addresses and domain names.

Eventually BOOTP was replaced with RFC 1531, Dynamic Host Configuration Protocol (1993), or DHCP for short. It was designed to be backward-compatible with BOOTP, so that it could provide services to existing BOOTP clients. It standardized the common extensions and added the ability to assign addresses from a pool, rather than needing a configuration file listing the address for each client. As memory got cheaper, routers began tracking which addresses they had leased out to which devices, to reduce the need for devices to change IP address.

DHCP remains the way most devices obtain IPv4 addresses. Your home Internet router has a DHCP server that tells each device connected to Wi-Fi or Ethernet what its IP address is, where to find the DNS server, and so on.

An imperfect solution

In the 1980s, the International Organization for Standardization (ISO) published standard X.200, the Open Systems Interconnection (OSI) model of network communication. The model divided network communication into 7 layers of abstraction, from the basic hardware up to the application program:

The OSI 7-layer model

This standard was very influential at the time, but unfortunately TCP/IP and its common protocols don’t fit the model very well. For example, HTTPS is an application protocol, but it also defines various data formats and compression schemes and handles session control, so it straddles layers 5, 6 and 7.

Similarly, DHCP operates over UDP (layer 6), but it requires details of MAC addresses (layer 2). This lack of clean separation between TCP/IP and the underlying network came to be seen as undesirable, as people wanted to transport TCP/IP over other types of network connection such as Frame Relay, HDLC, or dial-up modem, which lack MAC addresses.

The IPv4 approach also requires that each client machine broadcast a request to the entire subnet it is connected to. When Ethernet networks ran at 10Mbps, unnecessary broadcast traffic was a problem for large subnets.

Another issue for large subnets is that the DHCP server has to be stateful in order to track lease offers and manage the address pool. The need for a server can also be a problem for situations where it’s desirable to have an ad-hoc client-only local network.

In situations where a network segment has multiple internet links available, IPv4 DHCP offers no way to associate multiple IPv4 addresses with a single MAC in order to allow devices to be gracefully allocated new addresses when the network switches link.

IPv6 attempts to deal with all of these issues.

IPv6 and SLAAC

IPv6 introduces a new address allocation protocol known as SLAAC (pronounced ‘slack’), originally defined in RFC 1971, IPv6 Stateless Address Auto Configuration (1996). The RFC set out key goals for the new protocol:

  • No need for manual configuration of client machines.
  • No need for a stateful server or router on the network.
  • Devices can gracefully be given new network addresses without breaking connectivity.
  • If there is a router, it can tell clients whether to use SLAAC or some other mechanism.

IPv6 addresses

As a quick reminder, IPv6 addresses are 128 bits wide, and can be divided into three pieces:

  • 48 or more bits of network identifier (also known as the subscriber prefix)
  • 16 or fewer bits of subnet identifier
  • 64 bits of interface identifier

The network ID indicates how to route data between the customer network and the rest of the Internet. The network ID plus subnet ID always total 64 bits. ISPs may allocate each customer a 64 bit network ID, but they’re encouraged to give each customer a 48 bit ID to allow for subnet numbering.

The top 64 bits are generally referred to as the LAN prefix, or just “prefix”, and identify the route to a specific subnet. The interface ID identifies the device on that subnet.

For example, with a 16 bit subnet of 0001:

IPv6 address component illustration

Suppose a new device joins an existing network and wishes to obtain an IPv6 address via SLAAC and become a network node.

The first stage is that the new node must obtains a link-local address. This is unique only to a particular network link — the network it is joining — and so only valid for a specific network interface.

The address block fe80::/10 is reserved for link-local addresses. You can see a machine’s link-local addresses if you run ip addr (Linux), ifconfig (Mac) or ipconfig (Windows). An example:

fe80::18a3:6bcc:e0c8:49be%en0

Here the fe80:: prefix indicates that it’s a link-local address. The trailing %en0 indicates that this address is only unique and valid for the subnet attached to the en0 interface link. It’s unlikely, but possible, that fe80::18a3:6bcc:e0c8:49be could also be part of a link-local address on a network connected to a different interface; if that’s the case, fe80::18a3:6bcc:e0c8:49be alone would be ambiguous. So for link-local addresses, commands like ping require that the interface be specified.

It’s important to understand that link-local addresses are valid usable addresses, as long as the connecting systems are on the same subnet. All mainstream operating systems now set up link-local IPv6 addresses by default, so you likely have machines on your network that are reachable by IPv6 even if you have never done anything to set up IPv6.

Originally RFC 1972, A Method for the Transmission of IPv6 Packets over Ethernet Networks (1996), specified that for Ethernet, the link-local address should be obtained by taking the MAC address (EUI-48) of the interface card and using that as an “interface token”. The top 10 bits of the link-local address address were then the top ten bits of fe80, and the remaining 118 bits were the interface token left-padded with zeros. For example, a MAC address of e5:ea:5c:dc:5b:d7 would become fe80::e5ea:5cdc:5bd7. (EUI-48 MACs were later expanded to EUI-64.)

Unfortunately, on today’s networks MAC addresses aren’t unique. More than one hardware vendor has shipped multiple units with the same MAC address, and many people who use virtual machines will make copies of them without changing their MAC addresses.

Deriving the link-local address from the hardware MAC address was also bad for privacy and security: it meant that every host would have a fixed address that could be tracked between networks, and that device addresses would be within predictable subnets, making mass device scanning plausible.

An attempt to fix the privacy and security problem was made in RFC 4941, Privacy Extensions for Stateless Address Autoconfiguration in IPv6 (2007), which specified that hosts should generate pseudo-random interface tokens using a hashing algorithm.

The randomization approach was refined in RFC 7217, catchily named A Method for Generating Semantically Opaque Interface Identifiers with IPv6 Stateless Address Autoconfiguration (SLAAC) (2014). It specifies using a network ID and secret key as input to a pseudo-random number algorithm, so that the link-local address can be stable for any given network, but will be random across networks. This scheme is now the recommended approach per RFC 8064, Recommendation on Stable IPv6 Interface Identifiers (2017), and has been implemented in operating systems including iOS and macOS.

In short: for most devices, MAC addresses and link-local addresses are generated randomly, once, for each new network they connect to.

Whatever method is used to obtain a link-local address, the next step is to perform duplicate address detection to check whether a device already on the network has picked the same link-local address. It’s fairly unlikely that two nodes will pick the same address, given that the interface token is at least 48 bits wide, but definitely possible, particularly for older systems still basing link-local addresses on fixed MAC addresses.

Duplicate Address Detection relies on an IPv6 protocol known as Neighbor Discovery Protocol (NDP), or just Neighbor Discovery (ND), originally defined in RFC 1970, Neighbor Discovery for IP Version 6 (IPv6) (1996). This in turn relies on IPv6 multicast addresses, originally defined in RFC 1884, IP Version 6 Addressing Architecture (1995).

Each generated link-local address has a related solicited-node multicast address (SNMA), generated from the least significant bits of the link-local address. The solicited-node multicast address therefore includes a subset of nodes on the network that may have the same link-local address. All hosts are expected to listen to their solicited-node multicast address. In addition, there’s a single all-hosts multicast address every node is expected to listen to.

The solicited-node address was originally computed from the least significant 32 bits of the link-local address, but this was reduced to 24 bits in RFC 2373 to reduce the potential scope of multicasts.

Solicited node address calculation

The device checking for duplicate addresses sends a Neighbor Solicitation message — ICMP type 135 — to the solicited-node multicast address, with an unspecified source address, and a payload consisting of the full link-local address it has calculated and plans to use.

Devices listening to the same solicited-node multicast address are expected to check Neighbor Solicitation messages. If they see one that contains their link-local address as a tentative address, they reply by sending a Neighbor Advertisement message — ICMP type 136 — to the all-nodes multicast address, ff02::1.

If the device checking for duplicate addresses sees a Neighbor Advertisement address from another node with the link-local address it has calculated, it knows it can’t use that address.

This can be imagined as a conversation:

  • “Hey, everyone with an address ending f8:5335, I’m planning to use fe80::c6ab:08f8:5335 as my link-local address.”
  • “Hey, everyone on the network, I’m already using fe80::c6ab:08f8:5335.”

What happens next depends on how the new node is calculating its link-local addresses. If it is using a fixed interface token such as a hardware MAC address, it may be unable to connect to the network. If it’s using randomized interface tokens, it can generate a new one, compute a new tentative link-local address, and try again.

Note that while the Neighbor Discovery message is sent to a subset of hosts, the Neighbor Advertisement must be sent to all hosts because the new node performing Duplicate Address Detection doesn’t yet have a valid IP address. Since address collisions are expected to be extremely rare given the way link-local addresses are generated, this is still an improvement over IPv4.

In the case of an ad-hoc network, once the new node has a link-local address it simply uses that address on the network. For a network connected to the Internet, the process continues.

Step 3: Locating a router

The next step, locating a router, relies on two more ICMPv6 messages, and is more straightforward.

IPv6 routers are expected to advertise their presence on the subnet periodically, by sending a Router Advertisement (RA) message to the all-hosts link-local multicast address ff02::1. If the new node has seen a Router Advertisement message, then it has the address of a router. If not, it can send a Router Solicitation message to the all-routers link-local multicast address ff02::2 to request that a router identify itself.

Step 4: Calculating a routable address

The Router Advertisement message contains the routing prefix of the network, including any appropriate subnet ID. At this point the new node knows that it has a link-local address that’s unique on the subnet, which means it has an interface token that’s unique. It can use the routing prefix and subnet ID to form the top bits of the IP address, and its interface token to form the bottom bits. It now has what should be a valid globally routable IPv6 address.

Getting a working IP address without needing a special server is good, but there’s something else a computer generally needs in order to be useful: a DNS server. Initially SLAAC offered no solution to this problem, and it was expected that IPv6 systems would have manually configured DNS. However RFC 5006, IPv6 Router Advertisement Option for DNS Configuration (2007), added a field to the RA packet that contains the address of a recursive DNS server.

So the overall process looks like this:

SLAAC sequence diagram

As you’ve probably noticed, the entire SLAAC process is lengthier than requesting an address from a DHCP server. To speed it up, RFC 4429 Optimistic Duplicate Address Detection (DAD) for IPv6 (2006) introduced a modification. In this variant of DAD, tentative addresses are instead labeled “optimistic”, and used until some other suitable address is available. (Recall that address collisions are expected to be very rare.) When DAD eventually completes, the address either becomes “preferred” and is used, or is marked “deprecated” (expired).

The return of DHCP

Before RFC 5006 added a DNS server field to Router Advertisements, people had drafted and deployed DHCPv6 to solve the problem. It’s detailed in RFC 3315, Dynamic Host Configuration Protocol for IPv6 (DHCPv6) (2003).

DHCPv6 can work alongside SLAAC, distributing additional information such as domain suffixes for address resolution, NTP server addresses, boot image locations, and so on. When used for this purpose it can be run as stateless DHCPv6, avoiding the need to track every IPv6 node on the network.

Network administrators who prefer to run a stateful DHCPv6 server can configure routers to send Router Advertisements with the M bit (for Managed) set, to indicate that DHCPv6 should be used to obtain addresses instead of SLAAC.

One situation where DHCPv6 is preferable to SLAAC is when hosts are to be given Unique Local Addresses (ULAs), the equivalent of the RFC 1918 addresses used by most home NAT routers. Since one of the key benefits of IPv6 is not needing NAT, this is a fairly rare scenario.

Address renegotiation

The Privacy Extensions for SLAAC defined in RFC 3041 aren’t just applicable to obtaining an initial address. Even with a randomized interface token and random link-local address, if the eventual globally routable IPv6 remains constant, it could be used to track a web browser across multiple websites. If a device uses a hardware ID, its address could even be used to track it across different networks.

For this reason, the major operating systems now expire IPv6 addresses and obtain new ones using the same SLAAC protocol. The old addresses for the interface are labeled “deprecated” and eventually expired once any remaining traffic is expected to have completed.

Some ISPs also rotate customers’ IPv6 prefixes for privacy reasons. Unfortunately, if a device on the local network doesn’t support IPv6 Privacy Extensions and connects to the Internet, it can end up providing a tracking identifier for all devices on the network.

SLAAC security

As originally standardized, SLAAC is susceptible to spoofed Router Advertisement messages. Any system on the same subnet can send RA messages and potentially get accepted as a router, at which point it can redirect traffic. (This attack was carried out by a Chinese threat actor starting in 2022, targeting victims in China, Hong Kong, the Philippines, and UAE.)

Combining spoofed RA messages with the RFC 5006 extensions could allow for DNS spoofing as well.

To attempt to combat this, RFC 2462 (1998) updated the specification for Neighbor Discovery, suggesting that IPsec could be used to secure it. Unfortunately, IPsec is complicated to deploy and didn’t see much upkeep outside of enterprise environments. For this reason, RFC 3971, SEcure Neighbor Discovery (SEND) (2005), introduced a dedicated cryptographic authentication protocol for ND.

It’s worth remembering that IPv4 DHCP is also susceptible to spoofing, which led to RFC 3118 defining a mechanism for DHCP authentication.

Another potential issue is that a network device can respond with Neighbor Advertisement packets for every Neighbor Discovery it sees. This will effectively block any device from completing Duplicate Address Detection, hence blocking SLAAC from completing. Preventing this attack is a current research topic; for example, see:

Summary

  • IPv6 allows for address allocation and DNS configuration without needing a DHCP server and without needing any static configuration; all that’s needed is an IPv6 router.

  • Ad-hoc networks with no server or router of any kind can autoconfigure IPv6 link-local addresses to allow nodes to communicate with each other.

  • IPv6 Privacy Extensions rotate addresses periodically to prevent persistent user tracking.

  • IPv6 addresses can be cleanly reassigned if the upstream network connection changes.

  • DHCPv6 is available as a way to provide additional information beyond IP, router, and DNS, or as an alternative for managed networks.

Here are the current versions of the RFCs which define the SLAAC process and are mentioned above.

  • RFC 1971: Obsoleted by RFC 4862 IPv6 Stateless Address Autoconfiguration (2007)
  • RFC 1972: Obsoleted by RFC 2464 Transmission of IPv6 Packets over Ethernet Networks (1998)
  • RFC 4941: Obsoleted by RFC 8981 Temporary Address Extensions for Stateless Address Autoconfiguration in IPv6 (2021)
  • RFC 7217 A Method for Generating Semantically Opaque Interface Identifiers with IPv6 Stateless Address Autoconfiguration (SLAAC) (2014)
  • RFC 1970: Obsoleted by RFC 4861 Neighbor Discovery for IP version 6 (IPv6) (2007)
  • RFC 1884: Obsoleted by RFC 4291 IP Version 6 Addressing Architecture (2006)
  • RFC 5006: Obsoleted by RFC 8106 IPv6 Router Advertisement Options for DNS Configuration (2017)
  • RFC 4429 Optimistic Duplicate Address Detection (DAD) for IPv6 (2006)
  • RFC 3971 SEcure Neighbor Discovery (SEND) (2005)

Cake photo by Keithius on VisualHunt