摘要

  • RFC 1464 提议把 名称=取值 放进现有 DNS TXT 记录,使多数服务器无需支持新记录类型也能传递新属性;它没有建立通用的属性名称注册表。
  • 因而,成功查询和解析只证明特定时刻收到一组字节;名称的语义、发布者授权、缓存时效、DNSSEC 验证、应用决策与现实结果仍须分别留证。

1993 年的设计者面对一个很现实的阻力:DNS 擅长全球分发,但新增结构化信息并不只是在文档里写一个类型。权威服务器、解析库、诊断工具和中间软件都得逐步认识它。RFC 1464 选择绕过这条部署链最厚的一段。

它没有要求大多数 DNS 服务器理解新属性。服务器继续认识 TXT;属性格式则藏在 TXT-DATA 里面。应用把名称和值写成一条 ASCII 字符串,查询者在取回后自行拆解。这是一次把共同层做薄的实验,也把更多责任推给了端点。

属性由解析动作产生

RFC 1464 给出的外部形式包括所有者名称、类别、TTL、TXT 类型和一段带引号的文本。第一个未转义的等号是分隔符。等号之前是属性名,之后全部属于取值;因此 equation=a=4 的名称是 equation,值是 a=4。

属性名不区分大小写。两端的空格和制表符通常被忽略,除非用重音符号保留。若名称本身含等号,要在等号前放重音符号;名称中的重音符号也要重复。取值侧没有这套重音符号规则,所有可打印 ASCII 字符都可出现,后续等号和空白原样交给应用。

这一区分后来由已验证勘误 5193 修正得更清楚。原表格里一个取值错误地重复了重音符号;勘误指出,越过第一个未转义等号后,重音符号不再承担 RFC 1464 的引用功能。另一个保留待文档更新的勘误 5194 只是修正表格对齐。

没有未转义等号的 TXT 字符串会被这种查找忽略;以等号开头、属性名为空的字符串也会被忽略。RFC 还建议提供类似 gethostbyname 的专用函数,移除名称里的引用字符,并处理同一属性的多个值或多个不同属性。

这里已经出现三层事实。DNS 服务器返回了 TXT RRset;RFC 1464 解析器从某条字符串中认出了属性;上层程序再决定属性是否可用。没有实现这套解析器的程序并没有“错读 DNS”,它只是没有加入同一兼容集合。

一个可读的名称并不等于共享词典

RFC 1464 预见到名称冲突。它设想过为知名属性建立注册过程,可以是定期更新的清单,也可以依赖已发布的对象标识符。但文档明确不处理注册本身。

这使实验可以先运行,不必等候一个新的中央表格;代价是等号左边的词没有全网公认的定义。status=active 可以描述机器、账户、合同、路由、队列或某个本地流程。语法只知道 status 与 active 的边界,不知道对象类型、允许值、版本或冲突规则。

同样,能够修改区域文件的人具有发布字节的技术能力,却不当然拥有所有现实领域的授权。一个域名管理员可以把“approved”写进 DNS,但不因此成为采购批准人、法人代表或设备传感器。应用若要把该词转成动作,必须另外判断该发布者是否对这个决定拥有权限。

这正是现实层不能被符号替代的地方。字符串可见,是传输事实;属性被定义,是模式事实;发布者有权,是授权事实;对象确实如此,是现实事实。它们可能同时成立,也可能只成立一部分。

TXT 查询把邻居一并带回

RFC 1035 把 TXT 定义为一个或多个字符串,并指出文本语义依赖它所在的域。DNS 查询选择的是所有者、类别和记录类型,不会把“请只返回 RFC 1464 的 printer 属性”发送给权威服务器。客户端先收到该名称下的 TXT RRset,再在内部筛选。

RFC 5507 后来把这类做法分析为记录内部的子类型。客户端无法只请求所需子类型,必须搬运完整 RRset。DNSSEC 也对完整 RRset 签名,所以某一应用改动自己的字符串时,共享集合要整体重新签名。TXT 又没有标准选择字段;RFC 5507 对 RFC 1464 的评价是:它尝试过,但并未成功。

这句话不能倒推出“从未有人实现”。它说明的是规模化边界。两个预先约定的程序可以可靠交换名称和值;它们却无法阻止同一所有者名称下出现另一套 TXT 约定。解析器必须在无关记录、同名属性、多个取值和大小限制之间自我保护。

RFC 1464 本身也记录了当时的实现限制:有些服务器限制某一名称下 TXT 的大小或数量,甚至可能不支持 TXT。通用容器里的自由因此并非无限空间,而是多个应用共享同一响应预算。

TTL 让“DNS 说过”成为带时间的证词

区域内容变更后,旧值不会同时从所有解析器消失。递归解析器可以在 TTL 范围内继续返回此前取得的 RRset;应用还可能在它之上建立自己的缓存。一个完全符合 DNS 行为的答案,可能已经落后于发布者此刻的业务意图。

因此,仅保存 mode=off 不能解释一次决策。审计需要知道查询的完整名称、类别和类型,收到的完整 RRset,查询时间,剩余 TTL,递归路径,以及应用何时解析、何时执行。旧值可能是发布错误,也可能是正常缓存,还可能是应用在 TTL 之后继续复用;缺少时间链就无法区分。

TTL 规定 DNS 数据可复用多久,不会验证一项许可、报价或紧急状态在现实中仍有效。若属性直接触发高风险动作,应用必须规定自己的新鲜度上限,并说明它如何与 TTL、签名有效期和外部授权期限组合。

DNSSEC 保护来源链,不判断命题真假

RFC 1464 的安全章节只有一项边界声明:本文不讨论安全问题。后来 RFC 4033 描述的 DNSSEC 能在信任链下提供来源认证和 DNS 数据完整性保护,同时明确不提供保密性。

一次成功验证证明 RRset 沿验证者接受的 DNS 委派路径保持可认证、未被无声篡改。它不定义属性名,也不检查值所描述的设备、公司或人。它更不会自动证明区域操作者在应用所关心的法律或业务关系里有权发出指令。

于是,“secure”状态与“可执行”状态必须分开。一个经过 DNSSEC 验证的属性可以因模式不匹配、时间过旧或发布者无权而被拒绝。一个未验证的属性也可能在低风险、本地约定的环境中被使用,但其证据等级不能事后改写成已验证。

DNSSEC 能保护回答从哪里来;应用仍要解释回答在说什么、是否足以行动。

后来的办法是先缩小解释范围

TXT 没有因为 RFC 1464 的通用尝试受挫而退出应用协议。后续设计转而把解释上下文写得更窄。

RFC 6763 的 DNS-Based Service Discovery 同样使用键值对,但它们位于特定服务类型的 PTR、SRV 与 TXT 组合中。每个键值对独占 TXT 的一个组成字符串;服务配置文件定义哪些键有效;未知键被忽略;重复键保留第一次出现;主机名和端口留在 SRV,不在 TXT 里复制。

这不是把 RFC 1464 的语义追认为普遍规则。相似的等号服务于一套新的、受服务类型约束的协议。RFC 6763 甚至主张:如果应用协议能够在连接中协商版本和功能,TXT 最好只作为发现优化,而不是取代与真实服务的对话。

RFC 6950 回顾了 TXT 应用史:无需注册新 RR 类型的开放路径非常有吸引力,但解析器很难可靠地区分不同应用的记录。专用所有者名称可以把用途隔开。

RFC 8552 又把下划线 AttrLeaf 范围正式化。以下划线开头的全局节点名与 RR 类型形成需向 IANA 登记的唯一组合。应用直接查询专用叶节点,就能得到相关 RRset,不必从父名称下的一团通用记录里搜索。

然而,位置仍不等于内容规则。RFC 8552 明确把叶节点之下的详细结构交给各应用规范。后来的架构没有让记录自解释,而是把“在哪里解释”“由哪份规范解释”变成了可注册、可查询的事实。

文档记录的是提案,不是采用率

RFC 1464 的 Experimental 状态要求谨慎。规范提供语法、例子和一个可能的库接口,却没有列出互操作实现、运行区域或采用比例。要证明运行事实,还需要代码、测试、配置、区域文件和有来源的部署记录。

发布不是运行。生产者可以写出完全符合语法的属性,而消费者从未查找它;双方可以正确切分字符串,却对名称含义意见不同;应用可以接受取值,后续动作仍失败。

把这些结果分开,RFC 1464 的历史意义反而更清楚。它以最低共同改动打开一个实验面,同时暴露了共同层省略的每项决定最终会落到何处:名称、配置文件、解析器、缓存政策和运行代码。