wip: implement InitialSpec type (1/n)

- TransportParameters are now set as a part of ClientHelloSpecs
- Removes transportparameters package and uses tls.TransportParameters
This commit is contained in:
Gaukas Wang 2023-07-30 20:01:07 -06:00
parent 9327068651
commit 20e2a487b8
No known key found for this signature in database
GPG key ID: 9E2F8986D76F8B5D
9 changed files with 173 additions and 497 deletions

View file

@ -136,18 +136,19 @@ func populateConfig(config *Config) *Config {
SrcConnIDLength: config.SrcConnIDLength, SrcConnIDLength: config.SrcConnIDLength,
DestConnIDLength: config.DestConnIDLength, DestConnIDLength: config.DestConnIDLength,
InitPacketNumber: config.InitPacketNumber, InitPacketNumber: config.InitPacketNumber,
TransportParameters: config.TransportParameters,
InitPacketNumberLength: config.InitPacketNumberLength, InitPacketNumberLength: config.InitPacketNumberLength,
} }
} }
type PacketNumberLen = protocol.PacketNumberLen
const ( const (
// PacketNumberLen1 is a packet number length of 1 byte // PacketNumberLen1 is a packet number length of 1 byte
PacketNumberLen1 protocol.PacketNumberLen = 1 PacketNumberLen1 PacketNumberLen = 1
// PacketNumberLen2 is a packet number length of 2 bytes // PacketNumberLen2 is a packet number length of 2 bytes
PacketNumberLen2 protocol.PacketNumberLen = 2 PacketNumberLen2 PacketNumberLen = 2
// PacketNumberLen3 is a packet number length of 3 bytes // PacketNumberLen3 is a packet number length of 3 bytes
PacketNumberLen3 protocol.PacketNumberLen = 3 PacketNumberLen3 PacketNumberLen = 3
// PacketNumberLen4 is a packet number length of 4 bytes // PacketNumberLen4 is a packet number length of 4 bytes
PacketNumberLen4 protocol.PacketNumberLen = 4 PacketNumberLen4 PacketNumberLen = 4
) )

View file

@ -397,39 +397,31 @@ var newClientConnection = func(
s.mtuDiscoverer = newMTUDiscoverer(s.rttStats, getMaxPacketSize(s.conn.RemoteAddr()), s.sentPacketHandler.SetMaxDatagramSize) s.mtuDiscoverer = newMTUDiscoverer(s.rttStats, getMaxPacketSize(s.conn.RemoteAddr()), s.sentPacketHandler.SetMaxDatagramSize)
oneRTTStream := newCryptoStream() oneRTTStream := newCryptoStream()
var params *wire.TransportParameters params := &wire.TransportParameters{
if s.config.TransportParameters != nil { InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
params = &wire.TransportParameters{ InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
InitialSourceConnectionID: srcConnID, InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
} InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow),
params.PopulateFromUQUIC(s.config.TransportParameters) MaxIdleTimeout: s.config.MaxIdleTimeout,
s.connIDManager.SetConnectionIDLimit(params.ActiveConnectionIDLimit) MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams),
} else { MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams),
params = &wire.TransportParameters{ MaxAckDelay: protocol.MaxAckDelayInclGranularity,
InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow), AckDelayExponent: protocol.AckDelayExponent,
InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow), DisableActiveMigration: true,
InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow), // For interoperability with quic-go versions before May 2023, this value must be set to a value
InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow), // different from protocol.DefaultActiveConnectionIDLimit.
MaxIdleTimeout: s.config.MaxIdleTimeout, // If set to the default value, it will be omitted from the transport parameters, which will make
MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams), // old quic-go versions interpret it as 0, instead of the default value of 2.
MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams), // See https://github.com/quic-go/quic-go/pull/3806.
MaxAckDelay: protocol.MaxAckDelayInclGranularity, ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
AckDelayExponent: protocol.AckDelayExponent, InitialSourceConnectionID: srcConnID,
DisableActiveMigration: true,
// For interoperability with quic-go versions before May 2023, this value must be set to a value
// different from protocol.DefaultActiveConnectionIDLimit.
// If set to the default value, it will be omitted from the transport parameters, which will make
// old quic-go versions interpret it as 0, instead of the default value of 2.
// See https://github.com/quic-go/quic-go/pull/3806.
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
InitialSourceConnectionID: srcConnID,
}
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
} }
if s.config.EnableDatagrams {
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
if s.tracer != nil { if s.tracer != nil {
s.tracer.SentTransportParameters(params) s.tracer.SentTransportParameters(params)
} }
@ -529,38 +521,52 @@ var newUClientConnection = func(
oneRTTStream := newCryptoStream() oneRTTStream := newCryptoStream()
var params *wire.TransportParameters var params *wire.TransportParameters
if s.config.TransportParameters != nil { // params := &wire.TransportParameters{
params = &wire.TransportParameters{ // InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
InitialSourceConnectionID: srcConnID, // InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
} // InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
params.PopulateFromUQUIC(s.config.TransportParameters) // InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow),
s.connIDManager.SetConnectionIDLimit(params.ActiveConnectionIDLimit) // MaxIdleTimeout: s.config.MaxIdleTimeout,
} else { // MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams),
params = &wire.TransportParameters{ // MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams),
InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow), // MaxAckDelay: protocol.MaxAckDelayInclGranularity,
InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow), // AckDelayExponent: protocol.AckDelayExponent,
InitialMaxStreamDataUni: protocol.ByteCount(s.config.InitialStreamReceiveWindow), // DisableActiveMigration: true,
InitialMaxData: protocol.ByteCount(s.config.InitialConnectionReceiveWindow), // // For interoperability with quic-go versions before May 2023, this value must be set to a value
MaxIdleTimeout: s.config.MaxIdleTimeout, // // different from protocol.DefaultActiveConnectionIDLimit.
MaxBidiStreamNum: protocol.StreamNum(s.config.MaxIncomingStreams), // // If set to the default value, it will be omitted from the transport parameters, which will make
MaxUniStreamNum: protocol.StreamNum(s.config.MaxIncomingUniStreams), // // old quic-go versions interpret it as 0, instead of the default value of 2.
MaxAckDelay: protocol.MaxAckDelayInclGranularity, // // See https://github.com/quic-go/quic-go/pull/3806.
AckDelayExponent: protocol.AckDelayExponent, // ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
DisableActiveMigration: true, // InitialSourceConnectionID: srcConnID,
// For interoperability with quic-go versions before May 2023, this value must be set to a value // }
// different from protocol.DefaultActiveConnectionIDLimit. // if s.config.EnableDatagrams {
// If set to the default value, it will be omitted from the transport parameters, which will make // params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
// old quic-go versions interpret it as 0, instead of the default value of 2. // } else {
// See https://github.com/quic-go/quic-go/pull/3806. // params.MaxDatagramFrameSize = protocol.InvalidByteCount
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs, // }
InitialSourceConnectionID: srcConnID,
} // [UQUIC] iterate over all Extensions to set the TransportParameters
if s.config.EnableDatagrams { var tpSet bool
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize FOR_EACH_TLS_EXTENSION:
} else { for _, ext := range chs.Extensions {
params.MaxDatagramFrameSize = protocol.InvalidByteCount switch ext := ext.(type) {
case *tls.QUICTransportParametersExtension:
params = &wire.TransportParameters{
InitialSourceConnectionID: srcConnID,
}
params.PopulateFromUQUIC(ext.TransportParameters)
s.connIDManager.SetConnectionIDLimit(params.ActiveConnectionIDLimit)
tpSet = true
break FOR_EACH_TLS_EXTENSION
default:
continue FOR_EACH_TLS_EXTENSION
} }
} }
if !tpSet {
panic("applied ClientHelloSpec must contain a QUICTransportParametersExtension to proceed")
}
if s.tracer != nil { if s.tracer != nil {
s.tracer.SentTransportParameters(params) s.tracer.SentTransportParameters(params)
} }

View file

@ -12,8 +12,6 @@ import (
quic "github.com/quic-go/quic-go" quic "github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/http3" "github.com/quic-go/quic-go/http3"
qtp "github.com/quic-go/quic-go/transportparameters"
) )
func getCHS() *tls.ClientHelloSpec { func getCHS() *tls.ClientHelloSpec {
@ -99,7 +97,37 @@ func getCHS() *tls.ClientHelloSpec {
&tls.FakeRecordSizeLimitExtension{ &tls.FakeRecordSizeLimitExtension{
Limit: 0x4001, Limit: 0x4001,
}, },
&tls.QUICTransportParametersExtension{}, &tls.QUICTransportParametersExtension{
TransportParameters: tls.TransportParameters{
tls.InitialMaxStreamDataBidiRemote(0x100000),
tls.InitialMaxStreamsBidi(16),
tls.MaxDatagramFrameSize(1200),
tls.MaxIdleTimeout(30000),
tls.ActiveConnectionIDLimit(8),
&tls.GREASEQUICBit{},
&tls.VersionInformation{
ChoosenVersion: tls.VERSION_1,
AvailableVersions: []uint32{
tls.VERSION_GREASE,
tls.VERSION_1,
},
LegacyID: true,
},
tls.InitialMaxStreamsUni(16),
&tls.GREASE{
IdOverride: 0xff02de1a,
ValueOverride: []byte{
0x43, 0xe8,
},
},
tls.InitialMaxStreamDataBidiLocal(0xc00000),
tls.InitialMaxStreamDataUni(0x100000),
tls.InitialSourceConnectionID([]byte{}),
tls.MaxAckDelay(20),
tls.InitialMaxData(0x1800000),
&tls.DisableActiveMigration{},
},
},
&tls.UtlsPaddingExtension{ &tls.UtlsPaddingExtension{
GetPaddingLen: tls.BoringPaddingStyle, GetPaddingLen: tls.BoringPaddingStyle,
}, },
@ -129,35 +157,6 @@ func main() {
InitPacketNumber: 0, InitPacketNumber: 0,
InitPacketNumberLength: quic.PacketNumberLen1, // currently only affects the initial packet number InitPacketNumberLength: quic.PacketNumberLen1, // currently only affects the initial packet number
// Versions: []quic.VersionNumber{quic.Version2}, // Versions: []quic.VersionNumber{quic.Version2},
TransportParameters: qtp.TransportParameters{
qtp.InitialMaxStreamDataBidiRemote(0x100000),
qtp.InitialMaxStreamsBidi(16),
qtp.MaxDatagramFrameSize(1200),
qtp.MaxIdleTimeout(30000),
qtp.ActiveConnectionIDLimit(8),
&qtp.GREASEQUICBit{},
&qtp.VersionInformation{
ChoosenVersion: qtp.VERSION_1,
AvailableVersions: []uint32{
qtp.VERSION_GREASE,
qtp.VERSION_1,
},
LegacyID: true,
},
qtp.InitialMaxStreamsUni(16),
&qtp.GREASE{
IdOverride: 0xff02de1a,
ValueOverride: []byte{
0x43, 0xe8,
},
},
qtp.InitialMaxStreamDataBidiLocal(0xc00000),
qtp.InitialMaxStreamDataUni(0x100000),
qtp.InitialSourceConnectionID([]byte{}),
qtp.MaxAckDelay(20),
qtp.InitialMaxData(0x1800000),
&qtp.DisableActiveMigration{},
},
} }
roundTripper := &http3.RoundTripper{ roundTripper := &http3.RoundTripper{

View file

@ -12,7 +12,6 @@ import (
"github.com/quic-go/quic-go/internal/handshake" "github.com/quic-go/quic-go/internal/handshake"
"github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/logging" "github.com/quic-go/quic-go/logging"
"github.com/quic-go/quic-go/transportparameters"
) )
// The StreamID is the ID of a QUIC stream. // The StreamID is the ID of a QUIC stream.
@ -336,11 +335,10 @@ type Config struct {
Tracer func(context.Context, logging.Perspective, ConnectionID) logging.ConnectionTracer Tracer func(context.Context, logging.Perspective, ConnectionID) logging.ConnectionTracer
// TransportParameters override other transport parameters set by the Config. // TransportParameters override other transport parameters set by the Config.
TransportParameters transportparameters.TransportParameters // [UQUIC] SrcConnIDLength int // [UQUIC]
SrcConnIDLength int // [UQUIC] DestConnIDLength int // [UQUIC]
DestConnIDLength int // [UQUIC] InitPacketNumber uint64 // [UQUIC]
InitPacketNumber uint64 // [UQUIC] InitPacketNumberLength PacketNumberLen // [UQUIC]
InitPacketNumberLength protocol.PacketNumberLen // [UQUIC]
} }
type ClientHelloInfo struct { type ClientHelloInfo struct {

View file

@ -132,7 +132,7 @@ func NewUCryptoSetupClient(
cs.tlsConf = tlsConf cs.tlsConf = tlsConf
cs.conn = qtls.UQUICClient(quicConf, chs) cs.conn = qtls.UQUICClient(quicConf, chs)
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient)) // cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient)) // [UQUIC] doesn't require this
return cs return cs
} }

View file

@ -15,7 +15,7 @@ import (
"github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/internal/utils" "github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/quicvarint" "github.com/quic-go/quic-go/quicvarint"
"github.com/quic-go/quic-go/transportparameters" tls "github.com/refraction-networking/utls"
) )
// AdditionalTransportParametersClient are additional transport parameters that will be added // AdditionalTransportParametersClient are additional transport parameters that will be added
@ -91,7 +91,7 @@ type TransportParameters struct {
MaxDatagramFrameSize protocol.ByteCount MaxDatagramFrameSize protocol.ByteCount
// only used internally // only used internally
ClientOverride transportparameters.TransportParameters // [UQUIC] ClientOverride tls.TransportParameters // [UQUIC]
} }
// Unmarshal the transport parameters // Unmarshal the transport parameters
@ -513,41 +513,41 @@ func (p *TransportParameters) String() string {
return fmt.Sprintf(logString, logParams...) return fmt.Sprintf(logString, logParams...)
} }
func (tp *TransportParameters) PopulateFromUQUIC(quicparams transportparameters.TransportParameters) { func (tp *TransportParameters) PopulateFromUQUIC(quicparams tls.TransportParameters) {
for pIdx, param := range quicparams { for pIdx, param := range quicparams {
switch param.ID() { switch param.ID() {
case uint64(maxIdleTimeoutParameterID): case uint64(maxIdleTimeoutParameterID):
tp.MaxIdleTimeout = time.Duration(param.(transportparameters.MaxIdleTimeout)) * time.Millisecond tp.MaxIdleTimeout = time.Duration(param.(tls.MaxIdleTimeout)) * time.Millisecond
case uint64(initialMaxDataParameterID): case uint64(initialMaxDataParameterID):
tp.InitialMaxData = protocol.ByteCount(param.(transportparameters.InitialMaxData)) tp.InitialMaxData = protocol.ByteCount(param.(tls.InitialMaxData))
case uint64(initialMaxStreamDataBidiLocalParameterID): case uint64(initialMaxStreamDataBidiLocalParameterID):
tp.InitialMaxStreamDataBidiLocal = protocol.ByteCount(param.(transportparameters.InitialMaxStreamDataBidiLocal)) tp.InitialMaxStreamDataBidiLocal = protocol.ByteCount(param.(tls.InitialMaxStreamDataBidiLocal))
case uint64(initialMaxStreamDataBidiRemoteParameterID): case uint64(initialMaxStreamDataBidiRemoteParameterID):
tp.InitialMaxStreamDataBidiRemote = protocol.ByteCount(param.(transportparameters.InitialMaxStreamDataBidiRemote)) tp.InitialMaxStreamDataBidiRemote = protocol.ByteCount(param.(tls.InitialMaxStreamDataBidiRemote))
case uint64(initialMaxStreamDataUniParameterID): case uint64(initialMaxStreamDataUniParameterID):
tp.InitialMaxStreamDataUni = protocol.ByteCount(param.(transportparameters.InitialMaxStreamDataUni)) tp.InitialMaxStreamDataUni = protocol.ByteCount(param.(tls.InitialMaxStreamDataUni))
case uint64(initialMaxStreamsBidiParameterID): case uint64(initialMaxStreamsBidiParameterID):
tp.MaxBidiStreamNum = protocol.StreamNum(param.(transportparameters.InitialMaxStreamsBidi)) tp.MaxBidiStreamNum = protocol.StreamNum(param.(tls.InitialMaxStreamsBidi))
case uint64(initialMaxStreamsUniParameterID): case uint64(initialMaxStreamsUniParameterID):
tp.MaxUniStreamNum = protocol.StreamNum(param.(transportparameters.InitialMaxStreamsUni)) tp.MaxUniStreamNum = protocol.StreamNum(param.(tls.InitialMaxStreamsUni))
case uint64(maxAckDelayParameterID): case uint64(maxAckDelayParameterID):
tp.MaxAckDelay = time.Duration(param.(transportparameters.MaxAckDelay)) * time.Millisecond tp.MaxAckDelay = time.Duration(param.(tls.MaxAckDelay)) * time.Millisecond
case uint64(disableActiveMigrationParameterID): case uint64(disableActiveMigrationParameterID):
tp.DisableActiveMigration = true tp.DisableActiveMigration = true
case uint64(activeConnectionIDLimitParameterID): case uint64(activeConnectionIDLimitParameterID):
tp.ActiveConnectionIDLimit = uint64(param.(transportparameters.ActiveConnectionIDLimit)) tp.ActiveConnectionIDLimit = uint64(param.(tls.ActiveConnectionIDLimit))
case uint64(initialSourceConnectionIDParameterID): case uint64(initialSourceConnectionIDParameterID):
srcConnIDOverride, ok := param.(transportparameters.InitialSourceConnectionID) srcConnIDOverride, ok := param.(tls.InitialSourceConnectionID)
if ok { if ok {
if len(srcConnIDOverride) > 0 { // when nil/empty, will leave default srcConnID if len(srcConnIDOverride) > 0 { // when nil/empty, will leave default srcConnID
tp.InitialSourceConnectionID = protocol.ParseConnectionID(srcConnIDOverride) tp.InitialSourceConnectionID = protocol.ParseConnectionID(srcConnIDOverride)
} else { } else {
// reversely populate the transport parameter, for it must be written to network // reversely populate the transport parameter, for it must be written to network
quicparams[pIdx] = transportparameters.InitialSourceConnectionID(tp.InitialSourceConnectionID.Bytes()) quicparams[pIdx] = tls.InitialSourceConnectionID(tp.InitialSourceConnectionID.Bytes())
} }
} }
case uint64(maxDatagramFrameSizeParameterID): case uint64(maxDatagramFrameSizeParameterID):
tp.MaxDatagramFrameSize = protocol.ByteCount(param.(transportparameters.MaxDatagramFrameSize)) tp.MaxDatagramFrameSize = protocol.ByteCount(param.(tls.MaxDatagramFrameSize))
default: default:
// ignore unknown parameters // ignore unknown parameters
continue continue

View file

@ -806,19 +806,27 @@ func (p *packetPacker) appendLongHeaderPacketExternalPadding(buffer *packetBuffe
header.Length = pnLen + protocol.ByteCount(sealer.Overhead()) + pl.length header.Length = pnLen + protocol.ByteCount(sealer.Overhead()) + pl.length
startLen := len(buffer.Data) startLen := len(buffer.Data)
raw := buffer.Data[startLen:] raw := buffer.Data[startLen:] // [UQUIC] raw is a sub-slice of buffer.Data, whose len < size
raw, err := header.Append(raw, v) raw, err := header.Append(raw, v)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Printf("Pre-Payload: %x\n", raw)
payloadOffset := protocol.ByteCount(len(raw)) payloadOffset := protocol.ByteCount(len(raw))
raw, err = p.appendPacketPayload(raw, pl, 0, v) raw, err = p.appendCustomInitialPacketPayload(raw, pl, 0, v)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fmt.Printf("Pre-Encryption: %x\n", raw)
raw = p.encryptPacket(raw, sealer, header.PacketNumber, payloadOffset, pnLen) raw = p.encryptPacket(raw, sealer, header.PacketNumber, payloadOffset, pnLen)
buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)] buffer.Data = buffer.Data[:len(buffer.Data)+len(raw)]
fmt.Printf("Post-Encryption: %x\n", raw)
// [UQUIC] // [UQUIC]
// append zero to buffer.Data until 1200 bytes // append zero to buffer.Data until 1200 bytes
buffer.Data = append(buffer.Data, make([]byte, 1357-len(buffer.Data))...) buffer.Data = append(buffer.Data, make([]byte, 1357-len(buffer.Data))...)
@ -922,6 +930,44 @@ func (p *packetPacker) appendPacketPayload(raw []byte, pl payload, paddingLen pr
return raw, nil return raw, nil
} }
func (p *packetPacker) appendCustomInitialPacketPayload(raw []byte, pl payload, paddingLen protocol.ByteCount, v protocol.VersionNumber) ([]byte, error) {
payloadOffset := len(raw)
// [UQUIC] ignores the default ACK/PADDING frame and uses its own frames
// if pl.ack != nil {
// var err error
// raw, err = pl.ack.Append(raw, v)
// if err != nil {
// return nil, err
// }
// }
// if paddingLen > 0 {
// raw = append(raw, make([]byte, paddingLen)...)
// }
for _, f := range pl.frames {
var err error
raw, err = f.Frame.Append(raw, v)
if err != nil {
return nil, err
}
fmt.Printf("UQUIC: appending frame %v\n", f)
}
for _, f := range pl.streamFrames {
var err error
raw, err = f.Frame.Append(raw, v)
if err != nil {
return nil, err
}
fmt.Printf("UQUIC: appending stream frame %v\n", f)
}
if payloadSize := protocol.ByteCount(len(raw)-payloadOffset) - paddingLen; payloadSize != pl.length {
return nil, fmt.Errorf("PacketPacker BUG: payload size inconsistent (expected %d, got %d bytes)", pl.length, payloadSize)
}
return raw, nil
}
func (p *packetPacker) encryptPacket(raw []byte, sealer sealer, pn protocol.PacketNumber, payloadOffset, pnLen protocol.ByteCount) []byte { func (p *packetPacker) encryptPacket(raw []byte, sealer sealer, pn protocol.PacketNumber, payloadOffset, pnLen protocol.ByteCount) []byte {
_ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], pn, raw[:payloadOffset]) _ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], pn, raw[:payloadOffset])
raw = raw[:len(raw)+sealer.Overhead()] raw = raw[:len(raw)+sealer.Overhead()]

View file

@ -1,303 +0,0 @@
package transportparameters
import (
"crypto/rand"
"encoding/binary"
"math"
"math/big"
"github.com/quic-go/quic-go/quicvarint"
)
const (
// RFC IDs
max_idle_timeout uint64 = 0x1
max_udp_payload_size uint64 = 0x3
initial_max_data uint64 = 0x4
initial_max_stream_data_bidi_local uint64 = 0x5
initial_max_stream_data_bidi_remote uint64 = 0x6
initial_max_stream_data_uni uint64 = 0x7
initial_max_streams_bidi uint64 = 0x8
initial_max_streams_uni uint64 = 0x9
max_ack_delay uint64 = 0xb
disable_active_migration uint64 = 0xc
active_connection_id_limit uint64 = 0xe
initial_source_connection_id uint64 = 0xf
version_information uint64 = 0x11 // RFC 9368
padding uint64 = 0x15
max_datagram_frame_size uint64 = 0x20 // RFC 9221
grease_quic_bit uint64 = 0x2ab2
// Legacy IDs from draft
version_information_legacy uint64 = 0xff73db // draft-ietf-quic-version-negotiation-13 and early
)
type TransportParameters []TransportParameter
func (tps TransportParameters) Marshal() []byte {
var b []byte
for _, tp := range tps {
b = quicvarint.Append(b, tp.ID())
b = quicvarint.Append(b, uint64(len(tp.Value())))
b = append(b, tp.Value()...)
}
return b
}
// TransportParameter represents a QUIC transport parameter.
//
// Caller will write the following to the wire:
//
// var b []byte
// b = quicvarint.Append(b, ID())
// b = quicvarint.Append(b, len(Value()))
// b = append(b, Value())
//
// Therefore Value() should return the exact bytes to be written to the wire AFTER the length field,
// i.e., the bytes MAY be a Variable Length Integer per RFC depending on the type of the transport
// parameter, but MUST NOT including the length field unless the parameter is defined so.
type TransportParameter interface {
ID() uint64
Value() []byte
}
type GREASE struct {
IdOverride uint64 // if set to a valid GREASE ID, use this instead of randomly generated one.
Length uint16 // if len(ValueOverride) == 0, will generate random data of this size.
ValueOverride []byte // if len(ValueOverride) > 0, use this instead of random bytes.
}
const (
GREASE_MAX_MULTIPLIER = (0x3FFFFFFFFFFFFFFF - 27) / 31
)
// IsGREASEID returns true if id is a valid GREASE ID for
// transport parameters.
func (GREASE) IsGREASEID(id uint64) bool {
return (id-27)%31 == 0
}
// GetGREASEID returns a random valid GREASE ID for transport parameters.
func (GREASE) GetGREASEID() uint64 {
max := big.NewInt(GREASE_MAX_MULTIPLIER)
randMultiply, err := rand.Int(rand.Reader, max)
if err != nil {
return 27
}
return 27 + randMultiply.Uint64()*31
}
func (g *GREASE) ID() uint64 {
if !g.IsGREASEID(g.IdOverride) {
g.IdOverride = g.GetGREASEID()
}
return g.IdOverride
}
func (g *GREASE) Value() []byte {
if len(g.ValueOverride) == 0 {
g.ValueOverride = make([]byte, g.Length)
rand.Read(g.ValueOverride)
}
return g.ValueOverride
}
type MaxIdleTimeout uint64 // in milliseconds
func (MaxIdleTimeout) ID() uint64 {
return max_idle_timeout
}
func (m MaxIdleTimeout) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type MaxUDPPayloadSize uint64
func (MaxUDPPayloadSize) ID() uint64 {
return max_udp_payload_size
}
func (m MaxUDPPayloadSize) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type InitialMaxData uint64
func (InitialMaxData) ID() uint64 {
return initial_max_data
}
func (i InitialMaxData) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataBidiLocal uint64
func (InitialMaxStreamDataBidiLocal) ID() uint64 {
return initial_max_stream_data_bidi_local
}
func (i InitialMaxStreamDataBidiLocal) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataBidiRemote uint64
func (InitialMaxStreamDataBidiRemote) ID() uint64 {
return initial_max_stream_data_bidi_remote
}
func (i InitialMaxStreamDataBidiRemote) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamDataUni uint64
func (InitialMaxStreamDataUni) ID() uint64 {
return initial_max_stream_data_uni
}
func (i InitialMaxStreamDataUni) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamsBidi uint64
func (InitialMaxStreamsBidi) ID() uint64 {
return initial_max_streams_bidi
}
func (i InitialMaxStreamsBidi) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type InitialMaxStreamsUni uint64
func (InitialMaxStreamsUni) ID() uint64 {
return initial_max_streams_uni
}
func (i InitialMaxStreamsUni) Value() []byte {
return quicvarint.Append([]byte{}, uint64(i))
}
type MaxAckDelay uint64
func (MaxAckDelay) ID() uint64 {
return max_ack_delay
}
func (m MaxAckDelay) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type DisableActiveMigration struct{}
func (*DisableActiveMigration) ID() uint64 {
return disable_active_migration
}
// Its Value MUST ALWAYS be empty.
func (*DisableActiveMigration) Value() []byte {
return []byte{}
}
type ActiveConnectionIDLimit uint64
func (ActiveConnectionIDLimit) ID() uint64 {
return active_connection_id_limit
}
func (a ActiveConnectionIDLimit) Value() []byte {
return quicvarint.Append([]byte{}, uint64(a))
}
type InitialSourceConnectionID []byte // if empty, will be set to the Connection ID used for the Initial packet.
func (InitialSourceConnectionID) ID() uint64 {
return initial_source_connection_id
}
func (i InitialSourceConnectionID) Value() []byte {
return []byte(i)
}
type VersionInformation struct {
ChoosenVersion uint32
AvailableVersions []uint32 // Also known as "Other Versions" in early drafts.
LegacyID bool // If true, use the legacy-assigned ID (0xff73db) instead of the RFC-assigned one (0x11).
}
const (
VERSION_NEGOTIATION uint32 = 0x00000000 // rfc9000
VERSION_1 uint32 = 0x00000001 // rfc9000
VERSION_2 uint32 = 0x6b3343cf // rfc9369
VERSION_GREASE uint32 = 0x0a0a0a0a // -> 0x?a?a?a?a
)
func (v *VersionInformation) ID() uint64 {
if v.LegacyID {
return version_information_legacy
}
return version_information
}
func (v *VersionInformation) Value() []byte {
var b []byte
b = binary.BigEndian.AppendUint32(b, v.ChoosenVersion)
for _, version := range v.AvailableVersions {
if version != VERSION_GREASE {
b = binary.BigEndian.AppendUint32(b, version)
} else {
b = binary.BigEndian.AppendUint32(b, v.GetGREASEVersion())
}
}
return b
}
func (*VersionInformation) GetGREASEVersion() uint32 {
// get a random uint32
max := big.NewInt(math.MaxUint32)
randVal, err := rand.Int(rand.Reader, max)
if err != nil {
return VERSION_GREASE
}
return uint32(randVal.Uint64()&math.MaxUint32) | 0x0a0a0a0a // all GREASE versions are in 0x?a?a?a?a
}
type Padding []byte
func (Padding) ID() uint64 {
return padding
}
func (p Padding) Value() []byte {
return p
}
type MaxDatagramFrameSize uint64
func (MaxDatagramFrameSize) ID() uint64 {
return max_datagram_frame_size
}
func (m MaxDatagramFrameSize) Value() []byte {
return quicvarint.Append([]byte{}, uint64(m))
}
type GREASEQUICBit struct{}
func (*GREASEQUICBit) ID() uint64 {
return grease_quic_bit
}
// Its Value MUST ALWAYS be empty.
func (*GREASEQUICBit) Value() []byte {
return []byte{}
}

View file

@ -1,71 +0,0 @@
package transportparameters
import (
"bytes"
"testing"
)
func TestMarshal(t *testing.T) {
t.Run("Firefox", testTransportParametersFirefox)
}
func testTransportParametersFirefox(t *testing.T) {
if !bytes.Equal(_inputTransportParametersFirefox.Marshal(), _truthTransportParametersFirefox) {
t.Errorf("TransportParameters.Marshal() = %v, want %v", _inputTransportParametersFirefox.Marshal(), _truthTransportParametersFirefox)
}
}
var (
_inputTransportParametersFirefox = TransportParameters{
InitialMaxStreamDataBidiRemote(0x100000),
InitialMaxStreamsBidi(16),
MaxDatagramFrameSize(1200),
MaxIdleTimeout(30000),
ActiveConnectionIDLimit(8),
&GREASEQUICBit{},
&VersionInformation{
ChoosenVersion: 0x00000001,
AvailableVersions: []uint32{
0x8acafaea,
0x00000001,
},
LegacyID: true,
},
InitialMaxStreamsUni(16),
&GREASE{
IdOverride: 0xff02de1a,
ValueOverride: []byte{
0x43, 0xe8,
},
},
InitialMaxStreamDataBidiLocal(0xc00000),
InitialMaxStreamDataUni(0x100000),
InitialSourceConnectionID([]byte{0x53, 0xf0, 0xb2}),
MaxAckDelay(20),
InitialMaxData(0x1800000),
&DisableActiveMigration{},
}
_truthTransportParametersFirefox = []byte{
0x06, 0x04, 0x80, 0x10,
0x00, 0x00, 0x08, 0x01,
0x10, 0x20, 0x02, 0x44,
0xb0, 0x01, 0x04, 0x80,
0x00, 0x75, 0x30, 0x0e,
0x01, 0x08, 0x6a, 0xb2,
0x00, 0x80, 0xff, 0x73,
0xdb, 0x0c, 0x00, 0x00,
0x00, 0x01, 0x8a, 0xca,
0xfa, 0xea, 0x00, 0x00,
0x00, 0x01, 0x09, 0x01,
0x10, 0xc0, 0x00, 0x00,
0x00, 0xff, 0x02, 0xde,
0x1a, 0x02, 0x43, 0xe8,
0x05, 0x04, 0x80, 0xc0,
0x00, 0x00, 0x07, 0x04,
0x80, 0x10, 0x00, 0x00,
0x0f, 0x03, 0x53, 0xf0,
0xb2, 0x0b, 0x01, 0x14,
0x04, 0x04, 0x81, 0x80,
0x00, 0x00, 0x0c, 0x00,
}
)