Tcpdump Primer
Mini-primer on tcpdump
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! :)
General syntax
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'
.
A word about un-specified interface names
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.
Simple packet dumping
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.
Packet dumping with simple filter expressions
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'
Gotchas
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
A little complex filter expressions (but not that complex :)
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'
Save/Read packet captures
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 mighty-little BPF monster
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.
More filter expressions :)
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'
Extracted and adapted from the tcpdump
man page
The 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:
TCP conversation
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'
Lets do some webops yo!
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)'
More goodies
To print IP packets longer than 576 bytes sent through gateway snup:
$ tcpdump -n -i eth0 'gateway snup and ip[2:2] > 576'
Let there be broad/multi-casts
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'
And let there be ICMP echo req/reply gods
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'
If you like the post, feel free to support me via BuyMeACoffee or Patreon.
Thank you.
Leave a Comment