bootpdc is a product of the Network Systems Group at Princeton University’s Office of Information Technology, and is available from https://www.net.princeton.edu/software/bootpdc/
The script relies on perl 5.6.0 or later, and tcpdump(8).
The simplest way to use bootpdc is in a pipeline with tcpdump(8), e.g.
tcpdump -l -s 600 -q -x -e udp port bootps or udp port bootpc | bootpdc
Note that bootpdc does not read the raw packet capture files that are produced with tcpdump’s -w option. Instead, bootpdc reads the hex dump (textual) output produced by tcpdump’s -x option.
You must specify tcpdump’s -x option, to produce the hex dump that bootpdc expects to read. bootpdc expects that each packet it reads will consist of a single packet header line followed by hex dump lines. Therefore, you should not specify tcpdump’s -X option; it causes newer versions of tcpdump to also print the packet’s contents in ASCII. And it’s a good idea to include tcpdump’s -q option, which inhibits some additional decoding which tcpdump might decide to perform when it believes it knows how to decode the packet.
You must specify tcpdump’s -s option to increase the snarflen high enough to capture complete BootP and DHCP packets. A BootP packet consists of an IP header (20-60 bytes), a UDP header (8 bytes), followed by 300 bytes of UDP payload (the actual BootP packet). For a DHCP packet, the UDP payload (the actual DHCP packet) is of variable size, typically up to 548 bytes. Although larger messages may be used by mutually agreeing DHCP clients and servers, it is uncommon to see DHCP in IP datagrams greater than 576 bytes (total), due to the desire to avoid IP fragmentation. Therefore, a snarflen of 600 is normally more than adequate.
When used in a pipe, specify tcpdump’s -l option, so its output is line-buffered. (This isn’t necessary if you first write the tcpdump output to a file, then later process the file with bootpdc.)
Using tcpdump’s filter expression ’udp port bootps or udp port bootpc’ (as in the example above) would normally cause tcpdump to display IP (not Ethernet) source and destination IP addresses in the tcpdump packet header line. Usually you’ll want tcpdump to display the Ethernet src and dest addresses instead, since bootpdc will show the IP src and dest addresses for you. That’s why you’ll usually specify tcpdump’s -e option.
When used in a pipe to capture and analyze live data, you may wish to specify tcpdump’s -n option to suppress address lookups (e.g. host addresses, port numbers, etc). Otherwise, a slow address lookup can cause tcpdump to block long enough that it drops incoming packets. Similarly, you may wish to specify bootpdc’s -n option to suppress address lookups. Otherwise, a slow address lookup can cause bootpdc to block long enough that the pipe connecting it with tcpdump will fill; that would cause tcpdump to block, ultimately causing tcpdump to drop incoming packets.
To have the benefit of address lookups without the danger of dropping packets, redirect tcpdump’s output to a file, then post-process it with bootpdc; e.g.
tcpdump -s 600 -q -x -e udp port bootps or udp port bootpc > foo (then later) bootpdc foo
The -i and -u options are useful when the packet capture is produced by a program that only captures the UDP payload, and not the IP or UDP headers. This is typical if instead of tcpdump, you obtain the data via a sockets-based datagram client; just arrange for your program to write the packets in something vaguely resembling tcpdump output.
18:52:22.366458 wormhole foo 590: 0.0.0.0.bootpc > foo.example.org.bootps: udp 548 IP: Src=0.0.0.0 (0.0.0.0) Dst=192.168.200.10 (foo) UDP: SrcPort=client DstPort=server Len=556 Cksum=9fe7 BOOTP: Op=request htype=01 hlen=6 chaddr=000083a30393 hops=1 xid=0xb6b1d6fa secs=0 flags=0000 ciaddr=0.0.0.0 (0.0.0.0) yiaddr=0.0.0.0 (0.0.0.0) siaddr=0.0.0.0 (0.0.0.0) giaddr=192.168.128.1 (wormhole) sname= file= Options: starts with RFC1048 magic cookie, decoding (len=312): DHCPmessageType: DHCPDISCOVER DHCPparamRequestList: subnetMask routerList dnsServerList domainName end pad (seen 298 times) 18:52:22.369118 foo wormhole 353: foo.example.org.bootps > wormhole.example.org.bootps: udp 311 (DF) IP: Src=192.168.200.10 (foo) Dst=192.168.128.1 (wormhole) UDP: SrcPort=server DstPort=server Len=319 Cksum=97e7 BOOTP: Op=reply htype=01 hlen=6 chaddr=000083a30393 hops=0 xid=0xb6b1d6fa secs=0 flags=0000 ciaddr=0.0.0.0 (0.0.0.0) yiaddr=192.168.128.193 (hyperbole.marketing) siaddr=0.0.0.0 (0.0.0.0) giaddr=192.168.128.1 (wormhole) sname=foo.example.org file= Options: starts with RFC1048 magic cookie, decoding (len=75): DHCPmessageType: DHCPOFFER DHCPserverIdentifier: 192.168.200.10 (foo) DHCPipAddressLeaseTime: 86400 seconds (1 day) subnetMask: 255.255.255.0 routerList: 192.168.128.1 dnsServerList: 192.168.10.5 192.168.33.9 192.168.33.1 domainName: marketing.example.org broadcastAddr: 192.168.128.0 end 18:52:22.384424 wormhole foo 590: 0.0.0.0.bootpc > foo.example.org.bootps: udp 548 IP: Src=0.0.0.0 (0.0.0.0) Dst=192.168.200.10 (foo) UDP: SrcPort=client DstPort=server Len=556 Cksum=7f63 BOOTP: Op=request htype=01 hlen=6 chaddr=000083a30393 hops=1 xid=0xb6b1d6fa secs=0 flags=0000 ciaddr=0.0.0.0 (0.0.0.0) yiaddr=0.0.0.0 (0.0.0.0) siaddr=0.0.0.0 (0.0.0.0) giaddr=192.168.128.1 (wormhole) sname= file= Options: starts with RFC1048 magic cookie, decoding (len=312): DHCPmessageType: DHCPREQUEST DHCPserverIdentifier: 192.168.200.10 (foo) DHCPrequestedIPaddress: 192.168.128.193 DHCPparamRequestList: subnetMask routerList dnsServerList domainName end pad (seen 286 times) 18:52:22.386815 foo wormhole 381: foo.example.org.bootps > wormhole.example.org.bootps: udp 339 (DF) IP: Src=192.168.200.10 (foo) Dst=192.168.128.1 (wormhole) UDP: SrcPort=server DstPort=server Len=347 Cksum=0925 BOOTP: Op=reply htype=01 hlen=6 chaddr=000083a30393 hops=0 xid=0xb6b1d6fa secs=0 flags=0000 ciaddr=0.0.0.0 (0.0.0.0) yiaddr=192.168.128.193 (hyperbole.marketing) siaddr=0.0.0.0 (0.0.0.0) giaddr=192.168.128.1 (wormhole) sname=foo.example.org file= Options: starts with RFC1048 magic cookie, decoding (len=103): DHCPmessageType: DHCPACK DHCPserverIdentifier: 192.168.200.10 (foo) DHCPipAddressLeaseTime: 86400 seconds (1 day) DHCPrenewalTimeValue: 43200 seconds (12 hours) DHCPrebindingTimeValue: 73440 seconds (20 hours, 24 minutes) subnetMask: 255.255.255.0 routerList: 192.168.128.1 dnsServerList: 192.168.10.5 192.168.33.9 192.168.33.1 domainName: marketing.example.org broadcastAddr: 192.168.128.0 NETBIOSnodeType: H-node NETBIOSnbnsServerList: 192.168.90.1 192.168.90.2 routerDiscovery: False end
If the DHCP Option Overload option is used to overload the file and/or sname fields with options, we will correctly decode the options in those fields, printing them after decoding the usual options field. However, by that time we’ve already attempted to decode and print the file and sname fields using their normal interpretation as nul-delimited ASCII strings. Therefore, when these fields are overloaded, their initial decode will appear as garbage; non-ASCII bytes may cause the output of these (and other lines) to be corrupted or even overwritten entirely.