8.4 Using Tcpdump
Details on using tcpdump are presented in the following sections.
8.4.1 Running as Root
Ordinarily, a network interface is not configured to capture every packet it sees on the network. It collects only packets that are addressed to that particular interface, or broadcast packets that are addressed to every interface.1 In order to capture packets that are not addressed to the interface itself, tcpdump must put the interface into promiscuous mode. In promiscuous mode, all packets are collected regardless of their layer 2 destination address. On Unix-based operating systems, root privileges are required to put an interface into promiscuous mode; therefore, you will typically want to run tcpdump as root.2 Occasionally, you may come across a version of tcpdump that requires a special flag to be set in order to enable promiscuous mode, but typically, tcpdump will attempt to enable it by default.
Do note that in certain extreme circumstances, enabling promiscuous mode can lead to degraded performance of the operating system. For example, a system with high-speed interfaces, or simply a very large number of interfaces in promiscuous mode, will place a heavy burden on the kernel. Under more typical conditions, such as a machine with one or two interfaces running 10 or 100Mb/s Ethernet, there should be little problem, however.
8.4.2 Command Line Options
Tcpdump has a number of command line options available, all of which are documented in the tcpdump man page. Some of the most common options are listed here.
As you experiment with the options below, note that your network topology may not allow you to view all of the traffic on your network. The reasons for this and possible solutions to this problem are described in detail in Section 8.4.7.
-n
By default, tcpdump performs a DNS query to look up the hostname associated with an IP address and uses the hostname in the output. For example:
12:54:07.594427 server.example.com.telnet > client.example.com... 12:54:07.686828 client.example.com.37580 > server.example.com...
Here, tcpdump read the source and destination IP addresses from the packet, looked up the hostnames associated with those addresses, and printed those names instead of the numeric IP addresses.
Though this is a convenient feature, it can have a serious impact on the performance of the program. If many different hosts are present, some with name servers on distant networks, tcpdump may experience delays while waiting for DNS queries to complete. Allowing tcpdump to look up hostnames is perfectly acceptable for short-term viewing when network conditions are favorable. But for long-term packet monitoring, or if you suspect tcpdump will have trouble performing DNS queries, it is preferable to disable hostname lookups. This is the function of the -n flag, as you can see below:
Linux# tcpdump -n 13:00:46.335152 10.18.0.100.23 > 10.56.0.43.37580: P 1:29(28) ... 13:00:46.435029 10.56.0.43.37580 > 10.18.0.100.23: . ack 29 ...
Also notice that instead of printing "telnet" as the port on the server, tcpdump used the numeric port number 23.
-s snaplen
One counterintuitive default of tcpdump is that the amount of data captured is only the first 68 bytes of the packet. This is usually enough to grab the protocol headers, but it is not the entire packet. The snaplen option allows you to set the number of bytes tcpdump will grab from the packet. If you wish to view the entire packet (as with the -x option) or if you wish for the verbose options (-v and -vv) to have access to all of the data present in the packet, specify a snaplen size of 1500:
Linux# tcpdump -s 1500
We choose 1500 because it is the maximum size of the payload of an Ethernet frame. If we were using tcpdump on a network that is not Ethernet, we might need to set the snaplen size to an even larger value.
-x
The -x option instructs tcpdump to print the packet contents, which it does in hexadecimal notation:
13:11:44.459933 client.example.com.48630 > server.example.com... 4510 0028 7b8e 4000 fc06 dcc4 1265 0192 0a12 0064 bdf6 0017 b6e8 5b3c 2fdc c055 5010 210c a7f7 0000 0000 0000 0000
Note that if the snaplen, as described above, is smaller than the size of a packet, only the snaplen number of bytes will be printed in the output.
Later we will use a program to convert the hexadecimal output into a more readable format.
-v and -vv
As the previous examples have demonstrated, tcpdump understands some of the protocol information in the data it captures. In fact, it actually understands quite a bit more protocol information than it prints by default. If you add the -v option to the command line, tcpdump will print more information than usual about the protocols present, and if you instead use the -vv option, it will print even more detailed information. For example:
Linux# tcpdump -vv ...client.example.com.53454 > dns.example.com.domain: 15279 (38... ...dns.example.com.domain > client.example.com.53454: 15279* q:...
With the -vv option present, tcpdump now prints information about a DNS query being performed, including the name being looked up (server.example.com).
-q
The opposite of the -v and -vv options is the -q option, which instructs tcpdump to be more quiet; that is, to print less information on each line.
-i interface
If your system has more than one interface, you can specify which one tcpdump should listen on with the -i option, as in:
Linux# tcpdump -i eth1
If you do not specify an interface, tcpdump will choose the lowest numbered interface that is up and is not the loopback interface.
-e
If the -e option is supplied on the command line, tcpdump will include the Ethernet (or other layer 2) header information in the output:
Linux# tcpdump -e 23:48:28.556873 0:3:ba:9:1f:36 0:5:dc:95:d0:a ip 76: client.exa...
The first hardware address (0:3:ba:9:1f:36) is the source Ethernet address, and the second is the destination address. The text "ip" indicates that the protocol is IP, and 76 is the length of the payload data.
-l
In some circumstances, you may wish to force tcpdump output to be line buffered. For example, if you are sending the output to a file but wish to view the results at the same time, run tcpdump as:
Linux# tcpdump -l | tee tcpdump.out
This will allow packets to be displayed as soon as tcpdump detects them, instead of waiting for a large amount of data to be present.
-w file and -r
In the preceding example, the output from tcpdump is stored directly in a file. While this is a reasonable way to capture and store data for later analysis, it is not very efficient and it can be difficult to work with because the format is not conducive to automated processing.
As an alternative, you can use the -w option to store packet data in a binary format:
Linux# tcpdump -w tcpdump.data
Tcpdump can later play back the data exactly as if it were being read from the wire, using the -r option:
Linux# tcpdump -r tcpdump.data 11:51:46.637811 10.25.71.241.80 > 10.18.0.100.61965: . ack 415... 11:51:46.643077 10.25.71.241.80 > 10.18.0.100.61966: . ack 415...
When you replay the data, you can change the options to tcpdump in order to view the data differently. There are also a number of programs available that can use the tcpdump data file format to process packets for other kinds of analysis.
8.4.3 Filters
Everything on the tcpdump command line following the above options is an expression used to dictate exactly which packets should be captured and which should be ignored. Typically, you are interested in only a small number of the packets on the network. The filtering expression allows you to ignore anything you do not need to examine. A simple example is the best way to begin understanding how filters work:
Linux# tcpdump src client.example.com and dst server.example.com
In this example, tcpdump will print only those packets whose source address is that of client.example.com and whose destination address is that of server.example.com. The keywords src and dst are known as primitives. Another primitive is host, which specifies all traffic to or from a named host:
Linux# tcpdump host client.example.com
Here we view all traffic sent to or received from client.example.com. Some other useful tcpdump primitives are listed in .
Figure 8.2. Some Tcpdump Packet Matching Primitives.
Primitive |
Function |
---|---|
src addr |
Source IP address matches addr |
dst addr |
Destination IP address matches addr |
host addr |
Source or destination IP address matches addr |
ether <src/dst/host> addr |
Ethernet address matches addr |
[src/dst] net net |
IP address is on network net |
net net |
Source or destination IP addr is on network net |
net net mask mask |
As above but network range defined by mask |
[src/dst] port port |
Port is port |
port port |
Source or destination port is port |
less octets |
Packet size is less than or equal to octets |
greater octets |
Packet size is greater than or equal to octets |
icmp |
Packet is an ICMP packet |
tcp |
Packet is a TCP packet |
udp |
Packet is a UDP packet |
ip |
Packet is an IP packet |
arp |
Packet is an ARP packet |
broadcast |
Packet is addressed to a broadcast address |
Primitives can be combined with the boolean operators and, or and not, along with parentheses, to construct specialized filters. For example:
Linux# tcpdump "host client and not ( port telnet or port domain )"
will capture all packets sent to or from the host client.example.com but not those whose destination or source port is either telnet (port 25) or domain (port 53). We add the double quotes so that the parentheses will be passed directly to tcpdump instead of being interpreted by the shell.
8.4.4 Command Line Examples
Using the above knowledge, we can put together a number of useful tcpdump command lines. To display quick information on all traffic to or from the host broken.example.com:
Linux# tcpdump -q host broken.example.com
To view the entire packet for all bootp traffic:
Linux# tcpdump -xs 1500 port bootps or port bootpc
To leave tcpdump running for a long time, gathering data about ssh connections to client.example.com:
Linux# tcpdump -nxs 1500 -w tcpdump.data port 22 and host client
8.4.5 Understanding the Output
Some of the information printed by tcpdump is a bit cryptic, especially since the format is different for each protocol. The tcpdump man page lists the output format for each protocol, and the common ones are presented here as well.
UDP Output Format
In the case of a simple UDP packet, the output format is:
time source > destination: udp datalen
So in the following line:
13:45:20.364930 10.7.15.82.2103 > 10.18.0.100.47028: udp 342 (DF)
we see that 10.7.15.82 on port 2103 sent 342 bytes to 10.18.0.100 on port 47028. The 342 bytes of data refers to the data portion of the UDP packet. The (DF) at the end indicates that the IP "don't fragment" bit is set.
TCP Output Format
For TCP packets, the output format is:
time source > dest flags sequence [ack ack] win window [urgent] [options]
For example:
...10.7.21.70.80 > 10.18.0.100.34639: P 1461:2921(1460) ack 973 win 63268 (DF)
indicates that 10.7.21.70 on port 80 sent data to 10.18.0.100 on port 34639. The TCP PUSH flag was set, indicated by the "P." The string 1461:2921(1460) gives us information about the TCP sequence number. It indicates that the packet is starting 1461 octets (eight-bit bytes) from the first sequence number tcpdump observed. This is called a relative sequence number. If you would rather view the actual sequence number used in the TCP packet, you can supply the -S argument on the tcpdump command line. The number after the colon is one more than the sequence number of the last byte in the packet, though this number is not really in the TCP header. The number in parentheses, 1460, is the length of the data sent.
The text "ack 973" indicates a TCP ACK was present and that the next expected sequence number in the other direction (data sent from 10.18.0.100 to 10.7.21.70) will be 973. This is also a relative sequence number if the -S flag is not used.
Finally, "win 63268" indicates that 10.7.21.70 will accept a TCP window size of 63268 octets. As in the UDP example, the (DF) represents the presence of the IP don't fragment option. In this example, the urgent TCP flag is not used and there are no extra options to report.
8.4.6 Viewing Packet Data
As described earlier, the -x option, when used in conjunction with the -s 1500 setting, will instruct tcpdump to print the entire contents of a packet in hexadecimal. Because the hexadecimal output can be difficult to read, we can use an additional program to print character representations of each byte as well. Save the following into a file called tpcdump-data-filter.pl:
#!/usr/bin/perl # This code is hereby placed in the public domain by its author, # Marc Horowitz . If you use it, it would be polite if you left # my name on it, but there's no requirement. $| = 1; while(<>) { if (/^\s/) { ($nospc = $_) =~ s/\s+//g; ($spc = $nospc) =~ s/(....)/$1 /g; ($bin = pack("H*",$nospc)) =~ tr/\000-\037\177-\377/./; printf("%16s%-45s%s\n","",$spc,$bin); } else { print; } }
and give it execute permissions:
Linux# chmod u+x tcpdump-data-filter.pl
We can now pipe the tcpdump output through this program:
Linux# tcpdump -xls 1500 | ./tcpdump-data-filter.pl tcpdump: listening on eth0 20:11:35.686269 host.example.com.53454 > c.gtld-servers.net.dom... 4500 003d 9f2a 4000 ff11 add6 0a12 0064 E..=.*@........d c01a 5c1e d0ce 0035 0029 3674 8930 0000 ..\....5.)6t.0.. 0001 0000 0000 0000 0364 6e73 0765 7861 .........dns.exa 6d70 6c65 0363 6f6d 0000 0100 01 mple.com..... 20:11:35.740531 host.example.com.34243 > web.example.com.80: P ... 4500 03f4 a6f9 4000 4006 5641 0a12 0064 E.....@.@.VA...d 0a07 154d 85c3 0050 f0b0 2504 41bc a72f ...M...P..%.A../ 5018 60f4 3db0 0000 4745 5420 2f20 4854 P.'.=...GET / HT 5450 2f31 2e30 0d0a 486f 7374 3a20 7765 TP/1.0..Host: we ...
The character representation does not add much meaning to the packet header data, but it makes it much easier to understand the the protocol data. In the first packet, we can see host.example.com perform a DNS query for dns.example.com. In the second packet, we can see host.example.com performing a "GET / HTTP/1.0" in an HTTP transaction with web.example.com.
8.4.7 Seeing It All
Before the arrival of the modern network switch, it was easy to view all of the traffic on an Ethernet network. Every packet on the network arrived at every network card, and as long as the card was in promiscuous mode, the operating system could capture every packet. On a switched network, this is no longer the case. Traffic patterns are optimized so that a link carries only the traffic destined for hosts connected to that link.3 On a fully switched network this means tcpdump will be able to view only:
-
Traffic destined for your host
-
Traffic originating from your host
-
Broadcast traffic
-
Small random amounts of traffic for other hosts (see the footnote)
This is a real setback if the point of using tcpdump is to help us monitor the packets sent by some other host. There are two ways to solve this problem. One is to connect the host in question and your monitoring host to a true repeater, as in Figure 8.3. This is a simple and effective solution if you can easily travel to the machine and attach another host appropriately. If not, an alternative solution is to configure your network hardware to forward the packets you are interested in to a port you can monitor them from. Not all network hardware is capable of doing this, however.
Figure 8.3. Using a Repeater to Monitor Traffic.
Monitoring on Cisco CatOS Devices
Cisco switches are capable of sending packets to additional ports for monitoring, though the syntax depends on which generation of switch software you are using. On the older CatOS systems, use the "set span" command (SPAN stands for switch port analyzer). From enable mode:
switch15> (enable) set span 2/49 2/9 both inpkts enable
In this example, all the traffic that would ordinarily be transmitted to port 2/49 or received from port 2/49 will also be sent to port 2/9. Now a host attached to port 2/9 can run tcpdump and monitor any packets that would be sent or received by a host attached to port 2/49 (see Figure 8.4).
Figure 8.4. Forwarding Traffic to an Additional Port for Monitoring.
On this particular switch, port 2/49 happens to be the uplink to the rest of the network, so monitoring its traffic allows us to monitor traffic of every device on the switch. Use caution when redirecting a large amount of traffic like this; if the destination link is not as large as the source link, you may flood the monitoring host.
The keyword both in the example above indicates that both transmitted and received traffic should be sent. The inpkts enable option is important; it tells the switch that it should process incoming packets to port 2/9 normally. The default behavior for a port with SPAN enabled is to ignore incoming packets. If you do not care about having your monitoring host able to talk to the rest of the network, you may leave the inpkts option out, but if you do wish to have the monitoring host accessible, be sure to include it. Note that some early versions of the CatOS software do not have the ability to use the inpkts enable option.
The set span syntax also allows you to specify multiple source ports and ranges of ports. For example, 2/1-8 would represent port 2/1 through port 2/8. Using 2/1-8,2/10-50 would mean ports 2/1 through 2/8 and 2/10 through 2/50.
You can view the status of SPAN sessions with the show span command:
switch15> (enable) show span Status : enabled Admin Source : Port 2/49 Oper Source : Port 2/49 Destination : Port 2/9 Direction : transmit/receive Incoming Packets: enabled
Monitoring on Cisco IOS Devices
On Cisco devices running IOS (either switches or routers), port monitoring is configured with monitoring sessions. From configure mode:
switch18(config)#monitor session 1 source interface Gi1/1 switch18(config)#monitor session 1 destination interface Gi1/2
This would direct packets on port Gi1/1 to be copied to port Gi1/2. Remember to issue a write mem so that the configuration will still be in effect the next time the device is rebooted.
You can view monitoring sessions with the show monitor command:
switch18>show monitor Session 1 --------- Source Ports: RX Only: None TX Only: None Both: Gi1/1 Source VLANs: RX Only: None TX Only: None Both: None Destination Ports: Gi1/2 Filter VLANs: None