人人都会AI编程

11.5 数据包捕获:tcpdump 抓包基础与过滤规则

更新时间:2026-07-12

tcpdump 是 Linux 下最经典、最轻量的网络抓包工具。它不需要图形界面,直接输出数据包的头部信息和简要内容到终端,适合快速排查网络问题、分析协议交互过程。掌握它,无论在笔记本、服务器还是嵌入式设备上都能第一时间诊断网络异常。

1. 基本用法

最简单的抓包命令是让 tcpdump 监听某个网络接口:

sudo tcpdump -i eth0

它会不断输出所有经过 eth0 的数据包摘要。以下是一些常用选项:

  • -i any:监听所有接口。
  • -n:不将 IP 地址反向解析为主机名,不将端口号转为服务名,可以避免 DNS 查询带来的延迟和干扰。
  • -nn:同时禁用主机名和服务名解析,输出纯数字地址和端口,最为常用。
  • -c N:捕获 N 个包后自动退出。
  • -v-vv-vvv:输出更详细的信息(协议字段、TTL 等)。
  • -w file.pcap:将捕获的数据包存入文件,便于后续用 Wireshark 等工具分析。
  • -r file.pcap:从文件中读取包,而不是实时抓取。
  • -s snaplen:设置抓取的数据包快照长度,-s 0 表示完整抓取整个包,默认通常只抓前 96 字节,建议在需要完整载荷时手动加上。

日常排错中,最常用的基础命令形式是:

sudo tcpdump -i eth0 -nn

2. 读取输出信息

tcpdump 的每一行输出代表一个数据包,格式大致如下:

时间戳 协议 源地址.端口 > 目的地址.端口: 标志位 序列号/确认号 窗口大小 其他选项

例如:

14:32:10.123456 IP 192.168.1.10.54321 > 93.184.216.34.80: Flags [S], seq 123456789, win 64240, options [mss 1460], length 0
  • 14:32:10.123456 是精确到微秒的时间戳。
  • IP 表示使用 IP 协议。
  • 192.168.1.10.54321 > 93.184.216.34.80 表示从本地端口 54321 发往远程 80 端口。
  • Flags [S] 表示这是一个 SYN 包(TCP 连接请求)。
  • seqwinoptions 等是 TCP 具体信息。

关注 Flag 字段:

  • [S]:SYN(发起连接)
  • [S.]:SYN-ACK(响应连接请求)
  • [.]:ACK(确认)
  • [F]:FIN(结束连接)
  • [R]:RST(重置连接)
  • [P.]:PSH+ACK(数据推送)

通过这些标识可以快速判断 TCP 握手是否正常,连接是否被拒绝。

3. 过滤规则

在繁忙的网络接口上不加过滤地抓包会瞬间淹没终端,tcpdump 使用 BPF(Berkeley Packet Filter)语法 进行精准过滤。过滤器放在命令行的最后,支持多层条件组合。

3.1 按主机过滤

tcpdump host 192.168.1.100           # 所有收发到这个 IP 的包
tcpdump src host 192.168.1.100       # 源地址是该 IP
tcpdump dst host 192.168.1.100       # 目的地址是该 IP

3.2 按端口过滤

tcpdump port 80                        # 源或目的端口是80
tcpdump src port 54321                 # 源端口是54321
tcpdump dst port 443                   # 目的端口是443
tcpdump portrange 8000-8100            # 端口范围

3.3 按协议过滤

tcpdump tcp                            # 只看TCP包
tcpdump udp                            # 只看UDP包
tcpdump icmp                           # 只看ICMP包(如 ping)
tcpdump arp                            # 只看ARP包
tcpdump ip6                            # 只看IPv6包

3.4 组合过滤

使用 andornot 以及括号组合条件。括号在 Shell 中有特殊含义,需用引号保护或转义:

# 只看从192.168.1.10发往80端口的TCP包
tcpdump src host 192.168.1.10 and tcp dst port 80

# 只看来自192.168.1.20的非SSH(22端口)流量
tcpdump host 192.168.1.20 and not port 22

# 组合复杂条件:ICMP或目的端口为53的UDP(DNS)
tcpdump 'icmp or (udp and dst port 53)'

3.5 按特征过滤(高级)

# 看SYN包(TCP flags中SYN=1且ACK=0):tcp[tcpflags] & (tcp-syn) != 0
tcpdump 'tcp[tcpflags] & (tcp-syn) != 0 and tcp[tcpflags] & (tcp-ack) == 0'

# 抓取包含特定字节的数据包(偏移量 0 处为 GET )
tcpdump 'tcp and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'

这类过滤已经深入到包载荷,实际工作中更推荐先用 -w 保存再用 Wireshark 分析,但当环境只有命令行时,它极为强大。

4. 实用场景示例

排障 TCP 握手
单独监听与某主机的 TCP 三次握手:

sudo tcpdump -i eth0 -nn 'host 10.10.10.1 and tcp[tcpflags] & (tcp-syn) != 0'

你能清楚看到哪个方向没有回应 SYN-ACK,立即判断是网络不通还是服务未监听。

抓取 DNS 查询

sudo tcpdump -i any -nn port 53

输出中能看到完整的 DNS 请求和响应,快速定位域名解析故障。

实时抓取 HTTP 请求头

sudo tcpdump -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

-A 以 ASCII 显示包内容,-s 0 抓获完整数据,通过复杂过滤器找有数据载荷的包。更简洁的做法是先用 -w 保存再用 strings 命令:

sudo tcpdump -i eth0 -w http.pcap tcp port 80
strings http.pcap | grep -E '^(GET|POST|Host:)'

5. 注意事项

  • 抓包通常需要 root 权限(或 CAP_NET_RAW)。
  • 在生产服务器上抓包要注意磁盘空间和 CPU 占用,务必配合过滤器和 -c 限制数量,或使用 -W(文件轮转)等选项。
  • 明文抓取可能泄露敏感信息,连接加密协议(HTTPS、SSH)时只能看到密文,这是正常现象。
  • 对 VLAN 或隧道环境,可能需要指定接口或使用 -e 显示链路层头部。

tcpdump 的过滤语法初看起来有些晦涩,但掌握最常用的主机、端口、协议三件套,就已经能解决八成的网络诊断场景。它带来的价值在于:没有任何黑盒,任何一点网络异常都能被精确捕获并还原。