资讯详情

资讯详情

DNS原理与安全实战:BIND9搭建、dig排障与攻防加固

网安学习笔记写到第九天我原本以为会轻松一点结果翻开计划表一看今天要啃的是 DNS。说实话前八天从网络分层、TCP/IP、HTTP 协议一路学下来我都觉得还算有条理——协议看得见、抓包摸得着、字段一个个对着看就懂了。轮到 DNS情况完全变了它是整个互联网里最隐形的一层基础设施。你打开浏览器输一个域名几百毫秒内背后已经跑完了一整套查询链条快到你根本没意识到它存在可真出问题时网页打不开、内网系统连不上、邮件全被退所有人都第一时间怀疑网络、怀疑服务器最后才发现是解析出了岔子。更让我警觉的是DNS 在攻防对抗里的位置非常微妙。它几乎是唯一个必须放行的协议——防火墙可以封端口、可以拦应用但很少会把 53 端口彻底掐死因为一掐业务就全瘫。这种必须活着的特性让它同时成了攻击者最喜欢的通道和防守方最容易忽略的盲区。缓存投毒、响应欺骗、隧道外带、放大攻击这一串名词背后都指向同一个事实很多人对 DNS 的理解只停留在把域名翻译成 IP这一句话上。这篇笔记是我在实验室里折腾了一整天的产出。我从零搭了一台 BIND9把递归、迭代、转发、主从复制都跑了一遍用 dig 把每一段响应拆开看又抓包对照报文结构最后顺着安全面把常见的攻击手法和防护思路梳理了一遍。内容偏实操也偏踩坑记录——那些配置里少一个点、少一个分号就整个服务起不来的细节我都原样记下来了。不管你是刚入门想补基础还是已经做过运维但没系统梳理过 DNS应该都能从里面捞到点东西。1. 先把 DNS 到底在解决什么问题想明白1.1 从记电话号码这个比喻说起我刚接触 DNS 的时候看过最多的解释就是互联网的电话簿。这个比喻没错但它太浅浅到会让人误以为 DNS 只是一个静态的对照表。真上手之后我才发现它更像一整套分布式的、带缓存的、有层级授权关系的寻址系统——电话簿是死的DNS 是活的每一条记录都有生存时间每一级都有授权边界每一次查询都可能命中缓存也可能穿透到源头。先退回到最原始的问题为什么需要它因为 IP 地址对人太不友好了。IPv4 是 32 位写成点分十进制还能勉强记IPv6 是 128 位一长串十六进制根本没法背。更要紧的是IP 会变。业务迁移、机房切换、负载均衡扩缩容后端地址随时在调整。如果所有客户端都直接写死 IP那每次变更都是一场灾难。DNS 的价值就在于解耦把我要访问谁和它现在在哪分开。客户端只认名字名字到地址的映射由 DNS 负责维护和更新。这个解耦带来三个直接好处——地址变更对用户透明、可以做流量调度同一个名字返回不同地址、可以做故障转移主地址挂了换备用。理解了这一层你再看那些为什么我们公司要自建 DNS为什么改了 IP 还要等生效的问题答案就顺了。还有一个常被忽略的点DNS 不只是域名转 IP。它承载的信息类型非常多邮件路由靠 MX 记录服务发现靠 SRV 记录域名所有权验证靠 TXT 记录反向查询靠 PTR 记录。某种意义上DNS 是一个轻量级的分布式数据库只是它的查询接口被设计得极其简单。1.2 层级授权为什么全世界没有一个总数据库这是我今天第一个真正想通的问题。全世界有上亿个域名如果集中存在一台服务器上性能和可用性都不可能撑住。DNS 的解法是分层授权把谁负责哪一段这件事本身也变成数据。最顶层是根区它不存具体域名的地址只存每个顶级域该去问谁。往下是顶级域比如各类通用顶级域和国家地区顶级域它们存的是每个二级域该去问谁。再往下是各级权威服务器真正保存某个域名的具体记录。整个结构像一棵倒挂的树每一层只知道自己下一层在哪不需要知道全局。这个设计的关键在于委派上级不保存下级的具体数据只保存指向下级的 NS 记录和胶水记录。好处是任何一段出问题都不会拖垮全局任何一段要扩容也不用通知全世界。坏处是查询链路变长一次解析可能要问好几个服务器——所以才需要缓存缓存才是让这套体系跑得动的东西。我拿实验室的域名练手时特意观察了这一点查一个二级域下的主机名本地解析器先去问根根只回一个去问某个顶级域服务器的引用再问顶级域又只回一个去问这个域的权威服务器最后才拿到真正的 A 记录。整个过程像接力每一棒只告诉你下一棒在哪。1.3 递归查询与迭代查询两种问路方式这两个词特别容易混我用一句话区分递归是你帮我问到底迭代是你告诉我下一步问谁。递归查询发生在客户端和本地解析器之间。你的电脑把问题丢给本地 DNS然后就不管了等一个最终答案。本地解析器有义务要么给出结果要么给出明确的失败原因。这就是为什么家里路由器挂了或者公司 DNS 挂了你连域名不存在都看不到只会一直转圈。迭代查询发生在本地解析器和上游各级服务器之间。本地解析器自己去问根、问顶级域、问权威每一步拿到的是引用而不是答案它得自己一步步追下去。这个过程中本地解析器是主动方上游服务器只做指路。理解这个区别的实战意义在于排查。当用户说网站打不开你先要判断是客户端到本地解析器这一段断了还是本地解析器到上游这一段断了。方法很简单直接对本地解析器 dig再对一个公共解析器 dig两次结果一对比故障域立刻缩小一半。这个动作我后来养成了肌肉记忆比任何花哨工具都好使。注意本地解析器通常会开启递归功能而权威服务器必须关闭递归。如果一台对外提供权威解析的服务器同时开了递归就成了所谓的开放递归会被拿去做放大攻击的跳板。这条配置红线在后面的安全章节还会再提一次。2. 报文与记录类型把一次解析拆到字段级2.1 报文头部几个字段必须背下来DNS 报文结构其实不复杂头部 12 个字节后面跟着问题区、回答区、授权区、附加区四个段落。但头部里那几个标志位是判断这次解析到底发生了什么的关键。QR 位区分查询和响应Opcode 区分标准查询和其他操作AA 位表示这是权威回答——这个位特别有用抓包时看到 AA1 说明回答来自权威服务器AA0 说明是缓存给的。TC 位表示报文被截断通常发生在 UDP 响应超过512字节又没启用 EDNS0 的时候看到 TC1 就说明客户端该改用 TCP 重试了。RD 位是期望递归客户端置1表示希望对方帮忙查到底RA 位是支持递归服务器置1表示自己确实开了递归功能。最值得盯的是 RCODE响应码。0 是成功3 是 NXDOMAIN这个名字压根不存在2 是 SERVFAIL服务器自己出问题了5 是 REFUSED策略拒绝。我踩过一个典型坑内网某系统域名解析失败dig 出来 RCODE5我一开始以为是记录配错了翻了半天区域文件最后发现是访问控制列表没放行我测试机的网段服务器直接拒绝了查询。RCODE 是排查的第一入口养成先看它的习惯能省掉大量瞎猜。2.2 记录类型选型不是能用就行刚学的时候我觉得记录类型就那么几种背下来就完事。实际配了一遍才发现每种记录背后都有明确的适用场景选错了当时能跑后面维护起来很痛苦。记录类型作用典型场景选型注意点A域名到 IPv4 地址常规网站、内网服务最常用多值即为简单轮询AAAA域名到 IPv6 地址双栈环境别忘了和 A 记录同步维护CNAME域名别名CDN 接入、多地部署统一入口不能和 MX、NS 等共存于同一名字MX邮件交换自建邮件系统必须带优先级数字越小越优先NS授权服务器区域委派必须配胶水记录否则解析链断裂TXT文本信息域名验证、策略声明长度有限制超长需分段SOA区域起始授权每个区域必须有且只有一个序列号决定主从同步忘了加就不同步PTR反向解析日志溯源、邮件反垃圾需要独立的反向区域容易漏配SRV服务定位服务发现、协议内服务寻址带优先级和权重权重要合理分配CAA证书签发授权限制哪些机构可签发证书配错了会导致证书申请被拒CNAME 那条限制我吃过亏。当时想给一个已经配了 MX 的邮件域名再加个别名配置检查直接报错。原因是 CNAME 要求这个名字不能有任何其他记录因为别名一旦存在其他所有记录都应该去目标名字上找两者共存会产生语义歧义。后来我的做法是别名只用在纯 Web 入口上邮件、验证类记录一律用 A 记录直连。SOA 的序列号也是个经典坑。主从复制靠序列号判断是否有更新格式通常是年月日序号。有一次我改完记录忘了加序列号从服务器一直不同步两边数据不一致排查了快一个小时才想起来。现在的习惯是改区域文件的第一件事就是动序列号改完再动别的。2.3 TTL一个数字决定了你多久能反悔TTL 是记录里的生存时间单位秒。它决定了这条记录能被缓存多久。这个数字看起来不起眼实际上直接决定了运维的灵活度。TTL 设长了缓存命中率高解析压力小但一旦要改地址全世界客户端可能几小时甚至一天都还在用旧地址。TTL 设短了切换灵活但解析请求量暴涨上游压力大。我的经验是分场景稳定不变的基础服务TTL 可以设到 3600 甚至更长有迁移计划的域名提前一天把 TTL 降到 300 甚至 60等迁移完成、观察一段时间没问题后再调回去。这个提前降 TTL的动作是老运维的基本功因为它必须提前做——你没法在出故障的当下把已经缓存出去的旧 TTL 收回来。还有个细节本地操作系统的 DNS 缓存和应用层缓存是两回事。浏览器有自己的一套缓存Java 这类运行时也有自己的缓存策略有时候系统层已经拿到新记录了应用还在用旧的。排查这类问题时我会按浏览器缓存 → 系统缓存 → 本地解析器缓存 → 权威记录的顺序一层层验证而不是一上来就骂 DNS。3. 动手搭一台 DNS 服务器从装到能解析3.1 软件选型三种方案的真实差异搭之前先选软件。我把三个主流方案都试了一遍结论是它们根本不是同一类东西适用场景差异很大。方案定位配置复杂度适合场景我的评价BIND9功能完整的权威递归服务器高正式权威解析、主从架构功能最全学习价值最高但配置文件语法严格dnsmasq轻量转发本地缓存低小型内网、开发环境上手极快做不了复杂权威配置CoreDNS插件化、云原生友好中容器环境、服务发现配置用插件链思路和传统 DNS 完全不同我最终选了 BIND9 作为主线理由很直接它是理解 DNS 原理最好的载体。区域文件、SOA、NS 委派、视图、转发、主从这些东西在 BIND 里都是显式的你必须手写出来写的过程就是理解的过程。dnsmasq 太省事反而学不到东西CoreDNS 的插件模型很优雅但更适合已经懂 DNS 的人去做工程化。选型这件事我的建议是学习阶段用 BIND生产环境的轻量需求用 dnsmasq容器化环境用 CoreDNS。别指望一个方案通吃。3.2 最小可用配置逐行写、逐行解释实验环境我用的是文档保留网段避免和真实网络冲突服务器地址 192.0.2.10实验域名用 corp.lab。下面这份是能跑起来的最小配置。# named.conf 全局段 options { directory /var/cache/bind; listen-on port 53 { 127.0.0.1; 192.0.2.10; }; listen-on-v6 { none; }; recursion no; allow-query { 192.0.2.0/24; }; allow-transfer { none; }; dnssec-validation no; };逐行说一下为什么这么写。directory指定工作目录相对路径的缓存文件、区域文件都基于它。listen-on明确只监听回环和本机业务地址千万别图省事写成 any否则服务器上有几个网卡、几个地址全暴露出去攻击面白白扩大。recursion no是权威服务器必须做的事——这台机器只负责回答自己域内的数据不替任何人做递归。allow-query限制查询来源网段allow-transfer默认关掉需要主从同步时再单独放行从服务器地址。# 区域声明 zone corp.lab { type master; file /etc/bind/db.corp.lab; }; zone 2.0.192.in-addr.arpa { type master; file /etc/bind/db.192.0.2; };正向区域声明 corp.lab反向区域声明 192.0.2.0/24。反向区域的命名规则是把网段倒过来加 in-addr.arpa 后缀2.0.192 对应 192.0.2。这一步新手最容易写错顺序我的记法是网段从后往前念。3.3 区域文件语法严格到少一个点就变语义区域文件是 BIND 里最容易踩坑的地方因为它对结尾的点极其敏感。不带点的名字会被自动拼接上当前区域名带点的才是绝对名称。这个规则坑过几乎所有初学的人。$TTL 3600 IN SOA ns1.corp.lab. admin.corp.lab. ( 2024060901 ; serial 3600 ; refresh 900 ; retry 604800 ; expire 300 ; negative cache TTL ) IN NS ns1.corp.lab. ns1 IN A 192.0.2.10 www IN A 192.0.2.20 mail IN A 192.0.2.30 IN MX 10 mail.corp.lab. ftp IN CNAME www.corp.lab.代表当前区域名也就是 corp.lab。SOA 里两个名字必须是绝对的所以要带点admin.corp.lab.会被当成管理邮箱第一个点变成 。serial 我用日期加序号refresh、retry、expire 是从服务器同步的策略参数negative cache TTL 是查不到时的缓存时长这个值建议设小一些比如 300 秒不然一条误配的记录会让人难受五分钟以上。www IN A 192.0.2.20这里的 www 没带点会被解释成 www.corp.lab这是我们要的。而ftp IN CNAME www.corp.lab.里目标必须带点否则会变成 www.corp.lab.corp.lab解析必然失败。我第一次配的时候就栽在这个点上服务起得来、日志不报错但解析结果是个拼接错的怪名字。这类问题不看实际解析结果根本发现不了。反向区域文件里主机名部分只写最后一段$TTL 3600 IN SOA ns1.corp.lab. admin.corp.lab. ( 2024060901 3600 900 604800 300 ) IN NS ns1.corp.lab. 10 IN PTR ns1.corp.lab. 20 IN PTR www.corp.lab. 30 IN PTR mail.corp.lab.写完必须做语法检查这是我现在的固定动作named-checkconf /etc/bind/named.conf named-checkzone corp.lab /etc/bind/db.corp.lab named-checkzone 2.0.192.in-addr.arpa /etc/bind/db.192.0.2named-checkzone会明确告诉你行号和错误原因比等服务起不来去看系统日志高效得多。我建议把这两条命令当成保存文件后的肌肉记忆能省掉八成的重启调试。3.4 转发与主从内网解析怎么和公网衔接内网自建 DNS 有个绕不开的问题内部域名自己能答但员工上网还要查公网域名怎么办答案是转发。options { ... recursion yes; allow-recursion { 192.0.2.0/24; }; forwarders { 192.0.2.53; 192.0.2.54; }; forward only; };这份配置和前面那份的关键差别是开了递归但把递归服务范围严格限制在内网网段。forward only表示本地不自己迭代全部交给上游转发器处理。这种架构叫缓存加转发是内网 DNS 最常见的形态内部区域本地权威回答外部域名透传给上游。主从复制则是为了可用性。主服务器挂了从服务器还能继续答。配置上从服务器区域写成type slave; masters { 192.0.2.10; };主服务器那边在allow-transfer里放行从服务器地址。同步靠 SOA 序列号触发序列号不变就不同步——这也是前面强调改文件先改序列号的原因。实操心得主从切换一定要实际演练一次。我见过配了从服务器但从来没人验证过同步状态的场景真出故障时才发现从库压根没同步上等于白配。定期在主库改一条测试记录去从库 dig 一下两分钟就能确认链路健康。4. 命令行实战dig 的输出到底该怎么读4.1 一次 dig 输出的四段结构nslookup 好上手但信息少host 适合快速查真要排查我基本都用 dig。它的输出分四段每段都有用。第一段是头部状态最关键是status字段和flags。status: NOERROR是正常NXDOMAIN是名字不存在SERVFAIL是服务器侧出了问题REFUSED是策略不让查。flags 里看qr这是响应、aa权威回答、rd期望递归、ra支持递归。看到aa说明答案来自权威数据不是缓存。第二段是 QUESTION SECTION确认你问的到底是什么。这里能发现拼写错误和类型错误比如你想查 MX 但命令行写成了 A。第三段是 ANSWER SECTION真正的结果。右边那个数字是 TTL你会看到它随着缓存时间递减——这个细节挺有意思同一个缓存记录连续查两次TTL 会从 300 变成 298、296直观展示了缓存倒计时。第四段是权威区和附加区能看到这个域的 NS 有哪些、权威服务器地址是什么。排查解析结果不对时先看这一段的 NS 是不是你预期的服务器很多时候问题就出在流量被导到了别的权威上。4.2 排查场景下的命令组合不同的排查目标对应不同的参数组合我把常用的几组整理成表。排查目标命令看什么验证权威服务器直答dig 192.0.2.10 www.corp.lab A norecurs有没有 aa 标志答案对不对绕过本地缓存dig 192.0.2.10 www.corp.lab A nocache是否和缓存结果一致追踪完整解析链dig www.corp.lab trace从根到权威每一跳的响应检查邮件记录dig corp.lab MX short优先级和目标主机反查 IP 归属dig -x 192.0.2.20 shortPTR 记录是否正确测试 TCP 解析dig www.corp.lab tcp大响应或截断场景看响应时间dig www.corp.lab statsQuery time 是否异常trace这个参数特别好用它会模拟迭代查询把从根开始每一级的响应都打出来。第一次跑的时候我盯着输出看了很久才真正把委派这件事看明白——你能清晰看到根只回引用、顶级域只回引用、只有最后一级才给出 A 记录。这个输出比任何图都直观。norecurs也值得养成习惯。它告诉服务器别帮我递归你手上有什么就给我什么。用它去问权威服务器能确认权威数据本身是否正确把缓存问题和权威问题彻底分开。这一步做了之后排查路径会清晰很多。4.3 抓包对照把报文和输出对上号工具输出是结果抓包才是过程。我用抓包工具过滤dns协议把查询和响应抓下来逐字段和 dig 输出对照这一遍下来对报文结构的理解比看十篇文章都管用。抓的时候能明显看到查询包和响应包的 Transaction ID 是一致的这是用来匹配请求响应的查询包里问题区只有一条回答区是空的响应包里回答区才有内容。如果开着递归还能看到本地解析器向上游发出的多个查询包一个个对应迭代过程。有个现象我印象很深某个响应包返回后客户端立刻又发了一次 TCP 查询。抓包一看第一次 UDP 响应的 TC 位是 1说明超过512字节被截断了客户端按规范改用 TCP 重试。这个场景在返回记录多、或者带 DNSSEC 签名的情况下很常见。理解了这一点你就明白为什么UDP 53 通了但某些域名解析失败这种诡异现象会出现——防火墙可能只放行了 UDP 没放行 TCP。排查提示遇到部分域名能解析、部分不能优先怀疑两件事一是 MTU 或分片导致的大响应丢失二是 UDP 通而 TCP 不通。用tcp强制走 TCP 试一下能立刻验证第二种可能。5. 安全面DNS 为什么是攻防的灰色地带5.1 缓存投毒与响应欺骗信任模型本身就是弱点DNS 设计于一个彼此信任的年代查询和响应之间几乎没有强认证。客户端发出查询后只靠 Transaction ID 和源端口来匹配响应这两个值在早期实现里都很可预测。攻击者如果能抢先伪造一个响应并且 ID 和端口猜对了客户端就会采信。缓存投毒是这个问题在解析器层面的放大版攻击者想办法让递归解析器把伪造的记录存进缓存之后所有查询这个域名的用户都会拿到错误地址直到 TTL 到期。这个攻击的危害不是一个人受影响而是一片人受影响。现代实现的缓解手段主要是几条源端口随机化把可预测的 16 位 ID 扩展到 ID 加端口的组合空间、0x20 编码在查询名里随机改变大小写响应必须原样带回、以及 DNSSEC 的密码学签名验证。DNSSEC 是最彻底的方案它给记录加了数字签名解析器能验证数据确实来自该域的权威服务器且未被篡改。但 DNSSEC 的推广一直不快原因很现实它需要从根到每一级都完成签名链任何一环没配好整条链就断密钥轮换和签名过期需要运维流程支撑配置出错导致的解析失败比攻击本身还常见。我在实验环境里试配过一次光是密钥生成和签名时间参数就折腾了半天最后签名过期导致解析失败排查了好一阵。所以我的看法是DNSSEC 值得学、值得理解原理但落地要评估运维能力别为了安全把可用性搞崩。5.2 劫持的表现形式与识别思路劫持和投毒的区别在于位置。投毒发生在解析链路上劫持往往发生在更靠近用户的一侧——本地解析器被改、网关做了透明重定向、终端上的 hosts 文件被篡改、甚至路由器 DHCP 下发的 DNS 地址被换掉。识别劫持有一套比较实用的思路。第一步对比解析结果用本地默认解析器和另一个独立解析器分别查同一个域名结果不一致就是强信号。第二步看响应的权威性如果返回的地址是个陌生的、明显不该出现的地址基本可以确认。第三步检查链路确认终端的 DNS 配置是不是被改了hosts 文件有没有多出莫名其妙的内容网关有没有做重定向。我遇到过一次挺典型的情况某台机器解析某个域名总是返回一个奇怪的内网地址其他机器都正常。查了半天最后发现是那台机器的 hosts 文件被某次安装的软件写入了条目。这个案例说明排查 DNS 问题不能只盯着 DNS 服务器客户端本地同样是一个必须检查的环节而且成本最低应该放在最前面查。5.3 DNS 隧道为什么 53 端口必须被盯着这是我觉得 DNS 安全里最需要理解的一块。DNS 隧道的基本原理是把其他协议的数据编码进 DNS 查询名或者 TXT 记录里通过正常的 DNS 请求把数据带出去或者把指令带进来。因为 DNS 几乎必然被放行这条通道在很多环境里是通的。它的技术特征其实挺明显查询的域名特别长或者子域名部分是随机字符串查询的域名数量巨大但集中在少数几个域查询类型异常大量 TXT、NULL 类型请求请求频率稳定得像心跳单个会话的域名模式高度相似。这些特征组合起来就是检测的抓手。防守侧的做法是在出口 DNS 上做日志留存和频次统计对超长子域名、异常类型、高熵字符串做告警对内部终端只允许查询内网解析器禁止直连外部 DNS对不必要的外部解析做白名单收敛。这些措施不需要多高深的技术关键是有人真的去看日志。我在实验环境里做过一次对比观察正常浏览网页时DNS 查询的域名分布很分散长度正常类型基本都是 A 和 AAAA。而模拟的异常流量里域名长度明显偏长子域随机性高TXT 查询占比异常。这个对比让我意识到检测的核心不是找某个特征而是建立基线再看偏离。说明这里只讨论检测与防护思路不涉及任何具体的隧道工具或搭建方法。理解攻击特征的目的是让防守方知道该在日志里看什么。5.4 放大攻击开放递归为什么是公害DNS 放大攻击利用的是小请求、大响应这个特性。攻击者伪造源地址发出查询把响应指向受害者服务器把一个大得多的响应发给受害者从而放大流量。查询一个很小的包响应可能有几百甚至几千字节放大倍数很可观。如果响应能更大比如 ANY 查询、DNSSEC 签名响应放大效果更明显。这个攻击能成立的唯一前提是存在大量开放递归服务器也就是对任意来源都提供递归服务的解析器。所以防护的第一条也是最有效的一条就是关掉开放递归只对可信网段提供服务。第二条是启用响应速率限制对同一来源的重复查询做限速。第三条是在上游做流量清洗。回头看第 3 章的配置allow-recursion那一行其实就是这条防护的落地。很多人搭内网 DNS 时图省事写成any觉得内网嘛无所谓可一旦这台机器有公网地址或者内网里有人做了端口映射它立刻就成了别人的攻击工具。这条我是当红线记的递归服务范围必须精确到网段。5.5 一份能落地的 DNS 加固清单把上面的内容收拢成一份可执行的清单按优先级排。优先级措施说明高关闭开放递归递归只对明确网段开放其余一律拒绝高限制区域传送只允许从服务器地址禁止任意主机拉取全量记录高分离内外解析内网域名和公网域名用不同视图或不同服务器中启用查询日志保留足够时长用于事后溯源中主从冗余部署单点故障是可用性最大的敌人中版本信息隐藏关闭版本号泄露减少指纹识别中响应速率限制对单来源高频查询做限速低DNSSEC 部署视运维能力评估先小范围试点低客户端解析收敛只允许终端查询指定解析器禁止直连外部分离解析这块值得单独说一句。内外网用同一个域名但返回不同地址是很常见的需求——内网员工访问走内网地址外网用户访问走公网地址。BIND 用视图实现配置上要注意视图的匹配顺序匹配错了会出现内网用户拿到了公网地址这种诡异现象。我配的时候把匹配条件写得太宽结果所有查询都命中了第一个视图调了好一会儿才发现是顺序问题。6. 踩坑记录与问题速查6.1 几个让我印象深刻的故障现场第一个坑服务起不来日志里只写loading configuration: failure没有具体原因。这种情况九成是配置语法问题只是日志级别不够。解决办法是先跑named-checkconf它会精确指出行号和问题。如果还不明确把日志级别调高或者前台启动看实时输出。第二个坑区域加载失败提示某行有语法错误。原因是我在记录里用了制表符和空格混排看着对齐实际解析错位。BIND 区域文件对空白字符敏感多个空格和制表符虽然通常等价但混用时容易让字段错位。我后来的习惯是统一用空格写完必跑 checkzone。第三个坑解析能通但结果不对返回的是个拼接错的域名。这就是前面说的结尾的点问题。这类问题最难查因为服务不报错、查询有结果只有你仔细看返回的名字才发现不对。养成习惯区域文件里凡是绝对名称一律带点。第四个坑改了记录但客户端不生效。排查顺序应该是先确认权威服务器上是不是新数据直接 dig 权威地址再确认本地解析器缓存dig 本地解析器最后才看客户端。我一开始跳过了第一步直接去清客户端缓存白折腾了十几分钟。第五个坑主从不同步。原因有两个可能一是序列号没加二是传送被拒绝。前者看 SOA后者看主服务器的allow-transfer配置和日志。我从服务器的日志里会明确写transfer of zone failed看一眼就知道方向。6.2 问题速查表现象最可能原因排查动作RCODE5 REFUSED来源不在 allow-query 网段核对查询源地址和 ACL 配置RCODE3 NXDOMAIN记录不存在或名字拼错dig 权威服务器确认记录是否存在RCODE2 SERVFAIL上游不可达、区域加载失败、签名过期看解析器日志和 checkzone 结果解析超时无响应53 端口被拦、服务器未监听抓包看是否有请求发出、是否有响应回部分域名失败大响应截断、TCP 未放行用 tcp 重试检查防火墙 TCP 53结果时好时坏多台解析器数据不一致分别对每台 dig比对结果和序列号内网域名解析到公网地址视图匹配顺序错检查视图的 match-clients 条件改了记录不生效缓存未过期、序列号未更新查 TTL查 SOA 序列号反向解析失败反向区域未配置或 PTR 缺失dig -x 确认检查反向区域文件邮件被拒收MX 或 PTR 配置问题查 MX 优先级、查发信 IP 的 PTR这张表我在实验室贴了一张打印版出问题时先扫一眼能省掉大量从零开始想的时间。真正有价值的排查能力不是记住所有可能性而是有一套固定的、从近到远的检查顺序先客户端本地hosts、缓存、配置再本地解析器缓存、ACL、转发再权威记录、区域、序列号最后链路端口、抓包。按这个顺序走绝大多数问题都能在十分钟内定位。我这一整天折腾下来的体会是DNS 这个协议表面上简单得不像话——一个查询一个响应字段也不多——但它真正难的地方不在协议本身而在它牵扯的东西太多缓存策略影响运维灵活度层级授权影响故障范围TTL 影响你能多快反悔递归配置影响你是不是在给别人当枪使。我前后配错了五六次每次错误都很小一个点、一个分号、一行 ACL但每一次错误都逼着我去想它为什么这么设计。这种被小错误反复教育的过程比顺顺利利跑通一遍学到的东西多得多。后面我打算继续往下走把 DNSSEC 的签名链完整跑一遍再把日志分析和异常查询检测做成一个小脚本。DNS 这块内容看着基础实际上越往深挖越有意思它几乎是理解整个互联网寻址体系的一把钥匙。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →