package frames import ( "bytes" "fmt" "github.com/lucas-clemente/quic-go/internal/protocol" "github.com/lucas-clemente/quic-go/internal/wire" ) const version = protocol.VersionTLS // 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(version) parser.SetAckDelayExponent(protocol.DefaultAckDelayExponent) r := bytes.NewReader(data) initialLen := r.Len() var frames []wire.Frame for r.Len() > 0 { f, err := parser.ParseNext(r, encLevel) if err != nil { break } frames = append(frames, f) } parsedLen := initialLen - r.Len() if len(frames) == 0 { return 0 } b := &bytes.Buffer{} for _, f := range frames { if f == nil { // PADDING frame b.WriteByte(0x0) 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 } } lenBefore := b.Len() if err := f.Write(b, version); err != nil { panic(fmt.Sprintf("Error writing frame %#v: %s", f, err)) } frameLen := b.Len() - lenBefore if f.Length(version) != protocol.ByteCount(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 b.Len() > parsedLen { panic(fmt.Sprintf("Serialized length (%d) is longer than parsed length (%d)", b.Len(), parsedLen)) } return 1 }