Skip to content

Troubleshooting

This page covers the most common things that go sideways when bringing up a DHCP server.

The server does not start

  • Check whether another process is already bound to the UDP port.
  • On Windows, verify the process has permission to open the socket.
  • On Linux, confirm you are running with the privileges required for the binding mode you selected.
  • Remember that the package is pure Python, but DHCP serving still depends on OS socket privileges and UDP broadcast behavior.

No interfaces are listed

  • Make sure the host has at least one IPv4 interface configured.
  • In containers or sandboxes, interface enumeration may be limited by the runtime.
  • If you are using a virtual adapter, confirm it exposes an address the library can resolve.

Clients do not receive leases

  • Confirm the server is bound to the interface that sees the client traffic.
  • Verify the address pool overlaps the network on that interface.
  • Check that the lease backend is writing allocations the way you expect.

Packet decoding looks wrong

  • Capture the raw packet and compare it against the DHCP header layout.
  • Turn on debug logging to inspect the transaction ID and message type.
  • Validate that any custom options implement the DHCPOptionType contract correctly.

Decode packet hex to structured JSON when you want tooling-friendly output.

pydhcp packet --decode --input - --format json

Use summary output when you want a compact terminal view while troubleshooting captures.

pydhcp packet --decode --input - --format summary

If a command reports that captures or YAML, TOML or INI text need the pktcap extra, that TOML needs an extra, or that the command line needs the cli extra, install it in the environment running the CLI: pip install "pydhcp[pktcap]" or pip install "pydhcp[cli]". A settings file in TOML (before Python 3.11) or YAML names duho's extra: pip install "duho[config]" or "duho[yaml]". YAML and TOML text also need pktcap's own extras: pip install "pktcap[yaml,toml]".

Capturing live DHCP traffic

Use pydhcp capture when you want tshark-like DHCP-focused output without leaving the library's structured packet formats.

pydhcp capture --listen 127.0.0.1:6767 --filter "msg_type=DHCPDISCOVER" --output -

Useful filters include:

pydhcp capture --filter "op=BOOTREQUEST and sport=68"
pydhcp capture --filter "client_id=01:AA:BB:CC:DD:EE:FF"
pydhcp capture --filter "option.DHCP_MESSAGE_TYPE=DHCPREQUEST"

To look at the traffic in tcpdump or Wireshark, write a capture file; it holds each datagram as the client sent it.

pydhcp capture --output heard.pcap

To go through a capture someone else took (a tcpdump -w or Wireshark file) with the same filters, read it instead of listening:

pydhcp capture --read client.pcap --filter "client_id=01:AA:BB:CC:DD:EE:FF"

For long troubleshooting sessions, split captures into one file per packet.

pydhcp capture --format json --output "output/{client_id}/{timestamp}_{msg_type}.{format}" --per-record

Hooks are trusted local code. A Python hook uses module:function and its module must be on PYTHONPATH; a command hook path is executed once per accepted packet with the record of the frame on stdin and PKTCAP_HOOK_* in its environment. ./hook is the file in the working directory when the capture starts; a bare hook is looked up on PATH alone, and a file that is not executable is refused at start-up.

Wildcard listening behaves differently on Windows and Linux

  • Packet-info routing is opportunistic and only used on platforms that expose the needed socket APIs.
  • A socket bound to an address hears no broadcast on Linux. per_interface=True, and any listen that names an address, bind one socket per address, and on Linux such a socket receives none of the limited (255.255.255.255) or subnet broadcasts that a client without an address sends. Only the wildcard (listen="*", the default) serves those clients there. This was measured on Linux; macOS and the BSDs follow the same rule (unmeasured here). Windows delivers a broadcast to an address-bound socket. pydhcp logs a WARNING once per process when it binds such an address.
  • To serve one interface only, name it: listen="eth1" (an adapter name, a MAC or a netimps.Interface). That is one wildcard socket: on Linux it is bound to the device, elsewhere it drops what arrives on the other interfaces and counts it in metrics.packets_dropped_other_interface; a number there that grows is traffic from a segment the listener was told not to serve (on Linux it stays 0, the kernel delivers none). An address would hear no broadcast on Linux.
  • Explicit endpoint lists avoid interface-enumeration surprises while debugging, and are right for a unicast peer (a relay's server address, a test on loopback).
pydhcp server --listen 127.0.0.1:6767,127.0.0.1:6768 -v

Useful commands

pydhcp interfaces
pydhcp server --help
pydhcp packet --help
pydhcp capture --help