use std::env; use wireguard_proxy::{Args, ProxyClient, ProxyServer}; fn main() { let raw_args = env::args().collect(); let args = Args::new(&raw_args); if args.flag("-V") || args.flag("--version") { print!("wireguard-proxy {} ", env!("CARGO_PKG_VERSION")); #[cfg(not(any(feature = "tls", feature = "openssl_vendored", feature = "async")))] println!("TLS support: None"); #[cfg(feature = "async")] println!("TLS support: tokio-rustls"); #[cfg(all(feature = "openssl_vendored", not(feature = "async")))] println!("TLS support: Static/Vendored OpenSSL"); #[cfg(all(feature = "tls", not(feature = "openssl_vendored"), not(feature = "async")))] println!("TLS support: System OpenSSL"); return; } 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: {} --tls use TLS when connecting to tcp-target WARNING: authenticates/verifies nothing without --pinnedpubkey below!! --pinnedpubkey Public key to verify peer against, format is any number of base64 encoded sha256 hashes preceded by "sha256//" and separated by ";". Identical to curl's --pinnedpubkey and CURLOPT_PINNEDPUBLICKEY --tls-hostname send this in SNI instead of host from --tcp-target, useful for avoiding DNS lookup on connect 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 -tk, --tls-key TLS key to listen with, requires --tls-cert also -tc, --tls-cert TLS cert to listen with, requires --tls-key also Note: with both --tls-key and --tls-cert, - means stdin, also the same file can work for both if you combine them into one pem file Common Options: -h, --help print this usage text -V, --version Show version number and TLS support then quit -st, --socket-timeout Socket timeout (time to wait for data) before terminating, default: {} Environment variable support: For every long command line option (starting with --), if you replace the leading -- with WGP_, and replace all remaining - with _, and uppercase the whole thing, if you don't specify that command line option we will read that environment variable for the argument. boolean arguments are true if anything but unset, empty, 0, or false. Examples: --tcp-target ARG is WGP_TCP_TARGET=ARG --socket-timeout 5 is WGP_SOCKET_TIMEOUT=5 --tls is WGP_TLS=1 or WGP_TLS=true WGP_TLS=0 or WGP_TLS=false would be like not sending --tls "#, 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(&["-uh", "--udp-host"], "127.0.0.1:51820").to_owned(), tcp_target.to_owned(), socket_timeout, ); let tls = args.flag("--tls"); println!( "udp_host: {}, tcp_target: {}, socket_timeout: {:?}, tls: {}", proxy_client.udp_host, proxy_client.tcp_target, proxy_client.socket_timeout, tls, ); if tls { let hostname = args.get_option(&["--tls-hostname"]).or_else(|| tcp_target.split(":").next().map(&str::to_owned)); let pinnedpubkey = args.get_option(&["--pinnedpubkey"]); proxy_client.start_tls(hostname.as_ref().map(String::as_str), pinnedpubkey.as_ref().map(String::as_str)).expect("error running tls proxy_client"); } else { 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, ); let tls_key = args.get_option(&["-tk", "--tls-key"]); let tls_cert = args.get_option(&["-tc", "--tls-cert"]); println!( "udp_target: {}, udp_bind_host_range: {}, socket_timeout: {:?}, tls_key: {:?}, tls_cert: {:?}", proxy_server.client_handler.udp_target, udp_bind_host_range_str, proxy_server.client_handler.socket_timeout, tls_key, tls_cert, ); if tls_key.is_some() && tls_cert.is_some() { proxy_server.start_tls(&tls_key.unwrap(), &tls_cert.unwrap()).expect("error running TLS proxy_server"); } else if tls_key.is_none() && tls_cert.is_none() { proxy_server.start().expect("error running proxy_server"); } else { println!("Error: if one of --tls-key or --tls-cert is specified both must be!"); } }