2018-11-27 09:29:03 -05:00
package wire
import (
"bytes"
"errors"
"fmt"
"io"
2019-01-17 09:33:18 -05:00
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/protocol"
"v2ray.com/core/external/github.com/lucas-clemente/quic-go/internal/utils"
2018-11-27 09:29:03 -05:00
)
// ExtendedHeader is the header of a QUIC packet.
type ExtendedHeader struct {
Header
typeByte byte
PacketNumberLen protocol . PacketNumberLen
PacketNumber protocol . PacketNumber
KeyPhase int
}
func ( h * ExtendedHeader ) parse ( b * bytes . Reader , v protocol . VersionNumber ) ( * ExtendedHeader , error ) {
// read the (now unencrypted) first byte
var err error
h . typeByte , err = b . ReadByte ( )
if err != nil {
return nil , err
}
2019-01-02 07:01:06 -05:00
if _ , err := b . Seek ( int64 ( h . ParsedLen ( ) ) - 1 , io . SeekCurrent ) ; err != nil {
2018-11-27 09:29:03 -05:00
return nil , err
}
if h . IsLongHeader {
return h . parseLongHeader ( b , v )
}
return h . parseShortHeader ( b , v )
}
func ( h * ExtendedHeader ) parseLongHeader ( b * bytes . Reader , v protocol . VersionNumber ) ( * ExtendedHeader , error ) {
if h . typeByte & 0xc != 0 {
return nil , errors . New ( "5th and 6th bit must be 0" )
}
if err := h . readPacketNumber ( b ) ; err != nil {
return nil , err
}
return h , nil
}
func ( h * ExtendedHeader ) parseShortHeader ( b * bytes . Reader , v protocol . VersionNumber ) ( * ExtendedHeader , error ) {
if h . typeByte & 0x18 != 0 {
return nil , errors . New ( "4th and 5th bit must be 0" )
}
h . KeyPhase = int ( h . typeByte & 0x4 ) >> 2
if err := h . readPacketNumber ( b ) ; err != nil {
return nil , err
}
return h , nil
}
func ( h * ExtendedHeader ) readPacketNumber ( b * bytes . Reader ) error {
h . PacketNumberLen = protocol . PacketNumberLen ( h . typeByte & 0x3 ) + 1
pn , err := utils . BigEndian . ReadUintN ( b , uint8 ( h . PacketNumberLen ) )
if err != nil {
return err
}
h . PacketNumber = protocol . PacketNumber ( pn )
return nil
}
// Write writes the Header.
func ( h * ExtendedHeader ) Write ( b * bytes . Buffer , ver protocol . VersionNumber ) error {
if h . IsLongHeader {
return h . writeLongHeader ( b , ver )
}
return h . writeShortHeader ( b , ver )
}
func ( h * ExtendedHeader ) writeLongHeader ( b * bytes . Buffer , v protocol . VersionNumber ) error {
var packetType uint8
switch h . Type {
case protocol . PacketTypeInitial :
packetType = 0x0
case protocol . PacketType0RTT :
packetType = 0x1
case protocol . PacketTypeHandshake :
packetType = 0x2
case protocol . PacketTypeRetry :
packetType = 0x3
}
firstByte := 0xc0 | packetType << 4
if h . Type == protocol . PacketTypeRetry {
odcil , err := encodeSingleConnIDLen ( h . OrigDestConnectionID )
if err != nil {
return err
}
firstByte |= odcil
} else { // Retry packets don't have a packet number
firstByte |= uint8 ( h . PacketNumberLen - 1 )
}
b . WriteByte ( firstByte )
utils . BigEndian . WriteUint32 ( b , uint32 ( h . Version ) )
connIDLen , err := encodeConnIDLen ( h . DestConnectionID , h . SrcConnectionID )
if err != nil {
return err
}
b . WriteByte ( connIDLen )
b . Write ( h . DestConnectionID . Bytes ( ) )
b . Write ( h . SrcConnectionID . Bytes ( ) )
switch h . Type {
case protocol . PacketTypeRetry :
b . Write ( h . OrigDestConnectionID . Bytes ( ) )
b . Write ( h . Token )
return nil
case protocol . PacketTypeInitial :
utils . WriteVarInt ( b , uint64 ( len ( h . Token ) ) )
b . Write ( h . Token )
}
utils . WriteVarInt ( b , uint64 ( h . Length ) )
return h . writePacketNumber ( b )
}
// TODO: add support for the key phase
func ( h * ExtendedHeader ) writeShortHeader ( b * bytes . Buffer , v protocol . VersionNumber ) error {
typeByte := 0x40 | uint8 ( h . PacketNumberLen - 1 )
typeByte |= byte ( h . KeyPhase << 2 )
b . WriteByte ( typeByte )
b . Write ( h . DestConnectionID . Bytes ( ) )
return h . writePacketNumber ( b )
}
func ( h * ExtendedHeader ) writePacketNumber ( b * bytes . Buffer ) error {
if h . PacketNumberLen == protocol . PacketNumberLenInvalid || h . PacketNumberLen > protocol . PacketNumberLen4 {
return fmt . Errorf ( "invalid packet number length: %d" , h . PacketNumberLen )
}
utils . BigEndian . WriteUintN ( b , uint8 ( h . PacketNumberLen ) , uint64 ( h . PacketNumber ) )
return nil
}
// GetLength determines the length of the Header.
func ( h * ExtendedHeader ) GetLength ( v protocol . VersionNumber ) protocol . ByteCount {
if h . IsLongHeader {
length := 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol . ByteCount ( h . DestConnectionID . Len ( ) + h . SrcConnectionID . Len ( ) ) + protocol . ByteCount ( h . PacketNumberLen ) + utils . VarIntLen ( uint64 ( h . Length ) )
if h . Type == protocol . PacketTypeInitial {
length += utils . VarIntLen ( uint64 ( len ( h . Token ) ) ) + protocol . ByteCount ( len ( h . Token ) )
}
return length
}
length := protocol . ByteCount ( 1 /* type byte */ + h . DestConnectionID . Len ( ) )
length += protocol . ByteCount ( h . PacketNumberLen )
return length
}
// Log logs the Header
func ( h * ExtendedHeader ) Log ( logger utils . Logger ) {
if h . IsLongHeader {
var token string
if h . Type == protocol . PacketTypeInitial || h . Type == protocol . PacketTypeRetry {
if len ( h . Token ) == 0 {
token = "Token: (empty), "
} else {
token = fmt . Sprintf ( "Token: %#x, " , h . Token )
}
if h . Type == protocol . PacketTypeRetry {
logger . Debugf ( "\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sOrigDestConnectionID: %s, Version: %s}" , h . Type , h . DestConnectionID , h . SrcConnectionID , token , h . OrigDestConnectionID , h . Version )
return
}
}
logger . Debugf ( "\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %#x, PacketNumberLen: %d, Length: %d, Version: %s}" , h . Type , h . DestConnectionID , h . SrcConnectionID , token , h . PacketNumber , h . PacketNumberLen , h . Length , h . Version )
} else {
logger . Debugf ( "\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}" , h . DestConnectionID , h . PacketNumber , h . PacketNumberLen , h . KeyPhase )
}
}
func encodeConnIDLen ( dest , src protocol . ConnectionID ) ( byte , error ) {
dcil , err := encodeSingleConnIDLen ( dest )
if err != nil {
return 0 , err
}
scil , err := encodeSingleConnIDLen ( src )
if err != nil {
return 0 , err
}
return scil | dcil << 4 , nil
}
func encodeSingleConnIDLen ( id protocol . ConnectionID ) ( byte , error ) {
len := id . Len ( )
if len == 0 {
return 0 , nil
}
if len < 4 || len > 18 {
return 0 , fmt . Errorf ( "invalid connection ID length: %d bytes" , len )
}
return byte ( len - 3 ) , nil
}