摘要

  • RFC 9844 要求接收非 global IPv6 地址的用户界面,同时支持 link-local 或 scoped multicast 地址及其 zone identifier;后者通常是操作系统定义的接口名。
  • 人类可读标签要在本机映射成数值 interface index,才能驱动 socket;它对本地动作不可或缺,对其他节点却毫无既定含义,必须止于主机边界。
  • 完整凭证既要保存输入、校验、映射、接口生命周期与执行结果,也要用包级证据证明 zone 文本没有被传出去。

一次诊断失败,有时并不是目标不存在,而是工具把“地址正确”误当成“路径已经确定”。

主机同时接着两个链路。两个链路上都可能解释同一段 link-local 地址。表单只收地址,不收接口;内核没有足够信息选择范围。后来有人在地址后附上接口名,操作终于成功,却又把组合字符串写入跨主机自动化模板。第二台主机也有同名接口,但它连接的是另一张网。

前一个错误丢了本地上下文,后一个错误把本地上下文夸大成了通用身份。RFC 9844解决的正是这对相反风险。它的正式记录、纯文本版本和XML 源文档表明,该标准于 2025 年 8 月发布,废止 RFC 6874,并更新 RFC 4007、7622 与 8089。标准证明公共规范已经形成,不证明任何产品已经正确实现,也不证明界面里选中的设备就是业务想找的设备。

地址文本没有携带全部本地事实

RFC 4291定义 IPv6 地址架构,RFC 5952给出文本表示建议。Link-local 的价值恰恰来自范围受限,它并不承诺跨链路唯一。主机有多个活跃接口时,地址文本只能说明“链路内的地址”,无法单独说明“哪一条链路”。

RFC 4007用 zone index 补足这一点。在面向人的界面中,数值 index 常由 zone identifier 表达,通常就是接口名。RFC 9844 举出 Linux 风格的 %eth0 与 Windows 风格的十进制形式。这些字符不是 IPv6 报头中新添的地址位,而是当前节点交给本地协议栈的选择说明。

选择接口就是行使控制。Ping、设备配置、流量抓取或管理请求,即使语法完全合法,也可能落到错误链路。相反,一个拒绝 zone 输入的管理工具,可能让本来可达的 link-local-only 设备在操作层面变成“不可达”。RFC 9844 列举故障诊断、设备配置、监测、虚拟打印端口和海事网络;RFC 6991提供 YANG 相关数据类型,RFC 8925则提醒,在 IPv6-mostly 环境中,原生 IPv4 未必还能充当绕行出口。

支持复制粘贴并非界面修饰。完整地址与接口名都可能很长,手工重输会制造错误。不过,复制只能保留字符串,不能把原主机的接口表一起复制。文本离开生成它的节点后,权威随之结束。

从人类输入到数值接口

RFC 9844 的规范要求很窄,却很具体:任何允许输入非 global unicast IPv6 地址的 UI,都必须提供输入 link-local 或 scoped multicast 地址并选择 zone 的办法。优先支持 RFC 4007 的完整形式;若 % 分隔符受限,可以换用替代分隔符、把地址和接口分成两个字段、从活跃 zone 列表选择,或另设命令行参数。

这些界面长得可以不同,但控制不变量相同:地址和 zone 是两项可以分别审计的输入,最终要变成 socket 使用的数值 interface index。单个输入框不是标准的本质,映射链才是。

fe80::1%eth0 不能直接交给 inet_pton() 转成二进制。实现可以调用 getaddrinfo(),也可以先拆成两段,再分别使用 inet_pton() 与 if_nametoindex()。RFC 3493在 IPv6 socket 地址结构里定义 sin6_scope_id,但它与接口或接口集合之间的对应关系仍由实现决定。

因此,“输入通过”不是完成凭证。系统应记录原始值、解析和政策版本、长度与字符校验、映射所得数值 index、当时的接口身份、目标 scoped 地址、socket 构造结果以及最终观察。若接口在用户选择后、socket 使用前被删除或替换,竞态要显式失败,不能把旧批准悄悄粘到新接口上。

这是一种可验证的 running-code primacy。标准只协调最小交接规则,本地系统负责证明交接实际发生。下拉列表可能过期,合法接口名可能连着错误线缆,socket 成功也可能触达错误设备。证据必须一直跟到运行结果,不能停在表单边缘。

本地标签没有跨节点护照

RFC 9844 的安全边界没有模糊空间:zone identifier 仅具本地意义,不得发到线上。从 UI 获得该标签的软件不应继续传输。RFC 4007 的安全章节还警告,不要轻信数据包中作为数据出现的非 global 地址文本与 zone,因为远端可能借此欺骗接收方理解本地主机的 zone。

停止传输不是销毁证据,而是分离权威域。主机内部必须保留 zone 映射,才能解释 socket 为什么选中某接口;到了包边界,这段文本不再具有解释他人世界的资格。IPv6 包携带 scoped 地址,不携带本机接口名。审计日志可以保存本地选择,但 peer 不应被要求把它读成共享事实。

这条规则也防止接口命名泄露拓扑、系统习惯或组织结构。更大的风险是自动化中的权力膨胀:控制器把 eth0 存下来,在另一台机器重放,便声称重建了同一动作。它重建的只是字符,不是 zone。

所以最小证据单元必须成双出现。第一份是本地凭证,把人类输入绑定到某主机某时刻的 interface index;第二份是线上观察,证明本地标签没有逃逸。只存地址会丢掉控制决策;只存组合字符串却不存 host、映射时间与生命周期,会制造一种虚假的精确。抓包工具若把 zone 当作显示注释,也必须区分注释与真正发送的字节。

宽松语法不等于无害输入

RFC 4007 没有为 zone identifier 规定统一长度和字符集。这为不同操作系统保留空间,也把输入治理责任交给实现。RFC 9844 建议使用适合环境的长度限制,通常对齐操作系统接口名上限,并做相应字符检查。ASCII NUL 必须拒绝,否则后续字符串处理可能对“值在哪里结束”产生不同答案。

风险不只缓冲区溢出。不同阶段可能用不同方式解码分隔符;规范化可能改变查找结果;日志渲染出的值与系统调用拿到的值可能不同;shell 包装器会把字符当作语法;界面显示的活跃接口列表也可能在提交时已经过期。正确做法不是一条跨平台万能正则,而是一条类型清晰的路径:保存输入字节,按目标操作系统和调用方式校验,在临近使用处只映射一次,同时保留原表示与解析结果。

名称与数字各有失效方式。名称便于人工复核,却可能被重命名或复用;数字更接近 socket API,却可能在重启或接口重建后被回收。两者都不是永久资产标识。历史凭证还需要主机身份、启动或生命周期上下文、时间,以及可获得的稳定设备元数据。即便如此,结论也只能是:“这台主机在这个时刻把这段输入解析成这个接口。”

被废止的 URI 路径说明了什么

RFC 6874曾尝试更新 URI 语法,让 IPv6 literal 可以携带 zone identifier;它的状态页现在记录已被废止。RFC 9844 说明浏览器实现者认为那条路径不可行,于是撤销其对 RFC 3986 的更新,改成一般 UI 要求,并从 RFC 7622与 file URI 规范删除对 RFC 6874 的依赖。

这是标准治理的一条有价值记录。公开共识并不让初始设计免于运行现实。真正的稳定不是维护错误形式,而是把最小要求退回能够兑现本地语义的层。

RFC 9844 也明确承认,这套办法没有解决 RFC 6454 的 HTTP origin 问题,规范性语句不适用于浏览器抓取的 URI。本文保留这条边界,不把已经退出的浏览器方案借文章重新引入。

测试重点是“出现”和“消失”

验收环境应准备两个活跃接口,让同一 link-local 地址文本在两条链路上都可解释,然后验证显式选择、无意外 default,以及未知 zone 的清晰错误。还要在界面显示之后、真正使用之前重命名或删除接口;跨一次重启测试数值 index 复用;输入超长值、NUL、替代分隔符、Unicode 边界和对 shell 或日志有特殊意义的字符。

接着观察主机边界。本地凭证应显示最终 index,包级抓取应证明 zone 文本没有传出。远端内容若携带一个 zone 标签,系统不得不经本地映射与政策便直接信任。解析失败也不能成为“随便挑一个接口”的授权。

最后,把绿色状态拆成四个问题:输入是否被接受?接口是否解析成功?包是否发出?预期设备是否回答?这四项可以分别成功或失败。任何把它们压成一个勾号的 UI,都会把证据层重新混在一起。

证据边界

本文没有测试任何操作系统、浏览器、路由器、打印机、抓包器、YANG 客户端或海事网络;没有测量支持率、错误率、采用规模或安全事件。RFC 中的产品与系统例子只用于解释机制,不是当前版本认证。

能够成立的结论更窄也更可靠:scoped 地址要靠本地上下文才能行动;这个上下文必须在节点内可追责,并在节点边界失去权威。好的基础设施要同时保存这两个事实。

来源