summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2024-10-09 13:43:50 +0200
committerMarkus Pettersson <markus.pettersson@mullvad.net>2024-11-22 17:42:38 +0100
commit848ddea38dcd93a1cf1575f87f8fada316dff590 (patch)
tree855e9ef69fbd3f1e9e3943cb2c15502190f76cca
parent734abdd7fcafa3d1b4553460de1b2199d4043b51 (diff)
downloadmullvadvpn-848ddea38dcd93a1cf1575f87f8fada316dff590.tar.xz
mullvadvpn-848ddea38dcd93a1cf1575f87f8fada316dff590.zip
Add initial multihop config on Android
- Add some minor wireguard go changes
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt2
-rw-r--r--talpid-wireguard/src/wireguard_go/mod.rs50
-rw-r--r--wireguard-go-rs/libwg/libwg.go3
-rw-r--r--wireguard-go-rs/libwg/libwg_android.go74
-rw-r--r--wireguard-go-rs/libwg/tunnelcontainer/tunnelcontainer.go1
-rw-r--r--wireguard-go-rs/src/lib.rs30
6 files changed, 136 insertions, 24 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
index c36f10212e..c63da68471 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreen.kt
@@ -66,6 +66,7 @@ import com.ramcosta.composedestinations.result.NavResult
import com.ramcosta.composedestinations.result.ResultBackNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.spec.DestinationSpec
+import java.io.FileDescriptor
import kotlinx.coroutines.launch
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.compose.cell.FilterRow
@@ -753,6 +754,7 @@ private fun EditCustomListBottomSheet(
onDeleteCustomList: (item: RelayItem.CustomList) -> Unit,
closeBottomSheet: (animate: Boolean) -> Unit,
) {
+ FileDescriptor.out.
MullvadModalBottomSheet(
backgroundColor = backgroundColor,
onBackgroundColor = onBackgroundColor,
diff --git a/talpid-wireguard/src/wireguard_go/mod.rs b/talpid-wireguard/src/wireguard_go/mod.rs
index 25ebb45a38..5caab06d09 100644
--- a/talpid-wireguard/src/wireguard_go/mod.rs
+++ b/talpid-wireguard/src/wireguard_go/mod.rs
@@ -5,6 +5,7 @@ use once_cell::sync::OnceCell;
use std::{ffi::CString, fs, path::PathBuf};
use std::{
future::Future,
+ net::IpAddr,
os::unix::io::{AsRawFd, RawFd},
path::Path,
pin::Pin,
@@ -59,6 +60,34 @@ pub struct WgGoTunnel {
config: Config,
}
+// TODO: move into impl of Config
+fn exit_config(multihop_config: &Config) -> Option<Config> {
+ let mut exit_config = multihop_config.clone();
+ exit_config.entry_peer = multihop_config.exit_peer.clone()?;
+ Some(exit_config)
+}
+
+// TODO: move into impl of Config
+fn entry_config(multihop_config: &Config) -> Config {
+ let mut entry_config = multihop_config.clone();
+ entry_config.exit_peer = None;
+ entry_config
+}
+
+// TODO: move into impl of Config
+fn private_ip(config: &Config) -> CString {
+ if let Some(ip) = config
+ .tunnel
+ .addresses
+ .iter()
+ .find(|addr| matches!(addr, IpAddr::V4(_))) {
+ CString::new(ip.to_string()).unwrap()
+ }
+ else {
+ CString::default()
+ }
+}
+
impl WgGoTunnel {
pub fn start_tunnel(
config: &Config,
@@ -81,6 +110,27 @@ impl WgGoTunnel {
#[cfg(not(target_os = "android"))]
let mtu = config.mtu as isize;
+
+ let entry_config = entry_config(config);
+ let exit_config = exit_config(config);
+
+ #[cfg(target_os = "android")]
+ if let Some(exit_config) = exit_config {
+ let entry_config_str = entry_config.to_userspace_format();
+ let exit_config_str = exit_config.to_userspace_format();
+ let private_ip = private_ip(config);
+
+ let handle = wireguard_go_rs::Tunnel::turn_on_multihop(
+ exit_config_str,
+ entry_config_str,
+ private_ip,
+ tunnel_fd,
+ Some(logging::wg_go_logging_callback),
+ logging_context.0,
+ )
+ .map_err(|e| TunnelError::FatalStartWireguardError(Box::new(e)))?;
+ }
+
let handle = wireguard_go_rs::Tunnel::turn_on(
#[cfg(not(target_os = "android"))]
mtu,
diff --git a/wireguard-go-rs/libwg/libwg.go b/wireguard-go-rs/libwg/libwg.go
index 6cfbd0ba55..5dcc9141b2 100644
--- a/wireguard-go-rs/libwg/libwg.go
+++ b/wireguard-go-rs/libwg/libwg.go
@@ -65,6 +65,9 @@ func wgTurnOff(tunnelHandle int32) {
return
}
tunnel.Device.Close()
+ if tunnel.EntryDevice != nil {
+ tunnel.EntryDevice.Close()
+ }
}
// Calling twice convinces the GC to release NOW.
runtime.GC()
diff --git a/wireguard-go-rs/libwg/libwg_android.go b/wireguard-go-rs/libwg/libwg_android.go
index ce0b5e10a9..98599ba701 100644
--- a/wireguard-go-rs/libwg/libwg_android.go
+++ b/wireguard-go-rs/libwg/libwg_android.go
@@ -13,7 +13,6 @@ import (
"bufio"
"errors"
"net/netip"
- "os"
"strings"
"unsafe"
@@ -88,19 +87,27 @@ func wgTurnOn(cSettings *C.char, fd int, logSink LogSink, logContext LogContext)
return C.int32_t(handle)
}
-func wgTurnOnMultihopAgain(mtu int, exitSettings *C.char, entrySettings *C.char, privateIp *C.char, fd int32, logSink LogSink, logContext LogContext) C.int32_t {
+//export wgTurnOnMultihop
+func wgTurnOnMultihop(cExitSettings *C.char, cEntrySettings *C.char, privateIp *C.char, fd int, logSink LogSink, logContext LogContext) C.int32_t {
logger := logging.NewLogger(logSink, logging.LogContext(logContext))
- if exitSettings == nil {
- logger.Errorf("exitSettings is null\n")
+ if cExitSettings == nil {
+ logger.Errorf("cExitSettings is null\n")
return ERROR_INVALID_ARGUMENT
}
- exitSettings := goStringFixed(exitSettings)
+ exitSettings := goStringFixed(cExitSettings)
- if entrySettings == nil {
- logger.Errorf("exitSettings is null\n")
+ if cEntrySettings == nil {
+ logger.Errorf("cEntrySettings is null\n")
+ return ERROR_INVALID_ARGUMENT
+ }
+ entrySettings := goStringFixed(cEntrySettings)
+
+ exitEndpoint := parseEndpointFromConfig(exitSettings)
+
+ if exitEndpoint == nil {
+ logger.Errorf("exitEndpoint is null\n")
return ERROR_INVALID_ARGUMENT
}
- entrySettings := goStringFixed(entrySettings)
// Set up a two tunnel devices: One 'fake' device for the exit relay and one 'real' device for the entry relay
@@ -114,39 +121,70 @@ func wgTurnOnMultihopAgain(mtu int, exitSettings *C.char, entrySettings *C.char,
return ERROR_GENERAL_FAILURE
}
- device := device.NewDevice(tunDevice, conn.NewStdNetBind(), logger)
+ ip, err := netip.ParseAddr(goStringFixed(privateIp))
+ if err != nil {
+ logger.Errorf("%s\n", err)
+ tunDevice.Close()
+ return ERROR_INVALID_ARGUMENT
+ }
- setErr := device.IpcSetOperation(bufio.NewReader(strings.NewReader(settings)))
+ mtu, err := tunDevice.MTU()
+ if err != nil {
+ logger.Errorf("%s\n", err)
+ tunDevice.Close()
+ return ERROR_GENERAL_FAILURE
+ }
+
+ singleTunMtu := mtu - 80 //Internet mtu - Wireguard header size - ipv4 UDP header
+ singletun := multihoptun.NewMultihopTun(ip, exitEndpoint.Addr(), exitEndpoint.Port(), singleTunMtu)
+
+ entryDevice := device.NewDevice(tunDevice, singletun.Binder(), logger)
+
+ setErr := entryDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(entrySettings)))
if setErr != nil {
logger.Errorf("%s\n", setErr)
- device.Close()
+ entryDevice.Close()
return ERROR_INTERMITTENT_FAILURE
}
- device.DisableSomeRoamingForBrokenMobileSemantics()
- device.Up()
+ entryDevice.DisableSomeRoamingForBrokenMobileSemantics()
+
+ exitDevice := device.NewDevice(&singletun, conn.NewStdNetBind(), logger)
+
+ setErr = exitDevice.IpcSetOperation(bufio.NewReader(strings.NewReader(exitSettings)))
+ if setErr != nil {
+ logger.Errorf("%s\n", setErr)
+ exitDevice.Close()
+ return ERROR_INTERMITTENT_FAILURE
+ }
+
+ exitDevice.DisableSomeRoamingForBrokenMobileSemantics()
+
+ exitDevice.Up()
+ entryDevice.Up()
// Create the stuff that needs
context := tunnelcontainer.Context{
- Device: device,
+ Device: exitDevice,
+ EntryDevice: entryDevice,
Logger: logger,
}
handle, err := tunnels.Insert(context)
if err != nil {
logger.Errorf("%s\n", err)
- device.Close()
+ entryDevice.Close()
+ exitDevice.Close()
return ERROR_GENERAL_FAILURE
}
- // TODO
return C.int32_t(handle)
}
//export wgTurnOnMultihop
-func wgTurnOnMultihop(mtu int, exitSettings *C.char, entrySettings *C.char, privateIp *C.char, fd int32, logSink LogSink, logContext LogContext) C.int32_t {
+/*func wgTurnOnMultihop(mtu int, exitSettings *C.char, entrySettings *C.char, privateIp *C.char, fd int32, logSink LogSink, logContext LogContext) C.int32_t {
logger := logging.NewLogger(logSink, logging.LogContext(logContext))
if exitSettings == nil {
@@ -219,7 +257,7 @@ func wgTurnOnMultihop(mtu int, exitSettings *C.char, entrySettings *C.char, priv
}
return C.int32_t(handle)
-}
+}*/
func addTunnelFromDevice(exitDev *device.Device, entryDev *device.Device, exitSettings string, entrySettings string, logger *device.Logger) (*tunnelHandle, error) {
err := bringUpDevice(exitDev, exitSettings, logger)
diff --git a/wireguard-go-rs/libwg/tunnelcontainer/tunnelcontainer.go b/wireguard-go-rs/libwg/tunnelcontainer/tunnelcontainer.go
index 91291dcf4b..bd4003b409 100644
--- a/wireguard-go-rs/libwg/tunnelcontainer/tunnelcontainer.go
+++ b/wireguard-go-rs/libwg/tunnelcontainer/tunnelcontainer.go
@@ -18,6 +18,7 @@ type Context struct {
Device *device.Device
Uapi net.Listener
Logger *device.Logger
+ EntryDevice *device.Device
}
type Container struct {
diff --git a/wireguard-go-rs/src/lib.rs b/wireguard-go-rs/src/lib.rs
index 2a994a1443..321189ff5c 100644
--- a/wireguard-go-rs/src/lib.rs
+++ b/wireguard-go-rs/src/lib.rs
@@ -112,19 +112,21 @@ impl Tunnel {
/// The `logging_callback` let's you provide a Rust function that receives any logging output
/// from wireguard-go. `logging_context` is a value that will be passed to each invocation of
/// `logging_callback`.
+ #[cfg(target_os = "android")]
pub fn turn_on_multihop(
- #[cfg(not(target_os = "android"))] mtu: isize,
- settings: &CStr,
+ exit_settings: &CStr,
+ entry_settings: &CStr,
+ private_ip: &CStr,
device: Fd,
logging_callback: Option<LoggingCallback>,
logging_context: LoggingContext,
) -> Result<Self, Error> {
// SAFETY: pointer is valid for the the lifetime of this function
let code = unsafe {
- ffi::wgTurnOn(
- #[cfg(not(target_os = "android"))]
- mtu,
- settings.as_ptr(),
+ ffi::wgTurnOnMultihop(
+ exit_settings.as_ptr(),
+ entry_settings.as_ptr(),
+ private_ip.as_ptr(),
device,
logging_callback,
logging_context,
@@ -287,6 +289,22 @@ mod ffi {
logging_context: LoggingContext,
) -> i32;
+ /// Creates a new wireguard tunnel, uses the specific interface name, and file descriptors
+ /// for the tunnel device and logging. For targets other than android, this also takes an
+ /// MTU value.
+ ///
+ /// Positive return values are tunnel handles for this specific wireguard tunnel instance.
+ /// Negative return values signify errors.
+ pub fn wgTurnOnMultihop(
+ exit_settings: *const c_char,
+ entry_settings: *const c_char,
+ private_ip: *const c_char,
+ fd: Fd,
+ logging_callback: Option<LoggingCallback>,
+ logging_context: LoggingContext,
+ ) -> i32;
+
+
/// Pass a handle that was created by wgTurnOn to stop a wireguard tunnel.
///
/// Negative return values signify errors.