Tuesday, December 21, 2004

Understanding Tcpdump's -d Option, Part 2

In September I referenced a post by libpcap guru Guy Harris explaining outfrom from Tcpdump's -d switch. After looking at the original 1992 BSD Packet Filter (.pdf) paper and the subsequent 1999 BPF+ (.ps) paper, I understand the syntax for the compiled packet-matching code generated by the tcpdump -d switch. For example:

fedorov:/usr/local/etc/nsm# tcpdump -n -i em1 -d tcp
tcpdump: WARNING: em1: no IPv4 address assigned
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 4
(002) ldb [20]
(003) jeq #0x6 jt 7 jf 8
(004) jeq #0x800 jt 5 jf 8
(005) ldb [23]
(006) jeq #0x6 jt 7 jf 8
(007) ret #96
(008) ret #0

Here is what each instruction means:

  • 000 says load (using 'ldh') the "half word" or two bytes starting at offset 12 of the Ethernet header. Since we begin counting at 0, bytes 0 to 5 are the destination MAC address and bytes 6 to 11 are the source MAC address. The name of the two bytes beginning at offset 12 differs according to the Ethernet format used.

  • 001 compares the two bytes loaded in 000 with the value 0x86dd. That is the Ethertype of IPv6. A comparison is made (using 'jeq'); if equality is true, jump ('jt') to instruction 002. If false, jump ('jf') to 004.

  • 002 loads the byte found at offset 20. If we are evaluating this instruction we are in an IPv6 header. Offset 20 holds the "next header" value.

  • 003 compares the byte loaded in 002 with the value 0x6. This is the IP protocol code for TCP. A comparison is made (using 'jeq'); if equality is true, jump ('jt') to instruction 007. If false, jump ('jf') to 008.

  • 004 compares the byte loaded in 000 with the value 0x800. That is the Ethertype of IPv4. A comparison is made (using 'jeq'); if equality is true, jump ('jt') to instruction 005. If false, jump ('jf') to 008.

  • 005 loads the byte found at offset 23. If we are evaluating this instruction we are in an IPv4 header. Offset 20 holds the "protocol" value for the protocol following the IP header.

  • 006 compares the byte loaded in 005 with the value 0x6. That is the protocol value for TCP. A comparison is made (using 'jeq'); if equality is true, jump ('jt') to instruction 007. If false, jump ('jf') to 008.

  • 007 is the equivalent of "TRUE", meaning that the indicated number of bytes (96) of packet data will be copied to the calling application (in this case, Tcpdump). You reach this point if the packet being inspected is TCP, either using IPv4 or IPv6.

  • 008 is the equivalent of "FALSE", meaning zero bytes of packet data will be copied to the application. You reach this point if the packet being inspected is not TCP.


Understanding this syntax is a way to troubleshoot BPFs that don't behave as you expect. You can run 'tcpdump -d' and inspect the code as explained above to see if it performs as you want.

For those of you wanting a definition of a packet filter, here is what I've come up with based on the original paper, The Packet Filter: An Efficient Mechanism for User-level Network Code (.pdf): a packet filter is a kernel-resident packet demultiplexer that provides a way for userland processes to tell the kernel what packets they want. For more detail, I recommend reading the three papers mentioned in this story. Guy Harris also posted a message to tcpdump-workers explaining BPF.

3 comments:

Serg said...

Thank Rishard. Is very in detail stated

dghnfgj said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.