Re-factor code, send packet length header in TCP, add test
This commit is contained in:
parent
b28a68edb1
commit
d80b238666
10
README.md
10
README.md
@ -1,6 +1,14 @@
|
||||
# wireguard-proxy
|
||||
|
||||
Server-side daemon to proxy multiple TCP connections to wireguard, client-side implementation coming here soon
|
||||
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
|
||||
|
||||
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
|
||||
`test.sh` runs udp-test against itself and then through proxyd/proxy
|
||||
|
||||
Testing with GNU netcat:
|
||||
|
||||
|
94
src/bin/udp-test.rs
Normal file
94
src/bin/udp-test.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use std::net::UdpSocket;
|
||||
use std::time::Duration;
|
||||
|
||||
use std::env;
|
||||
use wireguard_proxy::Args;
|
||||
|
||||
const PONG: [u8; 246] = [
|
||||
0x6A, 0x2, 0x6B, 0xC, 0x6C, 0x3F, 0x6D, 0xC, 0xA2, 0xEA, 0xDA, 0xB6, 0xDC, 0xD6, 0x6E, 0x0,
|
||||
0x22, 0xD4, 0x66, 0x3, 0x68, 0x2, 0x60, 0x60, 0xF0, 0x15, 0xF0, 0x7, 0x30, 0x0, 0x12, 0x1A,
|
||||
0xC7, 0x17, 0x77, 0x8, 0x69, 0xFF, 0xA2, 0xF0, 0xD6, 0x71, 0xA2, 0xEA, 0xDA, 0xB6, 0xDC, 0xD6,
|
||||
0x60, 0x1, 0xE0, 0xA1, 0x7B, 0xFE, 0x60, 0x4, 0xE0, 0xA1, 0x7B, 0x2, 0x60, 0x1F, 0x8B, 0x2,
|
||||
0xDA, 0xB6, 0x60, 0xC, 0xE0, 0xA1, 0x7D, 0xFE, 0x60, 0xD, 0xE0, 0xA1, 0x7D, 0x2, 0x60, 0x1F,
|
||||
0x8D, 0x2, 0xDC, 0xD6, 0xA2, 0xF0, 0xD6, 0x71, 0x86, 0x84, 0x87, 0x94, 0x60, 0x3F, 0x86, 0x2,
|
||||
0x61, 0x1F, 0x87, 0x12, 0x46, 0x2, 0x12, 0x78, 0x46, 0x3F, 0x12, 0x82, 0x47, 0x1F, 0x69, 0xFF,
|
||||
0x47, 0x0, 0x69, 0x1, 0xD6, 0x71, 0x12, 0x2A, 0x68, 0x2, 0x63, 0x1, 0x80, 0x70, 0x80, 0xB5,
|
||||
0x12, 0x8A, 0x68, 0xFE, 0x63, 0xA, 0x80, 0x70, 0x80, 0xD5, 0x3F, 0x1, 0x12, 0xA2, 0x61, 0x2,
|
||||
0x80, 0x15, 0x3F, 0x1, 0x12, 0xBA, 0x80, 0x15, 0x3F, 0x1, 0x12, 0xC8, 0x80, 0x15, 0x3F, 0x1,
|
||||
0x12, 0xC2, 0x60, 0x20, 0xF0, 0x18, 0x22, 0xD4, 0x8E, 0x34, 0x22, 0xD4, 0x66, 0x3E, 0x33, 0x1,
|
||||
0x66, 0x3, 0x68, 0xFE, 0x33, 0x1, 0x68, 0x2, 0x12, 0x16, 0x79, 0xFF, 0x49, 0xFE, 0x69, 0xFF,
|
||||
0x12, 0xC8, 0x79, 0x1, 0x49, 0x2, 0x69, 0x1, 0x60, 0x4, 0xF0, 0x18, 0x76, 0x1, 0x46, 0x40,
|
||||
0x76, 0xFE, 0x12, 0x6C, 0xA2, 0xF2, 0xFE, 0x33, 0xF2, 0x65, 0xF1, 0x29, 0x64, 0x14, 0x65, 0x0,
|
||||
0xD4, 0x55, 0x74, 0x15, 0xF2, 0x29, 0xD4, 0x55, 0x0, 0xEE, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
];
|
||||
|
||||
struct Server {
|
||||
udp_host: String,
|
||||
udp_target: String,
|
||||
socket_timeout: Option<Duration>,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
fn new(udp_host: String, udp_target: String, secs: u64) -> Server {
|
||||
Server {
|
||||
udp_host,
|
||||
udp_target,
|
||||
socket_timeout: match secs {
|
||||
0 => None,
|
||||
x => Some(Duration::from_secs(x)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn start(&self) -> std::io::Result<usize> {
|
||||
let udp_host = UdpSocket::bind(&self.udp_host)?;
|
||||
udp_host.set_read_timeout(self.socket_timeout)?;
|
||||
|
||||
let udp_target = UdpSocket::bind("127.0.0.1:3401")?;
|
||||
udp_target.connect(&self.udp_target)?;
|
||||
|
||||
udp_target.send(&PONG)?;
|
||||
|
||||
let mut buf = [0u8; 2048];
|
||||
match udp_host.recv(&mut buf) {
|
||||
Ok(len) => {
|
||||
println!("udp got len: {}", len);
|
||||
assert_eq!(len, PONG.len());
|
||||
assert_eq!(&buf[..len], &PONG[..]);
|
||||
}
|
||||
Err(e) => {
|
||||
panic!("recv function failed: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
println!("success! received back exactly what we sent!");
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
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:51821] [udp_target, 127.0.0.1:51821] [socket_timeout, 1]",
|
||||
args.get_str(0, "udp-test")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let server = Server::new(
|
||||
args.get_str(1, "127.0.0.1:51821").to_owned(),
|
||||
args.get_str(2, "127.0.0.1:51821").to_owned(),
|
||||
args.get(3, 1),
|
||||
);
|
||||
|
||||
println!(
|
||||
"udp_host: {}, udp_target: {}, socket_timeout: {:?}",
|
||||
server.udp_host, server.udp_target, server.socket_timeout,
|
||||
);
|
||||
|
||||
server.start().expect("error running server");
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpStream, UdpSocket};
|
||||
use std::time::Duration;
|
||||
|
||||
use std::env;
|
||||
use std::thread;
|
||||
use wireguard_proxy::Args;
|
||||
use wireguard_proxy::{Args, TcpUdpPipe};
|
||||
|
||||
struct Server {
|
||||
udp_host: String,
|
||||
@ -27,49 +26,25 @@ impl Server {
|
||||
}
|
||||
|
||||
fn start(&self) -> std::io::Result<usize> {
|
||||
let mut tcp_stream = TcpStream::connect(&self.tcp_target)?;
|
||||
let tcp_stream = TcpStream::connect(&self.tcp_target)?;
|
||||
|
||||
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
||||
|
||||
let udp_socket = UdpSocket::bind(&self.udp_host)?;
|
||||
udp_socket.set_read_timeout(self.socket_timeout)?;
|
||||
udp_socket.connect(&self.udp_target)?;
|
||||
//udp_socket.connect(&self.udp_target)?; // this isn't strictly needed... just filters who we can receive from
|
||||
|
||||
let udp_socket_clone = udp_socket.try_clone().expect("clone udp_socket failed");
|
||||
let mut tcp_stream_clone = tcp_stream.try_clone().expect("clone tcp_stream failed");
|
||||
thread::spawn(move || {
|
||||
let mut buf = [0u8; 2048];
|
||||
loop {
|
||||
match udp_socket_clone.recv(&mut buf) {
|
||||
Ok(len) => {
|
||||
println!("udp got len: {}", len);
|
||||
tcp_stream_clone
|
||||
.write(&buf[..len])
|
||||
.expect("cannot write to tcp_clone");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("recv function failed: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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");
|
||||
});
|
||||
|
||||
let mut buf = [0u8; 2048];
|
||||
loop {
|
||||
match tcp_stream.read(&mut buf) {
|
||||
Ok(len) => {
|
||||
println!("tcp got len: {}", len);
|
||||
udp_socket.send(&buf[..len])?;
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Unable to read stream: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
udp_pipe.tcp_to_udp()?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpListener, TcpStream, UdpSocket};
|
||||
use std::time::Duration;
|
||||
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use wireguard_proxy::Args;
|
||||
use wireguard_proxy::{Args, TcpUdpPipe};
|
||||
|
||||
struct Server {
|
||||
udp_target: String,
|
||||
@ -35,7 +34,7 @@ impl Server {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_client(&self, mut tcp_stream: TcpStream) -> std::io::Result<usize> {
|
||||
fn handle_client(&self, tcp_stream: TcpStream) -> std::io::Result<usize> {
|
||||
tcp_stream.set_read_timeout(self.socket_timeout)?;
|
||||
|
||||
let mut port = self.udp_low_port;
|
||||
@ -51,45 +50,19 @@ impl Server {
|
||||
}
|
||||
};
|
||||
udp_socket.set_read_timeout(self.socket_timeout)?;
|
||||
//udp_socket.connect(&self.udp_target)?;
|
||||
udp_socket.connect(&self.udp_target)?;
|
||||
|
||||
let udp_socket_clone = udp_socket.try_clone().expect("clone udp_socket failed");
|
||||
let mut tcp_stream_clone = tcp_stream.try_clone().expect("clone tcp_stream failed");
|
||||
thread::spawn(move || {
|
||||
let mut buf = [0u8; 2048];
|
||||
loop {
|
||||
match udp_socket_clone.recv(&mut buf) {
|
||||
Ok(len) => {
|
||||
println!("udp got len: {}", len);
|
||||
tcp_stream_clone
|
||||
.write(&buf[..len])
|
||||
.expect("cannot write to tcp_clone");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("recv function failed: {:?}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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");
|
||||
});
|
||||
|
||||
let mut buf = [0u8; 2048];
|
||||
loop {
|
||||
match tcp_stream.read(&mut buf) {
|
||||
Ok(len) => {
|
||||
println!("tcp got len: {}", len);
|
||||
//udp_socket.send(&buf[..len])?;
|
||||
let sent = udp_socket.send_to(&buf[..len], &self.udp_target)?;
|
||||
println!("udp sent len: {}", sent);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Unable to read stream: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
udp_pipe.tcp_to_udp()?;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
50
src/lib.rs
50
src/lib.rs
@ -1,3 +1,5 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpStream, UdpSocket};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub struct Args<'a> {
|
||||
@ -24,3 +26,51 @@ impl<'a> Args<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TcpUdpPipe {
|
||||
buf: [u8; 2050], // 2048 + 2 for len
|
||||
tcp_stream: TcpStream,
|
||||
udp_socket: UdpSocket,
|
||||
}
|
||||
|
||||
impl TcpUdpPipe {
|
||||
pub fn new(tcp_stream: TcpStream, udp_socket: UdpSocket) -> TcpUdpPipe {
|
||||
TcpUdpPipe {
|
||||
tcp_stream,
|
||||
udp_socket,
|
||||
buf: [0u8; 2050],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_clone(&self) -> std::io::Result<TcpUdpPipe> {
|
||||
Ok(TcpUdpPipe::new(
|
||||
self.tcp_stream.try_clone()?,
|
||||
self.udp_socket.try_clone()?,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn udp_to_tcp(&mut self) -> std::io::Result<usize> {
|
||||
let len = self.udp_socket.recv(&mut self.buf[2..])?;
|
||||
println!("udp got len: {}", len);
|
||||
|
||||
self.buf[0] = ((len >> 8) & 0xFF) as u8;
|
||||
self.buf[1] = (len & 0xFF) as u8;
|
||||
|
||||
//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])
|
||||
}
|
||||
|
||||
pub fn tcp_to_udp(&mut self) -> std::io::Result<usize> {
|
||||
self.tcp_stream.read_exact(&mut self.buf[..2])?;
|
||||
let len = ((self.buf[0] as usize) << 8) + self.buf[1] as usize;
|
||||
println!("tcp expecting len: {}", len);
|
||||
self.tcp_stream.read_exact(&mut self.buf[..len])?;
|
||||
println!("tcp got len: {}", len);
|
||||
self.udp_socket.send(&self.buf[..len])
|
||||
|
||||
//let sent = udp_socket.send_to(&buf[..len], &self.udp_target)?;
|
||||
//assert_eq!(sent, len);
|
||||
}
|
||||
}
|
||||
|
22
test.sh
Executable file
22
test.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
# first make sure udp-test succeeds running against itself
|
||||
cargo run --release --bin udp-test || 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 &
|
||||
proxyd_pid=$!
|
||||
# wait for ports to be set up, this is fragile...
|
||||
sleep 1
|
||||
# proxy pointing to proxyd
|
||||
cargo run --release --bin wireguard-proxy &
|
||||
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
|
||||
udp_exit=$?
|
||||
|
||||
kill $proxyd_pid $proxy_pid
|
||||
|
||||
exit $udp_exit
|
Loading…
Reference in New Issue
Block a user