| DHCPIG(1) | User Commands | DHCPIG(1) |
NAME¶
dhcpig - DHCP exhaustion / network-hardening validation tool (whitehat)
SYNOPSIS¶
dhcpig command interface [options]
dhcpig ifaces
dhcpig report path
DESCRIPTION¶
dhcpig validates that a network is hardened against DHCP pool exhaustion, forced lease release, and gratuitous-ARP disruption, and passively fingerprints hosts on the segment. It exhausts a DHCP pool, releases and re-acquires neighbours' leases by name, evicts hosts off addresses with forged RFC 5227 ARP conflicts, and reports whether the network defended itself.
It needs root (raw sockets) and Python 3.11 or newer. A local web UI is available as dhcpig-web(1).
There is no authorization gate. release and exhaust disrupt live clients by design, and --scope is optional - with none given, a run targets the whole network attached to interface. Only run this against networks you own or are explicitly authorized to test.
COMMANDS¶
- exhaust interface
- Consume the DHCP pool. Non-destructive to the pool itself (it competes for free addresses rather than seizing bound ones outright), but it releases every ARP-discovered neighbour's lease first and forges ARP conflicts against what it re-acquires - see WHAT EACH COMMAND DOES below. This is the default, most invasive mode.
- scan interface
- Passive ARP + DHCP fingerprinting. Read-only: sends nothing, runs until stopped (Ctrl-C). CLI only - not available from the web UI.
- active-scan interface
- Active discovery: ARP-sweeps the scope and sends one DHCPINFORM to fingerprint the DHCP server(s). Non-destructive, but requires --scope (or a resolvable interface network) so its sweep stays bounded.
- release interface
- DESTRUCTIVE. DHCPRELEASE every in-scope, ARP-discovered neighbour's lease, re-acquire the freed addresses by name (DHCP option 50), then contest ownership of what it took with forged ARP conflicts (RFC 5227 §2.4). The pool itself is left intact, so most hosts can immediately get a new address; the verdict is whether any host lost its address and failed to get a new one.
- release-previous interface
- Recovery, not an attack. Replays this tool's on-disk lease journal and hands back every address a prior exhaust or release run took on this interface/network/server. Sends nothing if a new client can already obtain an address.
- restore interface
- Release exactly the leases the currently running process instance acquired (in-memory only - useless once that process has exited). For recovery after the process is gone, use release-previous instead.
- ifaces
- List interface names usable with the other commands.
- report path
- Re-render a previously saved JSON report file and print a one-line summary to stdout.
OPTIONS¶
Common to exhaust, scan, active-scan, release, release-previous¶
- --ipv6
- DHCPv6 instead of DHCPv4. Not currently implemented - every packet builder in this version is v4-only; passing this flag raises a configuration error immediately rather than running a broken v6 listen / v4 send mismatch.
- --report FILE
- Write a session report to FILE when the run ends. Format is chosen from FILE's extension (.json/.csv/.html; anything else falls back to JSON).
- -v, --verbosity N
- Output detail, 0–3 (default 2). 0 prints results only (findings and the final summary); 1 is a compact one-character-per-packet stream; 2 is the normal packet-level log; 3 adds internal debug lines.
- --status-interval SEC
- Emit a periodic status line with running totals every SEC seconds (default 5; 0 disables it). Shown only at -v3.
exhaust only¶
- --request-option SPEC
- DHCP option numbers to request (parameter request list), e.g. "12,14-19,23". Defaults to requesting options 0–79.
- --client-mac MAC
- Use this MAC for a simulated client instead of a random one. Repeatable; with more than one, the sender rotates through the list round-robin instead of generating random MACs.
- --spoof-eth-src
- Ethernet source address equals the per-client MAC, so each simulated client looks like a distinct device at Layer 2 (this is what exercises port security / DHCP snooping). Default; this flag exists for symmetry with --no-spoof-eth-src.
- --no-spoof-eth-src
- Use the real NIC's MAC as the Ethernet source for every frame, changing only the BOOTP chaddr per client. Needed on Wi-Fi, where an access point drops frames whose source MAC doesn't match the associated station.
- --scope CIDR
- Bound the run to this network. Repeatable. Defaults to the interface's own network. Supplying it also makes the pool-size estimate in the report deterministic (a host count from the CIDR) instead of inferred from the first DHCPOFFER's subnet.
- --dry-run
- Reconnaissance only: the ARP sweep and the legitimate before/after DHCP control transactions run for real (they need a raw-capable interface and root), but nothing that would take or disturb a lease is sent - no RELEASE, no re-acquisition flood, no ARP conflict.
- --no-journal
- Don't record acquired leases to the on-disk recovery journal (default: record them). Without it, release-previous has nothing to recover with if this run is interrupted.
- --no-evict
- Skip the ARP-conflict eviction phase against re-acquired addresses (default: run it). See RFC 5227 §2.4.
- --no-race-freed
- Skip firing a targeted DISCOVER the moment a live foreign DHCPNAK or DHCPDECLINE shows a specific address just became free at the server (default: race it, ahead of the untargeted flood).
- --race-on-rediscover
- Also race on a foreign DHCPDISCOVER from a MAC the ARP inventory already has an address for. Off by default - the highest-volume, lowest-precision trigger of the three.
active-scan, release, release-previous¶
- --scope CIDR
- Network(s) to sweep / target / recover. Repeatable. Defaults to the interface's own network. active-scan refuses to run if no scope can be determined at all.
- --rate N
- Send rate in packets per second (default 7; 50 on release-previous, see below). Not available on exhaust - its windowed handshake pipeline self-paces instead.
- --dry-run
- See above.
release only¶
- --no-evict
- Skip the ARP-conflict eviction phase (default: run it). release shares the same release / re-acquire / evict chain as exhaust, minus the pool-draining flood.
release-previous only¶
- --journal PATH
- Override the lease journal location (default: the resolved per-interface path under $XDG_STATE_HOME/dhcpig/).
- --max-age DAYS
- Ignore journal entries older than this many days (default 7). An optimisation, not a safety measure - a stale entry's MAC simply won't match the server's current binding.
- --any-server
- Release journal entries even when the currently reachable DHCP server differs from the one recorded at acquisition time (default: skip mismatches, to avoid releasing addresses on the wrong network).
- --rate N
- Default 50 here, not 7 - this mode runs during an outage the operator is actively trying to end, and its frames are unicast to one server rather than sprayed at the segment, so a faster default is the right trade-off.
- --passes N
- DHCPRELEASE has no reply (RFC 2131), so resend the selected set this many times as cheap insurance against a dropped frame (default 2).
EXIT STATUS¶
- 0
- Success.
- 2
- Bad arguments / configuration error (e.g. active-scan with no resolvable scope, --ipv6).
- 3
- No DHCP server detected before the no-server deadline elapsed.
- 130
- Interrupted (Ctrl-C).
FILES¶
- $XDG_STATE_HOME/dhcpig/leases-<iface>.jsonl
- (or ~/.local/state/dhcpig/... if $XDG_STATE_HOME is unset) - the append-only lease journal that release-previous replays. Per-engagement data; delete it when an engagement ends.
WHAT EACH COMMAND DOES¶
See README.md in the source distribution for a walkthrough of each mode's packet sequence, and docs/DESIGN.md for the reasoning behind the safety model (what still bounds a run now that there is no authorization gate) and the evidence model (why a verdict can be trusted).
EXAMPLES¶
- Exhaust a pool and write a JSON report:
- sudo dhcpig exhaust eth0 --report run.json
- Release active clients in one /22, DESTRUCTIVE:
- sudo dhcpig release eth0 --scope 192.168.4.0/22
- Read-only discovery of DHCP servers on a scope:
- sudo dhcpig active-scan eth0 --scope 192.168.4.0/22
- Undo a previous run from its lease journal:
- sudo dhcpig release-previous eth0
- Recon only, nothing mutating sent:
- sudo dhcpig exhaust eth0 --dry-run
SECURITY CONSIDERATIONS¶
Only run this against networks you own or are explicitly authorized to test. release and exhaust disrupt live clients on the segment by design, and, absent --scope, target the entire network attached to the given interface. The authors are not responsible for misuse.
SEE ALSO¶
dhcpig-web(1), pig(1)
AUTHOR¶
Kevin Amorin
| 2026-08-01 | dhcpig 2.5.0 |