Mental model
A device that just plugged in has no IP. It can’t send unicast traffic — there’s no source IP to put in the packet. So it broadcasts:
“Hello? Anyone? I need an IP.”
If a DHCP server is on the same broadcast domain (same VLAN / subnet), it hears the request and answers. If the server is on a different subnet, the router between them needs to be told to forward the broadcast — that’s the ip helper-address command (covered in DHCP Relay).
That’s the whole story. The rest is detail — what’s in each message, what gets configured where, and how attackers exploit it.
Why DHCP exists
Before DHCP (which came from BOOTP in the early 1990s), every network host needed its IP, mask, gateway, and DNS statically configured by a human. A typo on one host = no connectivity for that host. Moving a host to a new subnet = full reconfiguration.
DHCP automates all of that. Today’s PCs, phones, IoT devices, virtual machines — billions of them — all use DHCP. Without it, modern networks would be unmanageable.
The DORA exchange — what each message does
Step 1 — DISCOVER (client → broadcast):
"Hi. I have MAC AA:BB:CC:11:22:33. I need an IP."
Step 2 — OFFER (server → broadcast):
"Hi MAC AA:BB... here's 10.0.0.45/24, gateway 10.0.0.1, DNS 8.8.8.8, lease 1 day."
Step 3 — REQUEST (client → broadcast):
"I accept 10.0.0.45 offered by server 10.0.0.1." (Other servers see this and withdraw their offers.)
Step 4 — ACK (server → broadcast):
"Confirmed. 10.0.0.45 is yours until lease expires."
| # | Letter | From | To | UDP port | Carries |
|---|---|---|---|---|---|
| 1 | Discover | Client (0.0.0.0) | Broadcast (255.255.255.255) | 68 → 67 | Client MAC + request hints |
| 2 | Offer | Server | Broadcast (255.255.255.255) | 67 → 68 | Offered IP + mask + lease + options |
| 3 | Request | Client | Broadcast (255.255.255.255) | 68 → 67 | Selected offer (named server) |
| 4 | Ack | Server | Broadcast | 67 → 68 | Lease confirmed |
Why all four are broadcasts: the client has no IP yet (Discover, Request) or is committing publicly so other DHCP servers can withdraw competing offers. The Offer and Ack are broadcasts because the client doesn’t yet have its IP bound to its interface, so a unicast back would be invisible to the OS.
The race when multiple servers exist
If two DHCP servers see the Discover, both send Offers. The client picks one (usually the first one received) and references the chosen server’s ID in the Request. The losing server sees the Request, recognizes it didn’t win, and frees up the address it had tentatively reserved.
This is why DHCP failover designs need careful planning — naively running two servers with the same scope causes IP conflicts.
Packet anatomy — what’s in a DHCP message
A DHCP packet is a BOOTP message with extensions. The fields you’ll care about:
op — 1 = request (Discover/Request), 2 = reply (Offer/Ack)
htype — Hardware type (1 = Ethernet)
chaddr — Client hardware (MAC) address
ciaddr — Client IP (filled in only on renewal)
yiaddr — "Your" IP — the address being offered to the client
siaddr — Server IP
giaddr — Gateway IP (set by DHCP relay agent — see Relay section)
options — Variable-length list of typed values (covered below)
The giaddr field is critical for DHCP relay. When a router relays a Discover, it stamps giaddr with its own interface IP. The server uses giaddr to pick the right scope (the one whose subnet contains giaddr) and sends the Offer back to giaddr for relay back to the client.
DHCP options — the parts that confuse everyone
DHCP carries the IP + mask in fixed fields. Everything else (gateway, DNS, lease time, domain name, NTP server, TFTP server, vendor-specific stuff) lives in options — numbered TLV (type-length-value) entries.
| Option # | Name | Purpose |
|---|---|---|
| 1 | Subnet mask | Network mask for the client (often inferred from scope, but explicit is OK) |
| 3 | Router | Default gateway IP |
| 6 | Domain Name Server | DNS server IPs (one or more) |
| 15 | Domain Name | DNS search suffix (e.g., corp.example.com) |
| 42 | NTP Server | NTP server IPs |
| 43 | Vendor Specific | Used heavily for Cisco APs (controller discovery), Avaya phones, etc. |
| 51 | Lease Time | In seconds. Default ~86400 (1 day) |
| 53 | DHCP Message Type | 1=Discover, 2=Offer, 3=Request, 4=Decline, 5=Ack, 6=Nak, 7=Release, 8=Inform |
| 66 | TFTP Server Name | Used for IP phone boot |
| 67 | Bootfile Name | Used for PXE boot |
| 82 | Relay Agent Information | Inserted by DHCP relay agents — origin context for the server |
| 150 | Cisco TFTP Server | Cisco-specific TFTP option for IP phones |
CCNA exam loves option numbers. Memorize at least: 3 (router), 6 (DNS), 51 (lease), 53 (msg type), 82 (relay info), 150 (Cisco TFTP for phones).
Lease timing — T1 and T2
DHCP doesn’t just hand out IPs forever. Each lease has a duration. The client renews before it expires.
- T1 = 50% of lease — client tries to renew with the same server via unicast Request. If Ack received, lease extends. (No DORA — this is a 2-message renewal.)
- T2 = 87.5% of lease — if no renewal yet, client broadcasts a Rebind Request to any server. (Still 2-message.)
- Lease expiration — if still no response, client gives up, releases IP, starts a full DORA.
Default lease times vary:
- Cisco IOS server default: 1 day.
- Windows Server / Linux ISC DHCP default: 8 days.
- Home routers: typically 1 day.
Trade-off:
- Short leases (hours) — more accurate IP turnover, more DHCP traffic, server CPU higher.
- Long leases (a week+) — quiet DHCP server, but if you change scope settings (new DNS, new gateway) clients don’t pick up the change until renewal.
For a typical office: 8 hours to 1 day is the sweet spot.
Cisco IOS DHCP server — config
The router (or L3 switch) itself can run DHCP. Common for branch offices.
! Exclude addresses the server should NOT hand out
R1(config)# ip dhcp excluded-address 10.0.0.1 10.0.0.10
R1(config)# ip dhcp excluded-address 10.0.0.250 10.0.0.254
! Define the pool
R1(config)# ip dhcp pool USERS
R1(dhcp-config)# network 10.0.0.0 255.255.255.0
R1(dhcp-config)# default-router 10.0.0.1
R1(dhcp-config)# dns-server 8.8.8.8 1.1.1.1
R1(dhcp-config)# domain-name corp.example.com
R1(dhcp-config)# lease 1 ! 1 day
R1(dhcp-config)# option 150 ip 10.1.1.5 ! Cisco IP phone TFTP
Always exclude:
- The router’s own IP (
.1here). - Any static-assigned servers, printers, APs, switches with management IPs in this subnet.
- A reserved chunk at the end for future static assignments (e.g.,
.250–.254).
Verify with:
R1# show ip dhcp binding
R1# show ip dhcp pool
R1# show ip dhcp conflict
R1# show ip dhcp server statistics
show ip dhcp binding lists every active lease — IP + MAC + lease expiration. Daily-driver debug command.
Multiple pools on one router
You can serve DHCP for many subnets from one router. Each subnet needs its own pool. The router picks the right pool by matching the giaddr (or the receiving interface’s subnet for directly-connected clients).
R1(config)# ip dhcp pool USERS
R1(dhcp-config)# network 10.0.0.0 255.255.255.0
R1(dhcp-config)# default-router 10.0.0.1
R1(dhcp-config)# dns-server 8.8.8.8
R1(config)# ip dhcp pool SERVERS
R1(dhcp-config)# network 10.0.10.0 255.255.255.0
R1(dhcp-config)# default-router 10.0.10.1
R1(dhcp-config)# dns-server 8.8.8.8
R1(config)# ip dhcp pool VOICE
R1(dhcp-config)# network 10.0.20.0 255.255.255.0
R1(dhcp-config)# default-router 10.0.20.1
R1(dhcp-config)# option 150 ip 10.1.1.5
Static (manual) bindings
Some hosts should always get the same IP — printers, IP phones with extension-based dialing, license-bound servers. Two options:
Option 1 — exclude + static configure on the host. Simpler. Doesn’t scale.
Option 2 — DHCP manual binding (also called DHCP reservation):
R1(config)# ip dhcp pool PRINTER-OFFICE
R1(dhcp-config)# host 10.0.0.50 255.255.255.0
R1(dhcp-config)# client-identifier 0100.5056.b322.45 ! MAC with type prefix
R1(dhcp-config)# default-router 10.0.0.1
client-identifier is the MAC address with a leading 01 (Ethernet hardware type) and dots. The printer always gets 10.0.0.50. Multiple manual bindings → multiple ip dhcp pool blocks, one per device.
DHCP Relay — bridging broadcasts across subnets
Routers don’t forward broadcasts. So if your DHCP server is on a different subnet (often the case in enterprise), the router needs explicit instructions to relay DHCP broadcasts to specific servers:
! On the interface facing the clients
R1(config)# interface Vlan10
R1(config-if)# ip helper-address 10.99.0.5
R1(config-if)# ip helper-address 10.99.0.6 ! optional second server
ip helper-address forwards eight specific UDP services by default (including DHCP). The router:
- Receives the broadcast Discover.
- Converts it to a unicast to the helper IP, stamping
giaddr= the receiving SVI’s IP. - Server uses
giaddrto pick the right scope, sends Offer back togiaddr. - Router broadcasts the Offer on the client’s subnet.
See DHCP Relay for full Option-82 + multi-relay coverage.
What else ip helper-address forwards
By default it forwards eight UDP ports: 37 (Time), 49 (TACACS), 53 (DNS), 67 (DHCP), 68 (DHCP), 69 (TFTP), 137 (NetBIOS), 138 (NetBIOS). To restrict:
R1(config)# no ip forward-protocol udp 137
R1(config)# no ip forward-protocol udp 138
Or whitelist:
R1(config)# no ip forward-protocol udp 37
R1(config)# no ip forward-protocol udp 49
R1(config)# no ip forward-protocol udp 53
R1(config)# no ip forward-protocol udp 69
R1(config)# no ip forward-protocol udp 137
R1(config)# no ip forward-protocol udp 138
! Keep only DHCP 67/68
DHCP Snooping — the must-have security feature
Rogue DHCP server is the classic LAN attack: attacker plugs in a tiny DHCP server, hands out a malicious gateway IP, becomes a MITM for everyone on the VLAN.
DHCP Snooping is the switch’s defense. You designate “trusted” ports where legitimate DHCP servers live (uplinks, sometimes the SVI). All other ports are untrusted — the switch silently drops any DHCP server-side messages (Offer, Ack, Nak) arriving on them.
SW1(config)# ip dhcp snooping
SW1(config)# ip dhcp snooping vlan 10,20,30
! Mark uplinks / trusted ports
SW1(config)# interface Gi1/0/24
SW1(config-if)# ip dhcp snooping trust
! Optional: rate-limit DHCP messages on untrusted ports (anti-starvation)
SW1(config)# interface range Gi1/0/1 - 23
SW1(config-if-range)# ip dhcp snooping limit rate 100
Snooping also builds a binding table of IP-to-MAC-to-port mappings — used by Dynamic ARP Inspection and IP Source Guard to enforce identity. See DHCP Snooping for the deep dive.
DHCPv6 — the IPv6 cousin
DHCPv6 (RFC 8415) is a different protocol despite the name. Three notable differences:
- Two modes: Stateful (assigns full IPv6 addresses) and Stateless (only assigns DNS/etc., leaves addressing to SLAAC).
- No broadcast in IPv6. DHCPv6 uses link-local multicast (
ff02::1:2). - DUIDs replace MACs. Client identifier is a DHCP Unique Identifier, not a MAC directly.
For CCNA-level coverage of IPv6 addressing see IPv6 Basics and IPv6 SLAAC. DHCPv6 stateless mode often pairs with SLAAC.
Verification — the five commands
R1# show ip dhcp binding
R1# show ip dhcp pool
R1# show ip dhcp conflict
R1# show ip dhcp server statistics
R1# debug ip dhcp server packet ! high volume — use sparingly
| Command | Tells you |
|---|---|
show ip dhcp binding | Every active lease — IP, MAC, lease time |
show ip dhcp pool | Pool stats — IPs in pool, allocated, free |
show ip dhcp conflict | Pool entries the server detected as duplicates (someone else using the IP) |
show ip dhcp server statistics | Message counts (Discovers, Offers, Acks) — useful for spotting flapping clients |
debug ip dhcp server packet | Live message trace. Watch DORA in action. |
The 6-step DHCP debug workflow
When a client says “I’m not getting an IP”:
-
Same subnet as the server? If yes, broadcasts reach the server directly. If no, you need
ip helper-addresson the client-facing interface. Verify withshow running-config interface .... -
Server side seeing the Discover?
debug ip dhcp server packetwith filtering. If no Discover arrives, the broadcast isn’t reaching the server (routing, ACL, helper issue). -
Pool has free addresses?
show ip dhcp pool. If full or exhausted, no Offer comes back. -
Wrong pool matching? With multiple pools on one server, the
giaddr(or interface) determines which pool. Ifgiaddrdoesn’t fall within any pool’s network, no Offer. -
Conflict detected?
show ip dhcp conflict. The server may have detected the IP it tried to offer is already in use (someone configured statically). Server skips and tries next. -
Client behaving correctly? From client: re-trigger DHCP. Windows:
ipconfig /release+ipconfig /renew. macOS: System Settings → Network → Make Service Inactive → Reactivate. Linux:dhclient -v eth0.
Worked scenarios
Scenario 1. A user complains their PC is getting 169.254.42.10. What does that tell you?
Answer: APIPA (Automatic Private IP Addressing) — the 169.254.0.0/16 range. The PC tried DHCP, got no response, fell back to self-assigning. Means DHCP server is unreachable. Check: switch port state, VLAN, ip helper-address on the gateway, DHCP server availability.
Scenario 2. A new VLAN was added. Hosts in it can’t get DHCP. The DHCP server is on a different VLAN. The other VLANs work fine.
Answer: New VLAN’s SVI is missing ip helper-address. Add it:
R1(config)# interface Vlan50
R1(config-if)# ip helper-address 10.99.0.5
Scenario 3. Pool gives out IPs but every client also gets 10.0.0.1 as gateway. That’s the router’s IP. Now both router and a client have 10.0.0.1. Why?
Answer: The router’s IP wasn’t excluded from the pool. Add:
R1(config)# ip dhcp excluded-address 10.0.0.1
And remove the conflict via clear ip dhcp conflict *.
Scenario 4. A user reports their PC’s IP keeps changing. New IP every day. What’s wrong?
Answer: Lease is too short, OR DHCP server is rebooting and forgetting the binding (no persistent lease database). Check show ip dhcp pool lease time. Default 1 day with proper persistence should give the same IP back to the same MAC on each renewal.
Scenario 5. Two DHCP servers exist in the same broadcast domain offering the same scope. What happens?
Answer: Race condition. Both Offer; client picks one (typically the first Offer received). Other server frees the address it offered. In the long run, IPs from both servers get handed out — risk of IP conflicts if scopes overlap. Fix: ONE DHCP authority per subnet (use DHCP failover or just pick one).
Scenario 6. An attacker plugs in a rogue DHCP server handing out gateway 10.0.0.99 (attacker’s MITM box). Some clients get the attacker’s gateway and route through them. How do you prevent this in the future?
Answer: Enable DHCP Snooping on all access switches:
SW1(config)# ip dhcp snooping
SW1(config)# ip dhcp snooping vlan 10,20,30,40
SW1(config-if)# ip dhcp snooping trust ! ONLY on uplinks to legitimate DHCP servers
Everything else is untrusted by default — switch silently drops rogue Offers/Acks.
Scenario 7. An IP phone shows “no TFTP server” error during boot.
Answer: Missing Option 150 in the voice VLAN’s DHCP pool. Add:
R1(config)# ip dhcp pool VOICE
R1(dhcp-config)# option 150 ip 10.1.1.5 ! TFTP server IP
Reboot the phone to re-request DHCP. (Option 66 is the standards-based alternative; Option 150 is Cisco-specific. Many phones support either or both.)
Scenario 8. You want host aa:bb:cc:11:22:33 to always receive IP 10.0.0.50. How?
Answer: Either exclude 10.0.0.50 and set it statically on the host, or create a manual binding:
R1(config)# ip dhcp pool PRINTER
R1(dhcp-config)# host 10.0.0.50 255.255.255.0
R1(dhcp-config)# client-identifier 01aa.bbcc.1122.33
R1(dhcp-config)# default-router 10.0.0.1
The 01 prefix indicates Ethernet hardware type. The host’s MAC follows.
Common mistakes
-
Forgetting
ip helper-addressin routed networks. Symptom: APIPA addresses (169.254.x.x). Fix: helper-address on every client-facing SVI pointing to the DHCP server(s). -
Not excluding the gateway IP. Pool happily hands out the router’s IP → conflict. Always
ip dhcp excluded-addressfor router, static servers, reserved range. -
Lease too short. 1 hour lease = renewals every 30 min = noisy logs + server CPU. Default 1 day is usually fine.
-
Two DHCP servers on same broadcast domain with same scope. Race; possible conflicts. Pick one authority.
-
Trusting any DHCP server. Rogue server attacks. Enable DHCP Snooping with
trustonly on legitimate uplinks. -
Wrong DHCP option numbers. Option 3 = router, 6 = DNS, 51 = lease, 150 = Cisco TFTP. Memorize.
-
Manual binding without
client-identifierprefix. Cisco IOS requires the01(Ethernet) prefix before the MAC.client-identifier aa.bbcc.1122.33(missing prefix) silently fails to bind. -
DHCP for static infrastructure. Routers, switches, AP controllers should have static IPs — never DHCP. Server reboot during a DHCP outage = infrastructure outage compounded.
-
No DHCP failover plan. Enterprise DHCP needs failover. Cisco IOS server is not great for this; Windows or ISC DHCP with proper failover config is the enterprise standard.
-
Forgetting that DHCP runs at L2. DHCP traffic is broadcast at the link layer, even though it carries L3 information. Routes don’t help DHCP reach a server on a different subnet — only helper-address does.
Lab to try tonight
-
Single-router DHCP — one router, one switch, two PCs. Router has
10.0.0.1/24on its LAN interface. -
Configure DHCP server on the router. Exclude
10.0.0.1–10.0.0.10. Pool gives out10.0.0.11+with default-router10.0.0.1, DNS8.8.8.8, lease 1 day. -
Verify — set both PCs to DHCP, watch them get IPs.
show ip dhcp bindingconfirms both leases. -
DHCP relay — add a second router with
10.1.0.0/24. Connect a PC. Set PC to DHCP — observe APIPA failure (169.254.x.x). -
Add
ip helper-addresson the second router’s LAN interface pointing to the first router. Re-trigger DHCP on the PC. Verify it gets a10.1.0.xIP. -
Lease renewal observation — set lease to 2 minutes for testing. Watch the PC renew at T1 (50%, so 1 min). Use
debug ip dhcp server packetto see the unicast Renew. -
Manual binding — create a manual binding for one PC’s MAC. Release/renew that PC. Verify it gets the bound IP exactly.
-
DHCP Snooping — enable on the switches. Add a fake DHCP server on an untrusted port (use a second router temporarily). Watch the snooping table block the rogue Offers.
show ip dhcp snooping bindingshows legitimate bindings only. -
Option 150 test — configure Option 150 in the voice VLAN pool. Capture a packet exchange (using Wireshark / mirror port) and inspect the Option 150 in the Offer.
-
Bonus — DHCP starvation simulation. Use
dhcpigoryersiniaagainst an unrestricted switch port. Watch the pool deplete. Apply DHCP Snooping rate-limit + Port Security to mitigate.
Cheat strip
| Concept | Plain English |
|---|---|
| DORA | Discover → Offer → Request → Ack |
| All broadcast | All 4 DORA messages are L2 broadcasts |
| UDP ports | 67 = server, 68 = client |
| Renewal | T1 (50%) unicast Renew, T2 (87.5%) broadcast Rebind, then expiry |
| giaddr | Gateway IP — stamped by relay agents to identify source subnet |
| Lease default | Cisco IOS = 1 day. Windows = 8 days |
ip helper-address | Relay DHCP broadcasts across an L3 boundary |
excluded-address | IPs the pool must not hand out (gateway, statics) |
| DHCP Snooping | Switch-side security — only trust DHCP server messages on specific ports |
| Option 1 | Subnet mask |
| Option 3 | Default gateway |
| Option 6 | DNS server |
| Option 15 | DNS search domain |
| Option 42 | NTP server |
| Option 51 | Lease time (seconds) |
| Option 53 | DHCP message type |
| Option 66 | TFTP server (standards) |
| Option 82 | Relay agent info — for ISP / DHCP server logging |
| Option 150 | Cisco-specific TFTP for IP phones |
| APIPA | 169.254.0.0/16 — auto-self-assigned when DHCP fails |
| Static binding | Manual reservation — client-identifier 01... with 01 Ethernet prefix |
| DHCPv6 | Different protocol. Uses multicast ff02::1:2. Often paired with SLAAC |
| Stateless mode | DHCPv6 hands out DNS only; SLAAC handles addressing |