First (unsafe) go at tls support

This commit is contained in:
Travis Burtrum 2019-12-16 02:21:16 -05:00
parent 5280c038b7
commit 4c6f4258b4
7 changed files with 238 additions and 35 deletions

View File

@ -130,4 +130,5 @@ branches:
- master
- travis
- ci
- openssl

94
Cargo.lock generated
View File

@ -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"

View File

@ -18,3 +18,10 @@ include = [
"LICENSE-*",
"*.md",
]
[features]
default = ["tls"]
tls = ["openssl"]
[dependencies]
openssl = { version = "0.10.26", optional = true }

View File

@ -84,6 +84,7 @@ branches:
- master
- appveyor
- ci
- openssl
notifications:
- provider: Email

View File

@ -23,6 +23,8 @@ fn main() {
wireguard-proxy server is running
-uh, --udp-host <ip:port> 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 <ip:port> 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) {

View File

@ -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<String>,
@ -53,14 +55,14 @@ impl<'a> Args<'a> {
}
}
pub struct TcpUdpPipe {
pub struct TcpUdpPipe<T: Write + Read + TryClone<T> + 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<T: Write + Read + TryClone<T> + Send + 'static> TcpUdpPipe<T> {
pub fn new(tcp_stream: T, udp_socket: UdpSocket) -> TcpUdpPipe<T> {
TcpUdpPipe {
tcp_stream,
udp_socket,
@ -68,28 +70,30 @@ impl TcpUdpPipe {
}
}
pub fn try_clone(&self) -> std::io::Result<TcpUdpPipe> {
pub fn try_clone(&self) -> std::io::Result<TcpUdpPipe<T>> {
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<usize> {
pub fn shuffle_after_first_udp(&mut self) -> std::io::Result<usize> {
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<usize> {
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<usize> {
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<usize> {
@ -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<usize> {
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<usize> {
fn tcp_connect(&self) -> std::io::Result<TcpStream> {
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<UdpSocket> {
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<usize> {
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<usize> {
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<T> {
fn try_clone(&self) -> std::io::Result<T>;
}
impl TryClone<UdpSocket> for UdpSocket {
fn try_clone(&self) -> std::io::Result<UdpSocket> {
self.try_clone()
}
}
impl TryClone<TcpStream> for TcpStream {
fn try_clone(&self) -> std::io::Result<TcpStream> {
self.try_clone()
}
}
impl TryClone<OpensslCell> for OpensslCell {
fn try_clone(&self) -> std::io::Result<OpensslCell> {
Ok(self.clone())
}
}
pub struct OpensslCell {
sess: Arc<UnsafeCell<SslStream<TcpStream>>>,
}
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<TcpStream> {
unsafe {
&*self.sess.get()
}
}
pub fn borrow_mut(&self) -> &mut SslStream<TcpStream> {
unsafe {
&mut *self.sess.get()
}
}
}
impl Read for OpensslCell {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
self.borrow_mut().read(buf)
}
}
impl Write for OpensslCell {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
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<ProxyServerClientHandler>,
@ -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()
}
}

10
test.sh
View File

@ -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