ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


FreeBSD Basics

Capturing TCP Packets

03/21/2001

Also in FreeBSD Basics:

Fun with Xorg

Sharing Internet Connections

Building a Desktop Firewall

Using DesktopBSD

Using PC-BSD

In last week's article, we went through the various fields found in the Layer 3 and Layer 4 headers of an IP packet. While these fields may seem mind-numbingly technical at first, there is a good reason to be aware of the possible values for each field.

The values found in an IP packet's headers provide all of the information necessary to successfully send data from one computer running TCP/IP to another computer running TCP/IP; it doesn't matter if the two computers are cabled onto the same LAN or if they are physically separated by large geographic distances, the data will still arrive intact. Unfortunately, this robustness is a double-edged sword. If someone is so inclined, they can exploit the values found in an IP packet's headers in order to break into a computer running TCP/IP so they can steal or tamper with its data.

Your FreeBSD system provides many mechanisms to help protect your data from such exploits; these include ipfw, natd, ipfilter, and tcp wrappers. In order to successfully configure these mechanisms and ensure that they are blocking unwanted IP packets but are still allowing the delivery of wanted IP packets, you need to be aware of the differences in the values in the IP headers of a wanted and unwanted IP packet.

In today's article, I'd like to demonstrate the use of the tcpdump utility. This utility captures packets so you can examine the data and the headers within each packet. For this reason, you only run this utility on your own network; I repeat, don't run this utility on someone else's network unless they have given you explicit permission to do so.

When you run tcpdump, it will put your NIC into what is known as "promiscuous" mode. Normally, when a NIC sees a packet being transmitted on the media, it only monitors the signal long enough to determine if that packet is destined for its MAC address. If it is addressed to its MAC address, it will load the entire packet into RAM until the TCP/IP protocol has a chance to process the packet. If it is not addressed to its MAC address, it will simply ignore the rest of the packet and wait to monitor the next packet that is transmitted. When a NIC is placed into promiscuous mode, it will load and process all packets, regardless of whom the packets are destined for. This doesn't mean that the original recipient won't receive its packet; instead, it means that the packet will be received by both the intended recipient and the NIC that is running in promiscuous mode.

When you put a NIC into promiscuous mode on a FreeBSD system, the Berkeley Packet filter or bpf device is loaded. If you are running a recent version of FreeBSD, the bpf device should already be in your kernel. If it is not, this FAQ tells you what line you need to add to your kernel, and this link will give instructions on how to rebuild your kernel.

There is one last thing we need to be aware of before we run the tcpdump utility. Before an IP packet can be transmitted over a media, it must first be placed into a "frame"; this process is known as encapsulation. Encapsulation occurs at what is known as Layer 2, and it is the job of the interface that will transmit the packet to first encapsulate that packet into a frame. Just as there are many types of interfaces capable of transmitting packets, there are many types of frames. For example, a NIC may be cabled to an Ethernet network or to a Token Ring network; accordingly, there are Token Ring frames, which are different from Ethernet frames. Instead of a NIC, you may use a dial-up modem to connect to a network; in this case, your modem uses PPP, which in turn uses a protocol known as HDLC to create the PPP frames.

In my home network, I have a computer named "genisis" with an IP address of 10.0.0.1; it is connected using an Ethernet topology to a computer named "biko" whose IP address is 10.0.0.2. I'll use the tcpdump utility to capture the packets that are used to establish and disconnect a telnet session between these two computers.

Only the superuser can run the tcpdump utility; regular users will receive this warning message instead:

tcpdump
tcpdump: /dev/bpf0: Permission denied

On the computer "genisis," I'll become the superuser and start the tcpdump utility like so:

su
Password:

tcpdump -s 1518 -i ed0 -w dump
tcpdump: listening on ed0

A note on the switches I used: I specified the maximum number of bytes to capture per frame with -s 1518, which is the maximum size of an Ethernet frame. I specified which interface to monitor with -i ed0, and I told tcpdump to send its output to a file named dump instead of to my screen with -w dump.

If I now press ALT-F1, I'll also see the following console message:

Mar 4 10:25:24 genisis /kernel: ed0: promiscuous mode enabled

Now, at the computer named "biko," I'll telnet into the computer "genisis"; once I've successfully logged in, I'll immediately exit from the telnet connection:

telnet 10.0.0.1
Trying 10.0.0.1...
Connected to genisis.
Escape character is '^]'.

FreeBSD/i386 (istar.ca) (ttyp0)

login: genisis
Password:
Warning: your password expires on Thu Mar  8 17:31:47 2001
Last login: Sun Mar 4 10:23:04 from 127.0.0.1
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
	The Regents of the University of California.  All rights reserved.

FreeBSD 4.2-RELEASE (SOUND) #0 Tue Dec 12 20:01P29 EST 2000

			Welcome to FreeBSD 4.2!!!

You have mail.

Everybody is somebody else's weirdo.
	Dykstra

exit
logout
Connection closed by foreign host.

I then return to the keyboard on "genisis" and end the tcpdump like so:

^C
88 packets received by filter
0 packets dropped by kernel

And if I double-check the console:

Mar 4 10:25:44 genisis /kernel: ed0: promiscuous mode disabled

Since there aren't any other computers on this network, all of those 88 packets captured during that 20-second interval dealt with establishing and ending that telnet session.

There are several ways to analyze the output of my newly created "dump" file. I'll demonstrate several ways to view this file so you can see that different utilities vary in the amount of detail they show you regarding the contents of each captured frame.

Let's start by seeing what type of file tcpdump created:

file dump
dump: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 1518)

The dump file is not a text file, so we won't be using an editor or a pager to view its contents. We can use the tcpdump utility with the r switch to analyze the contents of this file; however, this output is not exactly novice friendly. I'll show some snipped output to demonstrate; at the very least, you may recognize some fields from last week's article:

tcpdump -r dump

<snipped to just show packets 10-12>

10:25:36.854420 10.0.0.2.blackjack > 10.0.0.1.telnet: S 3205630181:3205630181(0) win 16384 <mss 1460> (DF) [tos 0x10]
10:25:36.854653 10.0.0.1.telnet > 10.0.0.2.blackjack: S 1746119590:1746119590(0) ack 3205630182 win 17520 <mss 1460> (DF)
10:25:36.854996 10.0.0.2.blackjack > 10.0.0.1.telnet: . ack 1 win 17520 (DF) [tos 0x10]

The FreeBSD ports collection contains a utility known as tcpshow that can be used to display dump files created by tcpdump. Let's build this utility as the superuser and try it out:

cd /usr/ports/net/tcpshow
make install clean

Once your build is finished, you can exit the superuser account, as you don't need to be the superuser to use the tcpshow utility. Assuming you are in the same directory as the dump file to be analyzed, type:

tcpshow < dump |more

I won't analyze every packet with you, but I would like to look at some of the highlights of packets 10 to 12. You may remember from Understanding BSD Daemons (page 2) that TCP uses a three-way handshake before any data is actually transmitted. Let's take a look at packet number 10:

---------------------------------------------------------------
Packet 10
TIME: 10:25:36.854420 (6.232947)
LINK: 00:00:B4:3C:56:40 -> 00:50:BA:DE:36:33 type=IP
  IP: biko -> genisis hlen=20 TOS=10 dgramlen=44 id=0013
  MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=26A7
 TCP: port blackjack -> telnet seq=3205630181 ack=0000000000
      hlen=24 (data=0) UAPRSF=000010 wnd=16384 cksum=7814 urg=0
DATA: <No data>
---------------------------------------------------------------

Not counting the TIME heading, there are four parts to this packet. The LINK heading represents the Layer 2 frame. Normally, this is the portion of the packet that is monitored by the NIC; you'll note that it contains the MAC address of the sending computer and the MAC address of the destination computer. There are several different types of Ethernet frames; I can tell this is an Ethernet_II frame since it contains a "type" field.

The IP heading represents the Layer 3 IP header; all of the fields we mentioned last week are here except for the version field and the optional options field. You'll note that tcpshow resolved the IP addresses for genisis and biko for you; from the arrow, we can tell that this packet was sent by biko and is destined for genisis. Notice that the header length (hlen) has been interpreted as 20 bytes and the length of the entire IP packet (dgramlen) is 44 bytes. The "MF/DF" field represents the flags for may fragment and don't fragment; in this packet, the don't fragment flag has been turned on as it has been set to 1. Finally, the protocol (proto) indicates TCP; not surprisingly, the next column is labelled TCP, as it represents the Layer 4 TCP header.

In the TCP header, the source and destination port numbers have been resolved for you; not surprisingly, biko is trying to access the telnet port on the host genisis. This packet has a sequence number; since it is the first TCP packet, the acknowledgement has been set to 0 as there aren't any packets to acknowledge having been received yet. The TCP header length is 24 bytes; if you add these 24 bytes to the IP header length of 20 bytes, you'll receive the IP packet length of 44 bytes, so it looks like this packet arrived intact.

Now we get to the most interesting part of this IP packet. Note that the only TCP flag (UAPRSF) to be set to 1 is the S or the synchronize flag. This packet represents step one of the three-way handshake required to establish the TCP connection. Not surprisingly, there is no actual data being sent with this packet, and the DATA column contains no data. Remember, no data can be sent between applications that use TCP as their transport until the three-way handshake has been successful. Lastly, note that the Layer 4 header has indicated the window size biko is willing to use and has calculated the checksum on the contents of the IP packet.

Let's take a look at packet 11 to see how the computer genisis responded to this packet:

--------------------------------------------------------------
Packet 11
TIME: 10:25:36.854653 (0.000233)
LINK: 00:50:BA:DE:36:33 -> 00:00:B4:3C:56:40 type=IP
  IP: genisis -> biko hlen=20 TOS=00 dgramlen=44 id=9554
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=9175
 TCP: port telnet -> blackjack seq=1746119590 ack=3205630182
    hlen=24 (data=0) UAPRSF=010010 wnd=17520 cksum=5FD9 urg=0
DATA: <No data>
--------------------------------------------------------------

The TCP header contains the more interesting bits of genisis' response packet. Note that genisis responded with its own unique sequence number. Now compare the ack number in packet 11 with the original sequence number from packet 10; it is one more than the original sequence number of 3205630181. This indicates that the computer genisis successfully processed the IP packet containing that sequence number and is now ready to receive the packet that is next in sequence. When we look at biko's response to this IP packet, we'll expect to see an ack number that is one higher than this packet's sequence number of 1746119590.

Also notice that an additional flag has been set on this packet, since it is the second packet involved in the three-way handshake. You can always recognize this type of packet because both the A (acknowledgement) and S (synchronize) flags will be set. Again, this packet should not contain any actual data.

Now, let's see if packet number 12 contains the last step of the three-way handshake:

--------------------------------------------------------------
Packet 12
TIME: 10:25:36.854996 (0.000343)
LINK: 00:00:B4:3C:56:40 -> 00:50:BA:DE:36:33 type=IP
  IP: biko -> genisis hlen=20 TOS=10 dgramlen=40 id=0014
    MF/DF=0/1 frag=0 TTL=64 proto=TCP cksum=26AA
 TCP: port blackjack -> telnet seq=3205630182 ack=1746119591
    hlen=20 (data=0) UAPRSF=010000 wnd=17520 cksum=7796 urg=0
DATA: <No data>
--------------------------------------------------------------

It looks like we received the acknowledgement number that we were expecting; also note that biko responded to genisis' acknowledgement by sending the next packet in its sequence. This is the last packet involved in the three-way handshake; we can recognize it as such because the only flag that has been set is the A (acknowledgement) flag and there is no data contained within this IP packet.

Before we leave these three packets involved in the three-way handshake, I'd like to show you how the Ethereal utility views these same three packets. We've already covered how to build and use Ethereal in Using Ethereal. If I open up Ethereal on my FreeBSD system, I can go to the File Menu and open up the dump file to view its contents. Once I've opened up this file, I can save it to a text file by again going to the File Menu and choosing Print. When the print screen is displayed, I choose to print to a file; the resulting file can then be viewed using an editor or a pager. On my system, I used this method to create a file called etherdump:

more etherdump

<snip to just show packets 10-12>

Frame 10 (60 on wire, 60 captured)
Arrival Time: Mar 4, 2001 10:25:36.8544
Time delta from previous packet: 6.232947 seconds
Frame Number: 10
Packet Length: 60 bytes
Capture Length: 60 bytes
Ethernet II
Destination: 00:50:ba:de:36:33 (genisis)
Source: 00:00:b4:3c:56:40 (biko)
Type: IP (0x0800)
Trailer: 1011
Internet Protocol
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x10 (DSCP 0x04: Unknown DSCP; ECN: 0x00)
0001 00.. = Differentiated Services Codepoint: Unknown (0x04)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 44
Identification: 0x0013
Flags: 0x04
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: TCP (0x06)
Header checksum: 0x26a7 (correct)
Source: biko (10.0.0.2)
Destination: genisis (10.0.0.1)
Transmission Control Protocol, Src Port: blackjack (1025), Dst Port: telnet (23), Seq: 3205630181, Ack: 0
Source port: blackjack (1025)
Destination port: telnet (23)
Sequence number: 3205630181
Header length: 24 bytes
Flags: 0x0002 (SYN)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...0 .... = Acknowledgment: Not set
.... 0... = Push: Not set
.... .0.. = Reset: Not set
.... ..1. = Syn: Set
.... ...0 = Fin: Not set
Window size: 16384
Checksum: 0x7814
Options: (4 bytes)
Maximum segment size: 1460 bytes

Frame 11 (58 on wire, 58 captured)
Arrival Time: Mar 4, 2001 10:25:36.8546
Time delta from previous packet: 0.000233 seconds
Frame Number: 11
Packet Length: 58 bytes
Capture Length: 58 bytes
Ethernet II
Destination: 00:00:b4:3c:56:40 (biko)
Source: 00:50:ba:de:36:33 (genisis)
Type: IP (0x0800)
Internet Protocol
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
0000 00.. = Differentiated Services Codepoint: Default (0x00)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 44
Identification: 0x9554
Flags: 0x04
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: TCP (0x06)
Header checksum: 0x9175 (correct)
Source: genisis (10.0.0.1)
Destination: biko (10.0.0.2)
Transmission Control Protocol, Src Port: telnet (23), Dst Port: blackjack (1025), Seq: 1746119590, Ack: 3205630182
Source port: telnet (23)
Destination port: blackjack (1025)
Sequence number: 1746119590
Acknowledgement number: 3205630182
Header length: 24 bytes
Flags: 0x0012 (SYN, ACK)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...1 .... = Acknowledgment: Set
.... 0... = Push: Not set
.... .0.. = Reset: Not set
.... ..1. = Syn: Set
.... ...0 = Fin: Not set
Window size: 17520
Checksum: 0x5fd9
Options: (4 bytes)
Maximum segment size: 1460 bytes

Frame 12 (60 on wire, 60 captured)
Arrival Time: Mar 4, 2001 10:25:36.8549
Time delta from previous packet: 0.000343 seconds
Frame Number: 12
Packet Length: 60 bytes
Capture Length: 60 bytes
Ethernet II
Destination: 00:50:ba:de:36:33 (genisis)
Source: 00:00:b4:3c:56:40 (biko)
Type: IP (0x0800)
Trailer: 0C0D0E0F1011
Internet Protocol
Version: 4
Header length: 20 bytes
Differentiated Services Field: 0x10 (DSCP 0x04: Unknown DSCP; ECN: 0x00)
0001 00.. = Differentiated Services Codepoint: Unknown (0x04)
.... ..0. = ECN-Capable Transport (ECT): 0
.... ...0 = ECN-CE: 0
Total Length: 40
Identification: 0x0014
Flags: 0x04
.1.. = Don't fragment: Set
..0. = More fragments: Not set
Fragment offset: 0
Time to live: 64
Protocol: TCP (0x06) Header checksum: 0x26aa (correct)
Source: biko (10.0.0.2)
Destination: genisis (10.0.0.1)
Transmission Control Protocol, Src Port: blackjack (1025), Dst Port: telnet (23), Seq: 3205630182, Ack: 1746119591
Source port: blackjack (1025)
Destination port: telnet (23)
Sequence number: 3205630182
Acknowledgement number: 1746119591
Header length: 20 bytes Flags: 0x0010 (ACK)
0... .... = Congestion Window Reduced (CWR): Not set
.0.. .... = ECN-Echo: Not set
..0. .... = Urgent: Not set
...1 .... = Acknowledgment: Set
.... 0... = Push: Not set
.... .0.. = Reset: Not set
.... ..0. = Syn: Not set
.... ...0 = Fin: Not set
Window size: 17520
Checksum: 0x7796

You'll notice that Ethereal shows every field in great detail. It's interesting to see how one dump file can be interpreted in varying degrees by three different utilities. We'll continue our analysis of this dump file in next week's article.

Dru Lavigne is a network and systems administrator, IT instructor, author and international speaker. She has over a decade of experience administering and teaching Netware, Microsoft, Cisco, Checkpoint, SCO, Solaris, Linux, and BSD systems. A prolific author, she pens the popular FreeBSD Basics column for O'Reilly and is author of BSD Hacks and The Best of FreeBSD Basics.


Read more FreeBSD Basics columns.

Return to the BSD DevCenter.

Copyright © 2009 O'Reilly Media, Inc.