diff --git a/.travis.yml b/.travis.yml index fae5db7..2b1ce66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -130,4 +130,5 @@ branches: - master - travis - ci + - openssl diff --git a/Cargo.lock b/Cargo.lock index 80a6262..7677bb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,100 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cc" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "openssl" +version = "0.10.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "openssl-sys" +version = "0.9.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wireguard-proxy" version = "0.1.0" +dependencies = [ + "openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)", +] +[metadata] +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585" +"checksum openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)" = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" diff --git a/Cargo.toml b/Cargo.toml index d4489cb..570b872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,10 @@ include = [ "LICENSE-*", "*.md", ] + +[features] +default = ["tls"] +tls = ["openssl"] + +[dependencies] +openssl = { version = "0.10.26", optional = true } diff --git a/appveyor.yml b/appveyor.yml index cef5a0d..e934357 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -84,6 +84,7 @@ branches: - master - appveyor - ci + - openssl notifications: - provider: Email diff --git a/src/bin/wireguard-proxy.rs b/src/bin/wireguard-proxy.rs index be6ee97..d070124 100644 --- a/src/bin/wireguard-proxy.rs +++ b/src/bin/wireguard-proxy.rs @@ -23,6 +23,8 @@ fn main() { 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: currently verifies nothing! Server Mode (requires --tcp-host): -th, --tcp-host TCP host to listen on @@ -66,7 +68,11 @@ fn client(tcp_target: &str, socket_timeout: u64, args: Args) { proxy_client.socket_timeout, ); - proxy_client.start().expect("error running proxy_client"); + if args.flag("--tls") { + proxy_client.start_tls().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) { diff --git a/src/lib.rs b/src/lib.rs index 66dc089..c6ebef7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ use std::str::FromStr; use std::sync::Arc; use std::thread; use std::time::Duration; +use std::cell::{UnsafeCell}; +use openssl::ssl::{SslConnector, SslMethod, SslStream, SslVerifyMode}; pub struct Args<'a> { args: &'a Vec, @@ -53,14 +55,14 @@ impl<'a> Args<'a> { } } -pub struct TcpUdpPipe { +pub struct TcpUdpPipe + Send + 'static> { buf: [u8; 2050], // 2048 + 2 for len - tcp_stream: TcpStream, + tcp_stream: T, udp_socket: UdpSocket, } -impl TcpUdpPipe { - pub fn new(tcp_stream: TcpStream, udp_socket: UdpSocket) -> TcpUdpPipe { +impl + Send + 'static> TcpUdpPipe { + pub fn new(tcp_stream: T, udp_socket: UdpSocket) -> TcpUdpPipe { TcpUdpPipe { tcp_stream, udp_socket, @@ -68,28 +70,30 @@ impl TcpUdpPipe { } } - pub fn try_clone(&self) -> std::io::Result { + pub fn try_clone(&self) -> std::io::Result> { Ok(TcpUdpPipe::new( self.tcp_stream.try_clone()?, self.udp_socket.try_clone()?, )) } - pub fn udp_to_tcp_connect_socket(&mut self) -> std::io::Result { + pub fn shuffle_after_first_udp(&mut self) -> std::io::Result { let (len, src_addr) = self.udp_socket.recv_from(&mut self.buf[2..])?; println!("first packet from {}, connecting to that", src_addr); self.udp_socket.connect(src_addr)?; - self.send_udp(len) + self.send_udp(len)?; + + self.shuffle() } - pub fn udp_to_tcp(&mut self) -> std::io::Result { + pub fn udp_to_tcp(&mut self) -> std::io::Result<()> { let len = self.udp_socket.recv(&mut self.buf[2..])?; self.send_udp(len) } - fn send_udp(&mut self, len: usize) -> std::io::Result { + fn send_udp(&mut self, len: usize) -> std::io::Result<()> { println!("udp got len: {}", len); self.buf[0] = ((len >> 8) & 0xFF) as u8; @@ -98,7 +102,8 @@ impl TcpUdpPipe { //let test_len = ((self.buf[0] as usize) << 8) + self.buf[1] as usize; //println!("tcp sending test_len: {}", test_len); - self.tcp_stream.write(&self.buf[..len + 2]) + self.tcp_stream.write_all(&self.buf[..len + 2]) + // todo: do this? self.tcp_stream.flush() } pub fn tcp_to_udp(&mut self) -> std::io::Result { @@ -112,6 +117,19 @@ impl TcpUdpPipe { //let sent = udp_socket.send_to(&buf[..len], &self.udp_target)?; //assert_eq!(sent, len); } + + pub fn shuffle(&mut self) -> std::io::Result { + let mut udp_pipe_clone = self.try_clone()?; + thread::spawn(move || loop { + udp_pipe_clone + .udp_to_tcp() + .expect("cannot write to tcp_clone"); + }); + + loop { + self.tcp_to_udp()?; + } + } } pub struct ProxyClient { @@ -132,32 +150,110 @@ impl ProxyClient { } } - pub fn start(&self) -> std::io::Result { + fn tcp_connect(&self) -> std::io::Result { let tcp_stream = TcpStream::connect(&self.tcp_target)?; - tcp_stream.set_read_timeout(self.socket_timeout)?; + Ok(tcp_stream) + } + fn udp_connect(&self) -> std::io::Result { let udp_socket = UdpSocket::bind(&self.udp_host)?; udp_socket.set_read_timeout(self.socket_timeout)?; + Ok(udp_socket) + } - let mut udp_pipe = TcpUdpPipe::new(tcp_stream, udp_socket); + pub fn start(&self) -> std::io::Result { + let tcp_stream = self.tcp_connect()?; + + let udp_socket = self.udp_connect()?; // we want to wait for first udp packet from client first, to set the target to respond to - udp_pipe.udp_to_tcp_connect_socket()?; + TcpUdpPipe::new(tcp_stream, udp_socket).shuffle_after_first_udp() + } - let mut udp_pipe_clone = udp_pipe.try_clone()?; - thread::spawn(move || loop { - udp_pipe_clone - .udp_to_tcp() - .expect("cannot write to tcp_clone"); - }); + pub fn start_tls(&self) -> std::io::Result { + let tcp_stream = self.tcp_connect()?; - loop { - udp_pipe.tcp_to_udp()?; + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap().build().configure().unwrap(); + connector.set_verify_hostname(false); + connector.set_verify(SslVerifyMode::NONE); + let tcp_stream = connector.connect(self.tcp_target.split(":").next().unwrap(), tcp_stream).unwrap(); + let tcp_stream = OpensslCell { sess: Arc::new(UnsafeCell::new(tcp_stream)) }; + + let udp_socket = self.udp_connect()?; + + // we want to wait for first udp packet from client first, to set the target to respond to + TcpUdpPipe::new(tcp_stream, udp_socket).shuffle_after_first_udp() + } +} + + +pub trait TryClone { + fn try_clone(&self) -> std::io::Result; +} + +impl TryClone for UdpSocket { + fn try_clone(&self) -> std::io::Result { + self.try_clone() + } +} + +impl TryClone for TcpStream { + fn try_clone(&self) -> std::io::Result { + self.try_clone() + } +} + +impl TryClone for OpensslCell { + fn try_clone(&self) -> std::io::Result { + Ok(self.clone()) + } +} + +pub struct OpensslCell { + sess: Arc>>, +} + +unsafe impl Sync for OpensslCell {} +unsafe impl Send for OpensslCell {} + +impl Clone for OpensslCell { + fn clone(&self) -> Self { + OpensslCell { + sess: self.sess.clone(), } } } +impl OpensslCell { + pub fn borrow(&self) -> &SslStream { + unsafe { + &*self.sess.get() + } + } + pub fn borrow_mut(&self) -> &mut SslStream { + unsafe { + &mut *self.sess.get() + } + } +} + +impl Read for OpensslCell { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.borrow_mut().read(buf) + } +} + +impl Write for OpensslCell { + fn write(&mut self, buf: &[u8]) -> Result { + self.borrow_mut().write(buf) + } + + fn flush(&mut self) -> Result<(), std::io::Error> { + self.borrow_mut().flush() + } +} + pub struct ProxyServer { pub tcp_host: String, pub client_handler: Arc, @@ -238,16 +334,6 @@ impl ProxyServerClientHandler { udp_socket.set_read_timeout(self.socket_timeout)?; udp_socket.connect(&self.udp_target)?; - let mut udp_pipe = TcpUdpPipe::new(tcp_stream, udp_socket); - let mut udp_pipe_clone = udp_pipe.try_clone()?; - thread::spawn(move || loop { - udp_pipe_clone - .udp_to_tcp() - .expect("cannot write to tcp_clone"); - }); - - loop { - udp_pipe.tcp_to_udp()?; - } + TcpUdpPipe::new(tcp_stream, udp_socket).shuffle() } } diff --git a/test.sh b/test.sh index 8c7e59e..d3904c2 100755 --- a/test.sh +++ b/test.sh @@ -16,7 +16,13 @@ proxyd_pid=$! # wait for ports to be set up, this is fragile... sleep 1 # proxy pointing to proxyd -cargo run --release --bin wireguard-proxy -- -tt 127.0.0.1:5555 & +#cargo run --release --bin wireguard-proxy -- -tt 127.0.0.1:5555 & + +echo -e '\n\n\n\n\n\n\n' | openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.key +socat OPENSSL-LISTEN:5554,bind=127.0.0.1,cert=./cert.pem,key=./cert.key,verify=0 tcp4-connect:127.0.0.1:5555 & + +cargo run --release --bin wireguard-proxy -- -tt 127.0.0.1:5554 --tls & + proxy_pid=$! # wait for ports to be set up, this is fragile... sleep 1 @@ -26,6 +32,8 @@ udp_exit=$? kill $proxyd_pid $proxy_pid +rm -f cert.pem cert.key + [ $udp_exit -ne 0 ] && exit $udp_exit # now run udp-test essentially just like the script above, but all in rust