Table of Contents

Name

bootpdc - decode BootP and DHCP packets from tcpdump

Syntax

bootpdc [ -D stripdomain ] [ -h ] [ -i ] [ -n ] [ -s skipbytes ] [ -u ] [ -v ]

Description

The bootpdc perl script decodes BootP and DHCP packets from tcpdump(8) hex dump output.

Availability

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).

Options

-D stripdomain
Specify a DNS domain suffix to strip from hostnames before displaying them. This defaults to the name of the host on which bootpdc is run, with the first component removed. When address lookups have been suppressed with the -n option, the stripdomain is not used.
-h
Display a brief usage summary, then exit.
-i
Assume each packet lacks an IP header. The IP header fields we print are assumed to contain zeroes.
-n
Specifying this option suppresses address lookups, and a more compact form is used to display the output. Otherwise, address lookups default to enabled; IP addresses appearing in the IP and BootP or DHCP headers are looked up, as are IP addresses appearing in selected BootP and DHCP options. The hostname found, if any, is printed in parentheses, after the IP address. (If no hostname is found, the value in the parentheses is simply the IP address again.) If a hostname ends with stripdomain, that text is removed from the name before it is printed.
-s skipbytes
Skip over the first skipbytes bytes in each packet. This is useful if the hex dump produced by tcpdump(8) contains any bytes before the start of the packet’s IP header. For example, packets captured on a FDDI link will begin with 8 extra bytes of data before the IP packet begins; packets containing 802.1q tags contain an extra 4 bytes of data.
-u
Assume each packet lacks a UDP header. The UDP header fields we print are assumed to contain zeroes.
-v
Display the program’s version number, then exit.

Examples

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.

Sample 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

Author

The program was written by Chris Tengi of the Network Systems Group at Princeton University’s Office of Computing and Information Technology. It was enhanced by Irwin Tillman of the same organization.

Bugs

The program does not attempt to decode a packet until it is certain it has read the entire packet’s hex dump. The end of the packet is detected by looking for the next packet’s "tcpdump packet header" line, a short hex dump line, or EOF. As a result, if the hex dump of a packet we are reading from STDIN ends in a full line (a multiple of 16 bytes), we will not print the packet until the next packet arrives. If you kill bootpdc before that happens, that packet will never be printed. This can be avoided by reading the packet dump from a file and allowing the program run to completion.

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.

See Also

perl(1)
available from http://www.perl.org
tcpdump(8)
available from http://www.tcpdump.org


Table of Contents