<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>QUIC协议分析 on Lutong's Homepage</title><link>https://www.elliot98.top/series/quic%E5%8D%8F%E8%AE%AE%E5%88%86%E6%9E%90/</link><description>Recent content in QUIC协议分析 on Lutong's Homepage</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 19 Nov 2019 00:00:00 +0000</lastBuildDate><atom:link href="https://www.elliot98.top/series/quic%E5%8D%8F%E8%AE%AE%E5%88%86%E6%9E%90/index.xml" rel="self" type="application/rss+xml"/><item><title>QUIC专题| Quic Protocal Part 1：基本结构</title><link>https://www.elliot98.top/post/lab/quic-1/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.elliot98.top/post/lab/quic-1/</guid><description>&lt;h1 id="quic-协议第一部分"&gt;Quic 协议——第一部分&lt;/h1&gt;
&lt;h2 id="一简介"&gt;一、简介&lt;/h2&gt;
&lt;p&gt;QUIC 协议最初是由 Google 开发并使用在 Chrome 中的新一代 web 协议。
之后被 IETF 的 QUICWG 工作组接管，目前发布的版本为 24th。&lt;/p&gt;
&lt;p&gt;QUIC 协议是一个包含传输层、安全垫片和应用层的复合协议族。QUIC 协议
基于 UDP 协议，在此之上实现了可控有序到达、拥塞控制、流量控制等传输层功能；
提供了对于包和连接的完整性和机密性功能；提供了 http3.0 等的应用层功能。&lt;/p&gt;
&lt;h2 id="二quic-协议基本结构"&gt;二、QUIC 协议基本结构&lt;/h2&gt;
&lt;p&gt;QUIC 协议是基于 UDP 的协议，其最基本包的格式为 UDP 报文（package），由 package number 来提供有序到达的功能。
在一个 QUIC 报文之中，有多个独立功能的 QUIC 帧（frame），每一个帧都
用于实现不同的功能，比如传输帧，错误帧，校验帧等。&lt;/p&gt;
&lt;p&gt;在报文和帧的基础之上，QUIC 协议构成了一个双方共享连接状态的有状态协议，
因此有连接 （connection） 的概念。通过 connection id来区别不同的 QUIC 连接。
QUIC 连接具有完整的生命周期（建立、撤销、关闭等）&lt;/p&gt;
&lt;p&gt;在连接之上，QUIC协议使用了连接复用的概率，在连接之上建立了多个有状态的流（steam），
每一个流也是具有独立状态的。每一个流对应了上层的不同应用，比如 id 为 1 的流用于负责
握手协议和密码学参数的协商。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;+---------+---------+---------+
| stream1 | stream2 | stream3 |
+---------+---------+---------+
| connection |
+-----------------------------+
| packages (frame1 || frame2 )|
+-----------------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="三-quic-协议版本协商"&gt;三、 QUIC 协议版本协商&lt;/h2&gt;
&lt;p&gt;QUIC 报文头部的内容主要有协议的版本 （version） 和connection id 等。
其中 version 协商是建立 QUIC 协议首先需要做的工作。&lt;/p&gt;</description></item><item><title>QUIC专题| Quic Protocal Part 2：连接和流</title><link>https://www.elliot98.top/post/lab/quic-2/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.elliot98.top/post/lab/quic-2/</guid><description>&lt;h1 id="quic-protocal--part-2"&gt;QUIC Protocal —— Part 2&lt;/h1&gt;
&lt;p&gt;QUIC 流和连接是有状态的，因此发送方和接收方需要建立对应的状态机，也需要完成一定的握手和关闭动作。&lt;/p&gt;
&lt;h2 id="一quic-stream"&gt;一、QUIC Stream&lt;/h2&gt;
&lt;h3 id="11-流的基本结构"&gt;1.1 流的基本结构&lt;/h3&gt;
&lt;p&gt;QUIC 流是有状态的。每一个 QUIC 连接中可以复用多个流，每个流有一个独立的 stream id 来标记不同的流。其中 stream id 的最低有效位决定流是客户端建立的还是服务器建立的；次低有效位决定了流是单向的还是双向的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;同一个连接中，stream id 不允许复用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;QUIC 的流就像 TCP 协议一样，上层应用对于流的感知是连续的消息流，没有明显的边界（也就是说上层应用对于报文要有自然分割，否则可能发生粘包）。&lt;/p&gt;
&lt;h3 id="12-流的帧表示"&gt;1.2 流的帧表示&lt;/h3&gt;
&lt;p&gt;一个 stream 可能使用如下一些 QUIC 帧（frame）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STREAM 帧： 发送数据&lt;/li&gt;
&lt;li&gt;RST_STREAM: 接收流，收到对应 ACK 后关闭对应流。&lt;/li&gt;
&lt;li&gt;STREAM_DATA_BLOCK: 阻塞&lt;/li&gt;
&lt;li&gt;FIN: 发送结束&lt;/li&gt;
&lt;li&gt;MAX_STREAM_DATA: 提示数据大小&lt;/li&gt;
&lt;li&gt;STOP_SENDING: 接收方提示不再接收数据，后续可能被忽略&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="二流量控制"&gt;二、流量控制&lt;/h2&gt;
&lt;p&gt;QUIC 协议使用了基于 stream 和基于 connection 的两层流量控制。&lt;/p&gt;
&lt;h2 id="21-基于字节的流量控制"&gt;2.1 基于字节的流量控制&lt;/h2&gt;
&lt;p&gt;接收方可以发送 MAX_STREAM_DATA 或者 MAX_DATA 来提示流和连接的字节最大偏移量。当达到发送最大字节的时候，发送方发送 STREAM_DATA_BLOCK 或 DATA_BLOCK 来提示阻塞。&lt;/p&gt;
&lt;h2 id="22-基于stream-数量的流量控制"&gt;2.2 基于stream 数量的流量控制&lt;/h2&gt;
&lt;p&gt;通信双方可以通过 MAX_STREAMS 帧来告知对端最大可以建立的 stream 的个数，以此来进行流量控制。&lt;/p&gt;</description></item><item><title>QUIC专题| Quic Protocal Part 3：包和帧</title><link>https://www.elliot98.top/post/lab/quic-3/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.elliot98.top/post/lab/quic-3/</guid><description>&lt;h1 id="quic-协议第三部分"&gt;Quic 协议——第三部分&lt;/h1&gt;
&lt;p&gt;QUIC 的通信采用了包（Package）和帧（frame）的双重结构。&lt;/p&gt;
&lt;p&gt;一个 UDP 包中可能包含有多个 QUIC 包，其中每一个 QUIC 包中可以包含多个帧（frame）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一个 UDP 报文包的 QUIC 包必须是同一个连接中的多个 QUIC 数据包。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;帧是完整某项功能的基本单位，比如之前所述的 STREAM 帧用于发送流数据、CONNECTION_CLOSE 帧用于关闭连接等。&lt;/p&gt;
&lt;h2 id="一-quic-package"&gt;一、 QUIC Package&lt;/h2&gt;
&lt;p&gt;如前所述，QUIC 协议有长报文头和短报文头两种，在建立连接过程中使用的长报文头。这包括如下一些报文：初始数据包、0RTT数据包、握手数据包、重试数据包等。&lt;/p&gt;
&lt;p&gt;除了版本协商数据包和重试数据包之外，其他数据包均使用 AEAD 算法提供机密性、完整性和身份认证保护。&lt;/p&gt;
&lt;p&gt;包的 Package Number 是 0-2^62-1 的序列号，在实际报文中，可能被重新映射到 1-4字节。&lt;/p&gt;
&lt;p&gt;Package Number 被分配为：初始空间、握手空间和应用空间三个部分。每次都从对应空间的 0 号开始，而后以此递增。&lt;/p&gt;
&lt;p&gt;当 2^62 -1 时，必须关闭连接。&lt;/p&gt;
&lt;h3 id="11-长包头数据包"&gt;1.1 长包头数据包&lt;/h3&gt;
&lt;p&gt;长包头中包括了版本号，Package Number，源和目的 Connection ID 以及子类型，有如下几种类型：&lt;/p&gt;
&lt;h4 id="111-版本协商包-version-negotation-package"&gt;1.1.1 版本协商包 Version Negotation Package&lt;/h4&gt;
&lt;p&gt;当客户端版本不被接收的时候，由服务器端发送。&lt;/p&gt;
&lt;h4 id="112-初始数据包-initial-package"&gt;1.1.2 初始数据包 Initial Package&lt;/h4&gt;
&lt;p&gt;它携带客户端和服务器发送的第一个CRYPTO帧来执行密钥交换，并携带两个方向的ACK。&lt;/p&gt;
&lt;h4 id="113-0rtt-数据包"&gt;1.1.3 0RTT 数据包&lt;/h4&gt;
&lt;p&gt;0-RTT数据包使用类型值为0x1的长报头，后跟长度和数据包号字段。第一个字节包含保留和数据 包号长度位。它用于在握手完成之前，将“早期”数据从客户端传送到服务器，作为第一次传输的 一部分。作为TLS握手的一部分，服务器可以接受或拒绝此早期数据。&lt;/p&gt;</description></item><item><title>QUIC专题| Quic Protocal Part 4：出错校验、拥塞控制</title><link>https://www.elliot98.top/post/lab/quic-4/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.elliot98.top/post/lab/quic-4/</guid><description>&lt;h1 id="quic-协议第四部分"&gt;Quic 协议——第四部分&lt;/h1&gt;
&lt;h2 id="quic-协议的出错校验"&gt;QUIC 协议的出错校验&lt;/h2&gt;
&lt;p&gt;由于 QUIC 协议基于不可靠的 UDP 协议，因此需要实现校验、纠错和拥塞控制机制。(流量控制机制已经大致在前面说过了)。&lt;/p&gt;
&lt;p&gt;如前所述，其 Package Number 被划分成了三个子空间，每个空间指示了报文的安全级别。&lt;/p&gt;
&lt;h2 id="一ack-特性"&gt;一、ACK 特性&lt;/h2&gt;
&lt;p&gt;QUIC 报文可以延迟 ACK 但必须在最大确认延时（max_ack_delay, mostly 25ms) 给出ACK 确认。&lt;/p&gt;
&lt;p&gt;无序分组、有拥塞控制分组以及密码报文应当尽快确认。RTT 估值可参加 RFC6298。&lt;/p&gt;
&lt;h2 id="二丢失检验"&gt;二、丢失检验&lt;/h2&gt;
&lt;h3 id="21-基于ack的丢失检验"&gt;2.1 基于ACK的丢失检验&lt;/h3&gt;
&lt;p&gt;使用了类似TCP Early Retransit，Quick Retransit，SACK，FACK，RACK 等机制。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当收到后续包ACK但没有收到当前包ACK时重传。&lt;/li&gt;
&lt;li&gt;达到数据包阈值（Packet Threshold）或者时间阈值（Time Threshold）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="22-加密超时重传"&gt;2.2 加密超时重传&lt;/h3&gt;
&lt;p&gt;对于加密数据需要使用更灵活的机制来进行丢失检验&lt;/p&gt;
&lt;h3 id="23-探测超时probe-timeout"&gt;2.3 探测超时（Probe Timeout)&lt;/h3&gt;
&lt;p&gt;探测超时（PTO）在ack引出数据处于传输状态但在预期的时间段内未收到确认时触发探测数据包。&lt;/p&gt;
&lt;p&gt;当发送数据包超过 PTO 时间后，发送探测数据包。&lt;/p&gt;
&lt;p&gt;当PTO计时器到期时，新的或先前发送的数据 可能无法发送，并且数据包可能仍在发送中。 如果数据包在发送中，可以阻止发送方未来发 送新数据。在这些条件下，发件方应该 将仍在发送中的任何数据包标记为丢失。 如果发送方希望保证仍在运行中的数据包送达， 它可以发送一个ack-eliciting数据包并 重新设置PTO定时器。&lt;/p&gt;
&lt;p&gt;当接收到新确认一个或多个分组的ACK帧时， 就可以确认传输中的分组的已经送达或丢失。&lt;/p&gt;
&lt;h2 id="三拥塞控制"&gt;三、拥塞控制&lt;/h2&gt;
&lt;p&gt;QUIC的拥塞控制基于TCP NewReno（RFC6582）。 NewReno是基于拥塞窗口的拥塞控制。 NewReno中的 拥塞避免使用加法增加乘法减少（AIMD） 的方法将每个确认的拥塞窗口增加一个 最大数据包大小.当检测到丢失时， NewReno减半拥塞窗口并将慢启动阈值 设置为新的拥堵窗口。&lt;/p&gt;
&lt;p&gt;此外 QUIC 支持显示拥塞控制 ECN (参加 transport 草案中的 ACK 帧)。&lt;/p&gt;</description></item><item><title>QUIC专题| Quic Protocal Part 5：TLS 1.3 in QUIC</title><link>https://www.elliot98.top/post/lab/quic-5/</link><pubDate>Tue, 19 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.elliot98.top/post/lab/quic-5/</guid><description>&lt;h1 id="quic-协议第五部分"&gt;Quic 协议——第五部分&lt;/h1&gt;
&lt;p&gt;谷歌的 QUIC 协议中使用了自己的安全握手协议。而后 IETF 将
TLS 1.3 引入 QUIC 协议，并作为安全握手协议使用。&lt;/p&gt;
&lt;h2 id="一tls-13-协议简介"&gt;一、TLS 1.3 协议简介&lt;/h2&gt;
&lt;p&gt;TLS 是一个分层协议，包括下层的记录协议和上层的握手协议、告警协议和应用数据。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;!! QUIC 不支持 TLS 的密码变更协议&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TLS 1.3 提供了支持 1-RTT 的完整验证流程和 0-RTT 的快速回复机制。
TLS 报文有 0RTT 和 1RTT 两种安全级别。前者使用上次连接过程中建立的 psk。
后者使用 DH 秘钥交换等派生出 master key 后派生加密。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; 客户端 服务端

 客户端请求
 (0-RTT 应用数据) --------&amp;gt;
 服务端请求
 {加密扩展}
 {完结的}
 &amp;lt;-------- [应用程序数据]
 {完结的} --------&amp;gt;

 [应用程序数据] &amp;lt;-------&amp;gt; [应用程序数据]

 () 受早期数据(0-RTT)键保护的指示消息
 {} 使用握手密钥保护的指示消息
 [] 使用应用程序数据保护的指示消息(1-RTT)键
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="二-quic-协议中-tls-概述"&gt;二、 QUIC 协议中 TLS 概述&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;QUIC 协议中不再使用 TLS 协议的记录协议，而是直接由 QUIC 协议提供消息传递。&lt;/li&gt;
&lt;li&gt;TLS 协议中的告警协议和握手协议直接作为 QUIC 的一个 STREAM 来完成。&lt;/li&gt;
&lt;li&gt;QUIC 协议不兼容 TLS 协议的密码变更协议&lt;/li&gt;
&lt;li&gt;QUIC 协议直接使用 TLS 协议所派生的秘钥对整个连接进行保护，而不再使用 TLS 的应用数据协议&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;+--------------+--------------+ +-------------+
| TLS | TLS | | QUIC |
| handshake | alert | | application |
+--------------+--------------+-+-------------+
| QUIC Transport |
+---------------------------------------------+
| QUIC Data Package Protect |
+---------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="三tls-交互流程个人理解"&gt;三、TLS 交互流程（个人理解）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;QUIC 使用 CRYPTO 帧将 TLS 握手协议打包并发送，在传输过程中保证可靠达到。&lt;/li&gt;
&lt;li&gt;QUIC 将 TLS 告警协议中的错误值取出后封装在 CONNECTION_CLOSE 帧中。&lt;/li&gt;
&lt;li&gt;QUIC 将 HelloRetryRequest 用于纠错时，取出并改为发送 Retry_Package。&lt;/li&gt;
&lt;li&gt;QUIC 使用短头部中的 KEY_PHASE 来代替TLS中的KeyUpdate 消息来进行秘钥变更。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;握手协议流程（作者理解）：&lt;/p&gt;</description></item></channel></rss>