QUIC 包格式
传输的基本单元将是一个标准的 UDP 包(又名,包)。注意确保所有的数据传输将会被分解成刚好放入一个包的块。
包括用来协商一个连接的第一包在内的所有包,将利用 AEAD 加密。第一包将利用一个默认的空加密密钥,并且 AEAD 将只是用来排除意外干预(作为一个高质量的校验和)。加密协商将发生在流 1,由客户端产生。
header | payload |
QUIC 包
QUIC 包由头(header) 和有效载荷(payload) 组成。其中,payload 是 AEAD 算法认证的密文。
每个包的头包括:
- 1 字节的公共标识,详述头的剩下部分的设计
- 全局唯一标识符
- QUIC 版本
- 包序列号
公共标识 | 全局唯一标识符 | QUIC 版本 | 包序列号 |
QUIC 包的头部
数据包有效载荷由一系列帧组成:
头 | 一系列帧 |
FEC 包有效载荷由冗余数据组成:
头 | 冗余数据 |
在解密之后,我们将有一个明文有效载荷块,它包括:
- 1 字节的私有标识
- FEC 组号
- 一系列自我标识帧
私有标识 | FEC 组号 |
一系列自我标识帧 |
解密之后的 QUIC 包的有效载荷
QUIC 包详解
头:公共标识
在一个给定连接和给定包中,公共标识提供给每个包的其他区域的大小的说明。
头:全局唯一标识符
全局唯一标识符的长度被指定为 64 比特,所以,客户端可以随机地选择一个全局唯一标识符,在一个固定的端口联系一个服务器,有很小的可能性会与其他连接碰撞。
然而,全局唯一标识符对于一个已经创建了一个专用的短暂的联系服务器的端口的客户端来说完全是冗余的。客户端将在那个端口收到的包将会是单一的 QUIC 出口连接的一部分。结果,客户端可能请求,一个服务器不必费心的包括每个包的全局唯一标识符。一旦一个服务器收到一个请求(例如在连接协商期间),服务器可以使用公共标识表明,全局唯一标识符被省略(在头中的长度为 0)。
对一些服务器和服务来说,并行连接关系的编号是非常有限的。例如,一个服务器可能和一个客户端协商在一个特别的可选的 IP 和端口上继续那个连接。在那种情况下,服务器也可能对客户端表明,一个更小的全局唯一标识符或许是可接受的。
头:QUIC 版本
我们知道,协议发展的很快,并且需要发展。这个区域出现在第一包中,用来确保服务器可以理解客户端将提供的相同的版本。一旦连接建立,这个是冗余的,并且公共标识将会表明这个区域被省略了(长度为 0)。如果一个服务器需要区别版本,它将记住,被全局唯一标识符定义的连接有一个与众不同的版本。
头:包序列号
除了给包定序、留意副本、交流什么包丢失了,这个编号是加密的一个关键组成部分。这个编号组成了用来解密每个包的初始化向量的基础。结果,从概念上讲,它必须是大的,因为在连接期间,它必须绝不重复。那个需求强迫这个序列号概念上是大的,大约 2^64(比连接还要多的包等着发送),但是我们通常不需要提供每个包的 8 个字节!
在任何给定的时间,仅有一些有限的包序列号没有被确认。这个限制是由这个事实的自然结果,发送者必须缓存那些未决定的包中的内部数据,并且发送者的内存是有限的。另外,我们选择不去重传被声明为丢失的包,而是把他们的内容放入后来的数据包中。结果,接收者常常通知,它没有收到一个包,并且发送者将通知接收者 停止等待 那个包,因此没有被确认的包的窗口将总是恰好有界的,并且不确定性(讨论的可能的最大和最小值) 范围可能被发送者知道。给予那个限制,发送者可能大大地减少需要表示包序列号(使用公共标识) 的字节数。
例如,假设正在用一个像拥塞控制的 TCP 传输,并且目前的拥塞窗口是 20 个包。即使包丢失,在 1 个 RTT 或大约 20 个额外包内,接收者将知道一个丢失的包不再是未判定的。结果,发送者可以侥幸逃脱在线路上仅发送 64 比特包序列号的低序号字节。接收者给予那些比特可以轻易地决定较高的 56 比特必须是什么,可以使用那个去解密包。注意,如果一个非常老的包到达接收方,并且老的包序列号是被曲解的,那么 AEAD 认证会失败,并且老的(并且适合丢弃的) 包甚至会被忽略。
有效载荷:私有标识
目前 1 字节大小的私有标识表示 私有 ,因为他们被加密覆盖,并且对窃听者是不可见的。与公共标识一样,在标识中编码的一个值是 FEC 组号的大小,和有效载荷到帧的开始的隐式偏移。
私有标识还有另外 2 个独特的比特。第一个比特是一个随机加密比特,第二个比特用来鉴定 FEC 组中的最后一个包。FEC 组中的最后一个包是冗余 FEC 包(包含组中的明文有效载荷的异或)。
私有标识:加密比特
加密比特由发送者随机选择,并且放入每一个包中。这个信息用来对抗任何潜在的乐观确认攻击。当一个接收器发送一系列包的确认时,它需要证明它收到了那个集合,通过提供它宣称已经看见的加密比特哈希表宣称的那个集合。
加密比特的一个问题是,当一个包丢失时,它的加密比特是不可见的。为了解决这个问题,并且不需要接收器创建无止尽的丢失包列表(来自哈希表的异常),发送者常常提供一个更新,表明哈希表相对于一个特定的数据包来说应该是什么。
例如,假设包 1,2,3,4 被发送了。假设包 3 丢失了。接收器将表明(在一个确认帧里),它收到了从 1 到 4 的所有包,除了包 3。确认帧也会提供一个打包 1,2,3,4 包的加密比特的哈希表。发送器可以确认哈希表是正确的,并且声明包 3 丢失了。然后,发送器可以传输(包括一个确认帧) 它不再关注包 4 或者更老的包,并且它可以提供到包 4 为止的所有加密比特哈希表。结果,接收器终于知道到包 4 为止的包的哈希表,并且当它收到下一步的数据包时可以提供额外的增值哈希表结果。
私有标识:FEC 最后的比特
这个比特用来标记最后一个包是一个 FEC 组。我们现在的 FEC 方法在一系列受 FEC 保护的包的末尾恰好有一个 FEC 包。这个比特表明,整个有效载荷应该单独处理,并且被视作在这个组中的其他有效载荷的异或和。
注意,当这个比特被设置时,包必须是一些 FEC 组的一部分,因此 FEC 组号也必须总是存在的。
有效载荷:FEC 组号
假定,我们大约看见在互联网上 1%以上的包丢失,100 以上且不是 200 个包都无损失的被接收是完全不可能的。因为这个原因,我们决定限制 FEC 组不大于 255 个包。我们的实验暗示,当 FEC 丢失时,一个 10 到 20 的受一个冗余 FEC 包保护的包数据序列或许是最有益的。每 20 个包,有大约 5%的带宽消耗,并且有一个完全可见的延迟权衡。我们还注意到,对 TCP 来说,看见拥塞窗口正好低于 50 个包是最常见的。因此,和重传相比,对于更大的组使用一个 FEC 无益于减少延迟。
因为以上分析,我们目前支持一系列连续的包的简单异或 FEC,并且一字节足以鉴定一组受保护的包。如果发送器决定保护一系列包,它使用私有标识去表明,确实有一个嵌入式的 FEC 组号字节。每个 FEC 组的参与者有一个偏移 FEC 组号,它可以鉴定组中的第一个包(即,它是减去目前包序列号的一个总数)。这种方法考虑到就什么时候结束那个 FEC 组的一个懒惰的决定(即,包的准确编号不需要知道,最后的 FEC 包可以在任何时间被加入,例如当没有数据发送时)。
有效载荷:自我标识帧
每个 QUIC 包的块有望成为一个称为帧的数据的串行列表。每个帧都有标识帧的主要字节,和关于帧格式与内容的信息。例如,有些携带确认信息的帧,也有携带纯粹流数据的帧。还有一些其他的帧。
包通常被包装成充满一个或者更多帧的数据的包然后发送出去。帧在某种意义上来说是协议的载体.
所有的帧都以一个帧类型字节开始,但是我们希望在那个字节中包装一些额外的关于具体的每种类型的标识。结果,它实际上是用于鉴定帧类型的一个帧类型字节的开始几个比特,其他几个比特用来作为编码帧格式的标识。QUIC 的初始实现版本可能使用非常固定的大小区域表示一些帧类型,但是它应该随着我们优化和压缩那个编码而改变。
帧分为:流帧,确认帧,拥塞控制帧,重置流帧,连接关闭帧,离开流帧,
流帧
每个 QUIC 连接可以多路复用一些流,每个流帧承载一个流的应用数据。帧的头在概念上讲必须体现流编号,流编号由帧和独立数据(就像 TCP 为段提供字节偏移一样) 的流内开始偏移组成。一个流帧还用来隐式地打开或创建一个流,帧目前包含一个表明它是上述流的最后一部分的标志比特。
当一个大文件传输在一个流上时效率可能是至关重要的,为了提高效率,我们希望在这个帧的头部利用不同长度的区域。例如,即使我们希望支持非常大的文件传输,但是一个流使用许多对现在来说是最大偏移的 64 比特来传输数据这种情况还是很少发生的。同样的,当大的流被传输时,用一个有效载荷填充所有剩下的空间对一个数据流来说是很常见的,因此,它的大小(在有效载荷之内) 可以是隐式的而不是显式地。
正如 SPDY,我们希望压缩 HTTP 请求流的头部。这应该在连接建立和加密握手期间协商。这个方法的一个代价就是流头部必须按序编码,因此,一个新的流必须在前面的流的头部被编码后才能处理。我们期望,在许多情况下,HTTP 头的压缩效果是非常显著的,以至于大量的 HTTP 请求被很好地填充进一个 QUIC 包,并且这个头阻塞将是无关紧要的。我们同样期望,HTTP/2.0 将解决一个有更大提高的有更好的序列化编码控制的压缩算法,并且能够在 QUIC 中被使用。
确认帧
确认帧用来调整包丢失恢复和其他一些类似作用,但是和 TCP 中的一个确认包不是完全相同的。QUIC 中的确认总是累积的,新的确认包含的信息表明任何先前的确认都应该被丢弃。结果,如果包含一个确认帧的一个包丢失了,不需要重传带有确认的帧。
第一个且最清晰的概念性内容,一个帧包含的确认是一个接收器已经决定为遗失的包的否定确认列表。结果,一个确认帧有一个丢失包数量的计数和包列表。就像在 QUIC 头中呈现的包序列号,丢失的包可以很简洁的表示。即使有一个简洁的表示,有一个关于多少(数百) 否定确认可以在一个包内被枚举的限制。结果,在非常不可能的情况下,有太多否定确认以至于不能填充进一个包,仅仅最早的(数字上最低的) 一些丢失包被枚举了。由 1%的包丢失造成的这种不太可能的情况,可能限制有效的流动窗口大约为 1000 个包(不是一个很大的限制,但是任何情况下都应该能工作)。我们把这种情况视为一个 缩短了的确认帧 。
第二个呈现在确认帧中概念性元素通常是已经接收了的最大包序列号,并且我们把它视为 最大的观测的 包。那个结构使一个确认帧类似于一个 TCP 选择性的确认,后者列出了最大的接收到的偏移量和(如果有的话) 一个小的否定确认编位号列表(多大一对)。
QUIC 的一个并发症是,一个确认帧可以如上述的缩短。在那种确认帧被缩短的情况下,接收器丢失在这个压缩边界的几个包是有可能的。为了恰当的处理那种独特的情况,呈现在确认包中的 最大的观察的 包可能在否定确认包列表中!
为了使上述的问题更加清晰,考虑一个被发送从 1 到 1000 的数据包的接收器,但是仅仅收到包 1 和包 1000(即,它丢失了从 2 到 999 的所有包)。在那个例子中,我们假设,在一个确认帧中只有 200 个否定确认的空间。结果,一个确认帧列出了(显式地) 从包 2 到包 201 的 200 个否定确认。奇怪的是, 最大的接收到的 包是包 1000,但是这不可能在确认帧中陈述,因为它将看起来好像包 202 到 999 都被收到!在这个缩短的确认帧情况下, 最大的观察到的 包会被列为包 201。当发送器用一个不考虑否定确认包 201 或更早包的请求响应这个否定确认列表时,上述情况会自行快速解决。按钮行:即使在这种情况下,也会向前进步。
确认帧的第二个成分承载与普通情况相反的信息,因为它携带从发送器到接收器的确认信息。QUIC 不重传包,但是在他们仍然有用时把他们的内容装入一个后来的包中(即,它将倾向于重传丢失包的流帧,但是不重传丢失包的确认帧)。结果,当发送器通过一个丢失包的否定确定学习时,它需要通知接收器 停止否定确认 那个包。为了支持这个,一个确认帧也有一个鉴定一个 最小的未确认的 包的区域。这个包序列号鉴定一个点,发送器不想要任何更早的否定确认。
在确认帧中提供的最后的两个元素与用来排除一个积极确认攻击的加密哈希表有关。就像更早提到过的,在有效私有标识中每个包中提供一个加密比特。当接收器发送一个确认帧,潜在地指定知道的包和丢失的包,也会为每一个知道的包发送一个已接收加密哈希表。同样地,当发送器更新最小的否定确认的包编号时,它也提供哈希表,当累积加密到达那个最小的否定确认点时接收器应该用这个哈希表。
通常,只包含一个确认帧的一个包是未确认的(这反过来会导致一个连续的确认!)。跟着一个只包含一个确认帧的包的一个丢失包一定是确认过的,因为接收器不知道丢失包包含什么。
当发送器收到一个包含否定确认(特别是以前没有听说过的新否定确认) 的确认帧时,它可能提供一个应答的确认帧,要求接收器 停止否定确认 上述的包。
正如 TCP,当一个有效的时间长度(和 RTT 相关) 过去了,没有收到一个确认,发送器可能重传一个包的内容(即,即使提供了一个明确的否定确认)。这样的重传将继续使用一个指数的备值,但是就像 TCP 一样,假设当一个包正在重传时,他们没有被拥塞窗口限制(即,推测的损失允许有重传)。
拥塞控制帧
拥塞控制帧用来传递关于一个特定的拥塞控制算法的信息。在连接的开始,加密认证协商也包括适合的拥塞控制算法的协商。作为一个基线,所有的实现将支持一个类 TCP 算法,但是由于相应的不同数据的需求,我们期望使用其他的算法。
例如,在一个类 TCP 算法中,一个拥塞控制帧可能包含关于一个包什么时候收到的信息,或者同样地,在收到后多久确认被发送出去。这种反馈统计可能在计算 RTT 时有所帮助,就像 TCP 使用一个 TCP 确认的到达来估计一个 RTT(当假定在一个包的收到和一个相应的确认之间有微不足道的延迟时)。目前一个拥塞反馈帧的类 TCP 实现包括累积的包丢失数。
就一个注重测量逗留延迟的算法来说,一个拥塞反馈帧可能提供包之间的相对到达时间(允许发送器推断包传播),或者关于接收时间的统计。例如,它可能包括周期性的更新,最短的可观察到的包的往返时间是什么。也可能包括周期性的声明,对于一个特定的最近的包,用接收器时钟测量的到达时间是什么。在那种情况下,接收器时钟和发送器时钟是不同步的,但是发送器可以探测一个变化,它象征着一个增加或减少的中间包队列。这样的一个统计可能是一个更加精确的单程传输时间的估计(虽然它的精确性受到端点时钟差距影响)。
呈现在拥塞控制帧中的精确范围明显基于所使用的算法而变化。
重置流帧
重置流帧用来反常地终止一个流。例如,当接收器希望比预期早的阻止发送器发送额外的数据时或当数据源不再供应数据时可以使用它。为了帮助排出故障,一个动机短语和一个错误代码被包括在这些帧中。
连接关闭帧
连接关闭帧用来攻击性的和快速的终止一个连接,隐式地关闭所有流。为了试图支持这种比普通在 TCP 中还快的快速拆卸,这个帧后面跟着一个确认帧,为了更好地交流拆卸时的状态(即,在拆卸之前收到的最后一个包序列号是什么)。
离开流帧
离开流帧请求一个连接的完美终止,没有新的流产生,只有已存在的流存留(有希望立刻结束)。这个帧也包括一个动机短语和一个错误代码。
连接重置可选项
一个 QUIC 连接可以被连接的任意一端重置。连接重置意味着,连接永久地被丢弃或者拆除。没有使用与连接的当前全局唯一标识符相关的包进行的额外通信。一个 QUIC 连接不能通过注入一个通用包而被拆除。当足够多的流量丢失并且没有收到确认时,一个连接将(最终?) 被丢弃并且有效地重置。
有两种方式交流一个 QUIC 连接重置。两种方法都是经过认证的(排除第三方出入)。第一种方法是经由一个连接中所有其他已认证的同一认证的标准包,通过包括一个消失的帧或一个连接重置帧(以上所有描述的)。第二种重置的方式使用一个单向的预计划的重置,这是一个共享密钥。
如果收到一个带有不再与一个活跃 QUIC 连接相关的全局唯一标识符的包(不是一个启动包),这时需要一个迅速的重置。这个未被承认的全局唯一标识符(和相关的包) 可能选择性地被忽略(丢弃),但是那只会导致一个缓慢的由发送者引起的相关连接的丢弃。
现时标志通常可能被构造为一个全局唯一标识符的 MAC。
恶意的返回地址重写
一个恶意的中间盒对手可能重写源 IP 或端口,造成接收器迷惑于发送响应流到哪里。
避免这样一个靠不住的重置的一个方法就是继续指挥包流到先前的源 IP,直到一个 充分 多的来自新源 IP 的包被响应。
另外一个客户端(或中间盒) 可能制造的攻击是故意篡改源 IP 地址,产生一个流放大攻击。阻止这样一个攻击的比较自然的一个方式是避免广泛使用一个替换源 IP,直到一个包进行了至少一个往返。
中间盒可能有恶意的这个事实暗示,可能在这个协议能够多好/多块适应源地址的非固定改变上会受到限制。如果源了解到它的地址正在改变,在没能够认证细节时,发送一个已经过认证的改变正在临近的暗示是有可能的,这样一个暗示是非常有帮助的,例如,当一个移动设备切换到从 WiFi,因此可以向服务器发送保证,传输正在发生。
加密启动概览
有一个单独的 QUIC 加密文档提供细节和精确加密问候协议的理由,密钥交换,等等。这节仅意味着概念性的概述涉及连接建立的事件的序列。QUIC 加密文档是权威的。
一个典型的零 RTT 刷新连接建立将被客户端围绕推测建立,服务器仍然使用一个先前已知的公钥。基于那个推测,客户端可能传输一个被提议的会话密钥,等,用预测的公钥加密它。客户端可以立即跟踪具有加密数据且被初始会话密钥加密的那个连接建立传输。这个提供基础的高概率的 0-RTT 启动。
为了减少一个意外连接损失的可能性,连接的每一方都应该表明,一旦连接变成闲置,它期望维持会话状态多久。
1 个 RTT 回退
如果在一个连接建立中的最初的推测性的公钥对服务器来说是不可接受的,或者服务器想要额外验证请求客户端的地址,服务器或许会拒绝连接请求并在开始前进行一个往返验证。期望往返元素包括等值于一个现时标志的价值(与 TCP 同步 cookie 同类),等值于一个完整的如 TLS 演示的问候交流。在客户端响应服务器问候之后,在完整的协商会话密钥保护下,客户端可能重传任何数据请求(可能被一个服务器斜面丢弃)。在这个例子中,服务器可能选择性地丢弃所有先前的数据包,可能在推测性的公钥保护下发送的那些数据包。
2 个 RTT 的最糟糕的回退情况
服务器需要响应一个广泛的证书链这个事件中,服务器或许会拒绝发送一个多包有效负载给一个客户端,直到客户端可以证明它拥有了一个特定的源地址。在那种情况下,问候交流或许会花费多达 2 个 RTT。
在这个最糟糕的情况下,第一个客户端问候会被拒绝,但是服务器会提供一个令牌来证明客户端地址的所有权和服务器证书,不包括证书链(如果它太大以至于不能填充进单个包)。
客户端将会在第二个问候请求中使用源地址令牌,但是可能直到它收到完整的证书链时它才会愿意相信那个证书。在那个例子中,服务器将会拒绝第二个问候(因为对一个共享密钥来说缺乏任何实际的提议),但是将至少回复一个完全充实的证书链,需要发送几个包。
最后,拥有一个值得信任的服务器证书和一个可信任的源地址令牌在手,客户端可能就像在那个 0-RTT 例子中建议的一样提供一个客户端问候,连接将开始。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论