diff --git a/Cargo.lock b/Cargo.lock index 3572d97..cad63bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "afl" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2027b09e36bf321ace7af43a23df3d46dae645b855be337b0b6582c79ad53769" +checksum = "62656735672273d859b4e3dcd2d3c6dbe2f4decee62e3c206aad2363b1a2f9e2" dependencies = [ "home", "libc", @@ -31,19 +31,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" [[package]] name = "async-compression" -version = "0.4.36" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" +checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" dependencies = [ "compression-codecs", "compression-core", - "futures-core", "pin-project-lite", "tokio", ] @@ -73,9 +72,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-fips-sys" -version = "0.13.10" +version = "0.13.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57900537c00a0565a35b63c4c281b372edfc9744b072fd4a3b414350a8f5ed48" +checksum = "d3d619165468401dec3caa3366ebffbcb83f2f31883e5b3932f8e2dec2ddc568" dependencies = [ "bindgen", "cc", @@ -87,9 +86,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ "aws-lc-fips-sys", "aws-lc-sys", @@ -99,9 +98,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" dependencies = [ "cc", "cmake", @@ -186,9 +185,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" [[package]] name = "block-buffer" @@ -201,9 +200,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.1" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byteorder" @@ -213,9 +212,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "castaway" @@ -228,9 +227,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.51" +version = "1.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" dependencies = [ "find-msvc-tools", "jobserver", @@ -278,9 +277,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" dependencies = [ "cc", ] @@ -310,9 +309,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" dependencies = [ "compression-core", "flate2", @@ -447,9 +446,9 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", ] @@ -507,18 +506,18 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.4" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.8" +version = "0.11.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" dependencies = [ "env_filter", "log", @@ -537,14 +536,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "fastbloom" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" dependencies = [ "getrandom 0.3.4", "libm", @@ -554,15 +553,15 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -574,6 +573,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -591,9 +596,9 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -606,9 +611,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -616,15 +621,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -633,15 +638,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", @@ -650,21 +655,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -674,7 +679,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -701,9 +705,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -721,11 +725,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -734,9 +751,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -751,6 +768,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -803,7 +829,7 @@ dependencies = [ "rand", "ring", "rustls-pki-types", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", "tinyvec", "tokio", @@ -827,7 +853,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", ] @@ -894,9 +920,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ "atomic-waker", "bytes", @@ -909,7 +935,6 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "pin-utils", "smallvec", "tokio", "want", @@ -946,14 +971,13 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", "http", "http-body", @@ -962,7 +986,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.5.10", + "socket2", "tokio", "tower-service", "tracing", @@ -970,12 +994,13 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" dependencies = [ "displaydoc", "potential_utf", + "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -983,9 +1008,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ "displaydoc", "litemap", @@ -996,9 +1021,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1010,15 +1035,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] name = "icu_properties" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ "icu_collections", "icu_locale_core", @@ -1030,15 +1055,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ "displaydoc", "icu_locale_core", @@ -1049,6 +1074,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "idna" version = "1.1.0" @@ -1072,37 +1103,40 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "ipconfig" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +checksum = "4d40460c0ce33d6ce4b0630ad68ff63d6661961c48b6dba35e5a4d81cfb48222" dependencies = [ - "socket2 0.5.10", + "socket2", "widestring", - "windows-sys 0.48.0", - "winreg", + "windows-registry", + "windows-result", + "windows-sys 0.61.2", ] [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" dependencies = [ "memchr", "serde", @@ -1128,9 +1162,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jni" @@ -1141,7 +1175,7 @@ dependencies = [ "cesu8", "cfg-if", "combine", - "jni-sys", + "jni-sys 0.3.1", "log", "thiserror 1.0.69", "walkdir", @@ -1150,9 +1184,31 @@ dependencies = [ [[package]] name = "jni-sys" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] [[package]] name = "jobserver" @@ -1166,10 +1222,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1180,11 +1238,17 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.180" +version = "0.2.184" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" [[package]] name = "libloading" @@ -1198,15 +1262,15 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" @@ -1246,9 +1310,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -1283,9 +1347,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "wasi", @@ -1294,9 +1358,9 @@ dependencies = [ [[package]] name = "moka" -version = "0.12.12" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" dependencies = [ "crossbeam-channel", "crossbeam-epoch", @@ -1334,9 +1398,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" [[package]] name = "num-traits" @@ -1349,9 +1413,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" dependencies = [ "critical-section", "portable-atomic", @@ -1359,9 +1423,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "parking_lot" @@ -1394,18 +1458,18 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", @@ -1414,27 +1478,21 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "portable-atomic" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" dependencies = [ "zerovec", ] @@ -1466,18 +1524,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -1485,9 +1543,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", @@ -1498,9 +1556,9 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" dependencies = [ "prost", ] @@ -1518,8 +1576,8 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.5.10", - "thiserror 2.0.17", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -1527,9 +1585,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "aws-lc-rs", "bytes", @@ -1543,7 +1601,7 @@ dependencies = [ "rustls-pki-types", "rustls-platform-verifier", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -1558,16 +1616,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.43" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -1578,6 +1636,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "rand" version = "0.9.2" @@ -1600,9 +1664,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -1618,9 +1682,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -1630,9 +1694,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -1641,15 +1705,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64 0.22.1", "bytes", @@ -1695,7 +1759,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted 0.9.0", "windows-sys 0.52.0", @@ -1703,9 +1767,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" @@ -1718,9 +1782,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", "log", @@ -1746,9 +1810,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -1772,7 +1836,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1783,9 +1847,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ "aws-lc-rs", "ring", @@ -1823,9 +1887,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -1838,9 +1902,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -1853,9 +1917,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "3.5.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", "core-foundation", @@ -1866,9 +1930,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -1876,9 +1940,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -1912,9 +1976,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.148" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", @@ -1925,9 +1989,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -1994,21 +2058,21 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -2018,22 +2082,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -2056,9 +2110,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.114" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2102,11 +2156,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -2122,9 +2176,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", @@ -2142,28 +2196,28 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" dependencies = [ "displaydoc", "zerovec", @@ -2171,9 +2225,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -2186,16 +2240,16 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.49.0" +version = "1.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" dependencies = [ "bytes", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "tracing", "windows-sys 0.61.2", @@ -2203,9 +2257,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -2224,9 +2278,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -2247,9 +2301,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -2260,9 +2314,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.10+spec-1.1.0" +version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ "indexmap", "serde_core", @@ -2270,7 +2324,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow", + "winnow 0.7.15", ] [[package]] @@ -2284,24 +2338,24 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow", + "winnow 1.0.1", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", @@ -2316,7 +2370,7 @@ dependencies = [ "hyper-util", "percent-encoding", "pin-project", - "socket2 0.6.1", + "socket2", "sync_wrapper", "tokio", "tokio-stream", @@ -2328,9 +2382,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" dependencies = [ "bytes", "prost", @@ -2339,9 +2393,9 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -2425,9 +2479,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "once_cell", @@ -2457,7 +2511,7 @@ dependencies = [ "log", "rand", "sha1", - "thiserror 2.0.17", + "thiserror 2.0.18", "utf-8", ] @@ -2469,9 +2523,15 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -2487,9 +2547,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -2511,11 +2571,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.19.0" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", "wasm-bindgen", ] @@ -2559,18 +2619,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" dependencies = [ "cfg-if", "once_cell", @@ -2581,22 +2650,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" dependencies = [ - "cfg-if", "js-sys", - "once_cell", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2604,9 +2670,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" dependencies = [ "bumpalo", "proc-macro2", @@ -2617,18 +2683,52 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" dependencies = [ "js-sys", "wasm-bindgen", @@ -2646,32 +2746,32 @@ dependencies = [ [[package]] name = "web-transport-proto" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b5400535d6dd4c07dc86e83651a838fd513de7f5011d4e4eafa239fa4d0ded4" +checksum = "660175a6d1643adb93b71c4f853d4f20f0fce47f53ae579afe9f7711fe84870d" dependencies = [ "bytes", "http", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "url", ] [[package]] name = "web-transport-quinn" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91815d3170c715230c94b5107a71ccf81646513e548ee1408c3ce285d021d6ca" +checksum = "b1f44b4e68a3e7adb790793e24ec8b5923a610a8c2df1d6cd58849f9e4759d04" dependencies = [ "bytes", "futures", "http", - "log", "quinn", "rustls", "rustls-native-certs", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", + "tracing", "url", "web-transport-proto", "web-transport-trait", @@ -2679,27 +2779,27 @@ dependencies = [ [[package]] name = "web-transport-trait" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4bafa8c6ff708042f67ef8031ca0f342822fd785b70f36a4b2c014760fc442" +checksum = "cb67841c4a481ca3c1412ee4c9f463987401991e1ddc000903df2124f3dc85e9" dependencies = [ "bytes", ] [[package]] name = "webpki-root-certs" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -2716,7 +2816,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -2726,21 +2826,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-registry" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-targets 0.42.2", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -2785,21 +2905,6 @@ dependencies = [ "windows_x86_64_msvc 0.42.2", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -2839,12 +2944,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -2863,12 +2962,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -2887,12 +2980,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -2923,12 +3010,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -2947,12 +3028,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -2971,12 +3046,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -2995,12 +3064,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3015,31 +3078,109 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" [[package]] -name = "winreg" -version = "0.50.0" +name = "winnow" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "wit-bindgen-rust-macro", ] [[package]] -name = "wit-bindgen" -version = "0.46.0" +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "xdg" @@ -3082,9 +3223,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -3093,9 +3234,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", @@ -3105,18 +3246,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" dependencies = [ "proc-macro2", "quote", @@ -3125,18 +3266,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", @@ -3152,9 +3293,9 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" dependencies = [ "displaydoc", "yoke", @@ -3163,9 +3304,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" dependencies = [ "yoke", "zerofrom", @@ -3174,9 +3315,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", @@ -3185,6 +3326,6 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.5" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3280a1b827474fcd5dbef4b35a674deb52ba5c312363aef9135317df179d81b" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/fuzz/src/main.rs b/fuzz/src/main.rs index 3fb725d..6ed6a5b 100644 --- a/fuzz/src/main.rs +++ b/fuzz/src/main.rs @@ -33,7 +33,11 @@ fn main() { } Err(e) => { // more data is required, stanzafilter should never let this happen, let's panic - panic!("more data required? e: {:?}\nstanza: {}", e, String::from_utf8_lossy(stanza)); + panic!( + "more data required? e: {:?}\nstanza: {}", + e, + String::from_utf8_lossy(stanza) + ); } } } diff --git a/src/common/ca_roots.rs b/src/common/ca_roots.rs index 22f8852..927b87f 100644 --- a/src/common/ca_roots.rs +++ b/src/common/ca_roots.rs @@ -16,6 +16,11 @@ static ROOT_STORE: LazyLock> = LazyLock::new(|| { roots.into() }); -pub static SERVER_VERIFIER: LazyLock> = LazyLock::new(|| WebPkiServerVerifier::builder(ROOT_STORE.clone()).build().expect("couldn't create webpki verifier")); +pub static SERVER_VERIFIER: LazyLock> = LazyLock::new(|| { + WebPkiServerVerifier::builder(ROOT_STORE.clone()) + .build() + .expect("couldn't create webpki verifier") +}); -pub static TLS_SERVER_ROOTS: LazyLock<&[TrustAnchor<'static>]> = LazyLock::new(|| &ROOT_STORE.roots); +pub static TLS_SERVER_ROOTS: LazyLock<&[TrustAnchor<'static>]> = + LazyLock::new(|| &ROOT_STORE.roots); diff --git a/src/common/certs_key.rs b/src/common/certs_key.rs index f9077bd..fb62fd0 100644 --- a/src/common/certs_key.rs +++ b/src/common/certs_key.rs @@ -32,14 +32,20 @@ impl CertsKey { #[cfg(feature = "rustls-pemfile")] impl rustls::server::ResolvesServerCert for CertsKey { fn resolve(&self, _: rustls::server::ClientHello) -> Option> { - self.inner.as_ref().map(|rwl| rwl.read().expect("CertKey poisoned?").clone()).ok() + self.inner + .as_ref() + .map(|rwl| rwl.read().expect("CertKey poisoned?").clone()) + .ok() } } #[cfg(feature = "rustls-pemfile")] impl rustls::client::ResolvesClientCert for CertsKey { fn resolve(&self, _: &[&[u8]], _: &[SignatureScheme]) -> Option> { - self.inner.as_ref().map(|rwl| rwl.read().expect("CertKey poisoned?").clone()).ok() + self.inner + .as_ref() + .map(|rwl| rwl.read().expect("CertKey poisoned?").clone()) + .ok() } fn has_certs(&self) -> bool { diff --git a/src/common/incoming.rs b/src/common/incoming.rs index 4c83775..655b752 100644 --- a/src/common/incoming.rs +++ b/src/common/incoming.rs @@ -1,5 +1,8 @@ use crate::{ - common::{c2s, certs_key::CertsKey, shuffle_rd_wr_filter_only, stream_preamble, to_str, SocketAddrPath, ALPN_XMPP_CLIENT, ALPN_XMPP_SERVER}, + common::{ + c2s, certs_key::CertsKey, shuffle_rd_wr_filter_only, stream_preamble, to_str, + SocketAddrPath, ALPN_XMPP_CLIENT, ALPN_XMPP_SERVER, + }, context::Context, in_out::{StanzaRead, StanzaWrite}, slicesubsequence::SliceSubsequence, @@ -64,23 +67,39 @@ impl From<&ServerConnection> for ServerCerts { let sni = conn.server_name().map(|s| s.to_string()); let alpn = conn.alpn_protocol().map(|s| s.to_vec()); Self { - inner: InnerServerCerts { peer_certificates, sni, alpn }.into(), + inner: InnerServerCerts { + peer_certificates, + sni, + alpn, + } + .into(), is_tls: true, } } } -#[cfg(all(feature = "quic", any(feature = "s2s-incoming", feature = "webtransport")))] +#[cfg(all( + feature = "quic", + any(feature = "s2s-incoming", feature = "webtransport") +))] impl From<&quinn::Connection> for ServerCerts { fn from(conn: &quinn::Connection) -> Self { - let peer_certificates = conn.peer_identity().and_then(|v| v.downcast::>>().ok()).map(|v| v.to_vec()); + let peer_certificates = conn + .peer_identity() + .and_then(|v| v.downcast::>>().ok()) + .map(|v| v.to_vec()); let (sni, alpn) = conn .handshake_data() .and_then(|v| v.downcast::().ok()) .map(|h| (h.server_name, h.protocol)) .unwrap_or_default(); Self { - inner: InnerServerCerts { peer_certificates, sni, alpn }.into(), + inner: InnerServerCerts { + peer_certificates, + sni, + alpn, + } + .into(), is_tls: false, } } @@ -105,9 +124,25 @@ impl ServerCerts { } } -pub async fn shuffle_rd_wr(in_rd: StanzaRead, in_wr: StanzaWrite, config: Arc, server_certs: ServerCerts, local_addr: SocketAddr, client_addr: &mut Context<'_>) -> Result<()> { +pub async fn shuffle_rd_wr( + in_rd: StanzaRead, + in_wr: StanzaWrite, + config: Arc, + server_certs: ServerCerts, + local_addr: SocketAddr, + client_addr: &mut Context<'_>, +) -> Result<()> { let filter = StanzaFilter::new(config.max_stanza_size_bytes); - shuffle_rd_wr_filter(in_rd, in_wr, config, server_certs, local_addr, client_addr, filter).await + shuffle_rd_wr_filter( + in_rd, + in_wr, + config, + server_certs, + local_addr, + client_addr, + filter, + ) + .await } pub async fn shuffle_rd_wr_filter( @@ -120,7 +155,13 @@ pub async fn shuffle_rd_wr_filter( mut in_filter: StanzaFilter, ) -> Result<()> { // now read to figure out client vs server - let (stream_open, is_c2s) = stream_preamble(&mut in_rd, &mut in_wr, client_addr.log_from(), &mut in_filter).await?; + let (stream_open, is_c2s) = stream_preamble( + &mut in_rd, + &mut in_wr, + client_addr.log_from(), + &mut in_filter, + ) + .await?; client_addr.set_c2s_stream_open(is_c2s, &stream_open); #[cfg(feature = "s2s-incoming")] @@ -129,7 +170,9 @@ pub async fn shuffle_rd_wr_filter( "{} connected: sni: {:?}, alpn: {:?}, tls-not-quic: {}", client_addr.log_from(), server_certs.sni(), - server_certs.alpn().map(|a| String::from_utf8_lossy(a).to_string()), + server_certs + .alpn() + .map(|a| String::from_utf8_lossy(a).to_string()), server_certs.is_tls(), ); @@ -140,17 +183,37 @@ pub async fn shuffle_rd_wr_filter( .or_else(|_| stream_open.extract_between(b" from=\"", b"\"")) .and_then(|b| Ok(std::str::from_utf8(b)?))?; let (_, cert_verifier) = crate::srv::get_xmpp_connections(domain, is_c2s).await?; - let certs = server_certs.peer_certificates().ok_or_else(|| anyhow!("no client cert auth for s2s incoming from {}", domain))?; + let certs = server_certs + .peer_certificates() + .ok_or_else(|| anyhow!("no client cert auth for s2s incoming from {}", domain))?; // todo: send stream error saying cert is invalid cert_verifier.verify_cert(&certs[0], &certs[1..], UnixTime::now())?; } drop(server_certs); } - let (out_rd, out_wr) = open_incoming(&config, local_addr, client_addr, &stream_open, is_c2s, &mut in_filter).await?; + let (out_rd, out_wr) = open_incoming( + &config, + local_addr, + client_addr, + &stream_open, + is_c2s, + &mut in_filter, + ) + .await?; drop(stream_open); - shuffle_rd_wr_filter_only(in_rd, in_wr, out_rd, out_wr, is_c2s, config.max_stanza_size_bytes, client_addr, in_filter).await + shuffle_rd_wr_filter_only( + in_rd, + in_wr, + out_rd, + out_wr, + is_c2s, + config.max_stanza_size_bytes, + client_addr, + in_filter, + ) + .await } async fn open_incoming( @@ -172,7 +235,12 @@ async fn open_incoming( #[cfg(feature = "s2s-incoming")] &config.s2s_target }; - let target = target.as_ref().ok_or_else(|| anyhow!("incoming connection but `{}_target` not defined", c2s(is_c2s)))?; + let target = target.as_ref().ok_or_else(|| { + anyhow!( + "incoming connection but `{}_target` not defined", + c2s(is_c2s) + ) + })?; client_addr.set_to_addr(target.to_string()); let (out_rd, mut out_wr) = target.connect().await?; @@ -190,14 +258,22 @@ async fn open_incoming( write!( &mut in_filter.buf[0..], "PROXY TCP{} {} {} {} {}\r\n", - if client_addr.client_addr().is_ipv4() { '4' } else { '6' }, + if client_addr.client_addr().is_ipv4() { + '4' + } else { + '6' + }, client_addr.client_addr().ip(), local_addr.ip(), client_addr.client_addr().port(), local_addr.port() )?; let end_idx = &(&in_filter.buf[0..]).first_index_of(b"\n")? + 1; - trace!("{} '{}'", client_addr.log_from(), to_str(&in_filter.buf[0..end_idx])); + trace!( + "{} '{}'", + client_addr.log_from(), + to_str(&in_filter.buf[0..end_idx]) + ); out_wr.write_all(&in_filter.buf[0..end_idx]).await?; } trace!("{} '{}'", client_addr.log_from(), to_str(stream_open)); diff --git a/src/common/mod.rs b/src/common/mod.rs index 1314e8f..5523d39 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -42,8 +42,14 @@ pub const ALPN_XMPP_SERVER: &[u8] = b"xmpp-server"; pub trait AsyncReadAndWrite: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send {} impl AsyncReadAndWrite for T {} -pub trait AsyncReadWritePeekSplit: tokio::io::AsyncRead + tokio::io::AsyncWrite + Peek + Send + 'static + Unpin + Split {} -impl AsyncReadWritePeekSplit for T {} +pub trait AsyncReadWritePeekSplit: + tokio::io::AsyncRead + tokio::io::AsyncWrite + Peek + Send + 'static + Unpin + Split +{ +} +impl + AsyncReadWritePeekSplit for T +{ +} pub type BoxAsyncReadWrite = Box; pub type BufAsyncReadWrite = BufStream; @@ -73,11 +79,18 @@ pub enum SocketAddrPath { } impl SocketAddrPath { - pub async fn connect(&self) -> Result<(Box, Box)> { + pub async fn connect( + &self, + ) -> Result<( + Box, + Box, + )> { Ok(match self { SocketAddrPath::SocketAddr(sa) => TcpStream::connect(sa).await?.split_boxed(), #[cfg(not(target_os = "windows"))] - SocketAddrPath::Path(path) => tokio::net::UnixStream::connect(path).await?.split_boxed(), + SocketAddrPath::Path(path) => { + tokio::net::UnixStream::connect(path).await?.split_boxed() + } }) } @@ -93,7 +106,9 @@ impl SocketAddrPath { Ok(match self { SocketAddrPath::SocketAddr(sa) => UdpListener::Udp(UdpSocket::bind(sa)?), #[cfg(not(target_os = "windows"))] - SocketAddrPath::Path(path) => UdpListener::Unix(std::os::unix::net::UnixDatagram::bind(path)?), + SocketAddrPath::Path(path) => { + UdpListener::Unix(std::os::unix::net::UnixDatagram::bind(path)?) + } }) } } @@ -125,7 +140,9 @@ impl<'de> Deserialize<'de> for SocketAddrPath { } #[cfg(target_os = "windows")] { - Ok(SocketAddrPath::SocketAddr(SocketAddr::deserialize(deserializer)?)) + Ok(SocketAddrPath::SocketAddr(SocketAddr::deserialize( + deserializer, + )?)) } } } @@ -152,7 +169,12 @@ pub trait Split: Sized { fn stanza_rw(self) -> (StanzaRead, StanzaWrite); - fn split_boxed(self) -> (Box, Box) { + fn split_boxed( + self, + ) -> ( + Box, + Box, + ) { let (rd, wr) = self.split(); (Box::new(rd), Box::new(wr)) } @@ -177,7 +199,9 @@ impl Split for TcpStream { } #[cfg(feature = "tokio-rustls")] -impl Split for tokio_rustls::server::TlsStream { +impl Split + for tokio_rustls::server::TlsStream +{ type ReadHalf = tokio::io::ReadHalf>; type WriteHalf = tokio::io::WriteHalf>; @@ -244,7 +268,11 @@ impl Split for BufStream pub trait Peek { async fn peek_bytes<'a>(&mut self, p: &'a mut [u8]) -> anyhow::Result<&'a [u8]>; - async fn first_bytes_match<'a>(&mut self, p: &'a mut [u8], matcher: fn(&'a [u8]) -> bool) -> Result { + async fn first_bytes_match<'a>( + &mut self, + p: &'a mut [u8], + matcher: fn(&'a [u8]) -> bool, + ) -> Result { Ok(matcher(self.peek_bytes(p).await?)) } } @@ -326,7 +354,12 @@ impl Peek for BufReader { } /// Caution: this will loop forever, call timeout variant `first_bytes_match_buf_timeout` -async fn first_bytes_match_buf(duration: Duration, stream: &mut (dyn AsyncBufRead + Send + Unpin), len: usize, matcher: fn(&[u8]) -> bool) -> Result { +async fn first_bytes_match_buf( + duration: Duration, + stream: &mut (dyn AsyncBufRead + Send + Unpin), + len: usize, + matcher: fn(&[u8]) -> bool, +) -> Result { use tokio::io::AsyncBufReadExt; let start = std::time::Instant::now(); loop { @@ -342,20 +375,41 @@ async fn first_bytes_match_buf(duration: Duration, stream: &mut (dyn AsyncBufRea } } -pub async fn first_bytes_match_buf_timeout(stream: &mut (dyn AsyncBufRead + Send + Unpin), len: usize, matcher: fn(&[u8]) -> bool) -> Result { +pub async fn first_bytes_match_buf_timeout( + stream: &mut (dyn AsyncBufRead + Send + Unpin), + len: usize, + matcher: fn(&[u8]) -> bool, +) -> Result { // wait up to 10 seconds until 3 bytes have been read - tokio::time::timeout(Duration::from_secs(10), first_bytes_match_buf(Duration::from_secs(20), stream, len, matcher)).await? + tokio::time::timeout( + Duration::from_secs(10), + first_bytes_match_buf(Duration::from_secs(20), stream, len, matcher), + ) + .await? } -pub async fn stream_preamble(in_rd: &mut StanzaRead, in_wr: &mut StanzaWrite, client_addr: &'_ str, in_filter: &mut StanzaFilter) -> Result<(Vec, bool)> { +pub async fn stream_preamble( + in_rd: &mut StanzaRead, + in_wr: &mut StanzaWrite, + client_addr: &'_ str, + in_filter: &mut StanzaFilter, +) -> Result<(Vec, bool)> { let mut stream_open = Vec::new(); while let Ok(Some((buf, _))) = in_rd.next(in_filter, client_addr, in_wr).await { - trace!("{} received pre- stanza: '{}'", client_addr, to_str(buf)); + trace!( + "{} received pre- stanza: '{}'", + client_addr, + to_str(buf) + ); if buf.starts_with(b" stanza: {}", to_str(buf)); } @@ -410,7 +464,9 @@ pub async fn shuffle_rd_wr_filter_only( pub fn read_certified_key(tls_key: &str, tls_cert: &str) -> Result { use rustls::pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer}; - let key = rustls::crypto::CryptoProvider::get_default().expect("no crypto provider set").key_provider; + let key = rustls::crypto::CryptoProvider::get_default() + .expect("no crypto provider set") + .key_provider; let tls_key = PrivateKeyDer::pem_file_iter(tls_key)? .flat_map(|item| match item { diff --git a/src/common/outgoing.rs b/src/common/outgoing.rs index 49416e6..129ca55 100644 --- a/src/common/outgoing.rs +++ b/src/common/outgoing.rs @@ -10,17 +10,31 @@ pub struct OutgoingConfig { } impl OutgoingConfig { - pub fn with_custom_certificate_verifier(&self, is_c2s: bool, cert_verifier: Arc) -> OutgoingVerifierConfig { + pub fn with_custom_certificate_verifier( + &self, + is_c2s: bool, + cert_verifier: Arc, + ) -> OutgoingVerifierConfig { let config = match is_c2s { false => ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(cert_verifier) .with_client_cert_resolver(self.certs_key.clone()), - _ => ClientConfig::builder().dangerous().with_custom_certificate_verifier(cert_verifier).with_no_client_auth(), + _ => ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(cert_verifier) + .with_no_client_auth(), }; let mut config_alpn = config.clone(); - config_alpn.alpn_protocols.push(if is_c2s { ALPN_XMPP_CLIENT } else { ALPN_XMPP_SERVER }.to_vec()); + config_alpn.alpn_protocols.push( + if is_c2s { + ALPN_XMPP_CLIENT + } else { + ALPN_XMPP_SERVER + } + .to_vec(), + ); let config_alpn = Arc::new(config_alpn); diff --git a/src/common/stream_listener.rs b/src/common/stream_listener.rs index 77e70b9..54be0e0 100644 --- a/src/common/stream_listener.rs +++ b/src/common/stream_listener.rs @@ -59,7 +59,11 @@ pub enum AllStream { } impl AsyncRead for AllStream { - fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll> { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { match self.get_mut() { AllStream::Tcp(s) => Pin::new(s).poll_read(cx, buf), #[cfg(not(target_os = "windows"))] @@ -69,7 +73,11 @@ impl AsyncRead for AllStream { } impl AsyncWrite for AllStream { - fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { match self.get_mut() { AllStream::Tcp(s) => Pin::new(s).poll_write(cx, buf), #[cfg(not(target_os = "windows"))] @@ -77,7 +85,10 @@ impl AsyncWrite for AllStream { } } - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_flush( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { match self.get_mut() { AllStream::Tcp(s) => Pin::new(s).poll_flush(cx), #[cfg(not(target_os = "windows"))] @@ -85,7 +96,10 @@ impl AsyncWrite for AllStream { } } - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { match self.get_mut() { AllStream::Tcp(s) => Pin::new(s).poll_shutdown(cx), #[cfg(not(target_os = "windows"))] @@ -93,7 +107,11 @@ impl AsyncWrite for AllStream { } } - fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<'_>, bufs: &[IoSlice<'_>]) -> Poll> { + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { match self.get_mut() { AllStream::Tcp(s) => Pin::new(s).poll_write_vectored(cx, bufs), #[cfg(not(target_os = "windows"))] diff --git a/src/context.rs b/src/context.rs index d592a76..d277337 100644 --- a/src/context.rs +++ b/src/context.rs @@ -24,7 +24,11 @@ impl Context<'_> { #[cfg(feature = "logging")] let conn_id = { use rand::{distr::Alphanumeric, rng, Rng}; - rng().sample_iter(&Alphanumeric).take(10).map(char::from).collect() + rng() + .sample_iter(&Alphanumeric) + .take(10) + .map(char::from) + .collect() }; #[cfg(not(feature = "logging"))] let conn_id = "".to_string(); @@ -56,11 +60,11 @@ impl Context<'_> { "{}: ({} ({}) -> ({}-{}) -> {} ({})):", self.conn_id, self.client_addr, - if self.from.is_some() { self.from.as_ref().unwrap() } else { "unk" }, + self.from.as_deref().unwrap_or("unk"), self.proto, - if self.is_c2s.is_some() { c2s(self.is_c2s.unwrap()) } else { "unk" }, - if self.to_addr.is_some() { self.to_addr.as_ref().unwrap() } else { "unk" }, - if self.to.is_some() { self.to.as_ref().unwrap() } else { "unk" }, + self.is_c2s.map(c2s).unwrap_or("unk"), + self.to_addr.as_deref().unwrap_or("unk"), + self.to.as_deref().unwrap_or("unk"), ); self.log_to = self.log_from.replace(" -> ", " <- "); } diff --git a/src/in_out.rs b/src/in_out.rs index faad43b..7eeaae9 100644 --- a/src/in_out.rs +++ b/src/in_out.rs @@ -34,7 +34,13 @@ impl StanzaWrite { //AsyncWrite(Box::new(tokio::io::BufWriter::with_capacity(8192, wr))) } - pub async fn write_all<'a>(&'a mut self, is_c2s: bool, buf: &'a [u8], end_of_first_tag: usize, client_addr: &'a str) -> Result<()> { + pub async fn write_all<'a>( + &'a mut self, + is_c2s: bool, + buf: &'a [u8], + end_of_first_tag: usize, + client_addr: &'a str, + ) -> Result<()> { match self { AsyncWrite(wr) => Ok(wr.write_all(buf).await?), #[cfg(feature = "websocket")] @@ -71,7 +77,10 @@ impl StanzaRead { #[inline(always)] pub fn new(rd: T) -> Self { // we naively read 1 byte at a time, which buffering significantly speeds up - AsyncRead(StanzaReader(Box::new(BufReader::with_capacity(IN_BUFFER_SIZE, rd)))) + AsyncRead(StanzaReader(Box::new(BufReader::with_capacity( + IN_BUFFER_SIZE, + rd, + )))) } #[inline(always)] @@ -80,7 +89,12 @@ impl StanzaRead { AsyncRead(StanzaReader(Box::new(rd))) } - pub async fn next<'a>(&'a mut self, filter: &'a mut StanzaFilter, client_addr: &'a str, wrt: &mut StanzaWrite) -> Result> { + pub async fn next<'a>( + &'a mut self, + filter: &'a mut StanzaFilter, + client_addr: &'a str, + wrt: &mut StanzaWrite, + ) -> Result> { match self { AsyncRead(rd) => rd.next_eoft(filter).await, #[cfg(feature = "websocket")] diff --git a/src/lib.rs b/src/lib.rs index 2ed9fb4..b365f5d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,8 @@ pub mod context; pub mod in_out; #[cfg(feature = "rustls")] -pub fn install_default_rustls_provider() -> Result<(), std::sync::Arc> { +pub fn install_default_rustls_provider( +) -> Result<(), std::sync::Arc> { // set up default crypto provider, only one of these can be called #[cfg(all(feature = "tls-aws-lc-rs", not(feature = "tls-ring")))] use rustls::crypto::aws_lc_rs as provider; diff --git a/src/main.rs b/src/main.rs index b2a6a2a..e534512 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,7 +84,10 @@ impl Config { } #[cfg(all(unix, any(feature = "incoming", feature = "s2s-outgoing")))] -fn spawn_refresh_task(certs_key: &'static CertsKey, cfg_path: OsString) -> Option>> { +fn spawn_refresh_task( + certs_key: &'static CertsKey, + cfg_path: OsString, +) -> Option>> { if certs_key.inner.is_err() { None } else { @@ -128,7 +131,9 @@ async fn main() { #[cfg(feature = "logging")] { use env_logger::{Builder, Env, Target}; - let env = Env::default().filter_or("XMPP_PROXY_LOG_LEVEL", "info").write_style_or("XMPP_PROXY_LOG_STYLE", "never"); + let env = Env::default() + .filter_or("XMPP_PROXY_LOG_LEVEL", "info") + .write_style_or("XMPP_PROXY_LOG_STYLE", "never"); let mut builder = Builder::from_env(env); builder.target(Target::Stdout); if let Some(ref log_level) = main_config.log_level { @@ -151,7 +156,11 @@ async fn main() { } let mut quic_listen = Vec::new(); for a in main_config.quic_listen.iter() { - quic_listen.push(a.bind_udp().await.die("cannot listen on port/interface/socket")); + quic_listen.push( + a.bind_udp() + .await + .die("cannot listen on port/interface/socket"), + ); } let mut outgoing_listen = Vec::new(); for a in main_config.outgoing_listen.iter() { @@ -164,14 +173,20 @@ async fn main() { for fd in fds { match fd.listener() { SystemdListener::Tcp(tcp_listener) => { - let listener = Listener::Tcp(TcpListener::from_std(tcp_listener()).die("cannot open systemd TcpListener")); + let listener = Listener::Tcp( + TcpListener::from_std(tcp_listener()) + .die("cannot open systemd TcpListener"), + ); if let Some(name) = fd.name().map(|n| n.to_ascii_lowercase()) { if name.starts_with("in") { incoming_listen.push(listener); } else if name.starts_with("out") { outgoing_listen.push(listener); } else { - die!("systemd TCP socket name must start with 'in' or 'out' but is '{}'", name); + die!( + "systemd TCP socket name must start with 'in' or 'out' but is '{}'", + name + ); } } else { // what to do here... for now we will require names @@ -180,7 +195,10 @@ async fn main() { } } SystemdListener::UnixListener(unix_listener) => { - let listener = Listener::Unix(UnixListener::from_std(unix_listener()).die("cannot open systemd UnixListener")); + let listener = Listener::Unix( + UnixListener::from_std(unix_listener()) + .die("cannot open systemd UnixListener"), + ); if let Some(name) = fd.name().map(|n| n.to_ascii_lowercase()) { if name.starts_with("in") { incoming_listen.push(listener); @@ -194,8 +212,12 @@ async fn main() { die!("systemd Unix socket activation requires name that starts with 'in' or 'out'"); } } - SystemdListener::Udp(udp_socket) => quic_listen.push(UdpListener::Udp(udp_socket())), - SystemdListener::UnixDatagram(unix_datagram) => quic_listen.push(UdpListener::Unix(unix_datagram())), + SystemdListener::Udp(udp_socket) => { + quic_listen.push(UdpListener::Udp(udp_socket())) + } + SystemdListener::UnixDatagram(unix_datagram) => { + quic_listen.push(UdpListener::Unix(unix_datagram())) + } } } } @@ -214,16 +236,26 @@ async fn main() { tls::incoming::{spawn_tls_listener, tls_acceptor}, }; if main_config.c2s_target.is_none() && main_config.s2s_target.is_none() { - die!("one of c2s_target/s2s_target must be defined if incoming_listen is non-empty"); + die!( + "one of c2s_target/s2s_target must be defined if incoming_listen is non-empty" + ); } let acceptor = tls_acceptor(server_config(certs_key.clone()).die("invalid cert/key ?")); for listener in incoming_listen { // todo: first is slower at runtime but smaller executable size, second opposite //handles.push(spawn_tls_listener(listener, config.clone(), acceptor.clone())); match listener { - Listener::Tcp(listener) => handles.push(spawn_tls_listener(listener, config.clone(), acceptor.clone())), + Listener::Tcp(listener) => handles.push(spawn_tls_listener( + listener, + config.clone(), + acceptor.clone(), + )), #[cfg(not(target_os = "windows"))] - Listener::Unix(listener) => handles.push(spawn_tls_listener(listener, config.clone(), acceptor.clone())), + Listener::Unix(listener) => handles.push(spawn_tls_listener( + listener, + config.clone(), + acceptor.clone(), + )), } } } @@ -240,14 +272,26 @@ async fn main() { if main_config.c2s_target.is_none() && main_config.s2s_target.is_none() { die!("one of c2s_target/s2s_target must be defined if quic_listen is non-empty"); } - let quic_config = quic_server_config(server_config(certs_key.clone()).die("invalid cert/key ?")).die("invalid quick server config"); + let quic_config = + quic_server_config(server_config(certs_key.clone()).die("invalid cert/key ?")) + .die("invalid quick server config"); for listener in quic_listen { // todo: maybe write a way to Box this thing for smaller executable sizes //handles.push(spawn_quic_listener(listener, config.clone(), quic_config.clone())); match listener { - UdpListener::Udp(listener) => handles.push(spawn_quic_listener(listener, config.clone(), quic_config.clone())), + UdpListener::Udp(listener) => handles.push(spawn_quic_listener( + listener, + config.clone(), + quic_config.clone(), + )), #[cfg(not(target_os = "windows"))] - UdpListener::Unix(listener) => handles.push(xmpp_proxy::quic::incoming::spawn_quic_listener_unix(listener, config.clone(), quic_config.clone())), + UdpListener::Unix(listener) => { + handles.push(xmpp_proxy::quic::incoming::spawn_quic_listener_unix( + listener, + config.clone(), + quic_config.clone(), + )) + } } } } @@ -262,17 +306,25 @@ async fn main() { // todo: first is slower at runtime but smaller executable size, second opposite //handles.push(spawn_outgoing_listener(listener, outgoing_cfg.clone())); match listener { - Listener::Tcp(listener) => handles.push(spawn_outgoing_listener(listener, outgoing_cfg.clone())), + Listener::Tcp(listener) => { + handles.push(spawn_outgoing_listener(listener, outgoing_cfg.clone())) + } #[cfg(not(target_os = "windows"))] - Listener::Unix(listener) => handles.push(spawn_outgoing_listener(listener, outgoing_cfg.clone())), + Listener::Unix(listener) => { + handles.push(spawn_outgoing_listener(listener, outgoing_cfg.clone())) + } } } } #[cfg(not(feature = "outgoing"))] - die!("outgoing_listen non-empty but c2s-outgoing and s2s-outgoing disabled at compile-time"); + die!( + "outgoing_listen non-empty but c2s-outgoing and s2s-outgoing disabled at compile-time" + ); } if handles.is_empty() { - die!("all of incoming_listen, quic_listen, outgoing_listen empty, nothing to do, exiting..."); + die!( + "all of incoming_listen, quic_listen, outgoing_listen empty, nothing to do, exiting..." + ); } #[cfg(all(unix, any(feature = "incoming", feature = "s2s-outgoing")))] { diff --git a/src/outgoing.rs b/src/outgoing.rs index 8012d44..f6f52fd 100644 --- a/src/outgoing.rs +++ b/src/outgoing.rs @@ -1,5 +1,8 @@ use crate::{ - common::{outgoing::OutgoingConfig, shuffle_rd_wr_filter_only, stream_listener::StreamListener, stream_preamble, AsyncReadWritePeekSplit}, + common::{ + outgoing::OutgoingConfig, shuffle_rd_wr_filter_only, stream_listener::StreamListener, + stream_preamble, AsyncReadWritePeekSplit, + }, context::Context, slicesubsequence::SliceSubsequence, srv::srv_connect, @@ -10,14 +13,25 @@ use log::{error, info}; use tokio::task::JoinHandle; -async fn handle_outgoing_connection(mut stream: S, client_addr: &mut Context<'_>, config: OutgoingConfig) -> Result<()> { +async fn handle_outgoing_connection( + mut stream: S, + client_addr: &mut Context<'_>, + config: OutgoingConfig, +) -> Result<()> { info!("{} connected", client_addr.log_from()); let mut in_filter = StanzaFilter::new(config.max_stanza_size_bytes); #[cfg(feature = "websocket")] - let (mut in_rd, mut in_wr) = if stream.first_bytes_match(&mut in_filter.buf[0..3], |p| p == b"GET").await? { - crate::websocket::incoming_websocket_connection(Box::new(stream), config.max_stanza_size_bytes).await? + let (mut in_rd, mut in_wr) = if stream + .first_bytes_match(&mut in_filter.buf[0..3], |p| p == b"GET") + .await? + { + crate::websocket::incoming_websocket_connection( + Box::new(stream), + config.max_stanza_size_bytes, + ) + .await? } else { stream.stanza_rw() }; @@ -26,23 +40,51 @@ async fn handle_outgoing_connection(mut stream: S, c let (mut in_rd, mut in_wr) = stream.stanza_rw(); // now read to figure out client vs server - let (stream_open, is_c2s) = stream_preamble(&mut in_rd, &mut in_wr, client_addr.log_to(), &mut in_filter).await?; + let (stream_open, is_c2s) = + stream_preamble(&mut in_rd, &mut in_wr, client_addr.log_to(), &mut in_filter).await?; client_addr.set_c2s_stream_open(is_c2s, &stream_open); // we require a valid to= here or we fail - let to = std::str::from_utf8(stream_open.extract_between(b" to='", b"'").or_else(|_| stream_open.extract_between(b" to=\"", b"\""))?)?; + let to = std::str::from_utf8( + stream_open + .extract_between(b" to='", b"'") + .or_else(|_| stream_open.extract_between(b" to=\"", b"\""))?, + )?; let max_stanza_size_bytes = config.max_stanza_size_bytes; - let (out_wr, out_rd, stream_open) = srv_connect(to, is_c2s, &stream_open, &mut in_filter, client_addr, config).await?; + let (out_wr, out_rd, stream_open) = srv_connect( + to, + is_c2s, + &stream_open, + &mut in_filter, + client_addr, + config, + ) + .await?; // send server response to client - in_wr.write_all(is_c2s, &stream_open, 0, client_addr.log_from()).await?; + in_wr + .write_all(is_c2s, &stream_open, 0, client_addr.log_from()) + .await?; in_wr.flush().await?; drop(stream_open); - shuffle_rd_wr_filter_only(in_rd, in_wr, out_rd, out_wr, is_c2s, max_stanza_size_bytes, client_addr, in_filter).await + shuffle_rd_wr_filter_only( + in_rd, + in_wr, + out_rd, + out_wr, + is_c2s, + max_stanza_size_bytes, + client_addr, + in_filter, + ) + .await } -pub fn spawn_outgoing_listener(listener: impl StreamListener, config: OutgoingConfig) -> JoinHandle> { +pub fn spawn_outgoing_listener( + listener: impl StreamListener, + config: OutgoingConfig, +) -> JoinHandle> { tokio::spawn(async move { loop { let (stream, client_addr) = listener.accept().await?; diff --git a/src/quic/incoming.rs b/src/quic/incoming.rs index f3781ae..d454ac2 100644 --- a/src/quic/incoming.rs +++ b/src/quic/incoming.rs @@ -7,7 +7,10 @@ use crate::{ use anyhow::Result; use die::Die; use log::{error, info}; -use quinn::{crypto::rustls::QuicServerConfig, AsyncUdpSocket, Endpoint, EndpointConfig, ServerConfig, TokioRuntime}; +use quinn::{ + crypto::rustls::QuicServerConfig, AsyncUdpSocket, Endpoint, EndpointConfig, ServerConfig, + TokioRuntime, +}; use std::{ net::{SocketAddr, UdpSocket}, sync::Arc, @@ -15,22 +18,51 @@ use std::{ use tokio::task::JoinHandle; #[cfg(not(target_os = "windows"))] -pub fn spawn_quic_listener_unix(udp_socket: std::os::unix::net::UnixDatagram, config: Arc, server_config: ServerConfig) -> JoinHandle> { - let udp_socket = crate::quic::unix_datagram::wrap_unix_udp_socket(udp_socket).die("cannot wrap unix udp socket"); +pub fn spawn_quic_listener_unix( + udp_socket: std::os::unix::net::UnixDatagram, + config: Arc, + server_config: ServerConfig, +) -> JoinHandle> { + let udp_socket = crate::quic::unix_datagram::wrap_unix_udp_socket(udp_socket) + .die("cannot wrap unix udp socket"); let udp_socket = Arc::new(udp_socket); // todo: fake local_addr - let local_addr = udp_socket.local_addr().die("cannot get local_addr for quic socket"); - let incoming = Endpoint::new_with_abstract_socket(EndpointConfig::default(), Some(server_config), udp_socket, Arc::new(TokioRuntime)).die("cannot listen on port/interface"); + let local_addr = udp_socket + .local_addr() + .die("cannot get local_addr for quic socket"); + let incoming = Endpoint::new_with_abstract_socket( + EndpointConfig::default(), + Some(server_config), + udp_socket, + Arc::new(TokioRuntime), + ) + .die("cannot listen on port/interface"); internal_spawn_quic_listener(incoming, local_addr, config) } -pub fn spawn_quic_listener(udp_socket: UdpSocket, config: Arc, server_config: ServerConfig) -> JoinHandle> { - let local_addr = udp_socket.local_addr().die("cannot get local_addr for quic socket"); - let incoming = Endpoint::new(EndpointConfig::default(), Some(server_config), udp_socket, Arc::new(TokioRuntime)).die("cannot listen on port/interface"); +pub fn spawn_quic_listener( + udp_socket: UdpSocket, + config: Arc, + server_config: ServerConfig, +) -> JoinHandle> { + let local_addr = udp_socket + .local_addr() + .die("cannot get local_addr for quic socket"); + let incoming = Endpoint::new( + EndpointConfig::default(), + Some(server_config), + udp_socket, + Arc::new(TokioRuntime), + ) + .die("cannot listen on port/interface"); internal_spawn_quic_listener(incoming, local_addr, config) } -fn internal_spawn_quic_listener(incoming: Endpoint, local_addr: SocketAddr, config: Arc) -> JoinHandle> { +fn internal_spawn_quic_listener( + incoming: Endpoint, + local_addr: SocketAddr, + config: Arc, +) -> JoinHandle> { tokio::spawn(async move { // when could this return None, do we quit? while let Some(incoming_conn) = incoming.accept().await { @@ -44,15 +76,27 @@ fn internal_spawn_quic_listener(incoming: Endpoint, local_addr: SocketAddr, conf let server_certs = { let server_certs = ServerCerts::from(&new_conn); #[cfg(feature = "webtransport")] - if server_certs.alpn().map(|a| a == web_transport_quinn::ALPN.as_bytes()).unwrap_or(false) { - return crate::webtransport::incoming::handle_webtransport_session(new_conn, config, server_certs, local_addr, client_addr).await; + if server_certs + .alpn() + .map(|a| a == web_transport_quinn::ALPN.as_bytes()) + .unwrap_or(false) + { + return crate::webtransport::incoming::handle_webtransport_session( + new_conn, + config, + server_certs, + local_addr, + client_addr, + ) + .await; } server_certs }; #[cfg(not(any(feature = "s2s-incoming", feature = "webtransport")))] let server_certs = (); - handle_quic_session(new_conn, config, server_certs, local_addr, client_addr).await + handle_quic_session(new_conn, config, server_certs, local_addr, client_addr) + .await } }); } @@ -61,14 +105,29 @@ fn internal_spawn_quic_listener(incoming: Endpoint, local_addr: SocketAddr, conf }) } -pub async fn handle_quic_session(conn: quinn::Connection, config: Arc, server_certs: ServerCerts, local_addr: SocketAddr, client_addr: Context<'static>) { +pub async fn handle_quic_session( + conn: quinn::Connection, + config: Arc, + server_certs: ServerCerts, + local_addr: SocketAddr, + client_addr: Context<'static>, +) { while let Ok((wrt, rd)) = conn.accept_bi().await { let config = config.clone(); let mut client_addr = client_addr.clone(); let server_certs = server_certs.clone(); info!("{} connected new stream", client_addr.log_from()); tokio::spawn(async move { - if let Err(e) = shuffle_rd_wr(StanzaRead::new(rd), StanzaWrite::new(wrt), config, server_certs, local_addr, &mut client_addr).await { + if let Err(e) = shuffle_rd_wr( + StanzaRead::new(rd), + StanzaWrite::new(wrt), + config, + server_certs, + local_addr, + &mut client_addr, + ) + .await + { error!("{} {}", client_addr.log_from(), e); } }); @@ -77,12 +136,17 @@ pub async fn handle_quic_session(conn: quinn::Connection, config: Arc Result { #[cfg(feature = "webtransport")] - server_config.alpn_protocols.push(web_transport_quinn::ALPN.as_bytes().to_vec()); + server_config + .alpn_protocols + .push(web_transport_quinn::ALPN.as_bytes().to_vec()); let transport_config = quinn::TransportConfig::default(); // todo: configure transport_config here if needed let suite = initial_suite_from_provider()?; - let server_config = Arc::new(QuicServerConfig::with_initial(Arc::new(server_config), suite)?); + let server_config = Arc::new(QuicServerConfig::with_initial( + Arc::new(server_config), + suite, + )?); let mut server_config = ServerConfig::with_crypto(server_config); server_config.transport = Arc::new(transport_config); diff --git a/src/quic/mod.rs b/src/quic/mod.rs index 9dd2046..13fbb6f 100644 --- a/src/quic/mod.rs +++ b/src/quic/mod.rs @@ -27,14 +27,24 @@ pub struct QuicStream { } impl AsyncRead for QuicStream { - fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll> { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { Pin::new(&mut self.recv).poll_read(cx, buf) } } impl AsyncWrite for QuicStream { - fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - Pin::new(&mut self.send).poll_write(cx, buf).map_err(|e| Error::other(e)) + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + Pin::new(&mut self.send) + .poll_write(cx, buf) + .map_err(Error::other) } fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { diff --git a/src/quic/outgoing.rs b/src/quic/outgoing.rs index 8dcee7e..fbf671e 100644 --- a/src/quic/outgoing.rs +++ b/src/quic/outgoing.rs @@ -20,12 +20,20 @@ impl OutgoingVerifierConfig { } pub fn quic_endpoint(&self) -> &Result { - self.quic_endpoint.get_or_init(|| self.qe().map_err(|e: anyhow::Error| format!("{e}"))) + self.quic_endpoint + .get_or_init(|| self.qe().map_err(|e: anyhow::Error| format!("{e}"))) } } -pub async fn quic_connect(target: SocketAddr, server_name: &str, config: &OutgoingVerifierConfig) -> anyhow::Result<(StanzaWrite, StanzaRead)> { - let endpoint = config.quic_endpoint().as_ref().map_err(|e| anyhow::anyhow!("quic endpoint error: {e}"))?; +pub async fn quic_connect( + target: SocketAddr, + server_name: &str, + config: &OutgoingVerifierConfig, +) -> anyhow::Result<(StanzaWrite, StanzaRead)> { + let endpoint = config + .quic_endpoint() + .as_ref() + .map_err(|e| anyhow::anyhow!("quic endpoint error: {e}"))?; // connect to server let connection = endpoint.connect(target, server_name)?.await?; diff --git a/src/quic/unix_datagram.rs b/src/quic/unix_datagram.rs index 4f04c20..8f3baa0 100644 --- a/src/quic/unix_datagram.rs +++ b/src/quic/unix_datagram.rs @@ -44,13 +44,22 @@ impl AsyncUdpSocket for UnixUdpSocket { } fn try_send(&self, transmit: &Transmit) -> io::Result<()> { - self.io.try_io(Interest::WRITABLE, || self.inner.send((&self.io).into(), transmit)) + self.io.try_io(Interest::WRITABLE, || { + self.inner.send((&self.io).into(), transmit) + }) } - fn poll_recv(&self, cx: &mut Context, bufs: &mut [std::io::IoSliceMut<'_>], meta: &mut [udp::RecvMeta]) -> Poll> { + fn poll_recv( + &self, + cx: &mut Context, + bufs: &mut [std::io::IoSliceMut<'_>], + meta: &mut [udp::RecvMeta], + ) -> Poll> { loop { ready!(self.io.poll_recv_ready(cx))?; - if let Ok(res) = self.io.try_io(Interest::READABLE, || self.inner.recv((&self.io).into(), bufs, meta)) { + if let Ok(res) = self.io.try_io(Interest::READABLE, || { + self.inner.recv((&self.io).into(), bufs, meta) + }) { return Poll::Ready(Ok(res)); } } @@ -58,7 +67,9 @@ impl AsyncUdpSocket for UnixUdpSocket { fn local_addr(&self) -> io::Result { // todo: real SocketAddr - Ok("127.0.0.1:0".parse().expect("this one is hardcoded and fine")) + Ok("127.0.0.1:0" + .parse() + .expect("this one is hardcoded and fine")) } } @@ -78,7 +89,10 @@ impl UdpPollHelper { /// it yields [`Poll::Ready`], then creating a new one on the next /// [`poll_writable`](UdpPoller::poll_writable) fn new(make_fut: MakeFut) -> Self { - Self { make_fut, fut: None } + Self { + make_fut, + fut: None, + } } } diff --git a/src/slicesubsequence.rs b/src/slicesubsequence.rs index 5642d6a..3cac787 100644 --- a/src/slicesubsequence.rs +++ b/src/slicesubsequence.rs @@ -119,10 +119,20 @@ mod tests { let buf = &br###""###[..]; - assert_eq!(buf.extract_between(b" to='", b"'").or_else(|_| buf.extract_between(b" to=\"", b"\"")).unwrap(), b"example.org"); + assert_eq!( + buf.extract_between(b" to='", b"'") + .or_else(|_| buf.extract_between(b" to=\"", b"\"")) + .unwrap(), + b"example.org" + ); let buf = &br###""###[..]; - assert_eq!(buf.extract_between(b" to='", b"'").or_else(|_| buf.extract_between(b" to=\"", b"\"")).unwrap(), b"example.org"); + assert_eq!( + buf.extract_between(b" to='", b"'") + .or_else(|_| buf.extract_between(b" to=\"", b"\"")) + .unwrap(), + b"example.org" + ); } } diff --git a/src/srv.rs b/src/srv.rs index 8f3d21a..02dd57a 100644 --- a/src/srv.rs +++ b/src/srv.rs @@ -51,7 +51,9 @@ impl Resolve for HickoryDnsResolver { fn resolve(&self, name: Name) -> Resolving { Box::pin(async move { let lookup = RESOLVER.lookup_ip(name.as_str()).await?; - let addrs: Addrs = Box::new(SocketAddrs { iter: lookup.into_iter() }); + let addrs: Addrs = Box::new(SocketAddrs { + iter: lookup.into_iter(), + }); Ok(addrs) }) } @@ -125,7 +127,10 @@ impl Ord for XmppConnectionType { // so they are the same type, but WebSocket and WebTransport is a special case... match (self, other) { #[cfg(feature = "websocket")] - (XmppConnectionType::WebSocket(self_uri, self_origin), XmppConnectionType::WebSocket(other_uri, other_origin)) => { + ( + XmppConnectionType::WebSocket(self_uri, self_origin), + XmppConnectionType::WebSocket(other_uri, other_origin), + ) => { let cmp = self_uri.to_string().cmp(&other_uri.to_string()); if cmp != Ordering::Equal { return cmp; @@ -133,7 +138,10 @@ impl Ord for XmppConnectionType { self_origin.cmp(other_origin) } #[cfg(feature = "webtransport")] - (XmppConnectionType::WebTransport(self_url), XmppConnectionType::WebTransport(other_url)) => self_url.cmp(other_url), + ( + XmppConnectionType::WebTransport(self_url), + XmppConnectionType::WebTransport(other_url), + ) => self_url.cmp(other_url), (_, _) => Ordering::Equal, } } @@ -232,13 +240,21 @@ impl XmppConnection { client_addr: &mut Context<'_>, config: &OutgoingVerifierConfig, ) -> Result<(StanzaWrite, StanzaRead, SocketAddr, &'static str)> { - debug!("{} attempting connection to SRV: {:?}", client_addr.log_from(), self); + debug!( + "{} attempting connection to SRV: {:?}", + client_addr.log_from(), + self + ); // todo: for DNSSEC we need to optionally allow target in addition to domain, but what for SNI let orig_domain = domain; let domain = if self.secure { &self.target } else { domain }; //let ips = RESOLVER.lookup_ip(self.target.clone()).await?; let ips = if self.ips.is_empty() { - RESOLVER.lookup_ip(self.target.clone()).await?.iter().collect() + RESOLVER + .lookup_ip(self.target.clone()) + .await? + .iter() + .collect() } else { self.ips.clone() // todo: avoid clone? }; @@ -247,24 +263,49 @@ impl XmppConnection { debug!("{} trying ip {}", client_addr.log_from(), to_addr); match self.conn_type { #[cfg(feature = "tls")] - XmppConnectionType::StartTLS => match crate::tls::outgoing::starttls_connect(to_addr, domain, stream_open, in_filter, config).await { + XmppConnectionType::StartTLS => match crate::tls::outgoing::starttls_connect( + to_addr, + domain, + stream_open, + in_filter, + config, + ) + .await + { Ok((wr, rd)) => return Ok((wr, rd, to_addr, "starttls-out")), - Err(e) => error!("starttls connection failed to IP {} from SRV {}, error: {}", to_addr, self.target, e), + Err(e) => error!( + "starttls connection failed to IP {} from SRV {}, error: {}", + to_addr, self.target, e + ), }, #[cfg(feature = "tls")] - XmppConnectionType::DirectTLS => match crate::tls::outgoing::tls_connect(to_addr, domain, config).await { - Ok((wr, rd)) => return Ok((wr, rd, to_addr, "directtls-out")), - Err(e) => error!("direct tls connection failed to IP {} from SRV {}, error: {}", to_addr, self.target, e), - }, + XmppConnectionType::DirectTLS => { + match crate::tls::outgoing::tls_connect(to_addr, domain, config).await { + Ok((wr, rd)) => return Ok((wr, rd, to_addr, "directtls-out")), + Err(e) => error!( + "direct tls connection failed to IP {} from SRV {}, error: {}", + to_addr, self.target, e + ), + } + } #[cfg(feature = "quic")] - XmppConnectionType::QUIC => match crate::quic::outgoing::quic_connect(to_addr, domain, config).await { - Ok((wr, rd)) => return Ok((wr, rd, to_addr, "quic-out")), - Err(e) => error!("quic connection failed to IP {} from SRV {}, error: {}", to_addr, self.target, e), - }, + XmppConnectionType::QUIC => { + match crate::quic::outgoing::quic_connect(to_addr, domain, config).await { + Ok((wr, rd)) => return Ok((wr, rd, to_addr, "quic-out")), + Err(e) => error!( + "quic connection failed to IP {} from SRV {}, error: {}", + to_addr, self.target, e + ), + } + } #[cfg(feature = "websocket")] // todo: when websocket is found via DNS, we need to validate cert against domain, *not* target, this is a security problem with XEP-0156, we are doing it the secure but likely unexpected way here for now XmppConnectionType::WebSocket(ref url, ref origin) => { - match crate::websocket::outgoing::websocket_connect(to_addr, domain, url, origin, config).await { + match crate::websocket::outgoing::websocket_connect( + to_addr, domain, url, origin, config, + ) + .await + { Ok((wr, rd)) => return Ok((wr, rd, to_addr, "websocket-out")), Err(e) => { if self.secure && self.target != orig_domain { @@ -274,32 +315,51 @@ impl XmppConnection { Err(e2) => error!("websocket connection failed to IP {} from TXT {}, error try 1: {}, error try 2: {}", to_addr, url, e, e2), } } else { - error!("websocket connection failed to IP {} from TXT {}, error: {}", to_addr, url, e) + error!( + "websocket connection failed to IP {} from TXT {}, error: {}", + to_addr, url, e + ) } } } } #[cfg(feature = "webtransport")] - XmppConnectionType::WebTransport(ref url) => match crate::webtransport::outgoing::webtransport_connect(to_addr, domain, url.clone(), config).await { - Ok((wr, rd)) => return Ok((wr, rd, to_addr, "webtransport-out")), - Err(e) => { - if self.secure && self.target != orig_domain { - match crate::webtransport::outgoing::webtransport_connect(to_addr, orig_domain, url.clone(), config).await { + XmppConnectionType::WebTransport(ref url) => { + match crate::webtransport::outgoing::webtransport_connect( + to_addr, + domain, + url.clone(), + config, + ) + .await + { + Ok((wr, rd)) => return Ok((wr, rd, to_addr, "webtransport-out")), + Err(e) => { + if self.secure && self.target != orig_domain { + match crate::webtransport::outgoing::webtransport_connect(to_addr, orig_domain, url.clone(), config).await { Ok((wr, rd)) => return Ok((wr, rd, to_addr, "webtransport-out")), Err(e2) => error!("webtransport connection failed to IP {} from URL {}, error try 1: {}, error try 2: {}", to_addr, url, e, e2), } - } else { - error!("websocket connection failed to IP {} from URL {}, error: {}", to_addr, url, e) + } else { + error!( + "websocket connection failed to IP {} from URL {}, error: {}", + to_addr, url, e + ) + } } } - }, + } } } bail!("cannot connect to any IPs for SRV: {}", self.target) } } -fn collect_srvs(ret: &mut Vec, srv_records: std::result::Result, conn_type: XmppConnectionType) { +fn collect_srvs( + ret: &mut Vec, + srv_records: std::result::Result, + conn_type: XmppConnectionType, +) { if let Ok(srv_records) = srv_records { for srv in srv_records.iter() { if !srv.target().is_root() { @@ -373,12 +433,20 @@ fn wt_to_srv(url: &str) -> Option<(XmppConnectionType, u16)> { } #[cfg(feature = "websocket")] -fn collect_txts(ret: &mut Vec, txt_records: std::result::Result, is_c2s: bool) { +fn collect_txts( + ret: &mut Vec, + txt_records: std::result::Result, + is_c2s: bool, +) { if let Ok(txt_records) = txt_records { for txt in txt_records.iter() { for txt in txt.iter() { // we only support wss and not ws (insecure) on purpose - if txt.starts_with(if is_c2s { b"_xmpp-client-websocket=wss://" } else { b"_xmpp-server-websocket=wss://" }) { + if txt.starts_with(if is_c2s { + b"_xmpp-client-websocket=wss://" + } else { + b"_xmpp-server-websocket=wss://" + }) { // 23 is the length of "_xmpp-client-websocket=" and "_xmpp-server-websocket=" if let Ok(url) = String::from_utf8(txt[23..].to_vec()) { if let Some(srv) = wss_to_srv(&url, false) { @@ -395,13 +463,27 @@ fn collect_txts(ret: &mut Vec, txt_records: std::result::Result< } } -pub async fn get_xmpp_connections(domain: &str, is_c2s: bool) -> Result<(Vec, XmppServerCertVerifier)> { - let mut valid_tls_cert_server_names: Vec = vec![ServerName::try_from(domain)?.to_owned()]; +pub async fn get_xmpp_connections( + domain: &str, + is_c2s: bool, +) -> Result<(Vec, XmppServerCertVerifier)> { + let mut valid_tls_cert_server_names: Vec = + vec![ServerName::try_from(domain)?.to_owned()]; let mut sha256_pinnedpubkeys = Vec::new(); let (starttls, direct_tls, quic, websocket_txt) = if is_c2s { - ("_xmpp-client._tcp", "_xmpps-client._tcp", "_xmppq-client._udp", "_xmppconnect") + ( + "_xmpp-client._tcp", + "_xmpps-client._tcp", + "_xmppq-client._udp", + "_xmppconnect", + ) } else { - ("_xmpp-server._tcp", "_xmpps-server._tcp", "_xmppq-server._udp", "_xmppconnect-server") + ( + "_xmpp-server._tcp", + "_xmpps-server._tcp", + "_xmppq-server._udp", + "_xmppconnect-server", + ) }; let starttls = format!("{}.{}.", starttls, domain).into_name()?; @@ -460,7 +542,8 @@ pub async fn get_xmpp_connections(domain: &str, is_c2s: bool) -> Result<(Vec return Ok((out_wr, out_rd, server_response)), Err(e) => { - debug!("{} bad server response, going to next record, error: {}", client_addr.log_to(), e); + debug!( + "{} bad server response, going to next record, error: {}", + client_addr.log_to(), + e + ); client_addr.set_proto("unk-out"); continue; } @@ -564,14 +660,27 @@ pub async fn srv_connect( } #[cfg(not(feature = "websocket"))] -async fn collect_host_meta(ret: &mut Vec<XmppConnection>, sha256_pinnedpubkeys: &mut Vec<String>, domain: &str, is_c2s: bool) -> Result<Option<u16>> { +async fn collect_host_meta( + ret: &mut Vec<XmppConnection>, + sha256_pinnedpubkeys: &mut Vec<String>, + domain: &str, + is_c2s: bool, +) -> Result<Option<u16>> { collect_host_meta_json(ret, sha256_pinnedpubkeys, domain, is_c2s).await } #[cfg(feature = "websocket")] -async fn collect_host_meta(ret: &mut Vec<XmppConnection>, sha256_pinnedpubkeys: &mut Vec<String>, domain: &str, is_c2s: bool) -> Result<Option<u16>> { +async fn collect_host_meta( + ret: &mut Vec<XmppConnection>, + sha256_pinnedpubkeys: &mut Vec<String>, + domain: &str, + is_c2s: bool, +) -> Result<Option<u16>> { let mut xml = Vec::new(); - match tokio::join!(collect_host_meta_json(ret, sha256_pinnedpubkeys, domain, is_c2s), collect_host_meta_xml(&mut xml, domain, is_c2s)) { + match tokio::join!( + collect_host_meta_json(ret, sha256_pinnedpubkeys, domain, is_c2s), + collect_host_meta_xml(&mut xml, domain, is_c2s) + ) { (Ok(Some(ttl)), _) => Ok(Some(ttl)), // if ttl is returned, ignore host-meta.xml (_, Ok(_)) => { ret.append(&mut xml); @@ -661,7 +770,11 @@ struct LinkCommon { } impl LinkCommon { - fn into_xmpp_connection(self, conn_type: XmppConnectionType, port: u16) -> Option<XmppConnection> { + fn into_xmpp_connection( + self, + conn_type: XmppConnectionType, + port: u16, + ) -> Option<XmppConnection> { if self.ips.is_empty() { error!("invalid empty ips"); return None; @@ -744,7 +857,12 @@ impl Link { } impl HostMeta { - fn collect(self, ret: &mut Vec<XmppConnection>, sha256_pinnedpubkeys: &mut Vec<String>, is_c2s: bool) -> Option<u16> { + fn collect( + self, + ret: &mut Vec<XmppConnection>, + sha256_pinnedpubkeys: &mut Vec<String>, + is_c2s: bool, + ) -> Option<u16> { for link in self.links { if let Some(srv) = link.into_xmpp_connection(is_c2s) { ret.push(srv); @@ -759,7 +877,12 @@ impl HostMeta { } } -async fn collect_host_meta_json(ret: &mut Vec<XmppConnection>, sha256_pinnedpubkeys: &mut Vec<String>, domain: &str, is_c2s: bool) -> Result<Option<u16>> { +async fn collect_host_meta_json( + ret: &mut Vec<XmppConnection>, + sha256_pinnedpubkeys: &mut Vec<String>, + domain: &str, + is_c2s: bool, +) -> Result<Option<u16>> { let url = format!("https://{}/.well-known/host-meta.json", domain); let resp = https_get(&url).await?; if resp.status().is_success() { @@ -799,7 +922,11 @@ async fn parse_host_meta_xml(rel: &str, bytes: &[u8]) -> Result<Vec<String>> { } #[cfg(feature = "websocket")] -async fn collect_host_meta_xml(ret: &mut Vec<XmppConnection>, domain: &str, is_c2s: bool) -> Result<()> { +async fn collect_host_meta_xml( + ret: &mut Vec<XmppConnection>, + domain: &str, + is_c2s: bool, +) -> Result<()> { if !is_c2s { bail!("host-meta XML unsupported for S2s"); } @@ -822,7 +949,10 @@ async fn collect_host_meta_xml(ret: &mut Vec<XmppConnection>, domain: &str, is_c // https://datatracker.ietf.org/doc/html/rfc7711 // https://www.iana.org/assignments/posh-service-names/posh-service-names.xhtml async fn collect_posh(domain: &str) -> Result<Posh> { - match tokio::join!(collect_posh_service(domain, "xmpp-client"), collect_posh_service(domain, "xmpp-server")) { + match tokio::join!( + collect_posh_service(domain, "xmpp-client"), + collect_posh_service(domain, "xmpp-server") + ) { (Ok(client), Ok(server)) => Ok(client.append(server)), (_, Ok(server)) => Ok(server), (client, _) => client, @@ -834,14 +964,20 @@ async fn collect_posh_service(domain: &str, service_name: &str) -> Result<Posh> let resp = https_get(&url).await?; if resp.status().is_success() { match resp.json::<PoshJson>().await? { - PoshJson::PoshFingerprints { fingerprints, expires } => Posh::new(fingerprints, expires), + PoshJson::PoshFingerprints { + fingerprints, + expires, + } => Posh::new(fingerprints, expires), PoshJson::PoshRedirect { url, expires } => { let resp = https_get(&url).await?; match resp.json::<PoshJson>().await? { PoshJson::PoshRedirect { .. } => { bail!("posh illegal url redirect to another url") } - PoshJson::PoshFingerprints { fingerprints, expires: expires2 } => Posh::new( + PoshJson::PoshFingerprints { + fingerprints, + expires: expires2, + } => Posh::new( fingerprints, // expires is supposed to be the least of these two min(expires, expires2), @@ -871,8 +1007,14 @@ fn min(a: u64, b: u64) -> u64 { #[derive(Deserialize, Debug)] #[serde(untagged)] enum PoshJson { - PoshFingerprints { fingerprints: Vec<Fingerprint>, expires: u64 }, - PoshRedirect { url: String, expires: u64 }, + PoshFingerprints { + fingerprints: Vec<Fingerprint>, + expires: u64, + }, + PoshRedirect { + url: String, + expires: u64, + }, } #[derive(Deserialize, Debug)] @@ -920,8 +1062,10 @@ impl Posh { } pub fn valid_cert(&self, cert: &[u8]) -> bool { - (!self.sha_256_fingerprints.is_empty() && self.sha_256_fingerprints.contains(&digest(&SHA256, cert))) - || (!self.sha_512_fingerprints.is_empty() && self.sha_512_fingerprints.contains(&digest(&SHA512, cert))) + (!self.sha_256_fingerprints.is_empty() + && self.sha_256_fingerprints.contains(&digest(&SHA256, cert))) + || (!self.sha_512_fingerprints.is_empty() + && self.sha_512_fingerprints.contains(&digest(&SHA512, cert))) } } @@ -941,7 +1085,11 @@ mod tests { let posh: PoshJson = serde_json::from_slice(posh).unwrap(); let cert = BASE64.decode(cert).unwrap(); println!("posh: {:?}", posh); - if let PoshJson::PoshFingerprints { fingerprints, expires } = posh { + if let PoshJson::PoshFingerprints { + fingerprints, + expires, + } = posh + { let posh = Posh::new(fingerprints, expires).unwrap(); println!("posh: {:?}", posh); posh.valid_cert(&cert) @@ -994,7 +1142,11 @@ mod tests { "###; let posh: PoshJson = serde_json::from_slice(&posh[..]).unwrap(); println!("posh: {:?}", posh); - if let PoshJson::PoshFingerprints { fingerprints, expires } = posh { + if let PoshJson::PoshFingerprints { + fingerprints, + expires, + } = posh + { let posh = Posh::new(fingerprints, expires); println!("posh: {:?}", posh); } @@ -1029,7 +1181,10 @@ mod tests { println!("trying 1 domain {}, SRV: {:?}", domain, srv); let ips = RESOLVER.lookup_ip(srv.target.clone()).await?; for ip in ips.iter() { - println!("trying domain {}, ip {}, is_c2s: {}, SRV: {:?}", domain, ip, is_c2s, srv); + println!( + "trying domain {}, ip {}, is_c2s: {}, SRV: {:?}", + domain, ip, is_c2s, srv + ); } } Ok(()) @@ -1040,7 +1195,8 @@ mod tests { async fn http() -> Result<()> { let mut hosts = Vec::new(); let mut sha256_pinnedpubkeys = Vec::new(); - let res = collect_host_meta(&mut hosts, &mut sha256_pinnedpubkeys, "burtrum.org", true).await; + let res = + collect_host_meta(&mut hosts, &mut sha256_pinnedpubkeys, "burtrum.org", true).await; println!("burtrum.org res: {:?}", res); println!("burtrum.org hosts: {:?}", hosts); println!("burtrum.org hosts: {:?}", sha256_pinnedpubkeys); @@ -1051,25 +1207,46 @@ mod tests { #[tokio::test] async fn test_parse_host_meta() -> Result<()> { let xrd = br#"<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'><Link rel='urn:xmpp:alt-connections:xbosh' href='https://burtrum.org/http-bind'/><Link rel='urn:xmpp:alt-connections:websocket' href='wss://burtrum.org/xmpp-websocket'/></XRD>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket"] + ); let xrd = br#"<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><Link rel="urn:xmpp:alt-connections:xbosh" href="https://burtrum.org/http-bind"/><Link rel="urn:xmpp:alt-connections:websocket" href="wss://burtrum.org/xmpp-websocket"/></XRD>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket"] + ); let xrd = br#"<xrd xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'><link rel='urn:xmpp:alt-connections:xbosh' href='https://burtrum.org/http-bind'/><link rel='urn:xmpp:alt-connections:websocket' href='wss://burtrum.org/xmpp-websocket'/></xrd>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket"] + ); let xrd = br#"<xrd xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><link rel="urn:xmpp:alt-connections:xbosh" href="https://burtrum.org/http-bind"/><link rel="urn:xmpp:alt-connections:websocket" href="wss://burtrum.org/xmpp-websocket"/></xrd>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket"] + ); let xrd = br#"<xrd xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><link rel="urn:xmpp:alt-connections:xbosh" href="https://burtrum.org/http-bind"/><link rel="urn:xmpp:alt-connections:websocket" href="wss://burtrum.org/xmpp-websocket"/><link rel="urn:xmpp:alt-connections:s2s-websocket" href="wss://burtrum.org/xmpp-websocket-s2s"/></xrd>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:s2s-websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket-s2s"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:s2s-websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket-s2s"] + ); let xrd = br#"<xrd xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"><link rel="urn:xmpp:alt-connections:xbosh" href="https://burtrum.org/http-bind"/><link rel="urn:xmpp:alt-connections:websocket" href="wss://burtrum.org/xmpp-websocket"/><link rel="urn:xmpp:alt-connections:s2s-websocket" href="wss://burtrum.org/xmpp-websocket-s2s"/></xrd>"#; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, vec!["wss://burtrum.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", xrd).await?, + vec!["wss://burtrum.org/xmpp-websocket"] + ); let xrd = read_file("contrib/host-meta/xep-0156-current.xml")?; - assert_eq!(parse_host_meta_xml("urn:xmpp:alt-connections:websocket", &xrd).await?, vec!["wss://example.org/xmpp-websocket"]); + assert_eq!( + parse_host_meta_xml("urn:xmpp:alt-connections:websocket", &xrd).await?, + vec!["wss://example.org/xmpp-websocket"] + ); Ok(()) } diff --git a/src/stanzafilter.rs b/src/stanzafilter.rs index 4a297f5..f94f5ca 100644 --- a/src/stanzafilter.rs +++ b/src/stanzafilter.rs @@ -86,14 +86,18 @@ impl StanzaFilter { } StanzaFirstChar => match b { b'/' => self.state = EndStream, - b'!' | b'>' | b'\'' | b'"' => bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])), + b'!' | b'>' | b'\'' | b'"' => { + bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])) + } b'?' => self.state = QuestionTag(self.cnt + 4), // 4 is length of b"xml " _ => self.state = InsideTag, }, InsideTagFirstChar => match b { b'/' => self.tag_cnt = checked_sub(self.tag_cnt, 2)?, b'!' => self.state = ExclamationTag(self.cnt + 7), // 7 is length of b"[CDATA[" - b'?' | b'>' | b'\'' | b'"' => bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])), + b'?' | b'>' | b'\'' | b'"' => { + bail!("illegal stanza: {}", to_str(&self.buf[..(self.cnt + 1)])) + } _ => self.state = InsideTag, }, InsideTag => match b { @@ -110,7 +114,10 @@ impl StanzaFilter { return self.stanza_end(); } // now special case <stream:stream ...> which we want to send stand-alone: - if self.tag_cnt == 1 && self.buf.len() >= 15 && b"<stream:stream " == &self.buf[0..15] { + if self.tag_cnt == 1 + && self.buf.len() >= 15 + && b"<stream:stream " == &self.buf[0..15] + { return self.stanza_end(); } self.state = BetweenTags; @@ -214,7 +221,10 @@ impl<T: tokio::io::AsyncRead + Unpin> StanzaReader<T> { } } - pub async fn next_eoft<'a>(&'a mut self, filter: &'a mut StanzaFilter) -> Result<Option<(&'a [u8], usize)>> { + pub async fn next_eoft<'a>( + &'a mut self, + filter: &'a mut StanzaFilter, + ) -> Result<Option<(&'a [u8], usize)>> { use tokio::io::AsyncReadExt; loop { diff --git a/src/systemd.rs b/src/systemd.rs index ba2f388..400283f 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -1,5 +1,7 @@ use anyhow::{anyhow, bail, Result}; -use nix::sys::socket::{getsockname, getsockopt, AddressFamily, SockType, SockaddrLike, SockaddrStorage}; +use nix::sys::socket::{ + getsockname, getsockopt, AddressFamily, SockType, SockaddrLike, SockaddrStorage, +}; use std::{ env, net::{TcpListener, UdpSocket}, @@ -42,10 +44,18 @@ impl FileDescriptor { pub fn listener(&self) -> SystemdListener { let raw_fd = self.raw_fd; match (self.tcp_not_udp, self.inet_not_unix) { - (true, true) => SystemdListener::Tcp(Box::new(move || unsafe { TcpListener::from_raw_fd(raw_fd) })), - (false, true) => SystemdListener::Udp(Box::new(move || unsafe { UdpSocket::from_raw_fd(raw_fd) })), - (true, false) => SystemdListener::UnixListener(Box::new(move || unsafe { UnixListener::from_raw_fd(raw_fd) })), - (false, false) => SystemdListener::UnixDatagram(Box::new(move || unsafe { UnixDatagram::from_raw_fd(raw_fd) })), + (true, true) => SystemdListener::Tcp(Box::new(move || unsafe { + TcpListener::from_raw_fd(raw_fd) + })), + (false, true) => { + SystemdListener::Udp(Box::new(move || unsafe { UdpSocket::from_raw_fd(raw_fd) })) + } + (true, false) => SystemdListener::UnixListener(Box::new(move || unsafe { + UnixListener::from_raw_fd(raw_fd) + })), + (false, false) => SystemdListener::UnixDatagram(Box::new(move || unsafe { + UnixDatagram::from_raw_fd(raw_fd) + })), } } } @@ -58,7 +68,12 @@ pub fn receive_descriptors_with_names(unset_env: bool) -> Result<Vec<FileDescrip let pid = env::var("LISTEN_PID"); let fds = env::var("LISTEN_FDS"); let fdnames = env::var("LISTEN_FDNAMES"); - log::trace!("LISTEN_PID = {:?}; LISTEN_FDS = {:?}; LISTEN_FDNAMES = {:?}", pid, fds, fdnames); + log::trace!( + "LISTEN_PID = {:?}; LISTEN_FDS = {:?}; LISTEN_FDNAMES = {:?}", + pid, + fds, + fdnames + ); if unset_env { env::remove_var("LISTEN_PID"); @@ -79,7 +94,9 @@ pub fn receive_descriptors_with_names(unset_env: bool) -> Result<Vec<FileDescrip bail!("PID mismatch"); } - let names = fdnames.map(|n| n.split(':').map(String::from).collect()).unwrap_or_else(|_| Vec::new()); + let names = fdnames + .map(|n| n.split(':').map(String::from).collect()) + .unwrap_or_else(|_| Vec::new()); socks_from_fds(fds, names) } @@ -127,7 +144,9 @@ fn sock_type(raw_fd: RawFd) -> Option<SockType> { } fn address_family(raw_fd: RawFd) -> Option<AddressFamily> { - getsockname::<SockaddrStorage>(raw_fd).ok().and_then(|addr| addr.family()) + getsockname::<SockaddrStorage>(raw_fd) + .ok() + .and_then(|addr| addr.family()) } impl IntoRawFd for FileDescriptor { diff --git a/src/tls/incoming.rs b/src/tls/incoming.rs index b527207..de33209 100644 --- a/src/tls/incoming.rs +++ b/src/tls/incoming.rs @@ -24,7 +24,11 @@ pub fn tls_acceptor(server_config: ServerConfig) -> TlsAcceptor { TlsAcceptor::from(Arc::new(server_config)) } -pub fn spawn_tls_listener(listener: impl StreamListener, config: Arc<IncomingConfig>, acceptor: TlsAcceptor) -> JoinHandle<Result<()>> { +pub fn spawn_tls_listener( + listener: impl StreamListener, + config: Arc<IncomingConfig>, + acceptor: TlsAcceptor, +) -> JoinHandle<Result<()>> { tokio::spawn(async move { let local_addr = listener.local_addr()?; loop { @@ -33,7 +37,10 @@ pub fn spawn_tls_listener(listener: impl StreamListener, config: Arc<IncomingCon let acceptor = acceptor.clone(); tokio::spawn(async move { let mut client_addr = Context::new("tcp-in", client_addr); - if let Err(e) = handle_tls_connection(stream, &mut client_addr, local_addr, config, acceptor).await { + if let Err(e) = + handle_tls_connection(stream, &mut client_addr, local_addr, config, acceptor) + .await + { error!("{} {}", client_addr.log_from(), e); } }); @@ -41,7 +48,13 @@ pub fn spawn_tls_listener(listener: impl StreamListener, config: Arc<IncomingCon }) } -pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, client_addr: &mut Context<'_>, local_addr: SocketAddr, config: Arc<IncomingConfig>, acceptor: TlsAcceptor) -> Result<()> { +pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>( + mut stream: S, + client_addr: &mut Context<'_>, + local_addr: SocketAddr, + config: Arc<IncomingConfig>, + acceptor: TlsAcceptor, +) -> Result<()> { info!("{} connected", client_addr.log_from()); let mut in_filter = StanzaFilter::new(config.max_stanza_size_bytes); @@ -52,9 +65,17 @@ pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, cl * * could just check the leading 0x16 is TLS, it would *probably* be ok ? */ - let direct_tls = stream.first_bytes_match(&mut in_filter.buf[0..3], |p| p[0] == 0x16 && p[1] == 0x03 && p[2] <= 0x03).await?; - - client_addr.set_proto(if direct_tls { "directtls-in" } else { "starttls-in" }); + let direct_tls = stream + .first_bytes_match(&mut in_filter.buf[0..3], |p| { + p[0] == 0x16 && p[1] == 0x03 && p[2] <= 0x03 + }) + .await?; + + client_addr.set_proto(if direct_tls { + "directtls-in" + } else { + "starttls-in" + }); info!("{} direct_tls sniffed", client_addr.log_from()); // starttls @@ -69,7 +90,11 @@ pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, cl let mut in_rd = StanzaReader(in_rd); while let Ok(Some(buf)) = in_rd.next(&mut in_filter).await { - trace!("{} received pre-tls stanza: '{}'", client_addr.log_from(), to_str(buf)); + trace!( + "{} received pre-tls stanza: '{}'", + client_addr.log_from(), + to_str(buf) + ); if buf.starts_with(b"<?xml ") { trace!("{} '{}'", client_addr.log_to(), to_str(buf)); in_wr.write_all(buf).await?; @@ -115,8 +140,15 @@ pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, cl // though https://datatracker.ietf.org/doc/html/rfc6120#section-5.3.3 says that no data, not even whitespace, should be sent after <starttls... // some software in the wild actually does send extra stuff, and currently prosody and ejabberd handle this... so we'll read and discard bytes // until we get to the first byte of the TLS handshake... - while stream.first_bytes_match(&mut in_filter.buf[0..1], |p| p[0] != 0x16).await? { - warn!("{} buggy software connecting, sent byte after <starttls: {}", client_addr.log_to(), &in_filter.buf[0]); + while stream + .first_bytes_match(&mut in_filter.buf[0..1], |p| p[0] != 0x16) + .await? + { + warn!( + "{} buggy software connecting, sent byte after <starttls: {}", + client_addr.log_to(), + &in_filter.buf[0] + ); stream.read_exact(&mut in_filter.buf[0..1]).await?; } stream @@ -136,7 +168,16 @@ pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, cl #[cfg(not(feature = "websocket"))] { let (in_rd, in_wr) = stream.split(); - shuffle_rd_wr_filter(StanzaRead::new(in_rd), StanzaWrite::new(in_wr), config, server_certs, local_addr, client_addr, in_filter).await + shuffle_rd_wr_filter( + StanzaRead::new(in_rd), + StanzaWrite::new(in_wr), + config, + server_certs, + local_addr, + client_addr, + in_filter, + ) + .await } #[cfg(feature = "websocket")] @@ -145,10 +186,27 @@ pub async fn handle_tls_connection<S: AsyncReadWritePeekSplit>(mut stream: S, cl let websocket = first_bytes_match_buf_timeout(&mut stream, 3, |p| p == b"GET").await?; if websocket { - crate::websocket::incoming::handle_websocket_connection(Box::new(stream), config, server_certs, local_addr, client_addr, in_filter).await + crate::websocket::incoming::handle_websocket_connection( + Box::new(stream), + config, + server_certs, + local_addr, + client_addr, + in_filter, + ) + .await } else { let (in_rd, in_wr) = stream.split(); - shuffle_rd_wr_filter(StanzaRead::already_buffered(in_rd), StanzaWrite::new(in_wr), config, server_certs, local_addr, client_addr, in_filter).await + shuffle_rd_wr_filter( + StanzaRead::already_buffered(in_rd), + StanzaWrite::new(in_wr), + config, + server_certs, + local_addr, + client_addr, + in_filter, + ) + .await } } } diff --git a/src/tls/outgoing.rs b/src/tls/outgoing.rs index 46879ca..421affc 100644 --- a/src/tls/outgoing.rs +++ b/src/tls/outgoing.rs @@ -9,7 +9,11 @@ use rustls::pki_types::ServerName; use std::{convert::TryFrom, net::SocketAddr}; use tokio::io::AsyncWriteExt; -pub async fn tls_connect(target: SocketAddr, server_name: &str, config: &OutgoingVerifierConfig) -> Result<(StanzaWrite, StanzaRead)> { +pub async fn tls_connect( + target: SocketAddr, + server_name: &str, + config: &OutgoingVerifierConfig, +) -> Result<(StanzaWrite, StanzaRead)> { let dnsname = ServerName::try_from(server_name)?.to_owned(); let stream = tokio::net::TcpStream::connect(target).await?; let stream = config.connector_alpn.connect(dnsname, stream).await?; @@ -17,13 +21,23 @@ pub async fn tls_connect(target: SocketAddr, server_name: &str, config: &Outgoin Ok((StanzaWrite::new(wrt), StanzaRead::new(rd))) } -pub async fn starttls_connect(target: SocketAddr, server_name: &str, stream_open: &[u8], in_filter: &mut StanzaFilter, config: &OutgoingVerifierConfig) -> Result<(StanzaWrite, StanzaRead)> { +pub async fn starttls_connect( + target: SocketAddr, + server_name: &str, + stream_open: &[u8], + in_filter: &mut StanzaFilter, + config: &OutgoingVerifierConfig, +) -> Result<(StanzaWrite, StanzaRead)> { let dnsname = ServerName::try_from(server_name)?.to_owned(); let mut stream = tokio::net::TcpStream::connect(target).await?; let (in_rd, mut in_wr) = stream.split(); // send the stream_open - trace!("starttls sending: {} '{}'", server_name, to_str(stream_open)); + trace!( + "starttls sending: {} '{}'", + server_name, + to_str(stream_open) + ); in_wr.write_all(stream_open).await?; in_wr.flush().await?; diff --git a/src/verify.rs b/src/verify.rs index c3a2555..4f87224 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -16,19 +16,32 @@ use std::{convert::TryFrom, sync::LazyLock}; /// order. // this expect panic should not be possible to trigger because it'll trigger earlier in execution before we get to cert verification static SUPPORTED_SIG_ALGS: LazyLock<&'static [&'static dyn SignatureVerificationAlgorithm]> = - LazyLock::new(|| rustls::crypto::CryptoProvider::get_default().expect("no crypto provider set").signature_verification_algorithms.all); + LazyLock::new(|| { + rustls::crypto::CryptoProvider::get_default() + .expect("no crypto provider set") + .signature_verification_algorithms + .all + }); #[allow(deprecated)] pub fn pki_error(error: webpki::Error) -> Error { use webpki::Error::*; match error { BadDer | BadDerTime => Error::InvalidCertificate(CertificateError::BadEncoding), - InvalidSignatureForPublicKey | UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => Error::InvalidCertificate(CertificateError::BadSignature), + InvalidSignatureForPublicKey + | UnsupportedSignatureAlgorithm + | UnsupportedSignatureAlgorithmForPublicKey => { + Error::InvalidCertificate(CertificateError::BadSignature) + } e => Error::General(format!("invalid peer certificate: {}", e)), } } -pub fn verify_is_valid_tls_server_cert<'a>(end_entity: &'a CertificateDer, intermediates: &'a [CertificateDer], now: UnixTime) -> Result<webpki::EndEntityCert<'a>, Error> { +pub fn verify_is_valid_tls_server_cert<'a>( + end_entity: &'a CertificateDer, + intermediates: &'a [CertificateDer], + now: UnixTime, +) -> Result<webpki::EndEntityCert<'a>, Error> { // from WebPkiVerifier, validates CA trusted cert //let (cert, chain) = prepare(end_entity, intermediates)?; // EE cert must appear first. @@ -36,8 +49,16 @@ pub fn verify_is_valid_tls_server_cert<'a>(end_entity: &'a CertificateDer, inter // todo: check revocation ? where to get CRL list ? - cert.verify_for_usage(*SUPPORTED_SIG_ALGS, &TLS_SERVER_ROOTS, intermediates, now, webpki::KeyUsage::server_auth(), None, None) - .map_err(pki_error)?; + cert.verify_for_usage( + *SUPPORTED_SIG_ALGS, + &TLS_SERVER_ROOTS, + intermediates, + now, + webpki::KeyUsage::server_auth(), + None, + None, + ) + .map_err(pki_error)?; Ok(cert) } @@ -54,7 +75,12 @@ impl ClientCertVerifier for AllowAnonymousOrAnyCert { false } - fn verify_client_cert(&self, _end_entity: &CertificateDer<'_>, _intermediates: &[CertificateDer<'_>], _now: UnixTime) -> Result<ClientCertVerified, Error> { + fn verify_client_cert( + &self, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _now: UnixTime, + ) -> Result<ClientCertVerified, Error> { // this is checked only after the first <stream: stanza so we know the from= Ok(ClientCertVerified::assertion()) } @@ -63,11 +89,21 @@ impl ClientCertVerifier for AllowAnonymousOrAnyCert { &[] } - fn verify_tls12_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> { + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result<HandshakeSignatureValid, Error> { SERVER_VERIFIER.verify_tls12_signature(message, cert, dss) } - fn verify_tls13_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> { + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result<HandshakeSignatureValid, Error> { SERVER_VERIFIER.verify_tls13_signature(message, cert, dss) } @@ -84,21 +120,43 @@ pub struct XmppServerCertVerifier { } impl XmppServerCertVerifier { - pub fn new(names: Vec<ServerName<'static>>, posh: Option<Posh>, sha256_pinnedpubkeys: Vec<String>) -> Self { - XmppServerCertVerifier { names, posh, sha256_pinnedpubkeys } + pub fn new( + names: Vec<ServerName<'static>>, + posh: Option<Posh>, + sha256_pinnedpubkeys: Vec<String>, + ) -> Self { + XmppServerCertVerifier { + names, + posh, + sha256_pinnedpubkeys, + } } - pub fn verify_cert(&self, end_entity: &CertificateDer, intermediates: &[CertificateDer], now: UnixTime) -> Result<ServerCertVerified, Error> { + pub fn verify_cert( + &self, + end_entity: &CertificateDer, + intermediates: &[CertificateDer], + now: UnixTime, + ) -> Result<ServerCertVerified, Error> { if !self.sha256_pinnedpubkeys.is_empty() { let cert = webpki::anchor_from_trusted_cert(end_entity).map_err(pki_error)?; - trace!("subject_public_key_info.len(): {}", cert.subject_public_key_info.len()); - trace!("subject_public_key_info: {:?}", cert.subject_public_key_info); + trace!( + "subject_public_key_info.len(): {}", + cert.subject_public_key_info.len() + ); + trace!( + "subject_public_key_info: {:?}", + cert.subject_public_key_info + ); // todo: what is wrong with webpki? it returns *almost* the right answer but missing these leading bytes: // guess I'll open an issue... (I assume this is some type of algorithm identifying header or something) let mut pubkey: Vec<u8> = vec![48, 130, 1, 34]; pubkey.extend(cert.subject_public_key_info.as_ref()); - if self.sha256_pinnedpubkeys.contains(&digest(&SHA256, &pubkey)) { + if self + .sha256_pinnedpubkeys + .contains(&digest(&SHA256, &pubkey)) + { debug!("pinnedpubkey succeeded for {:?}", self.names.first()); return Ok(ServerCertVerified::assertion()); } @@ -123,7 +181,10 @@ impl XmppServerCertVerifier { } } - Err(Error::General(format!("invalid peer certificate: all validation attempts failed: {:?}", end_entity))) + Err(Error::General(format!( + "invalid peer certificate: all validation attempts failed: {:?}", + end_entity + ))) } } @@ -139,11 +200,21 @@ impl ServerCertVerifier for XmppServerCertVerifier { self.verify_cert(end_entity, intermediates, now) } - fn verify_tls12_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> { + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result<HandshakeSignatureValid, Error> { SERVER_VERIFIER.verify_tls12_signature(message, cert, dss) } - fn verify_tls13_signature(&self, message: &[u8], cert: &CertificateDer<'_>, dss: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> { + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result<HandshakeSignatureValid, Error> { SERVER_VERIFIER.verify_tls13_signature(message, cert, dss) } diff --git a/src/websocket/incoming.rs b/src/websocket/incoming.rs index 6c7b11c..8c7fcc3 100644 --- a/src/websocket/incoming.rs +++ b/src/websocket/incoming.rs @@ -22,7 +22,17 @@ pub async fn handle_websocket_connection( client_addr.set_proto("websocket-in"); info!("{} connected", client_addr.log_from()); - let (in_rd, in_wr) = incoming_websocket_connection(stream, config.max_stanza_size_bytes).await?; + let (in_rd, in_wr) = + incoming_websocket_connection(stream, config.max_stanza_size_bytes).await?; - shuffle_rd_wr_filter(in_rd, in_wr, config, server_certs, local_addr, client_addr, in_filter).await + shuffle_rd_wr_filter( + in_rd, + in_wr, + config, + server_certs, + local_addr, + client_addr, + in_filter, + ) + .await } diff --git a/src/websocket/mod.rs b/src/websocket/mod.rs index f288d3d..2896572 100644 --- a/src/websocket/mod.rs +++ b/src/websocket/mod.rs @@ -16,7 +16,8 @@ pub mod incoming; #[cfg(feature = "outgoing")] pub mod outgoing; -pub type WsWr = SplitSink<WebSocketStream<BoxAsyncReadWrite>, tokio_tungstenite::tungstenite::Message>; +pub type WsWr = + SplitSink<WebSocketStream<BoxAsyncReadWrite>, tokio_tungstenite::tungstenite::Message>; pub type WsRd = SplitStream<WebSocketStream<BoxAsyncReadWrite>>; // https://datatracker.ietf.org/doc/html/rfc7395 @@ -30,14 +31,26 @@ fn ws_cfg(max_stanza_size_bytes: usize) -> Option<WebSocketConfig> { ) } -pub async fn incoming_websocket_connection(stream: BoxAsyncReadWrite, max_stanza_size_bytes: usize) -> Result<(StanzaRead, StanzaWrite)> { +// `result_large_err` is allowed here because the `Err` type of the callback is mandated by +// dependencies +#[allow(clippy::result_large_err)] +pub async fn incoming_websocket_connection( + stream: BoxAsyncReadWrite, + max_stanza_size_bytes: usize, +) -> Result<(StanzaRead, StanzaWrite)> { // accept the websocket let stream = tokio_tungstenite::accept_hdr_async_with_config( stream, |_request: &Request, mut response: Response| { // todo: check SEC_WEBSOCKET_PROTOCOL or ORIGIN ? - response.headers_mut().append(SEC_WEBSOCKET_PROTOCOL, "xmpp".parse().expect("known to be good value")); - response.headers_mut().append(ACCESS_CONTROL_ALLOW_ORIGIN, "*".parse().expect("known to be good value")); + response.headers_mut().append( + SEC_WEBSOCKET_PROTOCOL, + "xmpp".parse().expect("known to be good value"), + ); + response.headers_mut().append( + ACCESS_CONTROL_ALLOW_ORIGIN, + "*".parse().expect("known to be good value"), + ); Ok(response) }, ws_cfg(max_stanza_size_bytes), @@ -46,7 +59,10 @@ pub async fn incoming_websocket_connection(stream: BoxAsyncReadWrite, max_stanza let (in_wr, in_rd) = stream.split(); - Ok((StanzaRead::WebSocketRead(in_rd), StanzaWrite::WebSocketClientWrite(in_wr))) + Ok(( + StanzaRead::WebSocketRead(in_rd), + StanzaWrite::WebSocketClientWrite(in_wr), + )) } pub fn from_ws(stanza: String) -> String { @@ -55,7 +71,10 @@ pub fn from_ws(stanza: String) -> String { // todo: hmm what to do here, xml needed? breaks srv pre-tls detection because it's really 2 "stanzas".... //.replace("<open ", r#"<?xml version='1.0'?><stream:stream "#) .replace("<open ", r#"<stream:stream "#) - .replace("urn:ietf:params:xml:ns:xmpp-framing-server", "jabber:server") + .replace( + "urn:ietf:params:xml:ns:xmpp-framing-server", + "jabber:server", + ) .replace("urn:ietf:params:xml:ns:xmpp-framing", "jabber:client"); if !stanza.contains("xmlns:stream=") { stanza.replace("/>", r#" xmlns:stream="http://etherx.jabber.org/streams">"#) @@ -74,7 +93,10 @@ pub fn to_ws_new(buf: &[u8], mut end_of_first_tag: usize, is_c2s: bool) -> Resul let buf = String::from_utf8(buf.to_vec())?; return Ok(buf .replace("<stream:stream ", "<open ") - .replace("jabber:server", "urn:ietf:params:xml:ns:xmpp-framing-server") + .replace( + "jabber:server", + "urn:ietf:params:xml:ns:xmpp-framing-server", + ) .replace("jabber:client", "urn:ietf:params:xml:ns:xmpp-framing") .replace('>', "/>")); } @@ -88,8 +110,13 @@ pub fn to_ws_new(buf: &[u8], mut end_of_first_tag: usize, is_c2s: bool) -> Resul end_of_first_tag -= 1; } let first_tag_bytes = &buf[0..end_of_first_tag]; - let has_xmlns = first_tag_bytes.first_index_of(b" xmlns='").is_ok() || first_tag_bytes.first_index_of(br#" xmlns=""#).is_ok(); - let has_xmlns_stream = !first_tag_bytes.contains_seq(b"stream:") || (first_tag_bytes.first_index_of(b" xmlns:stream='").is_ok() || first_tag_bytes.first_index_of(br#" xmlns:stream=""#).is_ok()); + let has_xmlns = first_tag_bytes.first_index_of(b" xmlns='").is_ok() + || first_tag_bytes.first_index_of(br#" xmlns=""#).is_ok(); + let has_xmlns_stream = !first_tag_bytes.contains_seq(b"stream:") + || (first_tag_bytes.first_index_of(b" xmlns:stream='").is_ok() + || first_tag_bytes + .first_index_of(br#" xmlns:stream=""#) + .is_ok()); if has_xmlns && has_xmlns_stream { // already set, do nothing return Ok(String::from_utf8(buf.to_vec())?); @@ -105,7 +132,11 @@ pub fn to_ws_new(buf: &[u8], mut end_of_first_tag: usize, is_c2s: bool) -> Resul let mut ret = String::with_capacity(buf.len() + capacity); ret.push_str(std::str::from_utf8(first_tag_bytes)?); if !has_xmlns { - ret.push_str(if is_c2s { " xmlns='jabber:client'" } else { " xmlns='jabber:server'" }); + ret.push_str(if is_c2s { + " xmlns='jabber:client'" + } else { + " xmlns='jabber:server'" + }); } if !has_xmlns_stream { ret.push_str(" xmlns:stream='http://etherx.jabber.org/streams'"); @@ -134,7 +165,10 @@ mod tests { from_ws(r#"<open xmlns="urn:ietf:params:xml:ns:xmpp-framing" version="1.0" to="test.moparisthe.best" xml:lang="en" />"#.to_string()), r#"<stream:stream xmlns="jabber:client" version="1.0" to="test.moparisthe.best" xml:lang="en" xmlns:stream="http://etherx.jabber.org/streams">"#.to_string() ); - assert_eq!(from_ws(r#"<close xmlns="urn:ietf:params:xml:ns:xmpp-framing" />"#.to_string()), r#"</stream:stream>"#.to_string()); + assert_eq!( + from_ws(r#"<close xmlns="urn:ietf:params:xml:ns:xmpp-framing" />"#.to_string()), + r#"</stream:stream>"#.to_string() + ); assert_eq!( from_ws(r#"<open to='one.example.org' xmlns='urn:ietf:params:xml:ns:xmpp-framing' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'/>"#.to_string()), @@ -142,7 +176,10 @@ mod tests { ); } - async fn to_vec_eoft<T: tokio::io::AsyncRead + Unpin>(mut stanza_reader: StanzaReader<T>, filter: &mut StanzaFilter) -> Result<Vec<String>> { + async fn to_vec_eoft<T: tokio::io::AsyncRead + Unpin>( + mut stanza_reader: StanzaReader<T>, + filter: &mut StanzaFilter, + ) -> Result<Vec<String>> { let mut ret = Vec::new(); while let Some((buf, end_of_first_tag)) = stanza_reader.next_eoft(filter).await? { ret.push(to_ws_new(buf, end_of_first_tag, true)?); diff --git a/src/websocket/outgoing.rs b/src/websocket/outgoing.rs index 8766ffd..c0e2450 100644 --- a/src/websocket/outgoing.rs +++ b/src/websocket/outgoing.rs @@ -15,9 +15,17 @@ use tokio_tungstenite::tungstenite::{ }, }; -pub async fn websocket_connect(target: SocketAddr, server_name: &str, url: &Uri, origin: &str, config: &OutgoingVerifierConfig) -> Result<(StanzaWrite, StanzaRead)> { +pub async fn websocket_connect( + target: SocketAddr, + server_name: &str, + url: &Uri, + origin: &str, + config: &OutgoingVerifierConfig, +) -> Result<(StanzaWrite, StanzaRead)> { let mut request = url.into_client_request()?; - request.headers_mut().append(SEC_WEBSOCKET_PROTOCOL, "xmpp".parse()?); + request + .headers_mut() + .append(SEC_WEBSOCKET_PROTOCOL, "xmpp".parse()?); request.headers_mut().append(ORIGIN, origin.parse()?); let dnsname = ServerName::try_from(server_name)?.to_owned(); @@ -29,9 +37,17 @@ pub async fn websocket_connect(target: SocketAddr, server_name: &str, url: &Uri, //let stream = BufStream::with_capacity(crate::IN_BUFFER_SIZE, 0, stream); let stream: BoxAsyncReadWrite = Box::new(stream); - let (stream, _) = tokio_tungstenite::client_async_with_config(request, stream, ws_cfg(config.max_stanza_size_bytes)).await?; + let (stream, _) = tokio_tungstenite::client_async_with_config( + request, + stream, + ws_cfg(config.max_stanza_size_bytes), + ) + .await?; let (wrt, rd) = stream.split(); - Ok((StanzaWrite::WebSocketClientWrite(wrt), StanzaRead::WebSocketRead(rd))) + Ok(( + StanzaWrite::WebSocketClientWrite(wrt), + StanzaRead::WebSocketRead(rd), + )) } diff --git a/src/webtransport/incoming.rs b/src/webtransport/incoming.rs index 504e4a6..64064c1 100644 --- a/src/webtransport/incoming.rs +++ b/src/webtransport/incoming.rs @@ -7,7 +7,13 @@ use crate::{ use log::{error, info}; use std::{net::SocketAddr, sync::Arc}; -pub async fn handle_webtransport_session(conn: quinn::Connection, config: Arc<IncomingConfig>, server_certs: ServerCerts, local_addr: SocketAddr, mut client_addr: Context<'static>) { +pub async fn handle_webtransport_session( + conn: quinn::Connection, + config: Arc<IncomingConfig>, + server_certs: ServerCerts, + local_addr: SocketAddr, + mut client_addr: Context<'static>, +) { client_addr.set_proto("webtransport-in"); // Perform the WebTransport handshake. @@ -18,7 +24,11 @@ pub async fn handle_webtransport_session(conn: quinn::Connection, config: Arc<In return; } }; - info!("{} received request URL: {}", client_addr.log_from(), request.url()); + info!( + "{} received request URL: {}", + client_addr.log_from(), + request.url() + ); // Accept the session. let session = match request.ok().await { @@ -36,7 +46,16 @@ pub async fn handle_webtransport_session(conn: quinn::Connection, config: Arc<In let server_certs = server_certs.clone(); info!("{} connected new stream", client_addr.log_from()); tokio::spawn(async move { - if let Err(e) = shuffle_rd_wr(StanzaRead::new(rd), StanzaWrite::new(wrt), config, server_certs, local_addr, &mut client_addr).await { + if let Err(e) = shuffle_rd_wr( + StanzaRead::new(rd), + StanzaWrite::new(wrt), + config, + server_certs, + local_addr, + &mut client_addr, + ) + .await + { error!("{} {}", client_addr.log_from(), e); } }); diff --git a/src/webtransport/outgoing.rs b/src/webtransport/outgoing.rs index bff5bae..331bc79 100644 --- a/src/webtransport/outgoing.rs +++ b/src/webtransport/outgoing.rs @@ -15,7 +15,9 @@ impl OutgoingVerifierConfig { // same config as quic, but different alpn let mut client_cfg = self.config_alpn.as_ref().clone(); client_cfg.alpn_protocols.clear(); - client_cfg.alpn_protocols.push(web_transport_quinn::ALPN.as_bytes().to_vec()); + client_cfg + .alpn_protocols + .push(web_transport_quinn::ALPN.as_bytes().to_vec()); let suite = crate::quic::initial_suite_from_provider()?; let client_cfg = Arc::new(QuicClientConfig::with_initial(client_cfg.into(), suite)?); @@ -27,19 +29,34 @@ impl OutgoingVerifierConfig { } pub fn webtransport_endpoint(&self) -> &Result<quinn::Endpoint, String> { - self.webtransport_endpoint.get_or_init(|| self.wte().map_err(|e: anyhow::Error| format!("{e}"))) + self.webtransport_endpoint + .get_or_init(|| self.wte().map_err(|e: anyhow::Error| format!("{e}"))) } } -pub async fn webtransport_connect(target: SocketAddr, server_name: &str, url: Url, config: &OutgoingVerifierConfig) -> Result<(StanzaWrite, StanzaRead)> { - let endpoint = config.webtransport_endpoint().as_ref().map_err(|e| anyhow::anyhow!("webtransport endpoint error: {e}"))?; +pub async fn webtransport_connect( + target: SocketAddr, + server_name: &str, + url: Url, + config: &OutgoingVerifierConfig, +) -> Result<(StanzaWrite, StanzaRead)> { + let endpoint = config + .webtransport_endpoint() + .as_ref() + .map_err(|e| anyhow::anyhow!("webtransport endpoint error: {e}"))?; // connect to server let connection = endpoint.connect(target, server_name)?.await?; - trace!("quic pre-wt connected: addr={}", connection.remote_address()); + trace!( + "quic pre-wt connected: addr={}", + connection.remote_address() + ); let connection = web_transport_quinn::Session::connect(connection, url).await?; - trace!("webtransport connected: addr={}", connection.remote_address()); + trace!( + "webtransport connected: addr={}", + connection.remote_address() + ); let (wrt, rd) = connection.open_bi().await?; Ok((StanzaWrite::new(wrt), StanzaRead::new(rd)))