Skip to content

Commit

Permalink
draft-17 support
Browse files Browse the repository at this point in the history
  • Loading branch information
mpiraux committed Jan 14, 2019
1 parent a39db78 commit 911d820
Show file tree
Hide file tree
Showing 29 changed files with 714 additions and 663 deletions.
2 changes: 1 addition & 1 deletion agents/ack_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type AckAgent struct {
}

func (a *AckAgent) Run(conn *Connection) {
a.Init("AckAgent", conn.SourceCID)
a.Init("AckAgent", conn.OriginalDestinationCID)
a.DisableAcks = make(map[PNSpace]bool)
a.TotalDataAcked = make(map[PNSpace]uint64)

Expand Down
4 changes: 2 additions & 2 deletions agents/base_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ type BaseAgent struct {
func (a *BaseAgent) Name() string { return a.name }

// All agents that embed this structure must call Init() as soon as their Run() method is called
func (a *BaseAgent) Init(name string, SCID ConnectionID) {
func (a *BaseAgent) Init(name string, ODCID ConnectionID) {
a.name = name
a.Logger = log.New(os.Stdout, fmt.Sprintf("[%s/%s] ", hex.EncodeToString(SCID), a.Name()), log.Lshortfile)
a.Logger = log.New(os.Stdout, fmt.Sprintf("[%s/%s] ", hex.EncodeToString(ODCID), a.Name()), log.Lshortfile)
a.Logger.Println("Agent started")
a.close = make(chan bool)
a.closed = make(chan bool)
Expand Down
2 changes: 1 addition & 1 deletion agents/buffer_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type BufferAgent struct {
}

func (a *BufferAgent) Run(conn *Connection) {
a.Init("BufferAgent", conn.SourceCID)
a.Init("BufferAgent", conn.OriginalDestinationCID)

uPChan := make(chan interface{}, 1000)
conn.UnprocessedPayloads.Register(uPChan)
Expand Down
2 changes: 1 addition & 1 deletion agents/closing_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ClosingAgent struct {
}

func (a *ClosingAgent) Run (conn *Connection) {
a.Init("ClosingAgent", conn.SourceCID)
a.Init("ClosingAgent", conn.OriginalDestinationCID)

outgoingPackets := make(chan interface{}, 1000)
conn.OutgoingPackets.Register(outgoingPackets)
Expand Down
16 changes: 9 additions & 7 deletions agents/handshake_agent.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package agents

import (
. "github.com/QUIC-Tracker/quic-tracker"
"github.com/dustin/go-broadcast"
"fmt"
"bytes"
"encoding/hex"
"errors"
"fmt"
. "github.com/QUIC-Tracker/quic-tracker"
"github.com/dustin/go-broadcast"
"strings"
"bytes"
)

type HandshakeStatus struct {
Expand All @@ -29,10 +29,11 @@ type HandshakeAgent struct {
SocketAgent *SocketAgent
HandshakeStatus broadcast.Broadcaster //type: HandshakeStatus
sendInitial chan bool
receivedRetry bool
}

func (a *HandshakeAgent) Run(conn *Connection) {
a.Init("HandshakeAgent", conn.SourceCID)
a.Init("HandshakeAgent", conn.OriginalDestinationCID)
a.HandshakeStatus = broadcast.NewBroadcaster(10)
a.sendInitial = make(chan bool, 1)

Expand Down Expand Up @@ -62,15 +63,16 @@ func (a *HandshakeAgent) Run(conn *Connection) {
conn.SendPacket(conn.GetInitialPacket(), EncryptionLevelInitial)
case p := <-incPackets:
switch p := p.(type) {
case *VersionNegotationPacket:
case *VersionNegotiationPacket:
err := conn.ProcessVersionNegotation(p)
if err != nil {
a.HandshakeStatus.Submit(HandshakeStatus{false, p, err})
return
}
conn.SendPacket(conn.GetInitialPacket(), EncryptionLevelInitial)
case *RetryPacket:
if bytes.Equal(conn.DestinationCID, p.OriginalDestinationCID) { // TODO: Check the original_connection_id TP too
if bytes.Equal(conn.DestinationCID, p.OriginalDestinationCID) && !a.receivedRetry { // TODO: Check the original_connection_id TP too
a.receivedRetry = true
conn.DestinationCID = p.Header().(*LongHeader).SourceCID
conn.TransitionTo(QuicVersion, QuicALPNToken)
conn.Token = p.RetryToken
Expand Down
2 changes: 1 addition & 1 deletion agents/http_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const (
)

func (a *HTTPAgent) Run(conn *Connection) {
a.Init("HTTPAgent", conn.SourceCID)
a.Init("HTTPAgent", conn.OriginalDestinationCID)
a.conn = conn
a.QPACK = QPACKAgent{EncoderStreamID: 6, DecoderStreamID: 10}
a.QPACK.Run(conn)
Expand Down
25 changes: 17 additions & 8 deletions agents/parse_agent.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package agents

import (
"bytes"
. "github.com/QUIC-Tracker/quic-tracker"
"unsafe"
"bytes"
)

// The ParsingAgent is responsible for decrypting and parsing the payloads received in UDP datagrams. It also decrypts
Expand All @@ -16,7 +16,7 @@ type ParsingAgent struct {

func (a *ParsingAgent) Run(conn *Connection) {
a.conn = conn
a.Init("ParsingAgent", conn.SourceCID)
a.Init("ParsingAgent", conn.OriginalDestinationCID)

incomingPayloads := make(chan interface{})
a.conn.IncomingPayloads.Register(incomingPayloads)
Expand All @@ -34,7 +34,6 @@ func (a *ParsingAgent) Run(conn *Connection) {
ciphertext := udpPayload[off:]
header := ReadHeader(bytes.NewReader(ciphertext), a.conn)
cryptoState := a.conn.CryptoStates[header.EncryptionLevel()]
var pnLength int

if lh, ok := header.(*LongHeader); ok && lh.Version == 0x00000000 {
packet := ReadVersionNegotationPacket(bytes.NewReader(ciphertext))
Expand All @@ -47,13 +46,23 @@ func (a *ParsingAgent) Run(conn *Connection) {

switch header.PacketType() {
case Initial, Handshake, ZeroRTTProtected, ShortHeaderPacket: // Decrypt PN
if cryptoState != nil && cryptoState.PacketRead != nil && cryptoState.Read != nil {
if cryptoState != nil && cryptoState.HeaderRead != nil && cryptoState.Read != nil {
a.Logger.Printf("Decrypting packet number of %s packet of length %d bytes", header.PacketType().String(), len(ciphertext))

firstByteMask := byte(0x1F)
if ciphertext[0] & 0x80 == 0x80 {
firstByteMask = 0x0F
}

sample, pnOffset := GetPacketSample(header, ciphertext)
pn := cryptoState.PacketRead.Encrypt(sample, ciphertext[pnOffset:pnOffset+4])
pnLength = ReadTruncatedPN(bytes.NewReader(pn)).Length
copy(ciphertext[pnOffset:pnOffset+4], pn[:pnLength])
mask := cryptoState.HeaderRead.Encrypt(sample, make([]byte, 5, 5))
ciphertext[0] ^= mask[0] & firstByteMask

pnLength := int(ciphertext[0] & 0x3) + 1

for i := 0; i < pnLength; i++ {
ciphertext[pnOffset+i] ^= mask[1+i]
}
header = ReadHeader(bytes.NewReader(ciphertext), a.conn) // Update PN
} else {
a.Logger.Printf("Packet number of %s packet of length %d bytes could not be decrypted, putting it back in waiting buffer\n", header.PacketType().String(), len(ciphertext))
Expand All @@ -70,7 +79,7 @@ func (a *ParsingAgent) Run(conn *Connection) {
switch header.PacketType() {
case Handshake, Initial:
lHeader := header.(*LongHeader)
pLen := int(lHeader.Length.Value) - pnLength
pLen := int(lHeader.Length.Value) - header.TruncatedPN().Length

if hLen+pLen > len(ciphertext) {
a.Logger.Printf("Payload length %d is past the %d received bytes, has PN decryption failed ? Aborting", hLen+pLen, len(ciphertext))
Expand Down
2 changes: 1 addition & 1 deletion agents/qpack_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const (
)

func (a *QPACKAgent) Run(conn *Connection) {
a.Init("QPACKAgent", conn.SourceCID)
a.Init("QPACKAgent", conn.OriginalDestinationCID)
a.DecodedHeaders = broadcast.NewBroadcaster(1000)
a.EncodedHeaders = broadcast.NewBroadcaster(1000)
a.DecodeHeaders = make(chan EncodedHeaders, 1000)
Expand Down
4 changes: 2 additions & 2 deletions agents/recovery_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type RecoveryAgent struct {
}

func (a *RecoveryAgent) Run(conn *Connection) {
a.Init("RecoveryAgent", conn.SourceCID)
a.Init("RecoveryAgent", conn.OriginalDestinationCID)
a.conn = conn

a.retransmissionBuffer = map[PNSpace]map[PacketNumber]RetransmittableFrames{
Expand Down Expand Up @@ -76,7 +76,7 @@ func (a *RecoveryAgent) Run(conn *Connection) {
case *RetryPacket:
a.Logger.Println("Received a Retry packet, emptying Initial retransmit buffer")
a.retransmissionBuffer[PNSpaceInitial] = make(map[PacketNumber]RetransmittableFrames)
case *VersionNegotationPacket:
case *VersionNegotiationPacket:
a.Logger.Println("Received a VN packet, emptying Initial retransmit buffer")
a.retransmissionBuffer[PNSpaceInitial] = make(map[PacketNumber]RetransmittableFrames)
}
Expand Down
4 changes: 2 additions & 2 deletions agents/rtt_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type SentPacket struct {
}

func (a *RTTAgent) Run(conn *Connection) {
a.Init("RTTAgent", conn.SourceCID)
a.Init("RTTAgent", conn.OriginalDestinationCID)
a.MinRTT = math.MaxUint64

a.SentPackets = map[PNSpace]map[PacketNumber]SentPacket{
Expand Down Expand Up @@ -63,7 +63,7 @@ func (a *RTTAgent) Run(conn *Connection) {
ack := f.(*AckFrame)

if sp, ok := a.SentPackets[p.PNSpace()][ack.LargestAcknowledged]; ok {
var ackDelayExponent uint8
var ackDelayExponent uint64
if conn.TLSTPHandler.ReceivedParameters != nil {
ackDelayExponent = conn.TLSTPHandler.ReceivedParameters.AckDelayExponent
}
Expand Down
2 changes: 1 addition & 1 deletion agents/send_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SendingAgent struct {
}

func (a *SendingAgent) Run(conn *Connection) {
a.Init("SendingAgent", conn.SourceCID)
a.Init("SendingAgent", conn.OriginalDestinationCID)

frameQueue := make(chan interface{}, 1000)
conn.FrameQueue.Register(frameQueue)
Expand Down
2 changes: 1 addition & 1 deletion agents/socket_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type SocketAgent struct {
}

func (a *SocketAgent) Run(conn *Connection) {
a.Init("SocketAgent", conn.SourceCID)
a.Init("SocketAgent", conn.OriginalDestinationCID)
a.conn = conn
a.SocketStatus = broadcast.NewBroadcaster(10)
a.ECNStatus = broadcast.NewBroadcaster(1000)
Expand Down
8 changes: 4 additions & 4 deletions agents/tls_agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type TLSAgent struct {
}

func (a *TLSAgent) Run(conn *Connection) {
a.Init("TLSAgent", conn.SourceCID)
a.Init("TLSAgent", conn.OriginalDestinationCID)
a.TLSStatus = broadcast.NewBroadcaster(10)
a.ResumptionTicket = broadcast.NewBroadcaster(10)

Expand Down Expand Up @@ -86,11 +86,11 @@ func (a *TLSAgent) Run(conn *Connection) {
}

if conn.CryptoStates[EncryptionLevelHandshake] != nil {
if conn.CryptoStates[EncryptionLevelHandshake].PacketRead == nil && len(conn.Tls.HandshakeReadSecret()) > 0 {
if conn.CryptoStates[EncryptionLevelHandshake].HeaderRead == nil && len(conn.Tls.HandshakeReadSecret()) > 0 {
a.Logger.Printf("Installing handshake read crypto with secret %s\n", hex.EncodeToString(conn.Tls.HandshakeReadSecret()))
conn.CryptoStates[EncryptionLevelHandshake].InitRead(conn.Tls, conn.Tls.HandshakeReadSecret())
}
if conn.CryptoStates[EncryptionLevelHandshake].PacketWrite == nil && len(conn.Tls.HandshakeWriteSecret()) > 0 {
if conn.CryptoStates[EncryptionLevelHandshake].HeaderWrite == nil && len(conn.Tls.HandshakeWriteSecret()) > 0 {
a.Logger.Printf("Installing handshake write crypto with secret %s\n", hex.EncodeToString(conn.Tls.HandshakeWriteSecret()))
conn.CryptoStates[EncryptionLevelHandshake].InitWrite(conn.Tls, conn.Tls.HandshakeWriteSecret())
}
Expand All @@ -117,7 +117,7 @@ func (a *TLSAgent) Run(conn *Connection) {
}

for _, e := range encryptionLevels {
if !encryptionLevelsAvailable[e] && conn.CryptoStates[e.EncryptionLevel] != nil && ((e.Read && conn.CryptoStates[e.EncryptionLevel].PacketRead != nil) || (!e.Read && conn.CryptoStates[e.EncryptionLevel].PacketWrite != nil)) {
if !encryptionLevelsAvailable[e] && conn.CryptoStates[e.EncryptionLevel] != nil && ((e.Read && conn.CryptoStates[e.EncryptionLevel].HeaderRead != nil) || (!e.Read && conn.CryptoStates[e.EncryptionLevel].HeaderWrite != nil)) {
encryptionLevelsAvailable[e] = true
conn.EncryptionLevelsAvailable.Submit(e)
}
Expand Down
73 changes: 28 additions & 45 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@
package quictracker

import (
"bytes"
"encoding/binary"
"github.com/mpiraux/pigotls"
. "github.com/QUIC-Tracker/quic-tracker/lib"
_ "github.com/mpiraux/ls-qpack-go"
"github.com/mpiraux/pigotls"
"math"
"bytes"
. "github.com/QUIC-Tracker/quic-tracker/lib"
)

var QuicVersion uint32 = 0xff00000f // See https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-4
var QuicALPNToken = "hq-15" // See https://www.ietf.org/mail-archive/web/quic/current/msg01882.html
var QuicVersion uint32 = 0xff000011 // See https://tools.ietf.org/html/draft-ietf-quic-transport-08#section-4
var QuicALPNToken = "hq-17" // See https://www.ietf.org/mail-archive/web/quic/current/msg01882.html

const (
MinimumInitialLength = 1252
MinimumInitialLengthv6 = 1232
MaxUDPPayloadSize = 65507
MaximumVersion = 0xff000010
MinimumVersion = 0xff00000f
MaximumVersion = 0xff000011
MinimumVersion = 0xff000011
)

// errors
Expand All @@ -69,44 +69,24 @@ func (p PacketNumber) Truncate(largestAcknowledged PacketNumber) TruncatedPN {
panic("PNs should be truncated with a lower PN")
}
length := (int(math.Log2(float64(p - largestAcknowledged + 1))) / 8) + 1 // See: https://tools.ietf.org/html/draft-ietf-quic-transport-13#section-4.8
switch length {
case 1:
mask := uint32(0x7f)
return TruncatedPN{uint32(p) & mask, 1}
case 2:
mask := uint32(0x3fff)
return TruncatedPN{(uint32(p) & mask) | 0x8000, 1}
case 3, 4:
mask := uint32(0x3fffffff)
return TruncatedPN{(uint32(p) & mask) | 0xc0000000, 4}
default:
if length > 4 {
println("couldn't truncate", p, "with", largestAcknowledged)
panic(length)
}
return TruncatedPN{uint32(p) & (0xFFFFFFFF >> (8 * (4 - uint(length)))), length}
}

type TruncatedPN struct {
Value uint32
Length int
}

func ReadTruncatedPN(buffer *bytes.Reader) TruncatedPN {
firstByte, _ := buffer.ReadByte()
if firstByte & 0x80 == 0 {
return TruncatedPN{uint32(firstByte), 1}
} else if firstByte & 0xc0 == 0x80 {
twoBytes := make([]byte, 2)
buffer.UnreadByte()
buffer.Read(twoBytes)
return TruncatedPN{uint32(0x3fff & binary.BigEndian.Uint16(twoBytes)), 2}
} else if firstByte & 0xc0 == 0xc0 {
fourBytes := make([]byte, 4)
buffer.UnreadByte()
buffer.Read(fourBytes)
return TruncatedPN{uint32(0x3fffffff & binary.BigEndian.Uint32(fourBytes)), 4}
} else {
panic("Could not decode truncated packet number")
}
func ReadTruncatedPN(buffer *bytes.Reader, length int) TruncatedPN {
pn := TruncatedPN{Length: length}
value := make([]byte, 4, 4)
buffer.Read(value[4-length:])
pn.Value = binary.BigEndian.Uint32(value)
return pn
}

func (t TruncatedPN) Encode() []byte {
Expand All @@ -116,23 +96,20 @@ func (t TruncatedPN) Encode() []byte {
buffer.WriteByte(byte(t.Value))
case 2:
buffer.Write(Uint16ToBEBytes(uint16(t.Value)))
case 3:
buffer.Write(Uint24ToBEBytes(t.Value))
case 4:
buffer.Write(Uint32ToBEBytes(t.Value))
}
return buffer.Bytes()
}

func (t TruncatedPN) Join(p PacketNumber) PacketNumber {
var mask uint64
switch t.Length {
case 1:
mask = uint64(0x7f)
case 2:
mask = uint64(0x3fff)
case 4:
mask = uint64(0x3fffffff)
}
return PacketNumber((uint64(p) & ^mask) | (uint64(t.Value) & mask))
return PacketNumber(uint64(p & (0xFFFFFFFFFFFFFFFF << uint(t.Length * 8))) | uint64(t.Value))
}

func (t *TruncatedPN) SetLength(length int) {
t.Length = length
}

type VarInt struct {
Expand Down Expand Up @@ -201,6 +178,12 @@ func Uint32ToBEBytes(uint32 uint32) []byte {
return b
}

func Uint24ToBEBytes(uint32 uint32) []byte {
b := make([]byte, 4, 4)
binary.BigEndian.PutUint32(b, uint32)
return b[1:]
}

func Uint16ToBEBytes(uint16 uint16) []byte {
b := make([]byte, 2, 2)
binary.BigEndian.PutUint16(b, uint16)
Expand Down
Loading

0 comments on commit 911d820

Please sign in to comment.