From 5121c28b855c9d7f12deaeb1352116eb490754bb Mon Sep 17 00:00:00 2001 From: Filipp Balakin Date: Mon, 5 Oct 2026 06:53:22 +0300 Subject: [PATCH] QUIC sniffer: Handle zero-filled datagram tails (#6882) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/XTLS/Xray-core/pull/6882#pullrequestreview-5395639793 --------- Co-authored-by: 风扇滑翔翼 --- common/protocol/quic/sniff.go | 4 ++++ common/protocol/quic/sniff_test.go | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/common/protocol/quic/sniff.go b/common/protocol/quic/sniff.go index 14c165c32..7ffbe3866 100644 --- a/common/protocol/quic/sniff.go +++ b/common/protocol/quic/sniff.go @@ -146,6 +146,10 @@ func SniffQUIC(b []byte) (*SniffHeader, error) { } restPayload := b[hdrLen+int(packetLen):] + // cachedReader can concatenate zero-padded UDP datagrams. + for len(restPayload) > 0 && restPayload[0] == 0 { + restPayload = restPayload[1:] + } if !isQUICInitial { // Skip this packet if it's not initial packet b = restPayload continue diff --git a/common/protocol/quic/sniff_test.go b/common/protocol/quic/sniff_test.go index 3674d9212..b65c6aa3d 100644 --- a/common/protocol/quic/sniff_test.go +++ b/common/protocol/quic/sniff_test.go @@ -294,3 +294,21 @@ func TestSniffFakeQUICPacketWithTooShortData(t *testing.T) { t.Error("failed") } } + +func TestSniffQUICTrailingZeroPadding(t *testing.T) { + // Incomplete Initial packet with trailing zero padding + pktWithPadding, err := hex.DecodeString("ca0000000108d799f48baf472fc3004047005411dcdaa24bd4c3cdbef653940a1ea0a671bb8c23222a8502bfcbd0a335af016df330b1190e4b1efd420aa82c4414a7dfd7b1aa63aa7bd0269ec8ed0d24895a467b737fcc514488a8142241b81c4952fb32e9f123f3f8d1be9eecc1340d7fa747c6f4838810209d51ad453fcec084ffaa382f9fed010a0585f8ce73c36dc6c628df940f72fb5b8e3e06f4612128d3b8f87725770d81305489a3a23cd443fcc668fece0ec9a909c82cfdb66819ce031422c3edd49ea72b6216efb940b8c186e2510b0f93d4cf3b6434ed9f5817c5a5a19fa861d24883bd48ba296df81e887fcb9ef18013ab1070df268049f3d35e8ddfffd2b100e4eb687176a02e7975085caa138e9df7cb6f9862356faafba3300f586df09af3b4e3eec15b6d1f14b34fe4eeb8e762ff482f3b7b0595c16d3eb20cf9c892b3f7c6449e51ffa33f3dc877d32e572e10ba4d5a320117110b150bec4a9434103de963aa2de1b22eaa992b59a8583c7a2d4e5743ef98a1b1f5f4aaeb2b49dbe441c331e7cb028e70432ce0890f78d40671f13d5feccc4ab264ae903affaa951897128d598ed8e8542294aa03abb0a2a7ec970ab874387b8777827c4847bb29ff93d0427c1fcc581407465611e4400bfeab39de4c4f65572365156421503706d66138317e514214db27303ad8b5b17eb443e959faad1ccb3d3def5f3843b241dd9a60378cd907a02cc5c6e8527715c7734079cf9143586ed471587690816133fa8f09b8421f2de6ff1f5cecc134ac404e53a367b57fd4f3c85fe7e121e7094fbf93c06d427cec30cd519ee43a6018a8bb8717c05d7660b379101a182bfd3018d485d5b46e81d39445ccd4d8baefdd7590e664f2289f11bbad3d35ea6d70e157aaa7f9e91a692794b85c5b86db33863151468d32792ecfdb2aec52784ded5aa431fa9a7337ddd9e95313a897fe5ca6ef3c7e0cf3d41f7f104506f8695f2ba307715022e5e98472d6ff24125004d14db2c7a4cc71ca39a9874bfb93b64dd54ef451097059bbdfa96aca6c6c01e1f000b8d35bdead1502874e5d80ac00a79593b6d7e2fbee406c2212b4abd7b7e9f0037518de232cd6559443f4e3f0f03c17cef616a74992f65754bb6699b08c0eb2ec59508086e496e070c6239a73f11a9d14a727b10188ca97ebf04851fa475ed1774836a94cfb6543c33888dfc250100e9992b0cca8bd27ae8552541f1b3d81546f15b740e4f07b41af864769fe17290eb7076c0c1f938ce56a45ead6deb6c89164f829543414a1b8cd2361c3d9b22cf85d4ad0d4221dcc87533506e32c1cfdc8240636b669f97f7c6e150ea3753fcb63a7b9eedb5615b257651e090b567a20fdc5c167ad58fa940985572db004db2b14709a6663c1fb79dc045e45cb7228f11eab4c60a48fffc702cd74dcf5aabded8355a5ae1a5e6325a3afff608e53af3aa944437139c438e6200c75bb27c8a8ce7ce9f9ec9723c4423e9e49c807b12484783ed79fc501b544f03e4b29bdf0c74eb055dbac9b78fe87a66efc819f9d2ea637dd478b920b7196232b970ed092050ba0621329aa2b3e26184176137a9c6283e4cc2c03c07e28d2da7b0485da51f131686f4dd6b23735c66316142f48781885c35c9940054a4b9187a20914bedd1c48e94af358994da5c6060dd224b0ba84ddd5e95f395fe941d464e2cccd857a180de756d32407540c3611b649c7a71cbf5a492bf5c8d4e112a743498ce83ea3e94bcaa60000000000000000000000000000000000000000000000000000000000000000") + common.Must(err) + quicHdr, err := quic.SniffQUIC(pktWithPadding) + if !errors.Is(err, protocol.ErrProtoNeedMoreData) { + t.Errorf("expected ErrProtoNeedMoreData for packet with trailing zero padding, got %v", err) + } + + // Packet 1 has trailing zero padding with packet 2 + pktsSplicedWithPadding, err := hex.DecodeString("ca0000000108d799f48baf472fc3004047005411dcdaa24bd4c3cdbef653940a1ea0a671bb8c23222a8502bfcbd0a335af016df330b1190e4b1efd420aa82c4414a7dfd7b1aa63aa7bd0269ec8ed0d24895a467b737fcc514488a8142241b81c4952fb32e9f123f3f8d1be9eecc1340d7fa747c6f4838810209d51ad453fcec084ffaa382f9fed010a0585f8ce73c36dc6c628df940f72fb5b8e3e06f4612128d3b8f87725770d81305489a3a23cd443fcc668fece0ec9a909c82cfdb66819ce031422c3edd49ea72b6216efb940b8c186e2510b0f93d4cf3b6434ed9f5817c5a5a19fa861d24883bd48ba296df81e887fcb9ef18013ab1070df268049f3d35e8ddfffd2b100e4eb687176a02e7975085caa138e9df7cb6f9862356faafba3300f586df09af3b4e3eec15b6d1f14b34fe4eeb8e762ff482f3b7b0595c16d3eb20cf9c892b3f7c6449e51ffa33f3dc877d32e572e10ba4d5a320117110b150bec4a9434103de963aa2de1b22eaa992b59a8583c7a2d4e5743ef98a1b1f5f4aaeb2b49dbe441c331e7cb028e70432ce0890f78d40671f13d5feccc4ab264ae903affaa951897128d598ed8e8542294aa03abb0a2a7ec970ab874387b8777827c4847bb29ff93d0427c1fcc581407465611e4400bfeab39de4c4f65572365156421503706d66138317e514214db27303ad8b5b17eb443e959faad1ccb3d3def5f3843b241dd9a60378cd907a02cc5c6e8527715c7734079cf9143586ed471587690816133fa8f09b8421f2de6ff1f5cecc134ac404e53a367b57fd4f3c85fe7e121e7094fbf93c06d427cec30cd519ee43a6018a8bb8717c05d7660b379101a182bfd3018d485d5b46e81d39445ccd4d8baefdd7590e664f2289f11bbad3d35ea6d70e157aaa7f9e91a692794b85c5b86db33863151468d32792ecfdb2aec52784ded5aa431fa9a7337ddd9e95313a897fe5ca6ef3c7e0cf3d41f7f104506f8695f2ba307715022e5e98472d6ff24125004d14db2c7a4cc71ca39a9874bfb93b64dd54ef451097059bbdfa96aca6c6c01e1f000b8d35bdead1502874e5d80ac00a79593b6d7e2fbee406c2212b4abd7b7e9f0037518de232cd6559443f4e3f0f03c17cef616a74992f65754bb6699b08c0eb2ec59508086e496e070c6239a73f11a9d14a727b10188ca97ebf04851fa475ed1774836a94cfb6543c33888dfc250100e9992b0cca8bd27ae8552541f1b3d81546f15b740e4f07b41af864769fe17290eb7076c0c1f938ce56a45ead6deb6c89164f829543414a1b8cd2361c3d9b22cf85d4ad0d4221dcc87533506e32c1cfdc8240636b669f97f7c6e150ea3753fcb63a7b9eedb5615b257651e090b567a20fdc5c167ad58fa940985572db004db2b14709a6663c1fb79dc045e45cb7228f11eab4c60a48fffc702cd74dcf5aabded8355a5ae1a5e6325a3afff608e53af3aa944437139c438e6200c75bb27c8a8ce7ce9f9ec9723c4423e9e49c807b12484783ed79fc501b544f03e4b29bdf0c74eb055dbac9b78fe87a66efc819f9d2ea637dd478b920b7196232b970ed092050ba0621329aa2b3e26184176137a9c6283e4cc2c03c07e28d2da7b0485da51f131686f4dd6b23735c66316142f48781885c35c9940054a4b9187a20914bedd1c48e94af358994da5c6060dd224b0ba84ddd5e95f395fe941d464e2cccd857a180de756d32407540c3611b649c7a71cbf5a492bf5c8d4e112a743498ce83ea3e94bcaa60000000000000000000000000000000000000000000000000000000000000000c00000000108d799f48baf472fc3004047005411dcdaa24bd4c3cdbef653940a1ea0a671bb8c23222a8502bfcbd0a335af016df330b1190e4b1efd420aa82c4414a7dfd7b1aa63aa7bd0269ec8ed0d24895a467b737fcc514488e7151df796764293639665547941eaaa7d83dfc9d42952583a821611921cba9e0276f9244f197e011b6c2d898255802c81c8792dd68d03cd8982ee6146c8734814e9640e0999312f97e898db60642ceca21700be9e698b5e577062148d1ac840e737f7bc4f18f9ffd13e656fca1517c96d0e0c607b67d7e75795f62131255b44c2178d896192348d5f053060fa21c855236401e853e435fbc71a428c8e126cd8393cb860193fd6304d9576e8a8ce7f6959739afa7d7ffaf86516afb061ade1eef603e8e5c66f002cacbef25546e84b59be707c547837f7b49471a59325ad58a4f189a525a3a354a4be5ffd3db34ce0585ec470f78f0ff6eb807989d5998e2fccc80bd651de654da3581b6c8a858b56c4df47c3041c50d74f0b3a3a5a325882cd356d0c46d6db74559cef934a1655c65a06daff218244f5f4e95b96794e45d371a03afee2c89768fe3d7bc134844f45440620a88d6ddb5d07b7f6c9b2adfbf5743c5c586520504febf14ee4b216f8186ee1bf9802ccebd4dac519bd337a554940a3873cd21ef32f3d4d4fdfd3eaabb172b5314490b3587a9ca2dc12637fa80dcd526859bb83d54f67dedeb173470e052beec9edba4b41444d31253accb3381237179a5381d437fc4d47c0a82f1c9da8c76ad3eee9417bf69acb8d530ac824e65d796b84bee40b14daa9e80c11e466f93233e1768ecc6c0237e71b901f1faa093bbd9e5324b2a160d02f09d4590392279a15c73edc4d1d7501ebad992fc8f1c9dce96c190879225dbbb09d20532f9dcbb845e3484c87cb8c3b06fe892b07bdc60926e3d4b5c9024acde5abed0a72686d546da535a2122cfd6d6488a491dc9612b90f3f6709835e83f59fd612c2259c3ac944fdae87ffd744176a92fbea1efd037565a39d5bc38991cfe6617135b43cd6c6484a3b228e10d3f8184227a7ee63121be20f099c4264461d52aecf4b8ee1a4d0ec41717f9a68e1394544cf3be0a3a171ece35c879b67afdaac49c12731e6dc5ccaa49fa72610901036a7f0752951077cd9f1d77eb6e4f12c16dab08e1a9655fda3ba0e80c34c767f40e61491f706ab9d1b50f48273ca4e37708d075909a3e2c4b173510114d8377b5300994f9a4f794db2781b98c2e9d0056fdbe87b249beb3e7301c86efe6b32242b4c7fabef280a1ca7bdd6abb38624cbebb01b6b75b07d0cd9090b2c296d0e330b9008788dd6f7e1af1dd63b02408f1a67b57be3316152270bf90c36e9f74322c9caba5adab3309e5bd7c44d3c2ac77329e167dafda7395e37313723fb550a6ab96729a9fa8f9e4a3e5957bffa3302617d48fd38196635309928c491ca974a112768de16043fc618001780b49a0bac2ea9fc2607ebd1f25b8ef65a6cab42d16c9184e23af496ac5cfab274d9557006d9c52bb56cd8c019ddf085f260a0582ef465c73f97fedc02271dda53eec20e6aa50503357ed1847f7d976899cb24e5dd42dd87ae48db3c9335b38957fc0f86a6ceee590b1cbee41fc6ace3189886bd86f9b082e66fb263f1a98dd8e564bff9ec412ae79e29fd519ac96e9c5b446b436b78a6ca555c496ca5c5e73c2c1c5837b13f7a953d57738440d4ed60efd4701bbbbcad79e1697b5724695f52dab8bce02e7f") + common.Must(err) + quicHdr, err = quic.SniffQUIC(pktsSplicedWithPadding) + if err != nil || quicHdr.Domain() != "play.google.com" { + t.Errorf("SniffQUIC() on spliced packets with padding error = %v, domain = %v", err, quicHdr) + } +}