diff options
| author | Odd Stranne <odd@mullvad.net> | 2022-03-18 11:32:20 +0100 |
|---|---|---|
| committer | Odd Stranne <odd@mullvad.net> | 2022-03-24 10:34:59 +0100 |
| commit | 0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48 (patch) | |
| tree | d1fda1f341a093f40d5f15faec9f6274c786b6df | |
| parent | e53c4552cf57b9263f88cdce1ff55419efa9daa4 (diff) | |
| download | mullvadvpn-0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48.tar.xz mullvadvpn-0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48.zip | |
Add tunnel-obfuscation crate
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | tunnel-obfuscation/Cargo.toml | 15 | ||||
| -rw-r--r-- | tunnel-obfuscation/src/lib.rs | 35 | ||||
| -rw-r--r-- | tunnel-obfuscation/src/main.rs | 36 | ||||
| -rw-r--r-- | tunnel-obfuscation/src/udp2tcp.rs | 88 |
5 files changed, 175 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml index 074445b867..51a87a03d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "talpid-dbus", "talpid-platform-metadata", "mullvad-management-interface", + "tunnel-obfuscation", ] exclude = ["dist-assets/binaries/shadowsocks-rust"] diff --git a/tunnel-obfuscation/Cargo.toml b/tunnel-obfuscation/Cargo.toml new file mode 100644 index 0000000000..02b7f9370e --- /dev/null +++ b/tunnel-obfuscation/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "tunnel-obfuscation" +version = "0.1.0" +authors = ["Mullvad VPN"] +description = "Provides different types of obfuscation layers for WireGuard" +license = "GPL-3.0" +edition = "2021" +publish = false + +[dependencies] +async-trait = "0.1" +err-derive = "0.3.0" +futures = "0.3.5" +tokio = { version = "1.8", features = ["rt-multi-thread", "macros", "net", "io-util"] } +udp-over-tcp = { git = "https://github.com/mullvad/udp-over-tcp", rev = "27b9519b63244736b6f3c7c4af60976c88dc6b95" } diff --git a/tunnel-obfuscation/src/lib.rs b/tunnel-obfuscation/src/lib.rs new file mode 100644 index 0000000000..c59fa284fd --- /dev/null +++ b/tunnel-obfuscation/src/lib.rs @@ -0,0 +1,35 @@ +use async_trait::async_trait; +use std::net::SocketAddr; + +mod udp2tcp; +pub use udp2tcp::Udp2TcpSettings; + +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(err_derive::Error, Debug)] +#[error(no_from)] +pub enum Error { + #[error(display = "Failed to create Udp2Tcp obfuscator")] + CreateUdp2TcpObfuscator(#[error(source)] udp2tcp::Error), + + #[error(display = "Failed to run Udp2Tcp obfuscator")] + RunUdp2TcpObfuscator(#[error(source)] udp2tcp::Error), +} + +#[async_trait] +pub trait Obfuscator: Send { + fn endpoint(&self) -> SocketAddr; + async fn run(self: Box<Self>) -> Result<()>; +} + +pub enum Settings { + Udp2Tcp(Udp2TcpSettings), +} + +pub async fn create_obfuscator(settings: &Settings) -> Result<Box<dyn Obfuscator>> { + match settings { + Settings::Udp2Tcp(s) => udp2tcp::create_obfuscator(s) + .await + .map_err(Error::CreateUdp2TcpObfuscator), + } +} diff --git a/tunnel-obfuscation/src/main.rs b/tunnel-obfuscation/src/main.rs new file mode 100644 index 0000000000..db613f773b --- /dev/null +++ b/tunnel-obfuscation/src/main.rs @@ -0,0 +1,36 @@ +use std::{env::args, net::SocketAddr}; +use tunnel_obfuscation::{create_obfuscator, Obfuscator, Settings, Udp2TcpSettings}; + +#[tokio::main] +async fn main() { + if args().len() != 2 { + println!("Missing arguments"); + } + + let obfuscator = instantiate_requested(&args().last().unwrap()).await; + + println!("endpoint() returns {:?}", obfuscator.endpoint()); + + if let Err(err) = obfuscator.run().await { + println!("obfuscator.run() failed: {:?}", err); + } +} + +async fn instantiate_requested(obfuscator_type: &String) -> Box<dyn Obfuscator> { + match obfuscator_type.as_str() { + "udp2tcp" => { + let settings = Udp2TcpSettings { + peer: SocketAddr::new("127.0.0.1".parse().unwrap(), 3030), + #[cfg(target_os = "linux")] + fwmark: Some(1337), + }; + + create_obfuscator(&Settings::Udp2Tcp(settings)) + .await + .expect("Creating obfuscator failed") + } + _ => { + unimplemented!() + } + } +} diff --git a/tunnel-obfuscation/src/udp2tcp.rs b/tunnel-obfuscation/src/udp2tcp.rs new file mode 100644 index 0000000000..877b53bd2f --- /dev/null +++ b/tunnel-obfuscation/src/udp2tcp.rs @@ -0,0 +1,88 @@ +use crate::Obfuscator; +use async_trait::async_trait; +use std::net::SocketAddr; +use udp_over_tcp::{ + udp2tcp::{ConnectError, ForwardError, Udp2Tcp as Udp2TcpImpl}, + TcpOptions, +}; + +pub struct Udp2TcpSettings { + pub peer: SocketAddr, + #[cfg(target_os = "linux")] + pub fwmark: Option<u32>, +} + +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(err_derive::Error, Debug)] +#[error(no_from)] +pub enum Error { + /// Failed to create obfuscator + #[error(display = "Failed to create obfuscator")] + CreateObfuscator(#[error(source)] ConnectError), + + /// Failed to determine UDP socket details + #[error(display = "Failed to determine UDP socket details")] + GetUdpSocketDetails(#[error(source)] std::io::Error), + + /// Failed to run obfuscator + #[error(display = "Failed to run obfuscator")] + RunObfuscator(#[error(source)] ForwardError), +} + +struct Udp2Tcp { + local_addr: SocketAddr, + instance: Udp2TcpImpl, +} + +impl Udp2Tcp { + pub async fn new(settings: &Udp2TcpSettings) -> Result<Self> { + let listen_addr = if settings.peer.is_ipv4() { + SocketAddr::new("127.0.0.1".parse().unwrap(), 0) + } else { + SocketAddr::new("::1".parse().unwrap(), 0) + }; + + let instance = Udp2TcpImpl::new( + listen_addr, + settings.peer, + #[cfg(target_os = "linux")] + TcpOptions { + recv_buffer_size: None, + send_buffer_size: None, + fwmark: settings.fwmark, + }, + #[cfg(not(target_os = "linux"))] + TcpOptions::default(), + ) + .await + .map_err(Error::CreateObfuscator)?; + let local_addr = instance + .local_udp_addr() + .map_err(Error::GetUdpSocketDetails)?; + + Ok(Self { + local_addr, + instance, + }) + } +} + +#[async_trait] +impl Obfuscator for Udp2Tcp { + fn endpoint(&self) -> SocketAddr { + self.local_addr + } + + async fn run(self: Box<Self>) -> crate::Result<()> { + self.instance + .run() + .await + .map_err(Error::RunObfuscator) + .map_err(crate::Error::RunUdp2TcpObfuscator) + } +} + +pub async fn create_obfuscator(settings: &Udp2TcpSettings) -> Result<Box<dyn Obfuscator>> { + Ok(Box::new(Udp2Tcp::new(settings).await?)) +} |
