0%

tcpdump的使用

本文介绍抓包工具tcpdump在linux下的使用。Linux的tcpdump manual中包含许多选项以及复杂的filter表达式,我们工作中往往用不到这么多的选项和太复杂的filter。所以本文介绍一些常用的选项和filter规则,尽可能的通过一些例子来说明。

常用选项 (1)

选择网络接口 (1.1)

常用的是通过-D选项列出所有的网络接口,然后通过-i来选择网络接口进行抓包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# tcpdump -D
1.bluetooth0 (Bluetooth adapter number 0)
2.nflog (Linux netfilter log (NFLOG) interface)
3.nfqueue (Linux netfilter queue (NFQUEUE) interface)
4.usbmon1 (USB bus number 1)
5.usbmon2 (USB bus number 2)
6.eno16777736
7.any (Pseudo-device that captures on all interfaces)
8.lo

# tcpdump -i 6
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
21:58:42.249107 IP 192.168.221.100.ssh > 192.168.221.1.64136: Flags [P.], seq 962061353:962061549, ack 63437321, win 313, options [nop,nop,TS val 4294759135 ecr 68900541], length 196
21:58:42.249257 IP 192.168.221.1.64136 > 192.168.221.100.ssh: Flags [.], ack 196, win 4089, options [nop,nop,TS val 68900689 ecr 4294759135], length 0

读写文件 (1.2)

默认情况下,tcpdump把抓到的包打印到标准输出(打印方式见1.3节)。我们还可以让tcpdump把抓到的包写入文件,文件名一般以.pcap结尾。pcap文件是二进制文件,还需要用tcpdump读取(也可以使用图形化工具wireshark打开)。涉及到的选项主要是-w-r
-w: 抓包并写入指定的pcap文件,例如,tcpdump -i 6 -w packs.pcap
-r: 从指定的pcap文件读取包并处理,例如,tcpdump -i 6 -r packs.pcap

打印选项 (1.3)

最常用的打印选项是-X,以16进制和ASCII码两种方式打印抓到的包。另一个常用选项是-A,以ASCII码方式来打印。

需要注意的是:

  • 打印的内容是从IP头开始的,不包括数据链路层的头部(Ethernet Header);
  • 它们只是控制打印方式,和写入文件(-w选项)的格式无关。抓包并写入文件的时候没有必要指定打印方式,通过-r选项读文件的时候才需要;

抓包并打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# tcpdump -i 6 -X 'icmp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
22:03:09.829237 IP 192.168.221.1 > 192.168.221.100: ICMP echo request, id 64280, seq 14, length 64
0x0000: 4500 0054 f154 0000 4001 4d9d c0a8 dd01 E..T.T..@.M.....
0x0010: c0a8 dd64 0800 687e fb18 000e 5b9b bf9d ...d..h~....[...
0x0020: 000c 8e12 0809 0a0b 0c0d 0e0f 1011 1213 ................
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567
22:03:09.829282 IP 192.168.221.100 > 192.168.221.1: ICMP echo reply, id 64280, seq 14, length 64
0x0000: 4500 0054 97c5 0000 4001 a72c c0a8 dd64 E..T....@..,...d
0x0010: c0a8 dd01 0000 707e fb18 000e 5b9b bf9d ......p~....[...
0x0020: 000c 8e12 0809 0a0b 0c0d 0e0f 1011 1213 ................
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567

抓包并存入文件(无须指定打印方式)

1
2
3
4
5
# tcpdump -i 6 -w packs.pcap 'icmp'
tcpdump: listening on eno16777736, link-type EN10MB (Ethernet), capture size 65535 bytes
^C2 packets captured
2 packets received by filter
0 packets dropped by kernel

读取文件并以16进制和ASCII码打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# tcpdump -i 6 -X -r packs.pcap
reading from file packs.pcap, link-type EN10MB (Ethernet)
22:10:48.020587 IP 192.168.221.1 > 192.168.221.100: ICMP echo request, id 12057, seq 15, length 64
0x0000: 4500 0054 bc91 0000 4001 8260 c0a8 dd01 E..T....@..`....
0x0010: c0a8 dd64 0800 8767 2f19 000f 5b9b c168 ...d...g/...[..h
0x0020: 0000 3969 0809 0a0b 0c0d 0e0f 1011 1213 ..9i............
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567
22:10:48.020631 IP 192.168.221.100 > 192.168.221.1: ICMP echo reply, id 12057, seq 15, length 64
0x0000: 4500 0054 97f3 0000 4001 a6fe c0a8 dd64 E..T....@......d
0x0010: c0a8 dd01 0000 8f67 2f19 000f 5b9b c168 .......g/...[..h
0x0020: 0000 3969 0809 0a0b 0c0d 0e0f 1011 1213 ..9i............
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567

读取文件并以ASCII码打印

1
2
3
4
5
6
7
8
# tcpdump -i 6 -A -r packs.pcap
reading from file packs.pcap, link-type EN10MB (Ethernet)
22:10:48.020587 IP 192.168.221.1 > 192.168.221.100: ICMP echo request, id 12057, seq 15, length 64
E..T....@..`.......d...g/...[..h..9i.
.................. !"#$%&'()*+,-./01234567
22:10:48.020631 IP 192.168.221.100 > 192.168.221.1: ICMP echo reply, id 12057, seq 15, length 64
E..T....@......d.......g/...[..h..9i.
.................. !"#$%&'()*+,-./01234567

抓包的长度 (1.4)

Tcpdump抓包的长度有一个默认值,不同系统不同,有的是65535 bytes,有的是262,144 bytes。可以使用-s来指定长度。有几点需要注意:

  • -s指定的长度是写入pcap文件的包的长度。比如-s 32的情况下,写入pcap文件的包长度就是32 bytes,多余的部分被截断(假如原来包长度大于等于32 bytes)。
  • -s指定的长度是包括数据链路层的头部的。比如Ethernet的头是14字节。
  • 虽然-s的长度包含数据链路层的头部,但是,使用-X打印的时候却不包含;也就是说,你使用-s 32截取32字节,-X只打印出18字节。
  • 数据包的长度大于-s指定的长度时,数据包就会被截断。一个数据包开头是Ethernet Header,接着是IP header,接着可能是TCP或者ICMP header……-s指定的值不同,被截断的位置也不同。tcpdump打印一个[|proto]来告诉你被截断的是什么协议;
  • 增大长度不但会增加包的处理时间,也会减少缓存的包的数量,这两个因素都可能造成丢包。所以,使用-s时,指定一个够用(包含所需信息)的值即可。
  • -s只能用于抓包时,不能读取包时。例如,抓包时使用-s 32来抓取前32 bytes;读包时使用-s 16来只读取前16 bytes是行不通的(还是会读取全部的32 bytes,-s 16好像被忽略)。反之抓取前16 bytes读取32 bytes更不可能行的通。

截断协议是ethernet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# tcpdump -i 6 -s 10 -w packs.pcap 
tcpdump: listening on eno16777736, link-type EN10MB (Ethernet), capture size 10 bytes
^C6 packets captured
9 packets received by filter
0 packets dropped by kernel


# tcpdump -i 6 -X -r packs.pcap
reading from file packs.pcap, link-type EN10MB (Ethernet)
23:27:21.977928 [|ether]
23:27:21.978135 [|ether]
23:27:22.464298 [|ether]
23:27:22.464341 [|ether]
23:27:23.466692 [|ether]
23:27:23.466738 [|ether]
  • 首先,[|ether]告诉我们截断的是ethernet协议。
  • 其次,由于-X打印从IP头开始,而数据包从ethernet头就被截断了,所以,没有打印出任何数据。

截断协议是IP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# tcpdump -i 6 -s 32 -w packs.pcap 
tcpdump: listening on eno16777736, link-type EN10MB (Ethernet), capture size 32 bytes
^C10 packets captured
13 packets received by filter
0 packets dropped by kernel

# tcpdump -i 6 -X -r packs.pcap
reading from file packs.pcap, link-type EN10MB (Ethernet)
23:32:37.863628 IP [|ip]
0x0000: 4512 00b0 1df0 4000 4006 e08e c0a8 dd64 E.....@.@......d
0x0010: c0a8 ..
23:32:37.863970 IP [|ip]
0x0000: 4510 0034 0000 4000 4006 fefc c0a8 dd01 E..4..@.@.......
0x0010: c0a8 ..
  • 首先,[|ip]告诉我们截断的是IP协议。
  • 其次,-s指定的长度32 bytes包含Ethernet头14 bytes,而-X打印从IP头开始,所以只打印出18 bytes。

读取包时-s被忽略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# tcpdump -i 6 -s 32 -w packs1.pcap 
tcpdump: listening on eno16777736, link-type EN10MB (Ethernet), capture size 32 bytes
^C3 packets captured
3 packets received by filter
0 packets dropped by kernel

# tcpdump -i 6 -X -s 16 -r packs1.pcap
reading from file packs1.pcap, link-type EN10MB (Ethernet)
00:09:10.660424 IP [|ip]
0x0000: 4512 00b0 ddfb 4000 4006 2083 c0a8 dd64 E.....@.@......d
0x0010: c0a8 ..
00:09:10.660633 IP [|ip]
0x0000: 4510 0034 0000 4000 4006 fefc c0a8 dd01 E..4..@.@.......
0x0010: c0a8 ..
00:09:18.762511 IP [|ip]
0x0000: 4512 0058 0000 4000 4006 fed6 c0a8 dd01 E..X..@.@.......
0x0010: c0a8 ..

读取包时我们指定-s 16没有起作用,否则应该只打印2 bytes(因为Ethernet头14 bytes)。而现在打印出18 bytes,加上Ethernet头14 bytes,其实就是抓包时指定的32 bytes。

host与port (1.5)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
source host是192.168.30.180
# tcpdump -i 1 -s 8192 src host 192.168.30.180 -w from.180.pcap

destination host是192.168.30.181
# tcpdump -i 1 -s 8192 dst host 192.168.30.181 -w to.181.pcap

source host或destination host是192.168.30.180
# tcpdump -i 1 -s 8192 host 192.168.30.180 -w to.from.180.pcap

source port是1234
# tcpdump -i 1 -s 8192 src port 1234 -w from.port.1234.pcap

destination port是7890
# tcpdump -i 1 -s 8192 dst port 7890 -w to.port.7890.pcap

source port或destination port是7890
# tcpdump -i 1 -s 8192 port 7890 -w to.from.port.7890.pcap

这些条件可以用and连接起来:

从192.168.30.180:1234到192.168.30.181:7890 (只抓单向的包)
# tcpdump -i 1 -s 8192 src host 192.168.30.180 and src port 1234 and dst host 192.168.30.181 and dst port 7890 -w from.180.1234.to.181.7890.pcap

通信的一端(source或destination)是192.168.30.181:7890 (抓双向的包)
# tcpdump -i 1 -s 8192 host 192.168.30.181 and port 7890 -w to.from.181.7890.pcap
写的不错,有赏!