权威之间的一致性:SOA 与 zone transfer
一个 zone 通常有两台以上权威服务器,理由是可用性:单点故障不该让整个域名消失。而协议同时要求它们的应答完全一致(RFC 2181 §4)——同一个查询问哪台都得到同样的记录。
这两个要求之间需要一套同步机制。DNS 给的是:一个版本号,加一个拉取协议。
1 · SOA:zone 的元数据
zone 顶点上那条 SOA(Start of Authority)记录,RDATA 有七个字段。前两个是名字,后五个是数字,各管一件事:
其中 MINIMUM 这个字段名是历史包袱。RFC 1035 定义它为「本 zone 所有 RR 的 TTL 下限」,而 RFC 2308 §4 明确废弃了那个含义——原话是那个用法「在实践中从未被使用,据此废弃」——只留下「否定应答的 TTL」这一条。
警示 · 即便只按新含义读,生效值也不是 MINIMUM 本身。RFC 2308 §3 规定否定应答的 TTL 取 MINIMUM 与否定应答里那条 SOA 记录自身 TTL 的较小者。于是把 SOA 的 TTL 设成 60 秒,否定缓存就是 60 秒,MINIMUM 写 3600 也不起作用。查「为什么写了记录还是查不到、要等多久」这类问题时,两个数都得看。
MNAME 指向 primary。它的实际用途有两处:NOTIFY 的发出方按它判断该通知谁(自己不通知自己),dynamic update 的请求也按它转发。RNAME 是管理员邮箱写成域名形式,dnsadm.vega.dev. 即 dnsadm@vega.dev——local part 里若有点,得写成 \.,否则会被当成 label 分隔符。
2 · SERIAL 是环上的位置
SERIAL 是 32 位无符号数,secondary 靠比较它决定是否需要拉取。但它不是计数器:从 4294967295 加 1 回到 0,而 secondary 必须仍然认为这是「更新了」。
RFC 1982 因此给出一套序列号空间的算术:
这个定义有一处刻意留白:当 时,两个值既不大于也不小于对方。RFC 1982 §3.2 明确列出这种情形,理由不是实现偷懒,而是若强行给它定序,就会出现 而 ——「序」这个概念自身就不自洽了。
把无定义实现成「相等」是个有后果的错误。相等的含义是「数据一致,不必传送」,而无从比较的含义是「状态已经坏了」——后者必须人工把 serial 拉到一个明确更大的值上,前者什么都不用做。
由此还推出一条运维约束:单次(或 EXPIRE 期间累计)的增量不得超过
。日常写法 YYYYMMDDnn 离这个上限很远,真正会越界的是误写——手抖多打一位数字,serial 被顶到环的另一侧,此后所有比较都要靠上面这套算术才不出错。这个写法自身的边界是每天 100 次:序号用到 99 就只能借第二天的日期。
3 · 触发路径与传送方式
触发有两条路径。REFRESH 到期是 secondary 主动轮询,这是基线机制,不依赖 primary 做任何事。NOTIFY(RFC 1996)是 primary 在数据变更后主动通知各 secondary。
两种传法:AXFR(RFC 5936)送整个 zone,IXFR(RFC 1995)只送两个版本之间的差分。IXFR 请求可以得到 AXFR 应答——这是合法的退化,发生在 primary 没保留足够历史时。
注 · NOTIFY 是整套 DNS 里唯一带 push 味道的机制,但它只是一个提示,不携带任何数据。收到之后 secondary 仍要自己去查 SOA、自己比 serial、自己发起传送;而且它不被信任——伪造一个 NOTIFY 最多让 secondary 白跑一趟去问 primary,问不出更新就什么也不做。所以即便把 NOTIFY 算作 push,数据的流向仍然是 pull。这一点在第 9 讲还要用到。
传送走 TCP。原因很直接:一个 zone 装不进单个 UDP 报文,而 AXFR 需要一个有序、可靠、可以持续多个报文的流。这也是 DNS 从一开始就同时用 53/udp 与 53/tcp 的原因之一。
4 · 谁能拉走整个 zone
AXFR 把 zone 的全部内容交出去,所以它必须限制来源。默认对全世界开放 AXFR 曾是常见配置错误,后果是把内部主机名清单、命名规律、乃至未公开的服务端点整份泄露出去。
现在的做法有三层:按 IP 限制(allow-transfer)、用 TSIG(RFC 8945)做共享密钥认证、以及在网络层限制 53/tcp 的可达范围。TSIG 是三者中唯一提供认证的手段——按 IP 限制拦不住源地址伪造,尽管 TCP 的三次握手已经让伪造 AXFR 请求比伪造 UDP 查询困难得多。
值得一提的是这与第 7 讲的 DNSSEC 是两件不同的事,且互不替代:DNSSEC 让应答可验证,但它不提供机密性,也不管谁有权拉走 zone。RFC 4033 §4 把这一点写得很明白。
5 · 一处实测
写本页的模拟器时踩到一个与直觉相反的地方:递归服务器缓存的委任 NS,TTL 取自父 zone 那一份,不是子 zone 顶点那一份。
本系列的 fixture 里,vega.dev 顶点自己的 NS 写着 TTL 600,而父 zone dev 里那组委任 NS 写着 10800。测试原本断言「600 秒后委任过期、解析要退回上一级」,实测没有——缓存里那份是 10800 的。
这件事的运维含义比它看起来重要:第 9 讲会讲到「换权威服务器前先把 NS 的 TTL 调短」,而要调的是父 zone / 委任元那一份。只把子 zone 顶点的 NS TTL 改小是不够的:在解析器只走过委任、尚未从子 zone 取回权威 NS 之前,缓存里用的一直是父那份 TTL。稳妥的做法是父子两份都提前调短。
6 · 参考文献
- Elz, R., & Bush, R. (1997). Clarifications to the DNS Specification (RFC 2181). IETF. §4 要求同一 zone 的各权威服务器应答一致。
- Elz, R., & Bush, R. (1996). Serial Number Arithmetic (RFC 1982). IETF. §3.2 是比较的定义与「无定义」那一档。
- Andrews, M. (1998). Negative Caching of DNS Queries (DNS NCACHE) (RFC 2308). IETF. §3 是否定应答 TTL 的取值,§4 废弃 MINIMUM 的原义。
- Vixie, P. (1996). A Mechanism for Prompt Notification of Zone Changes (DNS NOTIFY) (RFC 1996). IETF.
- Ohta, M. (1996). Incremental Zone Transfer in DNS (RFC 1995). IETF.
- Lewis, E., & Hoenes, A. (Eds.). (2010). DNS Zone Transfer Protocol (AXFR) (RFC 5936). IETF.
- Barr, D. (1996). Common DNS Operational and Configuration Errors (RFC 1912). IETF. §2.2 是
YYYYMMDDnn写法与各计时器取值的建议。