摘要

  • IPV6_ADDR_PREFERENCES 表示应用希望系统优先采用哪类源地址;调用成功只证明偏好格式被接受,不证明目标属性存在或最终入选。
  • 若属性是硬性要求,应用必须让栈选址、回读地址、单独验证并在不满足时终止;此后仍要分别观察发包、路径和业务完成。

一块控制台把“临时地址偏好已写入”显示成“隐私地址已使用”。两个绿色状态之间,只差了几个字,却跨过了整个操作系统和网络。

RFC 5014 处理的是一个有限接口问题。应用若直接用 bind() 或 IPV6_PKTINFO 指定源地址,就要自行判断该地址对目标、接口和作用域是否合适。该文档提供另一条路:应用只改变若干偏好维度,其余选址规则仍由系统执行。

规范定义三组相反属性:home 与 care-of、temporary 与 public、CGA 与 non-CGA。不同维度可以组合;同一维度的两端同时出现则矛盾。socket 侧返回 EINVAL,getaddrinfo() 侧返回 EAI_BADEXTFLAGS。这能证明请求没有自相矛盾,却不能证明机器能够满足请求。

RFC 5014 明确选择“偏好”而非“要求”。应用偏好临时地址,但节点没有临时地址时,系统可以改选公开地址。组合偏好中某一属性不可用时,可用的另一属性仍可生效,缺失维度回到系统默认。系统不支持的偏好标志应被静默忽略。因此 setsockopt() 返回成功,并不说明哪条分支真正发生。

选址还有解析器一侧。目标地址排序可能受预期源地址影响,所以应用必须向 getaddrinfo() 和 socket 提供语义一致的 IPV6_PREFER_SRC_* 标志;不一致时,规范把行为列为未定义。只记录 socket 选项,会漏掉此前已经改变目标顺序的决策。

更直接的指令还可以覆盖偏好。应用若同时通过 bind() 或 IPV6_PKTINFO 固定源地址,固定值优先。于是日志里的“偏好存在”是真实配置事件,却不是谁控制最终选择的真实说明。

规范第 13 节专门面对“不能用错属性”的应用,并直接指出偏好不能保证应用要求得到满足。正确流程是:向解析器和 socket 写入同义偏好;让协议栈选择;用 getsockname() 读取已选源地址;用 inet6_is_srcaddr() 验证该地址是否满足属性;不满足就中止通信。

“让协议栈选择”也要区分是否已经发包。面向连接的 connect() 可能在验证前发出 TCP SYN。若连一个包都不能先离开,RFC 5014 定义 bind2addrsel(),只绑定本来会被选择的源地址。UDP 的 connect() 则可在本地完成选择而不自行发出数据报。已选中不等于已发送。

验证函数有三个结果:本地地址满足全部有效标志时为 1;属性不符时为 0;地址不属于本机或输入无效时为 -1。即使返回 1,结论也有限。规范指出,在节点未实现 Mobile IPv6 或移动节点正在 home 状态时,IPV6_PREFER_SRC_HOME 都可能为真。它不能证明人的位置。

“临时”和“密码生成”也不能被市场语言放大。RFC 8981 说明地址轮换可以缩短基于同一地址进行简单活动关联的时间窗口,并不保证上层匿名。RFC 3972 让 CGA 与公钥材料建立可验证关联,同时明确 CGA 本身不是经过认证的身份。偏好 CGA 既不是签名验证,也不是授权结果。

默认规则还会随规范演进。RFC 5014 以 RFC 3484 为背景,当时相关默认偏好是公开地址;后来 RFC 6724 取代它,并把规则改为优先临时地址。审计必须捕获当时机器的候选集合与策略版本,不能从 2007 年文本反推今天所有实现。

一份源地址选择凭证至少应保存:应用与 socket 标识、请求标志及原值、解析器标志和目标排序、不支持或矛盾标志的处理、候选集合与策略修订、任何显式 bind() 覆盖、选址调用及其是否可能先发包、getsockname() 回读、inet6_is_srcaddr() 的输入与三态结果、继续或终止决定,以及独立观察到的出站包、回包和应用结果。

这是一项运营治理建议,不是 RFC 的隐藏要求。它落实 Heng Lu 的现实层级方法:应用意图、主机选择、本地属性、网络路径和业务结果属于不同事实对象。只有凭证把相邻边连接起来时,结论才能向前移动。

来源