Scroll to navigation

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

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.
Passive ARP + DHCP fingerprinting. Read-only: sends nothing, runs until stopped (Ctrl-C). CLI only - not available from the web UI.
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.
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.
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.
List interface names usable with the other commands.
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

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.
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).
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.
Emit a periodic status line with running totals every SEC seconds (default 5; 0 disables it). Shown only at -v3.

exhaust only

DHCP option numbers to request (parameter request list), e.g. "12,14-19,23". Defaults to requesting options 0–79.
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.
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.
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.
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.
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.
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.
Skip the ARP-conflict eviction phase against re-acquired addresses (default: run it). See RFC 5227 §2.4.
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).
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

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.
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.
See above.

release only

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

Override the lease journal location (default: the resolved per-interface path under $XDG_STATE_HOME/dhcpig/).
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.
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).
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.
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

sudo dhcpig exhaust eth0 --report run.json
sudo dhcpig release eth0 --scope 192.168.4.0/22
sudo dhcpig active-scan eth0 --scope 192.168.4.0/22
sudo dhcpig release-previous eth0
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