From 98ee91d1747e6b0dfe335d80c381177cba4fa704 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=A3rebe=20-=20Romain=20GERARD?= Date: Fri, 27 Oct 2023 21:02:12 +0200 Subject: [PATCH] chore(tcp): Add tests tcp proxy --- Cargo.lock | 197 ++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 4 + src/socks5.rs | 36 ++++---- src/tcp.rs | 83 +++++++++++++++++- src/tunnel/io.rs | 2 - src/tunnel/server.rs | 2 +- 6 files changed, 290 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8af8168..a9cde38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,7 +100,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -164,6 +164,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bollard-stubs" +version = "1.42.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed59b5c00048f48d7af971b71f800fdf23e858844a6f9e4d32ca72e9399e7864" +dependencies = [ + "serde", + "serde_with", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -222,7 +232,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -272,6 +282,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "deranged" version = "0.3.9" @@ -289,6 +334,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -336,6 +382,21 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -343,6 +404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -351,6 +413,23 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + [[package]] name = "futures-macro" version = "0.3.28" @@ -359,9 +438,15 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + [[package]] name = "futures-task" version = "0.3.28" @@ -376,8 +461,11 @@ checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", "slab", @@ -422,6 +510,21 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.9" @@ -479,6 +582,12 @@ dependencies = [ "want", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -681,7 +790,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -958,7 +1067,7 @@ checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -972,6 +1081,28 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "sha1" version = "0.10.6" @@ -983,6 +1114,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1060,6 +1202,23 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.38" @@ -1071,6 +1230,23 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "testcontainers" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d2931d7f521af5bae989f716c3fa43a6af9af7ec7a5e21b59ae40878cec00" +dependencies = [ + "bollard-stubs", + "futures", + "hex", + "hmac", + "log", + "rand", + "serde", + "serde_json", + "sha2", +] + [[package]] name = "thiserror" version = "1.0.50" @@ -1088,7 +1264,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -1184,7 +1360,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -1234,7 +1410,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", ] [[package]] @@ -1404,7 +1580,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -1426,7 +1602,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1559,6 +1735,7 @@ dependencies = [ "rustls-pemfile", "scopeguard", "serde", + "testcontainers", "tokio", "tokio-fd", "tokio-rustls", diff --git a/Cargo.toml b/Cargo.toml index 414d2ed..effe2eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,10 @@ async-trait = "0.1.74" tokio-fd = "0.3.0" +[dev-dependencies] +testcontainers = "0.15.0" + + [profile.release] lto = "fat" panic = "abort" diff --git a/src/socks5.rs b/src/socks5.rs index 04002e6..77ea70e 100644 --- a/src/socks5.rs +++ b/src/socks5.rs @@ -122,21 +122,21 @@ pub fn new_reply(error: &ReplyError, sock_addr: SocketAddr) -> Vec { reply } -#[cfg(test)] -mod test { - use super::*; - use futures_util::StreamExt; - use std::str::FromStr; - - #[tokio::test] - async fn socks5_server() { - let mut x = run_server(SocketAddr::from_str("[::]:4343").unwrap()) - .await - .unwrap(); - - loop { - let cnx = x.next().await.unwrap().unwrap(); - eprintln!("{:?}", cnx); - } - } -} +//#[cfg(test)] +//mod test { +// use super::*; +// use futures_util::StreamExt; +// use std::str::FromStr; +// +// #[tokio::test] +// async fn socks5_server() { +// let mut x = run_server(SocketAddr::from_str("[::]:4343").unwrap()) +// .await +// .unwrap(); +// +// loop { +// let cnx = x.next().await.unwrap().unwrap(); +// eprintln!("{:?}", cnx); +// } +// } +//} diff --git a/src/tcp.rs b/src/tcp.rs index b091935..b2aa675 100644 --- a/src/tcp.rs +++ b/src/tcp.rs @@ -159,10 +159,11 @@ pub async fn connect_with_http_proxy( } } - static OK_RESPONSE: &[u8; 12] = b"HTTP/1.0 200"; + static OK_RESPONSE_10: &[u8] = b"HTTP/1.0 200 "; + static OK_RESPONSE_11: &[u8] = b"HTTP/1.1 200 "; if !buf - .windows(OK_RESPONSE.len()) - .any(|window| window == OK_RESPONSE) + .windows(OK_RESPONSE_10.len()) + .any(|window| window == OK_RESPONSE_10 || window == OK_RESPONSE_11) { return Err(anyhow!( "Cannot connect to http proxy. Proxy returned an invalid response: {}", @@ -182,3 +183,79 @@ pub async fn run_server(bind: SocketAddr) -> Result Box> { + Box::new(vec!["mitmdump".to_string()].into_iter()) + } + } + + impl Image for MitmProxy { + type Args = Self; + + fn name(&self) -> String { + "mitmproxy/mitmproxy".to_string() + } + + fn tag(&self) -> String { + "10.1.1".to_string() + } + + fn ready_conditions(&self) -> Vec { + vec![WaitFor::Duration { + length: Duration::from_secs(5), + }] + } + } + + #[tokio::test] + async fn test_proxy_connection() { + let server_addr: SocketAddr = "[::1]:1236".parse().unwrap(); + let server = TcpListener::bind(server_addr).await.unwrap(); + + let docker = testcontainers::clients::Cli::default(); + let mitm_proxy: RunnableImage = + RunnableImage::from(MitmProxy {}).with_network("host".to_string()); + let _node = docker.run(mitm_proxy); + + let mut client = connect_with_http_proxy( + &"http://localhost:8080".parse().unwrap(), + &Host::Domain("[::1]".to_string()), + 1236, + &None, + Duration::from_secs(1), + ) + .await + .unwrap(); + + client + .write_all(b"GET / HTTP/1.1\r\n\r\n".as_slice()) + .await + .unwrap(); + let client_srv = server.accept().await.unwrap().0; + pin_mut!(client_srv); + + let mut buf = [0u8; 25]; + let ret = client_srv.read(&mut buf).await; + assert!(matches!(ret, Ok(18))); + client_srv + .write_all("HTTP/1.1 200 OK\r\n\r\n".as_bytes()) + .await + .unwrap(); + + client_srv.get_mut().shutdown().await.unwrap(); + let _ = client.read(&mut buf).await.unwrap(); + assert!(buf.starts_with(b"HTTP/1.1 200 OK\r\n\r\n")); + } +} diff --git a/src/tunnel/io.rs b/src/tunnel/io.rs index 7397c87..9612dfc 100644 --- a/src/tunnel/io.rs +++ b/src/tunnel/io.rs @@ -1,9 +1,7 @@ - use fastwebsockets::{Frame, OpCode, Payload, WebSocketError, WebSocketRead, WebSocketWrite}; use futures_util::pin_mut; use hyper::upgrade::Upgraded; - use std::time::Duration; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadHalf, WriteHalf}; use tokio::select; diff --git a/src/tunnel/server.rs b/src/tunnel/server.rs index 27cbc90..5324d29 100644 --- a/src/tunnel/server.rs +++ b/src/tunnel/server.rs @@ -252,7 +252,7 @@ pub async fn run_server(server_config: Arc) -> anyhow::Result<() let fut = async move { if let Err(e) = conn_fut.await { - error!("Error while upgrading cnx to weboscket: {:?}", e); + error!("Error while upgrading cnx to websocket: {:?}", e); } } .instrument(span);