You are here and that’s great! Let’s learn to dump ‘em packets ;)
Here are some small tcpdump
tricks that I thought could be helpful to others as well.
It should work on MacOS, Linux, and any number of *BSDs. The $
denotes the shell prompt.
The last time I checked Windows (Linux subsystem), it did not support tcpdump
. Call
your Microsoft rep to get it on Linux subsystem! :)
To keep simple things simple, i’ll begin with the format of tcpdump
$ tcpdump [options] [expression]
Options are things like e.g. -i any -nn -A -v
.
Expressions are things like e.g. dst port 9999
and should be single quoted e.g. 'host www.example.com'
.
If the interface option is left unspecified (-i
), then based on the implementation,
tcpdump
will choose the default interface available. On Linux and FreeBSD this is usually
the first available network interface such as eth0
, re0
. On macOS, this is a pseudo
interface PKTAP
which captures on all available interfaces.
To trace packets on network interface eth0
and not perform any DNS name resolution -n
and give super brief info of the packet traces -q
$ tcpdump -i eth0 -nq
I recommend using the -n
option for packet tracing because the packet dumps are much cleaner
as there would be no name resolution and thus no DNS traffic to pollute the capture.
To filter on host www.example.com on all network interface.
$ tcpdump -n 'host www.example.com'
The name resolution for www.example.com
happens once when the tcpdump
starts. If your
DNS resource record has a short TTL and the answer value changes often whilst debugging,
its important to keep this in mind.
To specify expression to filter on destination host 1.2.3.4
matching all protocols.
$ tcpdump -n 'dst host 1.2.3.4'
One of the important thing to consider is positioning of options.
On some tcpdump
implementations, the network interface and the other options come
before the expression. For e.g.,
# FreeBSD
$ tcpdump 'dst host 1.2.3.4' -i em0 -nq
tcpdump: syntax error
$ tcpdump -i em0 -nq 'dst host 1.2.3.4'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on em0, link-type EN10MB (Ethernet), capture size 65535 bytes
#MacOS
$ tcpdump 'dst host 1.2.3.4' -i en0 -nq
12:48:31.736991 IP 172.16.10.5 > 1.2.3.4: ICMP echo request, id 59336, seq 0, length 64
[...]
Some tcpdump
implementations support listening on all interfaces via -i any
. The default tcpdump
implementations on macOS and Linux support this feature
#FreeBSD
$ tcpdump -n -i any 'dst host 1.2.3.4'
tcpdump: any: No such device exists
(BIOCSETIF failed: Device not configured)
#MacOS
$ tcpdump -i any -n 'dst host 1.2.3.4' -nq (macOS)
tcpdump: data link type PKTAP
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
To filter on source port 9999, protocol tcp
on network interface eth0
$ tcpdump -n -i eth0 'tcp and src port 9999'
To filter on destination port 9999, protocol udp on netif eth0
$ tcpdump -n -i eth0 'udp and dst port 9999'
To dump tcp
traffic on port 8080 using -A
which prints the packets’ content in ASCII
$ tcpdump -n -i eth0 -A 'tcp and dst port 8080'
To write out icmp
packet traces to a pcap
formatted file (it can get quite large)
$ tcpdump -w /tmp/icmp-trace.pcap -n -i eth0 icmp
To read in pcap
packet traces (alternatively, tshark
or wireshark
is great too :)
$ tcpdump -r /tmp/icmp-trace.pcap
The tcpdump
expressions can be viewed as a BPF instructions using the -d
option
$ tcpdump -d 'dst host 8.8.4.4'
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 4
(002) ld [30]
(003) jeq #0x8080404 jt 8 jf 9
(004) jeq #0x806 jt 6 jf 5
(005) jeq #0x8035 jt 6 jf 9
(006) ld [38]
(007) jeq #0x8080404 jt 8 jf 9
(008) ret #65535
(009) ret #0
Each line is a BPF instruction that can be executed within a BPF VM.
From BPF Performance Tools: Linux System and Application Observability:
BPF works in an interesting way: A filter expression is defined by the end user using an instruction set for a BPF virtual machine (sometimes called the BPF bytecode) and then passed to the kernel for execution by an interpreter. This allows filtering to occur in the kernel level without costly copies of each packet going to the user-level processes, improving the performance of packet filtering, as used by tcpdump(8). It also provides safety, as filters from user space can be verified as being safe before execution. Given that early packet filtering had to occur in kernel space, safety was a hard requirement.
To trace all udp packets in a destination port range 50000-65535 (inclusive)
$ tcpdump -n -i eth0 'udp and dst portrange 50000-65535'
To trace all udp packets not going to host 1.2.3.4
or 5.6.7.8
on network interface eth0
$ tcpdump -n -i eth0 'udp and not dst host (1.2.3.4 or 5.6.7.8)'
To trace all IPv6 packets on network interface eth0
$ tcpdump -n -i eth0 ip6
To trace all IPv4 packets on network interface eth0
for network 17.0.0.0/8
(dst/src)
$ tcpdump -n -i eth0 'net 17.0.0.0/8'
To print all tcp
packets with just SYN
flag set
$ tcpdump -n -i eth0 'tcp[tcpflags] & tcp-syn == 2'
To print the first hundred tcp
packets to destination port 80 on eth0
$ tcpdump -n -i eth0 -c 100 'tcp and dst port 80'
Capture packets indefinitely and rotate every 10 seconds
$ tcpdump -i eth0 -G 10 -w dump-%S.pcap 'dst port 80'
tcpdump
man pageThe tcpdump
man page is a gold mine. I have spent a long time reading it and every single time I find something new in it.
Following are some of the handy ones:
To print the start and end packets (the SYN and FIN packets) of each TCP conversation that involves a non-local host.
$ tcpdump -n -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net 127.0.0.1'
To print all IPv4 HTTP packets to and from port 80, i.e. print only packets that contain data, not, for example, SYN and FIN packets and ACK-only packets.
$ tcpdump -n -i eth0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
To print IP packets longer than 576 bytes sent through gateway snup:
$ tcpdump -n -i eth0 'gateway snup and ip[2:2] > 576'
To print IP broadcast or multi-cast packets that were not sent via Ethernet broadcast or multicast:
$ tcpdump -n -i eth0 'ether[0] & 1 = 0 and ip[16] >= 224'
To print all ICMP packets that are not an ICMP echo request/reply (e.g. not ping packets):
$ tcpdump -n -i eth0 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'