diff --git a/common/protocol/quic/qtls_go118.go b/common/protocol/quic/qtls_go118.go index bfa5e2457..4983b71f7 100644 --- a/common/protocol/quic/qtls_go118.go +++ b/common/protocol/quic/qtls_go118.go @@ -1,18 +1,10 @@ package quic import ( - "crypto" "crypto/cipher" _ "crypto/tls" _ "unsafe" ) -type CipherSuiteTLS13 struct { - ID uint16 - KeyLen int - AEAD func(key, fixedNonce []byte) cipher.AEAD - Hash crypto.Hash -} - //go:linkname AEADAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 func AEADAESGCMTLS13(key, nonceMask []byte) cipher.AEAD diff --git a/common/protocol/quic/sniff.go b/common/protocol/quic/sniff.go index eee3640f9..14c165c32 100644 --- a/common/protocol/quic/sniff.go +++ b/common/protocol/quic/sniff.go @@ -3,7 +3,6 @@ package quic import ( "crypto" "crypto/aes" - "crypto/tls" "encoding/binary" "io" @@ -28,22 +27,43 @@ func (s SniffHeader) Domain() string { return s.domain } -const ( - versionDraft29 uint32 = 0xff00001d - version1 uint32 = 0x1 +var ( + errNotQUIC = errors.New("not quic") + errNotQUICInitial = errors.New("not initial packet") ) +type quicVersionSpec struct { + ver uint32 + typeInitial byte + initialSalt []byte + labelPrefix string +} + var ( - quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} - quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} - initialSuite = &CipherSuiteTLS13{ - ID: tls.TLS_AES_128_GCM_SHA256, - KeyLen: 16, - AEAD: AEADAESGCMTLS13, - Hash: crypto.SHA256, + quicDraft29 = quicVersionSpec{ + ver: 0xff00001d, + typeInitial: 0b00, + initialSalt: []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99}, + labelPrefix: "quic", + } + quicV1 = quicVersionSpec{ + ver: 0x1, + typeInitial: 0b00, + initialSalt: []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a}, + labelPrefix: "quic", + } + quicV2 = quicVersionSpec{ + ver: 0x6b3343cf, + typeInitial: 0b01, + initialSalt: []byte{0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9}, + labelPrefix: "quicv2", + } + + quicVersionSpecMap = map[uint32]*quicVersionSpec{ + quicDraft29.ver: &quicDraft29, + quicV1.ver: &quicV1, + quicV2.ver: &quicV2, } - errNotQuic = errors.New("not quic") - errNotQuicInitial = errors.New("not initial packet") ) func SniffQUIC(b []byte) (*SniffHeader, error) { @@ -63,60 +83,61 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { buffer := buf.FromBytes(b) typeByte, err := buffer.ReadByte() if err != nil { - return nil, errNotQuic + return nil, errNotQUIC } isLongHeader := typeByte&0x80 > 0 if !isLongHeader || typeByte&0x40 == 0 { - return nil, errNotQuicInitial + return nil, errNotQUICInitial } vb, err := buffer.ReadBytes(4) if err != nil { - return nil, errNotQuic + return nil, errNotQUIC } versionNumber := binary.BigEndian.Uint32(vb) - if versionNumber != 0 && typeByte&0x40 == 0 { - return nil, errNotQuic - } else if versionNumber != versionDraft29 && versionNumber != version1 { - return nil, errNotQuic + var s *quicVersionSpec + if v, ok := quicVersionSpecMap[versionNumber]; ok { + s = v + } else { + return nil, errNotQUIC } - packetType := (typeByte & 0x30) >> 4 - isQuicInitial := packetType == 0x0 - var destConnID []byte if l, err := buffer.ReadByte(); err != nil { - return nil, errNotQuic + return nil, errNotQUIC } else if destConnID, err = buffer.ReadBytes(int32(l)); err != nil { - return nil, errNotQuic + return nil, errNotQUIC } if l, err := buffer.ReadByte(); err != nil { - return nil, errNotQuic + return nil, errNotQUIC } else if common.Error2(buffer.ReadBytes(int32(l))) != nil { - return nil, errNotQuic + return nil, errNotQUIC } - if isQuicInitial { // Only initial packets have token, see https://datatracker.ietf.org/doc/html/rfc9000#section-17.2.2 - tokenLen, err := readShortQuicVarint(buffer) + packetType := (typeByte & 0x30) >> 4 + isQUICInitial := packetType == s.typeInitial + + if isQUICInitial { // Only initial packets have token, see https://datatracker.ietf.org/doc/html/rfc9000#section-17.2.2 + tokenLen, err := readShortQUICVarint(buffer) if err != nil || tokenLen > int32(len(b)) { - return nil, errNotQuic + return nil, errNotQUIC } if _, err = buffer.ReadBytes(tokenLen); err != nil { - return nil, errNotQuic + return nil, errNotQUIC } } - packetLen, err := readShortQuicVarint(buffer) + packetLen, err := readShortQUICVarint(buffer) if err != nil { - return nil, errNotQuic + return nil, errNotQUIC } // packetLen is impossible to be shorter than this if packetLen < 4 { - return nil, errNotQuic + return nil, errNotQUIC } hdrLen := len(b) - int(buffer.Len()) @@ -125,26 +146,22 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { } restPayload := b[hdrLen+int(packetLen):] - if !isQuicInitial { // Skip this packet if it's not initial packet + if !isQUICInitial { // Skip this packet if it's not initial packet b = restPayload continue } - var salt []byte - if versionNumber == version1 { - salt = quicSalt - } else { - salt = quicSaltOld - } + salt := s.initialSalt + label := s.labelPrefix initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt) - secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) - hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen) + secret := hkdfExpandLabel(initialSecret, "client in", crypto.SHA256.Size()) + hpKey := hkdfExpandLabel(secret, label+" hp", 16) block, err := aes.NewCipher(hpKey) if err != nil { return nil, err } if len(b) < hdrLen+4+block.BlockSize() { - return nil, errNotQuic + return nil, errNotQUIC } cache.Clear() mask := cache.Extend(int32(block.BlockSize())) @@ -155,8 +172,8 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { b[hdrLen+i] ^= mask[i+1] } - key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) - iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) + key := hkdfExpandLabel(secret, label+" key", 16) + iv := hkdfExpandLabel(secret, label+" iv", 12) cipher := AEADAESGCMTLS13(key, iv) nonce := cache.Extend(int32(cipher.NonceSize())) @@ -181,44 +198,44 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { case 0x00: // PADDING frame case 0x01: // PING frame case 0x02, 0x03: // ACK frame - if _, err = readShortQuicVarint(buffer); err != nil { // Field: Largest Acknowledged + if _, err = readShortQUICVarint(buffer); err != nil { // Field: Largest Acknowledged return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { // Field: ACK Delay + if _, err = readShortQUICVarint(buffer); err != nil { // Field: ACK Delay return nil, io.ErrUnexpectedEOF } - ackRangeCount, err := readShortQuicVarint(buffer) // Field: ACK Range Count + ackRangeCount, err := readShortQUICVarint(buffer) // Field: ACK Range Count if err != nil { return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { // Field: First ACK Range + if _, err = readShortQUICVarint(buffer); err != nil { // Field: First ACK Range return nil, io.ErrUnexpectedEOF } for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range - if _, err = readShortQuicVarint(buffer); err != nil { // Field: ACK Range -> Gap + if _, err = readShortQUICVarint(buffer); err != nil { // Field: ACK Range -> Gap return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { // Field: ACK Range -> ACK Range Length + if _, err = readShortQUICVarint(buffer); err != nil { // Field: ACK Range -> ACK Range Length return nil, io.ErrUnexpectedEOF } } if frameType == 0x03 { - if _, err = readShortQuicVarint(buffer); err != nil { // Field: ECN Counts -> ECT0 Count + if _, err = readShortQUICVarint(buffer); err != nil { // Field: ECN Counts -> ECT0 Count return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { // Field: ECN Counts -> ECT1 Count + if _, err = readShortQUICVarint(buffer); err != nil { // Field: ECN Counts -> ECT1 Count return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count + if _, err = readShortQUICVarint(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count return nil, io.ErrUnexpectedEOF } } case 0x06: // CRYPTO frame, we will use this frame - offset, err := readShortQuicVarint(buffer) // Field: Offset + offset, err := readShortQUICVarint(buffer) // Field: Offset if err != nil { return nil, io.ErrUnexpectedEOF } - length, err := readShortQuicVarint(buffer) // Field: Length + length, err := readShortQUICVarint(buffer) // Field: Length if err != nil || length > buffer.Len() { return nil, io.ErrUnexpectedEOF } @@ -234,13 +251,13 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { return nil, io.ErrUnexpectedEOF } case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet - if _, err = readShortQuicVarint(buffer); err != nil { // Field: Error Code + if _, err = readShortQUICVarint(buffer); err != nil { // Field: Error Code return nil, io.ErrUnexpectedEOF } - if _, err = readShortQuicVarint(buffer); err != nil { // Field: Frame Type + if _, err = readShortQUICVarint(buffer); err != nil { // Field: Frame Type return nil, io.ErrUnexpectedEOF } - length, err := readShortQuicVarint(buffer) // Field: Reason Phrase Length + length, err := readShortQUICVarint(buffer) // Field: Reason Phrase Length if err != nil { return nil, io.ErrUnexpectedEOF } @@ -250,7 +267,7 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { default: // Only above frame types are permitted in initial packet. // See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8 - return nil, errNotQuicInitial + return nil, errNotQUICInitial } } @@ -268,35 +285,33 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { return nil, protocol.ErrProtoNeedMoreData } -func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte { - b := make([]byte, 3, 3+6+len(label)+1+len(context)) - binary.BigEndian.PutUint16(b, uint16(length)) - b[2] = uint8(6 + len(label)) - b = append(b, []byte("tls13 ")...) - b = append(b, []byte(label)...) - b = b[:3+6+len(label)+1] - b[3+6+len(label)] = uint8(len(context)) - b = append(b, context...) +func hkdfExpandLabel(secret []byte, label string, length int) []byte { + b := make([]byte, 0, 2+1+6+len(label)+1) + b = binary.BigEndian.AppendUint16(b, uint16(length)) + b = append(b, byte(6+len(label))) + b = append(b, "tls13 "...) + b = append(b, label...) + b = append(b, 0) // context out := make([]byte, length) - n, err := hkdf.Expand(hash.New, secret, b).Read(out) + n, err := hkdf.Expand(crypto.SHA256.New, secret, b).Read(out) if err != nil || n != length { panic("quic: HKDF-Expand-Label invocation failed unexpectedly") } return out } -// readShortQuicVarint wraps quicvarint.Read with a max limit for length related fields. +// readShortQUICVarint wraps quicvarint.Read with a max limit for length related fields. // we only handle QUIC Initial so these numbers should not exceed 65535 // returns int32 to reduce type conversion -func readShortQuicVarint(reader io.ByteReader) (int32, error) { +func readShortQUICVarint(reader io.ByteReader) (int32, error) { v, err := quicvarint.Read(reader) if err != nil { return 0, err } if v > 65535 { // not used( - return 0, errNotQuicInitial + return 0, errNotQUICInitial } return int32(v), nil } diff --git a/common/protocol/quic/sniff_test.go b/common/protocol/quic/sniff_test.go index 8c6fbef42..3674d9212 100644 --- a/common/protocol/quic/sniff_test.go +++ b/common/protocol/quic/sniff_test.go @@ -268,6 +268,15 @@ func TestSniffQUICPacketNumberLength4(t *testing.T) { } } +func TestSniffQUICv2(t *testing.T) { + pkt, err := hex.DecodeString("d26b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2ae9c783da28244f30c6af9a8aeff6db7c5ae6c595b2e7d367a5e6578bbb9f7859202ac5a5cdaaf32429e7c94e4c6b9494ba1a83e3adab4c716a08e7fe38907888196905c660db7d72f461d2835e81e02f8cf976dc2f08ab3faa18939d73a3da2faca3e6be9df6ce51da00b00dcd5c64f53c6347531e509d7678aba83d8818026f8f6b955cfa95ea8ae9ba0ad0b7f01a11f424abcf490b704663dbb7e700bcecd9725974eb07d2eb67484aa9c8f361d12bb83ff88de06854c45576ff0141461164f999828407ff7ce54abb514ad75e8743c27b23801d330a8b58f75952fe8e4ea696056fc29676351c7e1d6a2d7860ab8ab2582d952c05720a39a551d24b1ce58edb6b14039e905feaa51cac9f712ee22798c6f62d186193c4b9abe7c339d528e0d20c7106a85575fe3535703e0e3bfc33ccdc4de1372466db56519c692e021e5976c0ef841222f1cad2884a6cf78f3973ce8b795a191397cea39d72080cb18f7da7da579758b7923f29c756ac89fa253302c403222bc1888bc7bc0e3f3cfd43000129d3b670b28a2f3b938f6c6c67b27a10fa5d5f92d845a78d063cfe83aa30386e8cba9d152999e56e46ade53940f228671573ca76ea36a910c01a269cf698681b7b462a9b0f467ac8083b2b1568dbb56f657f6ea4e52954520370ffa1b5e24375bfbc53a58aa2d1883e6712cdd6c10b88d69196357f93fa3856d253e01f2ce8237fbd71f27c897ef8378d6f5823af1c69334f97900da32d64359ae6a20231a8ddb56fdc694cdc7a4d2719df0494b34831f10d46f768af082ad6acb491c937ec0e9ad9c9c2aa9f5c8fab93538b4dbeead9c1ecf274fa894377482565aa827a65e6eac57c6e313a95bbc4cb597359f29a2d7ebfb528310c01ba5048a85f3611feafa239ab3ce24a5f8876771b72467b5b2a96bdda475250da97886361db71c001d5e324633246f60a19985c682ea8027aeb5885cbe1ee4f3249d273b111227ef7ba267545feaa4981c3e40cfa82f6f22e550eae2df67678d9591df1f9ffb9cd199dba82b270c0ca42f2977e12031e0ec6a61c1c635012c3f3887e9284394695a8be3ee7249600bb6828ab2e65e1193dc42b3411de0e42bd9abb4d4df7cab5fe2d0000874c08e2e3ebb5dd42129e4ed28327cb531b66e9a9cee4be3ceae38f0a57a4b333cca1a5e6807318d7c6a4b1c07bfd6787e5e73b8dbaddb959df91f41c8afeaaa2349f5d0c6f6a953a49375f72311a45d1beb536fffb032cd8b968c069688ac95dedbd65cf3c82c412e6dc8d1a3ef07c608cd9798a88b0652fdf8f6b42488d7a2aab024746b50c1e6628704e022e1fe29d6407988c78dc572f9d422789aaa9cb6c4b3dff3f9def75e29ed37f777c8d7dcfc235562f2e27736eafbedc0d42c15a2a65711e09ed21bfe69a4e6a6aceae1ae4f1f6af94715d5174c618700fcb15d65aca5b5bc2381f95c2dc1cf684add0fd2984257ae39787077d6ae4ee7b44f938d54fba7ccb3f0bf7336c4a20480b44364fc17956372dea9b182602408371a07b014b848f44f50d18e6a596d9f2ea73b89fd182c3cca573590899dc5aa4bb439925d64fbe56da8fd44c2e785db349b41e11737b1f0fae2fbf3692815b483bb492961d426f991cf0b615b12d3185ccf110f9f2ded4f611bc87ad8d167eb2e7638b1388d0c68dbfec9b56619a10c62f1a4146a617ab0802a0940234b4a3fdb1bdd0d67416ccba9ad21dd37bfd8320efe43bef743de305740f23764ad3e208b55e7de6b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2423d7e3778747532056c364b468ea574954ea0d66a8e67bd93d6896837814c76d24cccfcbece575590c5c022eb13598146aee3a164f133329c278e83daab535f8a595edfccafca9fa08bf5d729d55ff3fb810cfcd075726bd3f181466e2d0ab59e26f7fe9c2a220457c31b1cd25e98a1cf2de53232049950716c2b87fe96a3be76b34ec0d8806579260f727d209c6e3a54584ceb3a2d464c666fe12778a0a1cfe3fc2a7e52cd304031cdb900194c82d781418f518a2bacfc61fdcdd9070fb569fb60fdfd927cd40e1ce5524c485524c6a19a73126f0d1b8950ec83b6f2a5601c793440eea7ec53803411bc7462d026ca4acb6bc0889304fedaad4f74888e19b4dbc9a8d628b3a33da47dab660aa032a62d6de64de1ab25010d4623fd4a64ffacc2e5e990944384df899d5f4801371222cbc96895352d31caf1c1b6928d29df14b07d4f89ef766009dfc403139988b7d5718d0779ee9d7f08f0f6da313b73c2018f8724bd92ef9b69f56fa6d7a3158e580561eb31fe3c9ac8569bcc1cdc3b4deb3b7106f147acd1c7662dfd61c3b0836bc52dcf06d6905f36c189b5fba90c90d9e06d52fe4707e97808c4115d6f9c9aac9e11dc524b20b48a73913c00a330e028fb0a69976703515c858ce5c633fcf615531f7041c536dddb24617d3153bb9d7294bef7b1e1f4d0ae05f4aae0fb7e8f8be5884ecb12d2fd45ff58cd9031b121a521271270d6660d9d3dc358f65ea3ccf4a362f21a5f62b7d96fd5ef05a0e129f435944bbc7fcb3b40134e4842af013f526a0881216fdc1b2d64829360277d10b304f4316795ba0ce90cb7f994019b4869dfafffb8952cec74f266cac503fc59d00da5c94dd120a18097d7aebe2ef7879e27e6f31b6c73935050a64432696787af7afa69c119205c5afdfde63c0f42602ccbe85035bd33e7abd0d56acc44ead9508c8d5adc2463cf2caeb16a64c7108d99364e7781a7cabd84fa24820eb6f3910a05a351d68884cd9b73b8c0c1fb57a8cda4caa1bc8126ed8a8e351a5cd2dbea787be50ca52733bc77baa13eda498ec59850745531294a7a7b80c5fe18e860b3c85193af4c733972677a369717e1ae31ea4b660bfdf0355673643b75f23d8c5cfe8e5b6167b256eb37e3661e74f477926ad9defb0b1e48eeebc8426a3e7aa920ab85df106cabbead4117b9ad81cc40974950f97b51e299881aa52045c178febc2dca090666138677402191d1fb6541d4132c2994603b5ef90f15c0c2660b84b7211afad02eec9f956196bbb655c1754b3bb6551f76f36c448dcaff9f24cc65695b91d4449424744cd8a4b6ed55ac3cc489c94efb81b9c22fbce758be2626210484c305345baab7ca070b39d806c3546f0ba098ced2636d6c25d36fdefd0ff1d78591d223cd4d1c853acccf27578f7ad3c8bc6d124fc4e02c7c0946ce31dc442e05f3752a3ab6121fa087cd1fb276aa52d900ec7c79ea48568530ae40cf4fc7d7ed6ca520b809cfaf62189ea6a262831d598f1c373e8e8d0d5f3128bf76e0c61b82bb30b685cfa359979a38f412568642d9177be7bb2c9ae51438fa4d9610f2608266c374f5892c4802f672adfc42ee9ce83d415516b68e5ae06b3a1991628290c10369729fd2f213a0347ec13d21841766e964ffe5780f3f5adba0ed0b8cc4d222f41cb8797cd8b6f3044985c5c80601ff51da73d1e95483713cc2dffcbf6a4b0c239c3ced06f168842c8f231d2c45a4ad02d21ed37181d0960d42b02d7643b9baf1f6da6b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2614c156521c4569f1261c3fe04e09dfd9a1baa7f56530844007d051fea3c6cd8268e6e98a152a942294662a0e1a022a8a05c57f0b52f7c4dba202153dd25d009273e27dd003031cfa69854d15cd3499f74d766e94454a488d898eea2372ed520a9875ee38a1398253299bccc64bcc5487405be0833c42c46eabe7c1e85d5c8adefc59064183522cb494aa4c0e0454b2641b76ab460516017bbb784a16539c71ae598813e20f33efcda9596207678b5c275211d483a3cc0e6fe338e21903e68976661d678d62f399a7ec0f34884d21d9c8d093cc9c3f3f0bd0452c65afda505a7f9dcaaa6d263f83b5c29b469858c5202a97ae6128416719a924171009c3859635e20ec9eeaad4d153bfb7735aebd3f598c62b479d7fa733411ce77ca745327356ea4545749de9e9322fc094c1b4d6fe65da28a0f4ccec8396fa0b24fb975adc1129dbf5edb70b6d0ad70f9673a76e7f9fc08709032192de9e70e065b828a63757a294aff90c4ad9ae33f6c6184c7a954852575972e1a1c3b9944e0942d3a40a5d10c4d5fae8a5b79ef18772c2cb5db3973ff24af913caae03c756192edd60daa373b84c7c1a8936f2438c88051501421e80bb1abcea182e281da560114fc919c1aa1e131046068f662359a8cf7430977725c6a3d6f8f8b6fa70e32424ecc10bb7f39ac9f19b0b3875449696ec803cd32d294a78abbf4e166b04c455cf52b8229a29a3bb0bf98ec4461e483e470e4359c0e4191e9f9023f63408eeb67507096e1e6290da895a1fdf9bd670599a8dccda085e79de8ca6b01b650f1c6511e29f9b7879f706083d5ca31e152b656b614d444be23a124a618c94554e7ec2f9913959620ec149b269180f71a95e35c6d4d05e6fc779fe2ab4755dbff04465cbf4c5df1808870cea4f4357d5887538a2b1b1dffae2614ed301549f6ae0d623eb879a5d203c6ae32109a5d81e059b6719baab203ee4a5a4ecba4aca7a4a44f6042c7494804fcbad59e8e57cf8f3af4c1cc2359d45cc9134e2f410b42aca884845c261188d5a63b49214b3409af64c55a4b8b01b505423e6d571544b55d9d82411b5852481eb48d30446b217efc6817d3c322acf08b32f8ac6f282baeb6bea9b445e1aa98755d24e18966b89f1d4bb4e3b25585a8d2d42d2c688a74918b968b974fa476e5cb98ce0ff889e2839ac800b27b9d44cdcb23aa089e4b4b1ba3695b4b5e4bed2da40e5994f0545c72e7acc8ea8be1266bf4560e8f8fa8a8f800f1a23a5c466e1d5836ca4bf9331a1417af217bfe32c853595c14ca6d0af1ac7da0f54d6862cf0742978516fe072e88d04f61593ed9f5c316403464a13e960383e1db71efa440a439f0dbe2c429b8c4722470a0dc0d249f0de30e4012322133402c6238c5f9d3fa260b4f49d35f75f19097d4a5d6923c13546ff5fdd37a0780b93426d104ba4a9ce2c3fc57510b878c3e315567828e226fd5ec3eab8a364c119dd86857022e579d14b014a962901224a75115853b191a6127e81901fd033621da203edc2479adfef60a07f8bad9a704f2dbb7f5f25e9d1464ea3ae849fc1c4adb10d8db58df9ee60763f3f379ef8615acf96db7c4879dff9fce314f7814855cc9b5147fe9b684e3136ed11152b3326e8c9d09cf10e3c5ae2b11e79e656dad4ccf820f4b930b75e59bef74ad6e43e43da623195ba0ce25ef59c1e6b0c8171783868cb06df16a73a0ff4f9f1788b3209c4d12d4b59409a4acecff24f4f12e55cc1e0e50517427ebb30cc9d56b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e20a4b52b678d6c69e62366bcabf6b3dde5ef15a489e455c35c464988b9456651328b5018c2291306ed86e0352a20f1313ef89267028a04364a2e5c09bed8660e8642decfe270641b71682ddb22f605c2c9b7da14245ec51d1ce9d8126db7ca049d7d1e61544521f8e10b70f9c7b5e3bc9f41969e42de239dc532985ba19d9c18e54b277510a79f7a20a4675b8752b07d6d77721da2313981f7b2c9f2e712e2751b9b776a992cf7621a0c3d77049a4ec445d866207cc29bf97f7a75b645a725de4e1a21f64c9f1911dd21b2c12e0e26a620805cbcd9725b4643b76dba92a2568404f44cf5b26b5a5c27484c12a76cc74fcaf8406b021805c769beeaff196a2af69cc327c3a37cb53a6e9c92a51f3455e54823f20786cb4e3accf07b12b2cbddc30874353409a2da6bba6929ceaeb1552ebf1cb92c3cfbe90e19223a83027381d4906a19ed24111b733e390e25b08beaa14fa6dfd66429659fcb28ec7cb54e5dd4a33e626e3abbd979dc71b8e291ca3127a5fa637b395c0eff42f11f146d3bc94ea8433de2c4680aa3810423e5c97ed6617116c260da97ed5b0ab84d51aae3638ef93f037f032c3e074bd8fd9f01a7a1764a11d3e51f53636f29b6749913db895f9cbbe6e8b2b3b8adc7c27bb41c786e81b78a55f6fdde4189b027d91490e795c308f5b58d2dff0e01d4c57916213ae950063f624521e797240a0ceba216fd1351ee4c8becf1da891a98f88cc89694800d21c4562eaad49dd8fdd4940a927ec2b277f004f0f881d255ca27cc7293d62a7662f8b5cb6d611f50d4fdddda19873858aa5ee1d873bebcd0b3509a498129174c2df574c393ca081dc6165bd298170c8896f788ca599b23e0b19acb69d2293541c004d4b8cbf6fdadec455092e1f7226f9a6c2149d0df4eee3746ab9676c59a16cd8f09781975df9b826309c6ea3e9e19f9e095402c53101f6def94379e1f6c5457700d4ffb09b32b54dc0b4182611737aa9df5ef81ec15f108ccecfcd672b52599154d3c670864d721af24f242aa7104fddd089f5d6859cdf397e28731624a40d60ff85185843b1422263eba7431087b7a0b4f164d5950f3b927c200a266a5f88488c333f51dc888a05c75e8a7c619ae87df50d457ab79b8be03d1aa3a97800b638403803578a47b5fa0a58c64cf3cf1285f20d12ae44219fe5cd7427e905fb29718dd3120910e78a1ca46a1bfbb7d3fe4e99577ed8b4de9a0493dd83bae2fa2fb3e9afc1ef5a3613b9b3fcfe74a430b53b0528de4a1a2bfba6fb822a93a8c98a2335dfb4ad85075ecfe8ebededc7ce87e4da0a1d30b9d986e8f2a8280297b821ac909ddf0df91e990db315369cb95002f0a1d3eba9e8e6b0b9fad9d9638447fa55fb4ea4cd5fd381387bef0d41bcbd515a7f7f37cc0bb81c67ab73bf4829530ede3553731e4013c85b8a34179073f665286a4d5b44aba72bc76caa31c47a614ba708ccd80ef2fd6308c1174c63bda3dd31785391c5b2e7334f398952ec0b3e1a845298ab9bf5f22ad97696f4bfd434c673c1bdc4e68d588ae6b24d30333b8bd5a186a96d75b3ccd13f951f1cb65db8ac74d80a9ebdaf80890a3db645072c7ed441e6dc9f74a28a8b7681bf9c40e1fc4d201f8802ded71bc34b2d50f315ff3e8fd5e76a10c831c338f5cbdb80924d5621b281df8e81c71b61bb64fd456b9a03200aeb7931711b28fb581f616861e77f27b792e6cd10c6a1a99439036beb586a193224752c456fc97adfbf3665aa036406f8c9de6b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e28586520ef48c6fe89b7565bc5946f6abd6ca7845180d63c7b0e6e84d4955532ff8e99a1a8c93b4335179703c8a89d7d90068034f9981ddd9cb89cf6d298ec4df54b72806b7ca767cc40b752c4490780b6b725ac9b0d087b54f5d3892085cdfff5ba054afc9d0235abbb41d5234f758d640439270523719fa93d350dd66f333bc9f0c548adefe682f95986cc4eecdd7541a3faaa999a8a7bda8ebe4f1e297c4f0c88e4123257d3fe900637c7023f17b7f94e0d2791b5bd5328403f35024cf08c1708ae3af0529e3f67bf7cb0f363e9d8d508960b905793cd713e6f30f7338671d10c60f51cf5468696a510c77c2bfce3da768da3c0cb2281e00a711c6c43b861bad5dc642b7292a9022385953474d3e3c116176729dada5aacf879e708163ade724824768d978c294f6cceb5f0b4ecd85e38ba721025dbe72da8e29018aa12449ea5e4b9e065c50e54e05bdcbc28674fa57aec824feb1f745c400d828a94844ffcb1d32f12553967d78db776671bc7a14c747cd7dfb64bcc74e4a76aa7ea9560f6851443ac63953cc6398ed941728d38a8e14d033591787f5c5986cc8e74baefe7addce116aef35132e15bc6fd384baea77de47352c410c225d736dafecce217dda91c8171b076f6918bba00bd685947c7bf393ede7cef4dbaf5ed24dbbcc7055fc40a1828113b47ac9bde59fb0f5e8cd9b940f390d7b17463a820b9e6dfa45d0913e0dc5fa2e0a3e491b2ab16f2703348c797455de31722394d9d29956904339364ac25f330461242ad61bb58635b3788040e3537d9116b35148e4f907325b5bcae2532ac22691ee60e01dbd70c50122ec404646d6897bf4fc7bdf563e2233af67196952cad29feeb00dc70d72138711ebc5f3fe2d47341cc110a91c52afcf7bf07d44037ca08b1b5e19967d4d60a7faa33c87b59abd57da743509b083331bed0fecbb85d935566eb82ab6f78ebcf938ac47b30b23b0eed1cf939b16f252978a908e14781ff5a022d23baf3c74b1dbbea687eaf95e38404557e8d846b5763bf7cf6689b8d5a75c2c74a3f6bb8917e343557430912890fe76b207da019ffc45ade8d17fb6fc8277cdb037e6f541c67aef38e6fc4716dbea781dc8bdb29433536eac06f9eef1e95811e68144d2f53a7694e9bd750cc5c1b1136667d0bf0c6ea8b20e80bcd9d4f47eb6ed28ef8b20bb0e007a7a4aa6d4e24597968dd8f0bbfbc50049a1d6298395fb130a1edbc0792a0b4524d57c310e392b1609ebf4f1f639540900b80c10ba986927dc2b6447af93c214f9ac5c9b0fbbb4a650b2c5d67dfacf7e7a9b38dd26c5d3989c927217d50a74bf170fb871782c397090e89344d62e984f77257bf87ebc55557da8e1e72900adeac39b295430302a3bbffde69304534ba9f4fe75299d9707e5033ea01b4c4f14ece65e0feea8f27ef66ec06d9002205f0cfc8c2189b6999810f936a4e30d4f863578f6b7e92aa01037d641a029780fbd8dbbf1a0de7e46e1f7a2e6f2e4b45655d4139c3974c92ed2a59f6ab5d9d53021d2a9cd187c9b3ec92a979b6c4164697ea2377b6cdcb3fb25ed159db59a76031981388c9b49da88640b25b22f225ea4c4142383f26dd4912c169f9e2340bac781ca64588b6c786b0914ddc2ea3691fafc739d76a2d31f981db592171a2605667b58c5465dadc5dc4a66511d726d50d856e524885eb2ba4fd856f262328b9ba895f8dfa098aada2fda08d731acfb939ecb5d208f391054d3461f7eea2019b5fc261e8b95d86b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e26be96eb2df1b4d663f8f1a2e38467e2df1fcabfcc4ea0242afad0a76d0e3c4555d2f722d0b808e84f18e218875335c7f533fa81889402e3ed49895c1d751d8b40fc00dc20132522d9daf0355d7ef99497f44d22def2a885049bf705f9d66c9b31bd766a162e4fe454e478f3108454f7c7485c8544cfaeaed8bf42f7c834014cc8c14b1318b72cd49304f8f91d29709a90491bba44725df6fad1dfefc4e1b0462a6d0b0719ad53fb79379e224bb6e6fae24690d8edf3bb415967023f456411806f734edd0ddcf5d287e025b6eedf8856f2d1a46064aa80fd58ac1cb251e3c55d46c685d4aef763a27f4efb93089137fe84f51fff32bbd610b508e58e66ac334b00a0b8728a372dcea832a76db320dbd91d64d526d66270e0ccfd851ecb640c95e1aefc6ec3a8e42b2b35c75a4f284e8f149eca999f1bdc65fa961742d17edacd2d4b2d33465c44ccd7cf82906d6a6e6d615e2507e0eae9c2eef01777105b54d3b11a96ddf9a4104f9505886d072944f8cd5a557da7b771003cbfe8eff63f28877b4cd3269718d65016c524c9b9106055fd05977d7aec5733f6fcea089fbf11cd513ba7edc297db629577dad435cc859b441468ce4de8b5fead8c8fed170eb86d2d670dfb474811d83b1ea4cdf5d4bfd3c53d6c80a46b38568816836eac288b4150961285a6c59ad264e435cfb795ae51e20bd7d692127962c322ad79554f4590a09157ff2859473b5d9021400cc1c3e3da407b66d17f8fc303d7bd747e8c427d9469829a02c51480313a6a05f3c44aed32e3974b7a6f3c803e5dcdabb6c878581b60aa5e8801967c52ffdc9cac7db6c820e5006b286fb13d06a7ec13e9986589d54dfdd74aae5ecb050a40931896a5a0c6a63c7835df7e6045dc36ba7898de03a44ecbbb51cbc00e71aefb081f7db3adc0977b8213e9f551d37218bb96ceffd725b5a1df0fa0030366ebea0cd35de5f5023d838f3c92fb2ad2f36c4c3c82fbbdeda6eb7ab4e2473d034c78eafef0f1bbf1f14dd18a9ffae34a36b28090f22a3ca60c52dd209778cebe64bfba963503208589e1005799af36d778945c8211bc4d83945638f7b4aa993592df7ef7c6f9773d93fcf430459d0459c8a49a359659174556c7d844fe8a8e4e5085f4f0dc2aefeaa37d8ef5363ad00a5e12efb3fec5bbfa78f669f4f228b4f629108cc6abaab664e5623392da9f33fcea6e27cd5f34e040e9bf59b05c25b61d7ca1d31d1393ff3a009a76715729e62bb9646c3fea61de243b54f6ba585c968303b42ceab72a591a6cbdecb082e130841dfbf04049d73e31282b7ed18cd4638b1e358bb809c51bfe53fd43855871d9a1366b224199ebe4fa45b948be2f3c1fa986cdf0cdcc10fadd6eff4d1c325797578f9351c4b0c2bf36f97fee6a8c5b5162cdf9bdbd170728d34e2de9a9721e101a8ea57f1ba8b2994d8d66a784f9c843f85cc38c94ed98d864d22718f76b7105a3cd6a5822d2b688121ccc6f81128ddb5f2d895ec637b8c46aa4e3ff76f896894decc489a00bf4df2c133517e483f66eeb5aea11cece563b1959771a96a5a80498cde063c4bf82e8644cc9851132ee09a86053c0b31c0d025a20c760a4db2e46087b4f0ec82aecdf896f4835979bffe63fde207235dd7501bf9f7ed25fe6ebfb733200af0b081a2d25c800f263e4c831b7df2bdb76a8ddd32e92ed8a4117803ea8adf05cf03887a5bf0245ab609cc044a56eae9c690d692505c4696bb216cd14f59fde7ff68b6ae367796de6b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2bca71e020b3958cbd9f5bac9aecc60531cc5c734617f88b8ec772c46f6de6c7e6fb4e325c589eb3e9128769b9b5eb1fa796db7c279f90f0338494384a3a7910dba06d00d6ae03de7bc9affdecc7bfdb0ad3f596d349ac5a9b70b0a7fc6bbf0cacb43b149322365a0c40cfbb961893c6e6844d4a70f4e0bda3a2da6249c39551522b6de4471a6105c1da5af502e0298d1efd3732c315cdb03889b5b3ceab67d010911baa1e9dc0b0c9637d7d93df09e7153fd1380c3499e5355649c61337f98b640d629434bde4205c20c42571c33fc98e5b7fc484ef24b7dde4eca65519d913d93f8c9c271ee1c17dad044a0237ca3fbb808ec0c49a8eab69fc49f733b5ec900e8b0debef8008acb168465e43f02d1c859046afc83f57d014e78100a21e243155497c9de0973b635cb3aa2a6f3ba67aabaa352e2a15ae04c58746485e3466f0547e849ae208a3324cb860b92549b0991c06f9e11b9a217e4ba3044248e40474ea9a5c42f91815afc8c60818bbbfc373adc0f6242d1abb82fbdda55200c7005992558320f3a9db3be8fc90fcda594f10b1288088a96b261eca79e23462878bb8c5b62709d8b46d03f19cf6ec2ec68a0cd83ba7823169b2bdb43739022ca97ced2dd57bd65a6546b9f9321fc23e09e87f104d2bc420dde8333aced4c27f41c120c19102e78329923c9797042ee33db6c85bb9272f34e95643e17fa46bb877ca16020278af64540d1a66e36deaa4507d8061d00199a7f9ea47436198a610e54d821dbedaabc8b8903ce15d680384dd13842abfac1283554c82fe52f104faa590cf3ff5a8cf8bdf0e8749bd31751fa760c557853f82393756c6800f8651c17c7126575a1c6bd784b037189ea50f2d5df0d111171f0cdbf080622cd9f6fc101f80216978853bfbe076467523839b56aa0e9fdd2f2d6cc231746b529f8e3427dfeea0aaa910a421aa92ffa1e49362e2ee1ac4c9586c11482b3bf66a260baccdcb252fbbec17c081be90cbf31a2a2f8a81b86ac526ebe25a072fdf3ff6b849d0a5563b7643983df7d024ad9a7e62ebdb0c662aedff94574f26daf8657ab95698607230ff7221d3893db9125e567aafa9980aed8a8297856e9ae265b654e29099a48064d6c3063a52518724b4950e13ed1a95d54b5ec999802419e76942f7f7f1409fa825ad3d72921fbc531594f9af221f727d93ac2022795517be4f4904f87b7cfbfa6e759bbc3c0b61090a5c0d85c59f6938b90ffe5b3cd6e99934b692d3c25c0f211842e9a2fd9c2688d95083db659a202e6dbb0d5df8200ec63ff5e63629b1488ee35a60badafdc87a5f9bd45315ca78c711329a2d41ee150b195a22bc1a59686638796978b7a9d3709e9c181049fb7ec038ed296da30fb12fba5c1ff35c972a0527fd53b7d005b170652c89065113c16cdb37548b6ab634bee372cf986bf71cbba2b1bf3f0410f33d9f565fe89a56369651eb7c3eb94fdbf9412798b114a833e4bf69e1a0f345b6561e8370df0896acd7aa5ec79f7ff911d715da53f779ec9d3cb7655fcf0895f83f188a5900cd02a237a4c413b872c362afa0ca098570487f02e247ff65ad16dbd5f13d5e6d49f1ce81ac7e98595abcf949261984c7f5588e31e772e8f797762a7df18c43853f1c42ff475140634b00800ec98a541aa1d2b44a1d6b800c5f2f82e6e105dcb601da4eb69719c6cdfe5adb1af98109e8d02b226d34c7fa4c71fccdd4fc68af289008e2ec044680df28c0291a6ca86554b35c9525a9555d16b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2eaea2376f006580e3628eb4179704f587b104420de4e0df8f2cd6e872eba6bfdc149b8d7bd2626d7cca367af16e699a9d59feee39590cb674e01b60f79dccd9bc7a16bf408f15723e5b75def1233a465ad27f839bd9aaca05e871db1fd5203209158e327a81d8c4ac5cb87ecdd3a470b49c2cfc5a55e2c97fa773642156096c664e9ee894091ffa4f3472a07d0cf3f318c3ef21d60e03e28301ad4a8e007b9d7245592533755a9ce83938a88242575e4cf2ac9408f67c0d9ab2b265f91a92aabdfdb6241185f91187b05b1b340d429422857e356eadef470dda05556b15987879470ed6ce108000e1c21f6f6ce0b301ac43e33f9a0fef0a51b0335ae6db12a19fd42a2ffc576e51c13dd2d014d0457824a7a8472b77015b48a276d954318e3eed3a5be4d4cbd20d724cc1bffc29276e7b576f3d28df529d892b1fb7f49c0300df572e660032ecc31078d1fe29346137e1c14facb48ae1368e8bc7b4173e94e034119ef887099fb754d119d13dcc9b58be3828f86e94b8f3e3892697492758702b69f6d234786f55d9be7e777b3566de70a91989d3fcde859c2fc604da09c6ec4697ae72f07ae312e236be0f5e3ddf0c3feff19da67bb8a4c5a86e67fd3d0d795b2641d4e5b61a6a5a70c9403a9c7469b80472d5ee7dc48ac24a283666031a4f479b1d3f9eaa1f0316c14529627d8e5f655abd1f49b4feb6c0466dc76502aa8b62b1b3090cf7d5e78337a688006744dcacba3caf52c2c56857f95d1cb1a39570f5517bdf7d928f8c6c58a3b11f56615e87c2a51f446c4c4a42c7ed2f951366beb1dae4d5e525c31e052f905e1a15d032c273ab0678ce60415681db3053bb912bbed749bc8ba89eef53baed0bf6253baeb3c6313020ce0a4ec926c1123b094162c63f716105fea65ffb9e969ef771e2f2b212cd3eb0cd77292dc0fb51bfd43cd5b3d976d2b4ab4655e9dbeb4c2ced8de0cf94f7595cf69c4ee849b543de4a2eecba77c92655500b2550485195e69710ed5f5a60e345429ca084b04f5283bf35203f9fc88b33d371fc497e07587ae4d3490df2eb74f3fbf04a17cc36b3378c87d038e169378b717f1f1ba532025929d25538f00c17d2bf10fda9af2a8e314e2d656f37d8a1197304c69ce510c33221878713a632039da2954dc07e04771cdac44c6eb7443eb386c1504b4945a19f5d6b89e3983d97c8b22f6910e40b667bd0d243fc966fe16aa9d2fdb6cde5eae005d8e5e016e57f4ce13d917cb034fd915218eb8607d4a20663bd4cb5c0bdde8b21d16f0c16b29abb4432bd9a2a465a91b9e75b84d5e17fd8421731a5b709450b73954baf4d3d48245575a6180224479ba044362f335ef75523d67e874d4ecfadebc28dd2ef2ba8cde42532ee8bc2150ca665829a97aa1f76578e67e73be6016a8a4a2ef6e7888e6e9875c8f728294d95af4e369bc239aaf1249075f7ce6e76f8e039cc160c48d71c683f930dac05653e7c817e2478c1c0528537948e446990e51099a21033fe0ed43db83727501e4d0baa3aac9ce39c83e17dce22920c8c4783fa311a57e35ec7fe73cd86a8664f19a7b50279320e2c0a03844e191caff11cec4351d3c278c56ad523d4026b0850487468975d2b42c820cea108e4b15e23ee7703f306ed360f4d5ece164359fbe81698763bccad13d58c69e5f4b5a1728602798575d62f6b19632fbc4920b06ab34a5a51a3337ed7160b24653e35b8da5f0b483b3ed2fca8630af8a1cbf04fd39877baa1834065f9f") + common.Must(err) + quicHdr, err := quic.SniffQUIC(pkt) + if err != nil || quicHdr.Domain() != "test.example.com" { + t.Error("failed") + } +} + func TestSniffFakeQUICPacketWithInvalidPacketNumberLength(t *testing.T) { pkt, err := hex.DecodeString("cb00000001081c8c6d5aeb53d54400000090709b8600000000000000000000000000000000") common.Must(err)