summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOdd Stranne <odd@mullvad.net>2022-03-18 11:32:20 +0100
committerOdd Stranne <odd@mullvad.net>2022-03-24 10:34:59 +0100
commit0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48 (patch)
treed1fda1f341a093f40d5f15faec9f6274c786b6df
parente53c4552cf57b9263f88cdce1ff55419efa9daa4 (diff)
downloadmullvadvpn-0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48.tar.xz
mullvadvpn-0e5b3948ce70a3b5634fdbf39d6430f8a53fdd48.zip
Add tunnel-obfuscation crate
-rw-r--r--Cargo.toml1
-rw-r--r--tunnel-obfuscation/Cargo.toml15
-rw-r--r--tunnel-obfuscation/src/lib.rs35
-rw-r--r--tunnel-obfuscation/src/main.rs36
-rw-r--r--tunnel-obfuscation/src/udp2tcp.rs88
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?))
+}