tcpdump 命令详解与参数实测(Ubuntu 22.04)
在 Ubuntu 22.04 实测 tcpdump 常用参数:-i 接口选择、-n/-nn、-c、-w/-r、-A/-X/-s、host/net/port/src/dst 与 and/or/not 过滤、-v、-t、-l、-G/-W 轮转、-e 二层头,逐列解读回显与 TCP Flags,附 BPF 语法速查、-G 轮转降权限坑与 HTTP/DNS 实战,全部命令真实执行并记录回显。
tcpdump 命令详解与参数实测(Ubuntu 22.04)
一、环境信息
本文所有命令均在以下真实服务器环境中逐条执行并记录回显,读者可按相同条件复现:
- 操作系统:Ubuntu 22.04.5 LTS(
PRETTY_NAME="Ubuntu 22.04.5 LTS"),架构 x86_64,root 用户执行; - tcpdump 版本:
tcpdump version 4.99.1,libpcap version 1.10.1 (with TPACKET_V3),OpenSSL 3.0.2 15 Mar 2022(软件包版本4.99.1-3ubuntu0.2); - 网络接口:eth0(第一块网卡),本机地址
172.17.0.2/16,默认网关172.17.0.1;DNS 服务器192.168.146.2(内网解析,正反向均可用); - 出口链路:经 NAT 访问公网,
223.5.5.5(阿里云公共 DNS,反向解析名 public1.alidns.com)可达,RTT 约 21ms; - 本地演示固定装置:
python3 -m http.server 18080提供 HTTP 明文服务,站点根目录/root/demo/tcpdump/www,页面/index.html;实测时间以服务器时钟为准(回显时间戳为 2026-10-15 20 时段)。
⚠️ 说明:抓包需要 CAP_NET_RAW 原始套接字能力,本文以 root 执行。tcpdump 启动后会自动降权为
tcpdump用户运行(-Z默认行为),这一特性会在-w/-G小节产生真实影响(输出文件属主与轮转权限),详见 3.6 与 3.18 节。
二、命令概览
2.1 安装
tcpdump 在 Ubuntu Server 默认安装中通常已预装;未安装时通过 apt 安装即可。本机与 traceroute 同批重装(traceroute 详见同系列文档),安装命令与回显节选如下:
$ DEBIAN_FRONTEND=noninteractive apt-get install -y -qq traceroute tcpdump
Setting up tcpdump (4.99.1-3ubuntu0.2) ...
Setting up traceroute (1:2.1.0-2) ...
安装后位于 /usr/bin/tcpdump(软件包版本 4.99.1-3ubuntu0.2)。
2.2 语法与测试数据
tcpdump 的命令语法(取自 --help 原文):
Usage: tcpdump [-AbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ] [--count]
[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]
[ -i interface ] [ --immediate-mode ] [ -j tstamptype ]
[ -M secret ] [ --number ] [ --print ] [ -Q in|out|inout ]
[ -r file ] [ -s snaplen ] [ -T type ] [ --version ]
[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]
[ --time-stamp-precision precision ] [ --micro ] [ --nano ]
[ -z postrotate-command ] [ -Z user ] [ expression ]
两部分构成:选项(-i/-nn/-c/-w 等)控制「怎么抓、抓到哪」,过滤表达式(BPF 语法,写在命令末尾)控制「抓什么」——内核态先行过滤,只有匹配的包才送入用户态。本文测试数据约定:造流量目标 223.5.5.5(ping 测 ICMP、curl -sk https://223.5.5.5 测 TCP 443);本地 HTTP 固定装置 python3 -m http.server 18080 --directory /root/demo/tcpdump/www,页面 <h1>tcpdump demo page</h1>(27 字节);DNS 造流量用 python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" 强制发起一次 A 记录查询(比 getent 更可控)。后台抓包与造流量配合的长命令按分号拆行展示(语义与实测一致),每行回显均逐字取自实测日志。
2.3 --help 全量输出(逐行照抄)
$ tcpdump --help; echo rc=$?
tcpdump version 4.99.1
libpcap version 1.10.1 (with TPACKET_V3)
OpenSSL 3.0.2 15 Mar 2022
Usage: tcpdump [-AbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ] [--count]
[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]
[ -i interface ] [ --immediate-mode ] [ -j tstamptype ]
[ -M secret ] [ --number ] [ --print ] [ -Q in|out|inout ]
[ -r file ] [ -s snaplen ] [ -T type ] [ --version ]
[ -V file ] [ -w file ] [ -W filecount ] [ -y datalinktype ]
[ --time-stamp-precision precision ] [ --micro ] [ --nano ]
[ -z postrotate-command ] [ -Z user ] [ expression ]
rc=0
注意:tcpdump 的 --help 只给出选项速记(不是每个选项的说明),完整选项解释要查手册页(第六节给出链接)。退出码实测 rc=0。
2.4 版本信息
$ tcpdump --version
tcpdump version 4.99.1
libpcap version 1.10.1 (with TPACKET_V3)
OpenSSL 3.0.2 15 Mar 2022
libpcap 是 tcpdump 的抓包库,排查「抓包异常/丢包」时两者版本都要关注。tcpdump -D 可列出本机全部可抓接口(实测 8 个:eth0、any、lo、bluetooth-monitor、nflog、nfqueue、dbus-system、dbus-session),编号最前的 eth0 即不指定 -i 时的默认接口。
2.5 抓包回显逐列解读与同类工具对比
以一条典型抓包行为例(来源见 3.1 节完整回显):
20:03:54.210794 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [S], seq 2770491245, win 64240, options [mss 1460,sackOK,TS val 3014965719 ecr 0,nop,wscale 7], length 0
20:03:54.210794:抓到该包的时刻(默认时:分:秒.微秒,可用-t/-tttt变换格式,见 3.16 节);IP为网络层协议类型(IPv6 时显示IP6);f1034b9326b2.36366 > public1.alidns.com.https:源地址.源端口 > 目标地址.目标端口。默认对 IP 做反向解析(本机名 f1034b9326b2、对端 public1.alidns.com)、对端口做服务名解析(.https),加-nn后全部显示为数字(见 3.5 节);Flags [S]:TCP 控制位。[S]=SYN(发起连接)、[S.]=SYN+ACK(同意连接)、[.]=ACK(确认)、[P.]=PSH+ACK(推送数据)、[F.]=FIN+ACK(正常关闭)、[R.]=RST+ACK(异常重置)——组合读法见 4.4 节;seq 2770491245/ack 2770491246:TCP 序列号与确认号(相对序号,ack 1即「你的第一个字节我收到了」);win 64240/options [...]/length 0:窗口大小、TCP 选项(MSS、SACK、时间戳、窗口缩放)、应用层载荷字节数。
💡 技术拓展:Linux 下常用抓包/网络观测工具对比——
工具 交互形态 输出 特点与适用场景 tcpdump 命令行 文本 / pcap 文件 服务器标配、内核态 BPF 过滤性能好,本文主角 tshark 命令行 文本 / pcap Wireshark 的 CLI,解码能力最强(应用层字段级),依赖较重 Wireshark 图形界面 pcap + 交互分析 桌面分析 pcap 的最佳伴侣,服务器上用 tcpdump 抓、拉回本地看 ngrep 命令行 正则匹配报文内容 按「内容」抓包(如匹配 HTTP 关键字),轻量但协议解码弱 strace 命令行 系统调用 只看单个进程的收发(不经过网卡),与抓包互补 BPF 过滤原语速查(详见 man pcap-filter):
原语 示例 含义 host host 223.5.5.5源或目的为该地址 src / dst src host 223.5.5.5仅源 / 仅目的 net net 223.5.0.0/16匹配网段 port port 443源或目的端口 协议 tcp/udp/icmp匹配传输/网络层协议 组合符 and/or/not逻辑组合,可加括号
三、参数逐项实测
3.1 不指定 -i:默认抓第一块网卡(eth0)
不指定 -i 时,tcpdump 自动选择 -D 列表中的第一个可用接口(本机为 eth0),从启动起一直抓到手动停止;用 -c 10 让它抓满 10 包后自动退出,同时另开终端用 curl 造流量:
$ timeout 15 tcpdump -c 10 > /root/demo/tcpdump/cap_default.txt 2>&1 &
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ cat /root/demo/tcpdump/cap_default.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:03:54.210794 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [S], seq 2770491245, win 64240, options [mss 1460,sackOK,TS val 3014965719 ecr 0,nop,wscale 7], length 0
20:03:54.234062 IP public1.alidns.com.https > f1034b9326b2.36366: Flags [S.], seq 449200181, ack 2770491246, win 64240, options [mss 1460], length 0
20:03:54.234120 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [.], ack 1, win 64240, length 0
20:03:54.235644 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [P.], seq 1:518, ack 1, win 64240, length 517
20:03:54.235958 IP public1.alidns.com.https > f1034b9326b2.36366: Flags [.], ack 518, win 64240, length 0
20:03:54.239157 IP f1034b9326b2.48525 > 192.168.146.2.domain: 966+ PTR? 5.5.5.223.in-addr.arpa. (40)
20:03:54.240322 IP 192.168.146.2.domain > f1034b9326b2.48525: 966 1/0/0 PTR public1.alidns.com. (72)
20:03:54.257047 IP public1.alidns.com.https > f1034b9326b2.36366: Flags [P.], seq 1:2741, ack 518, win 64240, length 2740
20:03:54.257068 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [.], ack 2741, win 65535, length 0
20:03:54.257994 IP f1034b9326b2.36366 > public1.alidns.com.https: Flags [P.], seq 518:582, ack 2741, win 65535, length 64
10 packets captured
36 packets received by filter
0 packets dropped by kernel
逐块解读:
- 头两行:
verbose output suppressed...提示未加-v;listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes声明接口、链路类型与默认快照长度 262144 字节(截断对比见 3.10 节); - 第 1
3 行:TCP 三次握手7 行是 tcpdump 自身的反向解析查询——对 223.5.5.5 做 PTR 查询([S]→[S.]→[.](curl 向 223.5.5.5:443 发起 HTTPS 连接);第 4 行[P.]为 TLS ClientHello(517 字节,HTTPS 内容已加密只见长度);第 65.5.5.223.in-addr.arpa)得到 public1.alidns.com,默认不带-n时解析流量也会被抓到,是排障时常见的「意外流量」来源;第 8~10 行为服务端 TLS 握手响应(2740 字节)与后续确认; - 结尾三行摘要:
10 packets captured(tcpdump 实际读到的包)、36 packets received by filter(内核 BPF 匹配后交给它的包,含因-c 10未展示的)、0 packets dropped by kernel(内核缓冲区溢出丢弃数,非 0 说明抓包压力过大)。
3.2 -c:限定抓包数量,抓满自动退出
-c N 抓满 N 个匹配包后自动退出并打印摘要(见 3.1 结尾三行),避免手动 Ctrl+C。配合过滤表达式与 -c 2 抓一对 ICMP:
$ timeout 6 tcpdump -i eth0 -nn -c 2 'host 223.5.5.5' > /root/demo/tcpdump/f1.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/f1.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:04:52.484647 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 38, seq 1, length 64
20:04:52.505334 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 38, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
💡 要点:
-c统计的是「过滤后」的包数。上面的2 packets received by filter与captured相等说明没有丢包;若两者差距大(如 3.1 的 10 vs 36),说明匹配流量多于显示量,属正常截停。
3.3 -i any:抓所有接口(含方向标注)
-i any 同时监听全部接口,链路类型变为 LINUX_SLL2(Linux cooked v2),回显中会多出**接口名与方向(In/Out)**两列。eth0 Out / eth0 In 明确标注每个包从哪个接口、哪个方向进出,多网卡服务器排查「包到底从哪张卡走」时非常有用:
$ timeout 6 tcpdump -i any -nn -c 6 icmp > /root/demo/tcpdump/any2.txt 2>&1 &
$ ping -c 3 -i 0.3 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/any2.txt
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
20:10:54.455283 eth0 Out IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 51, seq 1, length 64
20:10:54.475838 eth0 In IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 51, seq 1, length 64
20:10:54.756314 eth0 Out IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 51, seq 2, length 64
20:10:54.776773 eth0 In IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 51, seq 2, length 64
20:10:55.057162 eth0 Out IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 51, seq 3, length 64
20:10:55.077597 eth0 In IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 51, seq 3, length 64
6 packets captured
6 packets received by filter
0 packets dropped by kernel
3.4 -i lo:抓回环接口
本机与本机之间的流量走 lo 接口(即使目的地址写的是本机 IP 172.17.0.2 也走 lo),对 127.0.0.1 的 HTTP 服务抓包:
$ nohup python3 -m http.server 18080 --directory /root/demo/tcpdump/www >/dev/null 2>&1 &
$ timeout 6 tcpdump -i lo -nn -c 4 'tcp port 18080' > /root/demo/tcpdump/lo2.txt 2>&1 &
$ curl -s -m 3 http://127.0.0.1:18080/index.html >/dev/null
$ cat /root/demo/tcpdump/lo2.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:11:00.085587 IP 127.0.0.1.45480 > 127.0.0.1.18080: Flags [S], seq 2722685666, win 65495, options [mss 65495,sackOK,TS val 727827580 ecr 0,nop,wscale 7], length 0
20:11:00.085592 IP 127.0.0.1.18080 > 127.0.0.1.45480: Flags [S.], seq 2908832226, ack 2722685667, win 65483, options [mss 65495,sackOK,TS val 727827580 ecr 727827580,nop,wscale 7], length 0
20:11:00.085597 IP 127.0.0.1.45480 > 127.0.0.1.18080: Flags [.], ack 1, win 512, options [nop,nop,TS val 727827580 ecr 727827580], length 0
20:11:00.085633 IP 127.0.0.1.45480 > 127.0.0.1.18080: Flags [P.], seq 1:90, ack 1, win 512, options [nop,nop,TS val 727827580 ecr 727827580], length 89
4 packets captured
26 packets received by filter
0 packets dropped by kernel
⚠️ 注意两个细节:① 抓本机服务一定要指定
-i lo(或-i any),在 eth0 上抓不到本机到本机的流量;② 回环上的包「发出又收到」被同一接口看到两次方向,26 packets received by filter是响应方向也匹配所致(抓包窗口内后续 HTTP 数据/FIN 包),而-c 4只展示前 4 个。
3.5 -n 与 -nn:停止名称解析
默认回显会把 IP 解析成主机名、端口解析成服务名(见 3.1 节 .https/.domain)。-n 不转换主机地址;-nn 进一步抑制协议等其余字段的名称转换(man 原文:-n 不转换主机地址,-nn 连协议与端口等也不转换):
$ timeout 6 tcpdump -i eth0 -n -c 2 'port 53' > /root/demo/tcpdump/cap_n.txt 2>&1 &
$ python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" >/dev/null
$ cat /root/demo/tcpdump/cap_n.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:04:17.972653 IP 172.17.0.2.51481 > 192.168.146.2.53: 60018+ A? www.baidu.com. (31)
20:04:17.977483 IP 192.168.146.2.53 > 172.17.0.2.51481: 60018 3/0/0 CNAME www.a.shifen.com., A 110.242.70.57, A 110.242.69.21 (90)
2 packets captured
2 packets received by filter
0 packets dropped by kernel
-nn 在此基础上的实测回显(本例中 -n 与 -nn 输出格式一致,差异见下方 💡):
$ timeout 6 tcpdump -i eth0 -nn -c 2 'port 53' > /root/demo/tcpdump/cap_nn.txt 2>&1 &
$ python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" >/dev/null
$ cat /root/demo/tcpdump/cap_nn.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:04:22.994503 IP 172.17.0.2.58644 > 192.168.146.2.53: 42702+ A? www.baidu.com. (31)
20:04:22.997293 IP 192.168.146.2.53 > 172.17.0.2.58644: 42702 3/0/0 CNAME www.a.shifen.com., A 110.242.69.21, A 110.242.70.57 (93)
2 packets captured
2 packets received by filter
0 packets dropped by kernel
💡 要点:解析行为有真实代价——3.1 节的默认抓包中,tcpdump 自己发出的 PTR 查询也被抓了进来;若 DNS 慢,回显还会卡顿。脚本化抓包一律加
-nn。顺带解读 DNS 报文:60018+是事务 ID 与「递归标志」,A?表示 A 记录查询,应答3/0/0= 3 条资源记录(1 条 CNAME 别名 www.a.shifen.com + 2 条 A 地址)/0 授权/0 附加。
3.6 -w:原始包写入 pcap 文件
-w 把原始报文(含链路层头)以 libpcap 格式落盘,供 Wireshark 等工具离线分析。造流量(ping + curl)的同时抓取 ICMP 与 TCP:
$ timeout 10 tcpdump -i eth0 -nn -w /root/demo/tcpdump/demo.pcap 'tcp or icmp' >/dev/null 2>&1 &
$ ping -c 2 -i 0.3 223.5.5.5 >/dev/null
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ ls -l /root/demo/tcpdump/demo.pcap
-rw-r--r-- 1 tcpdump tcpdump 4096 Oct 15 20:04 /root/demo/tcpdump/demo.pcap
⚠️ 注意文件属主是
tcpdump用户而非 root——tcpdump 启动后默认降权(-Z tcpdump),写出文件归该用户。这个特性在 3.18 节的轮转场景会引发真实的权限坑。
3.7 -r:读回 pcap 文件
-r 读取 pcap 并像实时抓包一样解析显示,过滤表达式同样生效:
$ tcpdump -nn -r /root/demo/tcpdump/demo.pcap 2>&1 | head -8
reading from file /root/demo/tcpdump/demo.pcap, link-type EN10MB (Ethernet), snapshot length 262144
20:04:27.717990 IP 192.0.2.1.80 > 172.17.0.2.39868: Flags [R.], seq 271339237, ack 2021831103, win 64240, length 0
20:04:28.003624 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 35, seq 1, length 64
20:04:28.024118 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 35, seq 1, length 64
20:04:28.304508 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 35, seq 2, length 64
20:04:28.324797 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 35, seq 2, length 64
20:04:28.328824 IP 172.17.0.2.50940 > 223.5.5.5.443: Flags [S], seq 1344610284, win 64240, options [mss 1460,sackOK,TS val 3014999837 ecr 0,nop,wscale 7], length 0
20:04:28.349538 IP 223.5.5.5.443 > 172.17.0.2.50940: Flags [S.], seq 1273132536, ack 1344610285, win 64240, options [mss 1460], length 0
读回后一切照旧:管道统计用 tcpdump -nn -r demo.pcap 2>/dev/null | wc -l(实测 10 包,首行提示走标准错误不计入行数);叠加过滤表达式用 tcpdump -nn -r demo.pcap 'icmp'(实测只回显 3 行 ICMP echo request/reply)。
💡 要点:第 1 行的
192.0.2.1.80 > 172.17.0.2.39868: Flags [R.]是抓包窗口内本机 80 端口收到的一笔复位置连接(服务器上其他业务的正常流量),说明-w忠实记录窗口内所有匹配包——真实服务器的抓包几乎总有「背景流量」,读回后靠过滤表达式聚焦。
3.8 -A:ASCII 显示应用层内容(抓 HTTP 明文)
-A 把每个包按 ASCII 渲染,抓 HTTP 等明文协议时可直读请求与响应。对本地 HTTP 服务抓完整会话:
$ timeout 6 tcpdump -i lo -nn -A -s0 'tcp port 18080' > /root/demo/tcpdump/http3.txt 2>&1 &
$ curl -s -m 3 http://127.0.0.1:18080/index.html
$ cat /root/demo/tcpdump/http3.txt
curl 返回页面内容 <h1>tcpdump demo page</h1>(与站点固定装置一致)。抓包文件内容如下(为控制篇幅,非数据包下方 1~2 行头部字节的乱码渲染行从略,仅保留三个数据包的字节行;所有行均逐字取自实测日志):
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:23:46.846536 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [S], seq 4100481317, win 65495, options [mss 65495,sackOK,TS val 728594341 ecr 0,nop,wscale 7], length 0
20:23:46.846543 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [S.], seq 2765856940, ack 4100481318, win 65483, options [mss 65495,sackOK,TS val 728594341 ecr 728594341,nop,wscale 7], length 0
20:23:46.846549 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [.], ack 1, win 512, options [nop,nop,TS val 728594341 ecr 728594341], length 0
20:23:46.846584 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [P.], seq 1:90, ack 1, win 512, options [nop,nop,TS val 728594341 ecr 728594341], length 89
E.....@.@..V..........F..ha&...............
+mw.+mw.GET /index.html HTTP/1.1
Host: 127.0.0.1:18080
User-Agent: curl/7.81.0
Accept: */*
20:23:46.846586 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [.], ack 90, win 511, options [nop,nop,TS val 728594341 ecr 728594341], length 0
20:23:46.848612 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [P.], seq 1:187, ack 90, win 512, options [nop,nop,TS val 728594343 ecr 728594341], length 186
E...ti@.@...........F........ha............
+mw.+mw.HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Date: Thu, 15 Oct 2026 20:23:46 GMT
Content-type: text/html
Content-Length: 27
Last-Modified: Thu, 15 Oct 2026 20:03:52 GMT
20:23:46.848640 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [.], ack 187, win 511, options [nop,nop,TS val 728594343 ecr 728594343], length 0
20:23:46.848659 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [P.], seq 187:214, ack 90, win 512, options [nop,nop,TS val 728594343 ecr 728594343], length 27
E..Otj@.@..<........F......g.ha......C.....
+mw.+mw.<h1>tcpdump demo page</h1>
20:23:46.848661 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [.], ack 214, win 511, options [nop,nop,TS val 728594343 ecr 728594343], length 0
20:23:46.848685 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [F.], seq 214, ack 90, win 512, options [nop,nop,TS val 728594343 ecr 728594343], length 0
20:23:46.848702 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [F.], seq 90, ack 215, win 512, options [nop,nop,TS val 728594343 ecr 728594343], length 0
20:23:46.848712 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [.], ack 91, win 512, options [nop,nop,TS val 728594343 ecr 728594343], length 0
12 packets captured
24 packets received by filter
0 packets dropped by kernel
一次 curl 的完整生命周期尽收眼底:[S]/[S.]/[.] 三次握手 → [P.] 携带 GET 请求原文(方法、路径、Host、User-Agent 一目了然)→ 服务端两个 [P.] 分别回 200 OK + 响应头 与 页面正文 → [F.] 两次挥手关闭。
3.9 -X:十六进制 + ASCII 双栏
-X 同时输出十六进制与 ASCII 两栏,适合核对报文字节(协议分析、payload 特征确认)。这里 dump 的是从 IP 头开始的 84 字节(无 -e 不含以太网头):首字节 45 = IPv4 + 头长 20 字节;0800 是 ICMP 类型/代码(echo request);da31 d16a 起 56 字节是 ping 的固定递增载荷(1011 1213...),请求与应答完全一致——可用它校验链路是否被中间设备改包。抓一对 ICMP 包:
$ timeout 6 tcpdump -i eth0 -nn -X -c 2 icmp > /root/demo/tcpdump/cap_x.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/cap_x.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:04:42.433647 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 36, seq 1, length 64
0x0000: 4500 0054 7648 4000 4001 3443 ac11 0002 E..TvH@.@.4C....
0x0010: df05 0505 0800 9fcd 0024 0001 da31 d16a .........$...1.j
0x0020: 0000 0000 e79d 0600 0000 0000 1011 1213 ................
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567
20:04:42.454173 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 36, seq 1, length 64
0x0000: 4500 0054 ee69 0000 7f01 bd21 df05 0505 E..T.i.....!....
0x0010: ac11 0002 0000 a7cd 0024 0001 da31 d16a .........$...1.j
0x0020: 0000 0000 e79d 0600 0000 0000 1011 1213 ................
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 3637 4567
2 packets captured
2 packets received by filter
0 packets dropped by kernel
3.10 -s:指定抓包快照长度(snaplen)
-s 限制每包抓取的字节数,只留头部时能减小文件、降低 CPU。-s 96 时监听头显示 snapshot length 96 bytes,且 hex dump 到 0x0050 行只有 2 字节(96 = 14 字节以太网头 + 82 字节 IP 包,后面被截断):
$ timeout 6 tcpdump -i eth0 -nn -s 96 -X -c 1 icmp > /root/demo/tcpdump/cap_s.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/cap_s.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 96 bytes
20:04:47.459065 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 37, seq 1, length 64
0x0000: 4500 0054 77b8 4000 4001 32d3 ac11 0002 E..Tw.@.@.2.....
0x0010: df05 0505 0800 5169 0025 0001 df31 d16a ......Qi.%...1.j
0x0020: 0000 0000 3001 0700 0000 0000 1011 1213 ....0...........
0x0030: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0040: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0050: 3435 45
1 packet captured
2 packets received by filter
0 packets dropped by kernel
与 3.9 节(默认 262144 字节,dump 到 0x0050 行共 4 字节 3435 3637)对比:-s 96 截掉了载荷尾部 2 字节。需要完整内容时用 -s 0(快照长度取接口上限,等价于「一包不落全抓」,3.8 节即用 -s0);只看 TCP 头部时可用 -s 96 这类小值省资源。
3.11 host / src / dst:按主机过滤
host 匹配「源或目的」(3.2 节的 f1 抓包即 host 223.5.5.5,一请求一应答两包);src host/dst host 只匹配单向。src host 223.5.5.5 只看对端发来的应答:
$ timeout 6 tcpdump -i eth0 -nn -c 2 'src host 223.5.5.5' > /root/demo/tcpdump/f2b.txt 2>&1 &
$ ping -c 2 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/f2b.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:11:10.119543 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 52, seq 1, length 64
20:11:11.120997 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 52, seq 2, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
dst host 223.5.5.5 只看本机发往对端的请求:
$ timeout 6 tcpdump -i eth0 -nn -c 2 'dst host 223.5.5.5' > /root/demo/tcpdump/f3b.txt 2>&1 &
$ ping -c 2 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/f3b.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:11:16.126445 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 53, seq 1, length 64
20:11:17.128037 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 53, seq 2, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
3.12 net:按网段过滤
net 223.5.0.0/16 匹配该 CIDR 内任意地址(可再配合 src net/dst net 定方向):
$ timeout 6 tcpdump -i eth0 -nn -c 2 'net 223.5.0.0/16' > /root/demo/tcpdump/f4.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/f4.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:07.560817 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 41, seq 1, length 64
20:05:07.581571 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 41, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
3.13 and / or / not:组合过滤
and 同时满足——只看回环上 18080 端口的 HTTP 流量:
$ timeout 6 tcpdump -i lo -nn -c 4 'host 127.0.0.1 and port 18080' > /root/demo/tcpdump/f5b.txt 2>&1 &
$ curl -s -m 3 http://127.0.0.1:18080/index.html >/dev/null
$ cat /root/demo/tcpdump/f5b.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:11:22.155640 IP 127.0.0.1.54178 > 127.0.0.1.18080: Flags [S], seq 1670553612, win 65495, options [mss 65495,sackOK,TS val 727849650 ecr 0,nop,wscale 7], length 0
20:11:22.155647 IP 127.0.0.1.18080 > 127.0.0.1.54178: Flags [S.], seq 1147967199, ack 1670553613, win 65483, options [mss 65495,sackOK,TS val 727849650 ecr 727849650,nop,wscale 7], length 0
20:11:22.155653 IP 127.0.0.1.54178 > 127.0.0.1.18080: Flags [.], ack 1, win 512, options [nop,nop,TS val 727849650 ecr 727849650], length 0
20:11:22.155690 IP 127.0.0.1.54178 > 127.0.0.1.18080: Flags [P.], seq 1:90, ack 1, win 512, options [nop,nop,TS val 727849650 ecr 727849650], length 89
4 packets captured
24 packets received by filter
0 packets dropped by kernel
or 任一满足——DNS 与 ICMP 混合流量(第 3 行是 A 记录查询 60308 > 192.168.146.2.53):
$ timeout 8 tcpdump -i eth0 -nn -c 3 'port 53 or icmp' > /root/demo/tcpdump/f6.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" >/dev/null
$ cat /root/demo/tcpdump/f6.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:17.594792 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 42, seq 1, length 64
20:05:17.615425 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 42, seq 1, length 64
20:05:17.626378 IP 172.17.0.2.60308 > 192.168.146.2.53: 60150+ A? www.baidu.com. (31)
3 packets captured
3 packets received by filter
0 packets dropped by kernel
not 取反——排除 ARP 与 ICMP,专注 TCP 业务流量(第 1 行为本机 80 端口一笔外部连接的 RST,属抓包窗口内的背景流量):
$ timeout 8 tcpdump -i eth0 -nn -c 4 'not arp and not icmp' > /root/demo/tcpdump/f7.txt 2>&1 &
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ cat /root/demo/tcpdump/f7.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:23.805112 IP 192.0.2.1.80 > 172.17.0.2.58186: Flags [R.], seq 808929172, ack 4172062551, win 64240, length 0
20:05:24.640007 IP 172.17.0.2.35752 > 223.5.5.5.443: Flags [S], seq 2494811916, win 64240, options [mss 1460,sackOK,TS val 3015056149 ecr 0,nop,wscale 7], length 0
20:05:24.660528 IP 223.5.5.5.443 > 172.17.0.2.35752: Flags [S.], seq 590684679, ack 2494811917, win 64240, options [mss 1460], length 0
20:05:24.660552 IP 172.17.0.2.35752 > 223.5.5.5.443: Flags [.], ack 1, win 64240, length 0
4 packets captured
6 packets received by filter
0 packets dropped by kernel
3.14 tcp / udp / icmp:按协议过滤
tcp——抓到 curl 发往 223.5.5.5:443 的 SYN/SYN-ACK 握手(也证明 443 端口可达);udp——抓到一次完整的 DNS 查询与应答(含 CNAME 与两条 A 记录);icmp 的实测评见 3.2 节(echo request/reply 成对出现)。
$ timeout 8 tcpdump -i eth0 -nn -c 2 'tcp' > /root/demo/tcpdump/p1b.txt 2>&1 &
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ cat /root/demo/tcpdump/p1b.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:11:36.584644 IP 172.17.0.2.43070 > 223.5.5.5.443: Flags [S], seq 1056067448, win 64240, options [mss 1460,sackOK,TS val 3015428093 ecr 0,nop,wscale 7], length 0
20:11:36.605856 IP 223.5.5.5.443 > 172.17.0.2.43070: Flags [S.], seq 339891721, ack 1056067449, win 64240, options [mss 1460], length 0
2 packets captured
17 packets received by filter
0 packets dropped by kernel
$ timeout 6 tcpdump -i eth0 -nn -c 2 'udp' > /root/demo/tcpdump/p2.txt 2>&1 &
$ python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" >/dev/null
$ cat /root/demo/tcpdump/p2.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:38.829566 IP 172.17.0.2.47749 > 192.168.146.2.53: 55930+ A? www.baidu.com. (31)
20:05:38.832351 IP 192.168.146.2.53 > 172.17.0.2.47749: 55930 3/0/0 CNAME www.a.shifen.com., A 110.242.70.57, A 110.242.69.21 (93)
2 packets captured
2 packets received by filter
0 packets dropped by kernel
3.15 -v / -vv / -vvv:详细程度递增
-v 解码并显示 IP 头字段(tos/ttl/id/offset/flags/proto/length)与协议细节(ICMP 的 id/seq、TTL 等),且不再有 verbose output suppressed 提示行;-vv 输出更多协议字段(本例 ICMP 无增量可见);-vvv 为最详级别(主要影响复杂协议如 ISAKMP/ESP 的解码),日常排障 -v 足够:
$ timeout 6 tcpdump -i eth0 -nn -v -c 2 icmp > /root/demo/tcpdump/v1.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/v1.txt
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:43.838821 IP (tos 0x0, ttl 64, id 49874, offset 0, flags [DF], proto ICMP (1), length 84)
172.17.0.2 > 223.5.5.5: ICMP echo request, id 43, seq 1, length 64
20:05:43.859392 IP (tos 0x0, ttl 127, id 514, offset 0, flags [none], proto ICMP (1), length 84)
223.5.5.5 > 172.17.0.2: ICMP echo reply, id 43, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
-vv 的实测回显(ICMP 场景与 -v 输出粒度一致,无增量字段,仅确认详细级别生效):
$ timeout 6 tcpdump -i eth0 -nn -vv -c 1 icmp > /root/demo/tcpdump/v2.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/v2.txt
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:05:48.863886 IP (tos 0x0, ttl 64, id 51593, offset 0, flags [DF], proto ICMP (1), length 84)
172.17.0.2 > 223.5.5.5: ICMP echo request, id 44, seq 1, length 64
1 packet captured
2 packets received by filter
0 packets dropped by kernel
💡 要点:请求
ttl 64(本机默认初值)、应答ttl 127——回包经 1 跳到达(128−1),且本环境出口为 NAT/代理形态。TTL 是判断「隔了几跳」的硬指标:应答 TTL 与常见初值(64/128/255)相减即为回程跳数。
3.16 -t 与 -tttt:时间戳格式
-t 不显示时间戳(关注内容时更清爽);-tttt 显示「年-月-日 时:分:秒.微秒」完整格式(跨天分析、与日志系统对时必备);另有两个冷门变体:-tt(Unix 纪元秒,便于脚本计算间隔)、-ttt(与上一包的相对时间差,看「每包间隔」最直观)。
$ timeout 6 tcpdump -i eth0 -nn -t -c 2 icmp > /root/demo/tcpdump/t1.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/t1.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 45, seq 1, length 64
IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 45, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
-tttt 的实测回显:
$ timeout 6 tcpdump -i eth0 -nn -tttt -c 2 icmp > /root/demo/tcpdump/t2.txt 2>&1 &
$ ping -c 1 223.5.5.5 >/dev/null
$ cat /root/demo/tcpdump/t2.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
2026-10-15 20:05:58.915005 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 46, seq 1, length 64
2026-10-15 20:05:58.935442 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 46, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
3.17 -l:标准输出行缓冲(配合管道实时处理)
tcpdump 默认向管道输出「块缓冲」,管道下游(grep/awk)要攒够一块才见到数据;-l 改为行缓冲,边抓边处理。典型组合:tcpdump -nn -l icmp | tee icmp.log | grep -i request(同时落盘与实时过滤)。实测用管道过滤 ICMP 行:
$ (timeout 6 tcpdump -i eth0 -nn -l -c 2 icmp 2>/dev/null | grep -i echo) &
$ ping -c 1 223.5.5.5 >/dev/null
20:06:03.940261 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 47, seq 1, length 64
20:06:03.960798 IP 223.5.5.5 > 172.17.0.2: ICMP echo reply, id 47, seq 1, length 64
3.18 -G / -W:按时间轮转写文件
-G 秒数 让 -w 每 N 秒换一个新文件;-W 数量 限制滚动文件数(配合 -C 则是按大小轮转)。文件名若含 %d 之外的 strftime 时间格式(如 %H%M%S)可保证文件名唯一。先看一个真实的权限坑:把轮转文件放进 root 属主的目录(/root/demo/tcpdump/rot/,755),首个文件能创建,但轮转重开文件时 tcpdump 已降权为 tcpdump 用户,报 Permission denied 后进程直接退出(g.log 连统计摘要都没打印),轮转后的包全部丢失:
$ rm -f /root/demo/tcpdump/rot/*
$ timeout 8 tcpdump -i eth0 -nn -w /root/demo/tcpdump/rot/t_%H%M%S.pcap -G 2 icmp > /root/demo/tcpdump/rot/g.log 2>&1 &
$ ping -i 0.3 -c 12 223.5.5.5 >/dev/null
$ ls -l /root/demo/tcpdump/rot/
total 8
-rw-r--r-- 1 root root 151 Oct 15 21:02 g.log
-rw-r--r-- 1 tcpdump tcpdump 822 Oct 15 21:02 t_210238.pcap
$ cat /root/demo/tcpdump/rot/g.log
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
tcpdump: /root/demo/tcpdump/rot/t_210240.pcap: Permission denied
修正:把输出目录放开给 tcpdump 用户可写(如 /tmp/gg 设 777,或预先 chown tcpdump),轮转立即正常——2 秒一个轮转点,实测 23 个包分布在 3 个文件中:
$ rm -f /tmp/gg/*; chmod 777 /tmp/gg
$ timeout 8 tcpdump -i eth0 -nn -w /tmp/gg/t_%H%M%S.pcap -G 2 icmp > /tmp/gg/g.log 2>&1 &
$ ping -i 0.3 -c 12 223.5.5.5 >/dev/null
$ ls -l /tmp/gg/
total 16
-rw-r--r-- 1 root root 164 Oct 15 21:02 g.log
-rw-r--r-- 1 tcpdump tcpdump 822 Oct 15 21:02 t_210247.pcap
-rw-r--r-- 1 tcpdump tcpdump 1620 Oct 15 21:02 t_210249.pcap
-rw-r--r-- 1 tcpdump tcpdump 252 Oct 15 21:02 t_210251.pcap
$ cat /tmp/gg/g.log
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
23 packets captured
23 packets received by filter
0 packets dropped by kernel
💡 要点与拓展:① 文件名中的
%系列按 strftime(3) 展开——若写成rot_%03d.pcap,%d会被展开为「日期中的日」(本例 15 日),所有轮转都写进同一个rot_015.pcap相互覆盖,实测最终只剩 1 个 138 字节的文件;②-W与-C 文件大小组合按「大小」滚动是长抓任务更常用的姿势;③ 长时间轮转务必给磁盘留空间并配置-z脚本压缩旧文件。
3.19 -e:显示二层链路层头(MAC 地址)
-e 在每行前追加链路层信息(以太网则为 MAC 地址与 ethertype):
$ timeout 6 tcpdump -i eth0 -nn -e -c 2 icmp > /root/demo/tcpdump/e1.txt 2>&1 &
$ ping -c 1 172.17.0.1 >/dev/null
$ cat /root/demo/tcpdump/e1.txt
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
20:06:20.300006 fe:7b:dc:56:f2:9d > e6:df:fb:96:2e:f4, ethertype IPv4 (0x0800), length 98: 172.17.0.2 > 172.17.0.1: ICMP echo request, id 49, seq 1, length 64
20:06:20.300038 e6:df:fb:96:2e:f4 > fe:7b:dc:56:f2:9d, ethertype IPv4 (0x0800), length 98: 172.17.0.1 > 172.17.0.2: ICMP echo reply, id 49, seq 1, length 64
2 packets captured
2 packets received by filter
0 packets dropped by kernel
fe:7b:dc:56:f2:9d 为本机 eth0 的 MAC,e6:df:fb:96:2e:f4 为网关的 MAC;length 98 也变为含 14 字节以太网头的帧长(84+14)。排查二层问题(MAC 冲突、漂移、VLAN 标签 vlan 原语)必加 -e。
四、实战示例
4.1 HTTP 明文排障全流程(本地服务)
组合 -i lo + host/port 过滤 + -A -s0,直接看到浏览器/curl 发了什么、服务端回了什么(完整实测回显见 3.8 节:GET /index.html HTTP/1.1 → HTTP/1.0 200 OK → <h1>tcpdump demo page</h1>)。把过滤对象换成业务端口(如 -i eth0 -A -s0 'host 10.0.0.5 and port 8080')即可用于真实服务,注意 HTTPS 流量在 -A 下只能看到 TLS 密文长度。
$ timeout 6 tcpdump -i lo -nn -A -s0 'tcp port 18080' > /root/demo/tcpdump/http3.txt 2>&1 &
$ curl -s -m 3 http://127.0.0.1:18080/index.html
$ cat /root/demo/tcpdump/http3.txt
(输出节选(实测关键行,完整回显见 3.8 节))
20:23:46.846536 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [S], seq 4100481317, win 65495, options [mss 65495,sackOK,TS val 728594341 ecr 0,nop,wscale 7], length 0
+mw.+mw.GET /index.html HTTP/1.1
Host: 127.0.0.1:18080
User-Agent: curl/7.81.0
Accept: */*
+mw.+mw.HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.10.12
Content-Length: 27
+mw.+mw.<h1>tcpdump demo page</h1>
验证结果:curl 拿到 <h1>tcpdump demo page</h1>(rc=0),抓包里请求行、响应状态行与响应体三段明文全部可读,证明本步排障链路成立。
4.2 抓一次 DNS 解析全程
命令与完整回显见 3.5 节 -n 实测(port 53 过滤 + getaddrinfo 造流量,查询 5ms 内应答)。解读:60018+ 是事务 ID 与递归标志,A? 表示 A 记录查询;应答 3/0/0 = 3 条资源记录(1 条 CNAME 别名 www.a.shifen.com + 2 条 A 地址)、0 授权、0 附加。排障要点:只见查询不见应答,检查 resolv.conf 指向的 DNS 是否可达(结合 ping);应答码为 3(NXDomain)说明域名不存在。
$ timeout 6 tcpdump -i eth0 -n -c 2 'port 53' > /root/demo/tcpdump/cap_n.txt 2>&1 &
$ python3 -c "import socket; socket.getaddrinfo('www.baidu.com', 80, socket.AF_INET, socket.SOCK_STREAM)" >/dev/null
$ cat /root/demo/tcpdump/cap_n.txt
(输出节选(实测首尾),完整回显见 3.5 节)
20:04:17.972653 IP 172.17.0.2.51481 > 192.168.146.2.53: 60018+ A? www.baidu.com. (31)
20:04:17.977483 IP 192.168.146.2.53 > 172.17.0.2.51481: 60018 3/0/0 CNAME www.a.shifen.com., A 110.242.70.57, A 110.242.69.21 (90)
2 packets captured
2 packets received by filter
0 packets dropped by kernel
验证结果:2 packets captured 与查询/应答各 1 包对上,查询到应答间隔约 5ms,本机 DNS 解析链路正常。
4.3 抓包存证,交给 Wireshark 深挖
服务器上只负责「抓到」,复杂解码交给桌面端(完整实测见 3.6/3.7 节):-w demo.pcap 落盘 → scp 拉回本地 → Wireshark 打开;服务器上可先用 -r + 过滤快速预览(tcpdump -nn -r demo.pcap 'icmp')确认抓没抓对,再用 | wc -l 统计包量。
$ timeout 10 tcpdump -i eth0 -nn -w /root/demo/tcpdump/demo.pcap 'tcp or icmp' >/dev/null 2>&1 &
$ ping -c 2 -i 0.3 223.5.5.5 >/dev/null
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ ls -l /root/demo/tcpdump/demo.pcap
$ tcpdump -nn -r /root/demo/tcpdump/demo.pcap 2>&1 | head -8
(输出节选(实测首尾),完整回显见 3.6/3.7 节)
-rw-r--r-- 1 tcpdump tcpdump 4096 Oct 15 20:04 /root/demo/tcpdump/demo.pcap
reading from file /root/demo/tcpdump/demo.pcap, link-type EN10MB (Ethernet), snapshot length 262144
20:04:27.717990 IP 192.0.2.1.80 > 172.17.0.2.39868: Flags [R.], seq 271339237, ack 2021831103, win 64240, length 0
20:04:28.003624 IP 172.17.0.2 > 223.5.5.5: ICMP echo request, id 35, seq 1, length 64
验证结果:pcap 文件非零落盘(4096 字节)、-r 读回能解析出链路层与报文行,说明存证文件有效,可放心交给 Wireshark。
4.4 读懂 TCP 握手与挥手(Flags 组合)
一次正常 HTTP 会话的 Flags 序列(实测见 3.8 节):[S](客户端 SYN)→ [S.](服务端 SYN+ACK,说明端口开放且可达)→ [.](三次握手完成)→ [P.](携带 GET 数据)→ [P.](服务端 200 OK)→ [F.]×2(双方正常关闭)。异常特征:只看到客户端反复 [S] 而无 [S.]——对端不可达或防火墙静默丢包;出现 [R.]——对端拒绝(端口未监听/被重置),实例见 3.7 与 3.13 节回显中的 Flags [R.]。
(输出节选(实测关键行):正常握手序列取自 3.8 节,[R.] 拒绝形态取自 3.7 节)
20:23:46.846536 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [S], seq 4100481317, win 65495, options [mss 65495,sackOK,TS val 728594341 ecr 0,nop,wscale 7], length 0
20:23:46.846543 IP 127.0.0.1.18080 > 127.0.0.1.57346: Flags [S.], seq 2765856940, ack 4100481318, win 65483, options [mss 65495,sackOK,TS val 728594341 ecr 728594341,nop,wscale 7], length 0
20:23:46.846549 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [.], ack 1, win 512, options [nop,nop,TS val 728594341 ecr 728594341], length 0
20:23:46.846584 IP 127.0.0.1.57346 > 127.0.0.1.18080: Flags [P.], seq 1:90, ack 1, win 512, options [nop,nop,TS val 728594341 ecr 728594341], length 89
20:04:27.717990 IP 192.0.2.1.80 > 172.17.0.2.39868: Flags [R.], seq 271339237, ack 2021831103, win 64240, length 0
验证要点:前三行 Flags [S] → [S.] → [.] 依次成对出现即三次握手完成;最后一行 [R.] 是读到 [R.] 形态时判定「对端拒绝」的直接证据。
4.5 定位「端口不通」的层次
先用 tcp 过滤确认 TCP 层(实测见 3.14 节:[S] 与 [S.] 成对 = 443 可达);再按 3.13 节组合 host + port 收窄到具体对端与端口;若只有 [S] 没有 [S.],配合 not arp and not icmp 排除二层与 ICMP 干扰后,即可判定为对端服务未监听或中间防火墙丢弃——再上 traceroute(同系列文档)定位是「哪一跳」开始丢。
$ timeout 8 tcpdump -i eth0 -nn -c 2 'tcp' > /root/demo/tcpdump/p1b.txt 2>&1 &
$ curl -sk -m 6 https://223.5.5.5 -o /dev/null
$ cat /root/demo/tcpdump/p1b.txt
(输出节选(实测首尾),完整回显见 3.14 节)
20:11:36.584644 IP 172.17.0.2.43070 > 223.5.5.5.443: Flags [S], seq 1056067448, win 64240, options [mss 1460,sackOK,TS val 3015428093 ecr 0,nop,wscale 7], length 0
20:11:36.605856 IP 223.5.5.5.443 > 172.17.0.2.43070: Flags [S.], seq 339891721, ack 1056067449, win 64240, options [mss 1460], length 0
2 packets captured
17 packets received by filter
0 packets dropped by kernel
验证结果:[S] 与 [S.] 在 21ms 内成对出现,判定 223.5.5.5:443 可达——这正是本节「端口通」判定的实测依据。
五、注意事项与常见问题
Q1:运行报 Operation not permitted?
抓包需要 CAP_NET_RAW 能力。root 用户天然具备;普通用户需 sudo 执行,或由管理员授予能力(setcap cap_net_raw+ep /usr/bin/tcpdump)。受限环境(无特权)下 tcpdump 无法抓包,可改用只读系统观测工具替代。
Q2:抓不到包,按什么顺序排查?
① 接口选对没有——tcpdump -D 确认,本机流量在 lo、跨机流量在业务口,拿不准就 -i any(见 3.3/3.4 节);② 过滤表达式方向写反没有——src/dst 是相对本机的(见 3.11 节);③ 流量真的存在吗——先 ping/curl 造一波;④ 过滤语法是否被 shell 吞了——表达式务必加引号(见 Q4);⑤ 内核是否匹配了但没显示——看 received by filter 与 captured 的差值(见 3.2 节)。
Q3:-n 与 -nn 到底差在哪?
man 原文:-n 不转换主机地址;-nn 连协议与端口等也不转换。本版本(4.99.1)实测中 -n 的回显端口已显示为数字(3.5 节 .53),默认则是 .domain/.https 服务名(3.1 节)——老文档「-n 只管地址、-nn 才管端口」的说法与本版行为有出入。脚本统一用 -nn 即可,还能避免 tcpdump 自身的 DNS 查询流量混入抓包结果。
Q4:过滤表达式为什么必须加引号?
BPF 表达式里的括号、and、主机名等会被 shell 优先解释;如 'not (host 1.2.3.4 or host 5.6.7.8)' 不加引号会被 shell 当作子命令执行而报语法错。习惯写法:单引号包住整个表达式,内部用双引号场景除外。表达式错误会在启动时立即报 syntax error,不会静默。
Q5:-w 写出的文件属主为什么是 tcpdump?以及轮转报 Permission denied?
tcpdump 启动后默认降权为 tcpdump 用户(-Z),文件属主随之改变(3.6 节实测)。由此推导:-G 轮转「重新打开文件」也以该用户身份进行——root 属主目录下轮转会报 Permission denied 并丢失后续包(3.18 节实测),务必保证输出目录对 tcpdump 用户可写(chmod/chown 或放 /tmp)。
Q6:长时间挂抓包要注意什么?
① 磁盘:-w 文件会持续膨胀,长任务用 -C 100(每 100MB 切文件)配 -W 20(滚动覆盖)并监控空间;② 性能:加精确过滤表达式减少进入用户态的包量,关注 dropped by kernel 是否非 0;③ 合规:抓包内容可能含用户敏感数据,落盘文件要有访问控制并及时清理;④ HTTPS 只能看到加密载荷(3.1 节实测可见长度但不可读内容);⑤ 退出方式:前台 Ctrl+C、后台 kill <pid>(勿用 kill -9,普通 TERM 即可让 tcpdump 刷出统计摘要并正常关闭 -w 文件,摘要三行含义见 3.1 节)。
六、参考链接
- tcpdump(1) 手册页:https://www.tcpdump.org/manpages/tcpdump.1.html
- pcap-filter(7) BPF 过滤语法手册:https://www.tcpdump.org/manpages/pcap-filter.7.html
- tcpdump & libpcap 官方站点:https://www.tcpdump.org/
- Ubuntu 22.04 (jammy) tcpdump 软件包页:https://packages.ubuntu.com/jammy/tcpdump
- Wireshark 官方站点(pcap 图形化分析):https://www.wireshark.org/