Server

DHCP DORA: How a Host Gets Its Address

By Prabath Thalangama· October 24, 2026· 3 min read
#dhcp#networking#troubleshooting

Introduction

DHCP is invisible until a device won't get an address, or gets the wrong one, or two servers fight over the same scope. The protocol is only four packets; knowing them makes these problems quick to isolate.

Concepts

A client with no IP can't do normal unicast, so DHCP bootstraps over broadcast (UDP: client port 68, server port 67).

DORA:

  1. DISCOVER — client broadcasts "is there a DHCP server?" It includes its MAC and often a hostname and a list of options it wants.
  2. OFFER — one or more servers broadcast (or unicast) back a proposed address, subnet mask, gateway, DNS servers, and lease time.
  3. REQUEST — client broadcasts "I'll take this offer from this server" (naming the server, so the others withdraw their offers).
  4. ACK — the chosen server confirms and commits the lease. (Or NAK if the address is no longer available — client restarts at DISCOVER.)

Lease timers

A lease has a duration, plus two timers:

  • T1 (renewal, ~50% of lease) — client unicasts a REQUEST to the same server to extend. Usually silent and successful.
  • T2 (rebinding, ~87.5%) — if the original server didn't answer, the client broadcasts a REQUEST to any server.
  • Expiry — client must stop using the address and start over.

This is why a short outage of the DHCP server doesn't drop everyone — existing leases keep working until T1/T2.

DHCP relay

Broadcasts don't cross routers. To serve multiple subnets from one central server, routers run a DHCP relay agent (ip helper-address on Cisco, dhcp-relay elsewhere) that forwards DISCOVER/REQUEST as unicast to the server, stamping the giaddr field so the server knows which subnet's scope to use.

Hands-on

Watch it on the wire

sudo tcpdump -ni any -v 'udp port 67 or udp port 68'

Then trigger a renewal:

# systemd-networkd / dhclient
sudo dhclient -r eth0 && sudo dhclient eth0
# NetworkManager
sudo nmcli device reapply eth0

Inspect the current lease

# dhclient
cat /var/lib/dhcp/dhclient.leases

# systemd-networkd
networkctl status eth0

# What did we actually get?
ip -4 addr show eth0
resolvectl status eth0        # DNS servers from DHCP option 6
ip route                      # default gateway from option 3

On the server (isc-dhcp / kea)

# isc-dhcp active leases
grep -A6 "lease .* {" /var/lib/dhcp/dhcpd.leases | tail -40
journalctl -u isc-dhcp-server -f

# kea
kea-shell --host 127.0.0.1 --port 8000 lease4-get-all

Verification and troubleshooting

  • No IP at all (169.254.x.x link-local / APIPA) — DISCOVER got no OFFER. Either no server on the segment, the relay isn't configured, the scope is exhausted, or a switch port-security / DHCP-snooping rule is dropping it. tcpdump on the server side: do the DISCOVERs even arrive?
  • Gets an IP but wrong subnet/gateway — a rogue DHCP server (someone plugged in a home router). The client takes whichever OFFER arrives first. Enable DHCP snooping on the switches; hunt the rogue with tcpdump for OFFERs from an unexpected server IP.
  • Wrong DNS servers — option 6 from DHCP is overriding what you want. NetworkManager: ipv4.ignore-auto-dns yes and set ipv4.dns.
  • Lease not renewing, drops every few hours — T1 renewal failing silently. Check server logs at the renewal time; often the server restarted and lost in-memory state, or two servers share a scope without failover and both think they own the address.
  • Relayed requests ignored — the server has no subnet declaration matching the giaddr, or the relay's source isn't in the server's allow/trust list.
  • DHCPNAK loop — client is asking for an address the server won't grant (moved networks, stale lease file). dhclient -r to release cleanly first.
PrabathStuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.