From 6d1a6dd6a9f825aa6fe434cd5098d2fb8684ae14 Mon Sep 17 00:00:00 2001 From: Friedel Ziegelmayer Date: Wed, 22 May 2024 14:41:38 +0200 Subject: [PATCH] feat(iroh-net)!: Implement http proxy support (#2298) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Headers are based on how `curl` and env variables on`reqwest`. Setting any of - `HTTP_PROXY` - `http_proxy` - `HTTPS_PROXY` - `https_proxy` will make all relay code use these to proxy outgoing connections. Closes #2295 ## Breaking Changes - Added `iroh_net::endpoint::Builder::proxy_url` - Added `iroh_net::endpoint::Builder::proxy_from_env` - Added `iroh_net::relay::http::ClientError::Proxy` enum variant ## TODOs - [x] config & parsing env variables - [x] the todos in the code - [x] https proxy - [x] testing: tested manually on two machines using `squid` --- Cargo.lock | 629 ++++++++++++++++---------- iroh-cli/Cargo.toml | 2 +- iroh-metrics/Cargo.toml | 2 +- iroh-net/Cargo.toml | 3 +- iroh-net/src/endpoint.rs | 68 +++ iroh-net/src/magicsock.rs | 15 + iroh-net/src/magicsock/relay_actor.rs | 6 +- iroh-net/src/relay/client.rs | 11 +- iroh-net/src/relay/http.rs | 1 + iroh-net/src/relay/http/client.rs | 196 +++++--- iroh-net/src/relay/http/streams.rs | 292 ++++++++++++ iroh-net/src/relay/server.rs | 7 +- iroh-net/src/util.rs | 2 + iroh-net/src/util/chain.rs | 138 ++++++ iroh/src/node/builder.rs | 1 + 15 files changed, 1059 insertions(+), 314 deletions(-) create mode 100644 iroh-net/src/relay/http/streams.rs create mode 100644 iroh-net/src/util/chain.rs diff --git a/Cargo.lock b/Cargo.lock index 1a7774d317..3caa10894b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,47 +78,48 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -126,9 +127,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arc-swap" @@ -200,7 +201,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", "synstructure 0.13.1", ] @@ -223,7 +224,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -234,7 +235,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -246,6 +247,12 @@ dependencies = [ "critical-section", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "attohttpc" version = "0.24.1" @@ -259,9 +266,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" @@ -328,7 +335,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -346,10 +353,10 @@ dependencies = [ "hyper 1.3.1", "hyper-util", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile 2.1.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower", "tower-service", ] @@ -411,9 +418,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64-url" @@ -522,9 +529,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -574,9 +581,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" [[package]] name = "cfg-if" @@ -667,7 +674,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.11.1", + "strsim", ] [[package]] @@ -679,7 +686,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -707,9 +714,9 @@ checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" @@ -748,9 +755,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] @@ -884,9 +891,9 @@ checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -912,9 +919,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" @@ -1027,14 +1034,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] name = "darling" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ "darling_core", "darling_macro", @@ -1042,27 +1049,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.60", + "strsim", + "syn 2.0.65", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1072,7 +1079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -1080,9 +1087,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" @@ -1131,7 +1138,7 @@ checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1161,7 +1168,7 @@ checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", "unicode-xid", ] @@ -1244,7 +1251,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1330,9 +1337,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" @@ -1389,7 +1396,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1402,7 +1409,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1422,7 +1429,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1448,9 +1455,9 @@ checksum = "76a5aa24577083f8190ad401e376b55887c7cd9083ae95d83ceec5d28ea78125" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1494,9 +1501,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fd-lock" @@ -1521,9 +1528,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "flume" @@ -1585,9 +1592,9 @@ dependencies = [ [[package]] name = "futures-buffered" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de8419e65098e54c06f5ae8a130a79e8ba2e391ff995d260ca5d77ea72ab2fe3" +checksum = "02dcae03ee5afa5ea17b1aebc793806b8ddfc6dc500e0b8e8e1eb30b9dad22c0" dependencies = [ "futures-core", "futures-util", @@ -1662,7 +1669,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.0.2", + "fastrand 2.1.0", "futures-core", "futures-io", "parking", @@ -1677,7 +1684,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -1760,9 +1767,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -1835,15 +1842,15 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http 1.1.0", "indexmap 2.2.6", "slab", @@ -1879,9 +1886,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -1889,11 +1896,11 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -1962,13 +1969,13 @@ dependencies = [ "once_cell", "rand", "ring 0.16.20", - "rustls", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "thiserror", "tinyvec", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tracing", "url", ] @@ -1988,12 +1995,12 @@ dependencies = [ "parking_lot", "rand", "resolv-conf", - "rustls", + "rustls 0.21.12", "serde", "smallvec", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tracing", ] @@ -2010,12 +2017,12 @@ dependencies = [ "futures-util", "hickory-proto", "hickory-resolver", - "rustls", + "rustls 0.21.12", "serde", "thiserror", "time", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tracing", ] @@ -2191,7 +2198,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.4", + "h2 0.4.5", "http 1.1.0", "http-body 1.0.0", "httparse", @@ -2212,9 +2219,26 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.28", - "rustls", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.22.4", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", + "tower-service", ] [[package]] @@ -2224,6 +2248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.0", @@ -2231,6 +2256,9 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -2319,7 +2347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -2337,12 +2365,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "indoc" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" - [[package]] name = "inout" version = "0.1.3" @@ -2363,9 +2385,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -2379,7 +2401,7 @@ dependencies = [ "socket2", "widestring", "windows-sys 0.48.0", - "winreg", + "winreg 0.50.0", ] [[package]] @@ -2515,7 +2537,7 @@ dependencies = [ "redb 1.5.1", "redb 2.1.0", "reflink-copy", - "rustls", + "rustls 0.21.12", "self_cell", "serde", "serde_json", @@ -2563,7 +2585,7 @@ dependencies = [ "rand", "ratatui", "regex", - "reqwest", + "reqwest 0.12.4", "rustyline", "serde", "serde_with", @@ -2611,13 +2633,13 @@ dependencies = [ "rcgen 0.12.1", "redb 2.1.0", "regex", - "rustls", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "struct_iterable", "strum 0.26.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-rustls-acme", "tokio-stream", "tokio-util", @@ -2721,7 +2743,7 @@ dependencies = [ "hyper-util", "once_cell", "prometheus-client", - "reqwest", + "reqwest 0.12.4", "serde", "struct_iterable", "time", @@ -2737,6 +2759,7 @@ dependencies = [ "anyhow", "axum", "backoff", + "base64 0.22.1", "bytes", "clap", "criterion", @@ -2785,12 +2808,12 @@ dependencies = [ "rand_core", "rcgen 0.11.3", "regex", - "reqwest", + "reqwest 0.12.4", "ring 0.17.8", "rtnetlink", - "rustls", + "rustls 0.21.12", "rustls-pemfile 1.0.4", - "rustls-webpki", + "rustls-webpki 0.101.7", "serde", "serde_json", "serde_with", @@ -2803,7 +2826,7 @@ dependencies = [ "thiserror", "time", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-rustls-acme", "tokio-util", "toml", @@ -2811,7 +2834,7 @@ dependencies = [ "tracing-subscriber", "url", "watchable", - "webpki-roots", + "webpki-roots 0.25.4", "windows 0.51.1", "wmi", "x509-parser 0.15.1", @@ -2843,7 +2866,7 @@ dependencies = [ "iroh-quinn-udp", "pin-project-lite", "rustc-hash", - "rustls", + "rustls 0.21.12", "thiserror", "tokio", "tracing", @@ -2859,7 +2882,7 @@ dependencies = [ "rand", "ring 0.16.20", "rustc-hash", - "rustls", + "rustls 0.21.12", "rustls-native-certs", "slab", "thiserror", @@ -2901,6 +2924,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -2945,9 +2974,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libm" @@ -2973,9 +3002,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2999,7 +3028,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -3084,9 +3113,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -3313,11 +3342,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -3356,9 +3384,9 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -3367,9 +3395,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -3403,7 +3431,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -3563,9 +3591,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem" @@ -3573,7 +3601,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "serde", ] @@ -3623,7 +3651,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -3654,7 +3682,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -3679,7 +3707,7 @@ dependencies = [ "ed25519-dalek", "mainline", "rand", - "reqwest", + "reqwest 0.11.27", "self_cell", "simple-dns", "thiserror", @@ -3716,9 +3744,9 @@ checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -3729,15 +3757,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -3760,7 +3788,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -3944,9 +3972,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] @@ -3971,7 +3999,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -4124,29 +4152,29 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a564a852040e82671dc50a37d88f3aa83bbc690dfc6844cfe7a2591620206a80" +checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef" dependencies = [ "bitflags 2.5.0", "cassowary", "compact_str", "crossterm", - "indoc", "itertools 0.12.1", "lru", "paste", "stability", "strum 0.26.2", "unicode-segmentation", + "unicode-truncate", "unicode-width", ] [[package]] name = "raw-cpuid" -version = "11.0.1" +version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1" +checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" dependencies = [ "bitflags 2.5.0", ] @@ -4244,22 +4272,22 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -4338,7 +4366,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", - "hyper-rustls", + "hyper-rustls 0.24.2", "ipnet", "js-sys", "log", @@ -4346,7 +4374,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -4354,14 +4382,55 @@ dependencies = [ "sync_wrapper 0.1.2", "system-configuration 0.5.1", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-rustls 0.26.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.22.4", + "rustls-pemfile 2.1.2", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "tokio", + "tokio-rustls 0.25.0", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", - "winreg", + "webpki-roots 0.26.1", + "winreg 0.52.0", ] [[package]] @@ -4455,9 +4524,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -4498,16 +4567,30 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -4535,15 +4618,15 @@ version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.5.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-webpki" @@ -4555,11 +4638,22 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -4598,9 +4692,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "salsa20" @@ -4661,11 +4755,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -4674,9 +4768,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -4684,24 +4778,24 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.198" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -4736,20 +4830,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -4768,9 +4862,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -4798,11 +4892,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -4816,14 +4910,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -4967,9 +5061,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5058,7 +5152,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a" dependencies = [ "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5079,12 +5173,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -5111,7 +5199,7 @@ dependencies = [ "proc-macro2", "quote", "struct_iterable_internal", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5129,7 +5217,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta-derive", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5140,7 +5228,7 @@ checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5171,7 +5259,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5184,7 +5272,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5193,7 +5281,7 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0adebf9fb8fba5c39ee34092b0383f247e4d1255b98fcffec94b4b797b85b677" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "bounded-integer", "byteorder", "crc", @@ -5246,9 +5334,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.60" +version = "2.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106" dependencies = [ "proc-macro2", "quote", @@ -5298,7 +5386,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5370,7 +5458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", - "fastrand 2.0.2", + "fastrand 2.1.0", "rustix", "windows-sys 0.52.0", ] @@ -5384,7 +5472,7 @@ dependencies = [ "proc-macro2", "quote", "structmeta", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5403,22 +5491,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.59" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5516,7 +5604,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5525,7 +5613,18 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", "tokio", ] @@ -5545,16 +5644,16 @@ dependencies = [ "pem", "proc-macro2", "rcgen 0.12.1", - "reqwest", + "reqwest 0.11.27", "ring 0.17.8", - "rustls", + "rustls 0.21.12", "serde", "serde_json", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "url", - "webpki-roots", + "webpki-roots 0.25.4", "x509-parser 0.16.0", ] @@ -5587,39 +5686,38 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "pin-project-lite", "slab", "tokio", - "tracing", ] [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.13", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -5637,15 +5735,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.6", + "winnow 0.6.8", ] [[package]] @@ -5741,7 +5839,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -5863,11 +5961,21 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "unicode-truncate" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5fbabedabe362c618c714dbefda9927b5afc8e2a8102f47f081089a9019226" +dependencies = [ + "itertools 0.12.1", + "unicode-width", +] + [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" @@ -5938,9 +6046,9 @@ dependencies = [ [[package]] name = "waker-fn" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" [[package]] name = "walkdir" @@ -5994,7 +6102,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", "wasm-bindgen-shared", ] @@ -6028,7 +6136,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6067,6 +6175,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "whoami" version = "1.5.1" @@ -6205,7 +6322,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -6216,7 +6333,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -6227,7 +6344,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -6238,7 +6355,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] @@ -6400,9 +6517,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] @@ -6417,6 +6534,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wmi" version = "0.13.3" @@ -6512,22 +6639,22 @@ checksum = "edb37266251c28b03d08162174a91c3a092e3bd4f476f8205ee1c507b78b7bdc" [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.60", + "syn 2.0.65", ] [[package]] diff --git a/iroh-cli/Cargo.toml b/iroh-cli/Cargo.toml index 112a977e2d..91ab81394e 100644 --- a/iroh-cli/Cargo.toml +++ b/iroh-cli/Cargo.toml @@ -48,7 +48,7 @@ postcard = "1.0.8" quic-rpc = { version = "0.9.0", features = ["flume-transport", "quinn-transport"] } rand = "0.8.5" ratatui = "0.26.2" -reqwest = { version = "0.11.19", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.12.4", default-features = false, features = ["json", "rustls-tls"] } rustyline = "12.0.0" serde = { version = "1.0.197", features = ["derive"] } serde_with = "3.7.0" diff --git a/iroh-metrics/Cargo.toml b/iroh-metrics/Cargo.toml index 3670038ed6..6789a13d7d 100644 --- a/iroh-metrics/Cargo.toml +++ b/iroh-metrics/Cargo.toml @@ -22,7 +22,7 @@ hyper = { version = "1", features = ["server", "http1"] } hyper-util = { version = "0.1.1", features = ["tokio"] } once_cell = "1.17.0" prometheus-client = { version = "0.22.0", optional = true } -reqwest = { version = "0.11.19", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.12.4", default-features = false, features = ["json", "rustls-tls"] } serde = { version = "1.0", features = ["derive"] } struct_iterable = "0.1" time = { version = "0.3.21", features = ["serde-well-known"] } diff --git a/iroh-net/Cargo.toml b/iroh-net/Cargo.toml index 9b52533a49..9d0f7cdc36 100644 --- a/iroh-net/Cargo.toml +++ b/iroh-net/Cargo.toml @@ -19,6 +19,7 @@ workspace = true axum = { version = "0.7.4", optional = true } aead = { version = "0.5.2", features = ["bytes"] } anyhow = { version = "1" } +base64 = "0.22.1" backoff = "0.4.0" bytes = "1" netdev = "0.25" @@ -54,7 +55,7 @@ quinn-udp = { package = "iroh-quinn-udp", version = "0.4" } rand = "0.8" rand_core = "0.6.4" rcgen = "0.11" -reqwest = { version = "0.11.19", default-features = false, features = ["rustls-tls"] } +reqwest = { version = "0.12.4", default-features = false, features = ["rustls-tls"] } ring = "0.17" rustls = { version = "0.21.11", default-features = false, features = ["dangerous_configuration"] } serde = { version = "1", features = ["derive", "rc"] } diff --git a/iroh-net/src/endpoint.rs b/iroh-net/src/endpoint.rs index 130db7e70d..e5cf7936ec 100644 --- a/iroh-net/src/endpoint.rs +++ b/iroh-net/src/endpoint.rs @@ -16,6 +16,7 @@ use derive_more::Debug; use futures_lite::{Stream, StreamExt}; use tokio_util::sync::{CancellationToken, WaitForCancellationFuture}; use tracing::{debug, info_span, trace, warn}; +use url::Url; use crate::{ config, @@ -58,6 +59,7 @@ pub struct Builder { concurrent_connections: Option, keylog: bool, discovery: Option>, + proxy_url: Option, /// Path for known peers. See [`Builder::peers_data_path`]. peers_path: Option, dns_resolver: Option, @@ -75,6 +77,7 @@ impl Default for Builder { concurrent_connections: Default::default(), keylog: Default::default(), discovery: Default::default(), + proxy_url: None, peers_path: None, dns_resolver: None, #[cfg(any(test, feature = "test-utils"))] @@ -100,6 +103,23 @@ impl Builder { self } + /// Set an explicit proxy url to proxy all HTTP(S) traffic through. + pub fn proxy_url(mut self, url: Url) -> Self { + self.proxy_url.replace(url); + self + } + + /// Set the proxy url from the environment, in this order: + /// + /// - `HTTP_PROXY` + /// - `http_proxy` + /// - `HTTPS_PROXY` + /// - `https_proxy` + pub fn proxy_from_env(mut self) -> Self { + self.proxy_url = proxy_url_from_env(); + self + } + /// If *keylog* is `true` and the KEYLOGFILE environment variable is present it will be /// considered a filename to which the TLS pre-master keys are logged. This can be useful /// to be able to decrypt captured traffic for debugging purposes. @@ -225,6 +245,7 @@ impl Builder { relay_map, nodes_path: self.peers_path, discovery: self.discovery, + proxy_url: self.proxy_url, dns_resolver, #[cfg(any(test, feature = "test-utils"))] insecure_skip_relay_cert_verify: self.insecure_skip_relay_cert_verify, @@ -831,6 +852,53 @@ fn try_send_rtt_msg(conn: &quinn::Connection, magic_ep: &Endpoint) { } } +/// Read a proxy url from the environemnt, in this order +/// +/// - `HTTP_PROXY` +/// - `http_proxy` +/// - `HTTPS_PROXY` +/// - `https_proxy` +fn proxy_url_from_env() -> Option { + if let Some(url) = std::env::var("HTTP_PROXY") + .ok() + .and_then(|s| s.parse::().ok()) + { + if is_cgi() { + warn!("HTTP_PROXY environment variable ignored in CGI"); + } else { + return Some(url); + } + } + if let Some(url) = std::env::var("http_proxy") + .ok() + .and_then(|s| s.parse::().ok()) + { + return Some(url); + } + if let Some(url) = std::env::var("HTTPS_PROXY") + .ok() + .and_then(|s| s.parse::().ok()) + { + return Some(url); + } + if let Some(url) = std::env::var("https_proxy") + .ok() + .and_then(|s| s.parse::().ok()) + { + return Some(url); + } + + None +} + +/// Check if we are being executed in a CGI context. +/// +/// If so, a malicious client can send the `Proxy:` header, and it will +/// be in the `HTTP_PROXY` env var. So we don't use it :) +fn is_cgi() -> bool { + std::env::var_os("REQUEST_METHOD").is_some() +} + // TODO: These tests could still be flaky, lets fix that: // https://github.com/n0-computer/iroh/issues/1183 #[cfg(test)] diff --git a/iroh-net/src/magicsock.rs b/iroh-net/src/magicsock.rs index 8243f4191d..f5c745dbc7 100644 --- a/iroh-net/src/magicsock.rs +++ b/iroh-net/src/magicsock.rs @@ -46,6 +46,7 @@ use tokio_util::sync::CancellationToken; use tracing::{ debug, error, error_span, info, info_span, instrument, trace, trace_span, warn, Instrument, }; +use url::Url; use watchable::Watchable; use crate::{ @@ -117,6 +118,9 @@ pub(super) struct Options { /// configuration. pub dns_resolver: DnsResolver, + /// Proxy configuration. + pub proxy_url: Option, + /// Skip verification of SSL certificates from relay servers /// /// May only be used in tests. @@ -132,6 +136,7 @@ impl Default for Options { relay_map: RelayMap::empty(), nodes_path: None, discovery: None, + proxy_url: None, dns_resolver: crate::dns::default_resolver().clone(), #[cfg(any(test, feature = "test-utils"))] insecure_skip_relay_cert_verify: false, @@ -170,6 +175,9 @@ pub(super) struct MagicSock { relay_actor_sender: mpsc::Sender, /// String representation of the node_id of this node. me: String, + /// Proxy + proxy_url: Option, + /// Used for receiving relay messages. relay_recv_receiver: flume::Receiver, /// Stores wakers, to be called when relay_recv_ch receives new data. @@ -249,6 +257,11 @@ impl MagicSock { self.my_relay.get() } + /// Get the current proxy configuration. + pub fn proxy_url(&self) -> Option<&Url> { + self.proxy_url.as_ref() + } + /// Sets the relay node with the best latency. /// /// If we are not connected to any relay nodes, set this to `None`. @@ -1283,6 +1296,7 @@ impl Handle { discovery, nodes_path, dns_resolver, + proxy_url, #[cfg(any(test, feature = "test-utils"))] insecure_skip_relay_cert_verify, } = opts; @@ -1341,6 +1355,7 @@ impl Handle { me, port: AtomicU16::new(port), secret_key, + proxy_url, local_addrs: std::sync::RwLock::new((ipv4_addr, ipv6_addr)), closing: AtomicBool::new(false), closed: AtomicBool::new(false), diff --git a/iroh-net/src/magicsock/relay_actor.rs b/iroh-net/src/magicsock/relay_actor.rs index ca46d2109e..ecae432cf3 100644 --- a/iroh-net/src/magicsock/relay_actor.rs +++ b/iroh-net/src/magicsock/relay_actor.rs @@ -479,7 +479,11 @@ impl RelayActor { let url1 = url.clone(); // building a client dials the relay - let builder = relay::http::ClientBuilder::new(url1.clone()) + let mut builder = relay::http::ClientBuilder::new(url1.clone()); + if let Some(url) = self.msock.proxy_url() { + builder = builder.proxy_url(url.clone()); + } + let builder = builder .address_family_selector(move || { let ipv6_reported = ipv6_reported.clone(); Box::pin(async move { ipv6_reported.load(Ordering::Relaxed) }) diff --git a/iroh-net/src/relay/client.rs b/iroh-net/src/relay/client.rs index cbee0aea0a..bf0e069bfc 100644 --- a/iroh-net/src/relay/client.rs +++ b/iroh-net/src/relay/client.rs @@ -8,12 +8,13 @@ use bytes::Bytes; use futures_lite::StreamExt; use futures_sink::Sink; use futures_util::sink::SinkExt; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::AsyncWrite; use tokio::sync::mpsc; use tokio_util::codec::{FramedRead, FramedWrite}; use tracing::{debug, info_span, trace, Instrument}; use super::codec::PER_CLIENT_READ_QUEUE_DEPTH; +use super::http::streams::{MaybeTlsStreamReader, MaybeTlsStreamWriter}; use super::{ codec::{ write_frame, DerpCodec, Frame, MAX_PACKET_SIZE, PER_CLIENT_SEND_QUEUE_DEPTH, @@ -63,7 +64,7 @@ impl ClientReceiver { } } -type RelayReader = FramedRead, DerpCodec>; +type RelayReader = FramedRead; #[derive(derive_more::Debug)] pub struct InnerClient { @@ -247,7 +248,7 @@ impl ClientWriter { pub struct ClientBuilder { secret_key: SecretKey, reader: RelayReader, - writer: FramedWrite, DerpCodec>, + writer: FramedWrite, local_addr: SocketAddr, } @@ -255,8 +256,8 @@ impl ClientBuilder { pub fn new( secret_key: SecretKey, local_addr: SocketAddr, - reader: Box, - writer: Box, + reader: MaybeTlsStreamReader, + writer: MaybeTlsStreamWriter, ) -> Self { Self { secret_key, diff --git a/iroh-net/src/relay/http.rs b/iroh-net/src/relay/http.rs index 5ea0aee188..e73da2de73 100644 --- a/iroh-net/src/relay/http.rs +++ b/iroh-net/src/relay/http.rs @@ -3,6 +3,7 @@ //! mod client; mod server; +pub(crate) mod streams; pub use self::client::{Client, ClientBuilder, ClientError, ClientReceiver}; pub use self::server::{Server, ServerBuilder, TlsAcceptor, TlsConfig}; diff --git a/iroh-net/src/relay/http/client.rs b/iroh-net/src/relay/http/client.rs index 339a50e432..39c9302bd4 100644 --- a/iroh-net/src/relay/http/client.rs +++ b/iroh-net/src/relay/http/client.rs @@ -5,16 +5,18 @@ use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use std::time::Duration; -use anyhow::bail; +use base64::{engine::general_purpose::URL_SAFE, Engine as _}; use bytes::Bytes; use futures_lite::future::Boxed as BoxFuture; +use http_body_util::Empty; use hyper::body::Incoming; use hyper::header::UPGRADE; -use hyper::upgrade::{Parts, Upgraded}; +use hyper::upgrade::Parts; use hyper::Request; +use hyper_util::rt::TokioIo; use rand::Rng; use rustls::client::Resumption; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::TcpStream; use tokio::sync::{mpsc, oneshot}; use tokio::task::JoinSet; @@ -24,13 +26,17 @@ use url::Url; use crate::dns::{DnsResolver, ResolverExt}; use crate::key::{PublicKey, SecretKey}; +use crate::relay::http::streams::{downcast_upgrade, MaybeTlsStream}; use crate::relay::RelayUrl; use crate::relay::{ client::Client as RelayClient, client::ClientBuilder as RelayClientBuilder, client::ClientReceiver as RelayClientReceiver, ReceivedMessage, }; +use crate::util::chain; use crate::util::AbortingJoinHandle; +use super::streams::ProxyStream; + const DIAL_NODE_TIMEOUT: Duration = Duration::from_millis(1500); const PING_TIMEOUT: Duration = Duration::from_secs(5); const CONNECT_TIMEOUT: Duration = Duration::from_secs(10); @@ -87,6 +93,9 @@ pub enum ClientError { /// The connection failed to upgrade #[error("failed to upgrade connection: {0}")] Upgrade(String), + /// The connection failed to proxy + #[error("failed to proxy connection: {0}")] + Proxy(String), /// The relay [`super::client::Client`] failed to build #[error("failed to build relay client: {0}")] Build(String), @@ -159,6 +168,7 @@ struct Actor { pings: PingTracker, ping_tasks: JoinSet<()>, dns_resolver: DnsResolver, + proxy_url: Option, } #[derive(Default, Debug)] @@ -200,6 +210,8 @@ pub struct ClientBuilder { /// Allow self-signed certificates from relay servers #[cfg(any(test, feature = "test-utils"))] insecure_skip_cert_verify: bool, + /// HTTP Proxy + proxy_url: Option, } impl std::fmt::Debug for ClientBuilder { @@ -224,6 +236,7 @@ impl ClientBuilder { url: url.into(), #[cfg(any(test, feature = "test-utils"))] insecure_skip_cert_verify: false, + proxy_url: None, } } @@ -275,6 +288,12 @@ impl ClientBuilder { self } + /// Set an explicit proxy url to proxy all HTTP(S) traffic through. + pub fn proxy_url(mut self, url: Url) -> Self { + self.proxy_url.replace(url); + self + } + /// Build the [`Client`] pub fn build(self, key: SecretKey, dns_resolver: DnsResolver) -> (Client, ClientReceiver) { // TODO: review TLS config @@ -316,6 +335,7 @@ impl ClientBuilder { url: self.url, tls_connector, dns_resolver, + proxy_url: self.proxy_url, }; let (msg_sender, inbox) = mpsc::channel(64); @@ -762,18 +782,6 @@ impl Actor { .and_then(|s| rustls::ServerName::try_from(s).ok()) } - fn url_port(&self) -> Option { - if let Some(port) = self.url.port() { - return Some(port); - } - - match self.url.scheme() { - "http" => Some(80), - "https" => Some(443), - _ => None, - } - } - fn use_https(&self) -> bool { // only disable https if we are explicitly dialing a http url if self.url.scheme() == "http" { @@ -782,14 +790,22 @@ impl Actor { true } - async fn dial_url(&self) -> Result { - debug!(%self.url, "dial url"); + async fn dial_url(&self) -> Result { + if let Some(ref proxy) = self.proxy_url { + let stream = self.dial_url_proxy(proxy.clone()).await?; + Ok(ProxyStream::Proxied(stream)) + } else { + let stream = self.dial_url_direct().await?; + Ok(ProxyStream::Raw(stream)) + } + } + async fn dial_url_direct(&self) -> Result { + debug!(%self.url, "dial url"); let prefer_ipv6 = self.prefer_ipv6().await; let dst_ip = resolve_host(&self.dns_resolver, &self.url, prefer_ipv6).await?; - let port = self - .url_port() + let port = url_port(&self.url) .ok_or_else(|| ClientError::InvalidUrl("missing url port".into()))?; let addr = SocketAddr::new(dst_ip, port); @@ -808,6 +824,102 @@ impl Actor { Ok(tcp_stream) } + async fn dial_url_proxy( + &self, + proxy_url: Url, + ) -> Result, MaybeTlsStream>, ClientError> { + debug!(%self.url, %proxy_url, "dial url via proxy"); + + // Resolve proxy DNS + let prefer_ipv6 = self.prefer_ipv6().await; + let proxy_ip = resolve_host(&self.dns_resolver, &proxy_url, prefer_ipv6).await?; + + let proxy_port = url_port(&proxy_url) + .ok_or_else(|| ClientError::Proxy("missing proxy url port".into()))?; + let proxy_addr = SocketAddr::new(proxy_ip, proxy_port); + + debug!(%proxy_addr, "connecting to proxy"); + + let tcp_stream = tokio::time::timeout(DIAL_NODE_TIMEOUT, async move { + TcpStream::connect(proxy_addr).await + }) + .await + .map_err(|_| ClientError::ConnectTimeout)? + .map_err(ClientError::DialIO)?; + + tcp_stream.set_nodelay(true)?; + + // Setup TLS if necessary + let io = if proxy_url.scheme() == "http" { + MaybeTlsStream::Raw(tcp_stream) + } else { + let hostname = proxy_url + .host_str() + .and_then(|s| rustls::ServerName::try_from(s).ok()) + .ok_or_else(|| ClientError::InvalidUrl("No tls servername for proxy url".into()))?; + let tls_stream = self.tls_connector.connect(hostname, tcp_stream).await?; + MaybeTlsStream::Tls(tls_stream) + }; + let io = TokioIo::new(io); + + let target_host = self + .url + .host_str() + .ok_or_else(|| ClientError::Proxy("missing proxy host".into()))?; + + let port = + url_port(&self.url).ok_or_else(|| ClientError::Proxy("invalid target port".into()))?; + + // Establish Proxy Tunnel + let mut req_builder = Request::builder() + .uri(format!("{}:{}", target_host, port)) + .method("CONNECT") + .header("Host", target_host) + .header("Proxy-Connection", "Keep-Alive"); + if !proxy_url.username().is_empty() { + // Passthrough authorization + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Proxy-Authorization + debug!( + "setting proxy-authorization: username={}", + proxy_url.username() + ); + let to_encode = format!( + "{}:{}", + proxy_url.username(), + proxy_url.password().unwrap_or_default() + ); + let encoded = URL_SAFE.encode(to_encode); + req_builder = req_builder.header("Proxy-Authorization", format!("Basic {}", encoded)); + } + let req = req_builder.body(Empty::::new())?; + + debug!("Sending proxy request: {:?}", req); + + let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?; + tokio::task::spawn(async move { + if let Err(err) = conn.with_upgrades().await { + error!("Proxy connection failed: {:?}", err); + } + }); + + let res = sender.send_request(req).await?; + if !res.status().is_success() { + return Err(ClientError::Proxy(format!( + "failed to connect to proxy: {}", + res.status(), + ))); + } + + let upgraded = hyper::upgrade::on(res).await?; + let Ok(Parts { io, read_buf, .. }) = upgraded.downcast::>() else { + return Err(ClientError::Proxy("invalid upgrade".to_string())); + }; + + let res = chain::chain(std::io::Cursor::new(read_buf), io.into_inner()); + + Ok(res) + } + /// Reports whether IPv4 dials should be slightly /// delayed to give IPv6 a better chance of winning dial races. /// Implementations should only return true if IPv6 is expected @@ -882,38 +994,6 @@ async fn resolve_host( } } -fn downcast_upgrade( - upgraded: Upgraded, -) -> anyhow::Result<( - Box, - Box, -)> { - match upgraded.downcast::>() { - Ok(Parts { read_buf, io, .. }) => { - let (reader, writer) = tokio::io::split(io.into_inner()); - // Prepend data to the reader to avoid data loss - let reader = std::io::Cursor::new(read_buf).chain(reader); - - Ok((Box::new(reader), Box::new(writer))) - } - Err(upgraded) => { - if let Ok(Parts { read_buf, io, .. }) = - upgraded.downcast::>>() - { - let (reader, writer) = tokio::io::split(io.into_inner()); - // Prepend data to the reader to avoid data loss - let reader = std::io::Cursor::new(read_buf).chain(reader); - - return Ok((Box::new(reader), Box::new(writer))); - } - - bail!( - "could not downcast the upgraded connection to a TcpStream or client::TlsStream" - ) - } - } -} - /// Used to allow self signed certificates in tests #[cfg(any(test, feature = "test-utils"))] struct NoCertVerifier; @@ -933,9 +1013,21 @@ impl rustls::client::ServerCertVerifier for NoCertVerifier { } } +fn url_port(url: &Url) -> Option { + if let Some(port) = url.port() { + return Some(port); + } + + match url.scheme() { + "http" => Some(80), + "https" => Some(443), + _ => None, + } +} + #[cfg(test)] mod tests { - use anyhow::Result; + use anyhow::{bail, Result}; use crate::dns::default_resolver; diff --git a/iroh-net/src/relay/http/streams.rs b/iroh-net/src/relay/http/streams.rs new file mode 100644 index 0000000000..7910049683 --- /dev/null +++ b/iroh-net/src/relay/http/streams.rs @@ -0,0 +1,292 @@ +use std::{ + net::SocketAddr, + pin::Pin, + task::{Context, Poll}, +}; + +use anyhow::{bail, Result}; +use bytes::Bytes; +use hyper::upgrade::{Parts, Upgraded}; +use hyper_util::rt::TokioIo; +use tokio::{ + io::{AsyncRead, AsyncWrite}, + net::TcpStream, +}; + +use crate::util::chain; + +pub enum MaybeTlsStreamReader { + Raw(chain::Chain, tokio::io::ReadHalf>), + Tls( + chain::Chain< + std::io::Cursor, + tokio::io::ReadHalf>, + >, + ), + #[cfg(test)] + Mem(tokio::io::ReadHalf), +} + +impl AsyncRead for MaybeTlsStreamReader { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf), + Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf), + #[cfg(test)] + Self::Mem(stream) => Pin::new(stream).poll_read(cx, buf), + } + } +} + +pub enum MaybeTlsStreamWriter { + Raw(tokio::io::WriteHalf), + Tls(tokio::io::WriteHalf>), + #[cfg(test)] + Mem(tokio::io::WriteHalf), +} + +impl AsyncWrite for MaybeTlsStreamWriter { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf), + Self::Tls(stream) => Pin::new(stream).poll_write(cx, buf), + #[cfg(test)] + Self::Mem(stream) => Pin::new(stream).poll_write(cx, buf), + } + } + + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_flush(cx), + Self::Tls(stream) => Pin::new(stream).poll_flush(cx), + #[cfg(test)] + Self::Mem(stream) => Pin::new(stream).poll_flush(cx), + } + } + + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx), + Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx), + #[cfg(test)] + Self::Mem(stream) => Pin::new(stream).poll_shutdown(cx), + } + } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + Self::Tls(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + #[cfg(test)] + Self::Mem(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + } + } +} + +pub fn downcast_upgrade( + upgraded: Upgraded, +) -> Result<(MaybeTlsStreamReader, MaybeTlsStreamWriter)> { + match upgraded.downcast::>() { + Ok(Parts { read_buf, io, .. }) => { + let inner = io.into_inner(); + let (reader, writer) = tokio::io::split(inner); + // Prepend data to the reader to avoid data loss + let reader = chain::chain(std::io::Cursor::new(read_buf), reader); + Ok(( + MaybeTlsStreamReader::Raw(reader), + MaybeTlsStreamWriter::Raw(writer), + )) + } + Err(upgraded) => { + if let Ok(Parts { read_buf, io, .. }) = + upgraded.downcast::>>() + { + let inner = io.into_inner(); + let (reader, writer) = tokio::io::split(inner); + // Prepend data to the reader to avoid data loss + let reader = chain::chain(std::io::Cursor::new(read_buf), reader); + + return Ok(( + MaybeTlsStreamReader::Tls(reader), + MaybeTlsStreamWriter::Tls(writer), + )); + } + + bail!( + "could not downcast the upgraded connection to a TcpStream or client::TlsStream" + ) + } + } +} + +pub enum ProxyStream { + Raw(TcpStream), + Proxied(chain::Chain, MaybeTlsStream>), +} + +impl AsyncRead for ProxyStream { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf), + Self::Proxied(stream) => Pin::new(stream).poll_read(cx, buf), + } + } +} + +impl AsyncWrite for ProxyStream { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf), + Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_write(cx, buf), + } + } + + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_flush(cx), + Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_flush(cx), + } + } + + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx), + Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_shutdown(cx), + } + } + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + Self::Proxied(stream) => Pin::new(stream.get_mut().1).poll_write_vectored(cx, bufs), + } + } +} + +impl ProxyStream { + pub fn local_addr(&self) -> std::io::Result { + match self { + Self::Raw(s) => s.local_addr(), + Self::Proxied(s) => s.get_ref().1.local_addr(), + } + } + + pub fn peer_addr(&self) -> std::io::Result { + match self { + Self::Raw(s) => s.peer_addr(), + Self::Proxied(s) => s.get_ref().1.peer_addr(), + } + } +} + +pub enum MaybeTlsStream { + Raw(TcpStream), + Tls(tokio_rustls::client::TlsStream), +} + +impl AsyncRead for MaybeTlsStream { + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_read(cx, buf), + Self::Tls(stream) => Pin::new(stream).poll_read(cx, buf), + } + } +} + +impl AsyncWrite for MaybeTlsStream { + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write(cx, buf), + Self::Tls(stream) => Pin::new(stream).poll_write(cx, buf), + } + } + + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_flush(cx), + Self::Tls(stream) => Pin::new(stream).poll_flush(cx), + } + } + + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_shutdown(cx), + Self::Tls(stream) => Pin::new(stream).poll_shutdown(cx), + } + } + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> Poll> { + match &mut *self { + Self::Raw(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + Self::Tls(stream) => Pin::new(stream).poll_write_vectored(cx, bufs), + } + } +} + +impl MaybeTlsStream { + pub fn local_addr(&self) -> std::io::Result { + match self { + Self::Raw(s) => s.local_addr(), + Self::Tls(s) => s.get_ref().0.local_addr(), + } + } + + pub fn peer_addr(&self) -> std::io::Result { + match self { + Self::Raw(s) => s.peer_addr(), + Self::Tls(s) => s.get_ref().0.peer_addr(), + } + } +} diff --git a/iroh-net/src/relay/server.rs b/iroh-net/src/relay/server.rs index dd4c8d6265..38493c4601 100644 --- a/iroh-net/src/relay/server.rs +++ b/iroh-net/src/relay/server.rs @@ -427,6 +427,7 @@ mod tests { use crate::relay::{ client::ClientBuilder, codec::{recv_frame, Frame, FrameType}, + http::streams::{MaybeTlsStreamReader, MaybeTlsStreamWriter}, types::ClientInfo, ReceivedMessage, }; @@ -570,13 +571,15 @@ mod tests { fn make_test_client(secret_key: SecretKey) -> (tokio::io::DuplexStream, ClientBuilder) { let (client, server) = tokio::io::duplex(10); let (client_reader, client_writer) = tokio::io::split(client); + let client_reader = MaybeTlsStreamReader::Mem(client_reader); + let client_writer = MaybeTlsStreamWriter::Mem(client_writer); ( server, ClientBuilder::new( secret_key, "127.0.0.1:0".parse().unwrap(), - Box::new(client_reader), - Box::new(client_writer), + client_reader, + client_writer, ), ) } diff --git a/iroh-net/src/util.rs b/iroh-net/src/util.rs index 58165a9b8d..e94655b51f 100644 --- a/iroh-net/src/util.rs +++ b/iroh-net/src/util.rs @@ -10,6 +10,8 @@ use std::{ use futures_lite::future::Boxed as BoxFuture; use futures_util::{future::Shared, FutureExt}; +pub mod chain; + /// A join handle that owns the task it is running, and aborts it when dropped. #[derive(Debug, derive_more::Deref)] pub struct AbortingJoinHandle { diff --git a/iroh-net/src/util/chain.rs b/iroh-net/src/util/chain.rs new file mode 100644 index 0000000000..f4b683f541 --- /dev/null +++ b/iroh-net/src/util/chain.rs @@ -0,0 +1,138 @@ +//! IO utilitiy to chain `AsyncRead`s together. + +// Based on tokios chain implementation, that doesn't make the concrete type public. + +use std::fmt; +use std::io; +use std::pin::Pin; +use std::task::ready; +use std::task::{Context, Poll}; + +use pin_project::pin_project; +use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf}; + +/// Stream for the [`chain`] method. +#[must_use = "streams do nothing unless polled"] +#[pin_project] +pub struct Chain { + #[pin] + first: T, + #[pin] + second: U, + done_first: bool, +} + +/// Chain two `AsyncRead`s together. +pub fn chain(first: T, second: U) -> Chain +where + T: AsyncRead, + U: AsyncRead, +{ + Chain { + first, + second, + done_first: false, + } +} + +impl Chain +where + T: AsyncRead, + U: AsyncRead, +{ + /// Gets references to the underlying readers in this `Chain`. + pub fn get_ref(&self) -> (&T, &U) { + (&self.first, &self.second) + } + + /// Gets mutable references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + pub fn get_mut(&mut self) -> (&mut T, &mut U) { + (&mut self.first, &mut self.second) + } + + /// Gets pinned mutable references to the underlying readers in this `Chain`. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying readers as doing so may corrupt the internal state of this + /// `Chain`. + pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) { + let me = self.project(); + (me.first, me.second) + } + + /// Consumes the `Chain`, returning the wrapped readers. + pub fn into_inner(self) -> (T, U) { + (self.first, self.second) + } +} + +impl fmt::Debug for Chain +where + T: fmt::Debug, + U: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Chain") + .field("t", &self.first) + .field("u", &self.second) + .finish() + } +} + +impl AsyncRead for Chain +where + T: AsyncRead, + U: AsyncRead, +{ + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + let me = self.project(); + + if !*me.done_first { + let rem = buf.remaining(); + ready!(me.first.poll_read(cx, buf))?; + if buf.remaining() == rem { + *me.done_first = true; + } else { + return Poll::Ready(Ok(())); + } + } + me.second.poll_read(cx, buf) + } +} + +impl AsyncBufRead for Chain +where + T: AsyncBufRead, + U: AsyncBufRead, +{ + fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let me = self.project(); + + if !*me.done_first { + match ready!(me.first.poll_fill_buf(cx)?) { + [] => { + *me.done_first = true; + } + buf => return Poll::Ready(Ok(buf)), + } + } + me.second.poll_fill_buf(cx) + } + + fn consume(self: Pin<&mut Self>, amt: usize) { + let me = self.project(); + if !*me.done_first { + me.first.consume(amt) + } else { + me.second.consume(amt) + } + } +} diff --git a/iroh/src/node/builder.rs b/iroh/src/node/builder.rs index 61a53f2828..833071ac05 100644 --- a/iroh/src/node/builder.rs +++ b/iroh/src/node/builder.rs @@ -391,6 +391,7 @@ where let endpoint = Endpoint::builder() .secret_key(self.secret_key.clone()) + .proxy_from_env() .alpns(PROTOCOLS.iter().map(|p| p.to_vec()).collect()) .keylog(self.keylog) .transport_config(transport_config)