mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-10-10 12:13:10 +08:00
chore: let the sniffer assemble client hello across TLS records
This commit is contained in:
@@ -455,20 +455,24 @@ func (q *quicPacketSender) tryAssemble() (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if len(q.ranges) != 1 || q.ranges[0].Start() != 0 || q.ranges[0].End() != uint64(len(q.buffer)) {
|
||||
// incomplete fragment, just return
|
||||
if len(q.ranges) == 0 || q.ranges[0].Start() != 0 || q.ranges[0].End() < tlsHandshakeHeaderLen {
|
||||
// The beginning of the CRYPTO stream is still incomplete.
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if len(q.buffer) <= 4 ||
|
||||
// Handshake Type (1) + uint24 Length (3) + ClientHello body
|
||||
// maxCryptoStreamOffset is in the valid range of uint16 so just ignore the q.buffer[1]
|
||||
int(binary.BigEndian.Uint16([]byte{q.buffer[2], q.buffer[3]})+4) != len(q.buffer) {
|
||||
// end of segment not reached, just return
|
||||
helloSize, err := clientHelloSize(q.buffer[:tlsHandshakeHeaderLen])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if helloSize > maxCryptoStreamOffset {
|
||||
return "", io.ErrShortBuffer
|
||||
}
|
||||
if q.ranges[0].End() < uint64(helloSize) {
|
||||
// The complete ClientHello has not arrived yet.
|
||||
return "", nil
|
||||
}
|
||||
|
||||
domain, err := ReadClientHello(q.buffer)
|
||||
domain, err := ReadClientHello(q.buffer[:helloSize])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
+139
-31
@@ -2,15 +2,60 @@ package sniffer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func makeTestClientHello(host string) []byte {
|
||||
serverName := []byte(host)
|
||||
serverNameListLen := 1 + 2 + len(serverName)
|
||||
extensionDataLen := 2 + serverNameListLen
|
||||
extension := make([]byte, 4+extensionDataLen)
|
||||
binary.BigEndian.PutUint16(extension[2:4], uint16(extensionDataLen))
|
||||
binary.BigEndian.PutUint16(extension[4:6], uint16(serverNameListLen))
|
||||
binary.BigEndian.PutUint16(extension[7:9], uint16(len(serverName)))
|
||||
copy(extension[9:], serverName)
|
||||
|
||||
body := make([]byte, 0, 64+len(serverName))
|
||||
body = append(body, 0x03, 0x03) // legacy_version
|
||||
body = append(body, make([]byte, 32)...) // random
|
||||
body = append(body, 0) // legacy_session_id
|
||||
body = append(body, 0, 2, 0x13, 0x01) // cipher_suites
|
||||
body = append(body, 1, 0) // compression_methods
|
||||
body = binary.BigEndian.AppendUint16(body, uint16(len(extension)))
|
||||
body = append(body, extension...)
|
||||
|
||||
hello := []byte{
|
||||
tlsHandshakeTypeClientHello,
|
||||
byte(len(body) >> 16),
|
||||
byte(len(body) >> 8),
|
||||
byte(len(body)),
|
||||
}
|
||||
return append(hello, body...)
|
||||
}
|
||||
|
||||
func makeTestTLSRecords(handshake []byte, cuts ...int) []byte {
|
||||
records := make([]byte, 0, len(handshake)+tlsRecordHeaderLen*(len(cuts)+1))
|
||||
start := 0
|
||||
for _, end := range append(cuts, len(handshake)) {
|
||||
payload := handshake[start:end]
|
||||
header := []byte{tlsRecordTypeHandshake, 0x03, 0x01, 0, 0}
|
||||
binary.BigEndian.PutUint16(header[3:], uint16(len(payload)))
|
||||
records = append(records, header...)
|
||||
records = append(records, payload...)
|
||||
start = end
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
type fakeSender struct {
|
||||
constant.PacketSender
|
||||
}
|
||||
@@ -105,6 +150,7 @@ func testQUICSniffer(data []string, async bool) (string, string, error) {
|
||||
|
||||
func TestQUICHeaders(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
input []string
|
||||
domain string
|
||||
invalid bool
|
||||
@@ -112,10 +158,12 @@ func TestQUICHeaders(t *testing.T) {
|
||||
// Normal domain quic sniff
|
||||
{
|
||||
input: []string{"cd0000000108f1fb7bcc78aa5e7203a8f86400421531fe825b19541876db6c55c38890cd73149d267a084afee6087304095417a3033df6a81bbb71d8512e7a3e16df1e277cae5df3182cb214b8fe982ba3fdffbaa9ffec474547d55945f0fddbeadfb0b5243890b2fa3da45169e2bd34ec04b2e29382f48d612b28432a559757504d158e9e505407a77dd34f4b60b8d3b555ee85aacd6648686802f4de25e7216b19e54c5f78e8a5963380c742d861306db4c16e4f7fc94957aa50b9578a0b61f1e406b2ad5f0cd3cd271c4d99476409797b0c3cb3efec256118912d4b7e4fd79d9cb9016b6e5eaa4f5e57b637b217755daf8968a4092bed0ed5413f5d04904b3a61e4064f9211b2629e5b52a89c7b19f37a713e41e27743ea6dfa736dfa1bb0a4b2bc8c8dc632c6ce963493a20c550e6fdb2475213665e9a85cfc394da9cec0cf41f0c8abed3fc83be5245b2b5aa5e825d29349f721d30774ef5bf965b540f3d8d98febe20956b1fc8fa047e10e7d2f921c9c6622389e02322e80621a1cf5264e245b7276966eb02932584e3f7038bd36aa908766ad3fb98344025dec18670d6db43a1c5daac00937fce7b7c7d61ff4e6efd01a2bdee0ee183108b926393df4f3d74bbcbb015f240e7e346b7d01c41111a401225ce3b095ab4623a5836169bf9599eeca79d1d2e9b2202b5960a09211e978058d6fc0484eff3e91ce4649a5e3ba15b906d334cf66e28d9ff575406e1ae1ac2febafd72870b6f5d58fc5fb949cb1f40feb7c1d9ce5e71b"},
|
||||
name: "single packet google",
|
||||
domain: "www.google.com",
|
||||
},
|
||||
{
|
||||
input: []string{"c3000000011266f50524e8d0fe88cbf51e3ad71a13198235000044c82dc5d943fb34cc6d5c5e433610dc7a44f5951935c2c1d14ac641b02472340a892c4492dbfe3f8262109108fc36d96bdc1e9e46b5f1f6ef6104add2aafbfd8e79246eb3b4637541aaed7d195571724e642ab4d31c909f1db86e7d8516117ce8716bd1e3acb664c499086b0f3bc7258595420e7bb969f934457d195e832ffff4ffddf11123eeadacc48190e356c8f0f6abc381deb7e285e3b0613a795b19bddb9f002ffdf6fd70f0ff2072302b33d2421aac6540bb9f0e85c7237af0dd56225b2264d769160febab952e64bd5155f23e58c6113891143f946591032b41816aed3ac54f521f60605f86791de24c5765b664c1348cc53d5d631b4bbefe1915f2b21fefafb47badeb72d8ba1fd5c3cfeb0ba9d0112396f170e94cd33952c4fa87997b870931bf1a300e8e127f530815ff087815b4f9d004cbcd17013ac143847572a1655a5b36e054e8b9951d747c2c6ff25d7b2edb13a2a6b8074062332f2191f6830cf435a4ed9db5d9c4eb43a143bf3edf0c48f6f9435dafad4afb743a5a33990379df953ecd388e848aff0ebba9ccc052b8303c0bd1fee7e7553af1894e81b7772818bb69249540ccb8cfb47b1517abaf71c81c3bd271f1a5f1b66465f850f377c9db682b8e543c3d0c10fcd2dee263630889b7d1d521d1d27e866ea4ab5f43790d6a7f76ceefd5783678ca92cc131fa42fc4a01e2a81cad734ddf17a53e1bda8e0a21afc9e8c1118c9459b13519f5b3c3d9692c92234f01129d47ae8ec70625170847472801190b46d36f73b868f55f5a18a3cb05af6d38610e0829e4fbf13ddcc202341702e43dcf33be76ff4afe327e5783287c137aad075752940b41e7d9f5146e36d908897c6d7a9fdc343fde2d9c9d6e6a6b237669bd3e6abe0a732861a679eadfa29a876c6a646953c9361830811b012b26b31c9e7158f8de9c9a108346ddee3dd3886da6258364c1281bff8e055f6384e3a23e198b5e6b726fa7f811b3338072019d4b5fd05891770d11e3ed6ab5f7ed33db1c6220c5aa8fa1909949ac55d5435b75982e17aa80940fa574f0aba4dc340129cad491fdf1f5e05c4e83e36ad29ff38f15e1c9436c792024442f57f07583d671dd05446c84ea20b471303f6ae4e5e13f244d671e0ebe94d3d5c17d3f3f378cdd51fa8a6d2c977c78a2397dd1e251cd979803d617d45f575e5d9db0a28b3c4c25fe2af24af5bddac09786b6d6d8aa19cfbd5409bdbfed7d518ef5c863f3ee757bd9d37cddc546cc57d2e52b6ae58789f297a300f1d76c3842603eae4b1224de31a939a68875c86e697aeebf7ebc65568f43fc681bacab830ac4a2164d324e90067125bad702192d01cb3cb3d2689ae681967e86fd7ac93a25cf2e905c88ca5ad7d11962f021754cf3f61224517bd3411d5b5a83955bcea79d702466d073a6eaadc1202b3693e555b051a5b19457023a01e7f943742bb7f5f8aeba8d4e363973aebdccfb12479619cfb93e833be702a307e796dc7431a48abd9b755b392c510b98cd20ef778e2ac88d6a04f23ba8a253d7eb7c13e0c88c3a21f7e23857c58704d139703a47e0965bf2dc8810dc36894ac1f3da73c155e271c106a718b2d184e4e5637c820fe909984642960edfc9e62ac50af5dd3feee6bc560ced7bda676d4e290c9c5916fad52180bbc83d3483e95c79bac15c209936f21042dc2b6253eefdac06e7f4745044eaa0acedabf1d1c8cd9402738"},
|
||||
name: "single packet cloudflare",
|
||||
domain: "cloudflare-dns.com",
|
||||
},
|
||||
|
||||
@@ -125,6 +173,7 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"c70000000108afb466a232f7f9f2000044d0168a15a021477ecb9731ed77784d42301462e2d59b0395adc1fa6b569d428583f100860d6b6ae29b6c1b8c0f9c0d9081475ff801f34a9e0677adf685f02b1169fe86c683fb51934915ff43921a73b98fb0b734406f8dd90ce6060d75e923b0d3c738291b421bf16de27ed4785d727ce589f5d0957c413c81d6ee75052e3ab50fe53f1abbb24a138a52e1412683992ad769e65ed301a736914843543e2a3e11eb395726d4fcc9283f8607b38685069f63d05ab8bf38aa24d4073a1e68fa1b6087cec44d7fa628342e9d88a0d20b381014cdd1a07b9d913a3bbcad0cfbddd0560617cf26054138075eb86e06db1e68781541587302e6dda86cae779f9848fcefcc33626f8953bfe4dc293d23e74c87020e79e9ffd58ee345382bd4d1d6e5a3389b0a977124708d05e3c305545857041734dc7092901ab54604b3750b3139dd3b8f2bd94cda89d85be3756fda6f0cfb6f66af3d2e36a7808ff7bce271a0272f8dbc88193ede31613433985cd35c7bd9b627d434e7b2e94b38402b8f1b5619a903572dcf4c2b864c6ee66657c9ec81e03fbe765037f83b2229171888ba08651fc78a1b50c7cc52f6dfe8273723e08932b1a16a6b717a80b5520cf3f40e46f9d9c350eaa914bf99dd4ab700cfdae21437daf695916d4f3121235e4913e0657d8cdcf4afd8f2c7ef977a2dfe49f46fef46c8fa6932e745311d4a6eb3124d5e0a204b9e3227e86a55e662f7002d4f4a72cba8c77c3adc3eff076dfb9195cf68455cecbbfc9b5444d9c4a4775bba68d57ff52edac6ce6ff4efbf6466579bf68308f2ba9a59b2c09506064091a86af621e9dae52366a90599db0d64a23944bc48966b6d3ab8e20f4afb5b0e94370d26a89a9c4207b454554e58ac74f62ffb3eb2686eaa596b9610322a5ce8eeb42f2ead1c71b11b51bc4f1800eb549a2bb529ca4a0d165ae461e45b556b2365e9459d531489d59d0dfa544a76c5c00b0a01270741d4061a331c32fd6cd0e68bbce49137b852e215c9db52f3e430416d8979520e5270be324f3d93132358c0eac35a4618ea7aad997dbbd8e99d4ea577271b935e3fe928f90abd94593806d272a565a414686b8e56c28e34b77671de6a696b09414380bc658c69a309d3225ba8493e9076dac776c845ce11a7ccd6cae58fba5434014250f3e211058b2efe3424b991d679a02ba949b086ba12144c7df3e049b5d026f386e4ae712c9b0b4b02730dd6862ed4e72730224cb6ec9101c5cbb7ee4fc30d497bb1dbf74ffdd49d8cae6c7c9a364ede453d9ae25edf27a2153ab285f3e3be66b2968d67a56480f1f74c4fe61dc69db3451f5b113d7ca02e5afa8627f579c07a9b1814853fb8fdaf0c0f220f89725c757f5617ba4e43cb4f3ad9ce18f48f23d10f9e8950b0fd737070655730532896d93df8768860ebf941365d0634db399feab1f8a88bad28d25e689c5a57321debb8d1435130e90a699e17fa5255f2063f09659a432e9ab5f89eeabe12756bfc5e02fcae2b78a9d0f570934b8d4af8f4afbd57549176f465a0cea485dd89c95a8ae915b4b99548a4c939710c16908f968368baf5f547cfee07f3cbb6142041d6e6084aac253a0d3aeac628cfe76f87b94c3806cb14a912ce8e4981e316511d5ede36f526805d6c3fab5b72d9d91f4eacd26e28cb181ec66611818f5c206ddd52488707a940dc12144ae825d25929bc32b718f46e471fdb30762d299b45c84f6310a72b60",
|
||||
"c20000000108afb466a232f7f9f2000044d00582e8683e329a63e5bf4dc93e93e325ff661e74b9cabefdfbf6065c7ab203c8a629534e87e5f2d4c0f463352904642358b8f137e99802c3a26cf22235782a777769ecd134c6b4d0dce6aa10b485c45ccdcf6deb805342e99ef97e2777aee0b2a44073843fccc2f8eb837031f76a8e968cb01c13c1268af095f54f860958e4062a84e2527bcc9b25a7791650a844de1b0c4b2476282a0e00c9de9d39a41914d1e797a88a8997b96b25a4c194762912b2ddee0e01a365f1afa1e82ea266c14ae94e47c90b5679e2cd00e63ee5a834505ca33463751bac22f3b87afc80099335dc7bfd12b7df224a23ced3d2e25b58a04c4b5cb089ca187abc54d782973c7bb157cc515c7508431ff5bdc227871da58b9ca8a9a576960f38edb384112b08e4c70672a6f23d17d9d901342e56c12370deaaafcb22810eb352f1a6d9377e96bdc1ad4dd397dbc6a227b70f204c1a4e9a4db2705763b82ec4df1fab11420aae547155c6b49abceeed997ff01b7d24e369c65f7edf18665d067c7d2bda5ec8623281fce8c77d893cb8a42053756713e910894a58ef5bf3d9f3a41071026660dd7cd05e1640767ec68f78e22c1716700ca9c0f076f90a65cffc394c10a32071c6532d07b59414181070d08c9c84e3d13842718d51bf90dd36ab1b3f708df7eeb3939dc8553787308983c3e9ba971e7d447788477a7140196c2f717b9ba4f5da92d73316dd11c1d1830b4200f26f733a6c65ec1cc21549b485e3a43dc7a2b68e95466a53544082a20d9a43387a7ccbfd353f7e590b7047f13bfc0d91923c2d75dad4f8091ea96502f98e83e5c30e52e4cd5c670f6c2248ce37cd6ee8b3970531fbf0c53c5fa9a0d73200442b755c91fa4f70524ffe8a36063b6709d3aa9f6b53eb0aaecc57a8c8c9a7ac5e57e03e9cfb290b67dd8222a245ff5439914147e2799fd1cd2ca2cb22fda299443b81e8024adc59d098058432fa4bde376b8e59075f6b86427b4ef6cd7c83b5c08add0c3d3543aee8d672c41cb287c1f0a17f1bc30f62a57490afb2d9f401bf302fd473ddbaf63f6883221579743d6aa1f386b8b2f5db06d7d6c36be81f29fafd14b82e863d744f116ce2be4921631f1fb2797289fffa9ee16a3e537ddfa52350546bc544459c0c9d66fdcbd41612cfc0e2744f50927983a3224291c1ae51608fbc00f40c60ec72573a7e128c3415b0d9a7db52de8ff763dd66e2eeb03ef2e67838c9e68cfddae4b86a3f34a69e0a473b5a73ab627282648df7912c11a4bf033ade185a8f438036b99b960aa6213c800abbbd751248a7ae600357ab888433125d49c5643705ecb8c86f2980050edd7e3c579ad6fcae9bbe2c8d8b38004426f35eadb543a3bef42355acb1b94c21d7eae7b6ed422ca0d58fa03b227b035628871465ed6509254c8a3bf43dfadbb247ecbc52d80d65e9c03c4bc7bc35a829502bde3868af9c33737cd88d70f7427790313eed4ed1938955c5dd360212ef700f274efcc8c26ea94c4e2e0937d475c5c4909edfb66714d15d12e153e5586725ce0c47e8a1506bb197366754ca8960508f22fe7b83a5eaa40f05f3cb87464dc6b848080c0e0cecf2dae82bfa42cc6f52694478dc3d00ab0e1ed696b98e26c7fd34d2efd969f83e284c28ce3f27b178f4691c772011f61722266153142dd0d526393e6c6848d201115b256e65f12b911a983bc2f96a5b4b99f63f0b58485a521553a3e1d4498ac5d4ee70c3f9",
|
||||
},
|
||||
name: "fragmented nginx",
|
||||
domain: "quic.nginx.org",
|
||||
},
|
||||
{
|
||||
@@ -132,6 +181,7 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"c00000000108e63b9140d034563d000044d066e1913892ec1d84c179dfa9596e0ce930171a134a09446a888d9e579a6f7bd77df6deda715b028d64f7866603c6deb468d60ecc6488b5e5ee2e2daa1840b76ead998023593c9ebc4178ec89cb198d3c79a867e27177a74ee5f3db74ea194e36e328047ffc3890192665a6feba09ba1e224967fa9575dc7b094e1c29c7f3be9961ba62e3e063f674a09786b7611138e1edaee32cd1d47839e840a74f25ed786463fc48bf3d38a4c793178ab7cbf5a3eb974415b9f9ef7861dfc73460594332f5545c7b7037043afdfc1aa62ac3dfb76ec2c6ae8ebd351f7483992c762d6483b3e2c1454c8ed939ce43f858ccca22d9149cc9da16af86a010be7f3248cf19fa442e94d625ec7f7144b01ac9afb8fb8c595d4cd12fcd2b2d9986371ae65f6f216bed152b79d2782d60f1f01e06b359f88900c4bb3f987f3ce336854a5beaaa616813af4e5f9bd82dca0af6886b544fff0261807bbd8cf90213299f5802b98edc27a6606be8e2bbc18fa7519eac260dcda139f164796a082908459c31aa964a5d3f6fed8944ad61bda126991468f3b7627f2470179619864f234a395ea3bd4f7ba4c0cdf9f5f0dd95d7d59476f2d2a36521c13886265a2fbbd4345e8d1d1e7b5d01a58fb11de23730b087e2b702200155a1ebd50db5751d279438822ac158173533140998a3056893bf470ac84720cb37a4a3205fa88267abc56520bcddacee06011d929c3a114314822d8ccf7cfef89f2fcf0a4fef800afbfca4a62ee848f22066f68c7d3c5c9a24402d422fc2fd5da6d3b470b0ea253f12a883705f7f78bd67006ade4f1c8a3e8fa052656b5b40dacd8062228871cc3bfb1a9c38472b0a720c3c750430edbcbdcecd46b144dfcaa009fee06770238d0270e80671e8ee5f5df18b86dfe8df2f121245c0710ccaefecbeda0ba3db945c768624dc38f21a4ac53741f4e58a5052f3d667fc466b69905f05d0843cfcb830163fae18dd1eb0ce62a59420db9c44958a0eca9ba4258c8060a9956343f155da6c55b2060427d07d9e311729d2971439c7541ae2babfce25a3f5f361fde86c39ef6c04e4e3cf7dd70c9cc0758ec5db3f0cb368e2447080af51c8a5fa6b84ec3175d2d3e6d877b6953e433b4e94b52e1a5f2a1ca37124c27e47f9de5d4c74644181cd37f3f3863ca529c0847bba91c246dadba94b4566b08eaa06a0db4d58b8cb0c8d3070533306a3089891b24a7c4e11b3aa50d5628fc1d136388e8bfbc420a6f12701333ccdc95dec25d09ce25fa4b654260965b91f05b1542c2ee02008d01de4419f14d6749c4bcfcc45a332ba0772def720ea3c8d207802418137b733e779eb406dace0b4b5f5e5e14c787f3e044e6d8160f90fc3c65bcc7f3449205b63294fbc11e9bb92c007d1cb59183eafbf76be9680224cb442806500d71870777d087bf864890848f4a79424c02304f2a6ee2b07f9257f4a2f185ee21239625e246cf680e74b85d292cca44261c6cee6da39bfac3882d28fe547a500f79519ffcd3f54ff5a905c99f22a5e8142c903c41adbe1eb9770b6cf554688529091b126ed2168a23bb191c2b89728e31773623bc58bcb9baebc2c664c79d6ffee7e4404e039723eb05e7f7835c87212431a0131603fcc3fe090cc2fda8239b8f42188b35f98d7fff949b3044544b3bb962ae236a664d76d0c751d9c9ed1271715d240f111febdf7045502f2afd7de8aaaac650511e7bc7716a5b6622ae925abb7",
|
||||
"c90000000108e63b9140d034563d000044d00b2498988864d8b7f59a00d26165f5ae638fc9b1c12d546ffd86212ccd85f654259cb8b8c9d753c696ddad7ee4847bf3b3c10063606cf3972f75e17ae23e73b6a3029f23541f674256d19677665cdd0b8ac15c3f60984bc14ff5dc7a9ae37395516204f2020965713fccaf35cb0a5823085cd6211d681dc6b39be9db46cbfef154a2b9049ed202e9088961b0b710e94bd73259b0967e4d6b8cdfd5b72774fee2f2ceb16bcafa010f247c43b0a9ca25578e7d45bfda7edb82e91f8e1c0a2cfa990223bf97ece42862d3f329521fe2d12493b717f174f966d173102e5cca10943d5b612101d65d0dd48b44416f9ac1eac4575558ecaaa39c47ade2dee6e25fd219d799b499143b47a5bf449701b939c1dde111349cd0d63efd2ff74fbd3573ed40abfdb2310e2740da40fc50c7a137a3f32c3a26b3d407f80e669fe7f9a3542fdd412a9cb53f845d9c1af0814377bf92e30f05ee387fb8675807a6de083c85d3d7860601c8170923c53e5773ee388b68e510a28cd7009c485bd4cb861eddfdd265de042e5a018d20cb810614e2bb17b0f52d6bf620a6f173e0b41951e1b83ffb29e3b3b3c5d9fff13acd3b409021195201d003e281d8cda7b0f02c273e17b1f9b9e8cec4296d65a1c4923b78a2e4273cb42e4e159980472e440078e542eeddcc5a9bfefa5a72871fbcd9ebb74fef20a50215bf75cfd8572d5ab9ac5945e8d6ca35884caf0af0446ee9aab0a1cc3a452ec79c9de786119e63bb3a75fce0ae29c15a0c320fff87e87cc23a05e75b4f4b30b75c6aa036c4b6657f8200ea014185b31ee7fcd00d1eaf40973f347fae227f89d41794fa57ac1ed1efda3ba840ef27852cf33a9dc9e2d77b56af9ced9e75707837aa8c5395cdc15134ba132de87152ce53d506c53284dab912bbc276542504cc94afaca71a5173ff13ea6cb45b47dde9965428ba5d8eb968cc2a5729c2f9b8f1c1de208943a2cd565196e040dcc415d769ceb6300c7909d7e32bbbe83c4cbf4d49f6e34fe56b651838628f3a0001e99f39cafe45c98e455aff8d98f89942a862f7505b9f7fe3f64dacf8c574affacf91c2c05f094127acaa5187f9dfa188f67db421243a02e583942138c2edf45fec4c6b6a8a791da9055be247e9b252e9f7c1330e76f9cb3aa5feebb21f871315b5fb90a1df0b8056513b74daeb6ac995f85c64150ad115a14830d145e5f4e6638c26987b676a1dd19a9775df29ab442ce6143b0fbf8f8d4618084896e34812ed59d63041e2b4ccf6c959a6c849813dd926082bb7b1adedf69246547f335552bcdbae7e466ac31e07e442530ad114abebc6f58015b786e7f35644307fa7ad3d9248c56c8ff472735c6911da1843fe53821b8f5180f8844db4a9f7a826a919fd93c4db4d25861054929260dcdc46d085827c46d60f1097424a6ef250f5aaf3235c80230eda4eb580ce93e1ac8aac422a7aa1241562af601981b84b74949f1c476705c8030eb5d447b2414f9716ff3fd606cd750030b94345c016078bdcb97b7ebc24f661fbd08802f32df18d6a2aa85bfe2e9b8dc76b121c44ae9f29e4413051b527e99fde29720724337476c0eff325cb6220a290a9eb852151c84836729d6a223032e2c638857d9e7f469b84d7d650c45e56e763aee73f902e82b055425c4568725e2d4efd7fde8b02906bda48af86bf47ea27ff00f4528494b74be9bbff001cc841449a184a4e00d64e51a72660a2c21f704f",
|
||||
},
|
||||
name: "fragmented openai",
|
||||
domain: "chat.openai.com",
|
||||
},
|
||||
// Fragmented quic and 0-rtt packet sniff
|
||||
@@ -141,6 +191,7 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"c50000000108c2751a596bd51c6e000044d0538af4ba75e226a6fc7f43e7f1f59610973b8a6670bb8338ca7ef7d90f81aa59f179dae5f8f6dbd24ec6fe576b28f6ce6cd46f26de143b8c99cdadaecf2041948a61bd5a8591486e10022fd100aa20e6423b4f4ca5773edb1aba79b73d6150ee185e66da60e658b2a698098462122b6b80c7fbc5542b0b8e9532898c1f31aa2ef55cbdf036d74c3069abbb261660f048d950b00b7db279ec2bc39912102679ddbffb53f1b1921f137fce43e164af86c72908532f4cdc48eb462a9d9e9cdd6d3c3faaf8aa8aea312dcac5d6aa75b1ade4af6901576649da7e3efd4199b92107d7acee8bbf06734b2484957c3d8cbb1f3fc0ccd56c55223628ed8ea514ffd101bac370c97b28c7da81175ab0508c0002d458cf41f7159dfce22b447c1ec502c186b782c1854718b7fc0fc39e5c09aee31113fc4c5003803fc27ca48850c08a54dbbfdef6ea9a6a138cac0ecd045cfd5607cb6c99c39c0cb21778857f97416b78fa7c6ac8ae3fa2ef2adb3b85fe3fdba70ef9265bb3d54e56ec68b8887d54d02d4a571a6b793ae4df8ff171c881a554b5c5a7848351d446ab94c90ee9c600f03b785fee6300450a4ffc2a55d417952e15449a491296d463ac6942bce4ca93c99440396bc8984073ec028b11ad412e97e26f9248031dc4b1a6ae385803bb578fa1a3b3a58a8ef19c6c511f17b28a275e8c40e51fca8f410a4a1879b5d8749a44a6a9f97c0c9df25318cc28fd0cc61eea78ddc603a17e74eb542c8c08cdbaafa3b44566db4d67e8d1429332375cd30cdaead9594c46d8ce91bce9813c3ca23f55ec2f4dd3ff141471bc3df590367bc65e4830018ff7d845ec4987d11e471d114c48acd1ae9b7670341a34077ae59ea6c3bfc4675cf419d37db48a98a5573b69867039731f537098b46415a193f50b2c85bf9e5da45d6757c5c366e21f04ea62d64b81c28be5148d89e53535414067cf609e59686b7fd135f5cb473e57f6c82dbb291308a1065e0f755935d77517adecee55e72cf37ecaab1b5c0c6e0c7463a014e7e439757913f6e43abb6af775d21ab6e43cbdbcd1935a000cf8025ebc11378d86d6f72d51bf2dfe4be1db5d3b0fcacd13e1b9fbaac6e9153c3d1f4e876f2fa9c3cfc84fd0910b778105b66be70827b1830b7b3c9633af5d83ad527efd81498cbbdd112873cc5ced573e6579acfe817b62280c2122b582b591d52b96cac047bff91192a5cfc001d15c811e055dcb1c9710dc892258ed1ab5152af2cfc57a0b93205dd41fd82b86090b4281b1493a8828ebc96bbd603b888cbca4a15799a5f3eaef93655d5609948080ca57c696d0ffc9a07665bdb063b547bb5a862c3b058c9efb2e7b79cf405fd83efacaa4b8e3a1fd126270587119756562c03d69a9cb67550369030a0204e531cb8df91ab2dfa2e4106c590c59b1b13c447843937929a574d3ea1785db0d52b4b2eeefd1a07c69729bec7c2813c9eb1249f706b3cc14a3d489d6b42a641dfd9e91aa70c7d3222e154af2d7fc1a8f48e5ba11739ae128d1f32ff929aaf4b249df5ea23f7847301e36ffda02342cdf1bd9dfd1979cbd8de32eb8b1eb8c415ddd267efe53f54678d9fc32435b34b00ee2256d8b6190e30a280df5bc48cf9fd669a52469954deccb0f1da37371d513ea57f31ead22a34f9379c7931fd18286d9fde6ecfaac8ca2a9be79d688c5401c65407543c066532f6621f256551c4a98a86b543c576ed0f3254daa4915",
|
||||
"cc0000000108c2751a596bd51c6e000044d07b624bf3d95fb3b7299b67dd836fbbbeb05a51650f9b2da3b2695070a0d19ab0d5334cc04de7ea7494fbe6c438f4e84fa56a3f246132468b5b4f1ba0fcc0251cf278338e15fdd715d5bfed18c1f98ca3cd3cc7b6f904aeeea2914a8b998dd3ae7df694c49c1742dccbf4c3472ddfe2e447959655459c11f18bddd9481eb597b887fb3f90a7d0f05224a144f87a5fdad502ea1e46c1c9f4b4154bafa4542c026296040228703bcd020202acceb772b596bf788341cceca864c8907037c39739e511b04e8ba956efa0fb5cb151ac90eb5817444f6488d593325ad4466058ba45214b965c5738f33d5591624584559ba18e89913b868619d498072e3aa1f333f5d6e3d1db88b28adf7d9350c3c383c1eda894f36bf1bb2a58c7a5e5c8b20597b71a099e46bbd3d8894877e43b0183919185b4e9f059472203979d3334c535fc4eaedebebc79bd1e423184765047a50e6dcc76ba2b23ad23511cae2edd2ad8e7f7f302226dbf6c0e4dbc8c08cda26340b9abfef1ef3333cd511295f14c87197d7890576b4076dd9686047854e67733599d96a99194aecf7b927cae2e5fa4568afc71e748dabd3bd71e6c3984f45b06a068a7c9c3a1ca7b5c245a9bb2cc7e2726e833e283430a25b6ccad55bc5b7644b44f99fedeff3c3bbf995a0387cf1e45a5684e5d1c01350d0cd2d615ffb6d1011d80ad16b75925efcbee483e4e2c0e2386e9e1b35b5a107ed97058adb60e323342989559856faeaafe5149bdcd60c113230f9923b2f654c95f986944a014198686f9c2275053c05080e3bf9fab7d46302948b152e2f2fb1ecbe71b412016b3f25ae512ad45cd096d5f284a0c2808b5eab03b4b9b2dff4d81bf234e75e30d480f39a5f9737563e31a19b14d1038296915af33e0ac0dc18e9c871e539e8772d525e5fa19afc582b1c00ae573af39fe293e16d182bbe57af5bee1c0939862ffb62e3d52a60aeb71e4db2a4a1708e75afa5f37d72cd6c0e036abcb4eb8db6515fbbdf98be95d0a6d261a9445797a8f38c3579a2f04c9f5b74dfd1ffaba2c6aa05959704b9b8cb0db30bcc360711c5afef0d1e7c2b076466dcaab104c70f3cc0cda33d7a47462c3fa3d7e34a99b2d8ff3fe5cafd27ede28b9e09b547cf955b97b0d0d4ec126957601c6982d176252be422df3366118895ca25fe27a96c9c234d484fe98634fb9e970e0d2b096f2ced5d56603505990a65363726c828aed2df0f112e0c44f058424ff5c25ae60aa2cb5fdfa289e8ebb63908365aa4e4609eae87e567f1e86d92c43992e6d505f55226fe3533f9fc9c9facff9dae02a3e3c97ca54191bebab93881c0e89b9de5bb4acd5c6fed5b1e7978803f693bfdbc125b4d08fd34fdc6aaf02444c4b06010b0eb2f15d86850a7aa5af05af438f6b7345fad4315f631bc5b017c7482e7af725a09844472f48e4de79b15284932a7e99a46ae72b187ee3faaa0f31a36726056e86eb706bc8eac04b68a3302307a157c91639f30bafc2d180670625673310a9a45a171063011e59c57c8eb67353a8ea344a87853e7b600c2b49a7a1b60a2904c0ea55951af6430667ecdfa6e90a8d2d0ed9857ba5b876cf78af190d5013d16208d2b30d02cf2c23e6ad1466f76c30d11034d5d2eca113e2764b2fb6298fc4940c16d971e28e3e6e5d0e8eea1ccb9b4b89741ed675861fc3680457ee08547f4efcf68bb6247313f8218ae3ec372e51ba8786ecae115dcff241e0",
|
||||
},
|
||||
name: "fragmented with zero rtt",
|
||||
domain: "fonts.gstatic.com",
|
||||
},
|
||||
// Test sniffer packet out of order
|
||||
@@ -149,6 +200,7 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"c50000000108b4b6d5c8b9a19769004047007e07df0d887979774085206f2e7f0146b02a8699715a54fc71ef27ab5a9e8cfbf155497bed9e25934aa74db1b3b270112472b7bf7587423b3ab2aaf99de34cdc591bfe04cc0a448875483ec1f071622121a49c456dc3ce16bae5f61f84ceaef9e8b71db56479845b764507dd9416e8c44b8c93406a230945eb8e484471c1b6207c9afd944fa0fee555a5c966f27ccffb4bfed37fe3936f2c84e9852c0d46c7e2e94b897fcef18c4b0b83d966aef75c0af4240325a24668bc017e0d3f69680ea5b2f59bd0b964062bc40190be86aef3ed0716a18a67057f309faaf3a040222812142a399deb72ebb330d03d59961e2ca10cf78d40886dd094368a881db261068920968f6adf7a7b1266faf8842e71840a29859e877c66e3ebc47d7fe3ee586b6512d9b0e1bea82b302647706473e68dc8209f4e9ca19f1dd25fe386e62c21d9c741e75cb8b11606739ba3de6d6325ee3a9cd1bb2b9613746140ccdaaf936eefdaa1ca7ad73d684e5d82b1ba1dd3356ca0c881f6eee72c02c8b78d02a8217a8fd972e463c77374d0fcbb761459e3ab0bb5492e516d7d4304c19c16a4bed11ea7f4e75616a26a7c81b04ffa580cce04d59825b8ed929578f9219e64bdbc6352ae6e4150a993fc3cc27ce4d66c62893866b9053bb737ac40364094b53d91e8b325b9dab5f537af04f10bf8db644897b0b03b42b1bd6c3aedfe018a6e4f6533183649f4ef6a6300383430f86e802fb4e51976d056a3c40c3b53c847b8308cfbe54dc2d20b8cdc870c73f5fc22c376c35d9a85348ca6a2288ae03dda6b97f0f502f35219e19cff3a810143289cb1f0715f8785028f887bf02c656c9cc372bdc419290f05957ad3dee82b56db352db65aca58e6fa0bd2f753160dd9e7214968c0496be1ab49f978a9252e49266939fedf542760abd653dd38b1659bcf452c753cb89e8235bcf732afcff8f524331be9b6f4a5081c81255e68c358b3444fb1d57bf5659d86b6674544fe2826ca81ee52f93a17b3291826678e488c3074c259223845e4083a413af7fc93d9992823620a8d29d321438a760293e36c4232216207060dd3ee5c4036250ede71ca9cbe335a1e068eb3ff6c10a7f1c8204750d6d0f3145014949a7b4e88a723566ee5446f960a95d9f81cc45155443da561d85a3a311df8172a1c4eb118bf27ec4b3cc4573b1ab421d96d41cc1e5557797ca68f701fe75c474527144d30b9bb00a117637f88896b0b2dcb9bb29ba144ec384b5a085e82e7387e0560a4621423c306b041ad42e84928ce23bc2a7f995ef5c21616de43be8a1657847489b32c8e364846389e7c8cae99530c499f3662a2ae7090e54958ba940b5d3eaf1333ebcecc7f06f29f68ffd97defe65017519c29d355ecb0a4b47ab08dbad8cb0cc5c86de65dfa703110c60a0c55281925018fb4ef49fe5d0132dcc86602c2ab9921a8f3451480d3e931f01c2f9a81873435bb83860128aa78dcc950fb13e416d90ea969aa92763f9caefa0fe3ef4ea82e3af4a3e717fabcc589fe8cb9bfba6810ddf7def8c1445fc0048fb07be043a628e9c920bb72c04d3b9472caafc6c14bffb854a1ba2170dda919322a6d79eab92e3a88888a224093946b87840033fe41941f780f569eaf1fdac55e36b74514d72d09823d71f48f5d5f0ceb7b6d69c5da0e0408c1b13c265d4775db6a0f952ae72bd5c277b22c4be2f2728451ce31e921c856000d20da0489103bad6a6ab4",
|
||||
"c60000000108b4b6d5c8b9a19769004047007e07df0d887979774085206f2e7f0146b02a8699715a54fc71ef27ab5a9e8cfbf155497bed9e25934aa74db1b3b270112472b7bf7587423b3ab2aaf99de34cdc591bfe04cc0a44884e9e716461869ca408431e1ba92740c598aa74e9cd45706f28942f9cc64dbfd7c292cd33e82b50ae0e2e08dc478c19886718cde33e56c38517f8834d64904bf4fb1d30650caedecb9567ea8ef50157c287a2741e98a00f8e7e19e76bbb0143ac7862a49393f17ec66aa0e2c02123ffb5abcc96ccf92cd542c8f571bd7a4382ff81432d11f83796959696c38f2029db6c6a536a9ea24b74c848b95882562d74739ac95f5a069d48e8756d1a9750c7ebc23d4ee22d617b29b415b7458b3bb8106c22de3a9ace9ec689e6e00471aa33e570f7481d15911d7cf46a429cee1a416558c5e78360795d905ff1e0c81d18fcf4954131fa5b9289ed2291e122cdffd666c66209aa2cab01730739249ce293b3ba3abb31683c108bdfd51f54593f47411077e948f01105bd9bfff1578d235674e96a8b9cfdde119edaa960b84e70fd681312514151de1d5939c79abdfe4953e22be5ad3e6e242d0ce9b3f2e589ce3c768f610d4d3a32e33225d8a5ce2ad74a9b40859cdd9ea99f14fa2a7018e4b6aa6e46a0d73d46d161ec5d3b30bd55078e23987865551a605a33472931428ce222040d20c07d1ebe970e576d9d54ae688a3fe9388adda3da4d011a7cbb604f1f19d2ef1be7ef4713bfa84d4d69ffa606a08b61a1ebb99aacc4e19d0c5034642da1ce2d7d5abecc8adbbc6d7f72ff2da4ce5228ff8626509b38e17b31717c0b7821558b021ba81502d54da7e778d4526367109333383e7c67d5d5bde86bd4001fa13a703ff9259e1c2268ca8f4ed2e6c022a7466e2178bc725f59792803ba28c629e3df7696c416dc294b510920077b2d2b258fdc3506c36c42d37796c8fdb20ba797ee68fdc410325a355f6c1189aa9fc9ee220d42186677e3955cd3c844ce505cd601f04201cc390e923db2ea6407fa2fb4ca7f3f82d0a82d52697ff5ba5d4633bb0d655d7ee3348b89c9cb42870cdfe7c0c162babab4208a9a54700c5785d4134e9e33361480e3512ac8b556e11775536e90ee1270a4cb4d6bf2faa72d7e1f23ceb4fc3aded0e423b6be6a55bc25e5a99163b4f5f72ec4a24fe96f68c739d1848c92c4236a5a637d19871456b8dae671ea6ae5c16ed4fc257612a0821e6dc1cbe2ef4963a1436925dcc4e6ce528fa75e41f7721b379fae8ca09e6fb51d0c3e3ae6c19b98860ab9f74013146c6d375656dd1f530abfa64670a510390e9a54bb9a4ad19977491377c8cd743597bc156ee3f58cfcafa5a547b20852749e66fa8838c100ebde039ea25c8ec32b0c6325b793797546a095e79b9388d8e67dc6b4b3892f93ecd13e64ba4b2ad26fc810fedc374b831921531344c581927da9ba822bd625584d98c7582759ae40f01e14277a0a13d30c2c12536df698330d8aa6a3613a42c493c42692b468b4a2cc6bb6dd45684ee6115848110bf517074efd93bf212c071013f4359f140cfed17bbe10328f2026cb8ada16427122d3fc8a933119a1e3e4cfe2b95cbc73af5044cb099cf34247228972495488ebaa4696280d17665c421be5f1727c5d5b013d8aac0e9943bbbb7fbc2162a4000a306dffe3bc4425cf272f1ebb63c8e4998f867fa6b05d71a8642e29392244d4e2e2351bc149d665efe1b9519cb1b15005393f938d",
|
||||
},
|
||||
name: "out of order duplicate fragments",
|
||||
domain: "ogads-pa.clients6.google.com",
|
||||
},
|
||||
{
|
||||
@@ -163,12 +215,14 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"dd0000000108277148f2b916666000406672db10ab41db38c01f7021709bac4d1659d872623eb5852b12b494535d13779a88d37e9685da572f6b2de35793a519a457493456ac4ee242933cf92d783f783656899c31832274bf1c26d24720d9d8ecfec598e19c58a478d2991dfc1cda3000f7bd7bd17e80",
|
||||
"d60000000108277148f2b916666000404ed98b1b4ac35c0c0ef18c88adf08a6701ccb0876ea75aac8c128349936fa3cb6728e4e58de8673dd7dc8457b092957f26bc8194233bb81c7e78127844f9b833f196dc46c5cb4064c773f3c6e0bc73",
|
||||
},
|
||||
name: "many out of order fragments",
|
||||
domain: "www.google.com",
|
||||
},
|
||||
// invalid packet
|
||||
{
|
||||
input: []string{"00000000000000000000"},
|
||||
invalid: true,
|
||||
name: "invalid packet",
|
||||
},
|
||||
// QUICv2
|
||||
{
|
||||
@@ -182,33 +236,54 @@ func TestQUICHeaders(t *testing.T) {
|
||||
"de6b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2bca71e020b3958cbd9f5bac9aecc60531cc5c734617f88b8ec772c46f6de6c7e6fb4e325c589eb3e9128769b9b5eb1fa796db7c279f90f0338494384a3a7910dba06d00d6ae03de7bc9affdecc7bfdb0ad3f596d349ac5a9b70b0a7fc6bbf0cacb43b149322365a0c40cfbb961893c6e6844d4a70f4e0bda3a2da6249c39551522b6de4471a6105c1da5af502e0298d1efd3732c315cdb03889b5b3ceab67d010911baa1e9dc0b0c9637d7d93df09e7153fd1380c3499e5355649c61337f98b640d629434bde4205c20c42571c33fc98e5b7fc484ef24b7dde4eca65519d913d93f8c9c271ee1c17dad044a0237ca3fbb808ec0c49a8eab69fc49f733b5ec900e8b0debef8008acb168465e43f02d1c859046afc83f57d014e78100a21e243155497c9de0973b635cb3aa2a6f3ba67aabaa352e2a15ae04c58746485e3466f0547e849ae208a3324cb860b92549b0991c06f9e11b9a217e4ba3044248e40474ea9a5c42f91815afc8c60818bbbfc373adc0f6242d1abb82fbdda55200c7005992558320f3a9db3be8fc90fcda594f10b1288088a96b261eca79e23462878bb8c5b62709d8b46d03f19cf6ec2ec68a0cd83ba7823169b2bdb43739022ca97ced2dd57bd65a6546b9f9321fc23e09e87f104d2bc420dde8333aced4c27f41c120c19102e78329923c9797042ee33db6c85bb9272f34e95643e17fa46bb877ca16020278af64540d1a66e36deaa4507d8061d00199a7f9ea47436198a610e54d821dbedaabc8b8903ce15d680384dd13842abfac1283554c82fe52f104faa590cf3ff5a8cf8bdf0e8749bd31751fa760c557853f82393756c6800f8651c17c7126575a1c6bd784b037189ea50f2d5df0d111171f0cdbf080622cd9f6fc101f80216978853bfbe076467523839b56aa0e9fdd2f2d6cc231746b529f8e3427dfeea0aaa910a421aa92ffa1e49362e2ee1ac4c9586c11482b3bf66a260baccdcb252fbbec17c081be90cbf31a2a2f8a81b86ac526ebe25a072fdf3ff6b849d0a5563b7643983df7d024ad9a7e62ebdb0c662aedff94574f26daf8657ab95698607230ff7221d3893db9125e567aafa9980aed8a8297856e9ae265b654e29099a48064d6c3063a52518724b4950e13ed1a95d54b5ec999802419e76942f7f7f1409fa825ad3d72921fbc531594f9af221f727d93ac2022795517be4f4904f87b7cfbfa6e759bbc3c0b61090a5c0d85c59f6938b90ffe5b3cd6e99934b692d3c25c0f211842e9a2fd9c2688d95083db659a202e6dbb0d5df8200ec63ff5e63629b1488ee35a60badafdc87a5f9bd45315ca78c711329a2d41ee150b195a22bc1a59686638796978b7a9d3709e9c181049fb7ec038ed296da30fb12fba5c1ff35c972a0527fd53b7d005b170652c89065113c16cdb37548b6ab634bee372cf986bf71cbba2b1bf3f0410f33d9f565fe89a56369651eb7c3eb94fdbf9412798b114a833e4bf69e1a0f345b6561e8370df0896acd7aa5ec79f7ff911d715da53f779ec9d3cb7655fcf0895f83f188a5900cd02a237a4c413b872c362afa0ca098570487f02e247ff65ad16dbd5f13d5e6d49f1ce81ac7e98595abcf949261984c7f5588e31e772e8f797762a7df18c43853f1c42ff475140634b00800ec98a541aa1d2b44a1d6b800c5f2f82e6e105dcb601da4eb69719c6cdfe5adb1af98109e8d02b226d34c7fa4c71fccdd4fc68af289008e2ec044680df28c0291a6ca86554b35c9525a9555",
|
||||
"d16b3343cf14a04d19d18c864e168f4e929ddf60ddd774708211000044e2eaea2376f006580e3628eb4179704f587b104420de4e0df8f2cd6e872eba6bfdc149b8d7bd2626d7cca367af16e699a9d59feee39590cb674e01b60f79dccd9bc7a16bf408f15723e5b75def1233a465ad27f839bd9aaca05e871db1fd5203209158e327a81d8c4ac5cb87ecdd3a470b49c2cfc5a55e2c97fa773642156096c664e9ee894091ffa4f3472a07d0cf3f318c3ef21d60e03e28301ad4a8e007b9d7245592533755a9ce83938a88242575e4cf2ac9408f67c0d9ab2b265f91a92aabdfdb6241185f91187b05b1b340d429422857e356eadef470dda05556b15987879470ed6ce108000e1c21f6f6ce0b301ac43e33f9a0fef0a51b0335ae6db12a19fd42a2ffc576e51c13dd2d014d0457824a7a8472b77015b48a276d954318e3eed3a5be4d4cbd20d724cc1bffc29276e7b576f3d28df529d892b1fb7f49c0300df572e660032ecc31078d1fe29346137e1c14facb48ae1368e8bc7b4173e94e034119ef887099fb754d119d13dcc9b58be3828f86e94b8f3e3892697492758702b69f6d234786f55d9be7e777b3566de70a91989d3fcde859c2fc604da09c6ec4697ae72f07ae312e236be0f5e3ddf0c3feff19da67bb8a4c5a86e67fd3d0d795b2641d4e5b61a6a5a70c9403a9c7469b80472d5ee7dc48ac24a283666031a4f479b1d3f9eaa1f0316c14529627d8e5f655abd1f49b4feb6c0466dc76502aa8b62b1b3090cf7d5e78337a688006744dcacba3caf52c2c56857f95d1cb1a39570f5517bdf7d928f8c6c58a3b11f56615e87c2a51f446c4c4a42c7ed2f951366beb1dae4d5e525c31e052f905e1a15d032c273ab0678ce60415681db3053bb912bbed749bc8ba89eef53baed0bf6253baeb3c6313020ce0a4ec926c1123b094162c63f716105fea65ffb9e969ef771e2f2b212cd3eb0cd77292dc0fb51bfd43cd5b3d976d2b4ab4655e9dbeb4c2ced8de0cf94f7595cf69c4ee849b543de4a2eecba77c92655500b2550485195e69710ed5f5a60e345429ca084b04f5283bf35203f9fc88b33d371fc497e07587ae4d3490df2eb74f3fbf04a17cc36b3378c87d038e169378b717f1f1ba532025929d25538f00c17d2bf10fda9af2a8e314e2d656f37d8a1197304c69ce510c33221878713a632039da2954dc07e04771cdac44c6eb7443eb386c1504b4945a19f5d6b89e3983d97c8b22f6910e40b667bd0d243fc966fe16aa9d2fdb6cde5eae005d8e5e016e57f4ce13d917cb034fd915218eb8607d4a20663bd4cb5c0bdde8b21d16f0c16b29abb4432bd9a2a465a91b9e75b84d5e17fd8421731a5b709450b73954baf4d3d48245575a6180224479ba044362f335ef75523d67e874d4ecfadebc28dd2ef2ba8cde42532ee8bc2150ca665829a97aa1f76578e67e73be6016a8a4a2ef6e7888e6e9875c8f728294d95af4e369bc239aaf1249075f7ce6e76f8e039cc160c48d71c683f930dac05653e7c817e2478c1c0528537948e446990e51099a21033fe0ed43db83727501e4d0baa3aac9ce39c83e17dce22920c8c4783fa311a57e35ec7fe73cd86a8664f19a7b50279320e2c0a03844e191caff11cec4351d3c278c56ad523d4026b0850487468975d2b42c820cea108e4b15e23ee7703f306ed360f4d5ece164359fbe81698763bccad13d58c69e5f4b5a1728602798575d62f6b19632fbc4920b06ab34a5a51a3337ed7160b24653e35b8da5f0b483b3ed2fca8630af8a1cbf04fd39877baa1834065f9f",
|
||||
},
|
||||
name: "quic v2 fragmented",
|
||||
domain: "test.example.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range cases {
|
||||
data, host, err := testQUICSniffer(test.input, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.domain, data)
|
||||
if test.invalid {
|
||||
assert.Equal(t, fakeHost, host)
|
||||
} else {
|
||||
assert.Equal(t, test.domain, host)
|
||||
}
|
||||
|
||||
data, host, err = testQUICSniffer(test.input, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, test.domain, data)
|
||||
if test.invalid {
|
||||
assert.Equal(t, fakeHost, host)
|
||||
} else {
|
||||
assert.Equal(t, test.domain, host)
|
||||
}
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
for _, mode := range []struct {
|
||||
name string
|
||||
async bool
|
||||
}{
|
||||
{name: "async", async: true},
|
||||
{name: "sync", async: false},
|
||||
} {
|
||||
t.Run(mode.name, func(t *testing.T) {
|
||||
data, host, err := testQUICSniffer(test.input, mode.async)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.domain, data)
|
||||
if test.invalid {
|
||||
assert.Equal(t, fakeHost, host)
|
||||
} else {
|
||||
assert.Equal(t, test.domain, host)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("client hello followed by crypto data", func(t *testing.T) {
|
||||
clientHello := makeTestClientHello("example.com")
|
||||
cryptoData := append(bytes.Clone(clientHello), 0x02, 0, 0, 0)
|
||||
q := &quicPacketSender{
|
||||
buffer: cryptoData,
|
||||
ranges: utils.IntRanges[uint64]{
|
||||
utils.NewRange(uint64(0), uint64(len(cryptoData))),
|
||||
},
|
||||
}
|
||||
domain, err := q.tryAssemble()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "example.com", domain)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSHeaders(t *testing.T) {
|
||||
generatedHello := makeTestClientHello("example.com")
|
||||
generatedHelloWithTrailingData := append(bytes.Clone(generatedHello), 0x02, 0, 0, 0)
|
||||
cases := []struct {
|
||||
name string
|
||||
input []byte
|
||||
domain string
|
||||
err bool
|
||||
@@ -242,6 +317,7 @@ func TestTLSHeaders(t *testing.T) {
|
||||
0xaa, 0xaa, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
|
||||
0xaa, 0xaa, 0x00, 0x01, 0x00,
|
||||
},
|
||||
name: "microsoft client hello",
|
||||
domain: "c.s-microsoft.com",
|
||||
err: false,
|
||||
},
|
||||
@@ -279,6 +355,7 @@ func TestTLSHeaders(t *testing.T) {
|
||||
0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x8a, 0x8a,
|
||||
0x00, 0x01, 0x00,
|
||||
},
|
||||
name: "clicktale client hello",
|
||||
domain: "www07.clicktale.net",
|
||||
err: false,
|
||||
},
|
||||
@@ -300,6 +377,7 @@ func TestTLSHeaders(t *testing.T) {
|
||||
0xb6, 0x90, 0x0a, 0xb7, 0xd5, 0xc4, 0x1b, 0x2f, 0x60, 0xaa, 0x56, 0x7b, 0x3f, 0x71, 0xc8, 0x01,
|
||||
0x7e, 0x86, 0xd3, 0xb7, 0x0c, 0x29, 0x1a, 0x9e, 0x5b, 0x38, 0x3f, 0x01, 0x72,
|
||||
},
|
||||
name: "short server name",
|
||||
domain: "dogfish",
|
||||
err: false,
|
||||
},
|
||||
@@ -339,27 +417,57 @@ func TestTLSHeaders(t *testing.T) {
|
||||
0x2b, 0x73, 0x2c, 0xa5, 0x4a, 0x98, 0x40, 0x3d,
|
||||
0x75, 0x6e, 0xb4, 0x76, 0xf9, 0x48, 0x8f, 0x36,
|
||||
},
|
||||
name: "ip server name",
|
||||
domain: "10.42.0.243",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "client hello across records",
|
||||
input: makeTestTLSRecords(generatedHello, 1, 2, 3, len(generatedHello)/2, len(generatedHello)-3),
|
||||
domain: "example.com",
|
||||
},
|
||||
{
|
||||
name: "client hello followed by handshake data",
|
||||
input: makeTestTLSRecords(generatedHelloWithTrailingData, 2),
|
||||
domain: "example.com",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range cases {
|
||||
input := bytes.Clone(test.input)
|
||||
domain, err := SniffTLS(test.input)
|
||||
if test.err {
|
||||
if err == nil {
|
||||
t.Errorf("Exepct error but nil in test %v", test)
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
input := bytes.Clone(test.input)
|
||||
domain, err := SniffTLS(test.input)
|
||||
assert.Equal(t, input, test.input)
|
||||
if test.err {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Errorf("Expect no error but actually %s in test %v", err.Error(), test)
|
||||
}
|
||||
if *domain != test.domain {
|
||||
t.Error("expect domain ", test.domain, " but got ", domain)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, input, test.input)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.domain, *domain)
|
||||
})
|
||||
}
|
||||
|
||||
fragmented := makeTestTLSRecords(generatedHello, 2, len(generatedHello)/2)
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
have int
|
||||
need int
|
||||
}{
|
||||
{name: "empty input", have: 0, need: tlsRecordHeaderLen},
|
||||
{name: "one byte record header", have: 1, need: tlsRecordHeaderLen},
|
||||
{name: "two byte record header", have: 2, need: tlsRecordHeaderLen},
|
||||
{name: "three byte record header", have: 3, need: tlsRecordHeaderLen},
|
||||
{name: "four byte record header", have: 4, need: tlsRecordHeaderLen},
|
||||
{name: "record payload missing", have: tlsRecordHeaderLen, need: tlsRecordHeaderLen + 2},
|
||||
{name: "next record header missing", have: tlsRecordHeaderLen + 2, need: 2*tlsRecordHeaderLen + 2},
|
||||
{name: "final record payload incomplete", have: len(fragmented) - 1, need: len(fragmented)},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
_, err := SniffTLS(fragmented[:test.have])
|
||||
var need *errNeedAtLeastData
|
||||
require.ErrorAs(t, err, &need)
|
||||
assert.Equal(t, test.need, need.length)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,13 @@ var (
|
||||
errNotClientHello = errors.New("not client hello")
|
||||
)
|
||||
|
||||
const (
|
||||
tlsRecordHeaderLen = 5
|
||||
tlsHandshakeHeaderLen = 4
|
||||
tlsRecordTypeHandshake = 0x16
|
||||
tlsHandshakeTypeClientHello = 0x01
|
||||
)
|
||||
|
||||
type errNeedAtLeastData struct {
|
||||
length int
|
||||
err error
|
||||
@@ -66,7 +73,8 @@ func IsValidTLSVersion(major, minor byte) bool {
|
||||
return major == 3
|
||||
}
|
||||
|
||||
// ReadClientHello returns server name (if any) from TLS client hello message.
|
||||
// ReadClientHello returns the server name (if any) from exactly one complete
|
||||
// ClientHello handshake message, including its four-byte handshake header.
|
||||
// https://github.com/golang/go/blob/master/src/crypto/tls/handshake_messages.go#L300
|
||||
func ReadClientHello(data []byte) (*string, error) {
|
||||
if len(data) < 42 {
|
||||
@@ -161,28 +169,93 @@ func ReadClientHello(data []byte) (*string, error) {
|
||||
return nil, errNotTLS
|
||||
}
|
||||
|
||||
func SniffTLS(b []byte) (*string, error) {
|
||||
if len(b) < 5 {
|
||||
return nil, ErrNoClue
|
||||
func clientHelloSize(data []byte) (int, error) {
|
||||
if len(data) < tlsHandshakeHeaderLen {
|
||||
return 0, ErrNoClue
|
||||
}
|
||||
if data[0] != tlsHandshakeTypeClientHello {
|
||||
return 0, errNotClientHello
|
||||
}
|
||||
|
||||
if b[0] != 0x16 /* TLS Handshake */ {
|
||||
return nil, errNotTLS
|
||||
}
|
||||
if !IsValidTLSVersion(b[1], b[2]) {
|
||||
return nil, errNotTLS
|
||||
}
|
||||
headerLen := int(binary.BigEndian.Uint16(b[3:5]))
|
||||
if 5+headerLen > len(b) {
|
||||
return nil, &errNeedAtLeastData{
|
||||
length: 5 + headerLen,
|
||||
err: ErrNoClue,
|
||||
}
|
||||
}
|
||||
|
||||
domain, err := ReadClientHello(b[5 : 5+headerLen])
|
||||
if err == nil {
|
||||
return domain, nil
|
||||
}
|
||||
return nil, err
|
||||
bodyLen := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
|
||||
return tlsHandshakeHeaderLen + bodyLen, nil
|
||||
}
|
||||
|
||||
// readTLSClientHello removes TLS record headers and returns one complete
|
||||
// ClientHello handshake message. It scans before allocating so an untrusted
|
||||
// handshake length cannot cause an allocation until all declared bytes exist.
|
||||
func readTLSClientHello(b []byte) ([]byte, error) {
|
||||
var handshakeHeader [tlsHandshakeHeaderLen]byte
|
||||
wireOffset := 0
|
||||
handshakeBytes := 0
|
||||
helloSize := 0
|
||||
records := 0
|
||||
|
||||
for {
|
||||
if len(b)-wireOffset < tlsRecordHeaderLen {
|
||||
return nil, &errNeedAtLeastData{
|
||||
length: wireOffset + tlsRecordHeaderLen,
|
||||
err: ErrNoClue,
|
||||
}
|
||||
}
|
||||
|
||||
header := b[wireOffset : wireOffset+tlsRecordHeaderLen]
|
||||
if header[0] != tlsRecordTypeHandshake || !IsValidTLSVersion(header[1], header[2]) {
|
||||
return nil, errNotTLS
|
||||
}
|
||||
|
||||
recordLen := int(binary.BigEndian.Uint16(header[3:]))
|
||||
payloadOffset := wireOffset + tlsRecordHeaderLen
|
||||
recordEnd := payloadOffset + recordLen
|
||||
if len(b) < recordEnd {
|
||||
return nil, &errNeedAtLeastData{
|
||||
length: recordEnd,
|
||||
err: ErrNoClue,
|
||||
}
|
||||
}
|
||||
if recordLen == 0 {
|
||||
return nil, errNotClientHello
|
||||
}
|
||||
|
||||
payload := b[payloadOffset:recordEnd]
|
||||
if handshakeBytes < tlsHandshakeHeaderLen {
|
||||
copy(handshakeHeader[handshakeBytes:], payload)
|
||||
}
|
||||
handshakeBytes += len(payload)
|
||||
records++
|
||||
|
||||
if helloSize == 0 && handshakeBytes >= tlsHandshakeHeaderLen {
|
||||
var err error
|
||||
helloSize, err = clientHelloSize(handshakeHeader[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if helloSize != 0 && handshakeBytes >= helloSize {
|
||||
if records == 1 {
|
||||
return payload[:helloSize], nil
|
||||
}
|
||||
|
||||
hello := make([]byte, helloSize)
|
||||
copied := 0
|
||||
for offset := 0; copied < helloSize; {
|
||||
recordLen := int(binary.BigEndian.Uint16(b[offset+3 : offset+tlsRecordHeaderLen]))
|
||||
payloadOffset := offset + tlsRecordHeaderLen
|
||||
copied += copy(hello[copied:], b[payloadOffset:payloadOffset+recordLen])
|
||||
offset = payloadOffset + recordLen
|
||||
}
|
||||
return hello, nil
|
||||
}
|
||||
|
||||
wireOffset = recordEnd
|
||||
}
|
||||
}
|
||||
|
||||
func SniffTLS(b []byte) (*string, error) {
|
||||
clientHello, err := readTLSClientHello(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadClientHello(clientHello)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user