目录
报文头
特殊报文
版本协商报文
Public Reset报文
普通报文(Regular Packet)
帧包(Frame Packet)
FEC包(FEC Packet)
参考资料
QUIC 的 packet 除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。这样只要对 QUIC 报文任何修改,接收端都能够及时发现,有效地降低了安全风险。
如图 1所示,红色部分是 Stream Frame 的报文头部,有认证。绿色部分是报文内容,全部经过加密。
QUIC报文分为特殊报文和普通报文。特殊报文又分为两类:版本协商报文(Version Negotiation Packets)及公共重置报文(Public Reset Packets)。普通报文也分为两类:帧报文及FEC(Forward Error Correction)报文。
QUIC报文的大小需要满足路径MTU的大小以避免被分片。当前QUIC在IPV6下的最大报文长度为1350,IPV4下的最大报文长度为1370.
QUIC报文都有一个公共的头部,大小在2-19字节之间,格式如图 2所示:
其中,图 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所示:
版本协商报文(version negotiation packet)只由服务端发送。版本协议报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_VERSION且标识Connection ID长度为8字节,最后面就是服务端支持的协议版本(4字节)。
Public Reset报文以1字节的Public Flag及8字节的Connection ID开始。必须设置PUBLIC_FLAG_RESET且标识Connection ID长度为8字节,剩余的部分是QUIC Tag。
Tag value map包含如下的tag-values:
RNON (public reset nonce proof):64位的无符号整数,必填
RSEQ (rejected packet number) :64位的无符号整数,必填
CADR (client address):客户端的IP地址及端口。当前用于调试用途,可选
普通的报文被验证(authenticated)且被加密。公有头被验证但是没有加密,从Private Flags字段开始的报文被加密。普通的报文包含AEAD(authenticated encryption and associated data)报文。普通报文必须被解密,并且密文被解密后,明文以Private Header开始。
普通报文中私有头格式如图 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确定到底是何种数据。
除了私有头外,帧包有一系列的基于类型的帧数据的负载,通用的帧包的格式如图 7所示:
FEC包(FLAG_FEC标志被置为1)的负载只包含位于FEC组中的每个数据包的空填充负载的XOR值。每个FEC包的FLAG_FEC_GROUP标志也必须被置为1。格式如图8所示
https://tools.ietf.org/html/draft-tsvwg-quic-protocol-02#ref-3