What Is a DHCP Relay Agent
A DHCP DISCOVER is sent with a destination IP address of 255.255.255.255 and a broadcast destination MAC address. Routers do not forward broadcasts, so when the client and the DHCP server are on different segments, the DISCOVER never reaches the server on its own.
Putting a DHCP server on every segment would solve it, but that means one server per site or per VLAN, which is not practical. Instead, the router attached to the client’s segment receives the broadcast on the client’s behalf, converts it into a unicast, and forwards it to a DHCP server on another segment. That function is called a DHCP relay agent.
The behavior of a relay agent is specified in RFC 2131, and the detailed requirements it inherits as a BOOTP relay are defined in RFC 1542. Just as DHCP inherited the BOOTP message format, the relay mechanism was inherited from the BOOTP relay agent.
The Role of giaddr
The key to understanding a relay agent is the giaddr (Gateway IP Address) field of the DHCP message.
| Field | As sent by the client | After passing through the relay agent |
|---|---|---|
giaddr | 0.0.0.0 | The relay agent writes in the IP address of its client-side interface |
hops | 0 | Incremented by one for every relay agent the message passes through |
| Destination IP address | 255.255.255.255 | The DHCP server’s IP address (unicast) |
| Source IP address | 0.0.0.0 | The relay agent’s IP address |
giaddr is not merely a record of where the message has been: it is the information the server uses to decide which pool to allocate from. The server looks at the giaddr of the message it receives and picks the pool for the subnet that contains that address. If the relay agent’s client-side interface is 192.168.20.1/24, that value goes into giaddr, so the server allocates from the 192.168.20.0/24 pool.
The server’s replies (OFFER and ACK) are also returned as unicast to giaddr. The relay agent receives them and forwards them to the client. The server never needs to know where the client is; it only has to answer based on giaddr.
hops counts how many relays a message has passed through and exists to prevent loops. RFC 1542 recommends that a relay agent discard a message whose hops exceeds 4. Ordinary designs never chain several relays, so this value is almost always still 1.The Packet Flow Through a Relay
Here is the flow of a DORA in a setup with a client on 192.168.20.0/24, relay agent R1, and a DHCP server at 10.1.2.2.
sequenceDiagram
participant C as Client
192.168.20.0/24
participant R as R1 (relay)
Gi1: 192.168.20.1
Gi2: 10.1.2.1
participant S as DHCP server
10.1.2.2
C->>R: 1. DISCOVER (broadcast)
Destination: 255.255.255.255
giaddr = 0.0.0.0, hops = 0
Note over R: Writes 192.168.20.1 into giaddr,
increments hops to 1,
converts to unicast
R->>S: 2. DISCOVER (unicast)
10.1.2.1 to 10.1.2.2
giaddr = 192.168.20.1, hops = 1
Note over S: giaddr is 192.168.20.1,
so the 192.168.20.0/24 pool is chosen
S->>R: 3. OFFER (unicast)
Destination: giaddr = 192.168.20.1
yiaddr = 192.168.20.101
R->>C: 4. OFFER (broadcast)
Forwarded onto the client segment
Note over C,S: REQUEST and ACK follow the same path
- The client sends its DISCOVER as a broadcast in the usual way. It is unaware that a relay agent exists.
- R1 receives it on GigabitEthernet1, writes the receiving interface’s IP address (192.168.20.1) into
giaddr, incrementshopsto 1, and forwards it as a unicast to the server named byip helper-address. - The server works out which segment the request came from using
giaddr, picks an address from the matching pool, and returns the OFFER as a unicast togiaddr. - R1 receives the OFFER and forwards it onto the client segment. Because the client does not have an address yet, it is normally forwarded as a broadcast.
REQUEST and ACK follow the same path. Neither the client nor the server treats the relay as a special case; the whole mechanism rests on the single giaddr field.
Configuration with ip helper-address
On Cisco IOS / IOS XE, a relay agent is enabled by configuring ip helper-address on the client-side interface. Note that it is not the server-side interface.
interface GigabitEthernet1
description to client segment
ip address 192.168.20.1 255.255.255.0
ip helper-address 10.1.2.2Where several DHCP servers exist, writing multiple ip helper-address lines forwards the message to all of them.
The server needs a route back to the client’s segment. OFFERs and ACKs are returned to giaddr (192.168.20.1), so the relay cannot work unless the server can reach that address.
ip helper-address forwards UDP broadcasts other than DHCP as well. Cisco IOS forwards the following eight services by default.
| Port | Service |
|---|---|
| 37 | TIME |
| 49 | TACACS |
| 53 | DNS |
| 67 | BOOTP / DHCP server |
| 68 | BOOTP / DHCP client |
| 69 | TFTP |
| 137 | NetBIOS Name Service |
| 138 | NetBIOS Datagram Service |
To forward only DHCP, disable the ones you do not want individually with no ip forward-protocol udp <port>. Unintentionally forwarding DNS or NetBIOS broadcasts to another segment leads to needless traffic and to security problems.
Option 82 (Relay Agent Information)
Option 82 is information a relay agent attaches to a DHCP message, defined in RFC 3046. It tells the server “which port (circuit) of which relay agent this request came from,” and it carries sub-options inside.
| Sub-option | Name | Contents |
|---|---|---|
| 1 | Circuit ID | An identifier for the circuit the request arrived on, such as a physical port number or a VLAN ID |
| 2 | Remote ID | An identifier for the relay agent itself, such as a MAC address or a host name |
The relay agent inserts Option 82 when it forwards a message from the client, and strips Option 82 out before forwarding the server’s reply to the client. The client therefore never sees Option 82.
On the server side this information is used for policies such as “assign this particular address only to equipment attached to this port,” and for auditing which addresses were handed out. Combined with DHCP Snooping on a switch, it also lets the binding table carry port information.
The configuration on Cisco IOS / IOS XE is as follows.
(on the relay agent)
ip dhcp relay information option
(on the DHCP server, to also accept Option 82 packets whose giaddr is 0)
ip dhcp relay information trust-allgiaddr is still 0.0.0.0 as invalid and discards it, because Option 82 being present without having gone through a relay agent suggests spoofing. In designs where a switch running DHCP Snooping inserts only Option 82 without rewriting giaddr, the server needs ip dhcp relay information trust-all.Verification on Real Devices
R3 (client), R1 (relay agent), and R2 (DHCP server) were connected on separate segments, and address acquisition through the relay was verified on real devices. All three routers run Cisco IOS XE 17.03.08a (csr1000v).
Taking a capture at two points at once is the key to this verification: it lets the same message be compared before and after the relay.
R2 (the server) is configured with the following pool and return route. Without the return route the OFFER cannot be sent back to giaddr, and the relay does not work.
ip dhcp excluded-address 192.168.20.1 192.168.20.100
!
ip dhcp pool LAN20
network 192.168.20.0 255.255.255.0
default-router 192.168.20.1
dns-server 10.1.2.2
domain-name kazulog.example
lease 0 0 2
!
ip route 192.168.20.0 255.255.255.0 10.1.2.1R1 (the relay) has ip helper-address on its client-side GigabitEthernet1.
interface GigabitEthernet1
description to R3 Gi1 (client segment / capture A)
ip address 192.168.20.1 255.255.255.0
ip helper-address 10.1.2.2Test Sequence and the Server-Side Counters
| STEP | Operation | R3’s Gi1 | DISCOVER rcvd | OFFER sent | REQUEST rcvd | ACK sent |
|---|---|---|---|---|---|---|
| 0 | Initial state (R3’s Gi1 shut down) | unassigned | 0 | 0 | 0 | 0 |
| 1 | no shutdown on R3’s Gi1 | 192.168.20.102 | 1 | 1 | 1 | 1 |
| 2 | Wait for T1 (60 seconds) to expire twice | 192.168.20.102 | 1 | 1 | 3 | 3 |
| 3 | Remove ip helper-address from R1, then release/renew | unassigned | 1 | 1 | 3 | 3 |
| 4 | Restore ip helper-address and renew | 192.168.20.103 | 2 | 2 | 5 | 5 |
| 5 | Enable Option 82, then release/renew | 192.168.20.104 | 3 | 3 | 7 | 7 |
Look at STEP 3. The client cannot obtain an address and stays unassigned, and the server’s DISCOVER counter does not move from 1. Removing ip helper-address stopped the DISCOVER from reaching the server, and the numbers show it.
How the Same DISCOVER Changes Across the Relay
Here is the DORA from STEP 1 as seen in the two captures. First, the client side.
1 0.000000 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x26d1
2 0.021989 52:54:00:86:de:30 → Broadcast ARP 60 Who has 192.168.20.102? Tell 192.168.20.1
3 2.051454 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP Offer - Transaction ID 0x26d1
4 2.057779 0.0.0.0 → 255.255.255.255 DHCP 375 DHCP Request - Transaction ID 0x26d1
5 2.070234 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP ACK - Transaction ID 0x26d1Now the server side. It is the same exchange, with the same Transaction ID 0x26d1, but everything is unicast.
1 0.000000 192.168.20.1 → 10.1.2.2 DHCP 357 DHCP Discover - Transaction ID 0x26d1
2 2.038251 10.1.2.2 → 192.168.20.1 DHCP 372 DHCP Offer - Transaction ID 0x26d1
3 2.053646 192.168.20.1 → 10.1.2.2 DHCP 375 DHCP Request - Transaction ID 0x26d1
4 2.060189 10.1.2.2 → 192.168.20.1 DHCP 372 DHCP ACK - Transaction ID 0x26d1Comparing the contents of the DISCOVER makes the fields the relay agent rewrote obvious. The first block is the client side, the second the server side.
Source Address: 0.0.0.0
Destination Address: 255.255.255.255
Dynamic Host Configuration Protocol (Discover)
Message type: Boot Request (1)
Hops: 0
Transaction ID: 0x000026d1
Bootp flags: 0x8000, Broadcast flag (Broadcast)
Client IP address: 0.0.0.0
Your (client) IP address: 0.0.0.0
Next server IP address: 0.0.0.0
Relay agent IP address: 0.0.0.0
Client MAC address: 52:54:00:49:49:5a (52:54:00:49:49:5a) Source Address: 192.168.20.1
Destination Address: 10.1.2.2
Dynamic Host Configuration Protocol (Discover)
Message type: Boot Request (1)
Hops: 1
Transaction ID: 0x000026d1
Bootp flags: 0x8000, Broadcast flag (Broadcast)
Client IP address: 0.0.0.0
Your (client) IP address: 0.0.0.0
Next server IP address: 0.0.0.0
Relay agent IP address: 192.168.20.1
Client MAC address: 52:54:00:49:49:5a (52:54:00:49:49:5a)| Field | Client side | Server side |
|---|---|---|
| Source IP address | 0.0.0.0 | 192.168.20.1 (the relay’s address) |
| Destination IP address | 255.255.255.255 | 10.1.2.2 (the server’s address) |
Hops | 0 | 1 |
Relay agent IP address (giaddr) | 0.0.0.0 | 192.168.20.1 |
Transaction ID | 0x000026d1 | 0x000026d1 (the same) |
Client MAC address | 52:54:00:49:49:5a | 52:54:00:49:49:5a (the same) |
As described earlier, the relay agent rebuilds the IP packet while carrying the DHCP message through unchanged apart from giaddr and hops. Because Transaction ID and Client MAC address stay the same, the server can identify the client correctly and the replies can be matched back to it.
From the client’s point of view, the source of the OFFER and the ACK is 192.168.20.1, the relay agent. To the client the relay looks like the DHCP server, while the Option 54 (Server Identifier) the client received holds the real server’s address.
R3#show dhcp lease
Temp IP addr: 192.168.20.102 for peer on Interface: GigabitEthernet1
Temp sub net mask: 255.255.255.0
DHCP Lease server: 10.1.2.2, state: 5 Bound
DHCP transaction id: 26D1
Lease: 120 secs, Renewal: 60 secs, Rebind: 105 secs
Temp default-gateway addr: 192.168.20.1
Next timer fires after: 00:00:17
Retry count: 0 Client-ID: cisco-5254.0049.495a-Gi1
Hostname: R3DHCP Lease server is 10.1.2.2, off the client’s own segment, while default-gateway is the relay’s 192.168.20.1 — the two point at different places, which is characteristic of a relayed setup.
The Lease Renewal Does Not Go Through the Relay
This is the renewal that happened when T1 (60 seconds) expired. It is No.10 and No.11 of the attached client-side capture.
10 66.279226 192.168.20.102 → 10.1.2.2 DHCP 363 DHCP Request - Transaction ID 0x26d1
11 66.285223 10.1.2.2 → 192.168.20.102 DHCP 372 DHCP ACK - Transaction ID 0x26d1The source is the client’s own 192.168.20.102 and the destination is the server’s 10.1.2.2; the relay agent’s address does not appear. Both packets still carry giaddr of 0.0.0.0 and hops of 0. As described earlier, a renewal is a unicast to the server rather than a broadcast, so it does not go through the relay processing and simply passes through R1 by ordinary routing.
The same packets also appear in the server-side capture. R1 is not relaying them; it is merely forwarding them as a router.
What Happens When ip helper-address Is Removed
In STEP 3, ip helper-address was removed from R1’s GigabitEthernet1 and R3 was made to acquire an address again.
16 179.110077 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439
17 182.335039 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439
18 186.335474 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0x1439The client retransmits three times with the same xid and then repeats with a new one. The client-side capture records nine of these DISCOVERs, while the server-side capture contains none at all.
| Capture | STEP 3 DISCOVERs (xid 0x1439 / 0x143a / 0x143b) |
|---|---|
| A (client side) | 9 packets |
| B (server side) | 0 packets |
On R1 at this point, the show ip helper-address list is empty.
R1#show ip helper-address
Interface Helper-Address VPN VRG Name VRG StateThe link stays up yet no address is obtained, and the server-side counters do not move. Those three observations together show that the broadcast is not crossing the router. Restoring ip helper-address in STEP 4 brought the DISCOVER counter from 1 to 2 and the client recovered.
Option 82 in Practice
In STEP 5, ip dhcp relay information option was configured on R1 and ip dhcp relay information trust-all on R2, and the address was acquired again. The packets are larger in the server-side capture.
21 387.544996 192.168.20.1 → 10.1.2.2 DHCP 373 DHCP Discover - Transaction ID 0xfb5
22 389.551056 10.1.2.2 → 192.168.20.1 DHCP 388 DHCP Offer - Transaction ID 0xfb5
23 389.561390 192.168.20.1 → 10.1.2.2 DHCP 391 DHCP Request - Transaction ID 0xfb5
24 389.567012 10.1.2.2 → 192.168.20.1 DHCP 388 DHCP ACK - Transaction ID 0xfb5The DISCOVER is 373 bytes, 16 bytes larger than the 357-byte DISCOVER from STEP 1 that had no Option 82. Its contents are as follows.
Option: (82) Agent Information Option
Length: 14
Option 82 Suboption: (2) Agent Remote ID
Length: 12
Agent Remote ID: 020a0000c0a8140100000000
Option: (255) End020a0000c0a8140100000000, c0a81401 is the relay agent’s interface address 192.168.20.1. What goes into Option 82 depends on the implementation and the design: where ports are distinguished, as with DHCP Snooping on a switch, a Circuit ID is inserted as well. In a router-to-router relay there is no “circuit” to distinguish, which is presumably why only the Remote ID appeared.Looking at the same exchange in the client-side capture, on the other hand, Option 82 does not appear at all.
42 387.547323 0.0.0.0 → 255.255.255.255 DHCP 357 DHCP Discover - Transaction ID 0xfb5
43 387.559201 52:54:00:86:de:30 → Broadcast ARP 60 Who has 192.168.20.104? Tell 192.168.20.1
44 389.562682 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP Offer - Transaction ID 0xfb5
45 389.566898 0.0.0.0 → 255.255.255.255 DHCP 375 DHCP Request - Transaction ID 0xfb5
46 389.577910 192.168.20.1 → 255.255.255.255 DHCP 372 DHCP ACK - Transaction ID 0xfb5The DISCOVER is still 357 bytes and the OFFER and ACK are still 372 bytes. Because the relay agent strips Option 82 out before forwarding to the client, the client never sees it. The behavior described earlier is observable directly as a difference in packet size.
Download the full capture A (client side)
Download the full capture B (server side)
Verification Config and show Output
At each step the following three kinds of output were collected from R1, R2, and R3, kept in separate files per router. The verification config is the ..._run.txt file (the final state is the one from STEP 5).
| File | Contents |
|---|---|
..._show.txt | show version / show interfaces description / show ip interface brief / show ip route / show arp / show ip helper-address / show ip dhcp pool / show ip dhcp binding / show ip dhcp server statistics / show ip dhcp conflict / show ip dhcp relay information trusted-sources / show dhcp lease |
..._log.txt | show logging narrowed to that step alone. A marker is written with send log at the start of each step, and that string is passed to show logging | begin when collecting |
..._run.txt | show running-config at that step (that is, the verification config for the step) |
STEP 0: initial state (R3’s Gi1 shut down)
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
STEP 1: R3’s Gi1 brought up and an address obtained through the relay
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
STEP 2: the lease renewed twice by the expiry of T1
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
STEP 3: ip helper-address removed from R1, leaving the client unable to obtain an address
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
STEP 4: ip helper-address restored and the client recovered
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
STEP 5: Option 82 enabled (final state)
| Node | show output | syslog | running-config |
|---|---|---|---|
| R1 (relay) | show | log | run |
| R2 (server) | show | log | run |
| R3 (client) | show | log | run |
References
| RFC | Title | Summary |
|---|---|---|
| RFC 2131 | Dynamic Host Configuration Protocol | Defines the handling of giaddr and hops and the basic behavior of a relay agent. |
| RFC 1542 | Clarifications and Extensions for the Bootstrap Protocol | The detailed requirements for a BOOTP relay agent, including the limit on hops. |
| RFC 3046 | DHCP Relay Agent Information Option | Defines Option 82 and its sub-options (Circuit ID / Remote ID). |