Tcpdump

tcpdump 是一个强大的命令行工具,用于捕获和分析网络流量。它是网络管理员、安全专业人员和开发人员在 Linux/Unix-like 系统上进行网络故障排除、监控、安全审计和协议分析的必备工具。

你可以把 tcpdump 想象成是给你的网卡安装了一双“透视眼”

它让你实时看到数据包是怎么在网络中穿梭的,从 MAC 层到 IP 层再到应用层,全都一览无遗。你不仅能“看到”别人说了什么(数据内容),还能知道他们从哪里来、去哪儿、用了哪种语言(协议)、走了哪条路(路由)

一、Tcpdump 核心概念:捕获与过滤

tcpdump 的核心功能:

  1. 实时数据包捕获tcpdump 可以实时地从网络接口捕获数据包,并将其内容打印到标准输出或保存到文件。
  2. 丰富的过滤表达式:它支持使用 BPF (Berkeley Packet Filter) 语法创建高度定制的过滤规则,只捕获你感兴趣的流量。
  3. 协议解析tcpdump 可以解析多种网络协议的头部信息,包括 Ethernet, IP, TCP, UDP, ICMP, ARP, DNS, HTTP 等,并以可读的格式显示。
  4. 远程捕获:由于是命令行工具,tcpdump 非常适合在没有图形界面的远程服务器上运行。
  5. 离线分析:可以将捕获的数据包保存为 .pcap 文件,供后续使用 tcpdump 本身或 Wireshark 等图形工具进行离线分析

二、Tcpdump 基本用法与常用选项

  • 基本语法sudo tcpdump [选项] [过滤表达式]

由于 tcpdump 需要访问网络接口的原始数据,因此通常需要 root 权限运行(使用 sudo)。

核心命令行选项:

  • -i <interface>:指定要监听的网络接口。
    • 示例:sudo tcpdump -i eth0 (监听 eth0 接口)
    • 示例:sudo tcpdump -i any (监听所有可用接口,但不使用混杂模式)
    • 可以通过 tcpdump -Dtcpdump --list-interfaces 查看所有可用接口。
  • -n:不解析主机名(显示 IP 地址)。这可以加快输出速度,并避免 DNS 解析带来的额外网络流量。
  • -nn:不解析主机名和端口号(显示 IP 地址和端口号)。
  • -v/-vv/-vvv :显示更详细的包信息。
  • -c <count>:指定捕获数据包的数量,达到数量后自动停止。
    • 示例:sudo tcpdump -c 10 -i eth0 (捕获 eth0 上的前10个数据包)
  • -w <file>:将捕获的数据包写入文件,文件格式为 .pcap
    • 示例:sudo tcpdump -w capture.pcap -i eth0 (将捕获的数据保存到 capture.pcap)
  • -r <file>:从指定的 .pcap 文件中读取数据包进行分析。
    • 示例:sudo tcpdump -r capture.pcap (读取 capture.pcap 并显示内容)
  • -v, -vv, -vvv:提高输出的详细程度(verbosity)。v 越多,显示的信息越多,包括 TTL、ID、报文长度等。
  • -A:以 ASCII 格式打印每个数据包的内容(用于查看 HTTP 等文本协议的数据)。
  • -X:以十六进制和 ASCII 格式打印每个数据包的内容(包括链路层头部)。
  • -XX:同 -X,但包含链路层头部。
  • -s <snaplen>:设置捕获的数据包的快照长度(snap length),即每个数据包捕获的字节数。默认通常很大 (e.g., 65535),这意味着捕获整个数据包。设置为 0 则表示捕获整个数据包。
    • 示例:sudo tcpdump -s 100 -i eth0 (只捕获每个数据包的前100字节)
  • -e:在输出中显示链路层头部信息(如 MAC 地址)。
  • -l:使输出行缓冲。这在将 tcpdump 的输出通过管道传递给其他命令(如 grep)时很有用。

三、精通过滤表达式 (BPF 语法)

过滤表达式是 tcpdump 最强大的功能之一。你可以通过它们来精确地指定你想要捕获的流量。过滤器可以由一个或多个“原语”(primitives)组成,并通过逻辑运算符 and (&&), or (||), not (!) 进行组合。

BPF(Berkeley Packet Filter) 是一种用于过滤网络数据包的表达式语言,最初用于 Unix 系统的 tcpdumplibpcap,现在广泛用于:

  • tcpdump
  • iptables/nftables
  • Wireshark
  • eBPF(扩展 BPF,用于内核监控、安全、可观测性)

BPF 表达式基本结构

BPF 表达式由若干部分构成,一般顺序如下:

1
[协议] [方向] [匹配类型] [操作符] [值]

这几项不是必须全部出现,可以按需组合。

  1. 类型(Type)限定符:指定要匹配的“类型”。

    • host <hostname/ip>:匹配特定主机。

      • tcpdump host 192.168.1.1 (捕获与 192.168.1.1 相关的所有流量)
    • net <network/cidr>:匹配特定网络。

      • tcpdump net 192.168.1.0/24 (捕获 192.168.1.0/24 网络的所有流量)
    • port <port_number>:匹配特定端口。

      • tcpdump port 80 (捕获所有端口 80 的流量)
    • portrange <port1-port2>:匹配端口范围。

      • tcpdump portrange 1024-65535
  2. 方向(Direction)限定符:指定流量方向。

    • src:源地址。
    • dst:目的地址。
    • src or dst: (默认)任意方向。
    • src and dst:必须同时匹配。
      • tcpdump src host 192.168.1.10 (捕获源自 192.168.1.10 的流量)
      • tcpdump dst port 22 (捕获目标端口为 22 的流量)
  3. 协议(Protocol)限定符:指定协议类型。

    • ether (以太网帧)
    • ip (IPv4)
    • ip6 (IPv6)
    • arp (ARP)
    • rarp (RARP)
    • tcp (TCP)
    • udp (UDP)
    • icmp (ICMP)
    • vlan (VLAN)
      • tcpdump tcp (捕获所有 TCP 流量)
      • tcpdump udp port 53 (捕获 UDP 协议的 DNS 流量)

逻辑运算符:

  • and (&&):与

  • or (||):或

  • not (!):非

  • = / !=

  • > / <

  • &(按位与)

  • 组合示例tcp and host 192.168.1.10 and port 80 (注意括号转义 \( \) 在 shell 中使用时的必要性)

组合过滤表达式:

使用 and, or, not (或它们的符号 &&, ||, !) 来组合过滤条件。

当使用逻辑运算符时,建议使用括号 () 来明确优先级,但需要注意在 shell 中使用括号时需要进行转义 ( 和 )。

  • tcpdump host 192.168.1.1 and port 22
  • tcpdump src host 192.168.1.10 and not dst port 22
  • tcpdump 'tcp port 80 or tcp port 443' (注意引号,避免 shell 解析 |)
  • tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' (捕获 SYN 包)
  • tcpdump icmp[icmptype] == icmp-echo (捕获 ping 请求)

字节偏移访问(BPF 原生命令)

BPF 支持通过偏移访问协议头部的特定字段,这种方式功能强大,能直接检查如 TTL、flags、窗口大小等底层内容。

格式如下:

1
2
proto[offset[:len]] op value
[协议名][偏移位置[:长度]] 操作符 值

例如:

1
2
3
4
5
6
tcp[13] & 0x02 != 0        # SYN
tcp[13] & 0x12 = 0x12 # SYN+ACK
tcp[13] & 0x04 != 0 # RST
tcp[13] = 0x02 # 仅 SYN
tcp[14:2] = 4096 # 窗口大小
ip[8] < 64 # TTL 小于 64

ip[8] 是 IPv4 报文中的 TTL 字段

tcp[13] 是 TCP 报文中的 flags 字节

tcp[14:2] 是 TCP 窗口大小字段(两个字节)

TCP Flags参考表(TCP/IP 报文结构):

Flag16进制描述
FIN0x01连接终止
SYN0x02发起连接
RST0x04连接复位
PSH0x08推送数据
ACK0x10应答确认
URG0x20紧急数据

组合示例:

1
2
tcpdump 'ip[9] = 6 and tcp[13] & 0x12 = 0x12 and port 80'
# 抓 TCP 包(协议号 = 6)且 同时带 SYN+ACK 标志 且 端口为 80(即服务端回应)

四、tcpdump 输出

tcpdump 的输出格式可能看起来很复杂,但它遵循一定的模式。一般信息包括:

1
时间戳 协议 源IP.源端口 > 目的IP.目的端口 标志: [数据] 序列号 确认号 窗口大小 选项 [数据长度]

例子:

1
14:30:00.123456 IP 192.168.1.10.54321 > 192.168.1.1.80: Flags [S], seq 1234567, win 29200, options [mss 1460,sackOK,TS val 123456 ecr 0], length 0
  • 14:30:00.123456:数据包捕获的时间戳。
  • IP:网络层协议(IPv4)。
  • 192.168.1.10.54321:源 IP 地址和源端口。
  • >:方向指示符。
  • 192.168.1.1.80:目的 IP 地址和目的端口。
  • Flags [S]:TCP 标志。S 表示 SYN (同步)。常见标志有 S (SYN), . (ACK), P (PSH), F (FIN), R (RST)。
  • seq 1234567:TCP 序列号。
  • win 29200:TCP 窗口大小。
  • options [...]:TCP 选项,如 MSS (最大段大小), SACK (选择性确认) 等。
  • length 0:应用层数据长度(不包括头部)。

五、Tcpdump 实践:常见网络问题诊断

核心理念:通过观察数据包的进出、序列号、标志位和时间戳来判断问题。

常用诊断用例与命令示例:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 1. 检查特定主机的所有流量:快速判断主机网络活动。
sudo tcpdump -n -i eth0 host 203.0.113.5

# 2. 检查特定端口的流量:验证服务是否接收到请求或发出响应。
sudo tcpdump -n -i eth0 port 80
sudo tcpdump -n -i eth0 dst port 80 # 仅入站
sudo tcpdump -n -i eth0 src port 80 # 仅出站

# 3. 检查 TCP 连接的三次握手:诊断连接建立失败原因。
sudo tcpdump -n -i eth0 tcp and host 192.168.1.100 and port 22

# 4. 捕获 TCP RST (连接重置) 或 FIN (连接结束) 包:识别异常断开。
sudo tcpdump -n -i eth0 'tcp[tcpflags] & (tcp-rst|tcp-fin) != 0'

# 5. 检查 DNS 查询流量:排查域名解析问题。
sudo tcpdump -n -i eth0 udp port 53

# 6. 捕获 HTTP 流量 (显示 ASCII 内容):简单查看 Web 请求/响应。
sudo tcpdump -n -i eth0 port 80 -A

# 7. 分析网络延迟和丢包的用例:
# 延迟:通过 SYN/SYN-ACK 时间戳判断往返时间。
# 丢包:观察 TCP 重传、序列号跳跃、ICMP 不可达消息。
sudo tcpdump -n -i eth0 host <IP> and port <PORT> -vvv # 用于详细分析时间戳和序列号
sudo tcpdump -n -i eth0 icmp # 捕获ICMP错误消息

# 8. 验证防火墙规则是否按预期工作:
# 允许规则:看请求和响应是否都出现。
# 拒绝/丢弃规则:看请求是否到达但无响应 (DROP) 或收到 RST/ICMP (REJECT)。
sudo tcpdump -n -i eth0 tcp dst port 22 # 看是否收到SYN-ACK或RST

# 9. 捕获特定主机和端口相关的 RST 包
# 示例:监听 eth0 接口上与 203.0.113.5 和 8080 端口相关的 RST 包。
sudo tcpdump -n -i eth0 'tcp[tcpflags] & tcp-rst != 0' and host 203.0.113.5 and port 8080
# 10. 将捕获的数据保存到 .pcap 文件以供离线分析
# 示例:监听 eth0 接口上所有流量,并将数据保存到 my_capture.pcap 文件中。
# 按 Ctrl+C 停止捕获。
sudo tcpdump -n -i eth0 -w my_capture.pcap

# 11. 读取并分析已保存的 .pcap 文件
# 示例:读取并显示 my_capture.pcap 文件的内容。

sudo tcpdump -r my_capture.pcap
# 12. 将捕获的数据保存到 .pcap 文件以供离线分析

# 示例:监听 eth0 接口上所有流量,并将数据保存到 my_capture.pcap 文件中。
# 按 Ctrl+C 停止捕获。
sudo tcpdump -n -i eth0 -w my_capture.pcap

六、优化 Tcpdump 使用体验与进阶技巧

  • 屏幕输出控制:
    • Ctrl+S (暂停) / Ctrl+Q (恢复):最简单的实时控制。
    • 通过管道传输到 lesssudo tcpdump -l -i eth0 | less (分页查看)。
  • 实时保存与文件轮换:
    • -w <filename.pcap>:保存到文件。
    • -C <size> / -W <count> / -G <seconds>:实现文件自动轮换,管理存储空间。
    • 示例:sudo tcpdump -n -i eth0 -w /var/log/tcpdump/capture_%Y%m%d_%H%M.pcap -G 3600 -W 24
  • 与 Wireshark 结合:
    • 强调 tcpdump 捕获 .pcap 文件后,使用 Wireshark 进行可视化和深度分析是最佳实践。
  • 远程抓包:
    • 通过 SSH 结合 tcpdump 进行远程服务器上的抓包。
    • 示例:ssh user@host "sudo tcpdump -i eth0 -w - 'not port 22'" | wireshark -k -S -i -