简介:围绕Wireshark数据包分析实战(第3版)中的网络故障案例,这份PDF整理了一次DNS查询与区域传送问题的完整排查笔记。案例从工作站172.16.16.101访问总部应用服务器172.16.16.200失败并被捕获的首包开始,先后看到DNS A记录查询、服务器故障响应、分公司DNS服务器发出的TCP SYN连接请求。文档详细对比了UDP与TCP在DNS协议中的用途,解释了当响应过大或进行区域传送时DNS会切换至TCP的原因,并结合第7章关于区域传送的讨论,将故障指向总部与分公司DNS服务器之间的资源记录同步失败。通过嗅探中心办公室DNS服务器流量,发现SYN包实际从未到达服务器,最终定位为中心办公室路由器仅允许53端口的UDP流量而阻止TCP流量这一配置错误。资源共1个PDF文件,大小为644KB,以图文对照方式呈现,包含数据包截图与关键字段解读,适合网络工程师、运维人员及Wireshark学习者练习从现象到根因的排障方法。目前已有326人学习下载,可作为《Wireshark 数据包分析实战》第3版第10章的补充阅读材料。
1. Wireshark 数据包分析实战(第 3 版)到底在练什么
Wireshark 数据包分析实战(第 3 版)不是一本让你背协议的书,它解决的是工程师最怕的一类问题:网络明明是通的,接口却慢得离谱;服务端说没收到请求,客户端说早就发出去了;日志全绿,用户已经骂街。抓包那一刻,所有说法都要让位给数据包本身。这本书的实战之处,就是把抓包变成一种排障习惯,而不是偶尔打开看一眼的工具。标题里那个 10.5.2 分析,我理解为一次完整会话的标准拆法:连接建立、数据交换、连接释放。适合后端开发、运维、测试,以及所有被网络问题折磨过的人。
2. 抓包不是拿起就抓:抓包点、网卡与循环抓包配置
抓包前有三个决定必须先做:在哪抓、抓多久、抓多大。这三个决定错了,后面所有分析都白费,甚至可能抓出一份“看起来没问题”的包,把整个排障方向带偏。先讲抓包点选择,这是新手最容易忽略、也是实际排障里最致命的一环。
2.1 抓包点选择题:本机回环、物理网卡还是镜像口
抓本机进程之间的流量,选回环接口。Linux 下叫 lo,macOS 下是 Loopback: lo0。很多人在本机起了服务、本机访问,结果在以太网卡上抓了半天一条包都没有,就是因为本机访问本机的流量根本不经过物理网卡。回环接口抓到的是协议栈内部的流量,能看到 TCP 三次握手、应用层数据,但看不到真实线路上的电磁信号层面的问题。
抓“客户端到服务器”的真实路径,要把抓包点放在端点附近。放在客户端侧,DNS 解析、TCP 建连、TLS 握手、首字节响应整个链路都能看到;放在服务端侧,你能确认的是请求有没有真正到达服务端,以及服务端从收到请求到发出响应花了多久。这两类数据不能互相替代。排接口慢时,我一般会在两端同时抓,再对齐时间轴,这样才能回答“慢在哪一段”而不是“到底谁撒谎”。
还有一种常见做法是交换机镜像口,把业务口的流量复制一份出来。适合抓不方便停服的线上设备,但镜像口本身的丢包能力取决于交换机的硬件设计,在流量接近端口上限时会出现统计缺口,丢包率看着像网络问题,实际上是抓包姿势问题。记住一个原则:本机抓包用本机网卡,跨设备排障用镜像口,中间设备尽量不参与判断。
提示:抓无线网卡时,很多人把“混杂模式”和“射频监控模式”混为一谈。混杂模式只能收到网卡能解码的帧,射频监控模式才是把无线信道上的原始帧都收进来。两者入口不同,别选错。
2.2 用 tshark 找到网卡并启动循环捕获
图形界面首页会列出可用网卡,一眼能看到名字和 IP,但命令行方式更可靠,尤其在一台机器有多块网卡、多块虚拟网卡的环境里。先列出所有接口:
tshark -D这条命令会输出每个接口的编号、名称和描述。注意看描述列,业务口通常有明确的名字,比如 eth0、ens192,虚拟网卡往往是 veth、docker0、vmnet 之类。找到目标接口后,我习惯用 tshark 直接做带循环捕获的抓包,而不是开图形界面,因为长时间抓包时图形界面更容易被文件体积拖垮。
sudo tshark -i eth0 -f "tcp port 443 or tcp port 80" \ -b duration:60 -b files:5 -w /data/capture.pcapng参数说明:-i指定接口;-f是 BPF 捕获过滤器,在抓包阶段就把无关流量丢掉,能显著降低文件和 CPU 负载;-b duration:60表示每 60 秒滚动一个新文件,-b files:5表示最多保留 5 个文件,超过后自动删除最老的。组合起来就是一个 5 分钟滑动窗口:始终保留最近 5 分钟的包。-b还可以配合filesize用,比如每个文件到 100MB 就切换,同时满足体积和时间两个约束。
这里要强调:-f捕获过滤器属于 libpcap 的 BPF 语法,它只支持“是否抓这个包”的粗粒度过滤,比如按端口、按 IP、按协议。它不理解ip.addr这种 Wireshark 显示过滤器字段。抓包阶段的过滤是“丢掉的包永远找不回来”,所以宁可在抓的时候多放一点,也不要过滤太狠,除非你非常清楚目标流量特征。
2.3 环形缓冲与文件容量预算
很多人抓到一半发现磁盘满了,或者打开一个几个 G 的 pcapng 卡到怀疑人生。问题出在没做容量预算。环形缓冲的核心参数就三个:单文件大小、单文件时长、保留文件数。总占用大致等于三个参数的乘积。
| 参数组合 | 单文件大小 | 保留文件数 | 预计最大占用 |
|---|---|---|---|
| duration:60, files:5 | 视流量而定 | 5 | 约 5 分钟流量总量 |
| filesize:102400, files:10 | 100 MB | 10 | 约 1 GB |
| duration:300, files:4 | 视流量而定 | 4 | 约 20 分钟流量总量 |
保存格式也需要考虑。新版 Wireshark 默认写 pcapng,这种格式能保留多接口、注解、元数据,适合精细分析。但如果是长期无人值守的高流量环境,用-F pcap指定老式 pcap 格式写入开销更低,兼容性也更好。另一个容易忽略的点是合规性:抓包文件里往往包含完整应用数据,可能涉及敏感信息。分析完需要移交或归档时,用“导出特定分组”功能按需剥离,避免把整份文件到处复制。
3. 显示过滤器:九成协议分析都在这里完成
显示过滤器和捕获过滤器完全是两套东西。捕获过滤器在包进入内存之前就把包丢了,显示过滤器则是把已经抓到的文件里把关心的包筛选出来。数据包分析里绝大多数操作都是显示过滤器,所以它的语法和字段语义必须吃透。
3.1 先搞清字段语义,再谈语法技巧
显示过滤器是建立在 Wireshark 字段解析树上的,每一个过滤表达式都是在和字段打交道,而不是在做字符串匹配。最容易翻车的是ip.addr。它表示“源地址或目标地址任意一个匹配”,本质上是一个复合字段,等价于ip.src == x or ip.dst == x。于是你会看到这样两个常见错误:
错误:ip.addr == 192.168.1.10 and ip.addr == 192.168.1.20 正确:(ip.src == 192.168.1.10 and ip.dst == 192.168.1.20) or (ip.src == 192.168.1.20 and ip.dst == 192.168.1.10)前者的语义是“同一个包里源地址和目的地址同时等于两个值”,这在现实里不可能发生,结果永远是 0 包。后者才表达“两台主机之间的双向流量”。想要省事可以直接用tcp.stream来定位会话,这个字段在 Wireshark 里是每个 TCP 连接唯一的整数索引,右键任意一个 TCP 包选择“追踪流”,相当于自动执行了tcp.stream eq n。
还有优先级陷阱。tcp.port == 443 || 80不是“443 或 80 端口”,而是“443 端口,或者 80 这个值本身为真”。后者永远为真,导致过滤器把所有包都放行。每个比较必须写完整,不要依赖类似编程语言里的短路简化。语法错误时输入框会变红并提示,但语义错误不会变红,只能靠观察结果数量判断。写完过滤串先看一眼左下角状态栏的匹配包数量,这是最直接的校验方式。
3.2 常用过滤串清单:查表即用
下面这组过滤串是我在日常排障里用得最多的,覆盖建连、重传、DNS、TLS、慢请求几类核心场景。
| 分析场景 | 显示过滤器 | 说明 |
|---|---|---|
| 只看 TCP 建连请求 | tcp.flags.syn==1 and tcp.flags.ack==0 | 排除 SYN-ACK,只看发起方向 |
| 定位重传 | tcp.analysis.retransmission or tcp.analysis.fast_retransmission | 快速重传与超时重传分开看 |
| 找连接重置 | tcp.flags.reset==1 | RST 包出现的位置往往就是异常发生点 |
| 只看 DNS 请求 | dns.flags.response==0 | 响应是 1,请求是 0 |
| TLS 握手起始 | tls.handshake.type==1 | ClientHello 出现即握手开始 |
| 相邻包间隔过大 | tcp.time_delta > 0.2 | 两包间隔超过 200ms 的位置要关注 |
| 大包排查 | tcp.len > 1400 | 超过常规 MSS 的包往往涉及巨型帧 |
| 排除背景噪声 | !(icmp or arp or stp) | 把探测和广播协议踢掉 |
| ACK 响应耗时 | tcp.analysis.ack_rtt > 0.1 | 数据到 ACK 超过 100ms 说明接收侧处理慢 |
注意tcp.analysis.ack_rtt这类 Expert Info 字段不是标准 TCP 头里的字段,而是 Wireshark 根据文件内容计算出来的分析结果。它只在抓包文件具备完整时序信息时才有意义,单独的包是算不出 RTT 的。
3.3 把常用过滤串固化成按钮与 Profile
每次排障都重新输入一遍长过滤串没有意义。新版 Wireshark 支持多 Profile,每个 Profile 可以独立保存自己的显示过滤器按钮、着色规则、列配置。入口通常在右下角状态栏的 Profile 切换器,或者通过“编辑 → 配置说明文件”进入。新建一个名为“troubleshoot”的 Profile,然后把上一节那些过滤串逐个存成快捷按钮。
# Linux 下 Wireshark 配置目录常见位置 # 个人 Profile 目录:~/.local/lib/wireshark/profiles/ # Windows 下常见位置:%APPDATA%\Wireshark\profiles\把整个 Profile 目录复制到另一台机器的相同位置,就能实现团队内共享。新成员接手时直接切 Profile,看到的是同样一组过滤按钮和着色规则,不需要现场教一遍“重传要看哪个字段”。我维护的 Profile 里固定有六个按钮:重传、RST、DNS、TLS 握手、慢包间隔、大包,任何一次抓包进来先按这六类扫一遍,问题大致方位就出来了。这也是第 3 版里反复强调的“先全局后局部”的分析节奏。
4. 从 10.5.2 分析落地:单次会话拆解的标准三步
不管标题里的 10.5.2 是书里的练习编号,还是你自己工单里的分析项,方法是一致的:任何一次会话都可以拆成建连、数据交换、释放三个阶段。把每个阶段的时间量化出来,问题就藏不住。
4.1 第一步:从 SYN 定位流,把会话从文件里挖出来
拿到一份抓包文件,我不会从头开始翻,而是先找第一个 SYN 包,因为它是一个 TCP 会话真实的起点。命令行里这样找:
tshark -r login.pcapng \ -Y "tcp.flags.syn==1 and tcp.flags.ack==0" \ -T fields \ -e frame.number -e frame.time_relative \ -e ip.src -e tcp.srcport -e ip.dst -e tcp.dstport \ -e tcp.window_size_value参数说明:-r指定读取文件;-Y用的是显示过滤器语法,和图形界面的输入框完全一致;-T fields表示输出自定义字段;-e后面每一个参数对应一列输出。frame.number是包在文件里的序号,frame.time_relative是相对文件第一个包的时间,tcp.window_size_value是 SYN 包宣告的接收窗口,这个值能初步判断接收缓冲区大小。
找到 SYN 后,在图形界面里右键这个包,选择“追踪 TCP 流”,Wireshark 会自动用tcp.stream eq N过滤出整条会话。要注意:同一个文件里可能会有多个 SYN,说明有多次重连。此时按frame.time_relative排序,确认哪一次会话对应要排查的时间点,别把多轮重连当成一条流来分析。
4.2 第二步:调整时间列,让异常自己浮出来
默认的时间列是从抓包开始算的绝对时间,看单条流没问题,但多条流并行时很难对齐先后关系。我会先做两件事:把时间显示格式改成“自参考时间起算”,然后在流的第一个 SYN 包上设置时间参考,这样整条流的时间都从 0 开始,每一跳的间隔直接就是相对时间。再加一列tcp.time_delta,显示相邻两包的时间差,这个列是最直观的“卡顿探测器”。
与之配合的是“专家信息”面板,入口在“分析 → 专家信息”。它会按严重程度把所有异常汇总:重传、快速重传、零窗口、乱序、重复 ACK 全部列出来。重点看四个信号。
| 信号 | 过滤/查看方式 | 说明 |
|---|---|---|
| 重传 | tcp.analysis.retransmission | 数据超时未确认,常见于丢包或对端处理慢 |
| 零窗口 | tcp.window_size_value == 0 | 接收方缓冲区耗尽,应用没及时读走数据 |
| 乱序 | tcp.analysis.out-of-order | 序号跳变或后到先达,可能网络路径变化 |
| ACK RTT | tcp.analysis.ack_rtt | 数据到达对端到对端回 ACK 的时间 |
零窗口不能直接判死刑。它只代表接收缓冲区已满,可能只是应用层线程卡顿,不一定是网络问题。先用tcp.analysis.ack_rtt看响应速度,再用零窗口判断哪个方向的接收端处理不过来,两者配合才能定位是网络还是应用。
4.3 第三步:把 HTTP/TLS 的耗时拆到具体阶段
接口慢是最常见的诉求。一份包里如果有 DNS 查询、TCP 建连、TLS 握手和 HTTP 请求,我习惯按五个阶段拆:DNS 解析、TCP 建连、TLS 握手、服务端处理、响应传输。每一段都能在包里找到边界包:DNS 请求到 DNS 响应;SYN 到 SYN-ACK;ClientHello 到服务端 Finished;HTTP 请求的最后一个字节到响应第一个字节;响应开始到响应结束。
用 tshark 的统计模块可以快速量化:
tshark -r api.pcapng -q -z io,stat,1 -z conv,tcp-q表示不输出每个包,只输出统计结果;-z io,stat,1按 1 秒间隔统计包量和速率;-z conv,tcp输出 TCP 会话列表,包含每个连接的收发字节数、相对起始时间。先看conv,tcp找到目标连接,再用io,stat看那一时间段内的流量曲线,传输速率是否在该时间段内出现断崖,一目了然。
TLS 握手本身也要细拆。Wireshark 的“统计 → TLS 握手”会列出每个握手的协商套件和耗时,但如果想看加密后的应用数据往返耗时,就需要解密。开发自建服务时,最常见的方式是让服务端进程把会话密钥写入日志文件:
export SSLKEYLOGFILE=/tmp/dev_keys.log node server.js参数说明:SSLKEYLOGFILE是 OpenSSL、GnuTLS 等 TLS 库都支持的环境变量,进程启动后会把每个 TLS 会话的密钥写进这个文件。在 Wireshark 的“协议 → TLS”设置里填入/tmp/dev_keys.log,即可对抓到的 TLS 流量解密。注意三点:环境变量必须在启动目标进程的那个终端里先导出;密钥日志是持续追加的,解密失败先确认文件里有没有覆盖抓包时间段的记录;TLS 1.3 每次握手都产生新密钥,文件写入频率更高,要用会话建立前后的记录对照。
如果目标程序不是用 OpenSSL 这类支持密钥导出的库实现的,解密这条路走不通,就在客户端和服务端同时抓包做时间对齐,同样能拆出延迟分布。不要把解密当成必须的,抓包分析的核心是“确认谁在等谁”,而不是把每个字节读透。
5. 数据包分析高频踩坑:五条翻车记录
抓包的坑基本不在“按开始按钮”这一步,而在后续的分析姿势。下面五条都是实际排障现场反复出现的问题,按现象到原因再到解决写清楚,省得你再走一遍。
5.1 抓到一堆包,就是没有目标流量
现象:抓了十分钟,文件里全是 ARP、广播、NetBIOS 之类的背景流量,目标 IP 一个包都没有。
原因:抓包接口选错了。最常见的是本机回环和应用流量走的物理网卡不是同一个接口;另一类常见原因是登录远程服务器排障时,抓的是管理口,业务流量走的是另一个口。
解决:先用tshark -D列出所有接口,核对接口描述里的 IP 是否属于业务网段。拿不准时,在同一终端里ping目标地址,然后看抓包窗口里是否有对应 ICMP 请求包。有,说明接口选对了;没有,换接口重抓。这个验证动作只需要几秒钟,但能避免一小时的无效抓包。
5.2 过滤串写出来“感觉对了”,结果翻倍或归零
现象:同样一个 IP 地址,用ip.addr == 目标过滤出来大量单向包;用ip.addr == A and ip.addr == B过滤则直接归零。
原因:ip.addr的语义是“源或目标任意匹配”,等价于ip.src == x or ip.dst == x。两个ip.addr做 and 运算时,要求同一个包里的源和目的同时各命中一个条件,这在双向流量里几乎不可能成立。
解决:按 3.1 中的写法,把双向流量展开成两个方向的组合。或者更省事:先找到目标流里的任意一个包,右键追踪 TCP 流,用tcp.stream eq N定位完整会话,不碰ip.addr的复合语义。
5.3 时间列忽大忽小,误判了乱序
现象:同一流的包在时间列里乱跳,看起来像是网络乱序,但着色规则里又没有标出乱序。
原因:时间显示格式默认是相对文件开始时间,而一份 pcapng 文件里有多个接口、多段捕获时,时间戳交错是正常的。另外,TCP 乱序的判定依据是序号而不是时间戳,时间列倒挂并不等于网络乱序。
解决:把时间显示格式切到“自参考时间起算”,然后在目标流的 SYN 包上设置时间参考,让所有包从 0 开始计数。要判断乱序,直接看“分析 → 专家信息”里的 out-of-order 条目,而不是凭时间列肉眼判断。
5.4 TLS 解密始终失败,key 文件填了还是密文
现象:Protocol 设置里填了密钥日志文件路径,抓包里应用数据依然显示为Encrypted Application Data。
原因:要么密钥文件里没有覆盖抓包时段的记录,要么目标进程根本不是用的支持SSLKEYLOGFILE的 TLS 库。还有一种情况是抓包开始得比进程早,但密钥文件是进程启动后才创建的,导致前几个会话没有密钥。
解决:先清空密钥文件,再启动目标进程,确认抓包开始时间在密钥文件首条记录之后。再检查SSLKEYLOGFILE是否传到了真正执行 TLS 握手的那一层,很多语言框架里 SSL 卸载发生在独立模块,环境变量没传进去就不会写文件。都不行就两端抓包对比,别耗在解密上。
5.5 几个 G 的抓包文件一打开就卡死
现象:双击 pcapng,界面转圈几十秒,输入过滤串后更卡,最后只能强退。
原因:文件过大,所有包一次性读入内存;显示过滤器执行时要做全文件扫描,内存和时间全都扛不住。
解决:先用capinfos 文件.pcapng看包量、时长、平均速率,判断文件规模和复杂度。再用 editcap 按时间切分:
editcap -i 60 big.pcapng part.pcapng参数说明:-i 60表示每 60 秒切一个文件,输出的是一组part.pcapng-0、part.pcapng-1这样的分片。先定位问题时间段再切,比从一开始就全量打开理智得多。也可以在切分时顺手用-c按包数切分,适合时间跨度长但包量集中的文件。
提示:先 capinfos 再看包,是省内存也省心情的习惯。文件看一眼大小就打开,是新手最常见的浪费。
6. 三个值得固化的进阶习惯:把 Wireshark 用成网络画像工具
第一个习惯:任何抓包文件到手,先跑capinfos。不打开图形界面,只用一行命令拿到时长、包数、平均包速率、文件大小和是否有截断信息。我在区分“这个问题是否值得展开分析”时,靠的就是这几个数字,如果一份 5 秒的文件里有几十万个包,先怀疑是风暴类问题,而不是直接进去翻包。
第二个习惯:用 tshark 把抓包文件抽成资产清单。TLS 握手里的证书、HTTP 请求里的 User-Agent、DNS 查询里的域名,都是现成的特征。排障时经常需要回答“这个网段上到底有哪些设备在通信”,与其靠记忆,不如直接抽字段归档。提取 TLS 证书和 UA 都是单条命令的事,输出重定向到文本文件后还能做去重排序,比人工翻包快了不止一个量级。
第三个习惯:把常用排障动作固化成着色规则和 Profile。重传的包标红,RST 标橙,SYN 标绿,零窗口标紫。这样打开大文件后,先不被详情面板干扰,扫描一眼色块分布,异常区域自己就跳出来了。配合前面做的过滤按钮,新人拿到同一份 Profile,操作路径和老师傅完全一致。这个习惯本质上是把“经验”从人脑迁移到工具配置里。
有一回我连续抓了两个多小时,最后发现抓的是本机回环接口,而业务流量走的是物理网卡。那个教训让我养成一个习惯:每换一个环境,第一件事就是tshark -D确认接口名,再用 ping 包验证抓包点,最后才开始正式分析。抓包分析里,先确认数据是从哪儿来的,再谈数据说了什么。希望帮到你。
本文还有配套的精品资源,点击获取