github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/testutils/testutils.go (about) 1 // Package testutils contains utilities for simulating packet injection and man-in-the-middle (MITM) attacker tests. 2 // It is not supposed to be used for non-testing purposes. 3 // The API is not guaranteed to be stable. 4 package testutils 5 6 import ( 7 "fmt" 8 9 "github.com/apernet/quic-go/internal/handshake" 10 "github.com/apernet/quic-go/internal/protocol" 11 "github.com/apernet/quic-go/internal/wire" 12 ) 13 14 // writePacket returns a new raw packet with the specified header and payload 15 func writePacket(hdr *wire.ExtendedHeader, data []byte) []byte { 16 b, err := hdr.Append(nil, hdr.Version) 17 if err != nil { 18 panic(fmt.Sprintf("failed to write header: %s", err)) 19 } 20 return append(b, data...) 21 } 22 23 // packRawPayload returns a new raw payload containing given frames 24 func packRawPayload(version protocol.Version, frames []wire.Frame) []byte { 25 var b []byte 26 for _, cf := range frames { 27 var err error 28 b, err = cf.Append(b, version) 29 if err != nil { 30 panic(err) 31 } 32 } 33 return b 34 } 35 36 // ComposeInitialPacket returns an Initial packet encrypted under key (the original destination connection ID) 37 // containing specified frames. 38 func ComposeInitialPacket( 39 srcConnID, destConnID, key protocol.ConnectionID, 40 token []byte, 41 frames []wire.Frame, 42 sentBy protocol.Perspective, 43 version protocol.Version, 44 ) []byte { 45 sealer, _ := handshake.NewInitialAEAD(key, sentBy, version) 46 47 // compose payload 48 var payload []byte 49 if len(frames) == 0 { 50 payload = make([]byte, protocol.MinInitialPacketSize) 51 } else { 52 payload = packRawPayload(version, frames) 53 } 54 55 // compose Initial header 56 payloadSize := len(payload) 57 const pnLength = protocol.PacketNumberLen4 58 length := payloadSize + int(pnLength) + sealer.Overhead() 59 hdr := &wire.ExtendedHeader{ 60 Header: wire.Header{ 61 Type: protocol.PacketTypeInitial, 62 Token: token, 63 SrcConnectionID: srcConnID, 64 DestConnectionID: destConnID, 65 Length: protocol.ByteCount(length), 66 Version: version, 67 }, 68 PacketNumberLen: pnLength, 69 PacketNumber: 0x0, 70 } 71 72 raw := writePacket(hdr, payload) 73 74 // encrypt payload and header 75 payloadOffset := len(raw) - payloadSize 76 var encrypted []byte 77 encrypted = sealer.Seal(encrypted, payload, hdr.PacketNumber, raw[:payloadOffset]) 78 hdrBytes := raw[0:payloadOffset] 79 encrypted = append(hdrBytes, encrypted...) 80 pnOffset := payloadOffset - int(pnLength) // packet number offset 81 sealer.EncryptHeader( 82 encrypted[payloadOffset:payloadOffset+16], // first 16 bytes of payload (sample) 83 &encrypted[0], // first byte of header 84 encrypted[pnOffset:payloadOffset], // packet number bytes 85 ) 86 return encrypted 87 } 88 89 // ComposeRetryPacket returns a new raw Retry Packet 90 func ComposeRetryPacket( 91 srcConnID protocol.ConnectionID, 92 destConnID protocol.ConnectionID, 93 origDestConnID protocol.ConnectionID, 94 token []byte, 95 version protocol.Version, 96 ) []byte { 97 hdr := &wire.ExtendedHeader{ 98 Header: wire.Header{ 99 Type: protocol.PacketTypeRetry, 100 SrcConnectionID: srcConnID, 101 DestConnectionID: destConnID, 102 Token: token, 103 Version: version, 104 }, 105 } 106 data := writePacket(hdr, nil) 107 return append(data, handshake.GetRetryIntegrityTag(data, origDestConnID, version)[:]...) 108 }