Networking for beginners. Part 16: DHCPv6

All parts of the series “Networking for beginners”

SLAAC from the previous part gives a host an address, a gateway and DNS without a single server, and for a home that is enough. But being serverless has a price: no one knows which device has which address, the set of parameters is limited, and the subscriber's router has to get its block of prefixes from somewhere. For this, IPv6 has DHCPv6, RFC 8415. The name promises "the same DHCP", but it is a different protocol: it has its own format, its own client identifiers, its own modes and, most importantly, it does not replace Router Advertisement but complements it. Without the RA from part fourteen, a DHCPv6 client will not even start.

To have something to compare against, keep DHCPv4 at hand.


How it differs from DHCPv4

DHCPv4 DHCPv6
Transport UDP 68 → 67, broadcast 255.255.255.255 from 0.0.0.0 UDP 546 → 547, multicast ff02::1:2 from the link-local address: the client already has it
How the client knows whether DHCP is needed always tries from the M and O flags in the RA
Who the client is MAC address or client-id DUID — an identifier of the machine, not the interface
What is handed out one address IA — a container with one or more addresses or prefixes, each with its own lifetimes
Mask option 1 none: prefix and on-link come from the RA
Gateway option 3 none, and never will be: only from the RA
Exchange DISCOVER, OFFER, REQUEST, ACK Solicit, Advertise, Request, Reply; with rapid commit — two messages
Lifetimes one lease preferred and valid, as in SLAAC
Server initiative none Reconfigure: the server can tell the client to renew
Handing out prefixes to routers none prefix delegation
"Options only" mode INFORM Information-Request, a standard stateless mode

The missing gateway option is not an oversight but a decision: a router knows best that it is a router and announces that itself; a DHCP server can sit anywhere and knows nothing about the segment's topology. The argument holds for IPv4 too, but there it was already too late.


DUID and IA

The DUID (DHCP Unique Identifier) is what the client calls itself. There is one per machine, not per interface; it is generated on first start and stored on disk. Three formats: DUID-LLT — a MAC address plus creation time (the most common), DUID-LL — only the MAC, DUID-UUID — the machine UUID from firmware. The server keeps reservations by DUID, and that causes practical pain: the DUID is not printed on a sticker, so to create a reservation for a new laptop you first have to turn it on and spot its DUID in the server log. Reinstalling the OS usually changes the DUID. Relay agents can add the client's MAC to the request (option 79), and modern servers can reserve by it, but that is a workaround, not the rule.

An IA (Identity Association) is the container in which the client asks for, and the server hands out, addresses. Each IA has an IAID — a number the client picks for the interface — and T1/T2 timers for renewal. Three kinds:

  • IA_NA (option 3) — ordinary addresses; inside, one or more IA Address entries (option 5) with preferred and valid lifetimes;
  • IA_TA (option 4) — temporary addresses, the counterpart of privacy extensions; rarely used, since SLAAC makes temporary addresses;
  • IA_PD (option 25) — prefixes: inside, IA Prefix (option 26) with a length and lifetimes.

A client can send several IAs in one request — for example, IA_NA for an address on the WAN interface and IA_PD for a block for the LAN — and the server answers each one separately with a status code.


The message

The header is 4 bytes, followed by options in "code (2 bytes), length (2 bytes), value" format:

 bytes:   1          3
        ┌────────┬────────────────┐
        │ msg-   │ transaction-id │   then options
        │ type   │                │
        └────────┴────────────────┘
msg-type Message Meaning
1 Solicit client: "who is the server here and what can you offer"
2 Advertise server: an offer
3 Request client: "I'll take it from this server"
4 Confirm client after sleep or reconnection: "are my addresses still good on this segment?"
5 Renew renewal with its own server (T1)
6 Rebind renewal with any server (T2)
7 Reply the server's reply to everything except Solicit
8 Release the client gives addresses back
9 Decline the address failed DAD
10 Reconfigure server: "renew", requires authentication
11 Information-Request client: "options only, I have my own address"
12, 13 Relay-Forward, Relay-Reply relay agent wrappers

Options you meet all the time: 1 Client ID (the client's DUID), 2 Server ID (the server's DUID), 3 IA_NA, 5 IA Address, 6 Option Request (what the client needs, the counterpart of 55 in DHCPv4), 7 Preference (the server with the higher value wins the client; 255 means "take me, don't wait for others"), 8 Elapsed Time (how long the client has been trying, for backup servers), 13 Status Code, 14 Rapid Commit, 23 DNS servers, 24 search domains, 25 IA_PD, 26 IA Prefix, 39 FQDN (the client name for DNS registration), 56 NTP servers.


Stateful: four messages

An RA with the flag M = 1. A client that receives such an RA starts DHCPv6:

   client fe80::3e52:…                                        server fe80::da47:…
     │                                                               │
     ├── Solicit ─────────── to ff02::1:2 (MAC 33:33:00:01:00:02) ──►│  to all servers and relays
     │   Client ID, IA_NA (IAID 1), Option Request: DNS, domains     │
     │                                                               │
     │◄── Advertise ──────── unicast to my link-local ───────────────┤  from each server
     │   Server ID, IA_NA: address, lifetimes; DNS; Preference       │
     │                                                               │
     ├── Request ──────────── to ff02::1:2 ─────────────────────────►│  with the chosen Server ID
     │                                                               │
     │◄── Reply ─────────────────────────────────────────────────────┤  confirmation
     │                                                               │
     │  DAD of the address, then in use; Renew at T1, Rebind at T2   │
  1. Solicit goes from the link-local address to ff02::1:2 — the group of all DHCPv6 servers and relay agents on the segment. Inside are the client's DUID, an empty IA_NA ("I want an address, any") and the list of options it needs. The client has a source address, so the reply comes as unicast, without the MAC tricks of DHCPv4.
  2. Advertise from each server, with the offered address inside an IA_NA and its lifetimes. The client waits a second, collects all offers and picks the server with the highest Preference. With Preference 255 there is no need to wait.
  3. Request goes to multicast again (so the other servers see the choice), but with the winner's Server ID.
  4. Reply — confirmation with the same IAs and options. The client assigns the address, checks it with DAD and, on conflict, sends a Decline.

If the server supports Rapid Commit in response to a Solicit (option 14 in the Solicit and in the reply), it answers with a Reply right away, and the exchange fits into two messages. For networks with a single server this is the norm.

In tcpdump:

$ sudo tcpdump -i eth0 -n 'udp port 546 or udp port 547'
IP6 fe80::3e52:82ff:fe1a:2b3c.546 > ff02::1:2.547: dhcp6 solicit (xid=1a2b3c (client-ID hwaddr/time type 1 time 700000000 3c52821a2b3c) (IA_NA IAID:1 T1:0 T2:0) (option-request DNS-server DNS-search-list) (elapsed-time 0))
IP6 fe80::da47:32ff:fe0a:b0c.547 > fe80::3e52:82ff:fe1a:2b3c.546: dhcp6 advertise (xid=1a2b3c (client-ID hwaddr/time type 1 time 700000000 3c52821a2b3c) (server-ID hwaddr/time type 1 time 650000000 d847320a0b0c) (IA_NA IAID:1 T1:3600 T2:5760 (IA_ADDR 2001:db8:1234:5678::1001 pltime:7200 vltime:14400)) (DNS-server 2001:db8:1234:5678::1) (preference 255))
IP6 fe80::3e52:82ff:fe1a:2b3c.546 > ff02::1:2.547: dhcp6 request (xid=1a2b3c (client-ID ...) (server-ID ... d847320a0b0c) (IA_NA IAID:1 ...) (option-request ...))
IP6 fe80::da47:32ff:fe0a:b0c.547 > fe80::3e52:82ff:fe1a:2b3c.546: dhcp6 reply (xid=1a2b3c ... (IA_NA IAID:1 T1:3600 T2:5760 (IA_ADDR 2001:db8:1234:5678::1001 pltime:7200 vltime:14400)) (DNS-server ...))

DUID type 1 is LLT: "hwaddr/time". The address ::1001 comes from the server's pool, with preferred 7200 and valid 14400, renewal at T1 = 3600.

Renewal is a Renew at T1 with the Server ID and a Rebind at T2 without it; both also go to ff02::1:2 unless the server explicitly allowed unicast with option 12. The client sends a Confirm after waking from sleep: "is the address ::1001 still good on this segment?" — the server checks it against the prefix and answers with a status. Release — on a clean disconnect.

What the server did not hand out: the gateway and the prefix. The host took the default route and 2001:db8:1234:5678::/64 dev eth0 from the same RA that brought the M flag. If a router announces M = 1 but sends no RA with prefix info, the host will get an address and not know that its neighbors are neighbors: every packet will go to the router, which will bounce it back with a Redirect. A "DHCPv6 without RA" setup does not exist.


Stateless: options only

An RA with M = 0, O = 1: make your address via SLAAC, and go to DHCPv6 for the rest. The client sends an Information-Request without an IA, and the server answers with a Reply with options: DNS, search domains, NTP, anything else. The server remembers nothing: no leases, no table, no DUIDs in a database. This is the cheapest way to hand out parameters that the RA does not carry, and before RDNSS appeared it was the only way to tell a host its DNS address.

With RDNSS in the RA, stateless DHCPv6 is needed less often: for time servers, the PBX address for IP phones (they speak SIP — a call setup protocol — and need to know where to register), boot parameters. But clients still honor the O flag, and in corporate networks it is usually set.


Prefix delegation

The most important role of DHCPv6 is one that DHCPv4 does not have at all. A home router has to get a block of addresses from the provider in order to give a /64 to each of its networks. This is done via IA_PD, and two routers take part:

   provider (delegating router)                           home router (requesting router)               LAN
   2001:db8::/32                                          WAN eth1                                      eth0
        │                                                 │                                             │
        │◄── RS ──────────────────────────────────────────┤                                             │
        ├── RA: "I am the gateway", no address prefix ───►│ default via fe80::<provider>                │
        │                                                 │                                             │
        │◄── Solicit: IA_PD (IAID 0, want a /56) ─────────┤                                             │
        ├── Advertise, then Reply: IA_PD with IA Prefix ─►│                                             │
        │   2001:db8:1200::/56, pltime, vltime            │ take a /64 from the /56 for each network    │
        │                                                 │                                             │
        │ route: 2001:db8:1200::/56 via fe80::<router>    ├── RA: prefix 2001:db8:1200::/64, flag A ───►│ SLAAC
        │                                                 │                                             │
  1. On the WAN interface, the subscriber's router receives an RA from the provider: a default route via the link-local address of the provider's router. There may be no prefix with the A flag at all: the WAN interface does not need a global address, link-local is enough.
  2. The router sends a Solicit with an IA_PD, in which it can hint at the desired length (/56). The provider answers with an IA Prefix: 2001:db8:1200::/56 with lifetimes.
  3. The provider's router installs a route to this /56 via the subscriber's link-local address: now the whole block is routed to the apartment.
  4. The subscriber's router takes a /64 from the block for each of its networks (2001:db8:1200:0::/64 for the LAN, 2001:db8:1200:1::/64 for the guest network) and announces them in RAs, as in the previous part. Hosts build their addresses via SLAAC.

IA_PD renewal is the same Renew/Rebind. If on reconnection the provider hands out a different /56 (this happens with providers that do not pin a prefix to a subscriber), the router withdraws the old prefix in an RA and announces the new one, and all hosts renumber within minutes — this is exactly why SLAAC is built around lifetimes. Convenient and inconvenient at the same time: device addresses at home change, and DNS records and firewall rules have to be written for ULAs or via dynamic updates.

On a Linux router all this is done by dhcpcd (a single line ia_pd 1 eth0/0 — "request a prefix, put the first /64 on eth0") or odhcpd in OpenWrt; on home routers it is an option called "DHCPv6-PD" or "obtain prefix automatically".


Relay

As in DHCPv4, the server can sit in another segment. The relay router catches multicast on ff02::1:2 and wraps the client's message in a Relay-Forward: inside is the original message in full (option 9 Relay Message), and the relay header carries the link-address, the relay's address in the client's segment (the counterpart of giaddr: the server picks the pool by it), and the peer-address, the client's link-local address. The relay may add an Interface-ID (option 18, which port it came from) and a Remote-ID (option 37, the subscriber identifier at the provider). The server answers with a Relay-Reply with the response inside, and the relay unwraps it and delivers it to the client. Several relays in a row nest messages inside each other, and the hop-count in the header grows.


On the server

The shortest stateful server is dnsmasq, which sends RAs as well:

enable-ra
dhcp-range=2001:db8:1234:5678::100,2001:db8:1234:5678::1ff,64,12h
dhcp-option=option6:dns-server,[2001:db8:1234:5678::1]
dhcp-host=id:00:01:00:01:29:b8:f0:00:3c:52:82:1a:2b:3c,[2001:db8:1234:5678::50],printer

The reservation is by DUID (id:…), as promised. Kea, the successor of ISC dhcpd, describes the same in JSON and supports prefix delegation for providers:

"subnet6": [{
  "subnet": "2001:db8:1234:5678::/64",
  "pools": [{ "pool": "2001:db8:1234:5678::100-2001:db8:1234:5678::1ff" }],
  "pd-pools": [{ "prefix": "2001:db8:1200::", "prefix-len": 48, "delegated-len": 56 }]
}]

Which flags to set in the RA is the administrator's decision, and it is worth making deliberately: M = 1 without A gives full accounting but leaves Android without an address; A = 1 and M = 1 give every host two addresses; A = 1 with O = 1 is the compromise "addresses by yourself, parameters from the server".


Hands-on

The flags in the RA are the first thing to check if DHCPv6 "doesn't work": without M or O the client simply will not start it:

$ sudo rdisc6 eth0 | grep -i stateful
Stateful address conf.    :          Yes
Stateful other conf.      :          Yes

The client's DUID is in its client's files: /var/lib/dhcpcd/duid, /var/lib/dhcp/dhclient6.leases, /var/lib/systemd/network/; on Windows — ipconfig /all, the "DHCPv6 Client DUID" line. The same place shows whether an address was assigned and with what lifetimes.

To request by hand: sudo dhcpcd -6 -T eth0 (a test without applying) or sudo dhclient -6 -v eth0. And the capture on ports 546/547 from the stateful section: if Solicit goes out but no Advertise comes back, there is no server on the segment or the relay is not configured; if a Reply arrives with Status Code NoAddrsAvail, the pool is exhausted or does not match the link-address.

On a provider or test router, look at the routes created by delegation: ip -6 route | grep -v 'proto kernel' will show the /56 via the neighbor's link-local address.


Key takeaways

  • DHCPv6 is a different protocol: UDP 546/547, multicast ff02::1:2 from the link-local address, DUID instead of MAC, IAs with several addresses and their own lifetimes, Rapid Commit in two messages.
  • It starts only on RA flags: M — addresses (stateful, Solicit/Advertise/Request/Reply), O — parameters (stateless, Information-Request/Reply). DHCPv6 has no gateway or prefix; they always come from the RA.
  • Prefix delegation: the subscriber's router requests an IA_PD, gets a /56 or /48, the provider installs a route to it, and the router hands out /64s to its networks via RA.
  • A relay wraps messages in a Relay-Forward with the link-address used to pick the pool.
  • Reservations are by DUID, which you learn after the first power-on; Android does not support DHCPv6, so SLAAC remains mandatory.

This concludes the IPv6 block. Next — segmentation and tunnels, and the first topic is Part 17: VLAN: how one physical network becomes several logical ones, the four bytes of the 802.1Q tag in a frame, access and trunk ports, native VLAN, inter-VLAN routing via a router and an L3 switch, and VLANs on Linux with a single command.

Only registered users can leave a comment.

Sign in or register to leave a comment.