github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/fuzzing/header/fuzz.go (about)

     1  package header
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/metacubex/quic-go/internal/protocol"
     8  	"github.com/metacubex/quic-go/internal/wire"
     9  )
    10  
    11  const version = protocol.Version1
    12  
    13  // PrefixLen is the number of bytes used for configuration
    14  const PrefixLen = 1
    15  
    16  // Fuzz fuzzes the QUIC header.
    17  //
    18  //go:generate go run ./cmd/corpus.go
    19  func Fuzz(data []byte) int {
    20  	if len(data) < PrefixLen {
    21  		return 0
    22  	}
    23  	connIDLen := int(data[0] % 21)
    24  	data = data[PrefixLen:]
    25  
    26  	if wire.IsVersionNegotiationPacket(data) {
    27  		return fuzzVNP(data)
    28  	}
    29  	connID, err := wire.ParseConnectionID(data, connIDLen)
    30  	if err != nil {
    31  		return 0
    32  	}
    33  
    34  	if !wire.IsLongHeaderPacket(data[0]) {
    35  		wire.ParseShortHeader(data, connIDLen)
    36  		return 1
    37  	}
    38  
    39  	is0RTTPacket := wire.Is0RTTPacket(data)
    40  	hdr, _, _, err := wire.ParsePacket(data)
    41  	if err != nil {
    42  		return 0
    43  	}
    44  	if hdr.DestConnectionID != connID {
    45  		panic(fmt.Sprintf("Expected connection IDs to match: %s vs %s", hdr.DestConnectionID, connID))
    46  	}
    47  	if (hdr.Type == protocol.PacketType0RTT) != is0RTTPacket {
    48  		panic("inconsistent 0-RTT packet detection")
    49  	}
    50  
    51  	var extHdr *wire.ExtendedHeader
    52  	// Parse the extended header, if this is not a Retry packet.
    53  	if hdr.Type == protocol.PacketTypeRetry {
    54  		extHdr = &wire.ExtendedHeader{Header: *hdr}
    55  	} else {
    56  		var err error
    57  		extHdr, err = hdr.ParseExtended(bytes.NewReader(data), version)
    58  		if err != nil {
    59  			return 0
    60  		}
    61  	}
    62  	// We always use a 2-byte encoding for the Length field in Long Header packets.
    63  	// Serializing the header will fail when using a higher value.
    64  	if hdr.Length > 16383 {
    65  		return 1
    66  	}
    67  	b, err := extHdr.Append(nil, version)
    68  	if err != nil {
    69  		// We are able to parse packets with connection IDs longer than 20 bytes,
    70  		// but in QUIC version 1, we don't write headers with longer connection IDs.
    71  		if hdr.DestConnectionID.Len() <= protocol.MaxConnIDLen &&
    72  			hdr.SrcConnectionID.Len() <= protocol.MaxConnIDLen {
    73  			panic(err)
    74  		}
    75  		return 0
    76  	}
    77  	// GetLength is not implemented for Retry packets
    78  	if hdr.Type != protocol.PacketTypeRetry {
    79  		if expLen := extHdr.GetLength(version); expLen != protocol.ByteCount(len(b)) {
    80  			panic(fmt.Sprintf("inconsistent header length: %#v. Expected %d, got %d", extHdr, expLen, len(b)))
    81  		}
    82  	}
    83  	return 1
    84  }
    85  
    86  func fuzzVNP(data []byte) int {
    87  	connID, err := wire.ParseConnectionID(data, 0)
    88  	if err != nil {
    89  		return 0
    90  	}
    91  	dest, src, versions, err := wire.ParseVersionNegotiationPacket(data)
    92  	if err != nil {
    93  		return 0
    94  	}
    95  	if !bytes.Equal(dest, connID.Bytes()) {
    96  		panic("connection IDs don't match")
    97  	}
    98  	if len(versions) == 0 {
    99  		panic("no versions")
   100  	}
   101  	wire.ComposeVersionNegotiation(src, dest, versions)
   102  	return 1
   103  }