如何使用 tcpdump 捕获和分析网络流量?

网络数据包分析利器:tcpdump 命令详解

tcpdump 是一款卓越的网络嗅探命令行工具,在捕获和分析 TCP/IP 数据包领域,它堪称业界标准。 掌握 tcpdump 的使用,对于排查网络故障,监控网络流量至关重要。

此工具在解决网络难题时能够提供强有力的支持。 它不仅能实时捕获数据包,还能将其保存至文件,便于日后深入分析。 为了保持对网络状态的敏锐洞察,定期运行 tcpdump 进行网络监控是一个明智的选择。

解读 tcpdump 的输出结果

通过 tcpdump,我们可以深入剖析 TCP/IP 数据包的头部信息。 该工具会逐行打印每个数据包的信息,并且会持续运行,直到用户按下 Ctrl+C 组合键来终止进程。

让我们仔细分析一个典型的输出示例:

20:58:26.765637 IP 10.0.0.50.80 > 10.0.0.1.53181: Flags [F.], seq 1, ack 2, win 453, options [nop,nop,TS val 3822939 ecr 249100129], length 0

上面这一行包含了以下关键信息:

时间戳 (20:58:26.765637) – Unix 时间戳,精确到微秒。
协议 (IP) – 表明数据包使用的网络协议。
源地址和端口 (10.0.0.50.80) – 发送数据包的主机 IP 地址和端口号。
目标地址和端口 (10.0.0.1.53181) – 接收数据包的主机 IP 地址和端口号。
TCP 标志 (Flags [F.]) – 用于指示连接状态的 TCP 标志。 [F.] 表示 FIN-ACK 标志,用于关闭连接。 常见的 TCP 标志包括:

  • S – 同步 (SYN)。 连接建立的第一步。
  • F – 结束 (FIN)。 连接终止。
  • . – 确认 (ACK)。 确认数据包已成功接收。
  • P – 推送 (PSH)。 告知接收方立即处理数据包,而非缓存。
  • R – 复位 (RST)。 通信中止。
序列号 (seq 1) – 数据包中数据的序列号。
确认号 (ack 2) – 确认号,用于确认收到的数据。
窗口大小 (win 453) – 接收缓冲区中可用的字节数。
TCP 选项 (options [nop,nop,TS val 3822939 ecr 249100129]) – TCP 协议的各种选项。
数据长度 (length 0) – 数据负载的长度,此处为 0。

安装 tcpdump

在基于 Debian 的 Linux 发行版上,您可以使用 apt 命令来安装 tcpdump

# apt install tcpdump -y

对于基于 RPM 的 Linux 发行版,可以使用 yum 命令进行安装:

# yum install tcpdump -y

或者,在 RHEL 8 系统中,可以使用 dnf 命令:

# dnf install tcpdump -y

tcpdump 命令的常用选项

要运行 tcpdump,您需要具备 root 权限。 该工具提供了丰富的选项和过滤器。 若不带任何选项运行,tcpdump 将会捕获流经默认网络接口的所有数据包。

使用以下命令,查看系统上可用的网络接口列表以及 tcpdump 可用于捕获数据包的网络接口列表:

# tcpdump -D

或者,您也可以使用:

# Tcpdump --list-interfaces
1.eth0
2.nflog (Linux netfilter log (NFLOG) interface)
3.nfqueue (Linux netfilter queue (NFQUEUE) interface)
4.eth1
5.any (Pseudo-device that captures on all interfaces)
6.lo [Loopback]

在某些没有命令列出网络接口的系统中,该命令尤为重要。

要捕获流经特定网络接口的数据包,使用带有接口名称的 -i 标志。 如果没有指定 -i 接口,tcpdump 将会自动选择它检测到的第一个网络接口。

# tcpdump -i eth1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
01:06:09.278817 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 4761, seq 1, length 64
01:06:09.279374 IP 10.0.0.51 > vagrant-ubuntu-trusty-64: ICMP echo reply, id 4761, seq 1, length 64
01:06:10.281142 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 4761, seq 2, length 64

-v 标志可以增加输出的数据包信息,而 -vv 标志会提供更详细的信息。

默认情况下,tcpdump 会将 IP 地址解析为主机名,并且还会使用服务名称来代替端口号。 如果 DNS 配置出现问题,或者您不希望 tcpdump 执行名称查找,请使用 -n 选项。

# tcpdump -n
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
04:19:07.675216 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 2186733178:2186733278, ack 204106815, win 37232, length 100
04:19:07.675497 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 100, win 65535, length 0
04:19:07.675747 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 100:136, ack 1, win 37232, length 36
04:19:07.675902 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 136, win 65535, length 0
04:19:07.676142 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 136:236, ack 1, win 37232, length 100

要仅捕获指定数量的数据包行,比如 5 行,使用 -c 标志:

#tcpdump -c 5
04:19:07.675216 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 2186733178:2186733278, ack 204106815, win 37232, length 100
04:19:07.675497 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 100, win 65535, length 0
04:19:07.675747 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 100:136, ack 1, win 37232, length 36
04:19:07.675902 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 136, win 65535, length 0
04:19:07.676142 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 136:236, ack 1, win 37232, length 100
5 packets captured

默认情况下,tcpdump 使用 Unix 时间戳。 若要捕获具有人类可读时间戳的数据包,可以使用 -tttt 选项:

# tcpdump -tttt
2020-07-06 04:30:12.203638 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 2186734102:2186734138, ack 204107103, win 37232, length 36
2020-07-06 04:30:12.203910 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 36, win 65535, length 0
2020-07-06 04:30:12.204292 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 36:72, ack 1, win 37232, length 36
2020-07-06 04:30:12.204524 IP 10.0.2.2.50422 > 10.0.2.15.22: Flags [.], ack 72, win 65535, length 0
2020-07-06 04:30:12.204658 IP 10.0.2.15.22 > 10.0.2.2.50422: Flags [P.], seq 72:108, ack 1, win 37232, length 36

tcpdump 的过滤器表达式

过滤器表达式用于选择要显示的数据包头部信息。 如果未应用过滤器,则将显示所有数据包的头部。 常用的过滤器包括 porthostsrcdsttcpudpicmp

端口过滤器

使用端口过滤器可以查看到达特定端口的数据包:

# Tcpdump -i eth1 -c 5 port 80
23:54:24.978612 IP 10.0.0.1.53971 > 10.0.0.50.80: Flags [SEW], seq 53967733, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 256360128 ecr 0,sackOK,eol], length 0
23:54:24.978650 IP 10.0.0.50.80 > 10.0.0.1.53971: Flags [S.E], seq 996967790, ack 53967734, win 28960, options [mss 1460,sackOK,TS val 5625522 ecr 256360128,nop,wscale 6], length 0
23:54:24.978699 IP 10.0.0.1.53972 > 10.0.0.50.80: Flags [SEW], seq 226341105, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 256360128 ecr 0,sackOK,eol], length 0
23:54:24.978711 IP 10.0.0.50.80 > 10.0.0.1.53972: Flags [S.E], seq 1363851389, ack 226341106, win 28960, options [mss 1460,sackOK,TS val 5625522 ecr 256360128,nop,wscale 6], length 0

主机过滤器

捕获所有到达或离开 IP 地址为 10.0.2.15 的主机的数据包:

# tcpdump host 10.0.2.15
03:48:06.087509 IP 10.0.2.15.22 > 10.0.2.2.50225: Flags [P.], seq 3862934963:3862934999, ack 65355639, win 37232, length 36
03:48:06.087806 IP 10.0.2.2.50225 > 10.0.2.15.22: Flags [.], ack 36, win 65535, length 0
03:48:06.088087 IP 10.0.2.15.22 > 10.0.2.2.50225: Flags [P.], seq 36:72, ack 1, win 37232, length 36
03:48:06.088274 IP 10.0.2.2.50225 > 10.0.2.15.22: Flags [.], ack 72, win 65535, length 0
03:48:06.088440 IP 10.0.2.15.22 > 10.0.2.2.50225: Flags [P.], seq 72:108, ack 1, win 37232, length 36

eth1 接口上,抓取特定协议类型的数据包,例如 icmp

# tcpdump -i eth1 icmp
04:03:47.408545 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 2812, seq 75, length 64
04:03:47.408999 IP 10.0.0.51 > vagrant-ubuntu-trusty-64: ICMP echo reply, id 2812, seq 75, length 64
04:03:48.408697 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 2812, seq 76, length 64
04:03:48.409208 IP 10.0.0.51 > vagrant-ubuntu-trusty-64: ICMP echo reply, id 2812, seq 76, length 64
04:03:49.411287 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 2812, seq 77, length 64

组合过滤器表达式

您可以将这些过滤器表达式与 ANDORNOT 运算符结合使用,以编写更精确的数据包筛选命令:

从特定 IP 发出并发送到特定端口的数据包:

# tcpdump -n -i eth1 src 10.0.0.1 and dst port 80
00:18:17.155066 IP 10.0.0.1.54222 > 10.0.0.50.80: Flags [F.], seq 500773341, ack 2116767648, win 4117, options [nop,nop,TS val 257786173 ecr 5979014], length 0
00:18:17.155104 IP 10.0.0.1.54225 > 10.0.0.50.80: Flags [S], seq 904045691, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 257786173 ecr 0,sackOK,eol], length 0
00:18:17.157337 IP 10.0.0.1.54221 > 10.0.0.50.80: Flags [P.], seq 4282813257:4282813756, ack 1348066220, win 4111, options [nop,nop,TS val 257786174 ecr 5979015], length 499: HTTP: GET / HTTP/1.1
00:18:17.157366 IP 10.0.0.1.54225 > 10.0.0.50.80: Flags [.], ack 1306947508, win 4117, options [nop,nop,TS val 257786174 ecr 5983566], length 0

要捕获除 ICMP 之外的所有数据包,可以使用 NOT 运算符:

# tcpdump -i eth1 not icmp

将数据包头部保存到文件

由于 tcpdump 的输出可能会在屏幕上快速滚动,您可以利用 -w 标志将数据包头部信息保存到文件中。 保存的文件会使用 pcap 格式,其扩展名为 .pcap

PCAP 代表数据包捕获。 以下命令会将 eth1 接口上的 10 行输出保存到名为 icmp.pcap 的文件中:

# tcpdump -i eth1 -c 10 -w icmp.pcap
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
10 packets captured
10 packets received by filter
0 packets dropped by kernel

您可以使用 -r 标志来读取此文件:

tcpdump -r icmp.pcap
reading from file icmp.pcap, link-type EN10MB (Ethernet)
05:33:20.852732 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 3261, seq 33, length 64
05:33:20.853245 IP 10.0.0.51 > vagrant-ubuntu-trusty-64: ICMP echo reply, id 3261, seq 33, length 64
05:33:21.852586 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 3261, seq 34, length 64
05:33:21.853104 IP 10.0.0.51 > vagrant-ubuntu-trusty-64: ICMP echo reply, id 3261, seq 34, length 64
05:33:22.852615 IP vagrant-ubuntu-trusty-64 > 10.0.0.51: ICMP echo request, id 3261, seq 35, length 64

查看数据包详细信息

到目前为止,我们只看到了数据包的头部信息。 要查看数据包的内容,请使用 -A 选项。 这将以 ASCII 格式打印数据包的内容,对于进行网络故障排除非常有帮助。 此外,-X 标志可用于以十六进制格式显示输出。 如果连接已加密,这些选项可能用处不大。

# tcpdump -c10 -i eth1 -n -A port 80
23:35:53.109306 IP 10.0.0.1.53916 > 10.0.0.50.80: Flags [P.], seq 2366590408:2366590907, ack 175457677, win 4111, options [nop,nop,TS val 255253117 ecr 5344866], length 499: HTTP: GET / HTTP/1.1
E..'[email protected]@.%.
...
..2...P..M.
uE............
.6.}.Q.bGET / HTTP/1.1
Host: 10.0.0.50
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-Modified-Since: Tue, 04 Mar 2014 11:46:45 GMT

总结

tcpdump 的设置过程非常简单。 一旦您理解了它的输出信息、各种标志以及过滤器,就可以使用它来解决网络问题并保护您的网络安全。