I have an upcoming homelab server project that involves booting all my machines over the network with PXE. That means I need to rely on and understand DHCP for a lot more than just handing out IP addresses.
Despite already running OpenWRT routers, home servers, and virtual networks, I still reduced DHCP to that service that gives my devices IP addresses and prevents IP conflicts on the same subnets.
Before touching the real project, I built a mini-network in VMware Workstation. An OpenWRT virtual machine at 192.168.24.254 served as the router and DHCP server, while a Windows 11 VM served as the test client. I connected them through an isolated host-only network and used Wireshark to capture everything.
As I found out, the IP address was only one tiny part of a much larger configuration handoff.
One DHCP exchange quietly configured half my network
The IP address was only one field in a much larger answer
When I forced the Windows VM to obtain a fresh IP lease with ipconfig /release and ipconfig /renew, Wireshark captured four packets. Together, they formed the DHCP process commonly shortened to DORA:
- Windows broadcasts a DHCP Discover to find a server.
- OpenWRT’s DHCP server kindly returned an Offer containing an available address and its configuration.
- Windows broadcasts a Request confirming that it accepted that offer.
- The DHCP server commits the lease and its settings with an Acknowledgment, or just “ACK.”
DHCP “options” are numbered fields that carry extra configuration details alongside the lease. I had expected the assigned address 192.168.24.138 actually to be another one of those options. Instead, the server placed it in a dedicated field named yiaddr, which literally just means “your IP address.” The numbered options filling out most of the packet carried separate instructions for configuring the client.
Since my Windows client had already talked to OpenWRT’s DHCP server, it wasn’t receiving this address for the first time. Its Discover included option 50, the Requested IP Address option, asking OpenWRT for 192.168.24.138 because it remembered it from its last lease. OpenWRT simply checked the address and handed it right back.
The final ACK then supplied the rest of the network configuration to the client:
-
Option 1 sets the subnet mask to
255.255.255.0. -
Option 3 sets
192.168.24.254as the gateway. - Option 6 points DNS requests at OpenWRT, which supplies the upstream DNS servers.
- Option 15 supplies the LAN domain.
- Option 28 supplies the broadcast address.
-
Option 54 identifies where the DHCP server is (
192.168.24.254in this case). - Options 51, 58, and 59 control how long the IP address lease lasts.
The lease given by OpenWRT’s DHCP server stipulates a 12-hour lifetime. It also schedules a renewal time T1 after six hours, when Windows would typically contact the original server. If the lease has not been renewed by T2 at 10.5 hours, Windows is allowed to broadcast a request to any available DHCP server.
Windows told the DHCP server exactly what it wanted
Option 55 exposed a surprisingly long and very old shopping list
The second big discovery about the nature of DHCP came from the client rather than the server. Windows wasn’t just passively waiting for whatever the DHCP server felt like sending. Its Discover contained Option 55, the Parameter Request List. This list kind of works like a big shopping list of settings it understood and wanted the server to return.
My Wireshark packet analysis showed requests ranging from essential configuration to legacy compatibility settings from the early 90s, when WINS and classful A/B/C network routing were still a thing:
|
Group |
Option |
What Windows requested |
|
Essential |
1 |
Subnet mask |
|
Essential |
3 |
Router |
|
Essential |
6 |
DNS servers |
|
Essential |
15 |
Domain name |
|
Advanced |
43 |
Vendor-specific data |
|
Advanced |
114 |
Captive portal information |
|
Advanced |
119 |
Domain search list |
|
Advanced |
121, 249 |
Standard and Microsoft classless routes |
|
Advanced |
252 |
WPAD proxy discovery |
|
Legacy |
31, 33 |
Router discovery and legacy static routes |
|
Legacy |
44, 46, 47 |
NetBIOS name server, node type, scope |
Interestingly, Windows 11 also identified itself through Option 60 as MSFT 5.0. So, while the operating system was current, parts of its DHCP introduction looked like they belonged in a time capsule.
I found the two route requests fascinating. Option 121 is the standard classless, or “CIDR route” option, while Option 249 is the Microsoft variant. It actually asked for both, presumably for compatibility reasons. Interestingly, Windows did not request Option 42, which is reserved for Network Time Protocol (NTP) servers.
It just goes to show that the complete IANA DHCP option registry is more like a cafeteria menu than a checklist that every client has to request. In this case, Option 55 didn’t write the DHCP server’s reply either. The server still supplied the broadcast address via Option 28, even though Windows never asked for it.
It seems the client gets a vote, but the server always has the final say.
I changed four options, and Windows rewired itself
DNS servers, search domains, and a static route arrived with one new lease
I know that a lot of network configuration, like DNS, can be changed within Windows manually, but I wanted to see just how much I could actually set without touching Windows. So, I added four new customer DHCP option strings to the LAN scope on OpenWRT for its DHCP server to push out:
-
6,9.9.9.9,1.1.1.1told Windows to use Quad9 and Cloudflare as IPv4 DNS servers. -
15,lab.home.arpachanged the connection-specific domain. -
119,lab.home.arpa,services.home.arpasupplied the client with two DNS search domains. -
121,0.0.0.0/0,192.168.24.254,198.51.100.0/24,192.168.24.254supplied two different routes.
After waiting an eternity for OpenWRT’s dnsmasq service to return, a second release and renewal of Windows’ IP address showed the DHCP server had delivered the new values:
-
The IPv4 resolvers became
9.9.9.9and1.1.1.1. -
Its connection-specific domain became
lab.home.arpa. - The search lists now contained both supplied domains.
-
PowerShell demonstrated that
198.51.100.0/24now routed through OpenWRT. - The route’s protocol appeared as Dhcp.
Direct lookups confirmed that both public resolvers were answering correctly. I had essentially changed one DHCP scope and renewed the lease, yet Windows now had DNS servers, naming, and routing configuration without me needing to edit anything manually.
Using documentation-only IP addresses in the IPv4 ranges of 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 for experimental routing is best practice. That’s because IPs in these ranges are reserved for documentation purposes and are the best way to avoid accidentally redirecting traffic that would otherwise end up in a real public network.
DHCP can offer plenty, but it can’t control everything
Changing my IPv4 scope configured only half of a dual-stack client
Several small failures on my part kept me from declaring DHCP the one server that rules all network configuration. The clearest limit appeared when I ran nslookup. Although Option 6 had changed Windows’ IPv4 resolvers to Quad9 and Cloudflare, the command still selected OpenWRT at its IPv6 address.
The IPv6 result taught me a valuable lesson and gave me fuel for thought regarding my upcoming PXE project. I had only changed DHCPv4, so OpenWRT just kept on advertising an IPv6 address (fd25:b0d6:47f::1) as a resolver through its separate IPv6 configuration.
I could, of course, just fix that by supplying IPv6 DNS servers through OpenWRT’s DHCPv6 advertisement settings. It’s not an unsolvable limitation, but another path I needed to check. None of this made DHCP’s options cosmetic in any sense of the word. OpenWRT changed every supported IPv4 setting that I tested, including a route installed directly into Windows.
After the experiment, I would no longer call DHCP an IP address vending machine. It’s closer to the network’s automated onboarding service, with the address serving as only the first item on the menu. In the end, I went looking for an IP lease and found an entire network setup file hiding inside it.