Skip to content

DHCPDISCOVER

INIT is the state a device is in when it has no lease at all — freshly connected to a network, or an old lease that's fully expired with nothing left to renew. The only move available from INIT is to ask, loudly, whether anyone on the local segment is willing to hand out an address at all. That ask is DHCPDISCOVER, and everything about how it's built follows from one constraint: the sender doesn't have an IP address yet, and can't get one without first being heard by something that has no way to address it directly.

What the client fills in, and what it can't

Looking at the shared header fields with that constraint in mind explains most of what a Discover packet contains:

  • op is 1 — this is a client-to-server message.
  • xid is a random value the client picks fresh for this attempt. It has nothing to match yet, but every Offer that comes back will echo this same value, which is how the client tells replies to this attempt apart from replies to an attempt it gave up on earlier.
  • ciaddr is 0.0.0.0. The client has no IP address to report — that's the entire reason it's asking.
  • chaddr carries the client's MAC address, since a MAC address is the one identifier the client already has and doesn't need anyone else's help to know.
  • secs starts at 0 and climbs on each retry, giving a server a rough sense of how long this client has already been waiting.

The destination is exactly what the DHCP article already described: source 0.0.0.0, destination 255.255.255.255, UDP port 67 on the server side, port 68 on the client side.

The broadcast flag, and why it usually doesn't matter

The flags field's one meaningful bit exists for a narrower reason than it looks. RFC 2131 lets a client set it to ask the server to send its reply as a broadcast rather than a unicast — meant for a client whose network stack genuinely can't receive a unicast datagram addressed to an IP it hasn't configured yet. In practice, modern operating systems can accept that unicast reply just fine before the address is formally assigned, so most clients leave this bit unset and get a unicast Offer back regardless. It's part of the spec worth recognizing in a packet capture, not a setting worth tuning.

What the client asks for, beyond an address

A Discover doesn't request nothing but an address — the options section tells the server what kind of configuration the client wants back:

  • DHCP Message Type (option 53) — set to Discover. This is the field that actually identifies the packet as a Discover; nothing in the fixed header does.
  • Parameter Request List (option 55) — a list of option numbers the client wants included in the reply, typically subnet mask, router, and DNS servers at minimum.
  • Client Identifier (option 61) — usually just the MAC address again, wrapped in a format the server can use as a stable key even if the underlying hardware type changes.
  • Requested IP Address (option 50) — present only if the client remembers a previous lease and would like it back, though it isn't in INIT-REBOOT state and so isn't demanding it the way a Request in INIT-REBOOT does.
sudo tcpdump -i eth0 -n -v port 67 or port 68
12:00:01.102340 IP (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto UDP (17), length 328)
    0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 08:00:27:4e:66:a1, length 300, xid 0x3d1e2f8a, secs 0, Flags [none]
      Client-Ethernet-Address 08:00:27:4e:66:a1
      Vendor-rfc1048 Extensions
        Magic Cookie 0x63825363
        DHCP-Message Option 53, length 1: Discover
        Client-ID Option 61, length 7: ether 08:00:27:4e:66:a1
        Parameter-Request Option 55, length 3: 
          Subnet-Mask, Default-Gateway, Domain-Name-Server

tcpdump -v decodes the message type and the options directly, which is a good deal more useful for this than the plain summary line the DHCP article's own capture showed — that one only got as far as "BOOTP/DHCP, Request," with no way to tell a Discover from a Request without opening the packet further. -v is that opening.

No answer at all

Nothing in DHCP guarantees a server is listening. RFC 2131 recommends a client retry a Discover with exponential backoff: roughly 4 seconds before the first retry, roughly 8 before the next, doubling again to roughly 16 and 32, capping at 64 seconds between attempts, each interval jittered by up to a second in either direction so that a room full of devices booting at the same instant doesn't retry in perfect, congesting unison.

If every retry goes unanswered, a client following RFC 3927 falls back to a link-local address — something in 169.254.0.0/16, chosen at random and verified conflict-free with an ARP probe before use, giving devices on the same broken segment at least a way to reach each other even though nothing beyond that segment is reachable.

This isn't a workaround for a slow server

A link-local address is a sign DHCP failed outright, not a sign it's running late. A DHCP server that's merely slow still answers eventually within the retry window; 169.254.x.x only appears once every retry has been exhausted with no server responding at all.

A laptop with no route anywhere

A laptop is moved into a conference room wired into a VLAN that, it turns out, has never had DHCP relay configured — the switch port exists and passes traffic, but nothing on that segment is listening on UDP port 67. ip addr shows the symptom immediately:

ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:4e:66:a1 brd ff:ff:ff:ff:ff:ff
    inet 169.254.31.201/16 brd 169.254.255.255 scope link noprefixroute eth0
       valid_lft forever preferred_lft forever

A 169.254.0.0/16 address with no default route configured is the tell. Running the capture from earlier confirms it directly — repeated Discover packets going out, secs climbing on each one, and never a single Offer coming back:

12:00:01.001 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 08:00:27:4e:66:a1, length 300, xid 0x9a41cc02, secs 0
12:00:05.234 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 08:00:27:4e:66:a1, length 300, xid 0x9a41cc02, secs 4
12:00:13.782 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, Request from 08:00:27:4e:66:a1, length 300, xid 0x9a41cc02, secs 12

The same xid on every line confirms these are retries of one attempt, not three separate ones — exactly the field the header table in the previous article flagged as the way to tell them apart. The fix isn't on the laptop at all: either a DHCP server needs to exist on this VLAN, or, far more likely given that every other VLAN on this network works, a relay agent needs to be configured on the router to forward these broadcasts to the DHCP server that already serves everyone else.

Practice exercises

  1. Run sudo tcpdump -i any -n -v port 67 or port 68 on a Linux machine while running sudo dhclient -r && sudo dhclient on a test interface, and find the xid value in the Discover packet — does it change if you cancel and immediately retry?
  2. Using the retry timing described above, roughly how long would a client wait, in the worst case, between its first Discover and its fourth retry, before jitter is applied?
  3. Explain why a link-local 169.254.x.x address is not, by itself, proof that a DHCP server is down — what else could cause the same symptom?

A Discover only asks the question. The next article covers what a server actually puts in its answer, and what happens when more than one server on the segment feels like answering.

Sources