RFC 9000
QUIC: A UDP-Based Multiplexed and Secure Transport —— 在 UDP 上做多路流、连接迁移和包保护。TLS 怎么嵌是 RFC 9001。
跑在 UDP 上的多路安全传输
QUIC is a secure general-purpose transport protocol. This document defines version 1 of QUIC, which conforms to the version-independent properties of QUIC defined in [QUIC-INVARIANTS]. QUIC is a connection-oriented protocol that creates a stateful interaction between a client and server. The QUIC handshake combines negotiation of cryptographic and transport parameters. QUIC integrates the TLS handshake [TLS13], although using a customized framing for protecting packets. The integration of TLS and QUIC is described in more detail in [QUIC-TLS]. The handshake is structured to permit the exchange of application data as soon as possible. This includes an option for clients to send data immediately (0-RTT), which requires some form of prior communication or configuration to enable.
[……下接分组、流、迁移]
Endpoints communicate in QUIC by exchanging QUIC packets. Most packets contain frames, which carry control information and application data between endpoints. QUIC authenticates the entirety of each packet and encrypts as much of each packet as is practical. QUIC packets are carried in UDP datagrams [UDP] to better facilitate deployment in existing systems and networks. Application protocols exchange information over a QUIC connection via streams, which are ordered sequences of bytes. Two types of streams can be created: bidirectional streams, which allow both endpoints to send data; and unidirectional streams, which allow a single endpoint to send data. A credit-based scheme is used to limit stream creation and to bound the amount of data that can be sent. QUIC provides the necessary feedback to implement reliable delivery and congestion control. An algorithm for detecting and recovering from loss of data is described in Section 6 of [QUIC-RECOVERY]. QUIC depends on congestion control to avoid network congestion. An exemplary congestion control algorithm is described in Section 7 of [QUIC-RECOVERY]. QUIC connections are not strictly bound to a single network path. Connection migration uses connection identifiers to allow connections to transfer to a new network path. Only clients are able to migrate in this version of QUIC. This design also allows connections to continue after changes in network topology or address mappings, such as might be caused by NAT rebinding.
[……下接术语:QUIC 不是首字母缩写]
QUIC: The transport protocol described by this document. QUIC is a
name, not an acronym.
注解
9000 定义 QUIC 第 1 版(版本号 0x00000001)的传输核心:流、连接、迁移、包与帧。TLS 怎么嵌进来是 RFC 9001;丢包与拥塞是 RFC 9002。
包在 UDP 数据报里(一报可含多包,叫 coalesce)。密码学握手用 CRYPTO 帧装 TLS 消息,不是在 QUIC 外面再套一层 TLS 记录。
规范写明:QUIC 是名字,不是缩写。不要展开成 Quick UDP Internet Connections 当考点答案。
流是有序字节,流与流之间不排序
Streams in QUIC provide a lightweight, ordered byte-stream abstraction to an application. Streams can be unidirectional or bidirectional. Streams can be created by sending data. Other processes associated with stream management -- ending, canceling, and managing flow control -- are all designed to impose minimal overheads. For instance, a single STREAM frame (Section 19.8) can open, carry data for, and close a stream. Streams can also be long-lived and can last the entire duration of a connection. Streams can be created by either endpoint, can concurrently send data interleaved with other streams, and can be canceled. QUIC does not provide any means of ensuring ordering between bytes on different streams.
[……下接 Stream ID 低两位]
The least significant bit (0x01) of the stream ID identifies the
initiator of the stream. Client-initiated streams have even-numbered
stream IDs (with the bit set to 0), and server-initiated streams have
odd-numbered stream IDs (with the bit set to 1).
The second least significant bit (0x02) of the stream ID
distinguishes between bidirectional streams (with the bit set to 0)
and unidirectional streams (with the bit set to 1).
The two least significant bits from a stream ID therefore identify a
stream as one of four types, as summarized in Table 1.
+======+==================================+
| Bits | Stream Type |
+======+==================================+
| 0x00 | Client-Initiated, Bidirectional |
+------+----------------------------------+
| 0x01 | Server-Initiated, Bidirectional |
+------+----------------------------------+
| 0x02 | Client-Initiated, Unidirectional |
+------+----------------------------------+
| 0x03 | Server-Initiated, Unidirectional |
+------+----------------------------------+
Table 1: Stream ID Types
注解
同一条流上的字节有序;不同流的字节之间,QUIC 不保证顺序。这是“无队头阻塞”能成立的前提:丢了流 0 的包,流 4 仍可往上交。
ID 低两位定类型:0 客户双向、1 服务器双向、2 客户单向、3 服务器单向。HTTP/3 把请求放在客户发起的双向流上。
发送侧 / 接收侧两套状态机
Figure 2 shows the states for the part of a stream that sends data to
a peer.
o
| Create Stream (Sending)
| Peer Creates Bidirectional Stream
v
+-------+
| Ready | Send RESET_STREAM
| |-----------------------.
+-------+ |
| |
| Send STREAM / |
| STREAM_DATA_BLOCKED |
v |
+-------+ |
| Send | Send RESET_STREAM |
| |---------------------->|
+-------+ |
| |
| Send STREAM + FIN |
v v
+-------+ +-------+
| Data | Send RESET_STREAM | Reset |
| Sent |------------------>| Sent |
+-------+ +-------+
| |
| Recv All ACKs | Recv ACK
v v
+-------+ +-------+
| Data | | Reset |
| Recvd | | Recvd |
+-------+ +-------+
Figure 2: States for Sending Parts of Streams
[……下接收侧]
Figure 3 shows the states for the part of a stream that receives data
from a peer. The states for a receiving part of a stream mirror only
some of the states of the sending part of the stream at the peer.
The receiving part of a stream does not track states on the sending
part that cannot be observed, such as the "Ready" state. Instead,
the receiving part of a stream tracks the delivery of data to the
application, some of which cannot be observed by the sender.
o
| Recv STREAM / STREAM_DATA_BLOCKED / RESET_STREAM
| Create Bidirectional Stream (Sending)
| Recv MAX_STREAM_DATA / STOP_SENDING (Bidirectional)
| Create Higher-Numbered Stream
v
+-------+
| Recv | Recv RESET_STREAM
| |-----------------------.
+-------+ |
| |
| Recv STREAM + FIN |
v |
+-------+ |
| Size | Recv RESET_STREAM |
| Known |---------------------->|
+-------+ |
| |
| Recv All Data |
v v
+-------+ Recv RESET_STREAM +-------+
| Data |--- (optional) --->| Reset |
| Recvd | Recv All Data | Recvd |
+-------+<-- (optional) ----+-------+
| |
| App Read All Data | App Read Reset
v v
+-------+ +-------+
| Data | | Reset |
| Read | | Read |
+-------+ +-------+
Figure 3: States for Receiving Parts of Streams
注解
QUIC 不画一张 HTTP/2 那样的单一生命周期图,而把一条双向流拆成发送部件和接收部件。发送:Ready → Send → Data Sent → Data Recvd,或随时 RESET_STREAM 走到 Reset Sent / Reset Recvd。接收:Recv → Size Known → Data Recvd → Data Read。
STREAM + FIN 可一次跨两态。这些图是规则说明,实现可以换状态机,只要对外行为一致。
连接不绑死在四元组上
Each connection possesses a set of connection identifiers, or connection IDs, each of which can identify the connection. Connection IDs are independently selected by endpoints; each endpoint selects the connection IDs that its peer uses. The primary function of a connection ID is to ensure that changes in addressing at lower protocol layers (UDP, IP) do not cause packets for a QUIC connection to be delivered to the wrong endpoint. Each endpoint selects connection IDs using an implementation-specific (and perhaps deployment-specific) method that will allow packets with that connection ID to be routed back to the endpoint and to be identified by the endpoint upon receipt. Multiple connection IDs are used so that endpoints can send packets that cannot be identified by an observer as being for the same connection without cooperation from an endpoint; see Section 9.5. Connection IDs MUST NOT contain any information that can be used by an external observer (that is, one that does not cooperate with the issuer) to correlate them with other connection IDs for the same connection. As a trivial example, this means the same connection ID MUST NOT be issued more than once on the same connection.
注解
Connection ID 的首要功能:下层地址变了(换网、NAT 重绑),包仍能送到同一个端点。第 1 版里只有客户端能主动迁移。负载均衡常看 DCID,而不是只看 IP:port。
端点为 peer 选择一个或多个 CID;CID 对 peer 不透明。非零长度 CID 可轮换以降低外部关联;签发端 / 协作负载均衡可用内部编码,但不得让非协作观察者据此关联同一连接。选了零长度 CID 的连接不能再签发新 CID,也就不轮换。
长包头带 Source 和 Destination 两个 CID;短包头只带 Destination,省略的是 DCID 的显式长度字段——对端必须已经知道 CID 长度。短头也没有 packet length,因此短头包只能位于 UDP datagram 最后。
握手:CRYPTO 帧里跑 TLS 1.3
QUIC relies on a combined cryptographic and transport handshake to
minimize connection establishment latency. QUIC uses the CRYPTO
frame (Section 19.6) to transmit the cryptographic handshake. The
version of QUIC defined in this document is identified as 0x00000001
and uses TLS as described in [QUIC-TLS]; a different QUIC version
could indicate that a different cryptographic handshake protocol is
in use.
QUIC provides reliable, ordered delivery of the cryptographic
handshake data. QUIC packet protection is used to encrypt as much of
the handshake protocol as possible. The cryptographic handshake MUST
provide the following properties:
* authenticated key exchange, where
- a server is always authenticated,
- a client is optionally authenticated,
- every connection produces distinct and unrelated keys, and
- keying material is usable for packet protection for both 0-RTT
and 1-RTT packets.
* authenticated exchange of values for transport parameters of both
endpoints, and confidentiality protection for server transport
parameters (see Section 7.4).
* authenticated negotiation of an application protocol (TLS uses
Application-Layer Protocol Negotiation (ALPN) [ALPN] for this
purpose).
The CRYPTO frame can be sent in different packet number spaces
(Section 12.3). The offsets used by CRYPTO frames to ensure ordered
delivery of cryptographic handshake data start from zero in each
packet number space.
Figure 4 shows a simplified handshake and the exchange of packets and
frames that are used to advance the handshake. Exchange of
application data during the handshake is enabled where possible,
shown with an asterisk ("*"). Once the handshake is complete,
endpoints are able to exchange application data freely.
Client Server
Initial (CRYPTO)
0-RTT (*) ---------->
Initial (CRYPTO)
Handshake (CRYPTO)
<---------- 1-RTT (*)
Handshake (CRYPTO)
1-RTT (*) ---------->
<---------- 1-RTT (HANDSHAKE_DONE)
1-RTT <=========> 1-RTT
Figure 4: Simplified QUIC Handshake
[……下接 1-RTT 实例]
Figure 5 provides an overview of the 1-RTT handshake. Each line
shows a QUIC packet with the packet type and packet number shown
first, followed by the frames that are typically contained in those
packets. For instance, the first packet is of type Initial, with
packet number 0, and contains a CRYPTO frame carrying the
ClientHello.
Multiple QUIC packets -- even of different packet types -- can be
coalesced into a single UDP datagram; see Section 12.2. As a result,
this handshake could consist of as few as four UDP datagrams, or any
number more (subject to limits inherent to the protocol, such as
congestion control and anti-amplification). For instance, the
server's first flight contains Initial packets, Handshake packets,
and "0.5-RTT data" in 1-RTT packets.
Client Server
Initial[0]: CRYPTO[CH] ->
Initial[0]: CRYPTO[SH] ACK[0]
Handshake[0]: CRYPTO[EE, CERT, CV, FIN]
<- 1-RTT[0]: STREAM[1, "..."]
Initial[1]: ACK[0]
Handshake[0]: CRYPTO[FIN], ACK[0]
1-RTT[0]: STREAM[0, "..."], ACK[0] ->
Handshake[1]: ACK[0]
<- 1-RTT[1]: HANDSHAKE_DONE, STREAM[3, "..."], ACK[0]
Figure 5: Example 1-RTT Handshake
[……下接 0-RTT 实例]
Figure 6 shows an example of a connection with a 0-RTT handshake and
a single packet of 0-RTT data. Note that as described in
Section 12.3, the server acknowledges 0-RTT data in 1-RTT packets,
and the client sends 1-RTT packets in the same packet number space.
Client Server
Initial[0]: CRYPTO[CH]
0-RTT[0]: STREAM[0, "..."] ->
Initial[0]: CRYPTO[SH] ACK[0]
Handshake[0] CRYPTO[EE, FIN]
<- 1-RTT[0]: STREAM[1, "..."] ACK[0]
Initial[1]: ACK[0]
Handshake[0]: CRYPTO[FIN], ACK[0]
1-RTT[1]: STREAM[0, "..."] ACK[0] ->
Handshake[1]: ACK[0]
<- 1-RTT[1]: HANDSHAKE_DONE, STREAM[3, "..."], ACK[1]
Figure 6: Example 0-RTT Handshake
[……下接 0-RTT 无重放保护]
An application protocol can use the connection during the handshake phase with some limitations. 0-RTT allows application data to be sent by a client before receiving a response from the server. However, 0-RTT provides no protection against replay attacks; see Section 9.2 of [QUIC-TLS]. A server can also send application data to a client before it receives the final cryptographic handshake messages that allow it to confirm the identity and liveness of the client. These capabilities allow an application protocol to offer the option of trading some security guarantees for reduced latency.
注解
本版本 QUIC 用 TLS(见 RFC 9001 §4.1.3)做密钥协商。CRYPTO 帧可出现在 Initial、Handshake、1-RTT 包里,不能出现在 0-RTT。Initial 与 Handshake 各有独立包号空间;0-RTT 与 1-RTT 共用 application data 空间。QUIC 承载的是 TLS 握手消息内容,不使用 TLS record 保护;应用协议用 ALPN 显式谈妥。
1-RTT:客户端 Initial 里带 ClientHello;服务器用 Initial + Handshake + 可以提前发的 1-RTT(所谓 0.5-RTT)回答;客户端再发 Handshake Finished 和 1-RTT 应用数据。整次握手可以少到约 4 个 UDP 数据报(包可 coalesce)。
0-RTT:客户端凭先前会话在第一趟就发应用数据。9000 写明:0-RTT 不提供重放保护(细节见 9001 §9.2,以及 TLS 1.3 §2.3)。服务器可拒 early data,退回普通 1-RTT。
0-RTT 与 1-RTT 共用包号空间;服务器在 1-RTT 包里确认 0-RTT。不要把“0-RTT 包”说成“没有加密”。
Initial 不是明文,但初期旁观者解得开
QUIC packets have different levels of cryptographic protection based on the type of packet. Details of packet protection are found in [QUIC-TLS]; this section includes an overview of the protections that are provided. Version Negotiation packets have no cryptographic protection; see [QUIC-INVARIANTS]. Retry packets use an AEAD function [AEAD] to protect against accidental modification. Initial packets use an AEAD function, the keys for which are derived using a value that is visible on the wire. Initial packets therefore do not have effective confidentiality protection. Initial protection exists to ensure that the sender of the packet is on the network path. Any entity that receives an Initial packet from a client can recover the keys that will allow them to both read the contents of the packet and generate Initial packets that will be successfully authenticated at either endpoint. The AEAD also protects Initial packets against accidental modification. All other packets are protected with keys derived from the cryptographic handshake. The cryptographic handshake ensures that only the communicating endpoints receive the corresponding keys for Handshake, 0-RTT, and 1-RTT packets. Packets protected with 0-RTT and 1-RTT keys have strong confidentiality and integrity protection.
[……下接 DCID 派生 Initial 密钥]
The Destination Connection ID field from the first Initial packet sent by a client is used to determine packet protection keys for Initial packets. These keys change after receiving a Retry packet; see Section 5.2 of [QUIC-TLS].
[……下接 Initial 包上的保护说明]
In order to prevent tampering by version-unaware middleboxes, Initial packets are protected with connection- and version-specific keys (Initial keys) as described in [QUIC-TLS]. This protection does not provide confidentiality or integrity against attackers that can observe packets, but it does prevent attackers that cannot observe packets from spoofing Initial packets.
[……下接盐 + DCID]
The packets that carry the cryptographic handshake are protected with a key that is derived from this connection ID and a salt specific to the QUIC version. This allows endpoints to use the same process for authenticating packets that they receive as they use after the cryptographic handshake completes. Packets that cannot be authenticated are discarded. Protecting packets in this fashion provides a strong assurance that the sender of the packet saw the Initial packet and understood it.
注解
Initial 使用 AEAD,密钥由线上可见的值派生:客户端第一枚 Initial 的 Destination Connection ID,加上该 QUIC 版本绑定的固定盐(盐的字节在 RFC 9001 §5.2,不在 9000)。因此 Initial 不是明文,也没有有效的机密性:任何收到这枚包的实体都能算出密钥,读出 CRYPTO(ClientHello)并伪造能通过认证的 Initial。
保护的真正目的:证明发送者在网络路径上,并挡住看不到原包的人去伪造 Initial(也挡住不懂版本的中间盒乱改)。Handshake / 0-RTT / 1-RTT 的密钥来自 TLS 握手,旁观者不能同样解开。
Version Negotiation 没有密码学保护。Retry 用 AEAD 防无意篡改,密钥材料同样是版本相关的。
长包头、短包头、包类型
Long Header Packet {
Header Form (1) = 1,
Fixed Bit (1) = 1,
Long Packet Type (2),
Type-Specific Bits (4),
Version (32),
Destination Connection ID Length (8),
Destination Connection ID (0..160),
Source Connection ID Length (8),
Source Connection ID (0..160),
Type-Specific Payload (..),
}
Figure 13: Long Header Packet Format
Long headers are used for packets that are sent prior to the
establishment of 1-RTT keys. Once 1-RTT keys are available, a sender
switches to sending packets using the short header (Section 17.3).
The long form allows for special packets -- such as the Version
Negotiation packet -- to be represented in this uniform fixed-length
packet format. Packets that use the long header contain the
following fields:
Header Form: The most significant bit (0x80) of byte 0 (the first
byte) is set to 1 for long headers.
Fixed Bit: The next bit (0x40) of byte 0 is set to 1, unless the
packet is a Version Negotiation packet. Packets containing a zero
value for this bit are not valid packets in this version and MUST
be discarded. A value of 1 for this bit allows QUIC to coexist
with other protocols; see [RFC7983].
Long Packet Type: The next two bits (those with a mask of 0x30) of
byte 0 contain a packet type. Packet types are listed in Table 5.
Type-Specific Bits: The semantics of the lower four bits (those with
a mask of 0x0f) of byte 0 are determined by the packet type.
Version: The QUIC Version is a 32-bit field that follows the first
byte. This field indicates the version of QUIC that is in use and
determines how the rest of the protocol fields are interpreted.
Destination Connection ID Length: The byte following the version
contains the length in bytes of the Destination Connection ID
field that follows it. This length is encoded as an 8-bit
unsigned integer. In QUIC version 1, this value MUST NOT exceed
20 bytes. Endpoints that receive a version 1 long header with a
value larger than 20 MUST drop the packet. In order to properly
form a Version Negotiation packet, servers SHOULD be able to read
longer connection IDs from other QUIC versions.
Destination Connection ID: The Destination Connection ID field
follows the Destination Connection ID Length field, which
indicates the length of this field. Section 7.2 describes the use
of this field in more detail.
Source Connection ID Length: The byte following the Destination
Connection ID contains the length in bytes of the Source
Connection ID field that follows it. This length is encoded as an
8-bit unsigned integer. In QUIC version 1, this value MUST NOT
exceed 20 bytes. Endpoints that receive a version 1 long header
with a value larger than 20 MUST drop the packet. In order to
properly form a Version Negotiation packet, servers SHOULD be able
to read longer connection IDs from other QUIC versions.
Source Connection ID: The Source Connection ID field follows the
Source Connection ID Length field, which indicates the length of
this field. Section 7.2 describes the use of this field in more
detail.
Type-Specific Payload: The remainder of the packet, if any, is type
specific.
In this version of QUIC, the following packet types with the long
header are defined:
+======+===========+================+
| Type | Name | Section |
+======+===========+================+
| 0x00 | Initial | Section 17.2.2 |
+------+-----------+----------------+
| 0x01 | 0-RTT | Section 17.2.3 |
+------+-----------+----------------+
| 0x02 | Handshake | Section 17.2.4 |
+------+-----------+----------------+
| 0x03 | Retry | Section 17.2.5 |
+------+-----------+----------------+
Table 5: Long Header Packet Types
[……下接 Initial 布局]
Initial Packet {
Header Form (1) = 1,
Fixed Bit (1) = 1,
Long Packet Type (2) = 0,
Reserved Bits (2),
Packet Number Length (2),
Version (32),
Destination Connection ID Length (8),
Destination Connection ID (0..160),
Source Connection ID Length (8),
Source Connection ID (0..160),
Token Length (i),
Token (..),
Length (i),
Packet Number (8..32),
Packet Payload (8..),
}
Figure 15: Initial Packet
[……下接短包头 1-RTT]
This version of QUIC defines a single packet type that uses the short
packet header.
17.3.1. 1-RTT Packet
A 1-RTT packet uses a short packet header. It is used after the
version and 1-RTT keys are negotiated.
1-RTT Packet {
Header Form (1) = 0,
Fixed Bit (1) = 1,
Spin Bit (1),
Reserved Bits (2),
Key Phase (1),
Packet Number Length (2),
Destination Connection ID (0..160),
Packet Number (8..32),
Packet Payload (8..),
}
Figure 19: 1-RTT Packet
注解
首字节最高位 Header Form:1 = 长头,0 = 短头。长头用于 1-RTT 密钥就绪之前:Initial 0x00、0-RTT 0x01、Handshake 0x02、Retry 0x03(Table 5 的 Type 是长头里那 2 bit)。Version 0 且长头是 Version Negotiation。
Fixed Bit(0x40)在本版本必须为 1(Version Negotiation 除外),为的是和别的 UDP 协议共存。
短头只有 1-RTT:无版本、无 Source CID、无 Length,所以短头包只能放在 UDP 数据报的最后。包号和若干首字节位受 header protection。
无队头阻塞指跨流,不是包永不丢
This version of QUIC uses the long packet header during connection establishment; see Section 17.2. Packets with the long header are Initial (Section 17.2.2), 0-RTT (Section 17.2.3), Handshake (Section 17.2.4), and Retry (Section 17.2.5). Version negotiation uses a version-independent packet with a long header; see Section 17.2.1. Packets with the short header are designed for minimal overhead and are used after a connection is established and 1-RTT keys are available; see Section 17.3.
[……下接多路复用与丢包]
Stream multiplexing is achieved by interleaving STREAM frames from multiple streams into one or more QUIC packets. A single QUIC packet can include multiple STREAM frames from one or more streams. One of the benefits of QUIC is avoidance of head-of-line blocking across multiple streams. When a packet loss occurs, only streams with data in that packet are blocked waiting for a retransmission to be received, while other streams can continue making progress. Note that when data from multiple streams is included in a single QUIC packet, loss of that packet blocks all those streams from making progress. Implementations are advised to include as few streams as necessary in outgoing packets without losing transmission efficiency to underfilled packets.
注解
TCP 把整个连接当成一条字节流:丢一个段,后续字节即使已到也不能上交应用——这是连接级队头阻塞。HTTP/2 在一条 TCP 上多路复用,丢包仍会卡住后面所有流。
QUIC 的“避免队头阻塞”是跨流:丢的那个包里没有的流,可以继续前进。同一包里若交错了多条流的 STREAM 帧,丢这包会同时挡住那些流。实现被建议别往一个包里塞太多流。
单条流内部仍是有序字节,丢了照样等重传。不要说成“QUIC 没有丢包”或“QUIC 完全没有队头阻塞”。
抓包对照
QUIC 在 UDP 上,HTTPS 常用 443。先认长包头和版本,再让 Wireshark 用版本盐解开 Initial。
- 过滤器从
udp.port == 443和quic起手。命中quic.long.packet_type == 0过滤到的是 Initial;客户端首次发送必须以 Initial 开始,但任意 Initial 不一定是首包(重传 / 后续 Initial 同样匹配)。 - Wireshark 知道 v1 的固定盐,能从 DCID 派生 Initial 密钥,于是 CRYPTO 里的 ClientHello 可在不配 TLS 密钥的情况下展开。Handshake / 1-RTT 仍要会话密钥。
- 一个 UDP 数据报里可能叠了 Initial + Handshake + 1-RTT。短头包没有 Length,只能在报尾。
- 不要把 QUIC 认成“UDP 上的 TLS 记录层”。TLS 消息在 CRYPTO 帧里,外层是 QUIC 包保护。
考点与易错点
- Initial 用 AEAD,密钥 = 可见 DCID + 版本绑定固定盐(9001 §5.2)。不是明文,但没有有效机密性;旁观者解得开、也能伪造。
- 1-RTT / 0-RTT 的密钥来自 TLS 1.3 握手(RFC 9001)。0-RTT 无重放保护;服务器可拒并退回 1-RTT。
- Connection ID 让连接脱离四元组,用于路由和迁移;不是 TCP 那种“地址+端口即连接”。
- 无队头阻塞是跨流的:丢包只挡住当时在那个包里的流。单流内部仍然有序、仍会等重传。
- 长头 type:Initial 0x00、0-RTT 0x01、Handshake 0x02、Retry 0x03。短头才是 1-RTT。
- QUIC 是名字不是缩写。抓包用
udp port 443和quic,不要用tcp port 443。