tcpdump是一个常用的网络包分析工具,可以用来显示通过网络传输到本系统的TCP/IP以及其他网络的数据包。tcpdump 使用 libpcap 库来抓取网络报,这个库在几乎在所有的 Linux/Unix 中都有。在 Windows 中我们通常会使用 Wireshark 进行图形化操作相当便捷,然而在 Linux 环境中如何巧妙应用 tcpdump 的命令来操作提升效率就显得尤为重要。在本文中,我们将会通过一些实例来演示如何使用 tcpdump 命令。

tcpdump是一款灵活、功能强大的抓包工具,能有效地帮助排查网路故障问题。

在linux中安装tcpdump

用下面的命令检查一下是否安装了tcpdump

$ which tcpdump
/usr/sbin/tcpdump

在CentOS用如下命令安装tcpdump, tcpdump依赖于libpcap库,该库文件用于捕获网络数据包,如果该库文件也没有安装,系统会依据依赖关系自动安装它,这样就可以抓包了。

$ sudo yum install -y tcpdump

如何用tcpdump抓包

使用tcpdump抓包需要管理员权限,因此下面示例中绝大多数命名都是以sudo开头。

首先,用tcpdump -D命令可以列出可以抓包的网络接口:

$ sudo tcpdump -D
1.eth0
2.docker0
3.eth1
4.any (Pseudo-device that captures on all interfaces)
5.lo [Loopback]

其中特殊接口any可用于抓取所有活动的网络接口的数据包。

tcpdump会持续抓包直到收到中断信号。你可以按Ctrl+C来停止抓包。-c选项也可以用于限制tcpdump抓包的数量。

$ sudo tcpdump -i any -c 5

tcpdump默认是将IP地址和端口号解析为对应的接口名以及服务协议名称。而在网络故障排查中,使用IP地址和端口号更便于分析问题,用-n选项显示IP地址,用-nn选项显示端口号。抓包中的数据包显示IP地址和端口号,还有一个好处就是,这样可以阻止tcpdump发出DNS查找,有助于网络故障排查中减少数据流量。

$ sudo tcpdump -i any -c 5 -nn

获取更多的包信息,并且以可读的形式显示时间戳

$ sudo tcpdump -i any -c 5 -nn -ttttnnvvS

获取整个网络的数据包

$ sudo tcpdump -i any -c 5 -nn net 192.168.1.0/24

理解抓取的报文

tcpdump能够抓取并解码多种协议类型的数据报文,如TCP、UDP、ICMP等。这里分析一下TCP报文,来入门tcpdump抓包。tcpdump抓取的报文如下:

15:50:24.052662 IP 10.0.41.134.60606 > 10.10.72.251.443: Flags [P.], seq 966417349:966418097, ack 1148820373, win 4096, options [nop,nop,TS val 1300637207 ecr 208489191], length 748

具体的字段根据不同的报文类型会有不同,但上面这个例子是一般的格式形式。

第一个字段15:50:24.052662是该数据报文被抓取的系统本地时间戳,然后IP是网络层协议类型,这里是IPv4,如果是IPv6协议,该字段值是IP610.0.41.134.60606是源IP地址和端口号,紧跟其后的是目的IP地址和端口号,这里是10.10.72.251.443,在源IP和目的IP之后,可以看到的是TCP报文标记段Flags [P.]。该字段通常取值如下:

标志类型 描述
S SYN Connection Start
F FIN Connection Finish
P PUSH Data push
R RST Connection reset
. ACK Acknowledgment

该字段也可以是这些值的组合,例如[S.]表示SYN-ACK数据包。

接下来是该数据包中数据的序列号。对于抓取的第一个数据包,该字段值是一个绝对数字,后续包使用相对数值,以便更容易查询跟踪。例如此处seq 966417349:966418097代表该数据包包含该数据流的第966417349到966418097字节。

接下来是ack值:ack 1148820373。该数据包是数据发送方,ack值为1148820373,在数据接收方,该字段代表数据流上的下一个预期字节数据,例如,该数据流中下一个数据包的ack值应该是966418097,

接下来字段是接收窗口大小win 4096,它表示接收缓冲区中的可用的字节数,后跟TCP选项如MSS(最大段大小)或者窗口比例值。Transmission Control Protocol(TCP) Parameters

最后length 748代表数据包的有效载荷字节长度,这个长度和seq序列号中字节数值长度是不一样的。

过滤数据包

tcpdump可以抓取很多类型的数据报文,其中很多可能和我们需要查找的问题并没有关系,举个例子假设正在定位一个与web服务器连接的网络问题,就不必关心SSH数据报文,因此在抓包中过滤SSH报文可能更便于分析问题。tcpdump有很多参数选项可以设置数据包过滤规则,例如根数据源IP以及目的IP地址,端口号、协议等等规则来过滤数据包。

协议

在命令中指定协议便可以按照协议类型来筛选数据包,比如抓取ICMP报文

$ sudo tcpdump -i any -c5 icmp
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

然后打开一个终端,去ping另一台机器

$ ping localhost
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.070 ms

回到运行tcpdump命令的终端,可以看到它筛选出了ICMP报文,这里tcpdump并没有显示有关localhost的域名解析数据包:

16:59:03.200140 IP localhost > localhost: ICMP echo request, id 49266, seq 0, length 64
16:59:03.200153 IP localhost > localhost: ICMP echo request, id 49266, seq 0, length 64
16:59:03.200162 IP localhost > localhost: ICMP echo reply, id 49266, seq 0, length 64
16:59:03.200164 IP localhost > localhost: ICMP echo reply, id 49266, seq 0, length 64
16:59:07.241378 IP localhost > localhost: ICMP echo request, id 51058, seq 0, length 64
5 packets captured
445 packets received by filter
0 packets dropped by kernel

主机

host参数只抓取和特定主机相关的数据包,如下所示只展示了127.0.0.1相关的数据包。不管是作为原地址还是目的地址。

$ sudo tcpdump -i any -c5 -nn host 127.0.0.1
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
17:01:43.178761 IP 127.0.0.1.54430 > 127.0.0.1.9229: Flags [S], seq 395265456, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1304878505 ecr 0,sackOK,eol], length 0
17:01:43.178772 IP 127.0.0.1.54430 > 127.0.0.1.9229: Flags [S], seq 395265456, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1304878505 ecr 0,sackOK,eol], length 0
17:01:43.178785 IP 127.0.0.1.9229 > 127.0.0.1.54430: Flags [R.], seq 0, ack 395265457, win 0, length 0
17:01:43.178788 IP 127.0.0.1.9229 > 127.0.0.1.54430: Flags [R.], seq 0, ack 1, win 0, length 0
17:01:43.179331 IP 127.0.0.1.54432 > 127.0.0.1.9229: Flags [SEW], seq 2113539719, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1304878505 ecr 0,sackOK,eol], length 0
5 packets captured
19 packets received by filter
0 packets dropped by kernel

端口号

tcpdump可以根据服务类型或者服务端口号来筛选数据包,例如,抓取HTTP服务相关的数据包

$ sudo tcpdump -i any -c5 -nn port 80
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
17:04:18.452643 IP 10.0.41.134.55093 > 101.226.49.154.80: Flags [S], seq 3289093077, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1305032376 ecr 0,sackOK,eol], length 0
17:04:18.492311 IP 101.226.49.154.80 > 10.0.41.134.55093: Flags [S.], seq 1464101569, ack 3289093078, win 14400, options [mss 1440,nop,nop,sackOK,nop,wscale 7], length 0
17:04:18.492351 IP 10.0.41.134.55093 > 101.226.49.154.80: Flags [.], ack 1, win 8192, length 0
17:04:18.492835 IP 10.0.41.134.55093 > 101.226.49.154.80: Flags [P.], seq 1:820, ack 1, win 8192, length 819: HTTP: POST /mmtls/5c92d9c6 HTTP/1.1
17:04:18.530531 IP 101.226.49.154.80 > 10.0.41.134.55093: Flags [.], ack 820, win 126, length 0
5 packets captured
21 packets received by filter
0 packets dropped by kernel

抓取指定端口范围的数据包

$ sudo tcpdump portrange 22-125

IP地址、主机名

同样,你可以根据原IP地址或者目的IP地址或者主机名来筛选数据包。例如抓取IP地址为127.0.0.1的数据包:

$ sudo tcpdump -i any -c5 -nn src 127.0.0.1
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
17:06:12.104421 IP 127.0.0.1.55583 > 127.0.0.1.9229: Flags [SEW], seq 3461944309, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305145006 ecr 0,sackOK,eol], length 0
17:06:12.104438 IP 127.0.0.1.55583 > 127.0.0.1.9229: Flags [SEW], seq 3461944309, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305145006 ecr 0,sackOK,eol], length 0
17:06:12.104449 IP 127.0.0.1.9229 > 127.0.0.1.55583: Flags [R.], seq 0, ack 3461944310, win 0, length 0
17:06:12.104453 IP 127.0.0.1.9229 > 127.0.0.1.55583: Flags [R.], seq 0, ack 1, win 0, length 0
17:06:12.105459 IP 127.0.0.1.55585 > 127.0.0.1.9229: Flags [S], seq 2708470450, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305145007 ecr 0,sackOK,eol], length 0
5 packets captured
67 packets received by filter
0 packets dropped by kernel

注意次数示例中抓取了来自源IP地址127.0.0.155583端口和9229端口的数据包,他们的应答包没有显示出来因为那些包的源IP地址已经变了。

相对的,使用dst就是按目的IP/主机名来筛选数据包。

$ sudo tcpdump -i any -c5 -nn dst 127.0.0.1
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
17:09:31.784422 IP 127.0.0.1.56437 > 127.0.0.1.9229: Flags [S], seq 2235026295, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305343167 ecr 0,sackOK,eol], length 0
17:09:31.784439 IP 127.0.0.1.56437 > 127.0.0.1.9229: Flags [S], seq 2235026295, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305343167 ecr 0,sackOK,eol], length 0
17:09:31.784449 IP 127.0.0.1.9229 > 127.0.0.1.56437: Flags [R.], seq 0, ack 2235026296, win 0, length 0
17:09:31.784453 IP 127.0.0.1.9229 > 127.0.0.1.56437: Flags [R.], seq 0, ack 1, win 0, length 0
17:09:31.785478 IP 127.0.0.1.56439 > 127.0.0.1.9229: Flags [SEW], seq 2854593421, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305343168 ecr 0,sackOK,eol], length 0
5 packets captured
31 packets received by filter
0 packets dropped by kernel

多条件筛选

当然可以使用多条件组合来筛选数据包,使用and以及or逻辑操作符来创建过滤规则,与(and,&&),或(or,||),非(not,!)。例如,筛选来自源IP地址127.0.0.1的HTTP数据包:

$ sudo tcpdump -i any -c5 -nn src 127.0.0.1 and port 80
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
17:11:49.784339 IP 127.0.0.1.57058 > 127.0.0.1.80: Flags [SEW], seq 3235382037, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305480256 ecr 0,sackOK,eol], length 0
17:11:49.784350 IP 127.0.0.1.57058 > 127.0.0.1.80: Flags [SEW], seq 3235382037, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305480256 ecr 0,sackOK,eol], length 0
17:11:49.784394 IP 127.0.0.1.80 > 127.0.0.1.57058: Flags [S.], seq 3853499898, ack 3235382038, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305480256 ecr 1305480256,sackOK,eol], length 0
17:11:49.784397 IP 127.0.0.1.80 > 127.0.0.1.57058: Flags [S.], seq 3853499898, ack 3235382038, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1305480256 ecr 1305480256,sackOK,eol], length 0
17:11:49.784406 IP 127.0.0.1.57058 > 127.0.0.1.80: Flags [.], ack 1, win 12759, options [nop,nop,TS val 1305480256 ecr 1305480256], length 0
5 packets captured
1322 packets received by filter
0 packets dropped by kernel

你也可以使用括号来创建更为复杂的过滤规则,但在shell中请用引号包含你的过滤规则以防止被识别为shell表达式。下面例子抓取来源IP为10.0.41.134或者10.0.0.253的HTTP(端口号为8060)的数据包。

$ sudo tcpdump -i any -c5 -nn "port 8060 and (src 10.0.41.134 or src 10.0.0.253)"
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
17:24:31.734446 IP 10.0.0.253.22173 > 10.0.41.134.8060: Flags [S], seq 1256704595, win 29200, options [mss 1460,sackOK,TS val 1627830283 ecr 0,nop,wscale 7], length 0
17:24:31.734599 IP 10.0.41.134.8060 > 10.0.0.253.22173: Flags [S.], seq 180679158, ack 1256704596, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1306237498 ecr 1627830283,sackOK,eol], length 0
17:24:31.742795 IP 10.0.0.253.22173 > 10.0.41.134.8060: Flags [.], ack 1, win 229, options [nop,nop,TS val 1627830287 ecr 1306237498], length 0
17:24:31.742837 IP 10.0.41.134.8060 > 10.0.0.253.22173: Flags [.], ack 1, win 4117, options [nop,nop,TS val 1306237506 ecr 1627830287], length 0
17:24:32.993148 IP 10.0.0.253.22173 > 10.0.41.134.8060: Flags [P.], seq 1:6, ack 1, win 229, options [nop,nop,TS val 1627831541 ecr 1306237506], length 5
5 packets captured
212 packets received by filter
0 packets dropped by kernel

检查数据包内容

在上面的例子中,我们只按照数据包头部的信息来建立规则刷选数据包,例如源地址、目的地址、端口号等。又是我们需要分析网络连接问题,可能需要分析数据包中的内容来判断什么内容需要被发送,什么内容需要被接收等。tcpdump提供了两个选项可以查看数据包内容,-X以十六进制打印数据报文内容,-A打印数据报文的ASCII码值。例如下面HTTP请求报文内容如下:

$ sudo tcpdump -i any -c10 -nn -A port 8060
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

17:31:18.161274 IP 10.0.0.253.32439 > 10.0.41.134.8060: Flags [S], seq 4077569604, win 29200, options [mss 1460,sackOK,TS val 1628236713 ecr 0,nop,wscale 7], length 0
xOC.....)9;o..E..<-.@.>..L
...
.).~..|.
.D......r..3.........
a...........
17:31:18.161418 IP 10.0.41.134.8060 > 10.0.0.253.32439: Flags [S.], seq 1696372135, ack 4077569605, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1306641720 ecr 1628236713,sackOK,eol], length 0
..)9;oxOC.....E..@.Q@.@.+.
.).
....|~.e....
.E....FR.............
M..8a.......
17:31:18.165864 IP 10.0.0.253.32439 > 10.0.41.134.8060: Flags [.], ack 1, win 229, options [nop,nop,TS val 1628236717 ecr 1306641720], length 0
xOC.....)9;o..E..4-.@.>..S
...
.).~..|.
.Ee........8.....
a...M..8
17:31:18.165868 IP 10.0.0.253.32439 > 10.0.41.134.8060: Flags [P.], seq 1:90, ack 1, win 229, options [nop,nop,TS val 1628236717 ecr 1306641720], length 89
xOC.....)9;o..E...-.@.>...
...
.).~..|.
.Ee..............
a...M..8GET /sd/health HTTP/1.1
User-Agent: curl/7.29.0
Host: 10.0.41.134:8060
Accept: */*


17:31:18.165910 IP 10.0.41.134.8060 > 10.0.0.253.32439: Flags [.], ack 1, win 4117, options [nop,nop,TS val 1306641724 ecr 1628236717], length 0
..)9;oxOC.....E..4."@.@.P.
.).
....|~.e....
.E....v......
M..<a...
17:31:18.165932 IP 10.0.41.134.8060 > 10.0.0.253.32439: Flags [.], ack 90, win 4114, options [nop,nop,TS val 1306641724 ecr 1628236717], length 0
..)9;oxOC.....E..4F.@.@...
.).
....|~.e....
......u......
M..<a...
17:31:18.168191 IP 10.0.41.134.8060 > 10.0.0.253.32439: Flags [P.], seq 1:138, ack 90, win 4114, options [nop,nop,TS val 1306641726 ecr 1628236717], length 137
..)9;oxOC.....E....F@.@..r
.).
....|~.e....
.......k.....
M..>a...HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Date: Wed, 22 Apr 2020 09:31:18 GMT
Content-Length: 20

10.0.0.253==========
17:31:18.175737 IP 10.0.0.253.32439 > 10.0.41.134.8060: Flags [.], ack 138, win 237, options [nop,nop,TS val 1628236725 ecr 1306641726], length 0
xOC.....)9;o..E..4-.@.>..Q
...
.).~..|.
..e..1.....@.....
a...M..>
17:31:18.175740 IP 10.0.0.253.32439 > 10.0.41.134.8060: Flags [F.], seq 90, ack 138, win 237, options [nop,nop,TS val 1628236725 ecr 1306641726], length 0
xOC.....)9;o..E..4-.@.>..P
...
.).~..|.
..e..1.....?.....
a...M..>
17:31:18.175770 IP 10.0.41.134.8060 > 10.0.0.253.32439: Flags [.], ack 91, win 4114, options [nop,nop,TS val 1306641733 ecr 1628236725], length 0
..)9;oxOC.....E..4..@.@.a.
.).
....|~.e..1.
......u......
M..Ea...
10 packets captured
138 packets received by filter
0 packets dropped by kernel

这对定位一些普通的http调用API接口的问题很有用,当然如果是加密报文,这个输出也就没有大用了。

保存抓包数据

tcpdump提供了保存抓包数据的功能已便后续分析数据包,例如你可以让它夜里抓包,早上起来分析它,同样当有很多包时显示过快也不利于分析,因此保存数据更利于分析。使用-w选项来保存数据包而不是在屏幕上显示出抓取的数据包:

$ sudo tcpdump -i any -c10 -nn -w webserver.pcap port 8060
tcpdump: data link type PKTAP
tcpdump: listening on any, link-type PKTAP (Apple DLT_PKTAP), capture size 262144 bytes
10 packets captured
704 packets received by filter
0 packets dropped by kernel

该命令抓取的数据包保存到文件webserver.pcap。后缀名pcap表示文件是抓取的数据包格式。正如示例所示,保存数据包到文件中屏幕上就没有任何数据有关的报文输出,其中 -c10表示抓取10个数据包就停止抓包,如果想有一些反馈来提示确实抓取到了数据包可以用-v选项。

tcpdump将数据包保存在二进制文件中,所以不能简单的用文本编辑器打开,使用-r选项来阅读该文件的报文内容。-A也可以解码为ASCII码便于阅读。这里不需要管理员权限 sudo 了,因为此刻并不是在网络接口处抓包。

$ tcpdump -nn -r webserver.pcap
reading from PCAP-NG file webserver.pcap
17:42:31.991307 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [S], seq 1820003953, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1307311658 ecr 0,sackOK,eol], length 0
17:42:31.991317 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [S], seq 1820003953, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1307311658 ecr 0,sackOK,eol], length 0
17:42:31.991371 IP 127.0.0.1.8060 > 127.0.0.1.64986: Flags [S.], seq 2500964260, ack 1820003954, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1307311658 ecr 1307311658,sackOK,eol], length 0
17:42:31.991374 IP 127.0.0.1.8060 > 127.0.0.1.64986: Flags [S.], seq 2500964260, ack 1820003954, win 65535, options [mss 16344,nop,wscale 5,nop,nop,TS val 1307311658 ecr 1307311658,sackOK,eol], length 0
17:42:31.991385 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [.], ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 0
17:42:31.991387 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [.], ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 0
17:42:31.991397 IP 127.0.0.1.8060 > 127.0.0.1.64986: Flags [.], ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 0
17:42:31.991401 IP 127.0.0.1.8060 > 127.0.0.1.64986: Flags [.], ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 0
17:42:31.991403 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [P.], seq 1:1117, ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 1116
17:42:31.991414 IP 127.0.0.1.64986 > 127.0.0.1.8060: Flags [P.], seq 1:1117, ack 1, win 12759, options [nop,nop,TS val 1307311658 ecr 1307311658], length 1116

你还可以使用我们讨论过的任何过滤规则来过滤文件中的内容,就像使用实时数据一样,例如,通过执行以下命令从源IP地址127.0.0.1检查文件中的数据包

下一步

以上基本功能以及可以帮助你使用tcpdump抓包工具了,更多的内容请参考 tcpdump 网站 以及它的 帮助文件

tcpdump 命令行工具为分析网络流量数据包提供了强大的灵活性。如果需要使用图形工具来抓包请参考 Wireshark

Wireshark 还可以用来读取 tcpdump 保存的 pcap 文件。你可以使用 tcpdump 命令行在没有 GUI 界面的远程机器上抓包然后在 Wireshark 中分析数据包。