Linux服务器如何抓取网络数据包?tcpdump命令实战教程

排查网络问题,日志看不出来、监控指标也正常,最后往往得靠抓包。数据包在网络里到底长什么样、谁先发的、有没有丢、有没有被重置,抓一份 pcap 一看就清楚。而 Linux 上最通用、几乎每台机器都有的抓包工具就是 tcpdump。

这篇文章从安装讲起,把常用参数、过滤表达式、几组实战场景、配合 Wireshark/tshark 分析的方法,以及权限和性能注意事项一次讲清楚。目标是让你遇到"服务不通""连接重置""响应慢"这类问题时,能立刻抓出有用的包,而不是抓一大堆看不过来。

一、安装 tcpdump

大多数发行版可以直接从仓库装:

# RHEL / CentOS / Rocky / AlmaLinux 7(yum)
sudo yum install -y tcpdump

# RHEL / CentOS / Rocky / AlmaLinux 8/9(dnf)
sudo dnf install -y tcpdump

# Debian / Ubuntu
sudo apt update && sudo apt install -y tcpdump

# 验证
tcpdump --version

如果机器不能上网,也可以从发行版镜像站下载对应的 rpm/deb 包本地安装。抓包要读原始套接字,需要 root 权限,或者给二进制文件授予 CAP_NET_RAW/CAP_NET_ADMIN 能力。

二、先认清网卡和基本用法

抓包第一步是选对网卡。机器上可能有物理网卡、docker0、隧道接口等,抓错网卡什么都看不到。

# 查看可用接口(-D 列出接口)
tcpdump -D

# 查看系统网卡
ip link show

tcpdump -D 的输出会给出接口编号和名称,比如 eth0、ens33、lo。用 -i 指定:

# 抓 eth0 上的流量,-nn 不解析主机名和端口名,-c 抓 10 个包后停止
sudo tcpdump -i eth0 -nn -c 10

# 抓所有接口(any)
sudo tcpdump -i any -nn -c 10

# 抓本地回环
sudo tcpdump -i lo -nn -c 10

不加 -i 时 tcpdump 会挑一个默认接口,不一定是你要的,所以养成显式指定 -i 的习惯。

怎么看 tcpdump 的输出

抓包容易,看懂才是关键。一行典型的 TCP 输出大概长这样:时间戳、源 IP.源端口、目的 IP.目标端口、TCP 标志、序号、确认号、窗口大小、长度。比如 10.0.0.5.52134 > 10.0.0.8.443: Flags [S], seq 12345, win 64240, length 0,意思是从 10.0.0.5 的 52134 端口发往 10.0.0.8 的 443 端口,标志位是 SYN,初始序号 12345,窗口 64240,没有携带数据。

几个核心要点记住就能读懂绝大多数包:

  • 方向箭头:> 表示发出,< 表示收到。看清是谁发的,是定位问题的第一步。
  • 标志位:[S] SYN 建连、[S.] SYN+ACK、[.] 纯 ACK、[P.] 带数据的 ACK、[F.] FIN 关闭、[R] RST 重置。方括号里有 . 表示 ACK 置位。
  • 序号与确认号:默认显示的是相对序号(相对第一个包),加 -S 显示绝对序号,分析重传和乱序时更有用。
  • length:载荷长度,length 0 说明是纯控制包,没有应用数据。
  • win:通告窗口大小,能侧面反映接收端缓冲区情况。

再看协议端口就能串起一条连接的故事:先 [S] 后 [S.] 再 [.],连接建立;中间大量 [P.] 是数据传输;出现 [F.] 是开始关闭;如果中途冒出一个 [R],说明连接被强制重置,往往就是故障点。理解了这套"读包语言",抓包才真正产生价值。

三、常用参数速查

参数 作用 说明
-i <接口> 指定网卡 any 表示所有接口
-nn 不解析主机名和端口 更快,避免 DNS 反查干扰
-s0 抓完整包(snaplen 0) 新版本默认就是全包
-c 抓 N 个包后退出 避免无限抓
-w <文件> 写入 pcap 文件 供后续分析
-r <文件> 读取 pcap 文件 分析已抓的包
-A 以 ASCII 显示载荷 看 HTTP 文本内容
-X 十六进制 + ASCII 显示 看二进制内容
-v / -vv / -vvv 显示更详细信息 看 TTL、校验等
-e 显示链路层头 看 MAC 地址
-S 显示 TCP 绝对序号 便于分析握手挥手
-t 不显示时间戳 输出更简洁
-q 精简输出 高流量下减少开销
-Z <用户> 抓包后切换到指定用户 降低权限风险

提示:老版本 tcpdump 默认只抓 96 字节,导致看不到完整载荷,需要 -s0(或 -s 65535)抓全包。较新版本默认已抓全,但写上 -s0 更保险。

四、过滤表达式:只抓有用的包

抓包最大的问题是量太大。过滤表达式(BPF 语法)是核心技能,掌握后抓包效率翻倍。

按主机过滤

# 源或目的为某 IP
sudo tcpdump -i eth0 -nn host 192.168.1.100

# 只要源 IP
sudo tcpdump -i eth0 -nn src 192.168.1.100

# 只要目的 IP
sudo tcpdump -i eth0 -nn dst 192.168.1.100

按端口过滤

# 某端口(源或目的)
sudo tcpdump -i eth0 -nn port 80

# 源端口
sudo tcpdump -i eth0 -nn src port 3306

# 目的端口
sudo tcpdump -i eth0 -nn dst port 443

# 端口范围
sudo tcpdump -i eth0 -nn portrange 8000-9000

按协议过滤

# 只看 TCP / UDP / ICMP
sudo tcpdump -i eth0 -nn tcp
sudo tcpdump -i eth0 -nn udp
sudo tcpdump -i eth0 -nn icmp

# 仅 IPv6
sudo tcpdump -i eth0 -nn ip6

逻辑组合

# and:同时满足
sudo tcpdump -i eth0 -nn 'host 192.168.1.100 and port 80'

# or:满足其一
sudo tcpdump -i eth0 -nn 'port 80 or port 443'

# not:排除
sudo tcpdump -i eth0 -nn 'host 10.0.0.5 and not port 22'

# 复杂组合:来自某网段访问 80 或 443 的 TCP 包
sudo tcpdump -i eth0 -nn 'tcp and src net 192.168.1.0/24 and (port 80 or port 443)'

注意:表达式里带括号、and/or 这类关键字时,整体用单引号包起来,避免被 shell 解释。

过滤表达式写得好不好,直接决定抓包效率。新手常见做法是只写 tcpdump -i eth0,结果满屏包刷个不停,关键信息淹没在噪声里。正确思路是先明确"我要看什么":是某台机器的问题,就写 host;是某个端口的问题,就写 port;是抓控制包还是数据包,就用 tcp[tcpflags] 进一步受限。一层层缩小范围,包的数量往往能从每秒几万降到每秒几条,问题一眼就能看出来。反过来,如果一开始过滤写得太死,也可能把关键的 ICMP 错误、RST 包漏掉,所以建议先用较宽松的条件确认有流量,再逐步收紧。

五、几个实战场景

场景一:抓某个服务的 TCP 握手和挥手

# 抓 443 端口的 SYN/FIN/RST,观察连接建立与释放
sudo tcpdump -i eth0 -nn -S 'tcp port 443 and (tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0)'

看输出:Flags [S] 是 SYN,[S.] 是 SYN+ACK,[.] 是 ACK,[F.] 是 FIN+ACK,[R] 是 RST,[P.] 是 PSH+ACK(带数据)。通过序号和标志就能还原握手挥手全过程。

场景二:抓 HTTP 请求内容

# 抓 80 端口并显示 ASCII 载荷,能看到请求行和响应头
sudo tcpdump -i eth0 -nn -A 'tcp port 80'

# 只抓 GET 请求
sudo tcpdump -i eth0 -nn -A 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'

注意 HTTPS 内容是加密的,-A 只能看到 TLS 握手记录,看不到真正的 HTTP 报文。要分析 HTTPS 内容需要密钥或采用其他手段。

场景三:抓指定 IP 之间的流量并保存成文件

# 抓 10.0.0.5 与 10.0.0.8 之间的流量,写入文件,最多抓 1000 个包
sudo tcpdump -i eth0 -nn -s0 -c 1000 -w /tmp/capture.pcap 'host 10.0.0.5 and host 10.0.0.8'

# 读取并查看
tcpdump -nn -r /tmp/capture.pcap -c 20

# 按端口再看
tcpdump -nn -r /tmp/capture.pcap 'tcp port 3306'

场景四:抓 RST 包定位连接重置

# 只抓带 RST 标志的包
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'

# 抓 RST 并显示详细信息,看是谁发出的
sudo tcpdump -i eth0 -nn -S 'tcp[tcpflags] & tcp-rst != 0' -vv

看 RST 的来源 IP 和目标端口,就能判断是服务端拒绝(端口没监听会直接回 RST)还是中间设备插了一脚。

场景五:抓 DNS 查询

# 抓 53 端口
sudo tcpdump -i eth0 -nn port 53

# 抓 DNS 查询,-vv 能看到查询的域名
sudo tcpdump -i eth0 -nn -vv port 53

六、配合 Wireshark / tshark 分析

tcpdump 擅长抓,Wireshark 擅长解析和可视化。最佳实践是:服务器上用 tcpdump 抓成 pcap,下载到本地用 Wireshark 打开。

# 服务器上抓包,限制大小防止占满磁盘
sudo tcpdump -i eth0 -nn -s0 -w /tmp/issue.pcap -C 100 -W 5 'host 10.0.0.8'

-C 100 表示每个文件最多 100 MB(1,000,000 字节),-W 5 表示保留 5 个文件循环覆盖,避免把磁盘写满。

如果想在服务器上直接分析,用 tshark(Wireshark 的命令行版):

# 安装(RHEL 系)
sudo dnf install -y wireshark-cli
# 安装(Debian/Ubuntu)——注意会弹出是否允许普通用户抓包的选项
sudo apt install -y tshark

# 用 tshark 读 pcap 并做统计
tshark -r /tmp/issue.pcap -q -z io,stat,1
# 统计 HTTP 请求
tshark -r /tmp/issue.pcap -Y http.request -T fields -e http.host -e http.request.uri
# 跟踪一条 TCP 流
tshark -r /tmp/issue.pcap -z follow,tcp,ascii,0

Wireshark 里最常用的几个功能:Follow TCP Stream(跟踪整条流)、Statistics → Conversations(看通信对端)、专家信息(自动提示重传、乱序、RST)。

七、权限与性能提示

权限:抓包要 root。长期让服务以 root 抓包不安全,可以用能力或让 tcpdump 抓完切换到普通用户:

# 给 tcpdump 授予抓包能力(避免每次 sudo)
sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump

# 抓包后切换身份
sudo tcpdump -i eth0 -Z nobody -w /tmp/x.pcap

性能:tcpdump 在高流量网卡上会消耗 CPU 并可能丢包(内核抓包缓冲不够)。几个缓解手段:

  • 加过滤条件,只抓需要的包,别用 any 全量抓。
  • 用 -c 限制包数、-C/-W 限制文件大小,防止磁盘和内存被占满。
  • 用 -q 减少输出开销,用 -w 直接落盘而不是打印到终端。
  • 提高抓包缓冲(-B)以减少丢包:sudo tcpdump -i eth0 -B 4096 -w /tmp/x.pcap。

风险提示:抓包文件包含明文流量(如 HTTP 请求、登录凭据),属于敏感数据。不要在共享环境随意存放,分析完及时删除;涉及生产数据时注意脱敏与合规要求。高流量下长时间抓包可能影响业务,建议限时限量,并在非高峰期操作。

常见问题

Q:抓不到包是什么原因?
A:常见三类:网卡选错(用 tcpdump -D 确认)、过滤表达式写错(先用 -nn 不过滤试一下)、流量根本没走这台机器(比如经过交换机旁路、或走了别的网卡/隧道)。

Q:为什么抓到的包看不到内容?
A:可能是 HTTPS 加密(看不到明文 HTTP),也可能是 snaplen 太小没抓全包,加 -s0。用 -A 或 -X 看载荷。

Q:-nn 到底省了什么?
A:不加 -nn 时 tcpdump 会尝试把 IP 反查成主机名、把端口号转成服务名,每次都要查 DNS,既慢又可能产生额外流量,还可能因为反查超时而拖慢输出。排查问题时用 -nn 既快又清晰。

Q:抓包影响业务吗?
A:正确使用(加过滤、限数量、限时长)影响很小。无过滤、长时间、全量抓包会吃 CPU、内存和磁盘,极端情况下会丢包甚至影响业务,务必克制。

Q:怎么抓本机进程之间的通信?
A:用 -i lo 抓回环接口,因为本机进程互访走的是 lo,不经过物理网卡。

总结

  • tcpdump 是 Linux 最通用的抓包工具,装好后用 -D 认接口、-i 指定网卡、-nn 免解析、-s0 抓全包、-c 限数量。
  • 过滤表达式是效率关键:host、src/dst、port、portrange、tcp/udp/icmp,配合 and/or/not 组合,整体加单引号。
  • 实战常用:抓握手挥手(tcp[tcpflags] & (tcp-syn|tcp-fin))、抓 HTTP 内容(-A)、抓指定 IP 落盘(-w)、抓 RST 定位重置。
  • 服务器抓包存成 pcap,下载到本地用 Wireshark 分析,或用 tshark 在服务器上直接统计与跟踪流。
  • 抓包需 root,务必加过滤、限大小时长,注意抓包文件的敏感性和对业务的影响。