summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorEmīls Piņķis <emils@mullvad.net>2022-10-12 13:32:59 +0200
committerEmīls <emils@mullvad.net>2022-11-07 11:54:33 +0100
commitac846d3154e584e429927f2ecbec2b906bf50a68 (patch)
tree808548e9da6e65d37a49c62e85b91728f9704d98
parent3b8e28cd91aaa59e236a4c4875d9cb43e823042f (diff)
downloadmullvadvpn-ac846d3154e584e429927f2ecbec2b906bf50a68.tar.xz
mullvadvpn-ac846d3154e584e429927f2ecbec2b906bf50a68.zip
Split up talpid-core
-rw-r--r--Cargo.lock146
-rw-r--r--Cargo.toml5
-rw-r--r--mullvad-api/Cargo.toml3
-rw-r--r--mullvad-cli/src/cmds/bridge.rs2
-rw-r--r--mullvad-daemon/Cargo.toml1
-rw-r--r--mullvad-daemon/src/early_boot_firewall.rs2
-rw-r--r--mullvad-daemon/src/lib.rs4
-rw-r--r--mullvad-daemon/src/tunnel.rs2
-rw-r--r--mullvad-jni/Cargo.toml1
-rw-r--r--mullvad-jni/src/talpid_vpn_service.rs2
-rw-r--r--mullvad-management-interface/src/types/conversions/custom_tunnel.rs2
-rw-r--r--mullvad-management-interface/src/types/conversions/relay_constraints.rs2
-rw-r--r--mullvad-paths/Cargo.toml2
-rw-r--r--mullvad-relay-selector/src/lib.rs6
-rw-r--r--mullvad-setup/src/main.rs11
-rw-r--r--mullvad-types/src/lib.rs6
-rw-r--r--mullvad-types/src/relay_list.rs8
-rw-r--r--talpid-core/Cargo.toml12
-rw-r--r--talpid-core/build.rs42
-rw-r--r--talpid-core/src/dns/linux/mod.rs2
-rw-r--r--talpid-core/src/dns/linux/network_manager.rs4
-rw-r--r--talpid-core/src/dns/linux/systemd_resolved.rs6
-rw-r--r--talpid-core/src/dns/mod.rs4
-rw-r--r--talpid-core/src/dns/windows/mod.rs15
-rw-r--r--talpid-core/src/firewall/linux.rs47
-rw-r--r--talpid-core/src/firewall/mod.rs11
-rw-r--r--talpid-core/src/firewall/windows.rs85
-rw-r--r--talpid-core/src/lib.rs23
-rw-r--r--talpid-core/src/linux/mod.rs12
-rw-r--r--talpid-core/src/logging/mod.rs4
-rw-r--r--talpid-core/src/logging/windows.rs78
-rw-r--r--talpid-core/src/offline/linux.rs19
-rw-r--r--talpid-core/src/offline/macos.rs6
-rw-r--r--talpid-core/src/offline/mod.rs16
-rw-r--r--talpid-core/src/offline/windows.rs15
-rw-r--r--talpid-core/src/split_tunnel/windows/driver.rs6
-rw-r--r--talpid-core/src/split_tunnel/windows/mod.rs15
-rw-r--r--talpid-core/src/split_tunnel/windows/volume_monitor.rs2
-rw-r--r--talpid-core/src/tunnel/mod.rs118
-rw-r--r--talpid-core/src/tunnel/tun_provider/unix.rs69
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs36
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs41
-rw-r--r--talpid-core/src/window.rs (renamed from talpid-core/src/windows/window.rs)2
-rw-r--r--talpid-dbus/src/network_manager.rs6
-rw-r--r--talpid-openvpn/Cargo.toml62
-rw-r--r--talpid-openvpn/build.rs9
-rw-r--r--talpid-openvpn/src/lib.rs (renamed from talpid-core/src/tunnel/openvpn/mod.rs)59
-rw-r--r--talpid-openvpn/src/mktemp.rs (renamed from talpid-core/src/mktemp.rs)0
-rw-r--r--talpid-openvpn/src/process/mod.rs (renamed from talpid-core/src/process/mod.rs)0
-rw-r--r--talpid-openvpn/src/process/openvpn.rs (renamed from talpid-core/src/process/openvpn.rs)19
-rw-r--r--talpid-openvpn/src/process/stoppable_process.rs (renamed from talpid-core/src/process/stoppable_process.rs)0
-rw-r--r--talpid-openvpn/src/proxy/mod.rs (renamed from talpid-core/src/proxy/mod.rs)0
-rw-r--r--talpid-openvpn/src/proxy/noop.rs (renamed from talpid-core/src/proxy/noop.rs)0
-rw-r--r--talpid-openvpn/src/proxy/shadowsocks.rs (renamed from talpid-core/src/proxy/shadowsocks.rs)2
-rw-r--r--talpid-openvpn/src/wintun.rs (renamed from talpid-core/src/tunnel/openvpn/wintun.rs)17
-rw-r--r--talpid-routing/Cargo.toml47
-rw-r--r--talpid-routing/src/android.rs (renamed from talpid-core/src/routing/android.rs)3
-rw-r--r--talpid-routing/src/lib.rs (renamed from talpid-core/src/routing/mod.rs)13
-rw-r--r--talpid-routing/src/linux.rs (renamed from talpid-core/src/routing/linux.rs)81
-rw-r--r--talpid-routing/src/macos.rs (renamed from talpid-core/src/routing/macos.rs)5
-rw-r--r--talpid-routing/src/unix.rs (renamed from talpid-core/src/routing/unix.rs)31
-rw-r--r--talpid-routing/src/windows/default_route_monitor.rs (renamed from talpid-core/src/routing/windows/default_route_monitor.rs)6
-rw-r--r--talpid-routing/src/windows/get_best_default_route.rs (renamed from talpid-core/src/routing/windows/get_best_default_route.rs)4
-rw-r--r--talpid-routing/src/windows/mod.rs (renamed from talpid-core/src/routing/windows/mod.rs)48
-rw-r--r--talpid-routing/src/windows/route_manager.rs (renamed from talpid-core/src/routing/windows/route_manager.rs)12
-rw-r--r--talpid-tunnel/Cargo.toml42
-rw-r--r--talpid-tunnel/src/lib.rs62
-rw-r--r--talpid-tunnel/src/tun_provider/android/ipnetwork_sub.rs (renamed from talpid-core/src/tunnel/tun_provider/android/ipnetwork_sub.rs)0
-rw-r--r--talpid-tunnel/src/tun_provider/android/mod.rs (renamed from talpid-core/src/tunnel/tun_provider/android/mod.rs)14
-rw-r--r--talpid-tunnel/src/tun_provider/mod.rs (renamed from talpid-core/src/tunnel/tun_provider/mod.rs)0
-rw-r--r--talpid-tunnel/src/tun_provider/stub.rs (renamed from talpid-core/src/tunnel/tun_provider/stub.rs)0
-rw-r--r--talpid-tunnel/src/tun_provider/unix.rs (renamed from talpid-core/src/network_interface.rs)108
-rw-r--r--talpid-tunnel/src/windows.rs (renamed from talpid-core/src/tunnel/windows.rs)2
-rw-r--r--talpid-types/src/net/openvpn.rs2
-rw-r--r--talpid-types/src/net/wireguard.rs2
-rw-r--r--talpid-windows-net/Cargo.toml24
-rw-r--r--talpid-windows-net/src/lib.rs10
-rw-r--r--talpid-windows-net/src/net.rs (renamed from talpid-core/src/windows/mod.rs)125
-rw-r--r--talpid-wireguard/Cargo.toml78
-rw-r--r--talpid-wireguard/build.rs36
-rw-r--r--talpid-wireguard/src/config.rs (renamed from talpid-core/src/tunnel/wireguard/config.rs)8
-rw-r--r--talpid-wireguard/src/connectivity_check.rs (renamed from talpid-core/src/tunnel/wireguard/connectivity_check.rs)4
-rw-r--r--talpid-wireguard/src/lib.rs (renamed from talpid-core/src/tunnel/wireguard/mod.rs)46
-rw-r--r--talpid-wireguard/src/logging.rs (renamed from talpid-core/src/tunnel/wireguard/logging.rs)0
-rw-r--r--talpid-wireguard/src/ping_monitor/android.rs (renamed from talpid-core/src/ping_monitor/android.rs)0
-rw-r--r--talpid-wireguard/src/ping_monitor/icmp.rs (renamed from talpid-core/src/ping_monitor/icmp.rs)0
-rw-r--r--talpid-wireguard/src/ping_monitor/mod.rs (renamed from talpid-core/src/ping_monitor/mod.rs)0
-rw-r--r--talpid-wireguard/src/stats.rs (renamed from talpid-core/src/tunnel/wireguard/stats.rs)0
-rw-r--r--talpid-wireguard/src/wireguard_go.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_go.rs)26
-rw-r--r--talpid-wireguard/src/wireguard_kernel/mod.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/mod.rs)0
-rw-r--r--talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs)0
-rw-r--r--talpid-wireguard/src/wireguard_kernel/nl_message.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/nl_message.rs)0
-rw-r--r--talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs)33
-rw-r--r--talpid-wireguard/src/wireguard_kernel/parsers.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/parsers.rs)0
-rw-r--r--talpid-wireguard/src/wireguard_kernel/wg_message.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_kernel/wg_message.rs)2
-rw-r--r--talpid-wireguard/src/wireguard_nt.rs (renamed from talpid-core/src/tunnel/wireguard/wireguard_nt.rs)52
96 files changed, 1276 insertions, 719 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a437183a59..2238ff5948 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1587,7 +1587,6 @@ dependencies = [
"talpid-types",
"tokio",
"tokio-rustls",
- "tokio-stream",
"uuid",
]
@@ -1626,7 +1625,6 @@ dependencies = [
"ctrlc",
"dirs-next",
"duct",
- "either",
"err-derive",
"fern",
"futures",
@@ -1690,6 +1688,7 @@ dependencies = [
"nix 0.23.1",
"rand 0.8.5",
"talpid-core",
+ "talpid-tunnel",
"talpid-types",
"tokio",
]
@@ -3121,10 +3120,7 @@ dependencies = [
"log",
"memoffset",
"mnl",
- "netlink-packet-core",
"netlink-packet-route",
- "netlink-packet-utils",
- "netlink-proto",
"netlink-sys",
"nftnl",
"nix 0.23.1",
@@ -3146,23 +3142,25 @@ dependencies = [
"subslice",
"system-configuration",
"talpid-dbus",
+ "talpid-openvpn",
"talpid-platform-metadata",
+ "talpid-routing",
"talpid-time",
+ "talpid-tunnel",
"talpid-tunnel-config-client",
"talpid-types",
+ "talpid-windows-net",
+ "talpid-wireguard",
"tempfile",
"tokio",
- "tokio-stream",
"tonic",
"tonic-build",
"triggered",
"trust-dns-server",
"tun",
- "tunnel-obfuscation",
"uuid",
"which",
"widestring 1.0.2",
- "winapi",
"windows",
"windows-service",
"windows-sys 0.42.0",
@@ -3183,6 +3181,43 @@ dependencies = [
]
[[package]]
+name = "talpid-openvpn"
+version = "0.0.0"
+dependencies = [
+ "async-trait",
+ "atty",
+ "bitflags",
+ "byteorder",
+ "cfg-if",
+ "duct",
+ "err-derive",
+ "futures",
+ "lazy_static",
+ "log",
+ "os_pipe",
+ "parity-tokio-ipc",
+ "parking_lot 0.11.2",
+ "prost",
+ "shadowsocks-service",
+ "shell-escape",
+ "socket2",
+ "talpid-routing",
+ "talpid-tunnel",
+ "talpid-types",
+ "talpid-windows-net",
+ "tokio",
+ "tonic",
+ "tonic-build",
+ "triggered",
+ "uuid",
+ "which",
+ "widestring 0.5.1",
+ "winapi",
+ "windows-sys 0.42.0",
+ "winreg",
+]
+
+[[package]]
name = "talpid-openvpn-plugin"
version = "0.0.0"
dependencies = [
@@ -3212,6 +3247,30 @@ dependencies = [
]
[[package]]
+name = "talpid-routing"
+version = "0.0.0"
+dependencies = [
+ "err-derive",
+ "futures",
+ "ipnetwork",
+ "jnix",
+ "lazy_static",
+ "libc",
+ "log",
+ "netlink-packet-route",
+ "netlink-sys",
+ "rtnetlink",
+ "socket2",
+ "talpid-types",
+ "talpid-windows-net",
+ "tokio",
+ "tokio-stream",
+ "widestring 1.0.2",
+ "winapi",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
name = "talpid-time"
version = "0.0.0"
dependencies = [
@@ -3220,6 +3279,26 @@ dependencies = [
]
[[package]]
+name = "talpid-tunnel"
+version = "0.0.0"
+dependencies = [
+ "cfg-if",
+ "duct",
+ "err-derive",
+ "futures",
+ "ipnetwork",
+ "jnix",
+ "log",
+ "nix 0.23.1",
+ "talpid-routing",
+ "talpid-types",
+ "talpid-windows-net",
+ "tokio",
+ "tun",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
name = "talpid-tunnel-config-client"
version = "0.0.0"
dependencies = [
@@ -3249,6 +3328,57 @@ dependencies = [
]
[[package]]
+name = "talpid-windows-net"
+version = "0.0.0"
+dependencies = [
+ "err-derive",
+ "futures",
+ "libc",
+ "socket2",
+ "winapi",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "talpid-wireguard"
+version = "0.0.0"
+dependencies = [
+ "bitflags",
+ "byteorder",
+ "chrono",
+ "duct",
+ "err-derive",
+ "futures",
+ "hex",
+ "internet-checksum",
+ "ipnetwork",
+ "lazy_static",
+ "libc",
+ "log",
+ "netlink-packet-core",
+ "netlink-packet-route",
+ "netlink-packet-utils",
+ "netlink-proto",
+ "nix 0.23.1",
+ "parking_lot 0.11.2",
+ "rand 0.8.5",
+ "rtnetlink",
+ "socket2",
+ "talpid-dbus",
+ "talpid-routing",
+ "talpid-tunnel",
+ "talpid-tunnel-config-client",
+ "talpid-types",
+ "talpid-windows-net",
+ "tokio",
+ "tokio-stream",
+ "tunnel-obfuscation",
+ "widestring 0.5.1",
+ "windows-sys 0.42.0",
+ "zeroize",
+]
+
+[[package]]
name = "tempfile"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 91fbf682aa..1868ba9dfe 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,9 +16,14 @@ members = [
"talpid-openvpn-plugin",
"talpid-core",
"talpid-dbus",
+ "talpid-openvpn",
"talpid-platform-metadata",
+ "talpid-routing",
"talpid-time",
+ "talpid-tunnel",
"talpid-tunnel-config-client",
+ "talpid-windows-net",
+ "talpid-wireguard",
"mullvad-management-interface",
"tunnel-obfuscation",
]
diff --git a/mullvad-api/Cargo.toml b/mullvad-api/Cargo.toml
index 2a7f8ef51d..e02ac22e11 100644
--- a/mullvad-api/Cargo.toml
+++ b/mullvad-api/Cargo.toml
@@ -34,6 +34,3 @@ talpid-time = { path = "../talpid-time" }
shadowsocks = { version = "1.14.2", default-features = false, features = ["stream-cipher"] }
uuid = { version = "0.8", features = ["v4"] }
-
-[target.'cfg(target_os="macos")'.dependencies]
-tokio-stream = { version = "0.1", features = ["io-util"] }
diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs
index 9d1c5172fa..e283dc96ed 100644
--- a/mullvad-cli/src/cmds/bridge.rs
+++ b/mullvad-cli/src/cmds/bridge.rs
@@ -383,6 +383,8 @@ impl Bridge {
peer: SocketAddr::new(remote_ip, remote_port),
password,
cipher,
+ #[cfg(target_os = "linux")]
+ fwmark: None,
};
let packed_proxy = openvpn::ProxySettings::Shadowsocks(proxy);
if let Err(error) = openvpn::validate_proxy_settings(&packed_proxy) {
diff --git a/mullvad-daemon/Cargo.toml b/mullvad-daemon/Cargo.toml
index 5069a38f2a..0348051bfe 100644
--- a/mullvad-daemon/Cargo.toml
+++ b/mullvad-daemon/Cargo.toml
@@ -12,7 +12,6 @@ cfg-if = "1.0"
chrono = { version = "0.4.19", features = ["serde"] }
clap = { version = "3.0", features = ["cargo"] }
err-derive = "0.3.1"
-either = "1"
fern = { version = "0.6", features = ["colored"] }
futures = "0.3"
ipnetwork = "0.16"
diff --git a/mullvad-daemon/src/early_boot_firewall.rs b/mullvad-daemon/src/early_boot_firewall.rs
index 7e93f47b27..a5df67be0b 100644
--- a/mullvad-daemon/src/early_boot_firewall.rs
+++ b/mullvad-daemon/src/early_boot_firewall.rs
@@ -14,7 +14,7 @@ pub enum Error {
}
pub async fn initialize_firewall() -> Result<(), Error> {
- let mut firewall = Firewall::new()?;
+ let mut firewall = Firewall::new(mullvad_types::TUNNEL_FWMARK)?;
let allow_lan = get_allow_lan().await.unwrap_or_else(|err| {
log::info!(
"Not allowing LAN traffic due to failing to read settings: {}",
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index 4f22c7244c..fce026ff1f 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -692,6 +692,10 @@ where
exclusion_gid,
#[cfg(target_os = "android")]
android_context,
+ #[cfg(target_os = "linux")]
+ mullvad_types::TUNNEL_FWMARK,
+ #[cfg(target_os = "linux")]
+ mullvad_types::TUNNEL_TABLE_ID,
)
.await
.map_err(Error::TunnelError)?;
diff --git a/mullvad-daemon/src/tunnel.rs b/mullvad-daemon/src/tunnel.rs
index 7f7fb0c8b3..81e0063166 100644
--- a/mullvad-daemon/src/tunnel.rs
+++ b/mullvad-daemon/src/tunnel.rs
@@ -216,6 +216,8 @@ impl InnerParametersGenerator {
exit_peer: endpoint.exit_peer,
ipv4_gateway: endpoint.ipv4_gateway,
ipv6_gateway: Some(endpoint.ipv6_gateway),
+ #[cfg(target_os = "linux")]
+ fwmark: Some(mullvad_types::TUNNEL_FWMARK),
},
options: self.tunnel_options.wireguard.options.clone(),
generic_options: self.tunnel_options.generic.clone(),
diff --git a/mullvad-jni/Cargo.toml b/mullvad-jni/Cargo.toml
index da60b07ea8..dcf3546a95 100644
--- a/mullvad-jni/Cargo.toml
+++ b/mullvad-jni/Cargo.toml
@@ -28,4 +28,5 @@ mullvad-problem-report = { path = "../mullvad-problem-report" }
mullvad-types = { path = "../mullvad-types" }
mullvad-api = { path = "../mullvad-api" }
talpid-core = { path = "../talpid-core" }
+talpid-tunnel = { path = "../talpid-tunnel" }
talpid-types = { path = "../talpid-types" }
diff --git a/mullvad-jni/src/talpid_vpn_service.rs b/mullvad-jni/src/talpid_vpn_service.rs
index d2b1f00075..554313b8e4 100644
--- a/mullvad-jni/src/talpid_vpn_service.rs
+++ b/mullvad-jni/src/talpid_vpn_service.rs
@@ -18,7 +18,7 @@ use std::{
os::unix::io::RawFd,
time::{Duration, Instant},
};
-use talpid_core::tunnel::TunConfig;
+use talpid_tunnel::tun_provider::TunConfig;
use talpid_types::ErrorExt;
#[derive(Debug, err_derive::Error)]
diff --git a/mullvad-management-interface/src/types/conversions/custom_tunnel.rs b/mullvad-management-interface/src/types/conversions/custom_tunnel.rs
index 950f8f920c..146799b473 100644
--- a/mullvad-management-interface/src/types/conversions/custom_tunnel.rs
+++ b/mullvad-management-interface/src/types/conversions/custom_tunnel.rs
@@ -94,6 +94,8 @@ impl TryFrom<proto::ConnectionConfig> for mullvad_types::ConnectionConfig {
exit_peer: None,
ipv4_gateway,
ipv6_gateway,
+ #[cfg(target_os = "linux")]
+ fwmark: Some(mullvad_types::TUNNEL_FWMARK),
},
))
}
diff --git a/mullvad-management-interface/src/types/conversions/relay_constraints.rs b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
index d76006bf7f..a402a058ed 100644
--- a/mullvad-management-interface/src/types/conversions/relay_constraints.rs
+++ b/mullvad-management-interface/src/types/conversions/relay_constraints.rs
@@ -520,6 +520,8 @@ impl TryFrom<proto::BridgeSettings> for mullvad_types::relay_constraints::Bridge
})?;
let proxy_settings = talpid_net::openvpn::ProxySettings::Shadowsocks(
talpid_net::openvpn::ShadowsocksProxySettings {
+ #[cfg(target_os = "linux")]
+ fwmark: Some(mullvad_types::TUNNEL_FWMARK),
peer,
password: proxy_settings.password,
cipher: proxy_settings.cipher,
diff --git a/mullvad-paths/Cargo.toml b/mullvad-paths/Cargo.toml
index 04edf4e365..57690210bb 100644
--- a/mullvad-paths/Cargo.toml
+++ b/mullvad-paths/Cargo.toml
@@ -11,5 +11,5 @@ publish = false
err-derive = "0.3.1"
log = "0.4"
-[target.'cfg(any(windows, target_os = "macos"))'.dependencies]
+[target.'cfg(windows)'.dependencies]
dirs-next = "2.0"
diff --git a/mullvad-relay-selector/src/lib.rs b/mullvad-relay-selector/src/lib.rs
index b398d5268e..e880b101d1 100644
--- a/mullvad-relay-selector/src/lib.rs
+++ b/mullvad-relay-selector/src/lib.rs
@@ -1138,7 +1138,11 @@ impl RelaySelector {
shadowsocks_endpoint.port,
shadowsocks_endpoint.protocol
);
- shadowsocks_endpoint.to_proxy_settings(relay.ipv4_addr_in.into())
+ shadowsocks_endpoint.to_proxy_settings(
+ relay.ipv4_addr_in.into(),
+ #[cfg(target_os = "linux")]
+ mullvad_types::TUNNEL_FWMARK,
+ )
})
}
diff --git a/mullvad-setup/src/main.rs b/mullvad-setup/src/main.rs
index 2f210ebb76..c5ef3f3000 100644
--- a/mullvad-setup/src/main.rs
+++ b/mullvad-setup/src/main.rs
@@ -154,10 +154,13 @@ async fn reset_firewall() -> Result<(), Error> {
return Err(Error::DaemonIsRunning);
}
- Firewall::new()
- .map_err(Error::FirewallError)?
- .reset_policy()
- .map_err(Error::FirewallError)
+ Firewall::new(
+ #[cfg(target_os = "linux")]
+ mullvad_types::TUNNEL_FWMARK,
+ )
+ .map_err(Error::FirewallError)?
+ .reset_policy()
+ .map_err(Error::FirewallError)
}
async fn remove_device() -> Result<(), Error> {
diff --git a/mullvad-types/src/lib.rs b/mullvad-types/src/lib.rs
index 6d636aceb5..d157f55467 100644
--- a/mullvad-types/src/lib.rs
+++ b/mullvad-types/src/lib.rs
@@ -14,3 +14,9 @@ pub mod wireguard;
mod custom_tunnel;
pub use crate::custom_tunnel::*;
+
+// b"mole" is [ 0x6d, 0x6f 0x6c, 0x65 ]
+#[cfg(target_os = "linux")]
+pub const TUNNEL_TABLE_ID: u32 = 0x6d6f6c65;
+#[cfg(target_os = "linux")]
+pub const TUNNEL_FWMARK: u32 = 0x6d6f6c65;
diff --git a/mullvad-types/src/relay_list.rs b/mullvad-types/src/relay_list.rs
index 643bcbd798..9e9b77be9d 100644
--- a/mullvad-types/src/relay_list.rs
+++ b/mullvad-types/src/relay_list.rs
@@ -164,11 +164,17 @@ pub struct ShadowsocksEndpointData {
}
impl ShadowsocksEndpointData {
- pub fn to_proxy_settings(&self, addr: IpAddr) -> ProxySettings {
+ pub fn to_proxy_settings(
+ &self,
+ addr: IpAddr,
+ #[cfg(target_os = "linux")] fwmark: u32,
+ ) -> ProxySettings {
ProxySettings::Shadowsocks(ShadowsocksProxySettings {
peer: SocketAddr::new(addr, self.port),
password: self.password.clone(),
cipher: self.cipher.clone(),
+ #[cfg(target_os = "linux")]
+ fwmark: Some(fwmark),
})
}
}
diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml
index fbd231a6a8..162bfd8ea9 100644
--- a/talpid-core/Cargo.toml
+++ b/talpid-core/Cargo.toml
@@ -25,16 +25,17 @@ os_pipe = "0.9"
parking_lot = "0.11"
regex = "1.1.0"
shell-escape = "0.1"
+talpid-routing = { path = "../talpid-routing" }
talpid-types = { path = "../talpid-types" }
talpid-time = { path = "../talpid-time" }
talpid-tunnel-config-client = { path = "../talpid-tunnel-config-client" }
+talpid-tunnel = { path = "../talpid-tunnel" }
+talpid-wireguard = { path = "../talpid-wireguard" }
uuid = { version = "0.8", features = ["v4"] }
zeroize = "1"
chrono = "0.4.21"
tokio = { version = "1.8", features = ["process", "rt-multi-thread", "fs"] }
-tokio-stream = { version = "0.1", features = ["io-util"] }
rand = "0.8.5"
-tunnel-obfuscation = { path = "../tunnel-obfuscation" }
shadowsocks-service = { version = "1.14.3", default-features = false, features = ["local", "stream-cipher"] }
[target.'cfg(not(target_os="android"))'.dependencies]
@@ -42,6 +43,7 @@ byteorder = "1"
internet-checksum = "0.2"
socket2 = { version = "0.4.2", features = ["all"] }
parity-tokio-ipc = "0.9"
+talpid-openvpn = { path = "../talpid-openvpn" }
triggered = "0.1.1"
tonic = "0.8"
prost = "0.11"
@@ -58,10 +60,7 @@ jnix = { version = "0.5", features = ["derive"] }
inotify = "0.10"
resolv-conf = "0.7"
rtnetlink = "0.11"
-netlink-packet-core = "0.4.2"
-netlink-packet-utils = "0.5.1"
netlink-packet-route = "0.13"
-netlink-proto = "0.10"
netlink-sys = "0.8.3"
nftnl = { version = "0.6.2", features = ["nftnl-1-1-0"] }
mnl = { version = "0.2.2", features = ["mnl-1-0-4"] }
@@ -81,10 +80,10 @@ subslice = "0.2"
[target.'cfg(windows)'.dependencies]
widestring = "1.0"
winreg = { version = "0.7", features = ["transactions"] }
-winapi = { version = "0.3.6", features = ["ws2def"] }
talpid-platform-metadata = { path = "../talpid-platform-metadata" }
memoffset = "0.6"
windows-service = "0.5.0"
+talpid-windows-net = { path = "../talpid-windows-net" }
[target.'cfg(windows)'.dependencies.windows]
version = "0.42.0"
@@ -108,7 +107,6 @@ features = [
"Win32_Globalization",
"Win32_Security",
"Win32_Storage_FileSystem",
- "Win32_System_Com",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_Ioctl",
"Win32_System_IO",
diff --git a/talpid-core/build.rs b/talpid-core/build.rs
index 70a1fb6d53..c9bced6bfb 100644
--- a/talpid-core/build.rs
+++ b/talpid-core/build.rs
@@ -1,8 +1,5 @@
-use std::{env, path::PathBuf};
-
#[cfg(windows)]
mod win {
- use super::manifest_dir;
use std::{env, path::PathBuf};
pub static WINFW_BUILD_DIR: &'static str = "..\\windows\\winfw\\bin";
@@ -39,6 +36,12 @@ mod win {
println!("cargo:rustc-link-search={}", lib_dir.display());
println!("cargo:rustc-link-lib=dylib={}", lib_name);
}
+
+ pub fn manifest_dir() -> PathBuf {
+ env::var("CARGO_MANIFEST_DIR")
+ .map(PathBuf::from)
+ .expect("CARGO_MANIFEST_DIR env var not set")
+ }
}
#[cfg(windows)]
@@ -56,38 +59,7 @@ fn main() {
#[cfg(not(windows))]
fn main() {
- generate_grpc_code();
-
- let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set");
-
- declare_libs_dir("../dist-assets/binaries");
- declare_libs_dir("../build/lib");
-
- let link_type = match target_os.as_str() {
- "android" => "",
- "linux" | "macos" => "=static",
- // We would like to avoid panicing on windows even if we can not link correctly
- // because we would like to be able to run check and clippy.
- // This does not allow for correct linking or building.
- "windows" => "",
- _ => panic!("Unsupported platform: {}", target_os),
- };
-
- println!("cargo:rustc-link-lib{}=wg", link_type);
-}
-
-fn manifest_dir() -> PathBuf {
- env::var("CARGO_MANIFEST_DIR")
- .map(PathBuf::from)
- .expect("CARGO_MANIFEST_DIR env var not set")
-}
-
-#[cfg(not(windows))]
-fn declare_libs_dir(base: &str) {
- let target_triplet = env::var("TARGET").expect("TARGET is not set");
- let lib_dir = manifest_dir().join(base).join(target_triplet);
- println!("cargo:rerun-if-changed={}", lib_dir.display());
- println!("cargo:rustc-link-search={}", lib_dir.display());
+ generate_grpc_code()
}
fn generate_grpc_code() {
diff --git a/talpid-core/src/dns/linux/mod.rs b/talpid-core/src/dns/linux/mod.rs
index 3eb11df51a..b7e2ad3f69 100644
--- a/talpid-core/src/dns/linux/mod.rs
+++ b/talpid-core/src/dns/linux/mod.rs
@@ -7,8 +7,8 @@ use self::{
network_manager::NetworkManager, resolvconf::Resolvconf, static_resolv_conf::StaticResolvConf,
systemd_resolved::SystemdResolved,
};
-use crate::routing::RouteManagerHandle;
use std::{env, fmt, net::IpAddr};
+use talpid_routing::RouteManagerHandle;
pub type Result<T> = std::result::Result<T, Error>;
diff --git a/talpid-core/src/dns/linux/network_manager.rs b/talpid-core/src/dns/linux/network_manager.rs
index d44c273cc1..14e3fe7178 100644
--- a/talpid-core/src/dns/linux/network_manager.rs
+++ b/talpid-core/src/dns/linux/network_manager.rs
@@ -13,9 +13,7 @@ pub struct NetworkManager {
impl NetworkManager {
pub fn new() -> Result<Self> {
let connection = DBus::new()?;
- connection.ensure_resolv_conf_is_managed()?;
- connection.ensure_network_manager_exists()?;
- connection.nm_version_dns_works()?;
+ connection.ensure_can_be_used_to_manage_dns()?;
let manager = NetworkManager {
connection,
device: None,
diff --git a/talpid-core/src/dns/linux/systemd_resolved.rs b/talpid-core/src/dns/linux/systemd_resolved.rs
index 321b4181ed..7094a5f28b 100644
--- a/talpid-core/src/dns/linux/systemd_resolved.rs
+++ b/talpid-core/src/dns/linux/systemd_resolved.rs
@@ -1,9 +1,7 @@
-use crate::{
- linux::{iface_index, IfaceIndexLookupError},
- routing::RouteManagerHandle,
-};
+use crate::linux::{iface_index, IfaceIndexLookupError};
use std::net::IpAddr;
use talpid_dbus::systemd_resolved::{AsyncHandle, SystemdResolved as DbusInterface};
+use talpid_routing::RouteManagerHandle;
use talpid_types::ErrorExt;
pub(crate) use talpid_dbus::systemd_resolved::Error as SystemdDbusError;
diff --git a/talpid-core/src/dns/mod.rs b/talpid-core/src/dns/mod.rs
index 900b32e902..ca06251f55 100644
--- a/talpid-core/src/dns/mod.rs
+++ b/talpid-core/src/dns/mod.rs
@@ -1,6 +1,6 @@
-#[cfg(target_os = "linux")]
-use crate::routing::RouteManagerHandle;
use std::net::IpAddr;
+#[cfg(target_os = "linux")]
+use talpid_routing::RouteManagerHandle;
#[cfg(target_os = "macos")]
use {
diff --git a/talpid-core/src/dns/windows/mod.rs b/talpid-core/src/dns/windows/mod.rs
index d173290be3..9b780b1f54 100644
--- a/talpid-core/src/dns/windows/mod.rs
+++ b/talpid-core/src/dns/windows/mod.rs
@@ -1,7 +1,7 @@
-use crate::windows::{guid_from_luid, luid_from_alias, string_from_guid};
use std::{io, net::IpAddr};
use talpid_types::ErrorExt;
-use windows_sys::core::GUID;
+use talpid_windows_net::{guid_from_luid, luid_from_alias};
+use windows_sys::{core::GUID, Win32::System::Com::StringFromGUID2};
use winreg::{
enums::{HKEY_LOCAL_MACHINE, KEY_SET_VALUE},
transaction::Transaction,
@@ -144,3 +144,14 @@ fn config_interface<'a>(
fn flush_dns_cache() -> Result<(), Error> {
dnsapi::flush_resolver_cache().map_err(Error::FlushResolverCacheError)
}
+
+/// Obtain a string representation for a GUID object.
+fn string_from_guid(guid: &GUID) -> String {
+ let mut buffer = [0u16; 40];
+ let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) }
+ as usize;
+ // cannot fail because `buffer` is large enough
+ assert!(length > 0);
+ let length = length - 1;
+ String::from_utf16(&buffer[0..length]).unwrap()
+}
diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs
index b873d71b62..14900afb51 100644
--- a/talpid-core/src/firewall/linux.rs
+++ b/talpid-core/src/firewall/linux.rs
@@ -11,7 +11,7 @@ use nftnl::{
use std::{
env,
ffi::{CStr, CString},
- io,
+ fs, io,
net::{IpAddr, Ipv4Addr},
};
use talpid_types::net::{AllowedTunnelTraffic, Endpoint, TransportProtocol};
@@ -19,6 +19,7 @@ use talpid_types::net::{AllowedTunnelTraffic, Endpoint, TransportProtocol};
/// Priority for rules that tag split tunneling packets. Equals NF_IP_PRI_MANGLE.
const MANGLE_CHAIN_PRIORITY: i32 = libc::NF_IP_PRI_MANGLE;
const PREROUTING_CHAIN_PRIORITY: i32 = libc::NF_IP_PRI_CONNTRACK + 1;
+const PROC_SYS_NET_IPV4_CONF_SRC_VALID_MARK: &str = "/proc/sys/net/ipv4/conf/all/src_valid_mark";
pub type Result<T> = std::result::Result<T, Error>;
@@ -96,7 +97,9 @@ enum End {
}
/// The Linux implementation for the firewall and DNS.
-pub struct Firewall(());
+pub struct Firewall {
+ fwmark: u32,
+}
struct FirewallTables {
main: Table,
@@ -105,12 +108,12 @@ struct FirewallTables {
}
impl Firewall {
- pub fn from_args(_args: FirewallArguments) -> Result<Self> {
- Ok(Firewall(()))
+ pub fn from_args(args: FirewallArguments) -> Result<Self> {
+ Firewall::new(args.fwmark)
}
- pub fn new() -> Result<Self> {
- Ok(Firewall(()))
+ pub fn new(fwmark: u32) -> Result<Self> {
+ Ok(Firewall { fwmark })
}
pub fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> {
@@ -119,7 +122,7 @@ impl Firewall {
mangle_v4: Table::new(&*MANGLE_TABLE_NAME_V4, ProtoFamily::Ipv4),
mangle_v6: Table::new(&*MANGLE_TABLE_NAME_V6, ProtoFamily::Ipv6),
};
- let batch = PolicyBatch::new(&tables).finalize(&policy)?;
+ let batch = PolicyBatch::new(&tables).finalize(&policy, self.fwmark)?;
Self::send_and_process(&batch)?;
Self::apply_kernel_config(&policy);
self.verify_tables(&[&TABLE_NAME, &MANGLE_TABLE_NAME_V4, &MANGLE_TABLE_NAME_V6])
@@ -152,7 +155,7 @@ impl Firewall {
}
if let FirewallPolicy::Connecting { .. } = policy {
- if let Err(err) = crate::linux::set_src_valid_mark_sysctl() {
+ if let Err(err) = set_src_valid_mark_sysctl() {
log::error!("Failed to apply src_valid_mark: {}", err);
}
}
@@ -314,17 +317,17 @@ impl<'a> PolicyBatch<'a> {
/// Finalize the nftnl message batch by adding every firewall rule needed to satisfy the given
/// policy.
- pub fn finalize(mut self, policy: &FirewallPolicy) -> Result<FinalizedBatch> {
+ pub fn finalize(mut self, policy: &FirewallPolicy, fwmark: u32) -> Result<FinalizedBatch> {
self.add_loopback_rules()?;
- self.add_split_tunneling_rules(policy)?;
+ self.add_split_tunneling_rules(policy, fwmark)?;
self.add_dhcp_client_rules();
self.add_ndp_rules();
- self.add_policy_specific_rules(policy)?;
+ self.add_policy_specific_rules(policy, fwmark)?;
Ok(self.batch.finalize())
}
- fn add_split_tunneling_rules(&mut self, policy: &FirewallPolicy) -> Result<()> {
+ fn add_split_tunneling_rules(&mut self, policy: &FirewallPolicy, fwmark: u32) -> Result<()> {
// Send select DNS requests in the tunnel
if let FirewallPolicy::Connected {
tunnel,
@@ -365,7 +368,7 @@ impl<'a> PolicyBatch<'a> {
rule.add_expr(&nft_expr!(cmp == split_tunnel::NET_CLS_CLASSID));
rule.add_expr(&nft_expr!(immediate data split_tunnel::MARK));
rule.add_expr(&nft_expr!(ct mark set));
- rule.add_expr(&nft_expr!(immediate data crate::linux::TUNNEL_FW_MARK));
+ rule.add_expr(&nft_expr!(immediate data fwmark));
rule.add_expr(&nft_expr!(meta mark set));
self.batch.add(&rule, nftnl::MsgType::Add);
}
@@ -416,7 +419,7 @@ impl<'a> PolicyBatch<'a> {
check_not_iface(&mut prerouting_rule, Direction::In, &tunnel.interface)?;
prerouting_rule.add_expr(&nft_expr!(ct mark));
prerouting_rule.add_expr(&nft_expr!(cmp == split_tunnel::MARK));
- prerouting_rule.add_expr(&nft_expr!(immediate data crate::linux::TUNNEL_FW_MARK));
+ prerouting_rule.add_expr(&nft_expr!(immediate data fwmark));
prerouting_rule.add_expr(&nft_expr!(meta mark set));
if *ADD_COUNTERS {
prerouting_rule.add_expr(&nft_expr!(counter));
@@ -551,7 +554,7 @@ impl<'a> PolicyBatch<'a> {
}
}
- fn add_policy_specific_rules(&mut self, policy: &FirewallPolicy) -> Result<()> {
+ fn add_policy_specific_rules(&mut self, policy: &FirewallPolicy, fwmark: u32) -> Result<()> {
let allow_lan = match policy {
FirewallPolicy::Connecting {
peer_endpoint,
@@ -560,7 +563,7 @@ impl<'a> PolicyBatch<'a> {
allowed_endpoint,
allowed_tunnel_traffic,
} => {
- self.add_allow_tunnel_endpoint_rules(peer_endpoint);
+ self.add_allow_tunnel_endpoint_rules(peer_endpoint, fwmark);
self.add_allow_endpoint_rules(&allowed_endpoint.endpoint);
// Important to block DNS after allow relay rule (so the relay can operate
@@ -589,7 +592,7 @@ impl<'a> PolicyBatch<'a> {
allow_lan,
dns_servers,
} => {
- self.add_allow_tunnel_endpoint_rules(peer_endpoint);
+ self.add_allow_tunnel_endpoint_rules(peer_endpoint, fwmark);
self.add_allow_dns_rules(tunnel, dns_servers, TransportProtocol::Udp)?;
self.add_allow_dns_rules(tunnel, dns_servers, TransportProtocol::Tcp)?;
// Important to block DNS *before* we allow the tunnel and allow LAN. So DNS
@@ -632,10 +635,10 @@ impl<'a> PolicyBatch<'a> {
Ok(())
}
- fn add_allow_tunnel_endpoint_rules(&mut self, endpoint: &Endpoint) {
+ fn add_allow_tunnel_endpoint_rules(&mut self, endpoint: &Endpoint, fwmark: u32) {
let mut prerouting_rule = Rule::new(&self.prerouting_chain);
check_endpoint(&mut prerouting_rule, End::Src, endpoint);
- prerouting_rule.add_expr(&nft_expr!(immediate data crate::linux::TUNNEL_FW_MARK));
+ prerouting_rule.add_expr(&nft_expr!(immediate data fwmark));
prerouting_rule.add_expr(&nft_expr!(meta mark set));
if *ADD_COUNTERS {
@@ -658,7 +661,7 @@ impl<'a> PolicyBatch<'a> {
let mut out_rule = Rule::new(&self.out_chain);
check_endpoint(&mut out_rule, End::Dst, endpoint);
out_rule.add_expr(&nft_expr!(meta mark));
- out_rule.add_expr(&nft_expr!(cmp == crate::linux::TUNNEL_FW_MARK));
+ out_rule.add_expr(&nft_expr!(cmp == fwmark));
add_verdict(&mut out_rule, &Verdict::Accept);
self.batch.add(&out_rule, nftnl::MsgType::Add);
@@ -1059,3 +1062,7 @@ fn add_verdict(rule: &mut Rule<'_>, verdict: &expr::Verdict) {
}
rule.add_expr(verdict);
}
+
+fn set_src_valid_mark_sysctl() -> io::Result<()> {
+ fs::write(PROC_SYS_NET_IPV4_CONF_SRC_VALID_MARK, b"1")
+}
diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs
index 5aea81cc90..dcd0c2bfb8 100644
--- a/talpid-core/src/firewall/mod.rs
+++ b/talpid-core/src/firewall/mod.rs
@@ -233,6 +233,10 @@ pub struct FirewallArguments {
pub initial_state: InitialFirewallState,
/// This argument is required for the blocked state to configure the firewall correctly.
pub allow_lan: bool,
+ /// Specifies the firewall mark used to identify traffic that is allowed to be excluded from
+ /// the tunnel and _leaked_ during blocked states.
+ #[cfg(target_os = "linux")]
+ pub fwmark: u32,
}
/// State to enter during firewall init.
@@ -252,9 +256,12 @@ impl Firewall {
}
/// Createsa new firewall instance.
- pub fn new() -> Result<Self, Error> {
+ pub fn new(#[cfg(target_os = "linux")] fwmark: u32) -> Result<Self, Error> {
Ok(Firewall {
- inner: imp::Firewall::new()?,
+ inner: imp::Firewall::new(
+ #[cfg(target_os = "linux")]
+ fwmark,
+ )?,
})
}
diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs
index 23be309a63..e2854e0197 100644
--- a/talpid-core/src/firewall/windows.rs
+++ b/talpid-core/src/firewall/windows.rs
@@ -1,6 +1,6 @@
-use crate::{logging::windows::log_sink, tunnel::TunnelMetadata};
+use crate::tunnel::TunnelMetadata;
-use std::{net::IpAddr, path::Path, ptr};
+use std::{ffi::CStr, io, net::IpAddr, path::Path, ptr};
use self::winfw::*;
use super::{FirewallArguments, FirewallPolicy, InitialFirewallState};
@@ -9,6 +9,7 @@ use talpid_types::{
tunnel::FirewallPolicyError,
};
use widestring::WideCString;
+use windows_sys::Win32::Globalization::{MultiByteToWideChar, CP_ACP};
/// Errors that can happen when configuring the Windows firewall.
#[derive(err_derive::Error, Debug)]
@@ -294,13 +295,91 @@ fn widestring_ip(ip: IpAddr) -> WideCString {
WideCString::from_str_truncate(ip.to_string())
}
+/// Logging callback implementation.
+pub extern "system" fn log_sink(
+ level: log::Level,
+ msg: *const libc::c_char,
+ context: *mut libc::c_void,
+) {
+ if msg.is_null() {
+ log::error!("Log message from FFI boundary is NULL");
+ } else {
+ let rust_log_level = log::Level::from(level);
+ let target = if context.is_null() {
+ "UNKNOWN".into()
+ } else {
+ unsafe { CStr::from_ptr(context as *const _).to_string_lossy() }
+ };
+
+ let mb_string = unsafe { CStr::from_ptr(msg) };
+
+ let managed_msg = match multibyte_to_wide(mb_string, CP_ACP) {
+ Ok(wide_str) => String::from_utf16_lossy(&wide_str),
+ // Best effort:
+ Err(_) => mb_string.to_string_lossy().into_owned(),
+ };
+
+ log::logger().log(
+ &log::Record::builder()
+ .level(rust_log_level)
+ .target(&target)
+ .args(format_args!("{}", managed_msg))
+ .build(),
+ );
+ }
+}
+
+fn multibyte_to_wide(mb_string: &CStr, codepage: u32) -> Result<Vec<u16>, io::Error> {
+ if unsafe { *mb_string.as_ptr() } == 0 {
+ return Ok(vec![]);
+ }
+
+ let wc_size = unsafe {
+ MultiByteToWideChar(
+ codepage,
+ 0,
+ mb_string.as_ptr() as *const u8,
+ -1,
+ ptr::null_mut(),
+ 0,
+ )
+ };
+
+ if wc_size == 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ let mut wc_buffer = Vec::with_capacity(wc_size as usize);
+
+ let chars_written = unsafe {
+ MultiByteToWideChar(
+ codepage,
+ 0,
+ mb_string.as_ptr() as *const u8,
+ -1,
+ wc_buffer.as_mut_ptr(),
+ wc_size,
+ )
+ };
+
+ if chars_written == 0 {
+ return Err(io::Error::last_os_error());
+ }
+
+ unsafe { wc_buffer.set_len((chars_written - 1) as usize) };
+
+ Ok(wc_buffer)
+}
+
#[allow(non_snake_case)]
mod winfw {
use super::{widestring_ip, AllowedEndpoint, AllowedTunnelTraffic, Error, WideCString};
- use crate::logging::windows::LogSink;
use libc;
use talpid_types::net::TransportProtocol;
+ type LogSink =
+ extern "system" fn(level: log::Level, msg: *const libc::c_char, context: *mut libc::c_void);
+
pub struct WinFwAllowedEndpointContainer {
_clients: Box<[WideCString]>,
clients_ptrs: Box<[*const u16]>,
diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs
index 46bb4c1169..cc908bbfbe 100644
--- a/talpid-core/src/lib.rs
+++ b/talpid-core/src/lib.rs
@@ -9,24 +9,15 @@
#[macro_use]
mod ffi;
-/// Windows API wrappers and utilities
+/// Window API wrappers and utilities
#[cfg(target_os = "windows")]
-pub mod windows;
-
-#[cfg(any(target_os = "linux", target_os = "macos"))]
-/// Working with IP interface devices
-pub mod network_interface;
-/// Abstraction over operating system routing table.
-pub mod routing;
+pub mod window;
mod offline;
/// Split tunneling
pub mod split_tunnel;
-/// Working with processes.
-pub mod process;
-
/// Abstracts over different VPN tunnel technologies
pub mod tunnel;
@@ -48,20 +39,10 @@ pub mod tunnel_state_machine;
/// Future utilities
pub mod future_retry;
-#[cfg(not(target_os = "android"))]
-/// Internal code for managing bundled proxy software.
-mod proxy;
-
-#[cfg(not(target_os = "android"))]
-mod mktemp;
-
/// Misc utilities for the Linux platform.
#[cfg(target_os = "linux")]
mod linux;
-/// A pair of functions to monitor and establish connectivity with ICMP
-pub mod ping_monitor;
-
/// A resolver that's controlled by the tunnel state machine
#[cfg(target_os = "macos")]
pub mod resolver;
diff --git a/talpid-core/src/linux/mod.rs b/talpid-core/src/linux/mod.rs
index 6c070c1985..05655bf4be 100644
--- a/talpid-core/src/linux/mod.rs
+++ b/talpid-core/src/linux/mod.rs
@@ -1,10 +1,8 @@
use std::{
ffi::{self, CString},
- fs, io,
+ io,
};
-const PROC_SYS_NET_IPV4_CONF_SRC_VALID_MARK: &str = "/proc/sys/net/ipv4/conf/all/src_valid_mark";
-
/// Converts an interface name into the corresponding index.
pub fn iface_index(name: &str) -> Result<libc::c_uint, IfaceIndexLookupError> {
let c_name = CString::new(name)
@@ -27,11 +25,3 @@ pub enum IfaceIndexLookupError {
#[error(display = "Failed to get index for interface {}", _0)]
InterfaceLookupError(String, #[error(source)] io::Error),
}
-
-// b"mole" is [ 0x6d, 0x6f 0x6c, 0x65 ]
-pub const TUNNEL_FW_MARK: u32 = 0x6d6f6c65;
-pub const TUNNEL_TABLE_ID: u32 = 0x6d6f6c65;
-
-pub fn set_src_valid_mark_sysctl() -> io::Result<()> {
- fs::write(PROC_SYS_NET_IPV4_CONF_SRC_VALID_MARK, b"1")
-}
diff --git a/talpid-core/src/logging/mod.rs b/talpid-core/src/logging/mod.rs
index 41791fe668..3251a39799 100644
--- a/talpid-core/src/logging/mod.rs
+++ b/talpid-core/src/logging/mod.rs
@@ -1,9 +1,5 @@
use std::{fs, io, path::Path};
-/// Types/implementations for logging through a callback.
-#[cfg(windows)]
-pub mod windows;
-
/// Unable to create new log file
#[derive(err_derive::Error, Debug)]
#[error(display = "Unable to create new log file")]
diff --git a/talpid-core/src/logging/windows.rs b/talpid-core/src/logging/windows.rs
deleted file mode 100644
index 2558660a5b..0000000000
--- a/talpid-core/src/logging/windows.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-use libc::{c_char, c_void};
-use std::{ffi::CStr, io, ptr};
-use windows_sys::Win32::Globalization::{MultiByteToWideChar, CP_ACP};
-
-/// Logging callback type.
-pub type LogSink = extern "system" fn(level: log::Level, msg: *const c_char, context: *mut c_void);
-
-/// Logging callback implementation.
-pub extern "system" fn log_sink(level: log::Level, msg: *const c_char, context: *mut c_void) {
- if msg.is_null() {
- log::error!("Log message from FFI boundary is NULL");
- } else {
- let rust_log_level = log::Level::from(level);
- let target = if context.is_null() {
- "UNKNOWN".into()
- } else {
- unsafe { CStr::from_ptr(context as *const _).to_string_lossy() }
- };
-
- let mb_string = unsafe { CStr::from_ptr(msg) };
-
- let managed_msg = match multibyte_to_wide(mb_string, CP_ACP) {
- Ok(wide_str) => String::from_utf16_lossy(&wide_str),
- // Best effort:
- Err(_) => mb_string.to_string_lossy().into_owned(),
- };
-
- log::logger().log(
- &log::Record::builder()
- .level(rust_log_level)
- .target(&target)
- .args(format_args!("{}", managed_msg))
- .build(),
- );
- }
-}
-
-fn multibyte_to_wide(mb_string: &CStr, codepage: u32) -> Result<Vec<u16>, io::Error> {
- if unsafe { *mb_string.as_ptr() } == 0 {
- return Ok(vec![]);
- }
-
- let wc_size = unsafe {
- MultiByteToWideChar(
- codepage,
- 0,
- mb_string.as_ptr() as *const u8,
- -1,
- ptr::null_mut(),
- 0,
- )
- };
-
- if wc_size == 0 {
- return Err(io::Error::last_os_error());
- }
-
- let mut wc_buffer = Vec::with_capacity(wc_size as usize);
-
- let chars_written = unsafe {
- MultiByteToWideChar(
- codepage,
- 0,
- mb_string.as_ptr() as *const u8,
- -1,
- wc_buffer.as_mut_ptr(),
- wc_size,
- )
- };
-
- if chars_written == 0 {
- return Err(io::Error::last_os_error());
- }
-
- unsafe { wc_buffer.set_len((chars_written - 1) as usize) };
-
- Ok(wc_buffer)
-}
diff --git a/talpid-core/src/offline/linux.rs b/talpid-core/src/offline/linux.rs
index 913202f08c..09db30e359 100644
--- a/talpid-core/src/offline/linux.rs
+++ b/talpid-core/src/offline/linux.rs
@@ -1,9 +1,9 @@
-use crate::routing::{self, RouteManagerHandle};
use futures::{channel::mpsc::UnboundedSender, StreamExt};
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::Arc,
};
+use talpid_routing::{self, RouteManagerHandle};
use talpid_types::ErrorExt;
pub type Result<T> = std::result::Result<T, Error>;
@@ -12,11 +12,12 @@ pub type Result<T> = std::result::Result<T, Error>;
#[error(no_from)]
pub enum Error {
#[error(display = "The route manager returned an error")]
- RouteManagerError(#[error(source)] routing::Error),
+ RouteManagerError(#[error(source)] talpid_routing::Error),
}
pub struct MonitorHandle {
route_manager: RouteManagerHandle,
+ fwmark: Option<u32>,
_notify_tx: Arc<UnboundedSender<bool>>,
}
@@ -26,7 +27,7 @@ const PUBLIC_INTERNET_ADDRESS_V6: IpAddr =
impl MonitorHandle {
pub async fn host_is_offline(&self) -> bool {
- match public_ip_unreachable(&self.route_manager).await {
+ match public_ip_unreachable(&self.route_manager, self.fwmark).await {
Ok(is_offline) => is_offline,
Err(err) => {
log::error!(
@@ -42,8 +43,9 @@ impl MonitorHandle {
pub async fn spawn_monitor(
notify_tx: UnboundedSender<bool>,
route_manager: RouteManagerHandle,
+ fwmark: Option<u32>,
) -> Result<MonitorHandle> {
- let mut is_offline = public_ip_unreachable(&route_manager).await?;
+ let mut is_offline = public_ip_unreachable(&route_manager, fwmark).await?;
let mut listener = route_manager
.change_listener()
@@ -54,6 +56,7 @@ pub async fn spawn_monitor(
let sender = Arc::downgrade(&notify_tx);
let monitor_handle = MonitorHandle {
route_manager: route_manager.clone(),
+ fwmark,
_notify_tx: notify_tx,
};
@@ -61,7 +64,7 @@ pub async fn spawn_monitor(
while let Some(_event) = listener.next().await {
match sender.upgrade() {
Some(sender) => {
- let new_offline_state = public_ip_unreachable(&route_manager)
+ let new_offline_state = public_ip_unreachable(&route_manager, fwmark)
.await
.unwrap_or_else(|err| {
log::error!(
@@ -83,14 +86,14 @@ pub async fn spawn_monitor(
Ok(monitor_handle)
}
-async fn public_ip_unreachable(handle: &RouteManagerHandle) -> Result<bool> {
+async fn public_ip_unreachable(handle: &RouteManagerHandle, fwmark: Option<u32>) -> Result<bool> {
Ok(handle
- .get_destination_route(PUBLIC_INTERNET_ADDRESS_V4, true)
+ .get_destination_route(PUBLIC_INTERNET_ADDRESS_V4, fwmark)
.await
.map_err(Error::RouteManagerError)?
.is_none()
&& handle
- .get_destination_route(PUBLIC_INTERNET_ADDRESS_V6, true)
+ .get_destination_route(PUBLIC_INTERNET_ADDRESS_V6, fwmark)
.await
.unwrap_or(None)
.is_none())
diff --git a/talpid-core/src/offline/macos.rs b/talpid-core/src/offline/macos.rs
index 20e2145e4f..baae3c40f1 100644
--- a/talpid-core/src/offline/macos.rs
+++ b/talpid-core/src/offline/macos.rs
@@ -27,7 +27,7 @@ use talpid_types::ErrorExt;
#[derive(err_derive::Error, Debug)]
pub enum Error {
#[error(display = "Failed to initialize route monitor")]
- StartMonitorError(#[error(source)] crate::routing::PlatformError),
+ StartMonitorError(#[error(source)] talpid_routing::PlatformError),
}
pub struct MonitorHandle {
@@ -43,7 +43,7 @@ impl MonitorHandle {
}
async fn exists_non_tunnel_default_route() -> bool {
- match crate::routing::get_default_routes().await {
+ match talpid_routing::get_default_routes().await {
Ok((Some(node), _)) | Ok((None, Some(node))) => {
let route_exists = node
.get_device()
@@ -85,7 +85,7 @@ pub async fn spawn_monitor(notify_tx: UnboundedSender<bool>) -> Result<MonitorHa
fn watch_route_monitor(
mut context: OfflineStateContext,
) -> Result<impl Future<Output = ()>, Error> {
- let mut monitor = crate::routing::listen_for_default_route_changes()?;
+ let mut monitor = talpid_routing::listen_for_default_route_changes()?;
Ok(async move {
while let Some(_route_change) = monitor.next().await {
diff --git a/talpid-core/src/offline/mod.rs b/talpid-core/src/offline/mod.rs
index 3c5448762b..a227b5e102 100644
--- a/talpid-core/src/offline/mod.rs
+++ b/talpid-core/src/offline/mod.rs
@@ -1,8 +1,8 @@
-#[cfg(any(target_os = "linux", target_os = "windows"))]
-use crate::routing::RouteManagerHandle;
#[cfg(target_os = "windows")]
-use crate::windows::window::PowerManagementListener;
+use crate::window::PowerManagementListener;
use futures::channel::mpsc::UnboundedSender;
+#[cfg(any(target_os = "linux", target_os = "windows"))]
+use talpid_routing::RouteManagerHandle;
#[cfg(target_os = "android")]
use talpid_types::android::AndroidContext;
@@ -44,22 +44,22 @@ impl MonitorHandle {
pub async fn spawn_monitor(
sender: UnboundedSender<bool>,
- #[cfg(target_os = "linux")] route_manager: RouteManagerHandle,
+ #[cfg(any(target_os = "linux", target_os = "windows"))] route_manager: RouteManagerHandle,
+ #[cfg(target_os = "linux")] fwmark: Option<u32>,
#[cfg(target_os = "android")] android_context: AndroidContext,
- #[cfg(target_os = "windows")] route_manager: RouteManagerHandle,
#[cfg(target_os = "windows")] power_mgmt_rx: PowerManagementListener,
) -> Result<MonitorHandle, Error> {
let monitor = if !*FORCE_DISABLE_OFFLINE_MONITOR {
Some(
imp::spawn_monitor(
sender,
- #[cfg(target_os = "linux")]
+ #[cfg(any(target_os = "windows", target_os = "linux"))]
route_manager,
+ #[cfg(target_os = "linux")]
+ fwmark,
#[cfg(target_os = "android")]
android_context,
#[cfg(target_os = "windows")]
- route_manager,
- #[cfg(target_os = "windows")]
power_mgmt_rx,
)
.await?,
diff --git a/talpid-core/src/offline/windows.rs b/talpid-core/src/offline/windows.rs
index 9dc341d03a..0709caa4ea 100644
--- a/talpid-core/src/offline/windows.rs
+++ b/talpid-core/src/offline/windows.rs
@@ -1,10 +1,6 @@
-use crate::{
- routing::{get_best_default_route, CallbackHandle, EventType, RouteManagerHandle},
- windows::{
- window::{PowerManagementEvent, PowerManagementListener},
- AddressFamily,
- },
-};
+use talpid_routing::{get_best_default_route, CallbackHandle, EventType, RouteManagerHandle};
+
+use crate::window::{PowerManagementEvent, PowerManagementListener};
use futures::channel::mpsc::UnboundedSender;
use parking_lot::Mutex;
use std::{
@@ -13,13 +9,14 @@ use std::{
time::Duration,
};
use talpid_types::ErrorExt;
+use talpid_windows_net::AddressFamily;
#[derive(err_derive::Error, Debug)]
pub enum Error {
#[error(display = "Unable to create listener thread")]
ThreadCreationError(#[error(source)] io::Error),
#[error(display = "Failed to start connectivity monitor")]
- ConnectivityMonitorError(#[error(source)] crate::routing::Error),
+ ConnectivityMonitorError(#[error(source)] talpid_routing::Error),
}
pub struct BroadcastListener {
@@ -125,7 +122,7 @@ impl BroadcastListener {
family: AddressFamily,
state_lock: &Arc<Mutex<SystemState>>,
) {
- use crate::routing::EventType::*;
+ use talpid_routing::EventType::*;
if matches!(event_type, UpdatedDetails(_)) {
// ignore changes that don't affect the route
diff --git a/talpid-core/src/split_tunnel/windows/driver.rs b/talpid-core/src/split_tunnel/windows/driver.rs
index b03d8b72af..2eb9aecd30 100644
--- a/talpid-core/src/split_tunnel/windows/driver.rs
+++ b/talpid-core/src/split_tunnel/windows/driver.rs
@@ -2,7 +2,6 @@ use super::windows::{
get_device_path, get_process_creation_time, get_process_device_path, open_process, Event,
Overlapped, ProcessAccess, ProcessSnapshot,
};
-use crate::windows::as_uninit_byte_slice;
use bitflags::bitflags;
use memoffset::offset_of;
use std::{
@@ -994,3 +993,8 @@ fn write_string_to_buffer(buffer: &mut [MaybeUninit<u8>], byte_offset: usize, st
buffer[byte_offset + i] = MaybeUninit::new(byte);
}
}
+
+/// Casts a struct to a slice of possibly uninitialized bytes.
+pub fn as_uninit_byte_slice<T: Copy + Sized>(value: &T) -> &[mem::MaybeUninit<u8>] {
+ unsafe { std::slice::from_raw_parts(value as *const _ as *const _, mem::size_of::<T>()) }
+}
diff --git a/talpid-core/src/split_tunnel/windows/mod.rs b/talpid-core/src/split_tunnel/windows/mod.rs
index 49028319a0..f10184ae74 100644
--- a/talpid-core/src/split_tunnel/windows/mod.rs
+++ b/talpid-core/src/split_tunnel/windows/mod.rs
@@ -5,14 +5,9 @@ mod volume_monitor;
mod windows;
use crate::{
- routing::{self, get_best_default_route, CallbackHandle, EventType, RouteManagerHandle},
tunnel::TunnelMetadata,
tunnel_state_machine::TunnelCommand,
- windows::{
- get_ip_address_for_interface,
- window::{PowerManagementEvent, PowerManagementListener},
- AddressFamily,
- },
+ window::{PowerManagementEvent, PowerManagementListener},
};
use futures::channel::{mpsc, oneshot};
use std::{
@@ -28,7 +23,9 @@ use std::{
},
time::Duration,
};
+use talpid_routing::{get_best_default_route, CallbackHandle, EventType, RouteManagerHandle};
use talpid_types::{tunnel::ErrorStateCause, ErrorExt};
+use talpid_windows_net::{get_ip_address_for_interface, AddressFamily};
use windows_sys::Win32::Foundation::ERROR_OPERATION_ABORTED;
const DRIVER_EVENT_BUFFER_SIZE: usize = 2048;
@@ -72,11 +69,11 @@ pub enum Error {
/// Failed to obtain default route
#[error(display = "Failed to obtain the default route")]
- ObtainDefaultRoute(#[error(source)] routing::Error),
+ ObtainDefaultRoute(#[error(source)] talpid_routing::Error),
/// Failed to obtain an IP address given a network interface LUID
#[error(display = "Failed to obtain IP address for interface LUID")]
- LuidToIp(#[error(source)] crate::windows::Error),
+ LuidToIp(#[error(source)] talpid_windows_net::Error),
/// Failed to set up callback for monitoring default route changes
#[error(display = "Failed to register default route change callback")]
@@ -854,7 +851,7 @@ fn split_tunnel_default_route_change_handler<'a>(
address_family: AddressFamily,
ctx_mutex: &Arc<Mutex<SplitTunnelDefaultRouteChangeHandlerContext>>,
) {
- use crate::routing::EventType::*;
+ use talpid_routing::EventType::*;
// Update the "internet interface" IP when best default route changes
let mut ctx = ctx_mutex.lock().expect("ST route handler mutex poisoned");
diff --git a/talpid-core/src/split_tunnel/windows/volume_monitor.rs b/talpid-core/src/split_tunnel/windows/volume_monitor.rs
index 0758463399..34ba36089e 100644
--- a/talpid-core/src/split_tunnel/windows/volume_monitor.rs
+++ b/talpid-core/src/split_tunnel/windows/volume_monitor.rs
@@ -1,7 +1,7 @@
//! Used to monitor volume mounts and dismounts, and reapply the split
//! tunnel config if any of the excluded paths are affected by them.
use super::path_monitor::PathMonitorHandle;
-use crate::windows::window::{create_hidden_window, WindowCloseHandle};
+use crate::window::{create_hidden_window, WindowCloseHandle};
use futures::{channel::mpsc, StreamExt};
use std::{
ffi::OsString,
diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs
index 4425c3c69d..a8d5792d5b 100644
--- a/talpid-core/src/tunnel/mod.rs
+++ b/talpid-core/src/tunnel/mod.rs
@@ -1,30 +1,18 @@
-use self::tun_provider::TunProvider;
-use crate::{logging, routing::RouteManagerHandle};
-use futures::{channel::oneshot, future::BoxFuture};
-use std::{
- net::{IpAddr, Ipv4Addr, Ipv6Addr},
- path::{Path, PathBuf},
- sync::{Arc, Mutex},
-};
+use crate::logging;
#[cfg(not(target_os = "android"))]
-use talpid_types::net::openvpn as openvpn_types;
-use talpid_types::net::{wireguard as wireguard_types, AllowedTunnelTraffic, TunnelParameters};
-
-#[cfg(target_os = "android")]
-pub use self::tun_provider::TunConfig;
-
-#[cfg(target_os = "windows")]
-mod windows;
-
-/// A module for all OpenVPN related tunnel management.
+use futures::channel::oneshot;
+use std::path;
+#[cfg(not(target_os = "android"))]
+use talpid_openvpn;
+#[cfg(any(target_os = "linux", target_os = "windows"))]
+use talpid_routing::RouteManagerHandle;
+pub use talpid_tunnel::{TunnelArgs, TunnelEvent, TunnelMetadata};
#[cfg(not(target_os = "android"))]
-pub mod openvpn;
+use talpid_types::net::openvpn as openvpn_types;
+use talpid_types::net::{wireguard as wireguard_types, TunnelParameters};
/// A module for all WireGuard related tunnel management.
-pub mod wireguard;
-
-/// A module for low level platform specific tunnel device management.
-pub(crate) mod tun_provider;
+use talpid_wireguard;
const OPENVPN_LOG_FILENAME: &str = "openvpn.log";
const WIREGUARD_LOG_FILENAME: &str = "wireguard.log";
@@ -42,7 +30,7 @@ pub enum Error {
/// Failure in Windows syscall.
#[cfg(windows)]
#[error(display = "Failure in Windows syscall")]
- WinnetError(#[error(source)] crate::routing::Error),
+ WinnetError(#[error(source)] talpid_routing::Error),
/// Running on an operating system which is not supported yet.
#[error(display = "Tunnel type not supported on this operating system")]
@@ -54,75 +42,27 @@ pub enum Error {
/// Failure to build Wireguard configuration.
#[error(display = "Failed to configure Wireguard with the given parameters")]
- WireguardConfigError(#[error(source)] self::wireguard::config::Error),
+ WireguardConfigError(#[error(source)] talpid_wireguard::config::Error),
/// There was an error listening for events from the OpenVPN tunnel
#[cfg(not(target_os = "android"))]
#[error(display = "Failed while listening for events from the OpenVPN tunnel")]
- OpenVpnTunnelMonitoringError(#[error(source)] openvpn::Error),
+ OpenVpnTunnelMonitoringError(#[error(source)] talpid_openvpn::Error),
/// There was an error listening for events from the Wireguard tunnel
#[error(display = "Failed while listening for events from the Wireguard tunnel")]
- WireguardTunnelMonitoringError(#[error(source)] wireguard::Error),
+ WireguardTunnelMonitoringError(#[error(source)] talpid_wireguard::Error),
/// Could not detect and assign the correct mtu
#[error(display = "Could not detect and assign a correct MTU for the Wireguard tunnel")]
AssignMtuError,
}
-/// Possible events from the VPN tunnel and the child process managing it.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum TunnelEvent {
- /// Sent when the tunnel fails to connect due to an authentication error.
- AuthFailed(Option<String>),
- /// Sent when the tunnel interface has been created, before routes are set up.
- InterfaceUp(TunnelMetadata, AllowedTunnelTraffic),
- /// Sent when the tunnel comes up and is ready for traffic.
- Up(TunnelMetadata),
- /// Sent when the tunnel goes down.
- Down,
-}
-
-/// Information about a VPN tunnel.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct TunnelMetadata {
- /// The name of the device which the tunnel is running on.
- pub interface: String,
- /// The local IPs on the tunnel interface.
- pub ips: Vec<IpAddr>,
- /// The IP to the default gateway on the tunnel interface.
- pub ipv4_gateway: Ipv4Addr,
- /// The IP to the IPv6 default gateway on the tunnel interface.
- pub ipv6_gateway: Option<Ipv6Addr>,
-}
-
/// Abstraction for monitoring a generic VPN tunnel.
pub struct TunnelMonitor {
monitor: InternalTunnelMonitor,
}
-/// Arguments for creating a tunnel.
-pub struct TunnelArgs<'a, L>
-where
- // L: (Fn(TunnelEvent) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>)
- L: (Fn(TunnelEvent) -> BoxFuture<'static, ()>) + Send + Clone + Sync + 'static,
-{
- /// Toktio runtime handle.
- pub runtime: tokio::runtime::Handle,
- /// Resource directory path.
- pub resource_dir: &'a Path,
- /// Callback function called when an event happens.
- pub on_event: L,
- /// Receiver oneshot channel for closing the tunnel.
- pub tunnel_close_rx: oneshot::Receiver<()>,
- /// Mutex to tunnel provider.
- pub tun_provider: Arc<Mutex<TunProvider>>,
- /// Connection retry attempts.
- pub retry_attempt: u32,
- /// Route manager handle.
- pub route_manager: RouteManagerHandle,
-}
-
// TODO(emilsp) move most of the openvpn tunnel details to OpenVpnTunnelMonitor
impl TunnelMonitor {
/// Creates a new `TunnelMonitor` that connects to the given remote and notifies `on_event`
@@ -130,7 +70,7 @@ impl TunnelMonitor {
#[cfg_attr(any(target_os = "android", windows), allow(unused_variables))]
pub fn start<L>(
tunnel_parameters: &mut TunnelParameters,
- log_dir: &Option<PathBuf>,
+ log_dir: &Option<path::PathBuf>,
args: TunnelArgs<'_, L>,
) -> Result<Self>
where
@@ -165,7 +105,7 @@ impl TunnelMonitor {
/// Returns a path to an executable that communicates with relay servers.
#[cfg(windows)]
- pub fn get_relay_client(resource_dir: &Path, params: &TunnelParameters) -> PathBuf {
+ pub fn get_relay_client(resource_dir: &path::Path, params: &TunnelParameters) -> path::PathBuf {
let resource_dir = resource_dir.to_path_buf();
let process_string = match params {
TunnelParameters::OpenVpn(params) => {
@@ -187,7 +127,7 @@ impl TunnelMonitor {
fn start_wireguard_tunnel<L>(
params: &mut wireguard_types::TunnelParameters,
- log: Option<PathBuf>,
+ log: Option<path::PathBuf>,
args: TunnelArgs<'_, L>,
) -> Result<Self>
where
@@ -200,8 +140,8 @@ impl TunnelMonitor {
#[cfg(any(target_os = "linux", target_os = "windows"))]
args.runtime
.block_on(Self::assign_mtu(&args.route_manager, params));
- let config = wireguard::config::Config::from_parameters(params)?;
- let monitor = wireguard::WireguardMonitor::start(
+ let config = talpid_wireguard::config::Config::from_parameters(params)?;
+ let monitor = talpid_wireguard::WireguardMonitor::start(
config,
if params.options.use_pq_safe_psk {
Some(
@@ -280,8 +220,8 @@ impl TunnelMonitor {
#[cfg(not(target_os = "android"))]
async fn start_openvpn_tunnel<L>(
config: &openvpn_types::TunnelParameters,
- log: Option<PathBuf>,
- resource_dir: &Path,
+ log: Option<path::PathBuf>,
+ resource_dir: &path::Path,
on_event: L,
tunnel_close_rx: oneshot::Receiver<()>,
#[cfg(target_os = "linux")] route_manager: RouteManagerHandle,
@@ -292,7 +232,7 @@ impl TunnelMonitor {
+ Sync
+ 'static,
{
- let monitor = openvpn::OpenVpnMonitor::start(
+ let monitor = talpid_openvpn::OpenVpnMonitor::start(
on_event,
config,
log,
@@ -323,8 +263,8 @@ impl TunnelMonitor {
#[cfg(not(target_os = "windows"))]
fn prepare_tunnel_log_file(
parameters: &TunnelParameters,
- log_dir: &Option<PathBuf>,
- ) -> Result<Option<PathBuf>> {
+ log_dir: &Option<path::PathBuf>,
+ ) -> Result<Option<path::PathBuf>> {
if let Some(ref log_dir) = log_dir {
match parameters {
TunnelParameters::OpenVpn(_) => {
@@ -342,8 +282,8 @@ impl TunnelMonitor {
#[cfg(target_os = "windows")]
fn prepare_tunnel_log_file(
parameters: &TunnelParameters,
- log_dir: &Option<PathBuf>,
- ) -> Result<Option<PathBuf>> {
+ log_dir: &Option<path::PathBuf>,
+ ) -> Result<Option<path::PathBuf>> {
if let Some(ref log_dir) = log_dir {
let filename = match parameters {
TunnelParameters::OpenVpn(_) => OPENVPN_LOG_FILENAME,
@@ -365,8 +305,8 @@ impl TunnelMonitor {
enum InternalTunnelMonitor {
#[cfg(not(target_os = "android"))]
- OpenVpn(openvpn::OpenVpnMonitor),
- Wireguard(wireguard::WireguardMonitor),
+ OpenVpn(talpid_openvpn::OpenVpnMonitor),
+ Wireguard(talpid_wireguard::WireguardMonitor),
}
impl InternalTunnelMonitor {
diff --git a/talpid-core/src/tunnel/tun_provider/unix.rs b/talpid-core/src/tunnel/tun_provider/unix.rs
deleted file mode 100644
index 5c48a3c663..0000000000
--- a/talpid-core/src/tunnel/tun_provider/unix.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use super::TunConfig;
-use crate::network_interface::{self, NetworkInterface, TunnelDevice};
-use std::{net::IpAddr, ops::Deref};
-
-/// Errors that can occur while setting up a tunnel device.
-#[derive(Debug, err_derive::Error)]
-#[error(no_from)]
-pub enum Error {
- /// Failure to create a tunnel device.
- #[error(display = "Failed to create a tunnel device")]
- CreateTunnelDevice(#[cause] network_interface::Error),
-
- /// Failure to set a tunnel device IP address.
- #[error(display = "Failed to set tunnel IP address: {}", _0)]
- SetIpAddr(IpAddr, #[cause] network_interface::Error),
-
- /// Failure to set the tunnel device as up.
- #[error(display = "Failed to set the tunnel device as up")]
- SetUp(#[cause] network_interface::Error),
-}
-
-/// Factory of tunnel devices on Unix systems.
-pub struct UnixTunProvider;
-
-impl Default for UnixTunProvider {
- fn default() -> Self {
- Self::new()
- }
-}
-
-impl UnixTunProvider {
- pub fn new() -> Self {
- UnixTunProvider
- }
-
- pub fn get_tun(&mut self, config: TunConfig) -> Result<UnixTun, Error> {
- let mut tunnel_device = TunnelDevice::new().map_err(Error::CreateTunnelDevice)?;
-
- for ip in config.addresses.iter() {
- tunnel_device
- .set_ip(*ip)
- .map_err(|cause| Error::SetIpAddr(*ip, cause))?;
- }
-
- tunnel_device.set_up(true).map_err(Error::SetUp)?;
-
- Ok(UnixTun(tunnel_device))
- }
-}
-
-/// Generic tunnel device.
-///
-/// Contains the file descriptor representing the device.
-pub struct UnixTun(TunnelDevice);
-
-impl UnixTun {
- /// Retrieve the tunnel interface name.
- pub fn interface_name(&self) -> &str {
- self.get_name()
- }
-}
-
-impl Deref for UnixTun {
- type Target = TunnelDevice;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index 964963d46e..cdf9029b81 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -5,10 +5,7 @@ use super::{
};
use crate::{
firewall::FirewallPolicy,
- routing::RouteManager,
- tunnel::{
- self, tun_provider::TunProvider, TunnelArgs, TunnelEvent, TunnelMetadata, TunnelMonitor,
- },
+ tunnel::{self, TunnelMonitor},
};
use cfg_if::cfg_if;
use futures::{
@@ -22,17 +19,16 @@ use std::{
thread,
time::{Duration, Instant},
};
+use talpid_routing::RouteManager;
+use talpid_tunnel::{tun_provider::TunProvider, TunnelArgs, TunnelEvent, TunnelMetadata};
use talpid_types::{
net::{AllowedTunnelTraffic, TunnelParameters},
tunnel::{ErrorStateCause, FirewallPolicyError},
ErrorExt,
};
-#[cfg(windows)]
-use crate::routing;
-
#[cfg(target_os = "android")]
-use crate::tunnel::tun_provider;
+use talpid_tunnel::tun_provider;
use super::connected_state::TunnelEventsReceiver;
@@ -175,16 +171,16 @@ impl ConnectingState {
tunnel::Error::EnableIpv6Error => ErrorStateCause::Ipv6Unavailable,
#[cfg(target_os = "android")]
tunnel::Error::WireguardTunnelMonitoringError(
- tunnel::wireguard::Error::TunnelError(
- tunnel::wireguard::TunnelError::SetupTunnelDeviceError(
+ talpid_wireguard::Error::TunnelError(
+ talpid_wireguard::TunnelError::SetupTunnelDeviceError(
tun_provider::Error::PermissionDenied,
),
),
) => ErrorStateCause::VpnPermissionDenied,
#[cfg(target_os = "android")]
tunnel::Error::WireguardTunnelMonitoringError(
- tunnel::wireguard::Error::TunnelError(
- tunnel::wireguard::TunnelError::SetupTunnelDeviceError(
+ talpid_wireguard::Error::TunnelError(
+ talpid_wireguard::TunnelError::SetupTunnelDeviceError(
tun_provider::Error::InvalidDnsServers(addresses),
),
),
@@ -227,7 +223,7 @@ impl ConnectingState {
Ok(_) => None,
Err(error) => match error {
tunnel::Error::WireguardTunnelMonitoringError(
- tunnel::wireguard::Error::TimeoutError,
+ talpid_wireguard::Error::TimeoutError,
) => {
log::debug!("WireGuard tunnel timed out");
None
@@ -481,9 +477,7 @@ impl ConnectingState {
#[cfg_attr(not(target_os = "windows"), allow(unused_variables))]
fn should_retry(error: &tunnel::Error, retry_attempt: u32) -> bool {
- #[cfg(windows)]
- use tunnel::openvpn;
- use tunnel::wireguard::{Error, TunnelError};
+ use talpid_wireguard::{Error, TunnelError};
match error {
tunnel::Error::WireguardTunnelMonitoringError(Error::CreateObfuscatorError(_)) => true,
@@ -513,18 +507,18 @@ fn should_retry(error: &tunnel::Error, retry_attempt: u32) -> bool {
)) if retry_attempt < MAX_ADAPTER_FAIL_RETRIES => true,
#[cfg(windows)]
- tunnel::Error::OpenVpnTunnelMonitoringError(openvpn::Error::WintunCreateAdapterError(
- _,
- )) if retry_attempt < MAX_ADAPTER_FAIL_RETRIES => true,
+ tunnel::Error::OpenVpnTunnelMonitoringError(
+ talpid_openvpn::Error::WintunCreateAdapterError(_),
+ ) if retry_attempt < MAX_ADAPTER_FAIL_RETRIES => true,
_ => false,
}
}
#[cfg(windows)]
-fn is_recoverable_routing_error(error: &crate::routing::Error) -> bool {
+fn is_recoverable_routing_error(error: &talpid_routing::Error) -> bool {
match error {
- routing::Error::AddRoutesFailed(_) => true,
+ talpid_routing::Error::AddRoutesFailed(_) => true,
_ => false,
}
}
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index 5d13b7d1f2..b802dd6c54 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -18,11 +18,11 @@ use crate::{
firewall::{Firewall, FirewallArguments, InitialFirewallState},
mpsc::Sender,
offline,
- routing::RouteManager,
- tunnel::{tun_provider::TunProvider, TunnelEvent},
};
#[cfg(windows)]
use std::ffi::OsString;
+use talpid_routing::RouteManager;
+use talpid_tunnel::{tun_provider::TunProvider, TunnelEvent};
use futures::{
channel::{mpsc, oneshot},
@@ -71,7 +71,7 @@ pub enum Error {
/// Failed to initialize the route manager.
#[error(display = "Failed to initialize the route manager")]
- InitRouteManagerError(#[error(source)] crate::routing::Error),
+ InitRouteManagerError(#[error(source)] talpid_routing::Error),
/// Failed to initialize filtering resolver
#[cfg(target_os = "macos")]
@@ -116,6 +116,8 @@ pub async fn spawn(
#[cfg(target_os = "windows")] volume_update_rx: mpsc::UnboundedReceiver<()>,
#[cfg(target_os = "macos")] exclusion_gid: u32,
#[cfg(target_os = "android")] android_context: AndroidContext,
+ #[cfg(target_os = "linux")] fwmark: u32,
+ #[cfg(target_os = "linux")] table_id: u32,
) -> Result<TunnelStateMachineHandle, Error> {
let (command_tx, command_rx) = mpsc::unbounded();
let command_tx = Arc::new(command_tx);
@@ -127,6 +129,12 @@ pub async fn spawn(
initial_settings.allow_lan,
#[cfg(target_os = "android")]
initial_settings.dns_servers.clone(),
+ #[cfg(target_os = "android")]
+ crate::firewall::ALLOWED_LAN_NETS
+ .iter()
+ .chain(crate::firewall::ALLOWED_LAN_MULTICAST_NETS.iter())
+ .cloned()
+ .collect(),
);
let (shutdown_tx, shutdown_rx) = oneshot::channel();
@@ -148,6 +156,10 @@ pub async fn spawn(
exclusion_gid,
#[cfg(target_os = "android")]
android_context,
+ #[cfg(target_os = "linux")]
+ fwmark,
+ #[cfg(target_os = "linux")]
+ table_id,
};
let state_machine = TunnelStateMachine::new(init_args).await?;
@@ -237,6 +249,10 @@ struct TunnelStateMachineInitArgs<G: TunnelParametersGenerator> {
exclusion_gid: u32,
#[cfg(target_os = "android")]
android_context: AndroidContext,
+ #[cfg(target_os = "linux")]
+ fwmark: u32,
+ #[cfg(target_os = "linux")]
+ table_id: u32,
}
impl TunnelStateMachine {
@@ -256,11 +272,17 @@ impl TunnelStateMachine {
let filtering_resolver = crate::resolver::start_resolver().await?;
#[cfg(target_os = "windows")]
- let power_mgmt_rx = crate::windows::window::PowerManagementListener::new();
+ let power_mgmt_rx = crate::window::PowerManagementListener::new();
- let route_manager = RouteManager::new(HashSet::new())
- .await
- .map_err(Error::InitRouteManagerError)?;
+ let route_manager = RouteManager::new(
+ HashSet::new(),
+ #[cfg(target_os = "linux")]
+ args.fwmark,
+ #[cfg(target_os = "linux")]
+ args.table_id,
+ )
+ .await
+ .map_err(Error::InitRouteManagerError)?;
#[cfg(windows)]
let split_tunnel = split_tunnel::SplitTunnel::new(
@@ -283,9 +305,12 @@ impl TunnelStateMachine {
InitialFirewallState::None
},
allow_lan: args.settings.allow_lan,
+ #[cfg(target_os = "linux")]
+ fwmark: args.fwmark,
};
let firewall = Firewall::from_args(fw_args).map_err(Error::InitFirewallError)?;
+
let dns_monitor = DnsMonitor::new(
#[cfg(target_os = "linux")]
runtime.clone(),
@@ -316,6 +341,8 @@ impl TunnelStateMachine {
route_manager
.handle()
.map_err(Error::InitRouteManagerError)?,
+ #[cfg(target_os = "linux")]
+ Some(args.fwmark),
#[cfg(target_os = "android")]
android_context,
#[cfg(target_os = "windows")]
diff --git a/talpid-core/src/windows/window.rs b/talpid-core/src/window.rs
index dd009f42ef..d3ba502dde 100644
--- a/talpid-core/src/windows/window.rs
+++ b/talpid-core/src/window.rs
@@ -1,4 +1,4 @@
-//! Utilities for windows.
+//! Utilities for working with windows on Windows.
use std::{os::windows::io::AsRawHandle, ptr, sync::Arc, thread};
use tokio::sync::broadcast;
diff --git a/talpid-dbus/src/network_manager.rs b/talpid-dbus/src/network_manager.rs
index a04870d615..40cdf0a656 100644
--- a/talpid-dbus/src/network_manager.rs
+++ b/talpid-dbus/src/network_manager.rs
@@ -393,6 +393,12 @@ impl NetworkManager {
}
}
+ pub fn ensure_can_be_used_to_manage_dns(&self) -> Result<()> {
+ self.ensure_resolv_conf_is_managed()?;
+ self.ensure_network_manager_exists()?;
+ self.nm_version_dns_works()?;
+ Ok(())
+ }
pub fn ensure_resolv_conf_is_managed(&self) -> Result<()> {
// check if NM is set to manage resolv.conf
let management_mode: String = self
diff --git a/talpid-openvpn/Cargo.toml b/talpid-openvpn/Cargo.toml
new file mode 100644
index 0000000000..1e701506a6
--- /dev/null
+++ b/talpid-openvpn/Cargo.toml
@@ -0,0 +1,62 @@
+[package]
+name = "talpid-openvpn"
+version = "0.0.0"
+authors = ["Mullvad VPN"]
+description = "Library for creating OpenVPN tunnels"
+license = "GPL-3.0"
+edition = "2021"
+publish = false
+
+
+[dependencies]
+bitflags = "1.2"
+async-trait = "0.1"
+atty = "0.2"
+cfg-if = "1.0"
+duct = "0.13"
+err-derive = "0.3.1"
+futures = "0.3.15"
+lazy_static = "1.0"
+log = "0.4"
+os_pipe = "0.9"
+parking_lot = "0.11"
+shell-escape = "0.1"
+talpid-routing = { path = "../talpid-routing" }
+talpid-tunnel = { path = "../talpid-tunnel" }
+talpid-types = { path = "../talpid-types" }
+uuid = { version = "0.8", features = ["v4"] }
+tokio = { version = "1.8", features = ["process", "rt-multi-thread", "fs"] }
+shadowsocks-service = { version = "1.14.3", default-features = false, features = ["local", "stream-cipher"] }
+
+[target.'cfg(not(target_os="android"))'.dependencies]
+byteorder = "1"
+socket2 = { version = "0.4.2", features = ["all"] }
+parity-tokio-ipc = "0.9"
+triggered = "0.1.1"
+tonic = "0.8"
+prost = "0.11"
+
+[target.'cfg(target_os = "linux")'.dependencies]
+which = { version = "4.0", default-features = false }
+
+[target.'cfg(windows)'.dependencies]
+widestring = "0.5"
+winreg = { version = "0.7", features = ["transactions"] }
+winapi = { version = "0.3.6", features = ["ws2def"] }
+talpid-windows-net = { path = "../talpid-windows-net" }
+
+[target.'cfg(windows)'.dependencies.windows-sys]
+version = "0.42.0"
+features = [
+ "Win32_Foundation",
+ "Win32_System_LibraryLoader",
+ "Win32_System_Registry",
+ "Win32_NetworkManagement_Ndis",
+]
+
+[build-dependencies]
+tonic-build = { version = "0.8", default-features = false, features = ["transport", "prost"] }
+
+
+[dev-dependencies]
+tokio = { version = "1", features = [ "test-util" ] }
diff --git a/talpid-openvpn/build.rs b/talpid-openvpn/build.rs
new file mode 100644
index 0000000000..2029098f5e
--- /dev/null
+++ b/talpid-openvpn/build.rs
@@ -0,0 +1,9 @@
+fn main() {
+ generate_grpc_code();
+}
+
+fn generate_grpc_code() {
+ const PROTO_FILE: &str = "../talpid-openvpn-plugin/proto/openvpn_plugin.proto";
+ tonic_build::compile_protos(PROTO_FILE).unwrap();
+ println!("cargo:rerun-if-changed={}", PROTO_FILE);
+}
diff --git a/talpid-core/src/tunnel/openvpn/mod.rs b/talpid-openvpn/src/lib.rs
index 439427c8e6..6ea22792aa 100644
--- a/talpid-core/src/tunnel/openvpn/mod.rs
+++ b/talpid-openvpn/src/lib.rs
@@ -1,17 +1,16 @@
-use super::TunnelEvent;
-#[cfg(target_os = "linux")]
-use crate::routing::{self, RequiredRoute};
-use crate::{
- mktemp,
- process::{
- openvpn::{OpenVpnCommand, OpenVpnProcHandle},
- stoppable_process::StoppableProcess,
- },
- proxy::{self, ProxyMonitor, ProxyResourceData},
-};
+//! Manage OpenVPN tunnels.
+
+#![deny(missing_docs)]
+#![deny(rust_2018_idioms)]
+
+use crate::proxy::{ProxyMonitor, ProxyResourceData};
use futures::channel::oneshot;
#[cfg(windows)]
use lazy_static::lazy_static;
+use process::{
+ openvpn::{OpenVpnCommand, OpenVpnProcHandle},
+ stoppable_process::StoppableProcess,
+};
#[cfg(target_os = "linux")]
use std::collections::{HashMap, HashSet};
#[cfg(windows)]
@@ -28,10 +27,12 @@ use std::{
thread,
time::Duration,
};
+#[cfg(target_os = "linux")]
+use talpid_routing::{self, RequiredRoute};
+use talpid_tunnel::TunnelEvent;
use talpid_types::{net::openvpn, ErrorExt};
use tokio::task;
-#[cfg(target_os = "linux")]
-use which;
+
#[cfg(windows)]
use widestring::U16CString;
#[cfg(windows)]
@@ -40,6 +41,10 @@ use windows_sys::{core::GUID, Win32::NetworkManagement::Ndis::NET_LUID_LH};
#[cfg(windows)]
mod wintun;
+mod mktemp;
+mod process;
+mod proxy;
+
#[cfg(windows)]
lazy_static! {
static ref ADAPTER_ALIAS: U16CString = U16CString::from_str("Mullvad").unwrap();
@@ -228,7 +233,7 @@ impl WintunContext for WintunContextImpl {
async fn wait_for_interfaces(&self) -> io::Result<()> {
let luid = self.adapter.luid();
- crate::windows::wait_for_interfaces(luid, true, self.wait_v6_interface).await
+ talpid_windows_net::wait_for_interfaces(luid, true, self.wait_v6_interface).await
}
fn prepare_interface(&self) {
@@ -252,7 +257,7 @@ impl OpenVpnMonitor<OpenVpnCommand> {
log_path: Option<PathBuf>,
resource_dir: &Path,
tunnel_close_rx: oneshot::Receiver<()>,
- #[cfg(target_os = "linux")] route_manager: routing::RouteManagerHandle,
+ #[cfg(target_os = "linux")] route_manager: talpid_routing::RouteManagerHandle,
) -> Result<Self>
where
L: (Fn(TunnelEvent) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>)
@@ -358,7 +363,7 @@ impl OpenVpnMonitor<OpenVpnCommand> {
#[cfg(target_os = "linux")]
fn extract_routes(env: &HashMap<String, String>) -> Result<HashSet<RequiredRoute>> {
let tun_interface = env.get("dev").ok_or(Error::MissingTunnelInterface)?;
- let tun_node = routing::Node::device(tun_interface.to_string());
+ let tun_node = talpid_routing::Node::device(tun_interface.to_string());
let mut routes = HashSet::new();
for network in &["0.0.0.0/0".parse().unwrap(), "::/0".parse().unwrap()] {
routes.insert(RequiredRoute::new(*network, tun_node.clone()));
@@ -806,7 +811,6 @@ impl ProcessHandle for OpenVpnProcHandle {
}
mod event_server {
- use crate::tunnel::TunnelMetadata;
use futures::stream::TryStreamExt;
use parity_tokio_ipc::Endpoint as IpcEndpoint;
use std::{
@@ -814,6 +818,7 @@ mod event_server {
pin::Pin,
task::{Context, Poll},
};
+ use talpid_tunnel::TunnelMetadata;
#[cfg(any(target_os = "linux", windows))]
use talpid_types::ErrorExt;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
@@ -846,7 +851,7 @@ mod event_server {
/// Implements a gRPC service used to process events sent to by OpenVPN.
pub struct OpenvpnEventProxyImpl<
L: (Fn(
- super::TunnelEvent,
+ talpid_tunnel::TunnelEvent,
) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>)
+ Send
+ Sync
@@ -857,14 +862,14 @@ mod event_server {
pub proxy_auth_file_path: Option<super::PathBuf>,
pub abort_server_tx: triggered::Trigger,
#[cfg(target_os = "linux")]
- pub route_manager_handle: super::routing::RouteManagerHandle,
+ pub route_manager_handle: talpid_routing::RouteManagerHandle,
#[cfg(target_os = "linux")]
pub ipv6_enabled: bool,
}
impl<
L: (Fn(
- super::TunnelEvent,
+ talpid_tunnel::TunnelEvent,
)
-> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>)
+ Send
@@ -877,7 +882,7 @@ mod event_server {
request: Request<EventDetails>,
) -> std::result::Result<Response<()>, tonic::Status> {
let env = request.into_inner().env;
- (self.on_event)(super::TunnelEvent::InterfaceUp(
+ (self.on_event)(talpid_tunnel::TunnelEvent::InterfaceUp(
Self::get_tunnel_metadata(&env)?,
talpid_types::net::AllowedTunnelTraffic::All,
))
@@ -925,11 +930,11 @@ mod event_server {
#[cfg(windows)]
{
let tunnel_device = metadata.interface.clone();
- let luid = crate::windows::luid_from_alias(tunnel_device).map_err(|error| {
+ let luid = talpid_windows_net::luid_from_alias(tunnel_device).map_err(|error| {
log::error!("{}", error.display_chain_with_msg("luid_from_alias failed"));
tonic::Status::unavailable("failed to obtain interface luid")
})?;
- crate::windows::wait_for_addresses(luid)
+ talpid_windows_net::wait_for_addresses(luid)
.await
.map_err(|error| {
log::error!(
@@ -940,7 +945,7 @@ mod event_server {
})?;
}
- (self.on_event)(super::TunnelEvent::Up(metadata)).await;
+ (self.on_event)(talpid_tunnel::TunnelEvent::Up(metadata)).await;
Ok(Response::new(()))
}
@@ -996,7 +1001,7 @@ mod event_server {
#[tonic::async_trait]
impl<
L: (Fn(
- super::TunnelEvent,
+ talpid_tunnel::TunnelEvent,
)
-> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>)
+ Send
@@ -1009,7 +1014,7 @@ mod event_server {
request: Request<EventDetails>,
) -> std::result::Result<Response<()>, tonic::Status> {
let env = request.into_inner().env;
- (self.on_event)(super::TunnelEvent::AuthFailed(
+ (self.on_event)(talpid_tunnel::TunnelEvent::AuthFailed(
env.get("auth_failed_reason").cloned(),
))
.await;
@@ -1040,7 +1045,7 @@ mod event_server {
&self,
_request: Request<EventDetails>,
) -> std::result::Result<Response<()>, tonic::Status> {
- (self.on_event)(super::TunnelEvent::Down).await;
+ (self.on_event)(talpid_tunnel::TunnelEvent::Down).await;
Ok(Response::new(()))
}
}
diff --git a/talpid-core/src/mktemp.rs b/talpid-openvpn/src/mktemp.rs
index 9e5709ce1f..9e5709ce1f 100644
--- a/talpid-core/src/mktemp.rs
+++ b/talpid-openvpn/src/mktemp.rs
diff --git a/talpid-core/src/process/mod.rs b/talpid-openvpn/src/process/mod.rs
index 54cdeb9042..54cdeb9042 100644
--- a/talpid-core/src/process/mod.rs
+++ b/talpid-openvpn/src/process/mod.rs
diff --git a/talpid-core/src/process/openvpn.rs b/talpid-openvpn/src/process/openvpn.rs
index 3d2f5668a0..4b8932ee13 100644
--- a/talpid-core/src/process/openvpn.rs
+++ b/talpid-openvpn/src/process/openvpn.rs
@@ -73,6 +73,8 @@ pub struct OpenVpnCommand {
tunnel_alias: Option<OsString>,
enable_ipv6: bool,
proxy_port: Option<u16>,
+ #[cfg(target_os = "linux")]
+ fwmark: Option<u32>,
}
impl OpenVpnCommand {
@@ -95,9 +97,18 @@ impl OpenVpnCommand {
tunnel_alias: None,
enable_ipv6: true,
proxy_port: None,
+ #[cfg(target_os = "linux")]
+ fwmark: None,
}
}
+ /// Sets what the firewall mark should be
+ #[cfg(target_os = "linux")]
+ pub fn fwmark(&mut self, fwmark: Option<u32>) -> &mut Self {
+ self.fwmark = fwmark;
+ self
+ }
+
/// Sets what configuration file will be given to OpenVPN
pub fn config(&mut self, path: impl AsRef<Path>) -> &mut Self {
self.config = Some(path.as_ref().to_path_buf());
@@ -253,11 +264,9 @@ impl OpenVpnCommand {
args.extend(self.proxy_arguments().iter().map(OsString::from));
#[cfg(target_os = "linux")]
- args.extend(
- ["--mark", &crate::linux::TUNNEL_FW_MARK.to_string()]
- .iter()
- .map(OsString::from),
- );
+ if let Some(mark) = &self.fwmark {
+ args.extend(["--mark", &mark.to_string()].iter().map(OsString::from));
+ }
args
}
diff --git a/talpid-core/src/process/stoppable_process.rs b/talpid-openvpn/src/process/stoppable_process.rs
index 3681c6cfa8..3681c6cfa8 100644
--- a/talpid-core/src/process/stoppable_process.rs
+++ b/talpid-openvpn/src/process/stoppable_process.rs
diff --git a/talpid-core/src/proxy/mod.rs b/talpid-openvpn/src/proxy/mod.rs
index dd0e0b6cc9..dd0e0b6cc9 100644
--- a/talpid-core/src/proxy/mod.rs
+++ b/talpid-openvpn/src/proxy/mod.rs
diff --git a/talpid-core/src/proxy/noop.rs b/talpid-openvpn/src/proxy/noop.rs
index 9eb96e0c95..9eb96e0c95 100644
--- a/talpid-core/src/proxy/noop.rs
+++ b/talpid-openvpn/src/proxy/noop.rs
diff --git a/talpid-core/src/proxy/shadowsocks.rs b/talpid-openvpn/src/proxy/shadowsocks.rs
index 54efbe1205..b9c9dad407 100644
--- a/talpid-core/src/proxy/shadowsocks.rs
+++ b/talpid-openvpn/src/proxy/shadowsocks.rs
@@ -73,7 +73,7 @@ impl ShadowsocksProxyMonitor {
#[cfg(target_os = "linux")]
{
- config.outbound_fwmark = Some(crate::linux::TUNNEL_FW_MARK);
+ config.outbound_fwmark = settings.fwmark;
}
let srv = local::create(config).await?;
diff --git a/talpid-core/src/tunnel/openvpn/wintun.rs b/talpid-openvpn/src/wintun.rs
index 92a670aa66..1e98aa08f8 100644
--- a/talpid-core/src/tunnel/openvpn/wintun.rs
+++ b/talpid-openvpn/src/wintun.rs
@@ -1,4 +1,3 @@
-use crate::windows::string_from_guid;
use lazy_static::lazy_static;
use std::{
ffi::CStr,
@@ -16,6 +15,7 @@ use windows_sys::{
Foundation::{HINSTANCE, NO_ERROR},
NetworkManagement::{IpHelper::ConvertInterfaceLuidToGuid, Ndis::NET_LUID_LH},
System::{
+ Com::StringFromGUID2,
LibraryLoader::{
FreeLibrary, GetProcAddress, LoadLibraryExW, LOAD_WITH_ALTERED_SEARCH_PATH,
},
@@ -103,7 +103,9 @@ impl WintunAdapter {
}
pub fn prepare_interface(&self) {
- if let Err(error) = crate::tunnel::windows::initialize_interfaces(self.luid(), None) {
+ if let Err(error) =
+ talpid_tunnel::network_interface::initialize_interfaces(self.luid(), None)
+ {
log::error!(
"{}",
error.display_chain_with_msg("Failed to set tunnel interface metric"),
@@ -355,6 +357,17 @@ fn find_adapter_registry_key(find_guid: &str, permissions: REG_SAM_FLAGS) -> io:
Err(io::Error::new(io::ErrorKind::NotFound, "device not found"))
}
+/// Obtain a string representation for a GUID object.
+fn string_from_guid(guid: &GUID) -> String {
+ let mut buffer = [0u16; 40];
+ let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) }
+ as usize;
+ // cannot fail because `buffer` is large enough
+ assert!(length > 0);
+ let length = length - 1;
+ String::from_utf16(&buffer[0..length]).unwrap()
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/talpid-routing/Cargo.toml b/talpid-routing/Cargo.toml
new file mode 100644
index 0000000000..e248f4e345
--- /dev/null
+++ b/talpid-routing/Cargo.toml
@@ -0,0 +1,47 @@
+[package]
+name = "talpid-routing"
+version = "0.0.0"
+authors = ["Mullvad VPN"]
+description = "Library for managing routing tables"
+license = "GPL-3.0"
+edition = "2021"
+publish = false
+
+
+[dependencies]
+err-derive = "0.3.1"
+futures = "0.3.15"
+ipnetwork = "0.16"
+log = "0.4"
+talpid-types = { path = "../talpid-types" }
+tokio = { version = "1.8", features = ["process", "rt-multi-thread"] }
+
+
+[target.'cfg(target_os = "android")'.dependencies]
+jnix = { version = "0.5", features = ["derive"] }
+
+
+[target.'cfg(target_os = "linux")'.dependencies]
+libc = "0.2"
+lazy_static = "1.0"
+rtnetlink = "0.11"
+netlink-packet-route = "0.13"
+netlink-sys = "0.8.3"
+
+[target.'cfg(target_os = "macos")'.dependencies]
+tokio-stream = { version = "0.1", features = ["io-util"] }
+
+
+[target.'cfg(windows)'.dependencies]
+libc = "0.2"
+socket2 = { version = "0.4.2", features = ["all"] }
+talpid-windows-net = { path = "../talpid-windows-net" }
+widestring = "1.0"
+winapi = { version = "0.3.6", features = ["ws2def"] }
+windows-sys = { version = "0.42.0", features = [
+ "Win32_NetworkManagement_Ndis",
+ "Win32_Globalization"
+]}
+
+[dev-dependencies]
+tokio = { version = "1", features = [ "test-util" ] }
diff --git a/talpid-core/src/routing/android.rs b/talpid-routing/src/android.rs
index 78f5c14a90..332e2ca093 100644
--- a/talpid-core/src/routing/android.rs
+++ b/talpid-routing/src/android.rs
@@ -1,5 +1,4 @@
-use crate::routing::{imp::RouteManagerCommand, RequiredRoute};
-// use futures01::{stream::Stream, sync::mpsc};
+use crate::{imp::RouteManagerCommand, RequiredRoute};
use futures::{channel::mpsc, stream::StreamExt};
use std::collections::HashSet;
diff --git a/talpid-core/src/routing/mod.rs b/talpid-routing/src/lib.rs
index 5d1247618e..06a8a09d18 100644
--- a/talpid-core/src/routing/mod.rs
+++ b/talpid-routing/src/lib.rs
@@ -1,5 +1,7 @@
-#![cfg_attr(target_os = "android", allow(dead_code))]
-#![cfg_attr(target_os = "windows", allow(dead_code))]
+//! Manage routing tables on various platforms.
+
+#![deny(missing_docs)]
+#![deny(rust_2018_idioms)]
use ipnetwork::IpNetwork;
use std::{fmt, net::IpAddr};
@@ -18,7 +20,7 @@ mod imp;
use netlink_packet_route::rtnl::constants::RT_TABLE_MAIN;
#[cfg(target_os = "macos")]
-pub(crate) use imp::{get_default_routes, listen_for_default_route_changes, PlatformError};
+pub use imp::{get_default_routes, listen_for_default_route_changes, PlatformError};
pub use imp::{Error, RouteManager};
@@ -35,7 +37,8 @@ pub struct Route {
}
impl Route {
- fn new(node: Node, prefix: IpNetwork) -> Self {
+ /// Construct a new Route
+ pub fn new(node: Node, prefix: IpNetwork) -> Self {
Self {
node,
prefix,
@@ -88,7 +91,7 @@ impl RequiredRoute {
node: node.into(),
prefix,
#[cfg(target_os = "linux")]
- table_id: crate::linux::TUNNEL_TABLE_ID,
+ table_id: u32::from(RT_TABLE_MAIN),
}
}
diff --git a/talpid-core/src/routing/linux.rs b/talpid-routing/src/linux.rs
index 1443f87453..edd2893ff3 100644
--- a/talpid-core/src/routing/linux.rs
+++ b/talpid-routing/src/linux.rs
@@ -1,4 +1,4 @@
-use crate::routing::{
+use crate::{
imp::{CallbackMessage, RouteManagerCommand},
NetNode, Node, RequiredRoute, Route,
};
@@ -17,6 +17,7 @@ use futures::{
};
use ipnetwork::IpNetwork;
use lazy_static::lazy_static;
+use libc::{AF_INET, AF_INET6};
use netlink_packet_route::{
constants::{ARPHRD_LOOPBACK, FIB_RULE_INVERT, FR_ACT_TO_TBL, NLM_F_REQUEST},
link::{nlas::Nla as LinkNla, LinkMessage},
@@ -37,8 +38,6 @@ use rtnetlink::{
Handle, IpVersion,
};
-use libc::{AF_INET, AF_INET6};
-
lazy_static! {
static ref SUPPRESS_RULE_V4: RuleMessage = RuleMessage {
header: RuleHeader {
@@ -56,29 +55,33 @@ lazy_static! {
v6_rule.header.family = AF_INET6 as u8;
v6_rule
};
- static ref NO_FWMARK_RULE_V4: RuleMessage = RuleMessage {
+}
+
+fn all_rules(fwmark: u32, table: u32) -> [RuleMessage; 4] {
+ [
+ no_fwmark_rule_v4(fwmark, table),
+ no_fwmark_rule_v6(fwmark, table),
+ SUPPRESS_RULE_V4.clone(),
+ SUPPRESS_RULE_V6.clone(),
+ ]
+}
+
+fn no_fwmark_rule_v4(fwmark: u32, table: u32) -> RuleMessage {
+ RuleMessage {
header: RuleHeader {
family: AF_INET as u8,
action: FR_ACT_TO_TBL,
flags: FIB_RULE_INVERT,
..RuleHeader::default()
},
- nlas: vec![
- RuleNla::FwMark(crate::linux::TUNNEL_FW_MARK),
- RuleNla::Table(crate::linux::TUNNEL_TABLE_ID),
- ],
- };
- static ref NO_FWMARK_RULE_V6: RuleMessage = {
- let mut v6_rule = NO_FWMARK_RULE_V4.clone();
- v6_rule.header.family = AF_INET6 as u8;
- v6_rule
- };
- static ref ALL_RULES: [&'static RuleMessage; 4] = [
- &*NO_FWMARK_RULE_V4,
- &*NO_FWMARK_RULE_V6,
- &*SUPPRESS_RULE_V4,
- &*SUPPRESS_RULE_V6,
- ];
+ nlas: vec![RuleNla::FwMark(fwmark), RuleNla::Table(table)],
+ }
+}
+
+fn no_fwmark_rule_v6(fwmark: u32, table: u32) -> RuleMessage {
+ let mut v6_rule = no_fwmark_rule_v4(fwmark, table);
+ v6_rule.header.family = AF_INET6 as u8;
+ v6_rule
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -136,10 +139,20 @@ pub struct RouteManagerImpl {
// currently added routes
added_routes: HashSet<Route>,
+
+ /// Tunnel specific routing table, traffic not marked will be routed via this routing table.
+ table_id: u32,
+ /// Firewall mark identifies traffic which shouldn't be routed via the tunnel routing table. It
+ /// is used to construct a routing rule.
+ fwmark: u32,
}
impl RouteManagerImpl {
- pub async fn new(required_routes: HashSet<RequiredRoute>) -> Result<Self> {
+ pub async fn new(
+ required_routes: HashSet<RequiredRoute>,
+ table_id: u32,
+ fwmark: u32,
+ ) -> Result<Self> {
let (mut connection, handle, messages) =
rtnetlink::new_connection().map_err(Error::Connect)?;
@@ -161,6 +174,8 @@ impl RouteManagerImpl {
iface_map,
listeners: vec![],
added_routes: HashSet::new(),
+ table_id,
+ fwmark,
};
monitor.clear_routing_rules().await?;
@@ -174,7 +189,7 @@ impl RouteManagerImpl {
self.clear_routing_rules().await?;
- for rule in ALL_RULES
+ for rule in all_rules(self.fwmark, self.table_id)
.iter()
.filter(|rule| rule.header.family as u16 == AF_INET || enable_ipv6)
{
@@ -194,7 +209,7 @@ impl RouteManagerImpl {
async fn clear_routing_rules(&mut self) -> Result<()> {
let rules = self.get_rules().await?;
- for rule in &*ALL_RULES {
+ for rule in all_rules(self.fwmark, self.table_id) {
let mut matching_rule = None;
// `RTM_DELRULE` is way too picky about which rules are considered the same.
@@ -368,8 +383,8 @@ impl RouteManagerImpl {
RouteManagerCommand::NewChangeListener(result_tx) => {
let _ = result_tx.send(self.listen());
}
- RouteManagerCommand::GetDestinationRoute(destination, set_mark, result_tx) => {
- let _ = result_tx.send(self.get_destination_route(&destination, set_mark).await);
+ RouteManagerCommand::GetDestinationRoute(destination, mark, result_tx) => {
+ let _ = result_tx.send(self.get_destination_route(&destination, mark).await);
}
RouteManagerCommand::GetMtuForRoute(ip, result_tx) => {
let _ = result_tx.send(self.get_mtu_for_route(ip).await);
@@ -735,7 +750,9 @@ impl RouteManagerImpl {
const STANDARD_MTU: u16 = 1500;
let mut attempted_ip = ip;
for _ in 0..RECURSION_LIMIT {
- let route = self.get_destination_route(&attempted_ip, false).await?;
+ let route = self
+ .get_destination_route(&attempted_ip, Some(self.fwmark))
+ .await?;
match route {
Some(route) => {
let node = route.get_node();
@@ -792,7 +809,7 @@ impl RouteManagerImpl {
async fn get_destination_route(
&self,
destination: &IpAddr,
- set_mark: bool,
+ fwmark: Option<u32>,
) -> Result<Option<Route>> {
let mut request = self.handle.route().get(get_ip_version(destination));
let octets = match destination {
@@ -800,10 +817,8 @@ impl RouteManagerImpl {
IpAddr::V6(address) => address.octets().to_vec(),
};
let message = request.message_mut();
- if set_mark {
- message
- .nlas
- .push(RouteNla::Mark(crate::linux::TUNNEL_FW_MARK));
+ if let Some(mark) = fwmark {
+ message.nlas.push(RouteNla::Mark(mark));
}
message.header.destination_prefix_length = 8u8 * (octets.len() as u8);
message.header.flags = RouteFlags::RTM_F_FIB_MATCH;
@@ -891,7 +906,7 @@ mod test {
fn test_drop_in_executor() {
let runtime = tokio::runtime::Runtime::new().expect("Failed to initialize runtime");
runtime.block_on(async {
- let manager = RouteManagerImpl::new(HashSet::new())
+ let manager = RouteManagerImpl::new(HashSet::new(), 0, 0)
.await
.expect("Failed to initialize route manager");
std::mem::drop(manager);
@@ -903,7 +918,7 @@ mod test {
fn test_drop() {
let runtime = tokio::runtime::Runtime::new().expect("Failed to initialize runtime");
let manager = runtime.block_on(async {
- RouteManagerImpl::new(HashSet::new())
+ RouteManagerImpl::new(HashSet::new(), 1000, 1000)
.await
.expect("Failed to initialize route manager")
});
diff --git a/talpid-core/src/routing/macos.rs b/talpid-routing/src/macos.rs
index f191551f42..568daf94f7 100644
--- a/talpid-core/src/routing/macos.rs
+++ b/talpid-routing/src/macos.rs
@@ -1,4 +1,4 @@
-use crate::routing::{imp::RouteManagerCommand, NetNode, Node, RequiredRoute, Route};
+use crate::{imp::RouteManagerCommand, NetNode, Node, RequiredRoute, Route};
use futures::{
channel::mpsc,
@@ -300,8 +300,7 @@ fn ip_vers(prefix: IpNetwork) -> &'static str {
/// Returns a stream that produces an item whenever a default route is either added or deleted from
/// the routing table.
-pub(crate) fn listen_for_default_route_changes() -> Result<impl Stream<Item = std::io::Result<()>>>
-{
+pub fn listen_for_default_route_changes() -> Result<impl Stream<Item = std::io::Result<()>>> {
let mut cmd = Command::new("route");
cmd.arg("-n")
.arg("monitor")
diff --git a/talpid-core/src/routing/unix.rs b/talpid-routing/src/unix.rs
index 326fb1fad1..2a117b9e07 100644
--- a/talpid-core/src/routing/unix.rs
+++ b/talpid-routing/src/unix.rs
@@ -24,7 +24,7 @@ use std::net::IpAddr;
#[path = "macos.rs"]
mod imp;
#[cfg(target_os = "macos")]
-pub(crate) use imp::listen_for_default_route_changes;
+pub use imp::listen_for_default_route_changes;
#[allow(clippy::module_inception)]
#[cfg(target_os = "linux")]
@@ -121,13 +121,13 @@ impl RouteManagerHandle {
pub async fn get_destination_route(
&self,
destination: IpAddr,
- set_mark: bool,
+ mark: Option<Fwmark>,
) -> Result<Option<Route>, Error> {
let (response_tx, response_rx) = oneshot::channel();
self.tx
.unbounded_send(RouteManagerCommand::GetDestinationRoute(
destination,
- set_mark,
+ mark,
response_tx,
))
.map_err(|_| Error::RouteManagerDown)?;
@@ -151,6 +151,10 @@ impl RouteManagerHandle {
}
}
+/// Represents a firewall mark.
+#[cfg(target_os = "linux")]
+type Fwmark = u32;
+
/// Commands for the underlying route manager object.
#[derive(Debug)]
pub(crate) enum RouteManagerCommand {
@@ -168,10 +172,11 @@ pub(crate) enum RouteManagerCommand {
NewChangeListener(oneshot::Sender<mpsc::UnboundedReceiver<CallbackMessage>>),
#[cfg(target_os = "linux")]
GetMtuForRoute(IpAddr, oneshot::Sender<Result<u16, PlatformError>>),
+ /// Attempt to fetch a route for the given destination with an optional firewall mark.
#[cfg(target_os = "linux")]
GetDestinationRoute(
IpAddr,
- bool,
+ Option<Fwmark>,
oneshot::Sender<Result<Option<Route>, PlatformError>>,
),
}
@@ -195,9 +200,20 @@ impl RouteManager {
/// Constructs a RouteManager and applies the required routes.
/// Takes a set of network destinations and network nodes as an argument, and applies said
/// routes.
- pub async fn new(required_routes: HashSet<RequiredRoute>) -> Result<Self, Error> {
+ pub async fn new(
+ required_routes: HashSet<RequiredRoute>,
+ #[cfg(target_os = "linux")] fwmark: u32,
+ #[cfg(target_os = "linux")] table_id: u32,
+ ) -> Result<Self, Error> {
let (manage_tx, manage_rx) = mpsc::unbounded();
- let manager = imp::RouteManagerImpl::new(required_routes).await?;
+ let manager = imp::RouteManagerImpl::new(
+ required_routes,
+ #[cfg(target_os = "linux")]
+ fwmark,
+ #[cfg(target_os = "linux")]
+ table_id,
+ )
+ .await?;
tokio::spawn(manager.run(manage_rx));
Ok(Self {
@@ -288,8 +304,7 @@ impl Drop for RouteManager {
/// Returns a tuple containing a IPv4 and IPv6 default route nodes.
#[cfg(target_os = "macos")]
-pub(crate) async fn get_default_routes() -> Result<(Option<super::Node>, Option<super::Node>), Error>
-{
+pub async fn get_default_routes() -> Result<(Option<super::Node>, Option<super::Node>), Error> {
use futures::TryFutureExt;
futures::try_join!(
imp::RouteManagerImpl::get_default_node(IpVersion::V4).map_err(Into::into),
diff --git a/talpid-core/src/routing/windows/default_route_monitor.rs b/talpid-routing/src/windows/default_route_monitor.rs
index 3976903f11..3675417062 100644
--- a/talpid-core/src/routing/windows/default_route_monitor.rs
+++ b/talpid-routing/src/windows/default_route_monitor.rs
@@ -1,6 +1,6 @@
use super::{
- get_best_default_route, get_best_default_route::route_has_gateway, AddressFamily, Error,
- InterfaceAndGateway, Result,
+ get_best_default_route, get_best_default_route::route_has_gateway, Error, InterfaceAndGateway,
+ Result,
};
use std::{
@@ -24,6 +24,8 @@ use windows_sys::Win32::{
},
};
+use talpid_windows_net::AddressFamily;
+
const WIN_FALSE: BOOLEAN = 0;
struct DefaultRouteMonitorContext {
diff --git a/talpid-core/src/routing/windows/get_best_default_route.rs b/talpid-routing/src/windows/get_best_default_route.rs
index 4ec7395fff..940fd93644 100644
--- a/talpid-core/src/routing/windows/get_best_default_route.rs
+++ b/talpid-routing/src/windows/get_best_default_route.rs
@@ -1,6 +1,8 @@
use super::{Error, Result};
-use crate::windows::{get_ip_interface_entry, try_socketaddr_from_inet_sockaddr, AddressFamily};
use std::{convert::TryInto, io, net::SocketAddr};
+use talpid_windows_net::{
+ get_ip_interface_entry, try_socketaddr_from_inet_sockaddr, AddressFamily,
+};
use widestring::{widecstr, WideCStr};
use windows_sys::Win32::{
Foundation::NO_ERROR,
diff --git a/talpid-core/src/routing/windows/mod.rs b/talpid-routing/src/windows/mod.rs
index 06d23368ca..7c0e2bd739 100644
--- a/talpid-core/src/routing/windows/mod.rs
+++ b/talpid-routing/src/windows/mod.rs
@@ -1,12 +1,18 @@
-use crate::{routing::RequiredRoute, windows::AddressFamily};
-use futures::channel::oneshot;
-use std::{collections::HashSet, io, net::IpAddr};
-use talpid_types::ErrorExt;
-use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
-
+use crate::RequiredRoute;
pub use default_route_monitor::EventType;
+use futures::{
+ channel::{
+ mpsc::{self, UnboundedReceiver, UnboundedSender},
+ oneshot,
+ },
+ StreamExt,
+};
pub use get_best_default_route::{get_best_default_route, route_has_gateway, InterfaceAndGateway};
+use net::AddressFamily;
pub use route_manager::{Callback, CallbackHandle, Route, RouteManagerInternal};
+use std::{collections::HashSet, io, net::IpAddr};
+use talpid_types::ErrorExt;
+use talpid_windows_net as net;
mod default_route_monitor;
mod get_best_default_route;
@@ -106,7 +112,7 @@ impl RouteManagerHandle {
) -> Result<CallbackHandle> {
let (response_tx, response_rx) = oneshot::channel();
self.tx
- .send(RouteManagerCommand::RegisterDefaultRouteChangeCallback(
+ .unbounded_send(RouteManagerCommand::RegisterDefaultRouteChangeCallback(
callback,
response_tx,
))
@@ -118,7 +124,7 @@ impl RouteManagerHandle {
pub async fn add_routes(&self, routes: HashSet<RequiredRoute>) -> Result<()> {
let (response_tx, response_rx) = oneshot::channel();
self.tx
- .send(RouteManagerCommand::AddRoutes(routes, response_tx))
+ .unbounded_send(RouteManagerCommand::AddRoutes(routes, response_tx))
.map_err(|_| Error::RouteManagerDown)?;
response_rx.await.map_err(|_| Error::ManagerChannelDown)?
}
@@ -127,7 +133,7 @@ impl RouteManagerHandle {
pub async fn get_mtu_for_route(&self, ip: IpAddr) -> Result<u16> {
let (response_tx, response_rx) = oneshot::channel();
self.tx
- .send(RouteManagerCommand::GetMtuForRoute(ip, response_tx))
+ .unbounded_send(RouteManagerCommand::GetMtuForRoute(ip, response_tx))
.map_err(|_| Error::RouteManagerDown)?;
response_rx.await.map_err(|_| Error::ManagerChannelDown)?
}
@@ -149,7 +155,7 @@ impl RouteManager {
Ok(internal) => internal,
Err(_) => return Err(Error::FailedToStartManager),
};
- let (manage_tx, manage_rx) = mpsc::unbounded_channel();
+ let (manage_tx, manage_rx) = mpsc::unbounded();
let manager = Self {
manage_tx: Some(manage_tx),
};
@@ -167,7 +173,7 @@ impl RouteManager {
if let Some(tx) = &self.manage_tx {
let (result_tx, result_rx) = oneshot::channel();
if tx
- .send(RouteManagerCommand::RegisterDefaultRouteChangeCallback(
+ .unbounded_send(RouteManagerCommand::RegisterDefaultRouteChangeCallback(
callback, result_tx,
))
.is_err()
@@ -193,7 +199,7 @@ impl RouteManager {
mut manage_rx: UnboundedReceiver<RouteManagerCommand>,
mut internal: RouteManagerInternal,
) {
- while let Some(command) = manage_rx.recv().await {
+ while let Some(command) = manage_rx.next().await {
match command {
RouteManagerCommand::AddRoutes(routes, tx) => {
let routes: Vec<_> = routes
@@ -242,7 +248,7 @@ impl RouteManager {
/// can be added
pub fn stop(&mut self) {
if let Some(tx) = self.manage_tx.take() {
- if tx.send(RouteManagerCommand::Shutdown).is_err() {
+ if tx.unbounded_send(RouteManagerCommand::Shutdown).is_err() {
log::error!("RouteManager channel already down or thread panicked");
}
}
@@ -253,7 +259,7 @@ impl RouteManager {
if let Some(tx) = &self.manage_tx {
let (result_tx, result_rx) = oneshot::channel();
if tx
- .send(RouteManagerCommand::AddRoutes(routes, result_tx))
+ .unbounded_send(RouteManagerCommand::AddRoutes(routes, result_tx))
.is_err()
{
return Err(Error::RouteManagerDown);
@@ -268,7 +274,7 @@ impl RouteManager {
/// [`RouteManager::add_routes`].
pub fn clear_routes(&self) -> Result<()> {
if let Some(tx) = &self.manage_tx {
- tx.send(RouteManagerCommand::ClearRoutes)
+ tx.unbounded_send(RouteManagerCommand::ClearRoutes)
.map_err(|_| Error::RouteManagerDown)
} else {
Err(Error::RouteManagerDown)
@@ -279,11 +285,13 @@ impl RouteManager {
fn get_mtu_for_route(addr_family: AddressFamily) -> Result<Option<u16>> {
match get_best_default_route(addr_family) {
Ok(Some(route)) => {
- let interface_row = crate::windows::get_ip_interface_entry(addr_family, &route.iface)
- .map_err(|e| {
- log::error!("Could not get ip interface entry: {}", e);
- Error::GetMtu
- })?;
+ let interface_row =
+ talpid_windows_net::get_ip_interface_entry(addr_family, &route.iface).map_err(
+ |e| {
+ log::error!("Could not get ip interface entry: {}", e);
+ Error::GetMtu
+ },
+ )?;
let mtu = interface_row.NlMtu;
let mtu = u16::try_from(mtu).map_err(|_| Error::GetMtu)?;
Ok(Some(mtu))
diff --git a/talpid-core/src/routing/windows/route_manager.rs b/talpid-routing/src/windows/route_manager.rs
index f1d878dd28..ad35d05f77 100644
--- a/talpid-core/src/routing/windows/route_manager.rs
+++ b/talpid-routing/src/windows/route_manager.rs
@@ -2,10 +2,7 @@ use super::{
default_route_monitor::{DefaultRouteMonitor, EventType as RouteMonitorEventType},
get_best_default_route, Error, InterfaceAndGateway, Result,
};
-use crate::{
- routing::NetNode,
- windows::{inet_sockaddr_from_socketaddr, try_socketaddr_from_inet_sockaddr, AddressFamily},
-};
+use crate::NetNode;
use ipnetwork::IpNetwork;
use std::{
collections::HashMap,
@@ -13,6 +10,9 @@ use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
sync::{Arc, Mutex},
};
+use talpid_windows_net::{
+ inet_sockaddr_from_socketaddr, try_socketaddr_from_inet_sockaddr, AddressFamily,
+};
use widestring::{WideCStr, WideCString};
use windows_sys::Win32::{
Foundation::{
@@ -862,7 +862,7 @@ impl<'a> Iterator for AdaptersIterator<'a> {
pub fn win_ip_address_prefix_from_ipnetwork_port_zero(from: IpNetwork) -> IP_ADDRESS_PREFIX {
// Port should not matter so we set it to 0
let prefix =
- crate::windows::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from.ip(), 0));
+ talpid_windows_net::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from.ip(), 0));
IP_ADDRESS_PREFIX {
Prefix: prefix,
PrefixLength: from.prefix(),
@@ -872,7 +872,7 @@ pub fn win_ip_address_prefix_from_ipnetwork_port_zero(from: IpNetwork) -> IP_ADD
/// Convert to a windows defined `SOCKADDR_INET` from a `IpAddr` but set the port to 0
pub fn inet_sockaddr_from_ipaddr(from: IpAddr) -> SOCKADDR_INET {
// Port should not matter so we set it to 0
- crate::windows::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from, 0))
+ talpid_windows_net::inet_sockaddr_from_socketaddr(std::net::SocketAddr::new(from, 0))
}
/// Convert to a `AddressFamily` from a `ipnetwork::IpNetwork`
diff --git a/talpid-tunnel/Cargo.toml b/talpid-tunnel/Cargo.toml
new file mode 100644
index 0000000000..cb5285fd1e
--- /dev/null
+++ b/talpid-tunnel/Cargo.toml
@@ -0,0 +1,42 @@
+[package]
+name = "talpid-tunnel"
+version = "0.0.0"
+authors = ["Mullvad VPN"]
+description = "Library for creating tunnel devices and interfacing with various VPN tunnels"
+license = "GPL-3.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+err-derive = "0.3.1"
+cfg-if = "1.0"
+ipnetwork = "0.16"
+talpid-routing = { path = "../talpid-routing" }
+talpid-types = { path = "../talpid-types" }
+futures = "0.3.15"
+tokio = { version = "1.8", features = ["process", "rt-multi-thread", "fs"] }
+
+[target.'cfg(unix)'.dependencies]
+duct = "0.13"
+nix = "0.23"
+
+[target.'cfg(target_os = "android")'.dependencies]
+jnix = { version = "0.5", features = ["derive"] }
+log = "0.4"
+
+[target.'cfg(target_os = "linux")'.dependencies]
+tun = "0.5.1"
+
+[target.'cfg(target_os = "macos")'.dependencies]
+tun = "0.5.1"
+
+[target.'cfg(windows)'.dependencies]
+talpid-windows-net = { path = "../talpid-windows-net" }
+
+[target.'cfg(windows)'.dependencies.windows-sys]
+version = "0.42.0"
+features = [
+ "Win32_Foundation",
+ "Win32_Networking_WinSock",
+ "Win32_NetworkManagement_Ndis",
+]
diff --git a/talpid-tunnel/src/lib.rs b/talpid-tunnel/src/lib.rs
new file mode 100644
index 0000000000..fc964ae82e
--- /dev/null
+++ b/talpid-tunnel/src/lib.rs
@@ -0,0 +1,62 @@
+use std::{
+ net::{IpAddr, Ipv4Addr, Ipv6Addr},
+ path::Path,
+ sync::{Arc, Mutex},
+};
+
+#[cfg(windows)]
+#[path = "windows.rs"]
+pub mod network_interface;
+
+pub mod tun_provider;
+use futures::{channel::oneshot, future::BoxFuture};
+use talpid_routing::RouteManagerHandle;
+use talpid_types::net::AllowedTunnelTraffic;
+use tun_provider::TunProvider;
+
+/// Arguments for creating a tunnel.
+pub struct TunnelArgs<'a, L>
+where
+ L: (Fn(TunnelEvent) -> BoxFuture<'static, ()>) + Send + Clone + Sync + 'static,
+{
+ /// Toktio runtime handle.
+ pub runtime: tokio::runtime::Handle,
+ /// Resource directory path.
+ pub resource_dir: &'a Path,
+ /// Callback function called when an event happens.
+ pub on_event: L,
+ /// Receiver oneshot channel for closing the tunnel.
+ pub tunnel_close_rx: oneshot::Receiver<()>,
+ /// Mutex to tunnel provider.
+ pub tun_provider: Arc<Mutex<TunProvider>>,
+ /// Connection retry attempts.
+ pub retry_attempt: u32,
+ /// Route manager handle.
+ pub route_manager: RouteManagerHandle,
+}
+
+/// Information about a VPN tunnel.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct TunnelMetadata {
+ /// The name of the device which the tunnel is running on.
+ pub interface: String,
+ /// The local IPs on the tunnel interface.
+ pub ips: Vec<IpAddr>,
+ /// The IP to the default gateway on the tunnel interface.
+ pub ipv4_gateway: Ipv4Addr,
+ /// The IP to the IPv6 default gateway on the tunnel interface.
+ pub ipv6_gateway: Option<Ipv6Addr>,
+}
+
+/// Possible events from the VPN tunnel and the child process managing it.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub enum TunnelEvent {
+ /// Sent when the tunnel fails to connect due to an authentication error.
+ AuthFailed(Option<String>),
+ /// Sent when the tunnel interface has been created, before routes are set up.
+ InterfaceUp(TunnelMetadata, AllowedTunnelTraffic),
+ /// Sent when the tunnel comes up and is ready for traffic.
+ Up(TunnelMetadata),
+ /// Sent when the tunnel goes down.
+ Down,
+}
diff --git a/talpid-core/src/tunnel/tun_provider/android/ipnetwork_sub.rs b/talpid-tunnel/src/tun_provider/android/ipnetwork_sub.rs
index ffaa585302..ffaa585302 100644
--- a/talpid-core/src/tunnel/tun_provider/android/ipnetwork_sub.rs
+++ b/talpid-tunnel/src/tun_provider/android/ipnetwork_sub.rs
diff --git a/talpid-core/src/tunnel/tun_provider/android/mod.rs b/talpid-tunnel/src/tun_provider/android/mod.rs
index b7ab5665d2..1cb6a49de4 100644
--- a/talpid-core/src/tunnel/tun_provider/android/mod.rs
+++ b/talpid-tunnel/src/tun_provider/android/mod.rs
@@ -65,6 +65,7 @@ pub struct AndroidTunProvider {
last_tun_config: TunConfig,
allow_lan: bool,
custom_dns_servers: Option<Vec<IpAddr>>,
+ allowed_lan_networks: Vec<IpNetwork>,
}
impl AndroidTunProvider {
@@ -73,6 +74,7 @@ impl AndroidTunProvider {
context: AndroidContext,
allow_lan: bool,
custom_dns_servers: Option<Vec<IpAddr>>,
+ allowed_lan_networks: Vec<IpNetwork>,
) -> Self {
let env = JnixEnv::from(
context
@@ -89,6 +91,7 @@ impl AndroidTunProvider {
last_tun_config: TunConfig::default(),
allow_lan,
custom_dns_servers,
+ allowed_lan_networks,
}
}
@@ -234,12 +237,11 @@ impl AndroidTunProvider {
.cloned()
.partition::<Vec<_>, _>(|route| route.is_ipv4());
- let (original_lan_ipv4_networks, original_lan_ipv6_networks) =
- crate::firewall::ALLOWED_LAN_NETS
- .iter()
- .chain(crate::firewall::ALLOWED_LAN_MULTICAST_NETS.iter())
- .cloned()
- .partition::<Vec<_>, _>(|network| network.is_ipv4());
+ let (original_lan_ipv4_networks, original_lan_ipv6_networks) = self
+ .allowed_lan_networks
+ .iter()
+ .cloned()
+ .partition::<Vec<_>, _>(|network| network.is_ipv4());
let lan_ipv4_networks = original_lan_ipv4_networks
.into_iter()
diff --git a/talpid-core/src/tunnel/tun_provider/mod.rs b/talpid-tunnel/src/tun_provider/mod.rs
index 9ac1e14895..9ac1e14895 100644
--- a/talpid-core/src/tunnel/tun_provider/mod.rs
+++ b/talpid-tunnel/src/tun_provider/mod.rs
diff --git a/talpid-core/src/tunnel/tun_provider/stub.rs b/talpid-tunnel/src/tun_provider/stub.rs
index ff659210cf..ff659210cf 100644
--- a/talpid-core/src/tunnel/tun_provider/stub.rs
+++ b/talpid-tunnel/src/tun_provider/stub.rs
diff --git a/talpid-core/src/network_interface.rs b/talpid-tunnel/src/tun_provider/unix.rs
index 0e00dd9b9f..106b3353a6 100644
--- a/talpid-core/src/network_interface.rs
+++ b/talpid-tunnel/src/tun_provider/unix.rs
@@ -1,15 +1,83 @@
+use super::TunConfig;
use nix::fcntl;
use std::{
io,
net::IpAddr,
+ ops::Deref,
os::unix::io::{AsRawFd, IntoRawFd, RawFd},
};
use tun::{platform, Configuration, Device};
+/// Errors that can occur while setting up a tunnel device.
+#[derive(Debug, err_derive::Error)]
+#[error(no_from)]
+pub enum Error {
+ /// Failure to create a tunnel device.
+ #[error(display = "Failed to create a tunnel device")]
+ CreateTunnelDevice(#[cause] NetworkInterfaceError),
+
+ /// Failure to set a tunnel device IP address.
+ #[error(display = "Failed to set tunnel IP address: {}", _0)]
+ SetIpAddr(IpAddr, #[cause] NetworkInterfaceError),
+
+ /// Failure to set the tunnel device as up.
+ #[error(display = "Failed to set the tunnel device as up")]
+ SetUp(#[cause] NetworkInterfaceError),
+}
+
+/// Factory of tunnel devices on Unix systems.
+pub struct UnixTunProvider;
+
+impl Default for UnixTunProvider {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl UnixTunProvider {
+ pub fn new() -> Self {
+ UnixTunProvider
+ }
+
+ pub fn get_tun(&mut self, config: TunConfig) -> Result<UnixTun, Error> {
+ let mut tunnel_device = TunnelDevice::new().map_err(Error::CreateTunnelDevice)?;
+
+ for ip in config.addresses.iter() {
+ tunnel_device
+ .set_ip(*ip)
+ .map_err(|cause| Error::SetIpAddr(*ip, cause))?;
+ }
+
+ tunnel_device.set_up(true).map_err(Error::SetUp)?;
+
+ Ok(UnixTun(tunnel_device))
+ }
+}
+
+/// Generic tunnel device.
+///
+/// Contains the file descriptor representing the device.
+pub struct UnixTun(TunnelDevice);
+
+impl UnixTun {
+ /// Retrieve the tunnel interface name.
+ pub fn interface_name(&self) -> &str {
+ self.get_name()
+ }
+}
+
+impl Deref for UnixTun {
+ type Target = TunnelDevice;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
/// Errors that can happen when working with *nix tunnel interfaces.
#[derive(err_derive::Error, Debug)]
#[error(no_from)]
-pub enum Error {
+pub enum NetworkInterfaceError {
/// Failed to set IP address
#[error(display = "Failed to set IPv4 address")]
SetIpv4Error(#[error(source)] tun::Error),
@@ -34,20 +102,18 @@ pub enum Error {
/// A trait for managing link devices
pub trait NetworkInterface: Sized {
/// Bring a given interface up or down
- fn set_up(&mut self, up: bool) -> Result<(), Error>;
+ fn set_up(&mut self, up: bool) -> Result<(), NetworkInterfaceError>;
/// Set host IPs for interface
- fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error>;
+ fn set_ip(&mut self, ip: IpAddr) -> Result<(), NetworkInterfaceError>;
/// Set MTU for interface
- fn set_mtu(&mut self, mtu: u16) -> Result<(), Error>;
+ fn set_mtu(&mut self, mtu: u16) -> Result<(), NetworkInterfaceError>;
/// Get name of interface
fn get_name(&self) -> &str;
}
-trait WireguardLink: AsRawFd + IntoRawFd {}
-
fn apply_async_flags(fd: RawFd) -> Result<(), nix::Error> {
fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFL)?;
let arg = fcntl::FcntlArg::F_SETFL(fcntl::OFlag::O_RDWR | fcntl::OFlag::O_NONBLOCK);
@@ -55,7 +121,7 @@ fn apply_async_flags(fd: RawFd) -> Result<(), nix::Error> {
Ok(())
}
-/// A tunnel devie
+/// A tunnel device
pub struct TunnelDevice {
dev: platform::Device,
}
@@ -63,15 +129,16 @@ pub struct TunnelDevice {
impl TunnelDevice {
/// Creates a new Tunnel device
#[allow(unused_mut)]
- pub fn new() -> Result<Self, Error> {
+ pub fn new() -> Result<Self, NetworkInterfaceError> {
let mut config = Configuration::default();
#[cfg(target_os = "linux")]
config.platform(|config| {
config.packet_information(true);
});
- let mut dev = platform::create(&config).map_err(Error::CreateDeviceError)?;
- apply_async_flags(dev.as_raw_fd()).map_err(Error::SetDeviceAsyncError)?;
+ let mut dev =
+ platform::create(&config).map_err(NetworkInterfaceError::CreateDeviceError)?;
+ apply_async_flags(dev.as_raw_fd()).map_err(NetworkInterfaceError::SetDeviceAsyncError)?;
Ok(Self { dev })
}
}
@@ -89,9 +156,12 @@ impl IntoRawFd for TunnelDevice {
}
impl NetworkInterface for TunnelDevice {
- fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
+ fn set_ip(&mut self, ip: IpAddr) -> Result<(), NetworkInterfaceError> {
match ip {
- IpAddr::V4(ipv4) => self.dev.set_address(ipv4).map_err(Error::SetIpv4Error),
+ IpAddr::V4(ipv4) => self
+ .dev
+ .set_address(ipv4)
+ .map_err(NetworkInterfaceError::SetIpv4Error),
IpAddr::V6(ipv6) => {
#[cfg(target_os = "linux")]
{
@@ -106,7 +176,7 @@ impl NetworkInterface for TunnelDevice {
)
.run()
.map(|_| ())
- .map_err(Error::SetIpv6Error)
+ .map_err(NetworkInterfaceError::SetIpv6Error)
}
#[cfg(target_os = "macos")]
{
@@ -119,20 +189,22 @@ impl NetworkInterface for TunnelDevice {
)
.run()
.map(|_| ())
- .map_err(Error::SetIpv6Error)
+ .map_err(NetworkInterfaceError::SetIpv6Error)
}
}
}
}
- fn set_up(&mut self, up: bool) -> Result<(), Error> {
- self.dev.enabled(up).map_err(Error::ToggleDeviceError)
+ fn set_up(&mut self, up: bool) -> Result<(), NetworkInterfaceError> {
+ self.dev
+ .enabled(up)
+ .map_err(NetworkInterfaceError::ToggleDeviceError)
}
- fn set_mtu(&mut self, mtu: u16) -> Result<(), Error> {
+ fn set_mtu(&mut self, mtu: u16) -> Result<(), NetworkInterfaceError> {
self.dev
.set_mtu(i32::from(mtu))
- .map_err(Error::ToggleDeviceError)
+ .map_err(NetworkInterfaceError::ToggleDeviceError)
}
fn get_name(&self) -> &str {
diff --git a/talpid-core/src/tunnel/windows.rs b/talpid-tunnel/src/windows.rs
index cb1cea345c..d9c54f6940 100644
--- a/talpid-core/src/tunnel/windows.rs
+++ b/talpid-tunnel/src/windows.rs
@@ -1,5 +1,5 @@
-use crate::windows::{get_ip_interface_entry, set_ip_interface_entry, AddressFamily};
use std::io;
+use talpid_windows_net::{get_ip_interface_entry, set_ip_interface_entry, AddressFamily};
use windows_sys::Win32::{
Foundation::ERROR_NOT_FOUND, NetworkManagement::Ndis::NET_LUID_LH,
Networking::WinSock::RouterDiscoveryDisabled,
diff --git a/talpid-types/src/net/openvpn.rs b/talpid-types/src/net/openvpn.rs
index 97fdf07de2..aaf08103c3 100644
--- a/talpid-types/src/net/openvpn.rs
+++ b/talpid-types/src/net/openvpn.rs
@@ -117,6 +117,8 @@ pub struct ShadowsocksProxySettings {
/// Password on peer.
pub password: String,
pub cipher: String,
+ #[cfg(target_os = "linux")]
+ pub fwmark: Option<u32>,
}
impl ShadowsocksProxySettings {
diff --git a/talpid-types/src/net/wireguard.rs b/talpid-types/src/net/wireguard.rs
index b5c3268af5..a6acb6fc6f 100644
--- a/talpid-types/src/net/wireguard.rs
+++ b/talpid-types/src/net/wireguard.rs
@@ -30,6 +30,8 @@ pub struct ConnectionConfig {
/// Gateway used by the tunnel (a private address).
pub ipv4_gateway: Ipv4Addr,
pub ipv6_gateway: Option<Ipv6Addr>,
+ #[cfg(target_os = "linux")]
+ pub fwmark: Option<u32>,
}
impl ConnectionConfig {
diff --git a/talpid-windows-net/Cargo.toml b/talpid-windows-net/Cargo.toml
new file mode 100644
index 0000000000..044d5efdd9
--- /dev/null
+++ b/talpid-windows-net/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "talpid-windows-net"
+version = "0.0.0"
+authors = ["Mullvad VPN"]
+description = "Work with Windows network interfaces and their configuration"
+license = "GPL-3.0"
+edition = "2021"
+publish = false
+
+[target.'cfg(windows)'.dependencies]
+err-derive = "0.3.1"
+libc = "0.2"
+socket2 = { version = "0.4.2", features = ["all"] }
+futures = "0.3.15"
+winapi = { version = "0.3.6", features = ["ws2def"] }
+windows-sys = { version = "0.42", features = [
+ "Win32_Foundation",
+ "Win32_Globalization",
+ "Win32_System_Com",
+ "Win32_System_IO",
+ "Win32_Networking_WinSock",
+ "Win32_NetworkManagement_IpHelper",
+ "Win32_NetworkManagement_Ndis",
+]}
diff --git a/talpid-windows-net/src/lib.rs b/talpid-windows-net/src/lib.rs
new file mode 100644
index 0000000000..48dc8062ee
--- /dev/null
+++ b/talpid-windows-net/src/lib.rs
@@ -0,0 +1,10 @@
+//! Interface with low-level windows specific bits.
+
+#![deny(missing_docs)]
+#![deny(rust_2018_idioms)]
+
+/// Nicer interfaces with Windows networking code.
+#[cfg(windows)]
+pub mod net;
+#[cfg(windows)]
+pub use net::*;
diff --git a/talpid-core/src/windows/mod.rs b/talpid-windows-net/src/net.rs
index 5504e11d93..6a11cf7018 100644
--- a/talpid-core/src/windows/mod.rs
+++ b/talpid-windows-net/src/net.rs
@@ -6,17 +6,14 @@ use std::{
mem::{self, MaybeUninit},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
os::windows::ffi::{OsStrExt, OsStringExt},
- path::PathBuf,
- ptr,
sync::Mutex,
time::{Duration, Instant},
};
-use widestring::WideCStr;
use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage;
use windows_sys::{
- core::{GUID, PWSTR},
+ core::GUID,
Win32::{
- Foundation::{ERROR_NOT_FOUND, HANDLE, NO_ERROR, S_OK},
+ Foundation::{ERROR_NOT_FOUND, HANDLE, NO_ERROR},
NetworkManagement::{
IpHelper::{
CancelMibChangeNotify2, ConvertInterfaceAliasToLuid, ConvertInterfaceLuidToAlias,
@@ -33,13 +30,9 @@ use windows_sys::{
IpDadStateTentative, AF_INET, AF_INET6, AF_UNSPEC, IN6_ADDR, IN_ADDR, NL_DAD_STATE,
SOCKADDR_IN as sockaddr_in, SOCKADDR_IN6 as sockaddr_in6, SOCKADDR_INET,
},
- System::Com::{CoTaskMemFree, StringFromGUID2},
- UI::Shell::{FOLDERID_System, SHGetKnownFolderPath},
},
};
-pub mod window;
-
/// Result type for this module.
pub type Result<T> = std::result::Result<T, Error>;
@@ -90,20 +83,34 @@ pub enum Error {
UnknownAddressFamily(u32),
}
-/// Address family. These correspond to the `AF_*` constants.
-#[derive(Debug, Clone, Copy)]
-pub enum AddressFamily {
- /// IPv4 address family
- Ipv4 = AF_INET as isize,
- /// IPv6 address family
- Ipv6 = AF_INET6 as isize,
+/// Handles cases where there DAD state is neither tentative nor preferred.
+#[derive(err_derive::Error, Debug)]
+pub enum DadStateError {
+ /// Invalid DAD state.
+ #[error(display = "Invalid DAD state")]
+ Invalid,
+
+ /// Duplicate unicast address.
+ #[error(display = "A duplicate IP address was detected")]
+ Duplicate,
+
+ /// Deprecated unicast address.
+ #[error(display = "The IP address has been deprecated")]
+ Deprecated,
+
+ /// Unknown DAD state constant.
+ #[error(display = "Unknown DAD state: {}", _0)]
+ Unknown(i32),
}
-impl fmt::Display for AddressFamily {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- AddressFamily::Ipv4 => write!(f, "IPv4 (AF_INET)"),
- AddressFamily::Ipv6 => write!(f, "IPv6 (AF_INET6)"),
+#[allow(non_upper_case_globals)]
+impl From<NL_DAD_STATE> for DadStateError {
+ fn from(state: NL_DAD_STATE) -> DadStateError {
+ match state {
+ IpDadStateInvalid => DadStateError::Invalid,
+ IpDadStateDuplicate => DadStateError::Duplicate,
+ IpDadStateDeprecated => DadStateError::Deprecated,
+ other => DadStateError::Unknown(other),
}
}
}
@@ -263,38 +270,6 @@ pub async fn wait_for_interfaces(luid: NET_LUID_LH, ipv4: bool, ipv6: bool) -> i
Ok(())
}
-/// Handles cases where there DAD state is neither tentative nor preferred.
-#[derive(err_derive::Error, Debug)]
-pub enum DadStateError {
- /// Invalid DAD state.
- #[error(display = "Invalid DAD state")]
- Invalid,
-
- /// Duplicate unicast address.
- #[error(display = "A duplicate IP address was detected")]
- Duplicate,
-
- /// Deprecated unicast address.
- #[error(display = "The IP address has been deprecated")]
- Deprecated,
-
- /// Unknown DAD state constant.
- #[error(display = "Unknown DAD state: {}", _0)]
- Unknown(i32),
-}
-
-#[allow(non_upper_case_globals)]
-impl From<NL_DAD_STATE> for DadStateError {
- fn from(state: NL_DAD_STATE) -> DadStateError {
- match state {
- IpDadStateInvalid => DadStateError::Invalid,
- IpDadStateDuplicate => DadStateError::Duplicate,
- IpDadStateDeprecated => DadStateError::Deprecated,
- other => DadStateError::Unknown(other),
- }
- }
-}
-
/// Wait for addresses to be usable on an network adapter.
pub async fn wait_for_addresses(luid: NET_LUID_LH) -> Result<()> {
// Obtain unicast IP addresses
@@ -402,17 +377,6 @@ pub fn get_unicast_table(
Ok(unicast_rows)
}
-/// Obtain a string representation for a GUID object.
-pub fn string_from_guid(guid: &GUID) -> String {
- let mut buffer = [0u16; 40];
- let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) }
- as usize;
- // cannot fail because `buffer` is large enough
- assert!(length > 0);
- let length = length - 1;
- String::from_utf16(&buffer[0..length]).unwrap()
-}
-
/// Returns the GUID of a network interface given its LUID.
pub fn guid_from_luid(luid: &NET_LUID_LH) -> io::Result<GUID> {
let mut guid = MaybeUninit::zeroed();
@@ -509,27 +473,22 @@ pub fn try_socketaddr_from_inet_sockaddr(addr: SOCKADDR_INET) -> Result<SocketAd
.ok_or(Error::UnknownAddressFamily(family))
}
-/// Returns the system directory, i.e. `%windir%\system32`.
-pub fn get_system_dir() -> io::Result<PathBuf> {
- let mut folder_path: PWSTR = ptr::null_mut();
- let status = unsafe { SHGetKnownFolderPath(&FOLDERID_System, 0, 0, &mut folder_path) };
- let result = if status == S_OK {
- let path = unsafe { WideCStr::from_ptr_str(folder_path) };
- Ok(path.to_ustring().to_os_string().into())
- } else {
- Err(io::Error::new(
- io::ErrorKind::NotFound,
- "Cannot find the system directory",
- ))
- };
- unsafe { CoTaskMemFree(folder_path as *mut _) };
- result
+/// Address family. These correspond to the `AF_*` constants.
+#[derive(Debug, Clone, Copy)]
+pub enum AddressFamily {
+ /// IPv4 address family
+ Ipv4 = AF_INET as isize,
+ /// IPv6 address family
+ Ipv6 = AF_INET6 as isize,
}
-/// Casts a struct to a slice of possibly uninitialized bytes.
-#[cfg(target_os = "windows")]
-pub fn as_uninit_byte_slice<T: Copy + Sized>(value: &T) -> &[mem::MaybeUninit<u8>] {
- unsafe { std::slice::from_raw_parts(value as *const _ as *const _, mem::size_of::<T>()) }
+impl fmt::Display for AddressFamily {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ AddressFamily::Ipv4 => write!(f, "IPv4 (AF_INET)"),
+ AddressFamily::Ipv6 => write!(f, "IPv6 (AF_INET6)"),
+ }
+ }
}
#[cfg(test)]
diff --git a/talpid-wireguard/Cargo.toml b/talpid-wireguard/Cargo.toml
new file mode 100644
index 0000000000..162492e8cb
--- /dev/null
+++ b/talpid-wireguard/Cargo.toml
@@ -0,0 +1,78 @@
+[package]
+name = "talpid-wireguard"
+version = "0.0.0"
+authors = ["Mullvad VPN"]
+description = "Library for creating various WireGuard tunnels"
+license = "GPL-3.0"
+edition = "2021"
+publish = false
+
+
+[dependencies]
+err-derive = "0.3.1"
+futures = "0.3.15"
+hex = "0.4"
+ipnetwork = "0.16"
+lazy_static = "1.0"
+libc = "0.2"
+log = "0.4"
+parking_lot = "0.11"
+talpid-routing = { path = "../talpid-routing" }
+talpid-types = { path = "../talpid-types" }
+talpid-tunnel-config-client = { path = "../talpid-tunnel-config-client" }
+talpid-tunnel = { path = "../talpid-tunnel" }
+zeroize = "1"
+chrono = "0.4.21"
+tokio = { version = "1.8", features = ["process", "rt-multi-thread", "fs"] }
+tunnel-obfuscation = { path = "../tunnel-obfuscation" }
+rand = "0.8.5"
+
+[target.'cfg(target_os="android")'.dependencies]
+duct = "0.13"
+
+[target.'cfg(not(target_os="android"))'.dependencies]
+byteorder = "1"
+internet-checksum = "0.2"
+socket2 = { version = "0.4.2", features = ["all"] }
+
+[target.'cfg(unix)'.dependencies]
+nix = "0.23"
+
+[target.'cfg(target_os = "linux")'.dependencies]
+rtnetlink = "0.11"
+netlink-packet-core = "0.4.2"
+netlink-packet-route = "0.13"
+netlink-packet-utils = "0.5.1"
+netlink-proto = "0.10"
+talpid-dbus = { path = "../talpid-dbus" }
+tokio-stream = { version = "0.1", features = ["io-util"] }
+
+[target.'cfg(windows)'.dependencies]
+bitflags = "1.2"
+talpid-windows-net = { path = "../talpid-windows-net" }
+widestring = "0.5"
+
+# Figure out which features are needed and which are not
+[target.'cfg(windows)'.dependencies.windows-sys]
+version = "0.42.0"
+features = [
+ "Win32_Foundation",
+ "Win32_Globalization",
+ "Win32_Security",
+ "Win32_System_Com",
+ "Win32_System_Diagnostics_ToolHelp",
+ "Win32_System_Ioctl",
+ "Win32_System_IO",
+ "Win32_System_LibraryLoader",
+ "Win32_System_ProcessStatus",
+ "Win32_System_Registry",
+ "Win32_System_Services",
+ "Win32_System_SystemServices",
+ "Win32_System_Threading",
+ "Win32_System_WindowsProgramming",
+ "Win32_Networking_WinSock",
+ "Win32_NetworkManagement_IpHelper",
+ "Win32_NetworkManagement_Ndis",
+ "Win32_UI_Shell",
+ "Win32_UI_WindowsAndMessaging",
+]
diff --git a/talpid-wireguard/build.rs b/talpid-wireguard/build.rs
new file mode 100644
index 0000000000..bcf7f1cfbf
--- /dev/null
+++ b/talpid-wireguard/build.rs
@@ -0,0 +1,36 @@
+use std::{env, path::PathBuf};
+
+fn main() {
+ let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS not set");
+
+ declare_libs_dir("../dist-assets/binaries");
+ declare_libs_dir("../build/lib");
+
+ let link_type = match target_os.as_str() {
+ "android" => "",
+ "linux" | "macos" => "=static",
+ // We would like to avoid panicing on windows even if we can not link correctly
+ // because we would like to be able to run check and clippy.
+ // This does not allow for correct linking or buijding.
+ #[cfg(not(windows))]
+ "windows" => "",
+ #[cfg(windows)]
+ "windows" => "dylib",
+ _ => panic!("Unsupported platform: {}", target_os),
+ };
+
+ println!("cargo:rustc-link-lib{}=wg", link_type);
+}
+
+fn declare_libs_dir(base: &str) {
+ let target_triplet = env::var("TARGET").expect("TARGET is not set");
+ let lib_dir = manifest_dir().join(base).join(target_triplet);
+ println!("cargo:rerun-if-changed={}", lib_dir.display());
+ println!("cargo:rustc-link-search={}", lib_dir.display());
+}
+
+fn manifest_dir() -> PathBuf {
+ env::var("CARGO_MANIFEST_DIR")
+ .map(PathBuf::from)
+ .expect("CARGO_MANIFEST_DIR env var not set")
+}
diff --git a/talpid-core/src/tunnel/wireguard/config.rs b/talpid-wireguard/src/config.rs
index 89cab4865a..2198b5a3fe 100644
--- a/talpid-core/src/tunnel/wireguard/config.rs
+++ b/talpid-wireguard/src/config.rs
@@ -20,7 +20,7 @@ pub struct Config {
pub mtu: u16,
/// Firewall mark
#[cfg(target_os = "linux")]
- pub fwmark: u32,
+ pub fwmark: Option<u32>,
/// Enable IPv6 routing rules
#[cfg(target_os = "linux")]
pub enable_ipv6: bool,
@@ -118,7 +118,7 @@ impl Config {
ipv6_gateway,
mtu,
#[cfg(target_os = "linux")]
- fwmark: crate::linux::TUNNEL_FW_MARK,
+ fwmark: connection_config.fwmark,
#[cfg(target_os = "linux")]
enable_ipv6: generic_options.enable_ipv6,
#[cfg(target_os = "windows")]
@@ -137,7 +137,9 @@ impl Config {
.add("listen_port", "0");
#[cfg(target_os = "linux")]
- wg_conf.add("fwmark", self.fwmark.to_string().as_str());
+ if let Some(fwmark) = &self.fwmark {
+ wg_conf.add("fwmark", fwmark.to_string().as_str());
+ }
wg_conf.add("replace_peers", "true");
diff --git a/talpid-core/src/tunnel/wireguard/connectivity_check.rs b/talpid-wireguard/src/connectivity_check.rs
index cce8b53ec4..02283add65 100644
--- a/talpid-core/src/tunnel/wireguard/connectivity_check.rs
+++ b/talpid-wireguard/src/connectivity_check.rs
@@ -1,6 +1,6 @@
use crate::{
ping_monitor::{new_pinger, Pinger},
- tunnel::wireguard::stats::StatsMap,
+ stats::StatsMap,
};
use std::{
cmp,
@@ -391,7 +391,7 @@ mod test {
use futures::Future;
use super::*;
- use crate::tunnel::wireguard::{
+ use crate::{
config::Config,
stats::{self, Stats},
TunnelError,
diff --git a/talpid-core/src/tunnel/wireguard/mod.rs b/talpid-wireguard/src/lib.rs
index b982dc148d..da4ea128a7 100644
--- a/talpid-core/src/tunnel/wireguard/mod.rs
+++ b/talpid-wireguard/src/lib.rs
@@ -1,8 +1,9 @@
+//! Manage WireGuard tunnels.
+
+#![deny(missing_docs)]
+#![deny(rust_2018_idioms)]
+
use self::config::Config;
-#[cfg(not(windows))]
-use super::tun_provider;
-use super::{tun_provider::TunProvider, TunnelArgs, TunnelEvent, TunnelMetadata};
-use crate::routing::{self, RequiredRoute};
use futures::future::{abortable, AbortHandle as FutureAbortHandle, BoxFuture, Future};
#[cfg(windows)]
use futures::{channel::mpsc, StreamExt};
@@ -23,6 +24,12 @@ use std::{
sync::{mpsc as sync_mpsc, Arc, Mutex},
time::Duration,
};
+use talpid_routing as routing;
+use talpid_routing::{self, RequiredRoute};
+#[cfg(not(windows))]
+use talpid_tunnel::tun_provider;
+use talpid_tunnel::{tun_provider::TunProvider, TunnelArgs, TunnelEvent, TunnelMetadata};
+
#[cfg(windows)]
use talpid_types::BoxedError;
use talpid_types::{
@@ -41,6 +48,7 @@ use tunnel_obfuscation::{
pub mod config;
mod connectivity_check;
mod logging;
+mod ping_monitor;
mod stats;
mod wireguard_go;
#[cfg(target_os = "linux")]
@@ -59,7 +67,7 @@ type EventCallback = Box<dyn (Fn(TunnelEvent) -> BoxFuture<'static, ()>) + Send
pub enum Error {
/// Failed to set up routing.
#[error(display = "Failed to setup routing")]
- SetupRoutingError(#[error(source)] crate::routing::Error),
+ SetupRoutingError(#[error(source)] talpid_routing::Error),
/// Tunnel timed out
#[error(display = "Tunnel timed out")]
@@ -93,7 +101,7 @@ pub enum Error {
/// Failed to set IP addresses on WireGuard interface
#[cfg(target_os = "windows")]
#[error(display = "Failed to set IP addresses on WireGuard interface")]
- SetIpAddressesError(#[error(source)] crate::windows::Error),
+ SetIpAddressesError(#[error(source)] talpid_windows_net::Error),
}
/// Spawns and monitors a wireguard tunnel
@@ -160,7 +168,7 @@ async fn maybe_create_obfuscator(
let settings = Udp2TcpSettings {
peer: *endpoint,
#[cfg(target_os = "linux")]
- fwmark: Some(crate::linux::TUNNEL_FW_MARK),
+ fwmark: config.fwmark,
};
let obfuscator = create_obfuscator(&ObfuscationSettings::Udp2Tcp(settings))
.await
@@ -423,12 +431,12 @@ impl WireguardMonitor {
})?;
// TODO: The LUID can be obtained directly.
- let luid = crate::windows::luid_from_alias(iface_name).map_err(|error| {
+ let luid = talpid_windows_net::luid_from_alias(iface_name).map_err(|error| {
log::error!("Failed to obtain tunnel interface LUID: {}", error);
CloseMsg::SetupError(Error::IpInterfacesError)
})?;
for address in addresses {
- crate::windows::add_ip_address_for_interface(luid, *address)
+ talpid_windows_net::add_ip_address_for_interface(luid, *address)
.map_err(|error| CloseMsg::SetupError(Error::SetIpAddressesError(error)))?;
}
Ok(())
@@ -514,7 +522,7 @@ impl WireguardMonitor {
) -> Result<Box<dyn Tunnel>> {
#[cfg(target_os = "linux")]
if !*FORCE_USERSPACE_WIREGUARD {
- if crate::dns::will_use_nm() {
+ if will_nm_manage_dns() {
match wireguard_kernel::NetworkManagerTunnel::new(runtime, config) {
Ok(tunnel) => {
log::debug!("Using NetworkManager to use kernel WireGuard implementation");
@@ -627,7 +635,7 @@ impl WireguardMonitor {
#[cfg(target_os = "linux")]
{
// No need due to policy based routing.
- std::iter::empty()
+ std::iter::empty::<RequiredRoute>()
}
#[cfg(not(target_os = "linux"))]
endpoints.iter().map(|ip| {
@@ -838,3 +846,19 @@ pub enum TunnelError {
#[error(display = "Failed to set up logging")]
LoggingError(#[error(source)] logging::Error),
}
+
+#[cfg(target_os = "linux")]
+fn will_nm_manage_dns() -> bool {
+ use talpid_dbus::network_manager::NetworkManager;
+
+ if talpid_dbus::systemd_resolved::SystemdResolved::new().is_ok() {
+ return false;
+ }
+
+ NetworkManager::new()
+ .and_then(|nm| {
+ nm.ensure_can_be_used_to_manage_dns()?;
+ Ok(true)
+ })
+ .unwrap_or(false)
+}
diff --git a/talpid-core/src/tunnel/wireguard/logging.rs b/talpid-wireguard/src/logging.rs
index 35ec10fc2f..35ec10fc2f 100644
--- a/talpid-core/src/tunnel/wireguard/logging.rs
+++ b/talpid-wireguard/src/logging.rs
diff --git a/talpid-core/src/ping_monitor/android.rs b/talpid-wireguard/src/ping_monitor/android.rs
index 9263dbac79..9263dbac79 100644
--- a/talpid-core/src/ping_monitor/android.rs
+++ b/talpid-wireguard/src/ping_monitor/android.rs
diff --git a/talpid-core/src/ping_monitor/icmp.rs b/talpid-wireguard/src/ping_monitor/icmp.rs
index 0bcd9da72f..0bcd9da72f 100644
--- a/talpid-core/src/ping_monitor/icmp.rs
+++ b/talpid-wireguard/src/ping_monitor/icmp.rs
diff --git a/talpid-core/src/ping_monitor/mod.rs b/talpid-wireguard/src/ping_monitor/mod.rs
index 9b105a50dc..9b105a50dc 100644
--- a/talpid-core/src/ping_monitor/mod.rs
+++ b/talpid-wireguard/src/ping_monitor/mod.rs
diff --git a/talpid-core/src/tunnel/wireguard/stats.rs b/talpid-wireguard/src/stats.rs
index bd7b578545..bd7b578545 100644
--- a/talpid-core/src/tunnel/wireguard/stats.rs
+++ b/talpid-wireguard/src/stats.rs
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_go.rs b/talpid-wireguard/src/wireguard_go.rs
index a1ca8be6ba..4232d99e70 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_go.rs
+++ b/talpid-wireguard/src/wireguard_go.rs
@@ -2,15 +2,9 @@ use super::{
stats::{Stats, StatsMap},
Config, Tunnel, TunnelError,
};
-#[cfg(not(windows))]
-use crate::tunnel::tun_provider::TunProvider;
-use crate::tunnel::wireguard::logging::{
- clean_up_logging, initialize_logging, wg_go_logging_callback, WgLogLevel,
-};
+use crate::logging::{clean_up_logging, initialize_logging, wg_go_logging_callback, WgLogLevel};
#[cfg(windows)]
use futures::SinkExt;
-#[cfg(not(windows))]
-use ipnetwork::IpNetwork;
use std::{
ffi::{c_void, CStr},
future::Future,
@@ -21,20 +15,22 @@ use std::{
#[cfg(windows)]
use talpid_types::BoxedError;
use zeroize::Zeroize;
+#[cfg(not(windows))]
+use {ipnetwork::IpNetwork, talpid_tunnel::tun_provider::TunProvider};
#[cfg(target_os = "windows")]
use std::ffi::CString;
#[cfg(target_os = "android")]
-use crate::tunnel::tun_provider;
+use talpid_tunnel::tun_provider;
#[cfg(not(target_os = "windows"))]
use {
- crate::tunnel::tun_provider::{Tun, TunConfig},
std::{
net::IpAddr,
os::unix::io::{AsRawFd, RawFd},
},
+ talpid_tunnel::tun_provider::{Tun, TunConfig},
};
type Result<T> = std::result::Result<T, TunnelError>;
@@ -63,7 +59,7 @@ pub struct WgGoTunnel {
// context that maps to fs::File instance, used with logging callback
_logging_context: LoggingContext,
#[cfg(target_os = "windows")]
- _route_callback_handle: Option<crate::routing::CallbackHandle>,
+ _route_callback_handle: Option<talpid_routing::CallbackHandle>,
#[cfg(target_os = "windows")]
setup_handle: tokio::task::JoinHandle<()>,
}
@@ -114,7 +110,7 @@ impl WgGoTunnel {
pub fn start_tunnel(
config: &Config,
log_path: Option<&Path>,
- route_manager_handle: crate::tunnel::RouteManagerHandle,
+ route_manager_handle: talpid_routing::RouteManagerHandle,
mut done_tx: futures::channel::mpsc::Sender<std::result::Result<(), BoxedError>>,
runtime: &tokio::runtime::Handle,
) -> Result<Self> {
@@ -176,9 +172,11 @@ impl WgGoTunnel {
log::debug!("Waiting for tunnel IP interfaces to arrive");
let prepare_interfaces = async move {
- crate::windows::wait_for_interfaces(luid, true, has_ipv6).await?;
+ talpid_windows_net::wait_for_interfaces(luid, true, has_ipv6).await?;
- if let Err(error) = crate::tunnel::windows::initialize_interfaces(luid, None) {
+ if let Err(error) =
+ talpid_tunnel::network_interface::initialize_interfaces(luid, None)
+ {
log::error!(
"{}",
error.display_chain_with_msg("Failed to set tunnel interface metric"),
@@ -211,7 +209,7 @@ impl WgGoTunnel {
#[cfg(target_os = "windows")]
pub fn default_route_changed_callback<'a>(
event_type: crate::routing::EventType<'a>,
- address_family: crate::windows::AddressFamily,
+ address_family: talpid_windows_net::AddressFamily,
) {
use crate::routing::EventType::*;
use windows_sys::Win32::NetworkManagement::IpHelper::ConvertInterfaceLuidToIndex;
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/mod.rs b/talpid-wireguard/src/wireguard_kernel/mod.rs
index 7a64ee3f65..7a64ee3f65 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/mod.rs
+++ b/talpid-wireguard/src/wireguard_kernel/mod.rs
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs
index b1159bb6de..b1159bb6de 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/netlink_tunnel.rs
+++ b/talpid-wireguard/src/wireguard_kernel/netlink_tunnel.rs
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nl_message.rs b/talpid-wireguard/src/wireguard_kernel/nl_message.rs
index 87f1537ea0..87f1537ea0 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nl_message.rs
+++ b/talpid-wireguard/src/wireguard_kernel/nl_message.rs
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs
index 92a8f5e81c..7428952585 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/nm_tunnel.rs
+++ b/talpid-wireguard/src/wireguard_kernel/nm_tunnel.rs
@@ -100,7 +100,7 @@ impl Tunnel for NetworkManagerTunnel {
let interface_name = self.interface_name.clone();
let mut wg = self.netlink_connections.wg_handle.clone();
Box::pin(async move {
- let index = crate::linux::iface_index(&interface_name).map_err(|err| {
+ let index = iface_index(&interface_name).map_err(|err| {
log::error!("Failed to fetch WireGuard device index: {}", err);
TunnelError::SetConfigError
})?;
@@ -120,7 +120,9 @@ fn convert_config_to_dbus(config: &Config) -> DeviceConfig {
let mut peer_configs = vec![];
wireguard_config.insert("mtu".into(), Variant(Box::new(config.mtu as u32)));
- wireguard_config.insert("fwmark".into(), Variant(Box::new(config.fwmark as u32)));
+ if let Some(fwmark) = config.fwmark {
+ wireguard_config.insert("fwmark".into(), Variant(Box::new(fwmark as u32)));
+ }
wireguard_config.insert("peer-routes".into(), Variant(Box::new(false)));
wireguard_config.insert(
"private-key".into(),
@@ -202,3 +204,30 @@ fn convert_config_to_dbus(config: &Config) -> DeviceConfig {
settings
}
+
+/// Converts an interface name into the corresponding index.
+#[cfg(target_os = "linux")]
+fn iface_index(name: &str) -> std::result::Result<libc::c_uint, IfaceIndexLookupError> {
+ let c_name = std::ffi::CString::new(name)
+ .map_err(|e| IfaceIndexLookupError::InvalidInterfaceName(name.to_owned(), e))?;
+ let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) };
+ if index == 0 {
+ Err(IfaceIndexLookupError::InterfaceLookupError(
+ name.to_owned(),
+ std::io::Error::last_os_error(),
+ ))
+ } else {
+ Ok(index)
+ }
+}
+
+/// Failure to lookup an interfaces index by its name.
+#[derive(Debug, err_derive::Error)]
+pub enum IfaceIndexLookupError {
+ /// The interface name is invalid - contains null bytes or is too long.
+ #[error(display = "Invalid network interface name: {}", _0)]
+ InvalidInterfaceName(String, #[error(source)] std::ffi::NulError),
+ /// Interface wasn't found by its name.
+ #[error(display = "Failed to get index for interface {}", _0)]
+ InterfaceLookupError(String, #[error(source)] std::io::Error),
+}
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/parsers.rs b/talpid-wireguard/src/wireguard_kernel/parsers.rs
index f08b2d6dfa..f08b2d6dfa 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/parsers.rs
+++ b/talpid-wireguard/src/wireguard_kernel/parsers.rs
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_kernel/wg_message.rs b/talpid-wireguard/src/wireguard_kernel/wg_message.rs
index d4b0ac78c6..0c36d45635 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_kernel/wg_message.rs
+++ b/talpid-wireguard/src/wireguard_kernel/wg_message.rs
@@ -96,7 +96,7 @@ impl DeviceMessage {
let nlas = vec![
DeviceNla::IfIndex(interface_index),
DeviceNla::ListenPort(0),
- DeviceNla::Fwmark(crate::linux::TUNNEL_FW_MARK),
+ DeviceNla::Fwmark(config.fwmark.unwrap_or(0)),
DeviceNla::PrivateKey(config.tunnel.private_key.to_bytes()),
DeviceNla::Flags(WGDEVICE_F_REPLACE_PEERS),
DeviceNla::Peers(peers),
diff --git a/talpid-core/src/tunnel/wireguard/wireguard_nt.rs b/talpid-wireguard/src/wireguard_nt.rs
index 08a75fd887..1044a3fd9a 100644
--- a/talpid-core/src/tunnel/wireguard/wireguard_nt.rs
+++ b/talpid-wireguard/src/wireguard_nt.rs
@@ -4,7 +4,6 @@ use super::{
stats::{Stats, StatsMap},
Tunnel,
};
-use crate::windows;
use bitflags::bitflags;
use futures::SinkExt;
use ipnetwork::IpNetwork;
@@ -23,6 +22,7 @@ use std::{
sync::{Arc, Mutex},
};
use talpid_types::{BoxedError, ErrorExt};
+use talpid_windows_net as net;
use widestring::{U16CStr, U16CString};
use windows_sys::{
core::GUID,
@@ -193,7 +193,7 @@ impl From<IpAddr> for WgIpAddr {
impl From<Ipv6Addr> for WgIpAddr {
fn from(address: Ipv6Addr) -> Self {
Self {
- v6: windows::in6addr_from_ipaddr(address),
+ v6: net::in6addr_from_ipaddr(address),
}
}
}
@@ -201,7 +201,7 @@ impl From<Ipv6Addr> for WgIpAddr {
impl From<Ipv4Addr> for WgIpAddr {
fn from(address: Ipv4Addr) -> Self {
Self {
- v4: windows::inaddr_from_ipaddr(address),
+ v4: net::inaddr_from_ipaddr(address),
}
}
}
@@ -262,12 +262,12 @@ impl PartialEq for WgAllowedIp {
}
match self.address_family as u32 {
AF_INET => {
- windows::ipaddr_from_inaddr(unsafe { self.address.v4 })
- == windows::ipaddr_from_inaddr(unsafe { other.address.v4 })
+ net::ipaddr_from_inaddr(unsafe { self.address.v4 })
+ == net::ipaddr_from_inaddr(unsafe { other.address.v4 })
}
AF_INET6 => {
- windows::ipaddr_from_in6addr(unsafe { self.address.v6 })
- == windows::ipaddr_from_in6addr(unsafe { other.address.v6 })
+ net::ipaddr_from_in6addr(unsafe { self.address.v6 })
+ == net::ipaddr_from_in6addr(unsafe { other.address.v6 })
}
_ => {
log::error!("Allowed IP uses unknown address family");
@@ -284,11 +284,11 @@ impl fmt::Debug for WgAllowedIp {
match self.address_family as u32 {
AF_INET => s.field(
"address",
- &windows::ipaddr_from_inaddr(unsafe { self.address.v4 }),
+ &net::ipaddr_from_inaddr(unsafe { self.address.v4 }),
),
AF_INET6 => s.field(
"address",
- &windows::ipaddr_from_in6addr(unsafe { self.address.v6 }),
+ &net::ipaddr_from_in6addr(unsafe { self.address.v6 }),
),
_ => s.field("address", &"<unknown>"),
};
@@ -340,7 +340,7 @@ impl From<SOCKADDR_INET> for SockAddrInet {
}
impl PartialEq for SockAddrInet {
fn eq(&self, other: &Self) -> bool {
- let self_addr = match windows::try_socketaddr_from_inet_sockaddr(self.addr) {
+ let self_addr = match net::try_socketaddr_from_inet_sockaddr(self.addr) {
Ok(addr) => addr,
Err(error) => {
log::error!(
@@ -350,7 +350,7 @@ impl PartialEq for SockAddrInet {
return true;
}
};
- let other_addr = match windows::try_socketaddr_from_inet_sockaddr(other.addr) {
+ let other_addr = match net::try_socketaddr_from_inet_sockaddr(other.addr) {
Ok(addr) => addr,
Err(error) => {
log::error!(
@@ -368,7 +368,7 @@ impl Eq for SockAddrInet {}
impl fmt::Debug for SockAddrInet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = f.debug_struct("SockAddrInet");
- let self_addr = windows::try_socketaddr_from_inet_sockaddr(self.addr)
+ let self_addr = net::try_socketaddr_from_inet_sockaddr(self.addr)
.map(|addr| addr.to_string())
.unwrap_or("<unknown>".to_string());
s.field("addr", &self_addr).finish()
@@ -473,12 +473,12 @@ async fn setup_ip_listener(
};
log::debug!("Waiting for tunnel IP interfaces to arrive");
- windows::wait_for_interfaces(luid, true, has_ipv6)
+ net::wait_for_interfaces(luid, true, has_ipv6)
.await
.map_err(Error::IpInterfacesError)?;
log::debug!("Waiting for tunnel IP interfaces: Done");
- crate::tunnel::windows::initialize_interfaces(luid, Some(mtu))
+ talpid_tunnel::network_interface::initialize_interfaces(luid, Some(mtu))
.map_err(Error::SetTunnelMtuError)?;
if let Some(device) = &*device.lock().unwrap() {
@@ -568,7 +568,7 @@ impl WgNtAdapter {
}
fn name(&self) -> io::Result<U16CString> {
- windows::alias_from_luid(&self.luid()).and_then(|alias| {
+ net::alias_from_luid(&self.luid()).and_then(|alias| {
U16CString::from_os_str(alias)
.map_err(|_| io::Error::new(io::ErrorKind::Other, "unexpected null char"))
})
@@ -824,7 +824,7 @@ fn serialize_config(config: &Config) -> Result<Vec<MaybeUninit<u8>>> {
peers_count: config.peers.len() as u32,
};
- buffer.extend(windows::as_uninit_byte_slice(&header));
+ buffer.extend(as_uninit_byte_slice(&header));
for peer in &config.peers {
let flags = if peer.psk.is_some() {
@@ -842,14 +842,14 @@ fn serialize_config(config: &Config) -> Result<Vec<MaybeUninit<u8>>> {
.map(|psk| psk.as_bytes().clone())
.unwrap_or([0u8; WIREGUARD_KEY_LENGTH]),
persistent_keepalive: 0,
- endpoint: windows::inet_sockaddr_from_socketaddr(peer.endpoint).into(),
+ endpoint: net::inet_sockaddr_from_socketaddr(peer.endpoint).into(),
tx_bytes: 0,
rx_bytes: 0,
last_handshake: 0,
allowed_ips_count: peer.allowed_ips.len() as u32,
};
- buffer.extend(windows::as_uninit_byte_slice(&wg_peer));
+ buffer.extend(as_uninit_byte_slice(&wg_peer));
for allowed_ip in &peer.allowed_ips {
let address_family = match allowed_ip {
@@ -864,7 +864,7 @@ fn serialize_config(config: &Config) -> Result<Vec<MaybeUninit<u8>>> {
let wg_allowed_ip =
WgAllowedIp::new(address, address_family, allowed_ip.prefix() as u8)?;
- buffer.extend(windows::as_uninit_byte_slice(&wg_allowed_ip));
+ buffer.extend(as_uninit_byte_slice(&wg_allowed_ip));
}
}
@@ -889,7 +889,7 @@ unsafe fn deserialize_config(
let peer: WgPeer = *(peer_data.as_ptr() as *const WgPeer);
tail = new_tail;
- if let Err(error) = windows::try_socketaddr_from_inet_sockaddr(peer.endpoint.addr) {
+ if let Err(error) = net::try_socketaddr_from_inet_sockaddr(peer.endpoint.addr) {
log::error!(
"{}",
error.display_chain_with_msg("Received invalid endpoint address")
@@ -986,6 +986,10 @@ impl Tunnel for WgNtTunnel {
}
}
+pub fn as_uninit_byte_slice<T: Copy + Sized>(value: &T) -> &[mem::MaybeUninit<u8>] {
+ unsafe { std::slice::from_raw_parts(value as *const _ as *const _, mem::size_of::<T>()) }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -1037,8 +1041,10 @@ mod tests {
public_key: WG_PUBLIC_KEY.as_bytes().clone(),
preshared_key: [0; WIREGUARD_KEY_LENGTH],
persistent_keepalive: 0,
- endpoint: windows::inet_sockaddr_from_socketaddr("1.2.3.4:1234".parse().unwrap())
- .into(),
+ endpoint: talpid_windows_net::inet_sockaddr_from_socketaddr(
+ "1.2.3.4:1234".parse().unwrap()
+ )
+ .into(),
tx_bytes: 0,
rx_bytes: 0,
last_handshake: 0,
@@ -1074,7 +1080,7 @@ mod tests {
#[test]
fn test_config_deserialization() {
- let config_buffer = windows::as_uninit_byte_slice(&*WG_STRUCT_CONFIG);
+ let config_buffer = as_uninit_byte_slice(&*WG_STRUCT_CONFIG);
let (iface, peers) = unsafe { deserialize_config(config_buffer) }.unwrap();
assert_eq!(iface, WG_STRUCT_CONFIG.interface);
assert_eq!(peers.len(), 1);