tcpdump: An Incomplete Guide
- 1 Basic options
- 2 Matching expressions
- 3 Advanced matching (header fields/bits matching)
- 4 Misc
- Reference
tcpdump
is a network tool to dump traffic on the network.
This post servers as a guide to some frequently used commands. For a complete guide,
please refer to the man page, or man tcpdump
on a linux machine.
1 Basic options
A help summary:
tcpdump [ -AbdDefhHIJKlLnNOpqStuUvxX# ] [ -B buffer_size ]
[ -c count ]
[ -C file_size ] [ -G rotate_seconds ] [ -F file ]
[ -i interface ] [ -j tstamp_type ] [ -m module ] [ -M secret ]
[ --number ] [ -Q in|out|inout ]
[ -r file ] [ -V file ] [ -s snaplen ] [ -T type ] [ -w file ]
[ -W filecount ]
[ -E spi@ipaddr algo:secret,... ]
[ -y datalinktype ] [ -z postrotate-command ] [ -Z user ]
[ --time-stamp-precision=tstamp_precision ]
[ --immediate-mode ] [ --version ]
[ expression ]
Running tcpdump
needs root privilege, so prefix sudo
before all commands in
this post if you are not root user.
1.1 Capture options
The simplest way to capture traffic on a host is to specify a device with
-i
option, the output may look like this:
$ sudo tcpdump -i eth0 # use CTL-C to terminate it
18:10:14.578057 IP 192.168.1.3.ssh > 192.168.1.124.53519: Flags [P.], seq 2350:2350, ack 166, win 198, length 240
18:10:14.578775 IP 192.168.1.124.53519 > 192.168.1.3.ssh: Flags [.], ack 240, win 252, length 0
18:10:14.634826 ARP, Request who-has 192.168.1.68 tell 192.168.1.81, length 46
18:10:14.670785 ARP, Request who-has 192.168.1.146 tell 192.168.1.81, length 46
^C
4 packets captured
39 packets received by filter
0 packets dropped by kernel
One tcpdump
process could only capture one device, to capture multiple devices, e.g. both eth0
and eth1
, you have to launch two processes:
$ tcpdump -i eth0 [OPTIONS]
$ tcpdump -i eth1 [OPTIONS]
1.2 Output options
This section describes the options for displaying packets info on standard output.
Verbosity
-v
verbose-vv
more verbose-vvv
even more verbose
IP, Protocol, Port
-n
print IP instead of host name. This can be used to avoid DNS lookups-nn
print integer protocol/port numbers instead of protocl/port names, e.g.22
vsssh
,80
vshttp
Examples:
$ tcpdump -i eth0
14:54:35.161548 IP ctn-1.example.com > ctn-2.example.com: ICMP echo request, id 29455, seq 0, length 64
14:54:35.161599 IP ctn-2.example.com > ctn-1.example.com: ICMP echo reply, id 29455, seq 0, length 64
$ tcpdump -n -i eth0
14:55:34.296206 IP 192.168.1.3 > 192.168.1.4: ICMP echo request, id 29711, seq 0, length 64
14:55:34.296259 IP 192.168.1.4 > 192.168.1.3: ICMP echo reply, id 29711, seq 0, length 64
MAC Address
-e
also print MAC address
$ tcpdump -n -e -i eth0
15:05:12.225901 fa:16:3e:39:8c:fd > 00:22:0d:27:c2:45, ethertype IPv4 (0x0800), length 294: 192.168.1.3 > 192.168.1.124: Flags [P.], seq ...
15:05:12.226585 00:22:0d:27:c2:45 > fa:16:3e:39:8c:fd, ethertype IPv4 (0x0800), length 60: 192.168.1.124 > 192.168.1.3: Flags [.], ack ...
Packet Content
-x
print the data of each packet (minus its link level header) in hex-xx
print the data of each packet, including its link level header, in hex.-X
print the data of each packet (minus its link level header) in hex and ASCII.-XX
print the data of each packet, including its link level header, in hex and ASCII.
$ tcpdump -i eth0 -x
19:33:33.724674 IP 192.168.1.3 > 192.168.1.4: ICMP echo request, id 10258, seq 0, length 64
0x0000: 4500 0054 6e2b 4000 4001 4926 c0a8 0103
0x0010: c0a8 0104 0800 a20e 2812 0000 0f1c 1ec3
0x0020: 0000 0000 0000 0000 0000 0000 0000 0000
0x0030: 0000 0000 0000 0000 0000 0000 0000 0000
0x0040: 0000 0000 0000 0000 0000 0000 0000 0000
0x0050: 0000 0000
1.3 Save to file & read from file
-w outfile.pcap
save packets to file-G
rotate the dump file, should be used with-w
option-r outfile.pcap
read a captured file
Captured files usually suffixed with cap
or .pcap
, which means packet
capture file. The captured files are totally different from those generated
with > outfile
, which only redirects the messages on standard output (text) to
a file.
# save raw packets to file
$ tcpdump -i eth0 -w test.pcap
# redirect logs to text file
$ tcpdump -i eth0 > test.txt
Captured files could be open again later:
$ tcpdump -e -nn -r test.pcap # read captured file content, print ether header, and be more numeric
15:10:40.111214 fa:16:30:a1:33:27 (oui Unknown) > fa:16:3f:e2:16:17 (oui Unknown), ethertype 802.1Q (0x8100), length 78: [|vlan]
15:10:40.111275 fa:16:30:a1:33:27 (oui Unknown) > fa:16:3f:e2:16:17 (oui Unknown), ethertype 802.1Q (0x8100), length 78: [|vlan]
Or, those files could also be opened with more professional traffic analyzing
tools, e.g. Wireshark
.
Split captured file
-C <N>
write pcap file every N MB.-W <N>
keep at most N copies, then start to rotate.
Example: read a large pcap file, split it into 10MB chunks:
$ tcpdump -r a.pcap -C 10 b.pcap
$ ls
b.pcap0 b.pcap1 b.pcap2 ...
1.4 Stop capturing
CTL-C
will stop capturing.
Besides, -c <count>
will auto exit after receiving <count>
packets.
$ tcpdump -i eth0 -c 2
15:00:18.129859 IP 192.168.1.3.ssh > 192.168.1.4.53519: Flags [P.], seq ...
15:00:18.130500 IP 192.168.1.4.53519 > 192.168.1.3.ssh: Flags [.], ack ...
2 packets captured
2 Matching expressions
tcpdump
supports filter expressions, this is where the real power comes to
place. A complete guide of pcap-filter
could be get from it’s man page,
or through:
$ man 7 pcap-filter
If no filter expressions specified, tcpdump will capture all the packets on the device, which may be huge in mount. With filter expressions, it will only capture those that match the expressions.
$ tcpdump [OPTIONS] [expression]
2.1 Match host
host <hostname or IP>
- capture packets sent from and tohost
src host <hostname or IP>
- capture packets sent fromhost
dst host <hostname or IP>
- capture packets sent tohost
Examples:
$ tcpdump -i eth0 host baidu.com # traffic from or to baidu.com
$ tcpdump -i eth0 host 192.168.1.3 # traffic from or to 192.168.1.3
$ tcpdump -i eth0 src host 192.168.1.3
$ tcpdump -i eth0 dst host 192.168.1.3
2.2 Match MAC address & VLAN
ether host <MAC>
- capture packets sent from and to<MAC>
ether src <MAC>
- capture packets sent from<MAC>
ether dst <MAC>
- capture packets sent to<MAC>
vlan <VLAN ID>
- match VLAN ID
2.3 Match network (ip range)
net <NET> mask <MASK>
- IPv4 onlynet <NET>/<LEN>
- IPv4/IPv6
May be qualified with src
and dst
.
Examples:
$ tcpdump -i eth0 net 192.168.1.0 mask 255.255.255.0
$ tcpdump -i eth0 net 192.168.1.0/24
2.4 Match port & port ranges
port <port>
- packets from and to<port>
src port <port>
- packets from<port>
dst port <port>
- packets to<port>
portrange <port1>-<port2>
- packets from and to<port1>-<port2>
src portrange <port1>-<port2>
- packets from<port1>-<port2>
dst portrange <port1>-<port2>
- packets to<port1>-<port2>
Examples:
$ tcpdump -i eth0 port 80
$ tcpdump -i eth0 dst port 80
$ tcpdump -i eth0 src portrange 8000-8080
2.5 Match protocol (L2-L4)
Match protocols in L3 header:
ip proto <PROTO>
- PROTO: icmp, icmp6, igmp, igrp, pim, ah, esp, vrrp, udp, or tcp
Follow are abbreviations:
icmp
=proto icmp
tcp
=proto tcp
udp
=proto udp
Match protocols in L2 header:
ether proto <PROTO>
- PROTO: ip, ip6, arp, rarp, atalk, aarp, decnet, sca, lat, mopdl, moprc, iso, stp, ipx, or netbeui
Follow are abbreviations:
ip
=ether proto ip
ip6
=ether proto ip6
arp
=ether proto arp
rarp
=ether proto rarp
$ tcpdump -i eth0 arp
$ tcpdump -i eth0 icmp
2.6 Match traffic direction (ingress/egress)
--direction=[in|out|inout]
or-Q [in|out]
- note that not all platform supports this
2.7 Match TCP flags
TCP flags (bits):
tcp-syn
tcp-ack
tcp-fin
tcp-rst
tcp-push
Filter expressions based on the above flags:
'tcp[tcpflags] & (tcp-rst) != 0'
: capture reset packets'tcp[tcpflags] & (tcp-syn) != 0'
ortcp[13] & 2 != 0
: capturesyn
packets'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'
: capture TCP handshake packets
$ tcpdump -nn -i eth0 'tcp[tcpflags] & (tcp-rst) != 0'
2.8 Logical operators
With logical operators, we could combine simple expressions into a complex one.
and
or&&
or
or||
not
or!
Examples:
# capture traffic: 192.168.1.3<->192.168.1.4:80
$ tcpdump -i eth0 'host 192.168.1.3 and (host 192.168.1.4 and port 80)'
# capture traffic: 192.168.1.3->192.168.1.4:80
$ tcpdump -i eth0 'src host 192.168.1.3 and (dst host 192.168.1.4 and port 80)'
# capture traffic: 192.168.1.0/24->10.1.1.4
$ tcpdump -i eth0 'src net 192.168.1.0/24 and dst host 10.1.1.4' -w test.pcap
3 Advanced matching (header fields/bits matching)
This part is borrowed from [4].
General format:
-
proto[x:y]
: starting fromx
th byte, extracty
consecutive bytes, wherex
starts from 0.For example:
ip[2:2]
means extracting the3rd
and4th
bytes. -
The extracted result could further be processed: e.g.
result & 0xF != 0
3.1 Match fields in IP header
IP header:
byte: 0 1 2 3
bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ip[6] = 32
: packets withMF=1
(More Fragments) inFlags
field, which indicates this is a fragmented packetip[8] < 5
: packets withTTL < 5
ip[2:2] > 600
: packets withlength > 600
bytes (Total Length
field)
3.2 Match fields in ICMP header
3.3 Match fields in TCP header
byte: 0 1 2 3
bit 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
tcp[0:2] > 1024
ortcp src portrange 1025-65535
: packets withsrc port > 1024
tcp[13] = 2
ortcp[tcpflags] & tcp-syn != 0
:syn
packetstcp[13] = 18
:syn+ack
packetstcp[13] & 2 = 2
:syn
orsyn+ack
packetstcp[13] & 1 = 1
:fin
packetstcp[13] & 4 = 4
:rst
packets
3.4 Match fields in UDP header
Filter reverse DNS lookup requests (dig -x <ipv6>
)
Query the domain name for IPv6 address fe80::5107:a8da:61ec:b226
, using DNS server 8.8.8.8
:
$ dig -x fe80::5107:a8da:61ec:b226 @8.8.8.8
...
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;6.2.2.b.c.e.1.6.a.d.8.a.7.0.1.5.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. IN PTR
;; AUTHORITY SECTION:
ip6.arpa. 3300 IN SOA b.ip6-servers.arpa. nstld.iana.org. 2022092102 1800 900 604800 3600
The plain text 6.2.2.b.c.e.1.6.a.d.8.a.7.0.1.5.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa.
will be encoded into the UDP data field. With wireshark, you can easily decide the offset
of the text: click on the binary data, then the corresponding text will be highlighted:
For example, text ip6.
(hex 0x69 0x70 0x36 0x04
)
is the 85~87
octet in UDP header,
so we can filter by this snippet to ignore all other DNS queries:
$ sudo tcpdump -nn -x -i enp0s3 dst port 53 and dst host 8.8.8.8 and "udp[85:4] = 0x69703604"
18:49:35.301843 IP 10.0.2.15.45855 > 8.8.8.8.53: 34915+ [1au] PTR? 6.2.2.b.c.e.1.6.a.d.8.a.7.0.1.5.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa. (113)
0x0000: 4500 008d 9337 0000 4011 cb0a 0a00 020f
0x0010: 0808 0808 b31f 0035 0079 1ca9 8863 0120
0x0020: 0001 0000 0000 0001 0136 0132 0132 0162
0x0030: 0163 0165 0131 0136 0161 0164 0138 0161
0x0040: 0137 0130 0131 0135 0130 0130 0130 0130
0x0050: 0130 0130 0130 0130 0130 0130 0130 0130
0x0060: 0130 0138 0165 0166 0369 7036 0461 7270
0x0070: 6100 000c 0001 0000 2910 0000 0000 0000
0x0080: 0c00 0a00 0854 a19a 7f83 9f15 c4
You could also filter by 0.8.e.f
, which is the start of all IPv6 link local addresses (fe80
).
Leave this exercise to readers.
3.5 Match fields in HTTP header
tcpdump <options> | grep GET
: HTTP GET requests
4 Misc
4.1 Truncate packet length
-s <LEN>
truncate each packet to length LEN
bytes. This could substantially
reduce the resulted pcap file size.
For example, if want to capture only L2 and L3 headers, you could truncate each packet to 14 (ether header) + 2 (potential VLAN) + 20 (IP header basic part) = 36 bytes, thus:
$ tcpdump -i eth0 -s 36 -w test.pcap