ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

DNS SERVFAIL根因追踪:TCP 53区域传送被路由器ACL静默丢弃

DNS SERVFAIL根因追踪:TCP 53区域传送被路由器ACL静默丢弃

简介:Wireshark 数据包分析实战(第3版)中的一节故障排查案例,适合网络运维、安全分析与协议学习人员参考。内容围绕分公司工作站访问总部应用失败的场景,演示如何从 DNS A 记录查询响应入手,利用 Wireshark 抓包逐层定位问题:先是 DNS 服务器返回 server failure,随后分公司 DNS 通过 TCP 53 端口与总部 DNS 通信,SYN 包未获回应,说明区域传送失败;最终经过中心办公室流量嗅探和路由器配置检查,发现路由器仅放行 UDP 53 而阻断 TCP 53,导致 DNS 区域传送无法完成。案例将 DNS 查询机制、区域传送原理、TCP/UDP 差异与抓包分析思路相结合,有助于提升真实网络故障的诊断能力。资源为 1 个 PDF 格式文档,大小 644KB,已有 327 人学习。读者可从中获得完整排查路径和协议细节解读,适合作为数据包分析入门或进阶时的辅助材料。

1. 一个 DNS SERVFAIL 就能让整个分公司瘫痪:先搞清故障链条再动手

DNS 故障是网络排错里最折磨人的一类:服务器明明活着、应用日志一片干净、客户端却集体报“连不上”,浏览器转几圈最后给你一个“无法解析服务器地址”。很多运维的第一反应是重启 DNS 服务、改 hosts、甚至重装客户端,结果折腾一整天问题照旧。这套路我太熟悉了——直到打开 Wireshark 抓到前两个数据包,才发现一切表象都指向一条被忽略的链路。本文复盘的就是某抓包分析实战手册里一个经典案例:工作站访问总部应用服务器失败,第一包 DNS 查询返回“服务器故障”,根因却藏在 53 端口 TCP 流量被路由器丢弃这个细节里。适合正在被 DNS 解析失败、区域传送异常、SERVFAIL 报错卡住的网络工程师和运维同学。

2. 现象初判:A 记录查询返回服务器故障,先确认不是客户端“玄学”问题

2.1 原始抓包里到底发生了什么:两个数据包还原故障起点

先看场景:工作站172.16.16.101试图访问托管在总部应用服务器172.16.16.200上的应用程序,捕获文件里只有两个数据包。第一个包是工作站发给 DNS 服务器172.16.16.251的 DNS 请求,查询应用服务器的 A 记录——也就是把应用服务器的域名解析成172.16.16.200这个 IP。第二个包是 DNS 响应,应答码却是“服务器故障”(SERVFAIL),整包只有错误标志,没有携带任何查询结果。

打开抓包文件后,我一般先用下面的命令快速还原这两个包的轮廓:

tshark -r capture.pcap -Y "dns" -T fields \ -e frame.number -e ip.src -e ip.dst \ -e dns.qry.name -e dns.qry.type -e dns.flags.rcode

执行后你会看到类似这样两行:第一行是172.16.16.101 → 172.16.16.251的查询,dns.qry.type为1(A 记录);第二行是响应包,dns.flags.rcode为2。这里-Y "dns"过滤出所有 DNS 报文,-e指定要打印的字段,dns.flags.rcode就是应答码字段。看到 rcode 为 2,基本可以确认问题出在 DNS 解析链路本身,而不是客户端配置或应用层故障。

2.2 别把 SERVFAIL 当成“服务器宕机”:应答码是定位的第一把钥匙

很多同学看到“服务器故障”几个字就慌了,直接判断是 DNS 服务器挂了。这个误判在实战中出现的频率极高。DNS 应答码(RCODE)是排查时的第一把钥匙,常见取值就三个:

RCODE含义典型场景
0NOERROR查询成功,能拿到解析结果
2SERVFAILDNS 服务器无法完成查询,通常是上游链路或权威数据问题
3NXDOMAIN域名确实不存在

关键区别在于:SERVFAIL 意味着 DNS 服务器“想查但查不到”,服务器进程本身是活着的;NXDOMAIN 才是域名本身不存在。这个案例里 DNS 服务器能正常回应查询,说明它在线,真正断掉的是它获取解析数据的链条。如果此时你去重启 DNS 服务,相当于对着错误的方向开火,问题当然不会消失。所以收到 SERVFAIL 第一步不是动服务,而是把排查焦点移到“服务器是从哪里拿到这些记录的”。

2.3 为什么要切换端口镜像而不是拔线插嗅探器

确定了问题在 DNS 链路后,手册里做了一个很关键的操作:把嗅探器留在原地,只改变交换机端口镜像设置。很多人习惯直接拔掉网线把嗅探器插到 DNS 服务器上,这在生产环境里是高风险动作——会中断业务流量,而且如果 DNS 服务器是虚拟机,你根本没地方插线。端口镜像(SPAN)的作用是把交换机某个端口的流量复制一份给监听端口,不影响原始流量转发,是生产环境抓包的默认姿势。

这一步的意义在于:对分公司来说,客户端发出的 DNS 请求最终由172.16.16.251这台 DNS 服务器负责迭代解析。要看清这台服务器为什么回 SERVFAIL,就必须把嗅探目标从客户端网段切到 DNS 服务器所在网段。捕获结果保存为stranded_branchdns.pcap,这个文件里多出来的那个“怪异”数据包,才是整个故障的真正突破口。

3. 根因深挖:看到 TCP 53 的 SYN 数据包,故障性质就变了

3.1 DNS 为什么突然走 TCP:大响应、EDNS 与区域传送三种场景

打开stranded_branchdns.pcap后,除了之前看到的查询和响应,还多了一个额外数据包。这个包看起来非常“违和”:它尝试与中心办公室的首选 DNS 服务器172.16.16.250的标准 DNS 服务端口 53 通信,但协议类型不是我们熟悉的 UDP,而是 TCP,并且是一个干净的 SYN 握手包。

在大多数人的认知里,DNS 就等于 UDP 53,看到 TCP 53 的包第一反应是“是不是有什么非法扫描流量混进来了”。实际上 DNS 走 TCP 有三种正经场景:一是 DNS 响应超过 UDP 承载上限(通常是 512 字节,启用 EDNS 后可能更大);二是 DNS 区域传送(Zone Transfer),用于在 DNS 服务器之间同步资源记录;三是某些解析器主动选择 TCP 重试。对照这个案例:分公司 DNS 服务器向总部 DNS 服务器发起 TCP 连接,方向是“服务器对服务器”,且没有先看到大体积 UDP 响应,基本可以断定这不是普通查询,而是区域传送。

tshark -r stranded_branchdns.pcap -Y "tcp.port == 53" \ -T fields -e frame.number -e ip.src -e ip.dst \ -e tcp.flags.syn -e tcp.flags.ack

这条命令过滤出所有 53 端口的 TCP 包,重点看 SYN 和 ACK 标志位。如果只看到syn=1, ack=0的包,而没有对应的syn=1, ack=1响应,说明 TCP 三次握手压根没建立起来。TCP 不像 UDP 那样“发了就不管”,握手失败是一个强信号——要么包没到对端,要么对端拒绝连接。

3.2 SYN 发出后没有任何 ACK 响应:最可能丢在中间链路

区域传送为什么会失败?从协议层面看,TCP 连接建立失败只有三种可能:源端没发出、中间网络丢弃、目的端拒绝。源端这里已经看到 SYN 包了,可以排除;目的端如果活着且服务正常,一般会回 RST 或 SYN-ACK,而不是完全沉默。剩下的最大嫌疑就是中间链路——也就是连接分公司和中心办公室的路由器。

这里有一个实战中容易犯的方向性错误:一看到 TCP 握手失败就去查 DNS 服务器配置、查区域传送权限设置,这属于检查“服务端愿不愿意接”。但更常见的情况是,包根本就没到服务端。判断方法很简单:在总部 DNS 服务器入方向再抓一次包。如果总部那边完全看不到这个 SYN,问题就百分百在中间路由器上,而不是 DNS 服务器本身。手册里明确提到“没有给出中心办公室 DNS 服务器的流量捕获文件,因为根本就没有”——这句话翻译过来就是:SYN 数据包从未到达服务器,中间设备是唯一的嫌疑对象。

3.3 区域传送失败如何传导成客户端的 SERVFAIL

把整条故障链串起来就非常清晰了:

  1. 分公司用户访问总部应用服务器,需要先解析应用服务器的域名。
  2. 分公司 DNS 服务器是总部 DNS 服务器的从属服务器,它没有独立维护这些记录,而是依赖从总部同步资源记录。
  3. 总部 DNS 服务器是被查询应用的权威 DNS 服务器。
  4. 分公司 DNS 服务器要完成解析,必须先把总部那边的 A 记录“搬”到自己这里,这个过程就是区域传送。
  5. 区域传送走 TCP 53,SYN 包被路由器丢弃,导致分公司 DNS 服务器一直缺少应用服务器的 A 记录。
  6. 客户端来查询时,分公司 DNS 服务器手里没有数据、上游也同步不下来,只能回一个 SERVFAIL。

这条链路解释了为什么客户端看到的是“服务器故障”而不是“超时”——分公司 DNS 服务器确实响应了,只是它给不出答案。排查这类问题,一定要顺着“数据从哪来”这个思路走,而不是盯着最后那一跳的响应结果发呆。

4. 逐段定位与修复:SYN 没到总部服务器,问题锁定路由器 ACL

4.1 分段抓包法:包在哪一段消失,故障就在哪一段前面

网络是黑匣子,分段抓包是打开黑匣子的唯一方式。我的排查顺序固定如下:

  1. 客户端网段抓包,确认请求发出、响应返回的情况(这里是 SERVFAIL)。
  2. 分公司 DNS 服务器网段抓包,确认它是否向上游发起查询或区域传送(这里看到 TCP SYN)。
  3. 总部 DNS 服务器入方向抓包,确认包是否抵达(这里什么都抓不到,说明中间断了)。
  4. 路由器两侧分别抓包,定位丢弃点。

第五步是最终实锤。在这个案例里,分公司 DNS 服务器的 SYN 包没有到达总部服务器,那么问题必然出在两个办公室之间的路由器上。判断依据不需要复杂的工具:只要在路由器入口、出口各做一次镜像,对比两次抓包结果,包在哪个方向“消失”,问题就在哪个方向的那台设备。

4.2 实锤:路由器只放行了 UDP 53,把 TCP 53 静默丢弃

技术员查看路由器配置后找到了罪魁祸首:中心办公室的路由器被配置成只允许 53 端口的 UDP 流量进入,而 53 端口的 TCP 流量被 ACL 规则阻止。这是一种非常隐蔽的配置错误——从表面看,DNS 服务“没有被封”,因为 UDP 53 是通的;实际效果却是区域传送这条关键链路被无声无息地切断。

下面给出这个场景下最常见的 ACL 配置形态,帮助你对比自己的设备:

ip access-list extended DNS-IN permit udp any any eq domain deny ip any any

问题就在第二行:它只放行了 UDP 53,把 TCP 53 连同所有其他流量一起拒之门外。ACL 默认隐式拒绝所有未匹配的流量,所以 TCP SYN 包会被静默丢弃,不会触发 ICMP 报错,抓包时看起来就是“发了没回”。修复方法是在deny之前追加一条允许 TCP 53 的规则:

ip access-list extended DNS-IN permit udp any any eq domain permit tcp any any eq domain deny ip any any

追加规则后,原 ACK 包和区域传送的数据流就能正常通过了。注意这里any any eq domain对应的是“所有来源访问 53 端口”,如果实际环境里区域传送只发生在特定的主从服务器之间,更稳妥的做法是把any换成具体的服务器 IP,缩小放行范围。

4.3 修复后的验证:区域传送恢复,客户端解析回到 NOERROR

改完 ACL 之后,我一般会按顺序做三个验证,确保问题真正闭环:

# 1. 在分公司 DNS 服务器上测试区域传送是否成功 dig @172.16.16.251 应用服务器域名 AXFR # 2. 模拟客户端,向分公司 DNS 查询 A 记录 dig @172.16.16.251 应用服务器域名 A # 3. 在总部 DNS 服务器入方向重新抓包,确认 TCP 53 流量到达 tshark -i eth0 -Y "tcp.port == 53"

第一条命令会从分公司 DNS 服务器直接发起一次完整的区域传送请求,如果配置修复成功,能看到一串资源记录被传输过来;第二条命令模拟客户端视角,此时应答码应该从 SERVFAIL 变成 NOERROR,并返回172.16.16.200;第三条命令确认 SYN 包能顺利到达总部服务器。三步全部通过,才说明修复没有留下死角——我在实际排错中经常看到有人改完配置就收工,第二天问题复现,就是漏了回归验证这一步。

5. 避坑清单:DNS 排错里最容易误判的 5 个常见问题

5.1 看到 SERVFAIL 就去重启 DNS 服务器

现象:客户端大量报“DNS 解析失败”,抓包看到应答码是 SERVFAIL,运维第一反应是重启 DNS 服务或清缓存。原因:SERVFAIL 表示 DNS 服务器想查但查不到,进程本身是健康的,问题出在上游链路、区域传送或权威数据同步上。解决:先看应答码区分故障类型,再用分段抓包定位是“发不出去”还是“拿不回来”,不要动服务。

5.2 只在客户端一个点抓包,把问题定性为“DNS 服务器不回包”

现象:客户端抓包看到请求发出后没有正常响应,直接断定 DNS 服务器有问题。原因:中间链路丢包和设备过滤同样会导致客户端看不到响应,客户端的抓包只能证明“这一段不通”,证明不了是谁丢的。解决:至少抓三个点——客户端、本地 DNS、上游/权威 DNS,对比数据包的到达情况;哪个点开始看不到流量,问题就在那个点之前的设备上。

5.3 过滤条件只写udp.port == 53,把关键包漏掉

现象:分析抓包文件时只过滤了udp.port == 53,从头到尾没看到异常,判定“网络是好的”。原因:DNS 区域传送走 TCP 53,在大多数 DNS 服务环境里默认就存在;只过滤 UDP 就把这条关键链路整个忽略了。解决:排查 DNS 故障时把过滤条件写成port == 53,同时覆盖 TCP 和 UDP,再结合tcp.flags.syn判断连接是否建立成功。

5.4 不区分“包没到对端”和“对端没回包”,方向性错误

现象:SYN 包没有收到 SYN-ACK,排错时一直在检查目标 DNS 服务器的配置、权限和监听状态。原因:TCP 握手失败可以是目的端拒绝,也可以是中间路由器静默丢弃,两种原因的处理方向完全不同。解决:在目标服务器入方向单独抓包,确认包是否到达;没到达就顺着链路往前找,不要对着服务器瞎折腾。

5.5 改完 ACL 或防火墙不做回归验证

现象:前一天改了防火墙规则,第二天用户反馈同样的故障又出现了。原因:很多防火墙同时存在多条规则,新加的放行规则可能被后面的拒绝规则覆盖,或者改的是错误的接口方向。解决:改完立即做端到端验证,既测试区传送又测试正常解析,必要的话在两端同时抓包对比;确认业务流量真的通了再宣布修复完成。

6. 快速定位这类 DNS 故障的固定套路

面对 DNS 解析失败、SERVFAIL、区域传送异常这类问题,我现在的套路已经固化成三步,每一步都有明确的判断标准。

第一步,客户端抓包定性。用dns.flags.response == 1过滤出所有响应包,看应答码;再用dns.flags.rcode == 2把所有 SERVFAIL 挑出来,确认故障类型。第二步,本地 DNS 服务器抓包定段。重点看它是否向上游发起了 TCP 53 的连接,用tcp.flags.syn == 1 && tcp.flags.ack == 0找到所有握手请求,再确认有没有对应的tcp.flags.syn == 1 && tcp.flags.ack == 1响应。没有响应,就不要急着查服务器配置,而是继续往下游走。第三步,在权威或上游 DNS 入方向抓包定责。这里需要一个判断准则:如果 SYN 到了而没有任何回应,重点查服务器本身的监听和防火墙;如果 SYN 根本没到,重点查中间路由器。

验证工具上,dig比 nslookup 好用得多:用dig @<DNS服务器> <域名> A看正常解析,用dig @<DNS服务器> <域名> AXFR测试区域传送,返回 NOERROR 且带资源记录才算真正恢复。Wireshark 的显示过滤器里我会同时打开port == 53、tcp.flags.syn == 1、dns.flags.rcode三组条件,确保 TCP 和 UDP 两个维度的流量都在视野内。

那次故障过后,我养成了一个习惯:凡是 DNS 类报错,先强制把“客户端 → 本地 DNS → 上游/权威 DNS”三步抓包走完,再动任何配置。这条流程帮我挡掉了至少三次“看起来是 DNS 挂了、实际上是中间设备过滤”的翻车现场。希望这一套思路,也能帮你少走点弯路。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进