Skip to content

Commit

Permalink
Initial draft-22 support
Browse files Browse the repository at this point in the history
  • Loading branch information
mpiraux committed Jul 18, 2019
1 parent 5315996 commit 88a6e8c
Show file tree
Hide file tree
Showing 15 changed files with 76 additions and 66 deletions.
2 changes: 1 addition & 1 deletion agents/base_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (c *ConnectionAgents) StopAll() {

// This function sends an (CONNECTION|APPLICATION)_CLOSE frame and wait for it to be sent out. Then it stops all the
// agents attached to this connection.
func (c *ConnectionAgents) CloseConnection(quicLayer bool, errorCode uint16, reasonPhrase string) {
func (c *ConnectionAgents) CloseConnection(quicLayer bool, errorCode uint64, reasonPhrase string) {
var a Agent
var present bool
if a, present = c.Has("ClosingAgent"); !present {
Expand Down
2 changes: 1 addition & 1 deletion agents/closing_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (a *ClosingAgent) Run(conn *Connection) { // TODO: Observe incoming CC and
}()
}

func (a *ClosingAgent) Close(quicLayer bool, errorCode uint16, reasonPhrase string) {
func (a *ClosingAgent) Close(quicLayer bool, errorCode uint64, reasonPhrase string) {
if !a.closing {
a.closing = true
a.conn.CloseConnection(quicLayer, errorCode, reasonPhrase)
Expand Down
4 changes: 2 additions & 2 deletions agents/stream_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (a *StreamAgent) close(streamId uint64) error {
return errors.New("cannot close server uni stream")
}

func (a *StreamAgent) reset(streamId uint64, appErrorCode uint16) error {
func (a *StreamAgent) reset(streamId uint64, appErrorCode uint64) error {
s := a.conn.Streams.Get(streamId)
if IsClient(streamId) || IsBidi(streamId) {
if s.WriteClosed {
Expand All @@ -102,7 +102,7 @@ func (a *StreamAgent) reset(streamId uint64, appErrorCode uint16) error {
return errors.New("cannot reset server uni stream")
}

func (a *StreamAgent) stopSending(streamId uint64, appErrorCode uint16) error {
func (a *StreamAgent) stopSending(streamId uint64, appErrorCode uint64) error {
if IsServer(streamId) || IsBidi(streamId) {
if _, present := a.conn.Streams.Has(streamId); !present && IsServer(streamId) {
return errors.New("cannot ask to stop sending on non-ready server stream")
Expand Down
3 changes: 2 additions & 1 deletion bin/http/http_get.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ func main() {
address := flag.String("address", "", "The address to connect to")
useIPv6 := flag.Bool("6", false, "Use IPV6")
path := flag.String("path", "/index.html", "The path to request")
alpn := flag.String("alpn", "hq", "The ALPN prefix to use when connecting ot the endpoint.")
netInterface := flag.String("interface", "", "The interface to listen to when capturing pcap")
timeout := flag.Int("timeout", 10, "The number of seconds after which the program will timeout")
h3 := flag.Bool("3", false, "Use HTTP/3 instead of HTTP/0.9")
flag.Parse()

t := time.NewTimer(time.Duration(*timeout) * time.Second)
conn, err := qt.NewDefaultConnection(*address, (*address)[:strings.LastIndex(*address, ":")], nil, *useIPv6, "hq", *h3)
conn, err := qt.NewDefaultConnection(*address, (*address)[:strings.LastIndex(*address, ":")], nil, *useIPv6, *alpn, *h3)
if err != nil {
panic(err)
}
Expand Down
15 changes: 6 additions & 9 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ import (
)

// TODO: Reconsider the use of global variables
var QuicVersion uint32 = 0xff000014 // See https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-4
var QuicALPNToken = "hq-20" // See https://www.ietf.org/mail-archive/web/quic/current/msg01882.html
var QuicH3ALPNToken = "h3-20" // See https://tools.ietf.org/html/draft-ietf-quic-http-17#section-2.1
var QuicVersion uint32 = 0xff000016 // See https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-4
var QuicALPNToken = "hq-22" // See https://www.ietf.org/mail-archive/web/quic/current/msg01882.html
var QuicH3ALPNToken = "h3-22" // See https://tools.ietf.org/html/draft-ietf-quic-http-17#section-2.1

const (
MinimumInitialLength = 1252
MinimumInitialLengthv6 = 1232
MaxUDPPayloadSize = 65507
MaximumVersion = 0xff000014
MinimumVersion = 0xff000013
MaximumVersion = 0xff000016
MinimumVersion = 0xff000016
)

// errors
Expand Down Expand Up @@ -204,10 +204,7 @@ func (a PacketNumberQueue) Len() int { return len(a) }
type ConnectionID []byte

func (c ConnectionID) CIDL() uint8 {
if len(c) == 0 {
return 0
}
return uint8(len(c) - 3)
return uint8(len(c))
}

func min(a, b uint64) uint64 {
Expand Down
2 changes: 1 addition & 1 deletion connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func (c *Connection) TransitionTo(version uint32, ALPN string) {
c.CryptoStates[EncryptionLevelInitial] = NewInitialPacketProtection(c)
c.Streams = Streams{streams: make(map[uint64]*Stream), lock: &sync.Mutex{}, input: &c.StreamInput}
}
func (c *Connection) CloseConnection(quicLayer bool, errCode uint16, reasonPhrase string) {
func (c *Connection) CloseConnection(quicLayer bool, errCode uint64, reasonPhrase string) {
if quicLayer {
c.FrameQueue.Submit(QueuedFrame{&ConnectionCloseFrame{errCode,0, uint64(len(reasonPhrase)), reasonPhrase}, EncryptionLevelBest})
} else {
Expand Down
8 changes: 4 additions & 4 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"github.com/mpiraux/pigotls"
)

var quicVersionSalt = []byte{ // See https://tools.ietf.org/html/draft-ietf-quic-tls-17#section-5.2
0xef, 0x4f, 0xb0, 0xab, 0xb4, 0x74, 0x70, 0xc4,
0x1b, 0xef, 0xcf, 0x80, 0x31, 0x33, 0x4f, 0xae,
0x48, 0x5e, 0x09, 0xa0,
var quicVersionSalt = []byte{ // See https://tools.ietf.org/html/draft-ietf-quic-tls-22#section-5.2
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9,
0x19, 0x3a, 0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd,
0x7a, 0x02, 0x64, 0x4a,
}

const (
Expand Down
33 changes: 18 additions & 15 deletions frames.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,41 +233,41 @@ func ReadAckECNFrame(buffer *bytes.Reader, conn *Connection) *AckECNFrame {

type ResetStream struct {
StreamId uint64
ApplicationErrorCode uint16
ApplicationErrorCode uint64
FinalSize uint64
}

func (frame ResetStream) FrameType() FrameType { return ResetStreamType }
func (frame ResetStream) WriteTo(buffer *bytes.Buffer) {
WriteVarInt(buffer, uint64(frame.FrameType()))
WriteVarInt(buffer, frame.StreamId)
binary.Write(buffer, binary.BigEndian, frame.ApplicationErrorCode)
WriteVarInt(buffer, frame.ApplicationErrorCode)
WriteVarInt(buffer, frame.FinalSize)
}
func (frame ResetStream) shouldBeRetransmitted() bool { return true }
func (frame ResetStream) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.StreamId)+2+VarIntLen(frame.FinalSize)) }
func (frame ResetStream) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.StreamId)+VarIntLen(frame.ApplicationErrorCode)+VarIntLen(frame.FinalSize)) }
func NewResetStream(buffer *bytes.Reader) *ResetStream {
frame := new(ResetStream)
buffer.ReadByte() // Discard frame type
frame.StreamId, _, _ = ReadVarIntValue(buffer)
binary.Read(buffer, binary.BigEndian, &frame.ApplicationErrorCode)
frame.ApplicationErrorCode, _, _ = ReadVarIntValue(buffer)
frame.FinalSize, _, _ = ReadVarIntValue(buffer)
return frame
}

type StopSendingFrame struct {
StreamId uint64
ApplicationErrorCode uint16
ApplicationErrorCode uint64
}

func (frame StopSendingFrame) FrameType() FrameType { return StopSendingType }
func (frame StopSendingFrame) WriteTo(buffer *bytes.Buffer) {
WriteVarInt(buffer, uint64(frame.FrameType()))
WriteVarInt(buffer, frame.StreamId)
binary.Write(buffer, binary.BigEndian, frame.ApplicationErrorCode)
WriteVarInt(buffer, frame.ApplicationErrorCode)
}
func (frame StopSendingFrame) shouldBeRetransmitted() bool { return true }
func (frame StopSendingFrame) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.StreamId)) + 2 }
func (frame StopSendingFrame) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.StreamId) + VarIntLen(frame.ApplicationErrorCode)) }
func NewStopSendingFrame(buffer *bytes.Reader) *StopSendingFrame {
frame := new(StopSendingFrame)
buffer.ReadByte() // Discard frame type
Expand Down Expand Up @@ -542,6 +542,7 @@ func NewStreamIdNeededFrame(buffer *bytes.Reader) *StreamsBlockedFrame {

type NewConnectionIdFrame struct {
Sequence uint64
RetirePriorTo uint64
Length uint8
ConnectionId []byte
StatelessResetToken [16]byte
Expand All @@ -551,16 +552,18 @@ func (frame NewConnectionIdFrame) FrameType() FrameType { return NewConnectionId
func (frame NewConnectionIdFrame) WriteTo(buffer *bytes.Buffer) {
WriteVarInt(buffer, uint64(frame.FrameType()))
WriteVarInt(buffer, frame.Sequence)
WriteVarInt(buffer, frame.RetirePriorTo)
buffer.WriteByte(frame.Length)
buffer.Write(frame.ConnectionId)
binary.Write(buffer, binary.BigEndian, frame.StatelessResetToken)
}
func (frame NewConnectionIdFrame) shouldBeRetransmitted() bool { return true }
func (frame NewConnectionIdFrame) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.Sequence)) + 1 + uint16(len(frame.ConnectionId)) + 16 }
func (frame NewConnectionIdFrame) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.Sequence) + VarIntLen(frame.RetirePriorTo)) + 1 + uint16(len(frame.ConnectionId)) + 16 }
func NewNewConnectionIdFrame(buffer *bytes.Reader) *NewConnectionIdFrame {
frame := new(NewConnectionIdFrame)
buffer.ReadByte() // Discard frame type
frame.Sequence, _, _ = ReadVarIntValue(buffer)
frame.RetirePriorTo, _, _ = ReadVarIntValue(buffer)
frame.Length, _ = buffer.ReadByte()
frame.ConnectionId = make([]byte, frame.Length, frame.Length)
buffer.Read(frame.ConnectionId)
Expand Down Expand Up @@ -628,7 +631,7 @@ func NewPathResponse(data [8]byte) *PathResponse {
}

type ConnectionCloseFrame struct {
ErrorCode uint16
ErrorCode uint64
ErrorFrameType uint64
ReasonPhraseLength uint64
ReasonPhrase string
Expand All @@ -637,19 +640,19 @@ type ConnectionCloseFrame struct {
func (frame ConnectionCloseFrame) FrameType() FrameType { return ConnectionCloseType }
func (frame ConnectionCloseFrame) WriteTo(buffer *bytes.Buffer) {
WriteVarInt(buffer, uint64(frame.FrameType()))
binary.Write(buffer, binary.BigEndian, frame.ErrorCode)
WriteVarInt(buffer, frame.ErrorCode)
WriteVarInt(buffer, frame.ErrorFrameType)
WriteVarInt(buffer, frame.ReasonPhraseLength)
if frame.ReasonPhraseLength > 0 {
buffer.Write([]byte(frame.ReasonPhrase))
}
}
func (frame ConnectionCloseFrame) shouldBeRetransmitted() bool { return false }
func (frame ConnectionCloseFrame) FrameLength() uint16 { return 1 + 2 + uint16(VarIntLen(frame.ErrorFrameType)+VarIntLen(frame.ReasonPhraseLength)) + uint16(frame.ReasonPhraseLength) }
func (frame ConnectionCloseFrame) FrameLength() uint16 { return 1 + uint16(VarIntLen(frame.ErrorCode)+VarIntLen(frame.ErrorFrameType)+VarIntLen(frame.ReasonPhraseLength)) + uint16(frame.ReasonPhraseLength) }
func NewConnectionCloseFrame(buffer *bytes.Reader) *ConnectionCloseFrame {
frame := new(ConnectionCloseFrame)
buffer.ReadByte() // Discard frame type
binary.Read(buffer, binary.BigEndian, &frame.ErrorCode)
frame.ErrorCode, _, _ = ReadVarIntValue(buffer)
frame.ErrorFrameType, _, _ = ReadVarIntValue(buffer)
frame.ReasonPhraseLength, _, _ = ReadVarIntValue(buffer)
if frame.ReasonPhraseLength > 0 {
Expand All @@ -662,15 +665,15 @@ func NewConnectionCloseFrame(buffer *bytes.Reader) *ConnectionCloseFrame {

type ApplicationCloseFrame struct {
// TODO: Merge it with 0x1c
errorCode uint16
errorCode uint64
reasonPhraseLength uint64
reasonPhrase string
}

func (frame ApplicationCloseFrame) FrameType() FrameType { return ApplicationCloseType }
func (frame ApplicationCloseFrame) WriteTo(buffer *bytes.Buffer) {
WriteVarInt(buffer, uint64(frame.FrameType()))
binary.Write(buffer, binary.BigEndian, frame.errorCode)
WriteVarInt(buffer, frame.errorCode)
WriteVarInt(buffer, frame.reasonPhraseLength)
if frame.reasonPhraseLength > 0 {
buffer.Write([]byte(frame.reasonPhrase))
Expand All @@ -681,7 +684,7 @@ func (frame ApplicationCloseFrame) FrameLength() uint16 { return 1 + 2 +
func NewApplicationCloseFrame(buffer *bytes.Reader) *ApplicationCloseFrame {
frame := new(ApplicationCloseFrame)
buffer.ReadByte() // Discard frame type
binary.Read(buffer, binary.BigEndian, &frame.errorCode)
frame.errorCode, _, _ = ReadVarIntValue(buffer)
frame.reasonPhraseLength, _, _ = ReadVarIntValue(buffer)
if frame.reasonPhraseLength > 0 {
reasonBytes := make([]byte, frame.reasonPhraseLength, frame.reasonPhraseLength)
Expand Down
16 changes: 5 additions & 11 deletions headers.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ func (h *LongHeader) Encode() []byte {
typeByte |= uint8(h.truncatedPN.Length) - 1
binary.Write(buffer, binary.BigEndian, typeByte)
binary.Write(buffer, binary.BigEndian, h.Version)
buffer.WriteByte((h.DestinationCID.CIDL() << 4) | h.SourceCID.CIDL())
buffer.WriteByte(h.DestinationCID.CIDL())
binary.Write(buffer, binary.BigEndian, h.DestinationCID)
buffer.WriteByte(h.SourceCID.CIDL())
binary.Write(buffer, binary.BigEndian, h.SourceCID)
if h.packetType == Initial {
buffer.Write(h.TokenLength.Encode())
Expand All @@ -93,7 +94,7 @@ func (h *LongHeader) PacketNumber() PacketNumber { return h.packetNumber }
func (h *LongHeader) TruncatedPN() TruncatedPN { return h.truncatedPN }
func (h *LongHeader) EncryptionLevel() EncryptionLevel { return packetTypeToEncryptionLevel[h.PacketType()] }
func (h *LongHeader) HeaderLength() int {
length := 6 + len(h.DestinationCID) + len(h.SourceCID) + h.Length.Length + h.truncatedPN.Length
length := 7 + len(h.DestinationCID) + len(h.SourceCID) + h.Length.Length + h.truncatedPN.Length
if h.packetType == Initial {
length += h.TokenLength.Length + len(h.Token)
}
Expand All @@ -105,17 +106,10 @@ func ReadLongHeader(buffer *bytes.Reader, conn *Connection) *LongHeader {
h.lowerBits = typeByte & 0x0F
h.packetType = PacketType(typeByte - 0xC0) >> 4
binary.Read(buffer, binary.BigEndian, &h.Version)
CIDL, _ := buffer.ReadByte()
DCIL := 3 + ((CIDL & 0xf0) >> 4)
if DCIL == 3 {
DCIL = 0
}
SCIL := 3 + (CIDL & 0xf)
if SCIL == 3 {
SCIL = 0
}
DCIL, _ := buffer.ReadByte()
h.DestinationCID = make([]byte, DCIL, DCIL)
binary.Read(buffer, binary.BigEndian, &h.DestinationCID)
SCIL, _ := buffer.ReadByte()
h.SourceCID = make([]byte, SCIL, SCIL)
binary.Read(buffer, binary.BigEndian, &h.SourceCID)
if h.packetType == Initial {
Expand Down
16 changes: 3 additions & 13 deletions packets.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,10 @@ func ReadVersionNegotationPacket(buffer *bytes.Reader) *VersionNegotiationPacket
}
p.UnusedField = b & 0x7f
binary.Read(buffer, binary.BigEndian, &p.Version)
CIDL, _ := buffer.ReadByte()
DCIL := 3 + ((CIDL & 0xf0) >> 4)
if DCIL == 3 {
DCIL = 0
}
SCIL := 3 + (CIDL & 0xf)
if SCIL == 3 {
SCIL = 0
}
DCIL, _ := buffer.ReadByte()
p.DestinationCID = make([]byte, DCIL, DCIL)
binary.Read(buffer, binary.BigEndian, &p.DestinationCID)
SCIL, _ := buffer.ReadByte()
p.SourceCID = make([]byte, SCIL, SCIL)
binary.Read(buffer, binary.BigEndian, &p.SourceCID)
for {
Expand Down Expand Up @@ -258,10 +251,7 @@ func ReadRetryPacket(buffer *bytes.Reader, conn *Connection) *RetryPacket {
p := new(RetryPacket)
h := ReadLongHeader(buffer, conn) // TODO: This should not be a full-length long header. Retry header ?
p.header = h
OCIDL := h.lowerBits & 0x0f
if OCIDL > 0 {
OCIDL += 3
}
OCIDL, _ := buffer.ReadByte()
p.OriginalDestinationCID = make([]byte, OCIDL)
buffer.Read(p.OriginalDestinationCID)
p.RetryToken = make([]byte, buffer.Len())
Expand Down
1 change: 1 addition & 0 deletions scenarii/connection_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func NewConnectionMigrationScenario() *ConnectionMigrationScenario {
return &ConnectionMigrationScenario{AbstractScenario{name: "connection_migration", version: 1}}
}
func (s *ConnectionMigrationScenario) Run(conn *qt.Connection, trace *qt.Trace, preferredPath string, debug bool) {
conn.TLSTPHandler.ActiveConnectionIdLimit = 0
connAgents := s.CompleteHandshake(conn, trace, CM_TLSHandshakeFailed)
if connAgents == nil {
return
Expand Down
14 changes: 13 additions & 1 deletion scenarii/connection_migration_v4_v6.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const (
CM46_HostDidNotValidateNewPath = 4
CM46_NoNewCIDReceived = 5
CM46_NoNewCIDUsed = 6
CM46_MigrationIsDisabled = 7
CM46_NoCIDAllowed = 8
)


Expand All @@ -34,11 +36,21 @@ func (s *ConnectionMigrationv4v6Scenario) Run(conn *qt.Connection, trace *qt.Tra
}
defer connAgents.CloseConnection(false, 0, "")

if conn.TLSTPHandler.ReceivedParameters.DisableMigration {
trace.ErrorCode = CM46_MigrationIsDisabled
return
}

if conn.TLSTPHandler.ReceivedParameters.ActiveConnectionIdLimit == 0 {
trace.ErrorCode = CM46_NoCIDAllowed
return
}

scid := make([]byte, 8)
var resetToken [16]byte
rand.Read(scid)
rand.Read(resetToken[:])
conn.FrameQueue.Submit(qt.QueuedFrame{&qt.NewConnectionIdFrame{ 1, uint8(len(scid)), scid, resetToken}, qt.EncryptionLevelBest})
conn.FrameQueue.Submit(qt.QueuedFrame{&qt.NewConnectionIdFrame{1, 0, uint8(len(scid)), scid, resetToken}, qt.EncryptionLevelBest})
firstFlightTimer := time.NewTimer(3 * time.Second)

var ncid qt.ConnectionID
Expand Down
8 changes: 7 additions & 1 deletion scenarii/new_connection_id.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
NCI_HostDidNotAnswerToNewCID = 3
NCI_HostDidNotAdaptCID = 4
NCI_HostSentInvalidCIDLength = 5
NCI_NoCIDAllowed = 6
)

type NewConnectionIDScenario struct {
Expand All @@ -33,6 +34,11 @@ func (s *NewConnectionIDScenario) Run(conn *qt.Connection, trace *qt.Trace, pref
}
defer connAgents.CloseConnection(false, 0, "")

if conn.TLSTPHandler.ReceivedParameters.ActiveConnectionIdLimit == 0 {
trace.ErrorCode = NCI_NoCIDAllowed
return
}

trace.ErrorCode = NCI_HostDidNotProvideCID

var expectingResponse bool
Expand Down Expand Up @@ -73,7 +79,7 @@ func (s *NewConnectionIDScenario) Run(conn *qt.Connection, trace *qt.Trace, pref
trace.ErrorCode = NCI_HostDidNotAnswerToNewCID // Assume it did not answer until proven otherwise
conn.DestinationCID = nci.ConnectionId
conn.SourceCID = scid
conn.FrameQueue.Submit(qt.QueuedFrame{&qt.NewConnectionIdFrame{ 1, uint8(len(scid)), scid, resetToken}, qt.EncryptionLevelBest})
conn.FrameQueue.Submit(qt.QueuedFrame{&qt.NewConnectionIdFrame{1, 0, uint8(len(scid)), scid, resetToken}, qt.EncryptionLevelBest})
conn.SendHTTP09GETRequest(preferredPath, 0)
expectingResponse = true
}
Expand Down
Loading

0 comments on commit 88a6e8c

Please sign in to comment.