tcp假连接_跟坚哥学QUIC系列:连接迁移(Connection Migration)

当代人的日常生活中,手机网络连接会经常在 Wi-Fi 和 蜂窝网络(Cellular)中进行切换。比如:早上从家里出门,连接从 Wi-Fi 变为 cellular;到喜欢的餐厅吃早餐,手机自动连接餐厅的 Wi-Fi;从餐厅到公司,连接又经历了 Wi-Fi -> cellular -> Wi-Fi 的过程。如果我们正在看短视频或者直播,网络在切换的过程出现中断,这无疑是非常影响体验的。

3359263fd01d4d71df1c564ca4c8ff5f.png
日常生活中 Wi-Fi 和 cellular 频繁切换

TCP 的连接标识是通过 “源IP + 源Port + 目标IP + 目标Port + 协议号“ 组成的唯一五元组,一旦其中一个参数发生变化,则需要重新创建新的 TCP 连接。

而 QUIC 的连接标识是一个 64位的连接 ID,用户在 Wi-Fi 和 蜂窝网络(Celluar)切换时,无论是 IP 或者端口(Port)发生变化,QUIC 连接中的连接 ID 保持不变,因此不需要重新创建连接。这种用户无感知的网络切换特性,叫连接迁移(Connection Migration)。

在短视频爆发和全民主播时代,QUIC 的连接迁移(Connection Migration)支持在 Wi-Fi 和 Cellular 无缝切换,给用户带来更好的体验。

7d84661030a5c097e44c5e39f56927ca.png
TCP 和 QUIC 在 Wi-Fi 和 cellular 切换时,唯一标识的不同情况

下面将基于 IETF QUIC 协议草案详细了解下 QUIC 是如何实现连接迁移,以及安全性和隐私方面的考量:

下文中出现的探测帧(probing frames)是指:PATH_CHALLENGEPATH_RESPONSENEW_CONNECTION_IDPADDING 帧是,所有其他帧都是非探测帧(non-probing frames)。只包含探测帧的包是探测包(probing packet),而包含任何其他帧的包是非探测包(non-probing packet)

连接迁移使用连接ID来允许连接转移到新的连接路径。使用连接ID可以在端点地址(IP地址和端口)发生更改的情况下继续使用原来的连接,如下图所示:

       (Before connection migration)
       +--------------+   Non-probing Packet   +--------------+
       |    Client    |  ------------------->  |              |
       |(Source IP: 1)|  <-------------------  |              |
       +--------------+   Non-probing Packet   |              |
              |                                |              |
              |                                |              |
              |                                |              |
              v                                |              |
       +--------------+   Non-probing Packet   |              |
       |              |  ------------------->  |              |
       |              |  <-------------------  |              |
       |              |   Non-probing Packet   |              |
       |              |                        |              |
       |              |                        |    Server    |
       |              |     Probing Packet     |              |
       |              |    (PATH_CHALLENGE)    |              |
       |    Client    |  <-------------------  |              |
       |(Source IP: 2)|  ------------------->  |              |
       |              |     Probing Packet     |              |
       |              |     (PATH_RESPONSE)    |              |
       |              |                        |              |
       |              |     Probing Packet     |              |
       |              |    (PATH_CHALLENGE)    |              |
       |              |  ------------------->  |              |
       |              |  <-------------------  |              |
       |              |     Probing Packet     |              |
       |              |     (PATH_RESPONSE)    |              |
       +--------------+                        +--------------+
       (After connection migration)

连接迁移的简化流程:

  1. 连接迁移之前,客户端的IP 1,使用非探测包(Non-probing Packet)和服务端进行通信。
  2. 客户端的IP变成 2,它可以发送包含非探测帧(non-probing frames)的包,将连接迁移到新的地址。
  3. 客户端在新路径启动路径验证,验证新路径的可达性(reachability)。
    1. 客户端发送包含PATH_CHALLENGE帧的探测包(Probing Packet),PATH_CHALLENGE帧里面包含一个不可预测的随机值。
    2. 服务端在PATH_RESPONSE帧里面包含前一步PATH_CHALLENGE接收到的随机值,响应探测包(Probing Packet)。
    3. 客户端接收到服务端的PATH_RESPONSE ,验证 payload 里面的值是否正确。
  4. 同样的,服务端也需要使用路径验证,验证客户端对其新IP地址的所有权()。

QUIC的设计依赖于端点(endpoints)在握手期间保持一个稳定的地址。在确认握手之前,端点不得(MUST NOT)启动连接迁移。

如果对端(peer)发送了disable_active_migration传输参数,则端点不得(MUST NOT)从不同的本地地址发送数据包(包括探测包(probing packets))给对端,除非该端点已经使用对端的preferred_address传输参数。如果对端(peer)违反此要求,则端点必须(MUST)在不生成无状态重置(stateless reset)的情况下丢弃该路径上传入的数据包,或者继续进行路径验证(path validation)并允许对端(peer)进行迁移。生成无状态重置(stateless reset)或关闭连接将允许网络中的第三方通过欺骗或以其他方式关闭连接。

并非所有对端地址的更改都是有意或主动的迁移。对端可能会经历 NAT 重绑定:由于中间设备(通常是 NAT)而导致的地址更改,分配新的端口甚至新的 IP 地址。如果端点检测到对端地址的任何更改,则必须(MUST)执行路径验证,除非它以前验证过该地址。

探测新路径(Probing a New Path)

在将连接迁移到新的本地地址(new local address)之前,端点可以(MAY)使用路径验证探测新的本地地址(new local address)到对端(peer)的可达性(reachability)。路径验证失败仅仅意味着新路径不能用于此连接。除非没有有效的替代路径,否则验证路径失败不会导致连接结束。

启动连接迁移(Initiating Connection Migration)

端点可以通过在新的本地地址(new local address)发送包含非探测帧(non-probing frames)的数据包,将连接迁移到新地址。

在建立连接期间,每个端点验证其对端(peer)的地址。因此,一个正在迁移的端点可以发送给它的对端(peer),知道它愿意在对端(peer)的当前地址接收数据。因此,端点可以迁移到新的本地地址,而无需首先验证对端的地址。

为了在新路径上建立可达性(reachability),端点在新路径上启动路径验证。端点可以(MAY)延迟路径验证,直到对端将下一个非探测帧(non-probing frame)发送到其新地址之后。

迁移时,新路径可能不支持端点的当前发送速率。因此,端点需要重置其拥塞控制器(congestion controller)和 RTT 估时。

响应连接迁移(Responding to Connection Migration)

从包含非探测帧(non-probing frame)的新对端(peer)地址接收数据包,表示对端已迁移到该地址。

如果接收方允许迁移,它必须(MUST)向新的对端地址发送后续数据包,并且必须(MUST)启动路径验证,以验证对端对地址的所有权(如果验证尚未进行)。

端点只有在响应编号最高的非探测数据包(non-probing packet)时,才改变它发送数据包的地址。这可以确保端点在接收到 reordered 的数据包的情况下不会将数据包发送到旧的对端地址。

在更改发送非探测数据包(non-probing packets)的地址后,端点可以放弃对其他地址的路径验证。

在验证一个新的客户端地址之后,服务端应该(SHOULD)向客户端发送新的地址验证令牌(见地址验证篇)。

注意:

端点可以(MAY)将数据发送到未经验证的对端地址,但必须(MUST)按照下面「对端(peer)地址欺骗」和「路径地址欺骗」的描述防止潜在攻击。如果对端地址是最近见过的(seen recently),端点可能(MAY)会跳过地址验证。特别是,如果端点在检测到某种形式的伪迁移后返回到先前验证的路径,则跳过地址验证并恢复丢失检测(loss detection)和拥塞状态(congestion state)可以减少攻击对性能的影响。

对端(peer)地址欺骗

对端(peer)有可能欺骗其源地址,导致端点向无辜的主机发送过多的数据。如果端点发送过多的数据,则攻击者可能会利用连接迁移来放大向受害者生成的数据量。

因此,需要端点来验证对端的新地址,以确认对端拥有新地址。在对端的地址被认为有效之前,端点必须(MUST)限制它向该地址发送数据的速率。端点在每个 RTT 估时(round-trip time estimation)发送的数据不得(MUST NOT)超过最小拥塞窗口值(minimum congestion window)。在没有这个限制的情况下,端点有可能被用来对不知情的受害者进行拒绝服务攻击(denial of service attack)。请注意,由于端点不会有到该新地址的任何 RTT(round-trip time)测量值,所以预估值应该(SHOULD)是默认的初始值。

如果端点跳过上述的对端地址验证,则不需要限制其发送速率。

路径(on-path)地址欺骗

在路径(on-path)上的攻击者可以通过复制和转发含有欺骗地址的数据包,使其在原始数据包之前到达,从而导致虚假连接迁移。含有欺骗地址的数据包将被视为来自迁移连接,而原始数据包将被视为重复数据并被丢弃。在假迁移之后,源地址的验证将失败,因为源地址处的实体(entity)没有加密密钥来读取或响应发送给它的PATH_CHALLENGE帧。

为了防止连接因这种错误的迁移而失败,当验证新的对端地址失败时,端点必须(MUST)恢复为使用最后一个验证通过的对端地址。

如果端点没有关于最后验证的对端地址的状态,它必须(MUST)通过放弃所有连接状态来静默地关闭连接。这会导致连接上的新数据包被一般性(generically)地处理。例如,端点可以(MAY)发送无状态重置(stateless reset)以响应任何进一步的传入包。

非路径(off-path)包转发

能够观察到数据包的非路径(off-path)攻击者可能会将真实数据包的副本转发到端点。如果复制的数据包在真正的数据包之前到达,这将显示为 NAT 重绑定。任何真实的数据包都将作为副本丢弃。如果攻击者能够继续转发数据包,则可能会导致通过攻击者迁移到某个路径。这将攻击者置于路径上,使其能够观察或丢弃所有后续数据包。

这种类型的攻击依赖于攻击者使用与端点之间的直接路径具有大致相同特征的路径。如果发送的数据包相对较少,或者数据包丢失与尝试的攻击一致,则更可能被攻击。

在原始路径上增加非探测包(non-probing)的最大接收包数将导致端点移回合法的路径。在此路径上Eliciting包会增加攻击失败的可能性。因此,减轻这种攻击依赖于触发包的交换。

为了响应明显(apparent)的迁移,端点必须(MUST)使用PATH_CHALLENGE帧验证之前活动的路径。这会导致在该路径上发送新的数据包。如果路径不再可行(viable),验证尝试将超时并失败;如果路径可行(viable),验证将成功,但只会导致在路径上发送探测包(probing packets)。

在活动路径上接收到PATH_CHALLENGE的端点应(SHOULD)发送非探测数据包(non-probing packet)作为响应。如果非探测数据包(non-probing packet)在攻击者生成任何副本之前到达,则会导致连接迁移回原始路径。任何后续迁移到其他路径都会重新启动整个过程。

这种防御是不完美的,但这不是一个严重的问题。如果通过攻击的路径确实比原始路径快,将无法区分攻击和路由改进。

端点还可以使用探索法(heuristics)来提高对这种类型攻击的检测。例如,如果最近在旧路径上接收到数据包,则不大可能是 NAT 重绑定,同样,在IPv6 路径上很少进行重绑定。端点也可以查找重复的数据包。相反,连接ID的更改更可能表示有意的(intentional)迁移,而不是攻击。

丢失检测和拥塞控制(Loss Detection and Congestion Control)

新路径上的可用容量可能与旧路径不同。在旧路径上发送的数据包不能(MUST NOT)用于新路径的拥塞控制(congestion control)或 RTT 估时(estimation)。

在确认对端对其新地址的所有权时,端点必须(MUST)立即将新路径的拥塞控制器(congestion controller)和 RTT 估计器(round-trip time estimator)重置为初始值,除非对端地址唯一更改是其端口号。由于仅端口更改通常是 NAT 重绑定或其他中间设备活动的结果,因此在这些情况下,端点可能(MAY)会保留其拥塞控制状态(congestion control state)和 RTT 估时(round-trip estimate),而不是恢复到初始值。如果旧路径保留的拥塞控制状态被用于新路径,发送方可能过于激进地发送,直到拥塞控制器(congestion controller)和 RTT 估计器(estimator)已经适应为止。通常,建议 QUIC 实现(implementations)在新路径上使用以前的值时要谨慎。

当一个端点在迁移期间从多个地址发送数据和探测时,接收方可能会出现明显的重新排序,因为两个结果路径的 RTT(round-trip times)可能不同。接收方仍将发送覆盖所有接收到的数据包的ACK帧。

虽然在连接迁移期间可能会使用多个路径,但是一个单一的拥塞控制上下文(congestion control context)和丢失恢复上下文(loss recovery context)就足够了。例如,端点可能会延迟切换到新的拥塞控制上下文,直到确认不再需要旧路径。

发送方可以对探测包(probe packets)进行异常处理,这样它们的丢失检测(loss detection)是独立的,并且不会过度地导致拥塞控制器(congestion controller)降低其发送速率。端点可以在发送PATH_CHALLENGE时设置一个单独的计时器,如果接收到对应的PATH_RESPONSE,则该计时器将被取消。如果计时器在收到PATH_RESPONSE之前触发,则端点可能会发送一个新的PATH_CHALLENGE,并在较长时间内重新启动计时器。

连接迁移的隐私影响(Privacy Implications of Connection Migration)

在多个网络路径上使用稳定的连接ID将允许被动观察者(passive observer)关联在这些路径之间的活动。网络中的端点可能不希望将其活动与除对端(peer)之外的任何实体(entity)关联,因此当从不同的本地地址发送时,将使用不同的连接ID。为了有效地实现这一点,端点需要确保它们提供的连接ID不能被任何其他实体(entity)链接。

在任何时候,端点都可以(MAY)将其传输的目标连接ID更改为未在其他路径上使用的值。

当从多个本地地址发送时,端点不能(MUST NOT)重用连接ID。

类似地,当发送到多个目标地址时,端点不能(MUST NOT)重用连接ID。由于网络变化超出其对端的控制范围,端点可能从具有相同目标连接ID的新源地址接收数据包,在这种情况下,它可以(MAY)继续使用当前连接ID和新的远程地址,同时仍然从同一本地地址发送数据包。

这些关于连接ID重用的要求只适用于包的发送,因为在路径无意(unintentional)更改情况下,不改变连接ID是可能的。例如,网络在一段时间不活动之后,当客户端恢复发送时,NAT 重绑定可能会导致数据包在新路径上发送。

在每个新的网络路径上,对双向(both directions)发送的数据包使用不同的连接ID,可以避免将来自同一连接的数据包跨不同的网络路径进行链接。报头保护确保数据包编号不能用于关联活动。这并不妨碍数据包的其他属性(如时间和大小)用于关联活动。

对于使用请求了零长度连接ID的对端,端点不应(SHOULD NOT)启动迁移,因为新路径上的流量可能可以链接旧路径上的流量。如果服务端能够将具有零长度连接ID的数据包与正确的连接相关联,则意味着服务端正在使用其他信息来分解(demultiplex)数据包。例如,服务端可以为每个客户端提供一个唯一的地址,例如使用 HTTP 替代服务[ALTSVC]。可能允许在多个网络路径上正确路由数据包的信息也将允许这些路径上的活动被非对端实体链接。

客户端可能希望在一段时间不活动后发送数据时使用新的连接ID和源 UDP 端口来降低可链接性。更改同时发送数据包的 UDP 端口可能会导致数据包显示为连接迁移。这确保对于不经历 NAT 重绑定或真正迁移的客户端也是同样的迁移机制。更改端口号可能会导致对端重置其拥塞状态,因此应(SHOULD)减少更改端口。

耗尽可用连接ID的端点不能探测新路径或启动迁移,也不能响应对端的探测或迁移尝试。为了确保迁移是可能的,并且在不同路径上发送的数据包不能相互关联,端点应该(SHOULD)在对端迁移之前提供新的连接ID。如果对端已用尽了可用的连接ID,则迁移端点可以在新网络路径上发送的所有数据包中包含一个NEW_CONNECTION_ID帧。

服务端的首选地址(Server's Preferred Address)

QUIC 允许服务端接受一个IP地址上的连接,并在握手后不久尝试将这些连接转移到更优先的地址(more preferred address)。当客户端最初连接到多个服务端共享的地址,但希望使用单播地址(unicast address)来确保连接稳定性时,这一点尤其有用。本节介绍将连接迁移到首选服务端地址(preferred server address)的协议。

通信首选地址(Communicating a Preferred Address)

服务端通过在 TLS 握手中包含preferred_address传输参数来传输首选地址(preferred address)。

服务端可以(MAY)通信每个地址族(address family,IPv4 和 IPv6)的首选地址(preferred address),以允许客户端选择最适合其网络的地址。

一旦握手被确认,客户端应该(SHOULD)从服务端提供的两个地址中选择一个并启动路径验证。客户端使用任何以前未使用的连接ID构造数据包,这些ID来自preferred_address传输参数或NEW_CONNECTION_ID帧。

一旦路径验证成功,客户端就应该(SHOULD)开始使用新的连接ID将所有后续的数据包发送到新的服务端地址,并停止使用旧的服务端地址。如果路径验证失败,客户端必须(MUST)继续将所有后续数据包发送到服务端的原始IP地址。

迁移到首选地址(Migration to a Preferred Address)

客户端必须(MUST)在迁移到首选地址(preferred address)之前验证所选地址是否有效。

服务端在接受连接后,可能会在任何时候接收到指向其首选IP地址(preferred IP address)的数据包。如果该数据包包含一个PATH_CHALLENGE帧,则服务端需要发送一个包含PATH_RESPONSE帧的数据包。服务端必须(MUST)从其原始地址发送非探测数据包(non-probing packets),直到它从客户端的首选地址(preferred address)接收到非探测数据包(non-probing packet),以及服务端验证了新路径。

服务端必须(MUST)从其首选地址(preferred address)探测指向客户端的路径。这有助于防止攻击者发起虚假迁移。

一旦服务端完成了路径验证,并且在其首选地址(preferred address)上收到了一个新的最大包号(largest packet number)的非探测包,服务端开始从其首选IP地址(preferred IP address)专门向客户端发送非探测包。它应该(SHOULD)丢弃该连接中旧IP地址上接收到的的数据包,但可以继续处理延迟的数据包。

服务端在preferred_address传输参数中提供的地址仅在当前连接有效。客户端不能将这些用于其他连接,包括从当前连接恢复的连接。

客户端迁移与首选地址交互(Interaction of Client Migration and Preferred Address)

客户端可能需要在迁移到服务端的首选地址(preferred address)之前执行连接迁移。在这种情况下,客户端应该(SHOULD)同时从客户端的新地址对原始服务端地址和首选服务端地址(preferred server address)执行路径验证。

如果服务端首选地址(preferred address)的路径验证成功,则客户端必须(MUST)放弃对原始地址的验证,并迁移到使用服务端的首选地址(preferred address)。如果服务端首选地址(preferred address)的路径验证失败,但服务端的原始地址验证成功,则客户端可以(MAY)迁移到其新地址并继续发送到服务端的原始地址。

如果在服务端的首选地址(preferred address)接收到的数据包的源地址与握手过程中从客户端观察到的源地址不同,则服务端必须(MUST)按照「对端(peer)地址欺骗」和「路径(on-path)地址欺骗」中的描述对潜在攻击进行防护。除了有意的同步迁移之外,这也可能是因为客户端的访问网络对服务端的首选地址(preferred address)使用了不同的 NAT 绑定。

服务端应该(SHOULD)在接收到来自不同地址的探测包时启动到客户端新地址的路径验证。在路径验证完成之前,服务端不能(MUST NOT)向新地址发送超过最小拥塞窗口值(minimum congestion window)的非探测数据包。

迁移到新地址的客户端应该(SHOULD)使用服务端同一地址族(address family)中的首选地址(preferred address)。

preferred_address传输参数中提供的连接ID并不特定于所提供的地址。提供此连接ID是为了确保客户端具有可用于迁移的连接ID,但客户端可以(MAY)在任何路径上使用此连接ID。

IPv6 流标签的使用和迁移(Use of IPv6 Flow-Label and Migration)

使用 IPv6 发送数据的端点应该(SHOULD)应用符合 [RFC6437] 的 IPv6 流标签(flow label),除非本地 API 不允许设置 IPv6 流标签(flow labels)。

IPv6 流标签应该(SHOULD)是源地址和目标地址、源和目标 UDP 端口以及目标连接ID字段的伪随机(pseudo-random)函数。流标签的生成必须(MUST)设计成最小化与之前使用的流标签的可链接性,这样可以避免在多个路径上关联活动。

一种可能的实现是将流标签计算为源和目标地址、源和目标UDP端口、目标连接ID字段和本地密钥(最小化)的加密哈希函数。

参考链接:

https://quicwg.org/base-drafts/draft-ietf-quic-transport.html#name-connection-migration

Connection Migration in QUIC


QUIC 的全称是 Quick UDP Internet Connections protocol,由 Google 设计提出,目前由 IETF 工作组推动进展,其设计的目标是替代 TCP 成为 HTTP/3 的数据传输层协议。熹乐科技在物联网(IoT)和边缘计算(Edge Computing)场景也一直在打造底层基于 QUIC 通讯协议的边缘计算微服务框架YoMo,长时间关注 QUIC 协议的发展,本系列文章总结了学习 QUIC 协议时的知识点。

在线社区:discord/quic

维护者:YoMo

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值