diff --git a/README.md b/README.md index 9783c5f..f70d83f 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,16 @@ Proxy wireguard UDP packets over TCP/TLS -`wireguard-proxyd` is a server-side daemon to accept TCP connections from multiple clients and pipe data to and from the specified UDP port -`wireguard-proxy` is a client-side daemon that accepts UDP packets on a local port from a single client, connects to a single remote TCP port, and pipes data between them +`wireguard-proxy` has 2 modes: +- server-side daemon to accept TCP connections from multiple clients and pipe data to and from the specified UDP port +- client-side daemon that accepts UDP packets on a local port from a single client, connects to a single remote TCP port, and pipes data between them Testing: -`udp-test` is a utility to send a UDP packet and then receive a UDP packet and ensure they are the same, this verifies packets sent through proxy/proxyd are unmolested -`udp-test -s` runs udp-test against itself through proxyd/proxy by spawning actual binaries -`udp-test -is` runs udp-test against itself through proxyd/proxy in same executable by using library, so does not test command line parsing etc -`test.sh` runs udp-test against itself, then the udp-test self tests above, and then through proxyd/proxy in the shell script +- `udp-test` is a utility to send a UDP packet and then receive a UDP packet and ensure they are the same, this verifies packets sent through proxy server/client are unmolested +- `udp-test -s` runs udp-test against itself through proxy server/client by spawning actual binaries +- `udp-test -is` runs udp-test against itself through proxy server/client in same executable by using library, so does not test command line parsing etc +- `test.sh` runs udp-test against itself, the udp-test self tests above, and through proxy server/client in the shell script Testing with GNU netcat: diff --git a/appveyor.yml b/appveyor.yml index 59b3163..cef5a0d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -53,7 +53,6 @@ test_script: before_deploy: # TODO Update this to build the artifacts that matter to you - cargo rustc --target %TARGET% --release --bin wireguard-proxy -- -C lto - - cargo rustc --target %TARGET% --release --bin wireguard-proxyd -- -C lto - ps: ci\before_deploy.ps1 deploy: diff --git a/ci/before_deploy.ps1 b/ci/before_deploy.ps1 index 6494492..cb397a2 100644 --- a/ci/before_deploy.ps1 +++ b/ci/before_deploy.ps1 @@ -11,7 +11,6 @@ Set-Location $STAGE $ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip" # TODO Update this to package the right artifacts -Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\wireguard-proxyd.exe" '.\' Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\wireguard-proxy.exe" '.\' 7z a "$ZIP" * diff --git a/ci/before_deploy.sh b/ci/before_deploy.sh index 4eec4cf..a922a80 100644 --- a/ci/before_deploy.sh +++ b/ci/before_deploy.sh @@ -19,17 +19,16 @@ main() { # TODO Update this to build the artifacts that matter to you cross rustc --bin wireguard-proxy --target $TARGET --release -- -C lto - cross rustc --bin wireguard-proxyd --target $TARGET --release -- -C lto # TODO Update this to package the right artifacts, this needs to handle .exe too... case $TARGET in x86_64-pc-windows-gnu) - strip target/$TARGET/release/wireguard-proxy.exe target/$TARGET/release/wireguard-proxyd.exe || echo 'strip failed, ignoring...' - cp target/$TARGET/release/wireguard-proxy.exe target/$TARGET/release/wireguard-proxyd.exe $stage/ + strip target/$TARGET/release/wireguard-proxy.exe || echo 'strip failed, ignoring...' + cp target/$TARGET/release/wireguard-proxy.exe $stage/ ;; *) - strip target/$TARGET/release/wireguard-proxy target/$TARGET/release/wireguard-proxyd || echo 'strip failed, ignoring...' - cp target/$TARGET/release/wireguard-proxy target/$TARGET/release/wireguard-proxyd $stage/ + strip target/$TARGET/release/wireguard-proxy || echo 'strip failed, ignoring...' + cp target/$TARGET/release/wireguard-proxy $stage/ ;; esac diff --git a/src/bin/udp-test.rs b/src/bin/udp-test.rs index 858b19e..721422b 100644 --- a/src/bin/udp-test.rs +++ b/src/bin/udp-test.rs @@ -70,41 +70,53 @@ impl Server { fn main() { let raw_args = env::args().collect(); let args = Args::new(&raw_args); - let mut first_arg = args.get_str(1, "127.0.0.1:51820"); - if first_arg.contains("-h") { - println!( - "usage: {} [-h] [-s run a self test through proxy/proxyd] [-is run a self test through proxy/proxyd without spawning other processes] [udp_host, 127.0.0.1:51820] [udp_target, 127.0.0.1:51820] [socket_timeout, 10]", - args.get_str(0, "udp-test") - ); + let default_udp_host_target = "127.0.0.1:51820"; + let default_socket_timeout = 10; + let mut first_arg = args.get_str(&["-uh", "--udp-host"], default_udp_host_target); + if args.flag("-h") || args.flag("--help"){ + println!(r#"usage: udp-test [options...] + -h, --help print this usage text + -s, --self-test run a self test through proxy + -is, --internal-self-test run a self test through proxy without + spawning other processes + -uh, --udp-host UDP host to listen on, default: {} + -ut, --udp-target UDP target to send packets to, default: {} + -st, --socket-timeout Socket timeout (time to wait for data) + before terminating, default: {} + "#, default_udp_host_target, default_udp_host_target, default_socket_timeout); return; - } else if first_arg.contains("-s") { + } else if args.flag("-s") || args.flag("--self-test") { // here is the hard work, we need to spawn proxyd and proxy from the same dir as udp-test... let host = "127.0.0.1:51822"; let tcp_host = "127.0.0.1:5555"; let sleep = Duration::from_secs(5); - let udp_test = args.get_str(0, "udp-test"); - let proxyd = udp_test.clone().replace("udp-test", "wireguard-proxyd"); + let udp_test = args.get_str_idx(0, "udp-test"); let proxy = udp_test.clone().replace("udp-test", "wireguard-proxy"); - println!("executing: {} '{}' '{}'", proxyd, tcp_host, host); - let mut proxyd = Command::new(proxyd) + println!("executing: {} -th '{}' -ut '{}'", proxy, tcp_host, host); + let mut proxyd = Command::new(proxy.clone()) + .arg("-th") .arg(tcp_host) + .arg("-ut") .arg(host) .spawn() - .expect("wireguard-proxyd failed to launch"); - println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep); + .expect("wireguard-proxy server failed to launch"); + println!("waiting: {:?} for wireguard-proxy server to come up.....", sleep); thread::sleep(sleep); - println!("executing: {}", proxy); + println!("executing: {} -tt {}", proxy, tcp_host); let mut proxy = Command::new(proxy) + .arg("-tt") + .arg(tcp_host) .spawn() - .expect("wireguard-proxy failed to launch"); - println!("waiting: {:?} for wireguard-proxy to come up.....", sleep); + .expect("wireguard-proxy client failed to launch"); + println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep); thread::sleep(sleep); - println!("executing: {} '{}'", udp_test, host); + println!("executing: {} -uh '{}'", udp_test, host); let mut udp_test = Command::new(udp_test) + .arg("-uh") .arg(host) .spawn() .expect("udp-test failed to launch"); @@ -123,7 +135,7 @@ fn main() { .code() .expect("could not get udp-test exit code"), ); - } else if first_arg.contains("-is") { + } else if args.flag("-is") || args.flag("--internal-self-test") { let host = "127.0.0.1:51822"; let tcp_host = "127.0.0.1:5555"; let sleep = Duration::from_secs(5); @@ -142,9 +154,9 @@ fn main() { proxy_server.client_handler.udp_target, proxy_server.client_handler.socket_timeout, ); - println!("executing: wireguard-proxyd '{}' '{}'", tcp_host, host); + println!("executing: wireguard-proxy -th '{}' -ut '{}'", tcp_host, host); thread::spawn(move || proxy_server.start().expect("error running proxy_server")); - println!("waiting: {:?} for wireguard-proxyd to come up.....", sleep); + println!("waiting: {:?} for wireguard-proxy server to come up.....", sleep); thread::sleep(sleep); let proxy_client = ProxyClient::new( @@ -160,9 +172,9 @@ fn main() { proxy_client.socket_timeout, ); - println!("executing: wireguard-proxy"); + println!("executing: wireguard-proxy -tt {}", tcp_host); thread::spawn(move || proxy_client.start().expect("error running proxy_client")); - println!("waiting: {:?} for wireguard-proxy to come up.....", sleep); + println!("waiting: {:?} for wireguard-proxy client to come up.....", sleep); thread::sleep(sleep); first_arg = host; @@ -170,8 +182,8 @@ fn main() { let server = Server::new( first_arg.to_owned(), - args.get_str(2, "127.0.0.1:51820").to_owned(), - args.get(3, 10), + args.get_str(&["-ut", "--udp-target"], default_udp_host_target).to_owned(), + args.get(&["-st", "--socket-timeout"], default_socket_timeout), ); println!( diff --git a/src/bin/wireguard-proxy.rs b/src/bin/wireguard-proxy.rs index cfa10d8..be6ee97 100644 --- a/src/bin/wireguard-proxy.rs +++ b/src/bin/wireguard-proxy.rs @@ -1,21 +1,62 @@ use std::env; -use wireguard_proxy::{Args, ProxyClient}; +use wireguard_proxy::{Args, ProxyClient, ProxyServer}; fn main() { let raw_args = env::args().collect(); let args = Args::new(&raw_args); - if args.get_str(1, "").contains("-h") { - println!( - "usage: {} [-h] [udp_host, 127.0.0.1:51820] [tcp_target, 127.0.0.1:5555] [socket_timeout, 0]", - args.get_str(0, "wireguard-proxy") - ); + + let default_udp_host_target = "127.0.0.1:51820"; + let default_socket_timeout = 0; + + let tcp_target = args.get_option(&["-tt", "--tcp-target"]); + let tcp_host = args.get_option(&["-th", "--tcp-host"]); + + if args.flag("-h") || args.flag("--help") || + // one of them must be set + (tcp_target.is_none() && tcp_host.is_none()) || + // but both cannot be set + (tcp_target.is_some() && tcp_host.is_some()) + { + println!(r#"usage: wireguard-proxy [options...] + Client Mode (requires --tcp-target): + -tt, --tcp-target TCP target to send packets to, where + wireguard-proxy server is running + -uh, --udp-host UDP host to listen on, point wireguard + client here, default: {} + + Server Mode (requires --tcp-host): + -th, --tcp-host TCP host to listen on + -ut, --udp-target UDP target to send packets to, where + wireguard server is running, + default: {} + -ur, --udp-bind-host-range UDP host and port range to bind to, + one port per TCP connection, to + listen on for UDP packets to send + back over the TCP connection, + default: 127.0.0.1:30000-40000 + + Common Options: + -h, --help print this usage text + -st, --socket-timeout Socket timeout (time to wait for data) + before terminating, default: {} + "#, default_udp_host_target, default_udp_host_target, default_socket_timeout); return; } + let socket_timeout = args.get(&["-st", "--socket-timeout"], default_socket_timeout); + + if tcp_target.is_some() { + client(tcp_target.unwrap(), socket_timeout, args); + } else { + server(tcp_host.unwrap(), socket_timeout, args); + } +} + +fn client(tcp_target: &str, socket_timeout: u64, args: Args) { let proxy_client = ProxyClient::new( - args.get_str(1, "127.0.0.1:51820").to_owned(), - args.get_str(2, "127.0.0.1:5555").to_owned(), - args.get(3, 0), + args.get_str(&["-uh", "--udp-host"], "127.0.0.1:51820").to_owned(), + tcp_target.to_owned(), + socket_timeout, ); println!( @@ -27,3 +68,45 @@ fn main() { proxy_client.start().expect("error running proxy_client"); } + +fn server(tcp_host: &str, socket_timeout: u64, args: Args) { + let udp_bind_host_range_str = args.get_str(&["-ur", "--udp-bind-host-range"], "127.0.0.1:30000-40000"); + let mut udp_bind_host_range = udp_bind_host_range_str.split(":"); + let udp_host = udp_bind_host_range + .next() + .expect("udp_bind_host_range host invalid"); + let mut udp_ports = udp_bind_host_range + .next() + .expect("udp_bind_host_range port range invalid") + .split("-"); + let udp_low_port = udp_ports + .next() + .expect("udp_bind_host_range low port invalid") + .trim() + .parse::() + .expect("udp_bind_host_range low port invalid"); + let udp_high_port = udp_ports + .next() + .expect("udp_bind_host_range low port invalid") + .trim() + .parse::() + .expect("udp_bind_host_range low port invalid"); + + let proxy_server = ProxyServer::new( + tcp_host.to_owned(), + args.get_str(&["-ut", "--udp-target"], "127.0.0.1:51820").to_owned(), + udp_host.to_string(), + udp_low_port, + udp_high_port, + socket_timeout, + ); + + println!( + "udp_target: {}, udp_bind_host_range: {}, socket_timeout: {:?}", + proxy_server.client_handler.udp_target, + udp_bind_host_range_str, + proxy_server.client_handler.socket_timeout, + ); + + proxy_server.start().expect("error running proxy_server"); +} diff --git a/src/bin/wireguard-proxyd.rs b/src/bin/wireguard-proxyd.rs deleted file mode 100644 index 300a9f7..0000000 --- a/src/bin/wireguard-proxyd.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::env; -use wireguard_proxy::{Args, ProxyServer}; - -fn main() { - let raw_args = env::args().collect(); - let args = Args::new(&raw_args); - if args.get_str(1, "").contains("-h") { - println!( - "usage: {} [-h] [tcp_host, 127.0.0.1:5555] [udp_target, 127.0.0.1:51820] [udp_bind_host_range, 127.0.0.1:30000-40000] [socket_timeout, 0]", - args.get_str(0, "wireguard-proxyd") - ); - return; - } - - let udp_bind_host_range_str = args.get_str(3, "127.0.0.1:30000-40000"); - let mut udp_bind_host_range = udp_bind_host_range_str.split(":"); - let udp_host = udp_bind_host_range - .next() - .expect("udp_bind_host_range host invalid"); - let mut udp_ports = udp_bind_host_range - .next() - .expect("udp_bind_host_range port range invalid") - .split("-"); - let udp_low_port = udp_ports - .next() - .expect("udp_bind_host_range low port invalid") - .trim() - .parse::() - .expect("udp_bind_host_range low port invalid"); - let udp_high_port = udp_ports - .next() - .expect("udp_bind_host_range low port invalid") - .trim() - .parse::() - .expect("udp_bind_host_range low port invalid"); - - let proxy_server = ProxyServer::new( - args.get_str(1, "127.0.0.1:5555").to_owned(), - args.get_str(2, "127.0.0.1:51820").to_owned(), - udp_host.to_string(), - udp_low_port, - udp_high_port, - args.get(4, 0), - ); - - println!( - "udp_target: {}, udp_bind_host_range: {}, socket_timeout: {:?}", - proxy_server.client_handler.udp_target, - udp_bind_host_range_str, - proxy_server.client_handler.socket_timeout, - ); - - proxy_server.start().expect("error running proxy_server"); -} diff --git a/src/lib.rs b/src/lib.rs index bffa188..66dc089 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,14 +13,31 @@ impl<'a> Args<'a> { pub fn new(args: &'a Vec) -> Args { Args { args } } - pub fn get_str(&self, index: usize, def: &'a str) -> &'a str { - match self.args.get(index) { + pub fn flag(&self, flag: &'a str) -> bool { + self.args.contains(&flag.to_owned()) + } + pub fn get_option(&self, flags: &[&'a str]) -> Option<&'a str> { + for flag in flags.iter() { + let mut found = false; + for arg in self.args.iter() { + if found { + return Some(arg); + } + if arg == flag { + found = true; + } + } + } + return None; + } + pub fn get_str(&self, flags: &[&'a str], def: &'a str) -> &'a str { + match self.get_option(flags) { Some(ret) => ret, None => def, } } - pub fn get(&self, index: usize, def: T) -> T { - match self.args.get(index) { + pub fn get(&self, flags: &[&'a str], def: T) -> T { + match self.get_option(flags) { Some(ret) => match ret.parse::() { Ok(ret) => ret, Err(_) => def, // or panic @@ -28,6 +45,12 @@ impl<'a> Args<'a> { None => def, } } + pub fn get_str_idx(&self, index: usize, def: &'a str) -> &'a str { + match self.args.get(index) { + Some(ret) => ret, + None => def, + } + } } pub struct TcpUdpPipe { diff --git a/test.sh b/test.sh index a4331cd..8c7e59e 100755 --- a/test.sh +++ b/test.sh @@ -1,29 +1,32 @@ #!/bin/sh set -x +# always run this clean +cargo clean + # first make sure udp-test succeeds running against itself cargo run --release --bin udp-test || exit 1 # now run udp-test without spawning other processes cargo run --release --bin udp-test -- -is || exit 1 -# now run udp-test essentially just like the script below, but all in rust -cargo run --release --bin udp-test -- -s || exit 1 - # now run proxyd pointing to udp-test -cargo run --release --bin wireguard-proxyd -- 127.0.0.1:5555 127.0.0.1:51822 & +cargo run --release --bin wireguard-proxy -- -th 127.0.0.1:5555 -ut 127.0.0.1:51822 & proxyd_pid=$! # wait for ports to be set up, this is fragile... sleep 1 # proxy pointing to proxyd -cargo run --release --bin wireguard-proxy & +cargo run --release --bin wireguard-proxy -- -tt 127.0.0.1:5555 & proxy_pid=$! # wait for ports to be set up, this is fragile... sleep 1 # and udp-test pointing to proxy, which then hops to proxyd, and finally back to udp-test -cargo run --release --bin udp-test -- 127.0.0.1:51822 +cargo run --release --bin udp-test -- -uh 127.0.0.1:51822 udp_exit=$? kill $proxyd_pid $proxy_pid -exit $udp_exit +[ $udp_exit -ne 0 ] && exit $udp_exit + +# now run udp-test essentially just like the script above, but all in rust +cargo run --release --bin udp-test -- -s