forked from quic-go/quic-go
send entropy in packets, validate entropy in received ACKs
This commit is contained in:
41
session.go
41
session.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/lucas-clemente/quic-go/frames"
|
"github.com/lucas-clemente/quic-go/frames"
|
||||||
"github.com/lucas-clemente/quic-go/handshake"
|
"github.com/lucas-clemente/quic-go/handshake"
|
||||||
"github.com/lucas-clemente/quic-go/protocol"
|
"github.com/lucas-clemente/quic-go/protocol"
|
||||||
|
"github.com/lucas-clemente/quic-go/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StreamCallback gets a stream frame and returns a reply frame
|
// StreamCallback gets a stream frame and returns a reply frame
|
||||||
@@ -25,7 +26,9 @@ type Session struct {
|
|||||||
ServerConfig *handshake.ServerConfig
|
ServerConfig *handshake.ServerConfig
|
||||||
cryptoSetup *handshake.CryptoSetup
|
cryptoSetup *handshake.CryptoSetup
|
||||||
|
|
||||||
Entropy EntropyAccumulator
|
EntropyReceived EntropyAccumulator
|
||||||
|
EntropySent EntropyAccumulator
|
||||||
|
EntropyHistory map[protocol.PacketNumber]EntropyAccumulator // ToDo: store this with the packet itself
|
||||||
|
|
||||||
lastSentPacketNumber protocol.PacketNumber
|
lastSentPacketNumber protocol.PacketNumber
|
||||||
lastObservedPacketNumber protocol.PacketNumber
|
lastObservedPacketNumber protocol.PacketNumber
|
||||||
@@ -48,6 +51,7 @@ func NewSession(conn *net.UDPConn, v protocol.VersionNumber, connectionID protoc
|
|||||||
streamCallback: streamCallback,
|
streamCallback: streamCallback,
|
||||||
lastObservedPacketNumber: 0,
|
lastObservedPacketNumber: 0,
|
||||||
Streams: make(map[protocol.StreamID]*Stream),
|
Streams: make(map[protocol.StreamID]*Stream),
|
||||||
|
EntropyHistory: make(map[protocol.PacketNumber]EntropyAccumulator),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,11 +81,11 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Entropy.Add(publicHeader.PacketNumber, privateFlag&0x01 > 0)
|
s.EntropyReceived.Add(publicHeader.PacketNumber, privateFlag&0x01 > 0)
|
||||||
|
|
||||||
s.SendFrames([]frames.Frame{&frames.AckFrame{
|
s.SendFrames([]frames.Frame{&frames.AckFrame{
|
||||||
LargestObserved: publicHeader.PacketNumber,
|
LargestObserved: publicHeader.PacketNumber,
|
||||||
Entropy: s.Entropy.Get(),
|
Entropy: s.EntropyReceived.Get(),
|
||||||
}})
|
}})
|
||||||
|
|
||||||
// read all frames in the packet
|
// read all frames in the packet
|
||||||
@@ -173,10 +177,21 @@ func (s *Session) handleStreamFrame(r *bytes.Reader) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) handleAckFrame(r *bytes.Reader) error {
|
func (s *Session) handleAckFrame(r *bytes.Reader) error {
|
||||||
_, err := frames.ParseAckFrame(r)
|
frame, err := frames.ParseAckFrame(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedEntropy, ok := s.EntropyHistory[frame.LargestObserved]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("No entropy value saved for received ACK packet")
|
||||||
|
}
|
||||||
|
delete(s.EntropyHistory, frame.LargestObserved)
|
||||||
|
|
||||||
|
if byte(expectedEntropy) != frame.Entropy {
|
||||||
|
return errors.New("Incorrect entropy value in ACK package")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +225,16 @@ func (s *Session) handleRstStreamFrame(r *bytes.Reader) error {
|
|||||||
// SendFrames sends a number of frames to the client
|
// SendFrames sends a number of frames to the client
|
||||||
func (s *Session) SendFrames(frames []frames.Frame) error {
|
func (s *Session) SendFrames(frames []frames.Frame) error {
|
||||||
var framesData bytes.Buffer
|
var framesData bytes.Buffer
|
||||||
framesData.WriteByte(0) // TODO: entropy
|
entropyBit, err := utils.RandomBit()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if entropyBit {
|
||||||
|
framesData.WriteByte(1)
|
||||||
|
} else {
|
||||||
|
framesData.WriteByte(0)
|
||||||
|
}
|
||||||
|
|
||||||
for _, f := range frames {
|
for _, f := range frames {
|
||||||
if err := f.Write(&framesData); err != nil {
|
if err := f.Write(&framesData); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -220,14 +244,17 @@ func (s *Session) SendFrames(frames []frames.Frame) error {
|
|||||||
s.lastSentPacketNumber++
|
s.lastSentPacketNumber++
|
||||||
|
|
||||||
var fullReply bytes.Buffer
|
var fullReply bytes.Buffer
|
||||||
responsePublicHeader := PublicHeader{ConnectionID: s.ConnectionID, PacketNumber: s.lastSentPacketNumber}
|
packetNumber := s.lastSentPacketNumber
|
||||||
|
responsePublicHeader := PublicHeader{ConnectionID: s.ConnectionID, PacketNumber: packetNumber}
|
||||||
if err := responsePublicHeader.WritePublicHeader(&fullReply); err != nil {
|
if err := responsePublicHeader.WritePublicHeader(&fullReply); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
s.EntropySent.Add(packetNumber, entropyBit)
|
||||||
|
s.EntropyHistory[packetNumber] = s.EntropySent
|
||||||
|
|
||||||
s.cryptoSetup.Seal(s.lastSentPacketNumber, &fullReply, fullReply.Bytes(), framesData.Bytes())
|
s.cryptoSetup.Seal(s.lastSentPacketNumber, &fullReply, fullReply.Bytes(), framesData.Bytes())
|
||||||
|
|
||||||
fmt.Printf("-> Sending packet %d (%d bytes) to %v\n", responsePublicHeader.PacketNumber, len(fullReply.Bytes()), s.CurrentRemoteAddr)
|
fmt.Printf("-> Sending packet %d (%d bytes) to %v\n", responsePublicHeader.PacketNumber, len(fullReply.Bytes()), s.CurrentRemoteAddr)
|
||||||
_, err := s.Connection.WriteToUDP(fullReply.Bytes(), s.CurrentRemoteAddr)
|
_, err = s.Connection.WriteToUDP(fullReply.Bytes(), s.CurrentRemoteAddr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,6 +124,20 @@ func Min(a, b int) int {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandomBit returns a cryptographically secure random bit (encoded as true / false)
|
||||||
|
func RandomBit() (bool, error) {
|
||||||
|
// ToDo: it's probably more efficient to read a bigger slice of random numbers at once and to cache them somewhere
|
||||||
|
b := make([]byte, 1)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if uint8(b[0])%2 == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Uint32Slice attaches the methods of sort.Interface to []uint32, sorting in increasing order.
|
// Uint32Slice attaches the methods of sort.Interface to []uint32, sorting in increasing order.
|
||||||
type Uint32Slice []uint32
|
type Uint32Slice []uint32
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,14 @@ var _ = Describe("Utils", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("Rand", func() {
|
||||||
|
It("returns either true or false", func() {
|
||||||
|
val, err := RandomBit()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(val).To(SatisfyAny(Equal(true), Equal(false)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Context("ReadUintN", func() {
|
Context("ReadUintN", func() {
|
||||||
It("reads n bytes", func() {
|
It("reads n bytes", func() {
|
||||||
m := map[uint8]uint64{
|
m := map[uint8]uint64{
|
||||||
|
|||||||
Reference in New Issue
Block a user