QUIC的那些事 | 包类型及格式

本文详细介绍了QUIC协议的报文结构,包括报文头、特殊报文(版本协商报文、公共重置报文)以及普通报文(帧包、FEC包)。重点阐述了报文头的Public Flags字段及其意义,同时讨论了QUIC报文的加密与认证机制,确保了通信的安全性。

目录

报文头

特殊报文

版本协商报文

Public Reset报文

普通报文(Regular Packet)

帧包(Frame Packet)

FEC包(FEC Packet)

参考资料


QUIC 的 packet 除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。

如图 1所示,红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。

图 1 QUIC报文格式

QUIC报文分为特殊报文和普通报文。特殊报文又分为两类:版本协商报文(Version Negotiation Packets)及公共重置报文(Public Reset Packets)。普通报文也分为两类:帧报文及FEC(Forward Error Correction)报文。

QUIC报文的大小需要满足路径MTU的大小以避免被分片。当前QUIC在IPV6下的最大报文长度为1350,IPV4下的最大报文长度为1370.

报文头

QUIC报文都有一个公共的头部,大小在2-19字节之间,格式如图 2所示:

 

图 2 Public Header 格式

其中,图 2中的长度是以Bit为单位,如Connection ID的0,8,32,64,单位均为Bit.

第一字节为:Public  Flags

Public Flag的8位如下所示,左边为高位,右边为低位

Bit7

Bit6

Bit5

Bit4

Bit3

Bit2

Bit1

Bit0

如果Bit0被置上(0x01 = PUBLIC_FLAG_VERSION = 0x01),该字段的含义取决于报文是客户端还是服务端发送。如果是客户端发送,这一位被置上表示QUIC Version字段不为空,且QUIC Version字段被填充为客户端的QUIC版本信息。在客户端收到服务端同意建立该版本的连接报文抵达之前,客户端发送的所有报文的这一位必须都要被设置。如果服务端同意建立该版本的连接,那么这一位不用设置。如果这一位被服务端置上,那么表示该报文是版本协商报文(Version Negotiation Packet)。

如果Bit1被置上(0x02 = PUBLIC_FLAG_RESET),表明该报文是公共重置报文(Public Reset packet)

Bit2、Bit3两位表示报文中的Connection ID的长度。直至协商另外一个值之前,在所有的报文中,这两位必须设置被设置为相同(客户端可能请求更少的数据,所以ConnectID的长度需要变化)

0x0C(Bit3及Bit2均为1)表示Connection ID长度是8字节

0x08(Bit3位1,Bit2为0)表示Connection ID长度是4字节

0x04(Bit3位0,Bit2为1)表示Connection ID长度是1字节

0x00(Bit3及Bit2均为0)表示无Connection ID

Bit4、Bit5两位表示每个数据包中存在的数据包编号的字节数。对于帧数据,这两位才使用,对于Public Reset报文及Version Negotiation报文,这两位必须为0

0x30(Bit5及Bit4均为1)表示:包序号是6个字节

0x20(Bit5为1,Bit4为0)表示:包序号是4个字节

0x10(Bit5为0,Bit4为1)表示:包序号是2个字节

0x00(Bit5及Bit4均为0)表示:包序号是1个字节

Bit6:预留给多路径使用

Bit7:未使用,必须为0

Connection ID:客户端随机选择的最大长度为64位的无符号整数。但是,长度可以协商。

QUIC Version:QUIC协议的版本号,32位的可选字段。如果Public Flag & FLAG_VERSION != 0,这个字段必填。客户端设置Public Flag中的Bit0为1,并且填写期望的版本号。如果客户端期望的版本号服务端不支持,服务端设置Public Flag中的Bit0为1,并且在该字段中列出服务端支持的协议版本(0或者多个),并且该字段后不能有任何报文。

Packet Number:长度取决于Public Flag中Bit4及Bit5两位的值,最大长度6字节。发送端在每个普通报文中设置Packet Number。发送端发送的第一个包的序列号是1,随后的数据包中的序列号的都大于前一个包中的序列号。

Public Flags的解析流程如图3所示:

 图3 Public Flag解析过程

 

特殊报文

版本协商报文

版本协商报文(version negotiation packet)只由服务端发送。版本协议报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_VERSION且标识Connection ID长度为8字节,最后面就是服务端支持的协议版本(4字节)。

 

图 4 协议协商报文格式

 

Public Reset报文

Public Reset报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_RESET且标识Connection ID长度为8字节,剩余的部分是QUIC Tag。

 

图 5 Public Reset报文格式

        

         Tag value map包含如下的tag-values:

         RNON (public reset nonce proof):64位的无符号整数,必填

         RSEQ (rejected packet number) :64位的无符号整数,必填

         CADR (client address):客户端的IP地址及端口。当前用于调试用途,可选        

普通报文(Regular Packet)

普通的报文被验证(authenticated)且被加密。公有头被验证但是没有加密,从Private Flags字段开始的报文被加密。普通的报文包含AEAD(authenticated encryption and associated data)报文。普通报文必须被解密,并且密文被解密后,明文以Private Header开始。

普通报文中私有头格式如图 6所示:

 

图 6 普通报文中私有头格式

Private Flags解析

当Bit0被置为1时(0x01 = FLAG_ENTROPY): 对于数据包,表示该包包含1位熵;对于FEC(Forward Error Correction)包,表示包含受保护包熵的异或。

当Bit1被置为1时(0x02 = FLAG_FEC_GROUP):表示是否有FEC 字段(Forward Error Correction)

当Bit2被置为1时(0x04 = FLAG_FEC):表示是FEC包

FEC(FEC Group Number offset):可选字段,8位的无符号整数,是相对值。

QUIC帧数据包由帧填充,通过Frame Type确定到底是何种数据。

帧包(Frame Packet)

除了私有头外,帧包有一系列的基于类型的帧数据的负载,通用的帧包的格式如图 7所示:

图 7 Frame packet格式

 

FEC包(FEC Packet)

FEC包(FLAG_FEC标志被置为1)的负载只包含位于FEC组中的每个数据包的空填充负载的XOR值。每个FEC包的FLAG_FEC_GROUP标志也必须被置为1。格式如图8所示

 

图 8 FEC包格式

 

参考资料

https://tools.ietf.org/html/draft-tsvwg-quic-protocol-02#ref-3

扫描二维码,关注“小眼睛的梦呓”公众号,在手机端查看文章
扫描二维码,关注“清远的梦呓”公众号,在手机端查看文章

 

QUIC协议的数据结构设计旨在提供高效、灵活的传输能力,同时支持多路复用、流控制和连接迁移等特性。QUIC的数据包格式由多个部分组成,主要括公共头部(Public Header)、加密的私有头部(Private Header)、帧(Frames)以及认证标签(Authentication Tag)等部分。 ### 数据结构详解 #### 1. 公共头部(Public Header) 公共头部是所有QUIC数据都必须含的部分,主要用于标识连接和处理基本的控制信息。它括以下几个关键字段: - **Connection ID(连接ID)**:一个64位的随机数,用于唯一标识一条QUIC连接。即使IP地址或端口号发生变化,只要连接ID不变,连接仍然保持有效,从而实现连接迁移功能 [^4]。 - **Packet Number(序号)**:每个数据都有一个唯一的序号,用于确认机制和丢检测。QUIC支持多种长度的序号编码,以适应不同的网络环境。 - **Packet Type(类型)**:指示数据类型,例如是初始(Initial Packet)、握手(Handshake Packet)、重传(Retransmission Packet)等。不同类型具有不同的处理逻辑。 - **Version(版本号)**:表示QUIC协议的版本,用于协商协议特性。不同版本的QUIC可能在数据包格式或功能上有所差异。 #### 2. 私有头部(Private Header) 私有头部仅存在于加密后的数据中,含了一些敏感的控制信息。这部分内容在传输过程中会被加密保护,确保安全性。私有头部通常含以下信息: - **Key Phase(密钥阶段)**:用于指示当前使用的加密密钥版本,以便接收方正确解密数据。 - **Packet Number Length(序号长度)**:指示序号字段的长度,用于解析数据。 #### 3. 帧(Frames) 帧是QUIC数据的核心部分,含了实际的控制信息或应用数据。QUIC支持多种类型的帧,每种帧都有特定的功能。常见的帧类型括: - **ACK Frame(确认帧)**:用于确认收到的数据QUIC的ACK Frame支持256个NACK区间,相比TCP的SACK更为灵活,能够更精确地告知发送方哪些数据已经成功接收 [^2]。 - **Stream Frame(流帧)**:用于传输应用层数据。每个流帧关联到一个特定的流(Stream),支持多路复用功能,避免了HTTP/2中的队头阻塞问题。 - **Window Update Frame(窗口更新帧)**:用于通知对端当前的接收窗口大小,实现流控制。 - **Connection Close Frame(连接关闭帧)**:用于优雅地关闭连接,通知对端当前连接即将终止。 - **Ping Frame(心跳帧)**:用于保持连接活跃,防止超时断开。 #### 4. 认证标签(Authentication Tag) 认证标签是数据的最后部分,用于确保数据的完整性和真实性。QUIC使用AEAD(Authenticated Encryption with Associated Data)算法对数据进行加密和认证,防止中间人攻击和数据篡改。 ### 数据包格式示例 以下是一个简化的QUIC数据包格式示意图: ``` +-------------------+-------------------+-------------------+-------------------+ | Public Header | Private Header | Frames | Authentication Tag| +-------------------+-------------------+-------------------+-------------------+ ``` 其中,公共头部和私有头部的长度根据具体的数据类型和配置可能会有所不同,而帧部分的长度则取决于实际传输的数据量。 ### 多路复用与流控制 QUIC通过流(Stream)机制实现了多路复用功能。每个流都有独立的流ID,数据中的流帧(Stream Frame)会携带该流ID,接收方可以根据流ID将数据正确分配到对应的流中。这种方式避免了HTTP/2中由于单一TCP流导致的队头阻塞问题,提高了传输效率 [^7]。 此外,QUIC还引入了基于信用的流控制机制。每个流都有一个接收窗口(Receive Window),接收方通过Window Update Frame通知发送方当前的接收能力,确保发送方不会超出接收方的缓冲区容量发送数据,从而避免了数据丢失和拥塞加剧。 ### 连接迁移 QUIC的连接迁移功能是其一大亮点。由于QUIC连接不再依赖于IP地址和端口号,而是通过连接ID进行标识,因此当客户端的网络环境发生变化时(例如从Wi-Fi切换到移动网络),只要连接ID不变,连接仍然有效,无需重新建立连接。这一特性极大地提升了用户体验,特别是在移动设备频繁切换网络的场景下 [^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值