摘要

  • RFC 5368 让 Refer-To 通过 cid: 指向资源名单,接收方据此为每个有效目标创建独立 SIP 请求;父 REFER 的成功响应不等于这些子请求成功。
  • 标准建议使用 norefersub 和 Refer-Sub: false,主动关闭单目标 REFER 通常拥有的隐式订阅,因为 message/sipfrag 通知没有定义如何承载多笔目标事务。
  • 可辩护记录必须同时保存引用对象、非分叉前提、返回的 Refer-Sub、名单归一化、逐目标事务和服务专属状态。RFC 8262 后来明确 cid: 可以指向 MIME 部分,也可以指向完整消息正文。

引用值精确,对象边界却曾经不精确

RFC 5368 没有把所有目标直接塞进 Refer-To。Refer-To 保存一个 Content-ID URL,资源名单放在消息正文中。这样做把控制意图与一组结构化字节连接起来,也允许名单拥有自己的内容类型与处置方式。

审计时不能只问两个字符串是否相等。还要问 Content-ID 标在什么对象上:multipart 中的某个部分,还是没有外层 multipart 的完整正文?消息经过网关后,边界、头部位置和标识符是否一起改变?解析器最终散列的是哪一段字节?

RFC 8262 解释了这不是纯理论问题。包括 RFC 5368 在内的一些文档示例曾经展示完整消息正文被 Content-ID 标记并由头部引用,但当时已有规范只明确了对正文部分的引用。许多实现者把示例当成许可。2017 年的更新才用规范性语言允许指向正文部分或完整正文,并允许使用 MIME Content-ID 或 SIP Content-ID。

因此,旧抓包中“cid 能解析”不够。分析者必须说明实现依据哪个规则、标识符附在哪里、引用解析到了什么对象,以及该对象的确切哈希。示例能启发实现,却不能替代未写出的规范权力。

被引用的名单只是父操作的输入

接收方收到多目标 REFER 后扮演两个角色。面向发起者,它是处理 REFER 的 UAS;面向名单中的每个目标,它变成发出新请求的 UAC。角色转换意味着事务、身份、授权和结果都出现了新的边界。

RFC 5368 的流程图先出现 202 Accepted,随后才出现逐目标 BYE。这一时间顺序已经足以限定 202 的含义:接收方接受了尝试执行的责任。它不可能提前证明某个 BYE 找到了正确对话、到达远端、被接受,或者导致参会者从会议状态中消失。

同理,200 也只属于父 REFER。把 2xx 写成所有目标的成功,是把上游受理凭证借给尚未完成的下游事务。正确的数据模型应当有一条父记录和多条子记录。父记录包含发起者、应用场景、名单引用、归一化规则与响应;每条子记录包含目标、方法、对话绑定、发送时间和独立结局。

名单中重复 URI 的处理也不能消失。提交集合、等价比较后的有效集合与实际发出的请求集合可能数量不同。数量变化若有规则和记录,是规范化;若没有记录,就无法区分去重、丢失或越权修改。

通常的结果通道被刻意关闭

普通单目标 REFER 会创建隐式 refer 事件订阅。接收方通过 NOTIFY 发送 message/sipfrag,让发起者看到被触发事务的进展。这个模型天然围绕一笔目标事务。

多目标 REFER 同时产生多笔事务。它们可能处于不同阶段,并拥有彼此矛盾的最终状态。RFC 5368 没有让一个 sipfrag 假装代表全部事务,而是明确说本文没有提供多目标结果报告机制,并建议使用 norefersub 与 Refer-Sub: false。

当接收方在 200 中返回 Refer-Sub: false,隐式订阅不创建。这之后没有 NOTIFY,是合同结果,不是“没有错误所以成功”。如果监控系统沿用单目标经验,把通知沉默转换为总体成功,它就在一个被标准主动删除的通道上制造证据。

请求中的 Refer-Sub: false 也只是提议。只有响应再次返回 false,才证明接收方同意抑制。响应缺失该字段或返回 true 时,普通隐式订阅仍然建立。请求与响应必须成对保存。

关闭订阅之前必须证明不会分叉

隐式订阅还承担发现 REFER 分叉所产生多个对话的作用。如果一条 REFER 可能到达多个独立 UA,却关闭订阅,发起者就可能看不到额外分支。

RFC 4488 因此规定,只有在发起者能够确定 REFER 不会分叉时,才可使用 Refer-Sub: false。RFC 5368 的示例使用 GRUU 来建立这一前提。地址不是展示用字符串,而是支撑抑制安全性的证据。

现代服务入口常常隐藏负载均衡。内部调度到唯一负责人,与 SIP 层把请求投递给多个 UA,不是同一件事。记录至少需要 Request-URI、路由集、非分叉依据、响应分支和实际接收者身份。仅保存 norefersub=true,会丢掉允许它成立的条件。

如果接收方不支持必需的 norefersub,会返回 420。它证明的是该目标不支持被要求的扩展,不证明名单成员拒绝操作。自动删掉 Require 再试,会改变结果通道;恢复策略必须同时说明以后从哪里取得逐目标证据。

列表属性不能跨方法继承含义

默认名单格式来自 RFC 4826,并可使用 RFC 5364 的复制控制属性。在 INVITE 场景中,to、cc、bcc 可能决定被邀请者看到怎样的接收者历史。但对既有对话中的 BYE,这类角色没有同样含义。

这正是 RFC 5368 要求接收方理解应用和方法的原因。它不得成为把任意方法向任意名单扩散的“哑服务器”。接收方需要认证发起者、判断其是否有权请求这种方法、遵守目标 opt-in 与应用政策,并拒绝不理解的方法。

IANA 中登记 multiple-refer 与 norefersub 只建立共同词汇。登记不能证明某台设备启用功能、某个用户有权使用、请求被接收、子事务被发出或业务效果发生。每一步都需要自己的凭证。

会议状态是另一架摄像机

标准建议,在会议应用里可以订阅会议状态来了解参与者变化。这是一条服务专属观察面,比父 REFER 的 2xx 更接近业务结果。

但会议状态也不是逐事务日志。通知有版本,可能是全量或增量,可能延迟或在订阅中断期间丢失。某人从名单中消失,可以支持“此刻 focus 不再将其列为参与者”,却不能单独证明具体 BYE 是原因。对方可能自行离开,也可能由另一控制者移除。

可靠核对应保留四组数据:原始请求与有效目标、生成的子事务、每笔事务的网络结果、带版本和接收时间的应用状态。差异不是噪声,而是故障调查入口。

证据边界

多目标 REFER 成功后,最强可辩护陈述是:特定接收方接受了一条请求;该请求的 Content-ID 引用解析到特定有效名单;双方达成了特定订阅安排。它没有自动声明每个目标已收到、接受或产生业务效果。

完整链条包括发起者身份与授权、应用上下文、非分叉证明、REFER 原始字节、选项标签、响应状态和 Refer-Sub、引用对象及哈希、提交和归一化名单、逐目标请求、逐事务结局、服务状态版本,以及最后单独记录的人类或商业结果。

这种结构没有削弱聚合命令的效率。它只是拒绝让一个父级受理回执冒充所有子级事实。