From 04e6538f68ed8ebcc96dd1dcb647e5dd00b7c190 Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Fri, 4 Sep 2020 18:50:24 -0400 Subject: [PATCH] use dns cache --- Cargo.lock | 359 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- src/lib.rs | 107 +++++++++++++++- src/main.rs | 53 +++++--- 4 files changed, 503 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c71cc..4942656 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,15 +104,18 @@ name = "bubble-flexrouter" version = "0.1.0" dependencies = [ "clap", + "futures", "futures-channel", "futures-core", "futures-util", "http", "hyper", + "hyper-tls", "lru", "os_info", "pnet", "tokio", + "tower", "trust-dns-resolver", ] @@ -122,6 +125,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" +[[package]] +name = "cc" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" + [[package]] name = "cfg-if" version = "0.1.10" @@ -143,6 +152,22 @@ dependencies = [ "vec_map", ] +[[package]] +name = "core-foundation" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" + [[package]] name = "enum-as-inner" version = "0.3.3" @@ -161,6 +186,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -185,6 +225,7 @@ checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -207,12 +248,35 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +[[package]] +name = "futures-executor" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +[[package]] +name = "futures-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.5" @@ -237,11 +301,14 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project", "pin-utils", + "proc-macro-hack", + "proc-macro-nested", "slab", ] @@ -377,6 +444,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-tls" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d979acc56dcb5b8dddba3917601745e877576475aa046df3226eabdecef78eed" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-tls", +] + [[package]] name = "idna" version = "0.2.0" @@ -589,6 +669,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "native-tls" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" +dependencies = [ + "lazy_static", + "libc", + "log 0.4.11", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "net2" version = "0.2.34" @@ -622,6 +720,39 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" +[[package]] +name = "openssl" +version = "0.10.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" +dependencies = [ + "bitflags 1.2.1", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a842db4709b604f0fe5d1170ae3565899be2ad3d9cbc72dedc789ac0511f78de" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_info" version = "2.0.8" @@ -670,6 +801,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" + [[package]] name = "pnet" version = "0.26.0" @@ -765,6 +902,18 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +[[package]] +name = "proc-macro-hack" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" + +[[package]] +name = "proc-macro-nested" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" + [[package]] name = "proc-macro2" version = "1.0.19" @@ -854,6 +1003,15 @@ version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "resolv-conf" version = "0.6.3" @@ -876,6 +1034,39 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi 0.3.9", +] + +[[package]] +name = "security-framework" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64808902d7d99f78eaddd2b4e2509713babc3dc3c85ad6f4c447680f3c01e535" +dependencies = [ + "bitflags 1.2.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bf11d99252f512695eb468de5516e5cf75455521e69dfe343f3b74e4748405" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.115" @@ -982,6 +1173,20 @@ dependencies = [ "unicode-xid 0.0.3", ] +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.9", +] + [[package]] name = "term" version = "0.4.6" @@ -1082,6 +1287,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a70f4fcd7b3b24fb194f837560168208f669ca8cb70d0c4b862944452396343" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.3.1" @@ -1096,12 +1311,138 @@ dependencies = [ "tokio", ] +[[package]] +name = "tower" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3169017c090b7a28fce80abaad0ab4f5566423677c9331bb320af7e49cfe62" +dependencies = [ + "futures-core", + "tower-buffer", + "tower-discover", + "tower-layer", + "tower-limit", + "tower-load-shed", + "tower-retry", + "tower-service", + "tower-timeout", + "tower-util", +] + +[[package]] +name = "tower-buffer" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4887dc2a65d464c8b9b66e0e4d51c2fd6cf5b3373afc72805b0a60bce00446a" +dependencies = [ + "futures-core", + "pin-project", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-discover" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6b5000c3c54d269cc695dff28136bb33d08cbf1df2c48129e143ab65bf3c2a" +dependencies = [ + "futures-core", + "pin-project", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a35d656f2638b288b33495d1053ea74c40dc05ec0b92084dd71ca5566c4ed1dc" + +[[package]] +name = "tower-limit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c3040c5dbed68abffaa0d4517ac1a454cd741044f33ab0eefab6b8d1361404" +dependencies = [ + "futures-core", + "pin-project", + "tokio", + "tower-layer", + "tower-load", + "tower-service", +] + +[[package]] +name = "tower-load" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc79fc3afd07492b7966d7efa7c6c50f8ed58d768a6075dd7ae6591c5d2017b" +dependencies = [ + "futures-core", + "log 0.4.11", + "pin-project", + "tokio", + "tower-discover", + "tower-service", +] + +[[package]] +name = "tower-load-shed" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f021e23900173dc315feb4b6922510dae3e79c689b74c089112066c11f0ae4e" +dependencies = [ + "futures-core", + "pin-project", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-retry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6727956aaa2f8957d4d9232b308fe8e4e65d99db30f42b225646e86c9b6a952" +dependencies = [ + "futures-core", + "pin-project", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-service" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +[[package]] +name = "tower-timeout" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "127b8924b357be938823eaaec0608c482d40add25609481027b96198b2e4b31e" +dependencies = [ + "pin-project", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1093c19826d33807c72511e68f73b4a0469a3f22c2bd5f7d5212178b4b89674" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "tower-service", +] + [[package]] name = "tracing" version = "0.1.19" @@ -1110,9 +1451,21 @@ checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ "cfg-if", "log 0.4.11", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.15" @@ -1221,6 +1574,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "vcpkg" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" + [[package]] name = "vec_map" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 9acb197..04c2fa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,15 +9,18 @@ edition = "2018" [dependencies] clap = "2.33.0" +futures = "0.3.5" futures-core = { version = "0.3", default-features = false } futures-channel = "0.3" futures-util = { version = "0.3", default-features = false } http = "0.2.1" -hyper = "0.13.7" +hyper = { version = "0.13.7", features = ["stream"] } +hyper-tls = "0.4.3" lru = "0.6.0" os_info = { version = "2.0.8", default-features = false } pnet = "0.26.0" tokio = { version = "0.2.22", features = ["full"] } +tower = "0.3.1" trust-dns-resolver = "0.19.5" [profile.release] diff --git a/src/lib.rs b/src/lib.rs index c0673a1..facca54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,17 +1,29 @@ -use std::net::SocketAddr; +use std::future::Future; +use std::net::{SocketAddr, IpAddr}; use std::process::{Command, Stdio}; use std::sync::Arc; +use std::io::Error; +use std::pin::Pin; +use std::task::{self, Poll}; use hyper::{Body, Response}; +use hyper::client::connect::dns::Name; use lru::LruCache; use os_info::{Info, Type}; +use tower::Service; + +use tokio::runtime::Runtime; use tokio::sync::Mutex; +use tokio::task::{JoinHandle, LocalSet}; use trust_dns_resolver::TokioAsyncResolver; use trust_dns_resolver::config::{NameServerConfig, Protocol, ResolverConfig, ResolverOpts}; +use futures_util::task::FutureObj; +use futures_util::TryFutureExt; +use futures::stream::{Unfold, Once}; pub async fn create_resolver (dns1_sock : SocketAddr, dns2_sock : SocketAddr) -> TokioAsyncResolver { let mut resolver_config : ResolverConfig = ResolverConfig::new(); @@ -104,6 +116,7 @@ pub async fn resolve_with_cache(host : &str, } } + pub fn needs_static_route(ip_string : &String) -> bool { println!("needs_static_route: checking ip={:?}", ip_string); let info : Info = os_info::get(); @@ -176,4 +189,94 @@ pub fn bad_request (message : &str) -> Result, hyper::Error> { let mut resp = Response::new(Body::from(String::from(message))); *resp.status_mut() = http::StatusCode::BAD_REQUEST; return Ok(resp); -} \ No newline at end of file +} + +#[derive(Clone)] +pub struct CacheResolver { + _resolver: Arc, + _cache : Arc>> +} + +impl CacheResolver { + pub fn new(resolver : Arc, cache : Arc>>) -> Self { + CacheResolver { _resolver: resolver, _cache: cache } + } +} + +pub struct IpAddrs { + ip: IpAddr, + addr: SocketAddr, + iter: std::vec::IntoIter, +} + +pub struct CacheAddrs { + inner: IpAddrs, +} + +pub struct CacheFuture { + inner: JoinHandle> +} + +pub async fn resolve_to_result(host : String, + resolver : Arc, + cache: Arc>>) -> Result{ + let ip = resolve_with_cache(host.as_str(), &resolver, cache).await; + let ip_addr: IpAddr = ip.parse().unwrap(); + let sock = SocketAddr::new(ip_addr, 0); + Ok(IpAddrs { ip: ip_addr, addr: sock, iter: vec![sock].into_iter() }) +} + +impl Service for CacheResolver { + type Response = CacheAddrs; + type Error = std::io::Error; + type Future = CacheFuture; + + fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&mut self, name: Name) -> CacheFuture { + println!("+++++++ resolving host={:?}", name.as_str()); + let resolver : Arc = self._resolver.clone(); + let cache: Arc>> = self._cache.clone(); + let addrs = tokio::task::spawn( + resolve_to_result(String::from(name.as_str()), resolver, cache) + // resolve_with_cache(host.as_str(), &resolver, cache) + ); + CacheFuture { inner: addrs } + } +} + +impl Future for CacheFuture { + type Output = Result; + + fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { + Pin::new(&mut self.inner).poll(cx).map(|res| match res { + Ok(Ok(addrs)) => Ok(CacheAddrs { inner: addrs }), + Ok(Err(err)) => Err(err), + Err(join_err) => { + if join_err.is_cancelled() { + Err(std::io::Error::new(std::io::ErrorKind::Interrupted, join_err)) + } else { + panic!("gai background task failed: {:?}", join_err) + } + } + }) + } +} + +impl Iterator for IpAddrs { + type Item = SocketAddr; + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl Iterator for CacheAddrs { + type Item = IpAddr; + + fn next(&mut self) -> Option { + self.inner.next().map(|sa| sa.ip()) + } +} diff --git a/src/main.rs b/src/main.rs index 2649fb7..2309d3e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,11 @@ -#![deny(warnings)] +//#![deny(warnings)] extern crate lru; use std::convert::Infallible; -use std::net::SocketAddr; +use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; +use std::iter; use clap::{Arg, ArgMatches, App}; @@ -13,6 +14,9 @@ use futures_util::future::try_join; use hyper::service::{make_service_fn, service_fn}; use hyper::upgrade::Upgraded; use hyper::{Body, Client, Method, Request, Response, Server}; +use hyper::client::Builder; +use hyper::client::HttpConnector; +use hyper_tls::HttpsConnector; use lru::LruCache; @@ -34,9 +38,6 @@ type HttpClient = Client; // $ curl -i https://www.some_domain.com/ #[tokio::main] async fn main() { - let client = HttpClient::new(); - let gateway = Arc::new(ip_gateway()); - let args : ArgMatches = App::new("bubble-flexrouter") .version("0.1.0") .author("Jonathan Cobb ") @@ -57,13 +58,30 @@ async fn main() { .takes_value(true)) .get_matches(); - let dns1_sock : SocketAddr = format!("{}:53", args.value_of("dns1").unwrap()).parse().unwrap(); - let dns2_sock : SocketAddr = format!("{}:53", args.value_of("dns2").unwrap()).parse().unwrap(); - let resolver = Arc::new(create_resolver(dns1_sock, dns2_sock).await); - let addr = SocketAddr::from(([127, 0, 0, 1], 8100)); + let dns1_ip = args.value_of("dns1").unwrap(); + let dns1_sock : SocketAddr = format!("{}:53", dns1_ip).parse().unwrap(); + let dns2_ip = args.value_of("dns2").unwrap(); + let dns2_sock : SocketAddr = format!("{}:53", dns2_ip).parse().unwrap(); + let async_resolver = create_resolver(dns1_sock, dns2_sock).await; + // let res_ref : &'static TokioAsyncResolver = &async_resolver; + // let async_resolver = create_resolver(dns1_sock, dns2_sock).await; + // let res_ref : &'static TokioAsyncResolver = &async_resolver; + + // let resolver = Arc::new(res_ref); + let resolver = Arc::new(async_resolver); + let addr = SocketAddr::from(([127, 0, 0, 1], 8100)); let resolver_cache = Arc::new(Mutex::new(LruCache::new(1000))); + let http_resolver = CacheResolver::new(resolver.clone(), resolver_cache.clone()); + let connector = HttpConnector::new_with_resolver(http_resolver); + let https = HttpsConnector::new_with_connector(connector); + let client + = Client::builder().build::>, hyper::Body>(https); + //let client = HttpClient::new(); + let gateway = Arc::new(ip_gateway()); + + let make_service = make_service_fn(move |_| { let client = client.clone(); let gateway = gateway.clone(); @@ -90,7 +108,7 @@ async fn main() { } } -async fn proxy(client: HttpClient, +async fn proxy(client: Client>>, gateway: Arc, resolver: Arc, resolver_cache: Arc>>, @@ -123,10 +141,11 @@ async fn proxy(client: HttpClient, // Note: only after client received an empty body with STATUS_OK can the // connection be upgraded, so we can't return a response inside // `on_upgrade` future. - if let Some(addr) = host_addr(req.uri()) { + if let Some(addr) = host_addr(req.uri(), &ip_string) { tokio::task::spawn(async move { match req.into_body().on_upgrade().await { Ok(upgraded) => { + println!(">>>> CONNECT: tunnelling to addr={:?}", addr); if let Err(e) = tunnel(upgraded, addr).await { eprintln!("server io error: {}", e); }; @@ -137,19 +156,17 @@ async fn proxy(client: HttpClient, Ok(Response::new(Body::empty())) } else { - eprintln!("CONNECT host is not socket addr: {:?}", req.uri()); - let mut resp = Response::new(Body::from("CONNECT must be to a socket address")); - *resp.status_mut() = http::StatusCode::BAD_REQUEST; - - Ok(resp) + eprintln!(">>> CONNECT host is not socket addr: {:?}", req.uri()); + return bad_request("CONNECT must be to a socket address"); } } else { + // ensure client resolves hostname to the same IP we resolved client.request(req).await } } -fn host_addr(uri: &http::Uri) -> Option { - uri.authority().and_then(|auth| auth.as_str().parse().ok()) +fn host_addr(uri: &http::Uri, ip: &String) -> Option { + Some(SocketAddr::new(ip.parse().unwrap(), u16::from(uri.port().unwrap()))) } // Create a TCP connection to host:port, build a tunnel between the connection and