This program is the workhorse for capturing network packets.

Note
If you need to capture traffic between two hosts that you don’t have easy ability to run software on but you have physical access, interject an old school hub between the hosts and put a 3rd host with decent Linux tools (running the capture) on that hub too.
Note
tcpdump pretty much always likes you more if your UID is 0 (i.e. use sudo and run as root). If you can’t do this, see trick above.

Useful Options

  • -U Flush on each packet instead of the arbitrary point when the buffer fills.

  • -w <file|-> Write packets to a file instead of parsing them and printing summary information about them. Use - for standard output.

  • -r <file>|- Read the packets from a file (maybe previously collected with -w) instead of a network source.

  • -i <interface> Specify the interface to listen to (eth0, etc.).

  • -s <val|0> Snapshot length is number of bytes per packet to look at. The default is 68 which may be enough to analyze the nature of traffic, but not enough to analyze the content of the packet. Set to 0 to capture the whole packet.

  • -tttt Print timestamp on each line of the dump.

Decoding Output

The general format of a tcp protocol line is:

src > dst: flags data-seqno ack window urgent options
Table 1. TCP Flags

U

URG

Urgent

.

ACK

Acknowledge (bit 11, don’t know its tcpdump code)

P

PUSH

R

RST

Reset

S

SYN

Synthesize (i.e. initiate)

F

FIN

E

ECN-Echo

Explicit Congestion Notification (RFC3168)

W

ECN CWR

Congestion Window Reduced

For the canonical reference see RFC793 - Transmission Control Protocol.

From the man page comes this helpful explanation.

Src and dst are the source and destination IP addresses and ports. Flags are some combination of S (SYN), F (FIN), P (PUSH), R (RST), U (URG), W (ECN CWR), E (ECN-Echo) or . (ACK), or none if no flags are set. Data-seqno describes the portion of sequence space covered by the data in this packet (see example below). Ack is sequence number of the next data expected the other direction on this connection. Window is the number of bytes of receive buffer space available the other direction on this connection. Urg indicates there is urgent data in the packet. Options are tcp options enclosed in angle brackets (e.g., <mss 1024>).

Useful Examples

Discovery

Before jumping into tcpdump, it can be helpful to check if the link is even properly up.

sudo ethtool eth0

Once the link is known to be active, one might wonder if the correct VLAN is active on the network.

sudo tcpdump -nn -v -i eth0 -s 1500 -c 1 'ether[20:2] == 0x2000'

Dumping to Files

By default the packets are summarized and cleaned up and sent to stdout, but you can specify a file name for the actual raw packets captured. This file can then be used by tcpdump in the place of actual interfaces to see the summarized and cleaned up output. Writing:

# tcpdump -w /thenameofthefilehere.dump

Reading (perhaps to have a quick look at it):

# tcpdump -r /thenameofthefilehere.dump | less

Snapshot Length

This controls the snapshot length which on Linux seems to be 90 bytes even though the man page says 68. This means that it only thinks about and writes the first 90 bytes of each packet. That’s fine if you just want to see packet headers and get a sense of what’s going on, but if you want to guarantee that a particular content is or isn’t (e.g. clear text passwords) being transmitted, you might want to capture all bytes. Set this to 0 for all bytes in the packet to be captured. Example:

# tcpdump -i eth0 -s 0

Focusing On The Problem

Let’s say you’re trying to troubleshoot some particular problem. If, for example, you want to scrutinize a web page request, you want to focus on port 80. Here’s how:

$ sudo tcpdump -i eth0 -s 0 tcp port 80

Sometimes there is a bunch of chatter from chattery processes and equipment (routers are filled with STP - spanning tree protocol, ARP - address resolution protocol, DTP - dynamic trunking protocol, etc). Perhaps the worst offender for traffic you do not wish to keep an eye on is the SSH traffic that you’re using to log into the machine in the first place. To specifically exclude such unwanted traffic from consideration use something like this:

tcpdump -i eth0 -s 0 not tcp port 22 and not tcp port 53 and not tcp port 123 and not arp and not stp

Analyzing A Specific Type Of Traffic

In this example I’m trying to capture all of the packets associated with a secure LDAP connection. By capturing all of the data that was passed back and forth to the LDAP server, I can search through it and check to see if any passwords went over in the clear. First to get the data use this command:

sudo tcpdump -i eth0 -s 0 -w ldapcapture.dump tcp port 636

Then run wireshark ldapcapture.dump to start up the graphical analysis program Wireshark. Go to Edit->Find Packet (Ctrl-F) and do a string search for the password you’re looking for (or hoping you won’t find).

Skip Resolving

To prevent hostname lookups use -n. What I find really annoying, however, are the often incorrect port/service lookups. To prevent this use -nn. This means that if you want hosts you get services too as far as I can tell.

Over SSH Without The SSH Traffic

Often you’ll need to monitor something on another computer. Obviously you monitoring is traffic and that is not interesting. Furthermore, it will become a feedback loop - the more traffic you monitor, the more traffic there is. To get around this problem you need to filter yourself out of what is being watched.

sudo /usr/sbin/tcpdump -i eth0 port not 22

Or if you want to watch the SSH traffic of other processes, you can try something like this.

sudo /usr/sbin/tcpdump -i eth0 port not 22 and host 192.168.0.88

Analyzing Bandwidth

Let’s say you want to watch a connection and see what activities cause a big spike in network traffic. Here’s what I used to do that.

# tcpdump -U -s 0 -i eth0 -w - host example.xed.ch  | ./bytecounter

The bytecounter program is a simple C program that spits out the current byte count as it is piped in:

bytecounter.c
#include  <stdio.h>
int main(int argc, char * argv[]) {
    int c, n=0;
    while ((c= getchar()) != EOF) {
        n++;
        if (n%100==0) {
            printf("\r<%d>",n);
            fflush(stdout);
        }
    }
}

Simple Text Data

To analyze the communication between bots and the simulation in the Simulated Car Racing competition, I needed to eavesdrop on simple data transmitted locally over UDP. Here’s what worked well:

sudo tcpdump -A -nn -i lo -s 0 udp port 3010  # All traffic
sudo tcpdump -A -nn -i lo -s 0 udp dst port 3010  # Driver Inputs
sudo tcpdump -A -nn -i lo -s 0 udp src port 3010  # Car Feedback

Finding MAC Addresses

This technique is helpful when you’re dealing with devices who only reveal their MAC addresses to the network. An example is a Sony PlayStation3. If you have MAC address filtering on your router, this is how you can find out what that MAC address is.

Another good case for this technique is if you just installed a new cluster and you plugged everything in. You’d like to give the machines a DHCP lease based on MAC address but you don’t know the MAC address. You could power up each machine with a monitor plugged in and write it down as it POSTs. But that’s lame. Better to just power it up fresh and let its natural factory-set desire to get it’s OS with PXE do the work. Basically you’ll want to use another working machine on that network and watch as you power up each node while tcpdump records the nodes' futile attempts to find out who it is.

# tcpdump -tttt -i eth1 port bootps or port bootpc | tee MACs.dump

The -tttt is needed to timestamp packets so you can match it with when you power on the machines. If you power on the machines quicker than its PXE cycle then there will be confusion unless precautions are taken. Turn them on at 15 second intervals using a watch for accuracy and look for that first packet at that interval.