mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-01 19:27:35 +03:00
132 lines
3.4 KiB
Go
132 lines
3.4 KiB
Go
package frames
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/refraction-networking/uquic/internal/protocol"
|
|
"github.com/refraction-networking/uquic/internal/wire"
|
|
)
|
|
|
|
const version = protocol.Version1
|
|
|
|
// PrefixLen is the number of bytes used for configuration
|
|
const PrefixLen = 1
|
|
|
|
func toEncLevel(v uint8) protocol.EncryptionLevel {
|
|
switch v % 3 {
|
|
default:
|
|
return protocol.EncryptionInitial
|
|
case 1:
|
|
return protocol.EncryptionHandshake
|
|
case 2:
|
|
return protocol.Encryption1RTT
|
|
}
|
|
}
|
|
|
|
// Fuzz fuzzes the QUIC frames.
|
|
//
|
|
//go:generate go run ./cmd/corpus.go
|
|
func Fuzz(data []byte) int {
|
|
if len(data) < PrefixLen {
|
|
return 0
|
|
}
|
|
encLevel := toEncLevel(data[0])
|
|
data = data[PrefixLen:]
|
|
|
|
parser := wire.NewFrameParser(true)
|
|
parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent)
|
|
|
|
var numFrames int
|
|
var b []byte
|
|
for len(data) > 0 {
|
|
initialLen := len(data)
|
|
l, f, err := parser.ParseNext(data, encLevel, version)
|
|
if err != nil {
|
|
break
|
|
}
|
|
data = data[l:]
|
|
numFrames++
|
|
if f == nil { // PADDING frame
|
|
continue
|
|
}
|
|
// We accept empty STREAM frames, but we don't write them.
|
|
if sf, ok := f.(*wire.StreamFrame); ok {
|
|
if sf.DataLen() == 0 {
|
|
sf.PutBack()
|
|
continue
|
|
}
|
|
}
|
|
validateFrame(f)
|
|
|
|
startLen := len(b)
|
|
parsedLen := initialLen - len(data)
|
|
b, err = f.Append(b, version)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error writing frame %#v: %s", f, err))
|
|
}
|
|
frameLen := protocol.ByteCount(len(b) - startLen)
|
|
if f.Length(version) != frameLen {
|
|
panic(fmt.Sprintf("inconsistent frame length for %#v: expected %d, got %d", f, frameLen, f.Length(version)))
|
|
}
|
|
if sf, ok := f.(*wire.StreamFrame); ok {
|
|
sf.PutBack()
|
|
}
|
|
if frameLen > protocol.ByteCount(parsedLen) {
|
|
panic(fmt.Sprintf("serialized length (%d) is longer than parsed length (%d)", len(b), parsedLen))
|
|
}
|
|
}
|
|
|
|
if numFrames == 0 {
|
|
return 0
|
|
}
|
|
return 1
|
|
}
|
|
|
|
func validateFrame(frame wire.Frame) {
|
|
switch f := frame.(type) {
|
|
case *wire.StreamFrame:
|
|
if protocol.ByteCount(len(f.Data)) != f.DataLen() {
|
|
panic("STREAM frame: inconsistent data length")
|
|
}
|
|
case *wire.AckFrame:
|
|
if f.DelayTime < 0 {
|
|
panic(fmt.Sprintf("invalid ACK delay_time: %s", f.DelayTime))
|
|
}
|
|
if f.LargestAcked() < f.LowestAcked() {
|
|
panic("ACK: largest acknowledged is smaller than lowest acknowledged")
|
|
}
|
|
for _, r := range f.AckRanges {
|
|
if r.Largest < 0 || r.Smallest < 0 {
|
|
panic("ACK range contains a negative packet number")
|
|
}
|
|
}
|
|
if !f.AcksPacket(f.LargestAcked()) {
|
|
panic("ACK frame claims that largest acknowledged is not acknowledged")
|
|
}
|
|
if !f.AcksPacket(f.LowestAcked()) {
|
|
panic("ACK frame claims that lowest acknowledged is not acknowledged")
|
|
}
|
|
_ = f.AcksPacket(100)
|
|
_ = f.AcksPacket((f.LargestAcked() + f.LowestAcked()) / 2)
|
|
case *wire.NewConnectionIDFrame:
|
|
if f.ConnectionID.Len() < 1 || f.ConnectionID.Len() > 20 {
|
|
panic(fmt.Sprintf("invalid NEW_CONNECTION_ID frame length: %s", f.ConnectionID))
|
|
}
|
|
case *wire.NewTokenFrame:
|
|
if len(f.Token) == 0 {
|
|
panic("NEW_TOKEN frame with an empty token")
|
|
}
|
|
case *wire.MaxStreamsFrame:
|
|
if f.MaxStreamNum > protocol.MaxStreamCount {
|
|
panic("MAX_STREAMS frame with an invalid Maximum Streams value")
|
|
}
|
|
case *wire.StreamsBlockedFrame:
|
|
if f.StreamLimit > protocol.MaxStreamCount {
|
|
panic("STREAMS_BLOCKED frame with an invalid Maximum Streams value")
|
|
}
|
|
case *wire.ConnectionCloseFrame:
|
|
if f.IsApplicationError && f.FrameType != 0 {
|
|
panic("CONNECTION_CLOSE for an application error containing a frame type")
|
|
}
|
|
}
|
|
}
|