网络与 IP

tcpdump 抓包命令详解:参数、过滤表达式与排障用法

tcpdump 是 Linux 服务器上的命令行抓包工具,最常用的写法是 tcpdump -i eth0 -nn -c 100 'tcp and host 198.51.100.7 and port 443':-i 选网卡,-nn 不做名称解析,-c 抓够就停,引号里是过滤条件。要细看就加 -w 存成 pcap 文件,下载到电脑上用 Wireshark 打开。

作者 顶联产品团队发布于 7 分钟阅读

tcpdump 抓包的基本格式是 tcpdump -i 网卡 参数 '过滤表达式'。比如在服务器上只看 198.51.100.7 访问本机 443 端口的 TCP 包:tcpdump -i eth0 -nn -c 50 'tcp and host 198.51.100.7 and port 443'。-i 指定网卡,-nn 不把地址和端口换成名字,-c 50 抓够 50 个包自动停止,引号里是 BPF 过滤表达式。需要事后细看时,加 -w 文件名.pcap 把原始报文存下来,下载到电脑上用 Wireshark 分析。本文示例地址均取自文档专用网段:服务器 203.0.113.10,客户端 198.51.100.7。

tcpdump 是什么软件:安装、权限和选网卡

tcpdump 是一款开源的命令行抓包工具,由 Tcpdump Group 维护,底层用 libpcap 库收包,能在 Linux、BSD、macOS 上运行。它把经过网卡的报文逐个解析成一行文字,也可以把原始报文写成 pcap 文件。它的过滤语法(BPF)和 Wireshark 的捕获过滤器是同一套,在 tcpdump 里写熟的条件可以直接拿到 Wireshark 里用。

apt install tcpdump      # Debian、Ubuntu
dnf install tcpdump      # RHEL、Rocky、AlmaLinux 8 及以后,老版本用 yum
tcpdump --version        # 查看 tcpdump 和 libpcap 的版本
tcpdump -D               # 列出可以抓包的网卡

抓包需要 root 权限,或者由管理员单独授予抓包能力。最容易出错的一步是选网卡,抓错了网卡,过滤条件写得再对也是一片空白:

要看的流量 在哪块网卡上抓 说明
服务器的公网业务 配着公网 IP 的业务网卡,如 eth0、eno1 用 ip -br addr 查哪块网卡上有这个地址
不确定从哪块网卡进出 -i any 所有网卡一起抓,但不开混杂模式;较新的版本会在每行前标出网卡名和 In、Out 方向;经过 bond、网桥或 VLAN 子接口的包可能出现两次
本机访问本机 -i lo 访问 127.0.0.1 或本机自己的 IP,包都不经过物理网卡
链路聚合 整体看 bond0,看具体走哪条链路就抓成员口 cat /proc/net/bonding/bond0 查成员网卡
KVM 虚拟机 宿主机上对应的 vnet 网卡 virsh domiflist 虚拟机名 查虚拟机和 vnet 的对应关系
Docker 容器 容器的网络命名空间 用下面的 nsenter 命令,容器里不用装 tcpdump
# 进入名为 web 的容器的网络命名空间,用宿主机上的 tcpdump 抓它的 eth0
nsenter -t "$(docker inspect -f '{{.State.Pid}}' web)" -n tcpdump -i eth0 -nn -c 20

tcpdump 参数详解:常用的 15 个

参数 作用 用法与注意
-i eth0 指定网卡 不写时自动选一块已启用的非回环网卡,容易选错,建议每次都写上
-n、-nn 不做名称解析 -n 不把 IP 反查成主机名,-nn 连端口和协议也显示数字。不同版本对单个 -n 是否转换端口名处理不一,习惯写 -nn 最稳妥。不加时每个地址都要做 DNS 反查,输出变慢,还会产生额外的 DNS 流量
-c 100 抓够 N 个包后退出 防止忘了停止;和 -w 一起用时,写够 N 个包就退出
-w 文件.pcap 把原始报文写入文件 屏幕上不再逐行打印;tcpdump 4.99 起可以加 --print 边存边看,老版本没有这个选项
-r 文件.pcap 读取抓包文件 可以再加过滤条件,从大文件里筛出一部分
-s 128 每个包只截取前 N 字节 -s 0 表示完整长度,较新的版本默认就抓完整的包(262144 字节);只看报头时截短,文件小,也不留业务内容
-v、-vv 显示更多报头字段 TTL、IP ID、总长度、TCP 选项等,排查 TTL 和分片问题时用
-e 显示二层帧头 打印源、目的 MAC 和 VLAN 标签,用来核对网关 MAC、查地址冲突
-A、-X 显示报文内容 -A 按 ASCII 显示,-X 按十六进制加 ASCII 显示,用来看明文 HTTP 请求头、Redis 命令
-tttt、-ttt 时间戳格式 -tttt 带日期,方便和日志对时间;-ttt 显示与上一个包的间隔
-l 行缓冲输出 输出接管道交给 grep、tee 时加上,否则结果要攒一大块才出来
-Q in、-Q out 只抓一个方向 Linux 上可用,部分平台不支持
-p 不把网卡设为混杂模式 只收本机该收的包:发给本机的单播,以及广播、组播
-B 8192 内核抓包缓冲区大小,单位 KiB 大流量下统计里出现 dropped by kernel 时调大
-C、-G、-W 按大小或时间轮转文件 见后文“用 -w 保存”一节

几个常用组合:

tcpdump -i eth0 -nn -c 20 icmp                                   # 看 ping 的请求和应答
tcpdump -i eth0 -nn -tttt -l 'udp port 53' | tee /tmp/dns.txt    # 带日期时间,同时存一份文本
tcpdump -i eth0 -nn -A -s 0 'tcp dst port 80'                    # 看明文 HTTP 请求头
tcpdump -i eth0 -nn -e -c 10 arp                                 # 带 MAC 地址看 ARP 请求和应答

过滤表达式:抓取指定 IP 和端口的 TCP 包

过滤表达式由三类关键字组合而成:对象(host、net、port、portrange)、方向(src、dst,不写表示两个方向都算)、协议(tcp、udp、icmp、arp、ip6),再用 and、or、not 连起来。常见需求的写法:

需求 表达式
与某个 IP 有关的所有包,双向 host 198.51.100.7
只看这个 IP 发来的包 src host 198.51.100.7
只看发往本机 22 端口的包 dst port 22
指定 IP 和端口的 TCP 包 tcp and host 198.51.100.7 and port 3306
某个网段 net 198.51.100.0/24
一段连续端口 portrange 30000-30100
这个 IP 的 80 或 443 端口 host 198.51.100.7 and (port 80 or port 443)
DNS 查询 udp port 53
只看新建连接的 SYN tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn
只看 RST tcp[tcpflags] & tcp-rst != 0
ICMP 不可达 icmp[icmptype] == icmp-unreach
IPv6 地址 ip6 and host 2001:db8::10
排除自己的 SSH 会话 not (host 192.0.2.5 and port 22)

写的时候注意四点:

  1. 整个表达式用单引号括起来。括号、!、& 在 shell 里有特殊含义,不加引号会被 shell 先解释掉,报语法错误。
  2. and 和 or 的优先级相同,从左到右结合。host 198.51.100.7 and port 80 or port 443 实际含义是“(这个 IP 且 80 端口) 或 所有人的 443 端口”,会抓进一大堆无关的包。想表达“这个 IP 的 80 或 443”,必须加括号。
  3. port 不分 TCP 和 UDP。port 443 同时匹配 TCP 443 和 UDP 443(HTTP/3 走 UDP 443),只要 TCP 就写成 tcp port 443 或 tcp and port 443。
  4. 按抓包点看到的地址写条件。客户端在 NAT 后面时,服务器上看到的是它出口的公网 IP,而不是它的内网地址;拿不准就先只按端口过滤,看清地址后再收紧。

在所有网卡上找某个 IP 的流量,是排查多网卡服务器时的常用写法:

tcpdump -i any -nn host 198.51.100.7

看懂输出:一行 TCP 包里有什么

一次 HTTPS 连接的开头,在服务器上抓到的输出是这样的(示例):

10:15:02.381245 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [S], seq 2814473922, win 64240, options [mss 1460,sackOK,TS val 1520637 ecr 0,nop,wscale 7], length 0
10:15:02.381290 IP 203.0.113.10.443 > 198.51.100.7.51544: Flags [S.], seq 90233411, ack 2814473923, win 65160, options [mss 1460,sackOK,TS val 88123 ecr 1520637,nop,wscale 7], length 0
10:15:02.412870 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [.], ack 1, win 502, options [nop,nop,TS val 1520668 ecr 88123], length 0
10:15:02.413511 IP 198.51.100.7.51544 > 203.0.113.10.443: Flags [P.], seq 1:518, ack 1, win 502, options [nop,nop,TS val 1520669 ecr 88123], length 517

从左到右依次是:时间戳;IP 表示 IPv4(IPv6 显示 IP6);源地址.源端口 > 目的地址.目的端口,最后一段数字是端口;Flags 是 TCP 标志;seq 和 ack 是序号和确认号,握手之后 tcpdump 默认改用相对值,加 -S 显示原始值;win 是接收窗口;length 是这个包携带的数据字节数,不含报头。

标志位里 S 是 SYN(发起连接),点号是 ACK,P 是 PSH(携带数据),F 是 FIN(正常关闭),R 是 RST(强制复位)。所以 [S] 是连接请求,[S.] 是服务器同意建连,[R.] 是拒绝或强制断开。

ICMP 和 UDP 的输出更简单,ping 的序号和端口不可达都直接写在行里:

10:20:11.004512 IP 198.51.100.7 > 203.0.113.10: ICMP echo request, id 3021, seq 17, length 64
10:20:11.004560 IP 203.0.113.10 > 198.51.100.7: ICMP echo reply, id 3021, seq 17, length 64
10:21:40.770031 IP 203.0.113.10 > 198.51.100.7: ICMP 203.0.113.10 udp port 9999 unreachable, length 36

用 -w 保存到文件:-c、-C、-G 控制大小

屏幕输出适合边抓边看,复杂问题要存下来,交给 Wireshark 看重传、时序和协议细节:

# 写够 5000 个包自动退出,文件名带上日期时间
tcpdump -i eth0 -nn -c 5000 -w /tmp/api-$(date +%m%d-%H%M).pcap 'tcp port 8080'

# 每 300 秒换一个文件,写满 12 个(共 1 小时)后自动退出
tcpdump -i eth0 -nn -G 300 -W 12 -w '/tmp/cap-%Y%m%d-%H%M%S.pcap' 'host 198.51.100.7'

# 从已有的文件里只挑出 RST 包,另存一个小文件
tcpdump -nn -r /tmp/cap-20261222-101500.pcap -w /tmp/rst.pcap 'tcp[tcpflags] & tcp-rst != 0'

# 直接按文本查看文件内容
tcpdump -nn -r /tmp/rst.pcap | head -20

几个容易踩的坑:

  • -w 写的是二进制 pcap,不是文本。把屏幕输出重定向成 tcpdump ... > a.pcap,得到的是文字,Wireshark 打不开;反过来,-w 的文件用 cat 看是乱码,要用 tcpdump -r 或 Wireshark 读。
  • 用 -G 时文件名里要带时间格式。不带 %H%M%S 这类占位符,每个新文件都会覆盖上一个。按大小轮转用 -C,单位是百万字节,配合 -W 限制文件个数,写满后从第一个开始覆盖。
  • 先估算文件有多大。1 Gbps 的流量跑满时每秒 125 MB,完整抓包一分钟就是约 7.5 GB。只需要看连接建立、重传、时序这些报头信息时,加 -s 128 截短,一般够装下以太网、IP 和 TCP 报头,文件能小一个数量级,也不会把业务内容留在磁盘上。
  • 看清停止时的统计。按 Ctrl+C 后,tcpdump 会打印抓到、过滤通过和被内核丢弃的包数。dropped by kernel 不为 0,是 tcpdump 自己没来得及收,属于漏抓,不能当成网络丢包;处理办法是收紧过滤条件、改成写文件而不是打印、用 -B 加大缓冲区。

端口不通、丢包:两端同时抓包定位

单点抓包只能说明“这里看到了什么”,要回答“包丢在哪”,最有效的办法是两端同时抓,用同一组条件对照。

端口不通:服务器和客户端各抓一份

# 服务器 203.0.113.10 上:-i any 能看出包从哪块网卡进出
tcpdump -i any -nn 'host 198.51.100.7 and tcp port 8080'

# 客户端 198.51.100.7 上:同时开始抓,再从另一个窗口发起连接
tcpdump -i eth0 -nn 'host 203.0.113.10 and tcp port 8080'
nc -zv -w 3 203.0.113.10 8080

判断依据有一个前提:在 Linux 上,tcpdump 看到的入方向包发生在本机防火墙处理之前,出方向包则是已经通过了本机防火墙的。对照两端的输出:

客户端看到 服务器看到 结论 下一步
SYN 反复重发(Linux 上间隔约 1、2、4 秒) 没有任何包 包在路上被丢:安全组、机房 ACL、上游防火墙或路由 从服务器往外逐段排查
SYN 重发 收到 SYN,没有回应 多半是本机防火墙把 SYN 丢了 查 iptables、nftables 或 firewalld 的入方向规则
收到 [R.] 收到 SYN,回了 [R.] 端口上没有程序监听 用 ss -lntp 'sport = :8080' 确认服务是否在运行、监听在哪个地址
SYN 重发 收到 SYN,也发出了 [S.] 回程出了问题:回包从别的网卡或别的源 IP 发出、路由不对称被沿途的状态防火墙丢弃,或交换机的源地址校验丢掉了源 IP 不属于该端口的包 用 ip route get 198.51.100.7 看回包从哪块网卡、用哪个源地址发出
收到 ICMP 不可达 回了 ICMP,或者服务器上什么也没看到 被 REJECT 规则拒绝,或路由不可达 看 ICMP 包的源地址,就知道是哪台设备拒绝的

第四行最容易被忽略:服务器明明回了包,客户端却收不到,问题不在应用,也不在入方向的防火墙,而在回程。多网卡、多 IP 的服务器尤其要查这一项。

丢包:对照 ping 序号判断去程还是回程

ping 的每个请求都带递增的序号,两端一对就知道丢在哪个方向:

# 1. 服务器上开始抓,同时存一份文本
tcpdump -i eth0 -nn -l 'icmp and host 198.51.100.7' | tee /tmp/icmp.txt

# 2. 客户端上发 200 个 ping,记下最后统计的收到数
ping -c 200 -i 0.2 203.0.113.10

# 3. 服务器上按 Ctrl+C 停止,统计收到的请求数、发出的应答数,并找出缺了哪些序号
grep -c 'echo request' /tmp/icmp.txt
grep -c 'echo reply' /tmp/icmp.txt
awk '/echo request/{for(i=1;i<=NF;i++) if($i=="seq"){s=$(i+1)+0; if(p && s!=p+1) print "缺少 " p+1 " 到 " s-1; p=s}}' /tmp/icmp.txt

假设客户端显示 200 个只收到 188 个,对照服务器上的计数:

服务器收到请求 服务器发出应答 客户端收到 结论
200 200 188 丢在回程,即服务器到客户端方向
188 188 188 丢在去程,即客户端到服务器方向
200 188 188 服务器自己没回:有 ICMP 限速规则或者系统过忙

确定方向之后,把抓包点往中间移动,例如客户端的出口网关、机房边界设备,或者在交换机上做端口镜像,范围就能逐步缩小。还要注意,不少网络设备会对 ICMP 限速或低优先级处理,ping 丢包不一定代表业务丢包;业务是 TCP 的,用 -w 抓一段业务流量,在 Wireshark 里看重传比例,结论更可靠。

在管理系统里怎么落地

抓包之前,先要知道该在哪台机器、哪个端口上抓。Toplink DCIM 的实时流量图带异常检测,网络 TOP 排行能快速定位高占用的节点;服务器列表里直接显示它接在哪台交换机的哪个端口、端口速率和 VLAN,需要在交换机侧查计数或配镜像时,可以在交换机管理里打开浏览器终端,会话全程录像。

上面“服务器回了 SYN-ACK、客户端却收不到”的情况,在开启了源地址校验的机房里有一个常见原因:服务器私自加了一个没有分配给它的 IP,交换机只放行源 IP 属于该端口的流量,用这个地址回的包被直接丢弃。到 IP 地址管理里核对这台服务器名下分配了哪些地址,比在服务器上反复抓包更快。如果网络已经断到 SSH 登不上,就通过 IPMI 远程管理打开 VNC 控制台,在服务器本地执行 tcpdump 并写入文件,等网络恢复后再下载分析。

常见问题

tcpdump 抓包会影响服务器性能吗?

加了过滤条件、写入文件时开销很小。在大流量网卡上不加过滤、把每个包都打印到终端,会明显占用 CPU,经 SSH 回传的输出还会制造更多流量。生产环境抓包要加过滤,用 -c 或 -G、-W 限定范围,只看报头时用 -s 截短。

tcpdump 能抓到 HTTPS 的内容吗?

能抓到包,但内容是加密的:看得到双方 IP、端口、握手时序,通常还能从 TLS 握手里看到访问的域名(SNI),看不到 URL 和正文。要分析明文,得在 TLS 终止之后的环节抓,例如反向代理到后端的明文段,或者把会话密钥导出给 Wireshark 解密。

Windows 上能用 tcpdump 吗?

tcpdump 主要用在 Linux、BSD、macOS 上,Windows 上一般不用它,而是装 Wireshark。Wireshark 自带命令行版 tshark,用 -i 选网卡、-f 写捕获过滤条件、-w 保存文件,捕获过滤语法和 tcpdump 相同。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88