概述
当传递确认(acknowledgment)被静默丢失时,流式客户端连接可能会陷入停滞。发送方会不断重传数据,直到收到确认或连接被断开,但无法可靠地确认确认消息是否已到达对端。本提案在 SendMessageExpiresMessage 的 flags 字段中新增一个标志位,使客户端可以指示路由器为发送至同一目的地的后续消息选择不同的出站隧道。流式协议在检测到连接停滞时,将使用该标志位来触发隧道切换。
触发器
在流层应测量到两种情况,当出现这两种情况时,客户端应设置下一个出站消息的标志。
发送方
在客户端当前的重传超时时间内未收到确认。
接收端
接收方已观察到远程多次重传相同的数据,表明其确认信息未能到达远程。接收方应在下一条出站 I2CP 消息中设置此标志,以便确认信息通过不同的路径到达远程。接收方必须等待以下条件全部满足后才能设置该标志:(1)已收到重复的数据包,(2)已发送至少一个确认信息,以及(3)远程再次进行了重传。
为限制基于时间关联的攻击,客户端在每个连接的每10秒时间窗口内不得设置该标志超过一次。客户端在检测到阻塞情况后,还应延迟设置该标志,延迟时间为从 [0, min(T/4, 2000ms)] 范围内均匀随机选取的抖动值(T 为客户端当前重传超时时间,单位为毫秒),以降低时间关联的精确度。
规范
SendMessageExpiresMessage 的 flags 字段位于 Date 字段之后的高 2 个字节(自 0.8.4 版本起重新定义),并以大端序传输。第 15 位目前未使用;本提案对此进行了定义。
位序:15…0
| 位 | 名称 | 描述 |
|---|---|---|
| 15 | SWITCH_OUTBOUND_TUNNEL | 若为1,路由器应从此目的地的消息发送池中选择一个不同的出站隧道。若没有可用的备用隧道,则此标志将被静默忽略。路由器绝不应仅因设置了此标志就关闭或停用先前使用的隧道。 |
| 此标志默认为 0。未实现此标志的路由器必须在不报错的情况下忽略它。 |
实现说明
当设置 SWITCH_OUTBOUND_TUNNEL 时,路由器应从出站隧道池中均匀随机地选择一条隧道,但需排除以下情况:
- 当前会话正在使用的隧道,以及
- 池中最近一次失败的隧道(如果有的话)。
所有其他隧道健康度量指标、构建时间或选择历史都不得影响选择,因为加权选择可能会有利于Sybil攻击者。如果经过这些排除后,池中没有符合条件的隧道,则该标志将被静默忽略。
此标志不会产生额外的隧道消息;切换隧道可能会改变感知到的延迟。每连接每10秒的速率限制(参见触发条件)可防止过度切换。
匿名性考量
SendMessageExpiresMessage 中的标志通过 I2CP 传递,I2CP 是客户端与其自身路由器之间的本地接口。这些标志对网络观察者不可见。
匿名性风险基于流量模式:能够监视多个隧道端点的攻击者可以观察到隧道使用情况变化的时间。
直接因客户端停滞而切换出站隧道会产生可检测的行为模式。具体存在两种观测向量:
对出站隧道第一跳的女巫攻击
每个出站隧道的第一个节点会看到从发送方路由器进入该隧道的所有流量。如果攻击者控制了发送方隧道池中多个隧道的第一个节点,就能观察到流量在一个第一个节点停止,同时在另一个节点几乎立即开始,从而将这两个隧道关联到同一个发送者。当拥有 N 个隧道的池中,攻击者控制了 K 个第一个节点时,其观测到任意一次切换事件的概率为 K/N。
流量间隙定时
在连接停滞期间,客户端不会发送新数据,因此旧的出站隧道会变得安静。当切换发生时,流量会在另一条路径上恢复。位于发送方路由器位置的攻击者——例如发送方的网络提供商或第一跳节点本身——可以观察到这种“先沉默后恢复”的模式。此外,中断的持续时间还会泄露客户端当前重传超时值的大致信息。
客户端必须遵守触发器中的速率限制和抖动要求。