摘要
- CNAME 让一个 DNS owner name 成为只指向一个目标的别名。为了避免源名与目标名各给出一套互相矛盾的答案,别名节点不能再保存 A、MX、TXT、NS 等普通数据。
- 解析器缓存 CNAME 后从目标名重新查询。源 zone 控制改道,目标 authority 控制最终数据;这既不是 delegation,也不证明身份、所有权或服务可用性。
一个名字想承担两种互不相容的职责
设想 portal.example 被发布为 service.example.net 的 CNAME。客户端询问地址,源服务器先返回别名,解析器再去目标名寻找 A 或 AAAA。若源 zone 同时给 portal.example 放上一条自己的 A 记录,缓存该信哪一个:源名直接携带的地址,还是沿别名抵达的地址?
1987 年 11 月发布的 RFC 1034 没有把这个冲突留给实现者随意选择。CNAME 的 owner 是 alias,RDATA 中的名字才是 canonical target;一旦节点存在 CNAME,就不应再有其他普通数据。
这不是 zone file 的整洁偏好。规范给出两个架构理由:canonical name 与 alias 的数据不能互相打架;缓存了 CNAME 的解析器也必须能够直接使用它,不必回头询问权威服务器这个 owner 是否还有另一类型的数据会推翻改道。
“排他”因此创造了一种很窄的权力。CNAME 不告诉解析器地址、邮件服务器或应用服务是什么,只决定下一次问题应从哪个名字开始。
答案会改写接下来要问的问题
CNAME 不是被动返回一个同义拼写。若 QTYPE 不是 CNAME,RFC 1034 的算法要求服务器把 CNAME RR 放入 Answer,随后把工作中的 QNAME 改成目标名,从头开始匹配。只有直接查询 CNAME 时不追随,因为此时客户端要看的正是改道记录本身。
RFC 9499 用三组术语呈现这次移动。Original QNAME 是请求报文真正携带的名字;effective QNAME 是沿 CNAME chain 实际解析过的任何名字;final QNAME 是链尾最终处理的名字。因此,响应 Question 区仍可回显原始名字,而真正回答请求的 RRset owner 已是另一个名字。
失败时,这一差别尤其重要。源别名可能确实存在,并得到源 authority 的权威回答;终点却可能不存在、暂时故障,或落在完全不同的 zone。final QNAME 的否定答案不能倒推成 original alias 从未存在。
改道不是委派
DNS alias 与 DNS delegation 都会让解析继续前进,却转移不同的东西。zone cut 上的 NS RRset 告诉解析器,哪个 name server 对下级 zone 掌握权威。CNAME 始终是源 authority 为自己的名字发布的数据:它启动另一次查询,却没有把源 zone 的权力交给目标运营者。
源 zone 管理员可以创建、修改或删除 portal.example,并选择 alias TTL。service.example.net 的 authority 则控制终点 A、AAAA 或其他 RRset 及其 TTL。源方指向目标,并不获得修改目标的权力;目标方也不能因此编辑源别名。
RFC 6604 后来澄清 CNAME/DNAME chain 的状态语义:一个响应可以对第一段 alias 给出权威答案,同时在后续阶段携带 referral 或失败。第一句话是谁说的,与整段旅程由谁保证,是两件事。
一个别名只有一个目标,不等于一台机器只能有一个名字
“canonical” 很容易诱发越界理解,仿佛 DNS 规定一台 host 或 interface 只能有一个官方名称。RFC 2181 明确否定这种推论。DNS 没有对机器身份设下一名制。
真正的规则更窄:一个 CNAME owner 只能有一个 canonical target。RFC 2181 还提醒,把 owner 口头称为“一个 CNAME”会掩盖方向。owner 是 alias,record value 才是该 alias 操作中的 canonical name。
多组域名可以合法地通向同一服务;不是 alias 的名字也可以同时拥有多种普通 RRset。被禁止的是同一个 owner 一边宣布“请去别处继续问”,一边又自称可以在这里独立回答。
zone apex 为什么不能走这条捷径
排他规则带来一个直接后果。zone apex 必须携带 SOA 与 NS;CNAME owner 又不能同时携带这些普通记录,因此 apex 不能是普通的 CNAME。
RFC 1912 记录过这种配置的危险。它用当时的 BIND 举例:若 apex 的 NS 旁再放 CNAME,服务器可能接受 CNAME 而忽略其他资源,最终连该 zone 下的名字都不可见。具体行为属于那个时期的实现,数据模型的冲突却不会因此消失。
今天某些服务会在 apex 综合生成地址答案,或把这种产品行为称为 flattening。它们可能有实际用途,却不是 wire 上的 CNAME RR。诊断时若把所有便利功能都叫“apex CNAME”,反而会抹掉协议真正要求核对的 authority 与 cache 边界。
有些位置不能把下一跳藏在别名后面
RFC 2181 还规定,NS 的 target 与 MX 的 exchange 不能是 alias。查询 NS 或 MX 时,服务器会尝试在 Additional section 附上相关地址,减少预见得到的后续查询;这一处理不会先追 CNAME,再替 canonical target 补地址。
若把 alias 填进这些位置,就会增加查询与网络负担;在 delegation 等困难场景里,缺失地址甚至会让解析失败。写入 NS/MX 的管理员应先解析别名,再直接发布真正拥有地址 RRset 的名字。
这不是禁止所有“名字指向名字”。它限制的是那些依赖可预测地址发现的协议位置:隐含的额外跳转会破坏原本可一次随附的引导信息。
DNSSEC 增加证明,没有让别名重新成为目的地
随着 DNSSEC 演进,“不能有其他数据”获得了必要的限定。RFC 2181 允许当时的安全记录与 CNAME 共存;RFC 4034 后来要求 signed zone 在 CNAME owner 处放置 RRSIG 与 NSEC。
这些记录不与目标竞争。RRSIG 验证 CNAME RRset,NSEC 参与认证否定与类型证明。它们说明别名节点处于什么状态,不赋予源名一套独立地址、邮件路径或应用内容。
RFC 4033 也限制了安全结论。DNSSEC 在验证成功时提供 data-origin authentication、integrity 与 authenticated denial;它不会证明目标应用健康、某个人或企业的身份、合同关系或源名的法律所有权。
chain 可以存在,loop 必须被识别
一个 alias 可以再指向另一个 alias。RFC 1034 因效率原因建议避免多层 chain,却没有把有限 chain 本身定义成错误。解析器真正必须捕获的是 loop,以及最终指向不存在名字的情况,并把错误状态交给客户端。
所以运维对象是一张图,不是一次字符串替换。每条边都有 owner、authority、TTL,可能还有自己的 DNSSEC 状态;链尾数据另有一套 TTL。不同 cache 按不同时间淘汰旧边,同一迁移在各观察点会经历不同阶段。
这正是解耦的价格与价值。源运营者无需复制目标数据就能移动熟悉名称;目标运营者更换地址时也不必编辑所有别名 zone。但双方都能独立变化,缓存会把过去的陈述保存到各自到期为止。
最小共同规则靠拒绝混合真相而成立
CNAME 用一项刻意很薄的机制解决分布式维护问题。它不需要一个登记所有等价名字的全球 registry,也不需要中央机构裁定哪个地址才“真正属于”alias。它只需要一条任何解析器都能缓存、追随并独立验证方向的边。
排他规则是这项设计的制度中心。源名可以是绕路,也可以是目的地,但不能同时扮演两者。一旦选择绕路,它的权力真实而有限:发布一个目标,保留链上证据,把终点数据留给终点的控制者。
来源与证据边界
原始模型与解析算法来自 RFC 1034、RFC 1035;常见配置错误与命名澄清来自 RFC 1912、RFC 2181;DNSSEC 例外来自 RFC 4033、RFC 4034;chain 状态与现行术语来自 RFC 6604、RFC 9499。这些标准不能证明当代部署比例、厂商 flattening 行为、解析器 chain 上限、dangling alias 发生率、应用所有权或任何现有服务的可用性。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
