本文介绍抓包工具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