summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-11-22 16:18:18 +0100
committerDavid Lönnhager <david.l@mullvad.net>2023-11-22 16:18:18 +0100
commitf7eb43c9170176a59019f5ba3eb5bed08c413058 (patch)
tree5e358a22218210c560c44006585cf411d1ddb23b
parent6b0b627bc042da11496bd0ced8662557962572ef (diff)
parent56970baac0773952d2153dc0719faa1bc699ad91 (diff)
downloadmullvadvpn-f7eb43c9170176a59019f5ba3eb5bed08c413058.tar.xz
mullvadvpn-f7eb43c9170176a59019f5ba3eb5bed08c413058.zip
Merge branch 'fix-macos-tests' into main
-rw-r--r--.github/workflows/desktop-e2e.yml35
-rw-r--r--mullvad-daemon/src/lib.rs48
-rw-r--r--mullvad-management-interface/src/client.rs4
-rw-r--r--talpid-core/src/tunnel_state_machine/connected_state.rs70
-rw-r--r--talpid-core/src/tunnel_state_machine/connecting_state.rs27
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnected_state.rs10
-rw-r--r--talpid-core/src/tunnel_state_machine/disconnecting_state.rs36
-rw-r--r--talpid-core/src/tunnel_state_machine/error_state.rs35
-rw-r--r--talpid-core/src/tunnel_state_machine/mod.rs6
-rw-r--r--test/test-manager/src/tests/account.rs3
-rw-r--r--test/test-manager/src/tests/dns.rs84
-rw-r--r--test/test-manager/src/tests/helpers.rs69
-rw-r--r--test/test-manager/src/tests/install.rs10
-rw-r--r--test/test-manager/src/tests/mod.rs1
-rw-r--r--test/test-manager/src/tests/settings.rs42
-rw-r--r--test/test-manager/src/tests/tunnel.rs118
-rw-r--r--test/test-manager/src/tests/tunnel_state.rs67
-rw-r--r--test/test-rpc/src/client.rs18
-rw-r--r--test/test-rpc/src/lib.rs20
-rw-r--r--test/test-runner/src/main.rs26
-rw-r--r--test/test-runner/src/net.rs154
21 files changed, 450 insertions, 433 deletions
diff --git a/.github/workflows/desktop-e2e.yml b/.github/workflows/desktop-e2e.yml
index 511a450cc7..cd10128bc8 100644
--- a/.github/workflows/desktop-e2e.yml
+++ b/.github/workflows/desktop-e2e.yml
@@ -70,11 +70,10 @@ jobs:
path: ~/.cache/mullvad-test/packages
- name: Checkout repository
uses: actions/checkout@v4
- with:
- fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
+ git fetch --tags --force
./test/ci-runtests.sh ${{ matrix.os }}
- uses: actions/upload-artifact@v3
if: '!cancelled()'
@@ -140,11 +139,10 @@ jobs:
path: ~/.cache/mullvad-test/packages
- name: Checkout repository
uses: actions/checkout@v4
- with:
- fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
+ git fetch --tags --force
./test/ci-runtests.sh ${{ matrix.os }}
- uses: actions/upload-artifact@v3
if: '!cancelled()'
@@ -154,36 +152,30 @@ jobs:
build-macos:
if: ${{ !startsWith(github.ref, 'refs/tags/') && github.ref != 'refs/heads/main' }}
- runs-on: macos-latest
+ runs-on: [self-hosted, desktop-test, macOS] # app-test-macos-arm
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Checkout submodules
run: git submodule update --init --depth=1
+ - name: Install Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.18.5
- name: Install Protoc
- uses: arduino/setup-protoc@v1
+ uses: arduino/setup-protoc@v2
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
node-version: 18
- - name: Install Rust
- uses: actions-rs/toolchain@v1.0.6
- with:
- toolchain: stable
- target: aarch64-apple-darwin
- default: true
- - name: Install Go
- uses: actions/setup-go@v3
- with:
- go-version: 1.18.5
+ cache: 'npm'
+ cache-dependency-path: gui/package-lock.json
- name: Build app
- run: ./build.sh --universal
+ run: ./build.sh
- name: Build test executable
- run: ./gui/scripts/build-test-executable.sh aarch64-apple-darwin
- # FIXME: This fails for some reason, but the artifact is built
- continue-on-error: true
+ run: ./gui/scripts/build-test-executable.sh
- uses: actions/upload-artifact@v3
if: '!cancelled()'
with:
@@ -210,11 +202,10 @@ jobs:
path: ~/Library/Caches/mullvad-test/packages
- name: Checkout repository
uses: actions/checkout@v4
- with:
- fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
+ git fetch --tags --force
./test/ci-runtests.sh ${{ matrix.os }}
- uses: actions/upload-artifact@v3
if: '!cancelled()'
diff --git a/mullvad-daemon/src/lib.rs b/mullvad-daemon/src/lib.rs
index b8a21dda07..a540791838 100644
--- a/mullvad-daemon/src/lib.rs
+++ b/mullvad-daemon/src/lib.rs
@@ -1899,9 +1899,15 @@ where
.await
{
Ok(settings_changed) => {
- Self::oneshot_send(tx, Ok(()), "set_allow_lan response");
if settings_changed {
- self.send_tunnel_command(TunnelCommand::AllowLan(allow_lan));
+ self.send_tunnel_command(TunnelCommand::AllowLan(
+ allow_lan,
+ oneshot_map(tx, |tx, ()| {
+ Self::oneshot_send(tx, Ok(()), "set_allow_lan response");
+ }),
+ ));
+ } else {
+ Self::oneshot_send(tx, Ok(()), "set_allow_lan response");
}
}
Err(e) => {
@@ -1946,11 +1952,15 @@ where
.await
{
Ok(settings_changed) => {
- Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response");
if settings_changed {
self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected(
block_when_disconnected,
+ oneshot_map(tx, |tx, ()| {
+ Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response");
+ }),
));
+ } else {
+ Self::oneshot_send(tx, Ok(()), "set_block_when_disconnected response");
}
}
Err(e) => {
@@ -2148,12 +2158,18 @@ where
.await
{
Ok(settings_changed) => {
- Self::oneshot_send(tx, Ok(()), "set_dns_options response");
if settings_changed {
let settings = self.settings.to_settings();
let resolvers =
dns::addresses_from_options(&settings.tunnel_options.dns_options);
- self.send_tunnel_command(TunnelCommand::Dns(resolvers));
+ self.send_tunnel_command(TunnelCommand::Dns(
+ resolvers,
+ oneshot_map(tx, |tx, ()| {
+ Self::oneshot_send(tx, Ok(()), "set_dns_options response");
+ }),
+ ));
+ } else {
+ Self::oneshot_send(tx, Ok(()), "set_dns_options response");
}
}
Err(e) => {
@@ -2396,7 +2412,8 @@ where
&& (*self.target_state == TargetState::Secured || self.settings.auto_connect)
{
log::debug!("Blocking firewall during shutdown since system is going down");
- self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected(true));
+ let (tx, _rx) = oneshot::channel();
+ self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected(true, tx));
}
self.state.shutdown(&self.tunnel_state);
@@ -2408,7 +2425,8 @@ where
// without causing the service to be restarted.
if *self.target_state == TargetState::Secured {
- self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected(true));
+ let (tx, _rx) = oneshot::channel();
+ self.send_tunnel_command(TunnelCommand::BlockWhenDisconnected(true, tx));
}
self.target_state.lock();
}
@@ -2569,3 +2587,19 @@ fn new_selector_config(settings: &Settings) -> SelectorConfig {
relay_overrides: settings.relay_overrides.clone(),
}
}
+
+/// Consume a oneshot sender of `T1` and return a sender that takes a different type `T2`. `forwarder` should map `T1` back to `T2` and
+/// send the result back to the original receiver.
+fn oneshot_map<T1: Send + 'static, T2: Send + 'static>(
+ tx: oneshot::Sender<T1>,
+ forwarder: impl Fn(oneshot::Sender<T1>, T2) + Send + 'static,
+) -> oneshot::Sender<T2> {
+ let (new_tx, new_rx) = oneshot::channel();
+ tokio::spawn(async move {
+ match new_rx.await {
+ Ok(result) => forwarder(tx, result),
+ Err(oneshot::Canceled) => (),
+ }
+ });
+ new_tx
+}
diff --git a/mullvad-management-interface/src/client.rs b/mullvad-management-interface/src/client.rs
index c1b27fea65..64ee088d18 100644
--- a/mullvad-management-interface/src/client.rs
+++ b/mullvad-management-interface/src/client.rs
@@ -73,6 +73,10 @@ impl MullvadProxyClient {
super::new_rpc_client().await.map(Self)
}
+ pub fn from_rpc_client(client: crate::ManagementServiceClient) -> Self {
+ Self(client)
+ }
+
pub async fn connect_tunnel(&mut self) -> Result<bool> {
Ok(self
.0
diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs
index 687e941aa7..21375f056b 100644
--- a/talpid-core/src/tunnel_state_machine/connected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connected_state.rs
@@ -213,8 +213,8 @@ impl ConnectedState {
use self::EventConsequence::*;
match command {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
- if let Err(error_cause) = shared_values.set_allow_lan(allow_lan) {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
+ let consequence = if let Err(error_cause) = shared_values.set_allow_lan(allow_lan) {
self.disconnect(shared_values, AfterDisconnect::Block(error_cause))
} else {
match self.set_firewall_policy(shared_values) {
@@ -230,43 +230,55 @@ impl ConnectedState {
AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError(error)),
),
}
- }
+ };
+ let _ = complete_tx.send(());
+ consequence
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
shared_values.allowed_endpoint = endpoint;
let _ = tx.send(());
SameState(self)
}
- Some(TunnelCommand::Dns(servers)) => match shared_values.set_dns_servers(servers) {
- Ok(true) => {
- if let Err(error) = self.set_firewall_policy(shared_values) {
- return self.disconnect(
- shared_values,
- AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError(error)),
- );
- }
-
- match self.set_dns(shared_values) {
- #[cfg(target_os = "android")]
- Ok(()) => self.disconnect(shared_values, AfterDisconnect::Reconnect(0)),
- #[cfg(not(target_os = "android"))]
- Ok(()) => SameState(self),
- Err(error) => {
- log::error!("{}", error.display_chain_with_msg("Failed to set DNS"));
- self.disconnect(
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
+ let consequence = match shared_values.set_dns_servers(servers) {
+ Ok(true) => {
+ if let Err(error) = self.set_firewall_policy(shared_values) {
+ return self.disconnect(
shared_values,
- AfterDisconnect::Block(ErrorStateCause::SetDnsError),
- )
+ AfterDisconnect::Block(ErrorStateCause::SetFirewallPolicyError(
+ error,
+ )),
+ );
+ }
+
+ match self.set_dns(shared_values) {
+ #[cfg(target_os = "android")]
+ Ok(()) => self.disconnect(shared_values, AfterDisconnect::Reconnect(0)),
+ #[cfg(not(target_os = "android"))]
+ Ok(()) => SameState(self),
+ Err(error) => {
+ log::error!(
+ "{}",
+ error.display_chain_with_msg("Failed to set DNS")
+ );
+ self.disconnect(
+ shared_values,
+ AfterDisconnect::Block(ErrorStateCause::SetDnsError),
+ )
+ }
}
}
- }
- Ok(false) => SameState(self),
- Err(error_cause) => {
- self.disconnect(shared_values, AfterDisconnect::Block(error_cause))
- }
- },
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Ok(false) => SameState(self),
+ Err(error_cause) => {
+ self.disconnect(shared_values, AfterDisconnect::Block(error_cause))
+ }
+ };
+ let _ = complete_tx.send(());
+ consequence
+ }
+ Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected, complete_tx)) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
SameState(self)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs
index 2a728513ff..d7d93da9d4 100644
--- a/talpid-core/src/tunnel_state_machine/connecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs
@@ -392,12 +392,14 @@ impl ConnectingState {
use self::EventConsequence::*;
match command {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
- if let Err(error_cause) = shared_values.set_allow_lan(allow_lan) {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
+ let consequence = if let Err(error_cause) = shared_values.set_allow_lan(allow_lan) {
self.disconnect(shared_values, AfterDisconnect::Block(error_cause))
} else {
self.reset_firewall(shared_values)
- }
+ };
+ let _ = complete_tx.send(());
+ consequence
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
if shared_values.allowed_endpoint != endpoint {
@@ -418,14 +420,19 @@ impl ConnectingState {
let _ = tx.send(());
SameState(self)
}
- Some(TunnelCommand::Dns(servers)) => match shared_values.set_dns_servers(servers) {
- #[cfg(target_os = "android")]
- Ok(true) => self.disconnect(shared_values, AfterDisconnect::Reconnect(0)),
- Ok(_) => SameState(self),
- Err(cause) => self.disconnect(shared_values, AfterDisconnect::Block(cause)),
- },
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
+ let consequence = match shared_values.set_dns_servers(servers) {
+ #[cfg(target_os = "android")]
+ Ok(true) => self.disconnect(shared_values, AfterDisconnect::Reconnect(0)),
+ Ok(_) => SameState(self),
+ Err(cause) => self.disconnect(shared_values, AfterDisconnect::Block(cause)),
+ };
+ let _ = complete_tx.send(());
+ consequence
+ }
+ Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected, complete_tx)) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
SameState(self)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
diff --git a/talpid-core/src/tunnel_state_machine/disconnected_state.rs b/talpid-core/src/tunnel_state_machine/disconnected_state.rs
index 5a2cf6fc4d..d46f06e782 100644
--- a/talpid-core/src/tunnel_state_machine/disconnected_state.rs
+++ b/talpid-core/src/tunnel_state_machine/disconnected_state.rs
@@ -128,7 +128,7 @@ impl TunnelState for DisconnectedState {
use self::EventConsequence::*;
match runtime.block_on(commands.next()) {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
if shared_values.allow_lan != allow_lan {
// The only platform that can fail is Android, but Android doesn't support the
// "block when disconnected" option, so the following call never fails.
@@ -138,6 +138,7 @@ impl TunnelState for DisconnectedState {
Self::set_firewall_policy(shared_values, false);
}
+ let _ = complete_tx.send(());
SameState(self)
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
@@ -148,15 +149,15 @@ impl TunnelState for DisconnectedState {
let _ = tx.send(());
SameState(self)
}
- Some(TunnelCommand::Dns(servers)) => {
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
// Same situation as allow LAN above.
shared_values
.set_dns_servers(servers)
.expect("Failed to reconnect after changing custom DNS servers");
-
+ let _ = complete_tx.send(());
SameState(self)
}
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected, complete_tx)) => {
if shared_values.block_when_disconnected != block_when_disconnected {
shared_values.block_when_disconnected = block_when_disconnected;
Self::set_firewall_policy(shared_values, true);
@@ -178,6 +179,7 @@ impl TunnelState for DisconnectedState {
Self::reset_dns(shared_values);
}
}
+ let _ = complete_tx.send(());
SameState(self)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
diff --git a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
index 08248fbac2..185d2f7d0a 100644
--- a/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
+++ b/talpid-core/src/tunnel_state_machine/disconnecting_state.rs
@@ -40,8 +40,9 @@ impl DisconnectingState {
self.after_disconnect = match after_disconnect {
AfterDisconnect::Nothing => match command {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
let _ = shared_values.set_allow_lan(allow_lan);
+ let _ = complete_tx.send(());
AfterDisconnect::Nothing
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
@@ -49,12 +50,17 @@ impl DisconnectingState {
let _ = tx.send(());
AfterDisconnect::Nothing
}
- Some(TunnelCommand::Dns(servers)) => {
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
let _ = shared_values.set_dns_servers(servers);
+ let _ = complete_tx.send(());
AfterDisconnect::Nothing
}
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::BlockWhenDisconnected(
+ block_when_disconnected,
+ complete_tx,
+ )) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
AfterDisconnect::Nothing
}
Some(TunnelCommand::IsOffline(is_offline)) => {
@@ -76,8 +82,9 @@ impl DisconnectingState {
}
},
AfterDisconnect::Block(reason) => match command {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
let _ = shared_values.set_allow_lan(allow_lan);
+ let _ = complete_tx.send(());
AfterDisconnect::Block(reason)
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
@@ -85,12 +92,17 @@ impl DisconnectingState {
let _ = tx.send(());
AfterDisconnect::Block(reason)
}
- Some(TunnelCommand::Dns(servers)) => {
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
let _ = shared_values.set_dns_servers(servers);
+ let _ = complete_tx.send(());
AfterDisconnect::Block(reason)
}
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::BlockWhenDisconnected(
+ block_when_disconnected,
+ complete_tx,
+ )) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
AfterDisconnect::Block(reason)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
@@ -117,8 +129,9 @@ impl DisconnectingState {
None => AfterDisconnect::Block(reason),
},
AfterDisconnect::Reconnect(retry_attempt) => match command {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
let _ = shared_values.set_allow_lan(allow_lan);
+ let _ = complete_tx.send(());
AfterDisconnect::Reconnect(retry_attempt)
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
@@ -126,12 +139,17 @@ impl DisconnectingState {
let _ = tx.send(());
AfterDisconnect::Reconnect(retry_attempt)
}
- Some(TunnelCommand::Dns(servers)) => {
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
let _ = shared_values.set_dns_servers(servers);
+ let _ = complete_tx.send(());
AfterDisconnect::Reconnect(retry_attempt)
}
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::BlockWhenDisconnected(
+ block_when_disconnected,
+ complete_tx,
+ )) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
AfterDisconnect::Reconnect(retry_attempt)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
diff --git a/talpid-core/src/tunnel_state_machine/error_state.rs b/talpid-core/src/tunnel_state_machine/error_state.rs
index 11a805f7dc..2f82cb4cf5 100644
--- a/talpid-core/src/tunnel_state_machine/error_state.rs
+++ b/talpid-core/src/tunnel_state_machine/error_state.rs
@@ -138,13 +138,16 @@ impl TunnelState for ErrorState {
use self::EventConsequence::*;
match runtime.block_on(commands.next()) {
- Some(TunnelCommand::AllowLan(allow_lan)) => {
- if let Err(error_state_cause) = shared_values.set_allow_lan(allow_lan) {
- NewState(Self::enter(shared_values, error_state_cause))
- } else {
- let _ = Self::set_firewall_policy(shared_values);
- SameState(self)
- }
+ Some(TunnelCommand::AllowLan(allow_lan, complete_tx)) => {
+ let consequence =
+ if let Err(error_state_cause) = shared_values.set_allow_lan(allow_lan) {
+ NewState(Self::enter(shared_values, error_state_cause))
+ } else {
+ let _ = Self::set_firewall_policy(shared_values);
+ SameState(self)
+ };
+ let _ = complete_tx.send(());
+ consequence
}
Some(TunnelCommand::AllowEndpoint(endpoint, tx)) => {
if shared_values.allowed_endpoint != endpoint {
@@ -163,15 +166,19 @@ impl TunnelState for ErrorState {
let _ = tx.send(());
SameState(self)
}
- Some(TunnelCommand::Dns(servers)) => {
- if let Err(error_state_cause) = shared_values.set_dns_servers(servers) {
- NewState(Self::enter(shared_values, error_state_cause))
- } else {
- SameState(self)
- }
+ Some(TunnelCommand::Dns(servers, complete_tx)) => {
+ let consequence =
+ if let Err(error_state_cause) = shared_values.set_dns_servers(servers) {
+ NewState(Self::enter(shared_values, error_state_cause))
+ } else {
+ SameState(self)
+ };
+ let _ = complete_tx.send(());
+ consequence
}
- Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected)) => {
+ Some(TunnelCommand::BlockWhenDisconnected(block_when_disconnected, complete_tx)) => {
shared_values.block_when_disconnected = block_when_disconnected;
+ let _ = complete_tx.send(());
SameState(self)
}
Some(TunnelCommand::IsOffline(is_offline)) => {
diff --git a/talpid-core/src/tunnel_state_machine/mod.rs b/talpid-core/src/tunnel_state_machine/mod.rs
index 12bc4cfc86..5957b2f731 100644
--- a/talpid-core/src/tunnel_state_machine/mod.rs
+++ b/talpid-core/src/tunnel_state_machine/mod.rs
@@ -189,15 +189,15 @@ pub async fn spawn(
/// Representation of external commands for the tunnel state machine.
pub enum TunnelCommand {
/// Enable or disable LAN access in the firewall.
- AllowLan(bool),
+ AllowLan(bool, oneshot::Sender<()>),
/// Endpoint that should never be blocked. `()` is sent to the
/// channel after attempting to set the firewall policy, regardless
/// of whether it succeeded.
AllowEndpoint(AllowedEndpoint, oneshot::Sender<()>),
/// Set DNS servers to use.
- Dns(Option<Vec<IpAddr>>),
+ Dns(Option<Vec<IpAddr>>, oneshot::Sender<()>),
/// Enable or disable the block_when_disconnected feature.
- BlockWhenDisconnected(bool),
+ BlockWhenDisconnected(bool, oneshot::Sender<()>),
/// Notify the state machine of the connectivity of the device.
IsOffline(bool),
/// Open tunnel connection.
diff --git a/test/test-manager/src/tests/account.rs b/test/test-manager/src/tests/account.rs
index 5b1991abb5..92c95346b2 100644
--- a/test/test-manager/src/tests/account.rs
+++ b/test/test-manager/src/tests/account.rs
@@ -107,12 +107,13 @@ pub async fn test_too_many_devices(
)
.await
.unwrap();
- assert!(ui_result.success());
if let Err(error) = clear_devices(&device_client).await {
log::error!("Failed to clear devices: {error}");
}
+ assert!(ui_result.success());
+
Ok(())
}
diff --git a/test/test-manager/src/tests/dns.rs b/test/test-manager/src/tests/dns.rs
index 310d5eb0dc..89755c3fd6 100644
--- a/test/test-manager/src/tests/dns.rs
+++ b/test/test-manager/src/tests/dns.rs
@@ -9,9 +9,12 @@ use mullvad_management_interface::{types, ManagementServiceClient};
use mullvad_types::{relay_constraints::RelaySettings, ConnectionConfig, CustomTunnelEndpoint};
use talpid_types::net::wireguard;
use test_macro::test_function;
-use test_rpc::{Interface, ServiceClient};
+use test_rpc::ServiceClient;
-use super::{helpers::connect_and_wait, Error, TestContext};
+use super::{
+ helpers::{self, connect_and_wait, set_relay_settings},
+ Error, TestContext,
+};
use crate::network_monitor::{
start_packet_monitor_until, start_tunnel_packet_monitor_until, Direction, IpHeaderProtocols,
MonitorOptions,
@@ -22,8 +25,6 @@ use crate::vm::network::{
CUSTOM_TUN_REMOTE_TUN_ADDR, NON_TUN_GATEWAY,
};
-use super::helpers::set_relay_settings;
-
/// How long to wait for expected "DNS queries" to appear
const MONITOR_TIMEOUT: Duration = Duration::from_secs(5);
@@ -47,7 +48,7 @@ pub async fn test_dns_leak_default(
leak_test_dns(
&rpc,
&mut mullvad_client,
- Interface::Tunnel,
+ true,
IpAddr::V4(CUSTOM_TUN_REMOTE_TUN_ADDR),
)
.await
@@ -82,7 +83,7 @@ pub async fn test_dns_leak_custom_public_ip(
.await
.expect("failed to configure DNS server");
- leak_test_dns(&rpc, &mut mullvad_client, Interface::Tunnel, CONFIG_IP).await
+ leak_test_dns(&rpc, &mut mullvad_client, true, CONFIG_IP).await
}
/// Test whether DNS leaks can be produced when using a custom private IP. This test succeeds if and
@@ -114,7 +115,7 @@ pub async fn test_dns_leak_custom_private_ip(
.await
.expect("failed to configure DNS server");
- leak_test_dns(&rpc, &mut mullvad_client, Interface::NonTunnel, CONFIG_IP).await
+ leak_test_dns(&rpc, &mut mullvad_client, false, CONFIG_IP).await
}
/// See whether it is possible to send "DNS queries" to a particular whitelisted destination on
@@ -124,11 +125,9 @@ pub async fn test_dns_leak_custom_private_ip(
async fn leak_test_dns(
rpc: &ServiceClient,
mullvad_client: &mut ManagementServiceClient,
- interface: Interface,
+ use_tun: bool,
whitelisted_dest: IpAddr,
) -> Result<(), Error> {
- let use_tun = interface == Interface::Tunnel;
-
//
// Connect to local wireguard relay
//
@@ -137,24 +136,32 @@ async fn leak_test_dns(
.await
.expect("failed to connect to custom wg relay");
- let guest_ip = rpc
- .get_interface_ip(Interface::NonTunnel)
+ let nontun_iface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to find non-tun interface");
+ let tunnel_iface = helpers::get_tunnel_interface(mullvad_client.clone())
+ .await
+ .expect("failed to find tunnel interface");
+
+ let nontun_ip = rpc
+ .get_interface_ip(nontun_iface.clone())
.await
.expect("failed to obtain guest IP");
let tunnel_ip = rpc
- .get_interface_ip(Interface::Tunnel)
+ .get_interface_ip(tunnel_iface.clone())
.await
.expect("failed to obtain tunnel IP");
log::debug!("Tunnel (guest) IP: {tunnel_ip}");
- log::debug!("Non-tunnel (guest) IP: {guest_ip}");
+ log::debug!("Non-tunnel (guest) IP: {nontun_ip}");
//
// Spoof DNS packets
//
let tun_bind_addr = SocketAddr::new(tunnel_ip, 0);
- let guest_bind_addr = SocketAddr::new(guest_ip, 0);
+ let nontun_bind_addr = SocketAddr::new(nontun_ip, 0);
let whitelisted_dest = SocketAddr::new(whitelisted_dest, 53);
let blocked_dest_local = "10.64.100.100:53".parse().unwrap();
@@ -216,40 +223,35 @@ async fn leak_test_dns(
// send to allowed dest
spoof_packets(
&rpc,
- Some(Interface::Tunnel),
+ Some(tunnel_iface.clone()),
tun_bind_addr,
whitelisted_dest,
),
spoof_packets(
&rpc,
- Some(Interface::NonTunnel),
- guest_bind_addr,
+ Some(nontun_iface.clone()),
+ nontun_bind_addr,
whitelisted_dest,
),
// send to blocked local dest
spoof_packets(
&rpc,
- Some(Interface::Tunnel),
+ Some(tunnel_iface.clone()),
tun_bind_addr,
blocked_dest_local,
),
spoof_packets(
&rpc,
- Some(Interface::NonTunnel),
- guest_bind_addr,
+ Some(nontun_iface.clone()),
+ nontun_bind_addr,
blocked_dest_local,
),
// send to blocked public dest
+ spoof_packets(&rpc, Some(tunnel_iface), tun_bind_addr, blocked_dest_public,),
spoof_packets(
&rpc,
- Some(Interface::Tunnel),
- tun_bind_addr,
- blocked_dest_public,
- ),
- spoof_packets(
- &rpc,
- Some(Interface::NonTunnel),
- guest_bind_addr,
+ Some(nontun_iface),
+ nontun_bind_addr,
blocked_dest_public,
),
)
@@ -578,17 +580,25 @@ async fn run_dns_config_test<
}
}
- let guest_ip = rpc
- .get_interface_ip(Interface::NonTunnel)
+ let nontun_iface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to find non-tun interface");
+ let tunnel_iface = helpers::get_tunnel_interface(mullvad_client.clone())
+ .await
+ .expect("failed to find tunnel interface");
+
+ let nontun_ip = rpc
+ .get_interface_ip(nontun_iface)
.await
.expect("failed to obtain guest IP");
let tunnel_ip = rpc
- .get_interface_ip(Interface::Tunnel)
+ .get_interface_ip(tunnel_iface)
.await
.expect("failed to obtain tunnel IP");
log::debug!("Tunnel (guest) IP: {tunnel_ip}");
- log::debug!("Non-tunnel (guest) IP: {guest_ip}");
+ log::debug!("Non-tunnel (guest) IP: {nontun_ip}");
let monitor = create_monitor().await;
@@ -661,19 +671,21 @@ async fn connect_local_wg_relay(mullvad_client: &mut ManagementServiceClient) ->
async fn spoof_packets(
rpc: &ServiceClient,
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
dest: SocketAddr,
) {
let tcp_rpc = rpc.clone();
+ let tcp_interface = interface.clone();
let tcp_send = async move {
log::debug!("sending to {}/tcp from {}", dest, bind_addr);
- let _ = tcp_rpc.send_tcp(interface, bind_addr, dest).await;
+ let _ = tcp_rpc.send_tcp(tcp_interface, bind_addr, dest).await;
};
let udp_rpc = rpc.clone();
+ let udp_interface = interface.clone();
let udp_send = async move {
log::debug!("sending to {}/udp from {}", dest, bind_addr);
- let _ = udp_rpc.send_udp(interface, bind_addr, dest).await;
+ let _ = udp_rpc.send_udp(udp_interface, bind_addr, dest).await;
};
let _ = tokio::join!(tcp_send, udp_send);
}
diff --git a/test/test-manager/src/tests/helpers.rs b/test/test-manager/src/tests/helpers.rs
index ea876bbbbe..5b1c0a9903 100644
--- a/test/test-manager/src/tests/helpers.rs
+++ b/test/test-manager/src/tests/helpers.rs
@@ -1,7 +1,7 @@
use super::{config::TEST_CONFIG, Error, PING_TIMEOUT, WAIT_FOR_TUNNEL_STATE_TIMEOUT};
use crate::network_monitor::{start_packet_monitor, MonitorOptions};
use futures::StreamExt;
-use mullvad_management_interface::{types, ManagementServiceClient};
+use mullvad_management_interface::{types, ManagementServiceClient, MullvadProxyClient};
use mullvad_types::{
location::Location,
relay_constraints::{
@@ -19,7 +19,7 @@ use std::{
time::Duration,
};
use talpid_types::net::wireguard::{PeerConfig, PrivateKey, TunnelConfig};
-use test_rpc::{package::Package, AmIMullvad, Interface, ServiceClient};
+use test_rpc::{package::Package, AmIMullvad, ServiceClient};
use tokio::time::timeout;
#[macro_export]
@@ -82,17 +82,30 @@ pub async fn using_mullvad_exit(rpc: &ServiceClient) -> bool {
.mullvad_exit_ip
}
+/// Get VPN tunnel interface name
+pub async fn get_tunnel_interface(rpc: ManagementServiceClient) -> Option<String> {
+ let mut client = MullvadProxyClient::from_rpc_client(rpc);
+ match client.get_tunnel_state().await.ok()? {
+ TunnelState::Connecting { endpoint, .. } | TunnelState::Connected { endpoint, .. } => {
+ endpoint.tunnel_interface
+ }
+ _ => None,
+ }
+}
+
/// Sends a number of probes and returns the number of observed packets (UDP, TCP, or ICMP)
pub async fn send_guest_probes(
rpc: ServiceClient,
- interface: Option<Interface>,
+ interface: String,
destination: SocketAddr,
) -> Result<ProbeResult, Error> {
+ const MONITOR_DURATION: Duration = Duration::from_secs(8);
+
let pktmon = start_packet_monitor(
move |packet| packet.destination.ip() == destination.ip(),
MonitorOptions {
direction: Some(crate::network_monitor::Direction::In),
- timeout: Some(Duration::from_secs(3)),
+ timeout: Some(MONITOR_DURATION),
..Default::default()
},
)
@@ -100,7 +113,7 @@ pub async fn send_guest_probes(
let send_handle = tokio::spawn(send_guest_probes_without_monitor(
rpc,
- interface,
+ Some(interface),
destination,
));
@@ -132,12 +145,12 @@ pub async fn send_guest_probes(
/// Send one probe per transport protocol to `destination` without running a packet monitor
pub async fn send_guest_probes_without_monitor(
rpc: ServiceClient,
- interface: Option<Interface>,
+ interface: Option<String>,
destination: SocketAddr,
) {
- let bind_addr = if let Some(interface) = interface {
+ let bind_addr = if let Some(ref interface) = interface {
SocketAddr::new(
- rpc.get_interface_ip(interface)
+ rpc.get_interface_ip(interface.clone())
.await
.expect("failed to obtain interface IP"),
0,
@@ -147,9 +160,19 @@ pub async fn send_guest_probes_without_monitor(
};
let tcp_rpc = rpc.clone();
- let tcp_send = async move { tcp_rpc.send_tcp(interface, bind_addr, destination).await };
+ let tcp_interface = interface.clone();
+ let tcp_send = async move {
+ tcp_rpc
+ .send_tcp(tcp_interface, bind_addr, destination)
+ .await
+ };
let udp_rpc = rpc.clone();
- let udp_send = async move { udp_rpc.send_udp(interface, bind_addr, destination).await };
+ let udp_interface = interface.clone();
+ let udp_send = async move {
+ udp_rpc
+ .send_udp(udp_interface, bind_addr, destination)
+ .await
+ };
let icmp = async move { ping_with_timeout(&rpc, destination.ip(), interface).await };
let _ = tokio::join!(tcp_send, udp_send, icmp);
}
@@ -157,7 +180,7 @@ pub async fn send_guest_probes_without_monitor(
pub async fn ping_with_timeout(
rpc: &ServiceClient,
dest: IpAddr,
- interface: Option<Interface>,
+ interface: Option<String>,
) -> Result<(), Error> {
timeout(PING_TIMEOUT, rpc.send_ping(interface, dest))
.await
@@ -449,30 +472,6 @@ pub fn unreachable_wireguard_tunnel() -> talpid_types::net::wireguard::Connectio
}
}
-/// Randomly select an entry and exit node from the daemon's relay list.
-/// The exit node is distinct from the entry node.
-///
-/// * `mullvad_client` - An interface to the Mullvad daemon.
-/// * `critera` - A function used to determine which relays to include in random selection.
-pub async fn random_entry_and_exit<Filter>(
- mullvad_client: &mut ManagementServiceClient,
- criteria: Filter,
-) -> Result<(Relay, Relay), Error>
-where
- Filter: Fn(&Relay) -> bool,
-{
- use itertools::Itertools;
- // Pluck the first 2 relays and return them as a tuple.
- // This will fail if there are less than 2 relays in the relay list.
- filter_relays(mullvad_client, criteria)
- .await?
- .into_iter()
- .next_tuple()
- .ok_or(Error::Other(
- "failed to randomly select two relays from daemon's relay list".to_string(),
- ))
-}
-
/// Return a filtered version of the daemon's relay list.
///
/// * `mullvad_client` - An interface to the Mullvad daemon.
diff --git a/test/test-manager/src/tests/install.rs b/test/test-manager/src/tests/install.rs
index 04d401a22d..37a89f5fc8 100644
--- a/test/test-manager/src/tests/install.rs
+++ b/test/test-manager/src/tests/install.rs
@@ -11,7 +11,7 @@ use std::{
};
use test_macro::test_function;
use test_rpc::meta::Os;
-use test_rpc::{mullvad_daemon::ServiceStatus, Interface, ServiceClient};
+use test_rpc::{mullvad_daemon::ServiceStatus, ServiceClient};
/// Install the last stable version of the app and verify that it is running.
#[test_function(priority = -200)]
@@ -102,10 +102,14 @@ pub async fn test_upgrade_app(ctx: TestContext, rpc: ServiceClient) -> Result<()
// Begin monitoring outgoing traffic and pinging
//
+ let guest_iface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to obtain default interface");
let guest_ip = rpc
- .get_interface_ip(Interface::NonTunnel)
+ .get_interface_ip(guest_iface)
.await
- .expect("failed to obtain tunnel IP");
+ .expect("failed to obtain non-tun IP");
log::debug!("Guest IP: {guest_ip}");
log::debug!("Monitoring outgoing traffic");
diff --git a/test/test-manager/src/tests/mod.rs b/test/test-manager/src/tests/mod.rs
index b35f1b9b7a..ada613ca34 100644
--- a/test/test-manager/src/tests/mod.rs
+++ b/test/test-manager/src/tests/mod.rs
@@ -63,6 +63,7 @@ pub enum Error {
#[error(display = "Failed to parse gRPC response")]
InvalidGrpcResponse(#[error(source)] types::FromProtobufTypeError),
+ #[cfg(target_os = "macos")]
#[error(display = "An error occurred: {}", _0)]
Other(String),
}
diff --git a/test/test-manager/src/tests/settings.rs b/test/test-manager/src/tests/settings.rs
index 4c5808f790..aea81028fe 100644
--- a/test/test-manager/src/tests/settings.rs
+++ b/test/test-manager/src/tests/settings.rs
@@ -1,5 +1,5 @@
use super::helpers;
-use super::helpers::{connect_and_wait, disconnect_and_wait, get_tunnel_state, send_guest_probes};
+use super::helpers::{connect_and_wait, get_tunnel_state, send_guest_probes};
use super::{Error, TestContext};
use crate::assert_tunnel_state;
use crate::vm::network::DUMMY_LAN_INTERFACE_IP;
@@ -8,7 +8,7 @@ use mullvad_management_interface::ManagementServiceClient;
use mullvad_types::states::TunnelState;
use std::net::{IpAddr, SocketAddr};
use test_macro::test_function;
-use test_rpc::{Interface, ServiceClient};
+use test_rpc::ServiceClient;
/// Verify that traffic to private IPs is blocked when
/// "local network sharing" is disabled, but not blocked
@@ -46,11 +46,12 @@ pub async fn test_lan(
log::info!("Test whether outgoing LAN traffic is blocked");
+ let default_interface = rpc.get_default_interface().await?;
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await?;
assert!(
detected_probes.none(),
- "observed unexpected outgoing LAN packets"
+ "observed unexpected outgoing LAN packets: {detected_probes:?}"
);
//
@@ -71,14 +72,12 @@ pub async fn test_lan(
log::info!("Test whether outgoing LAN traffic is blocked");
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface, lan_destination).await?;
assert!(
detected_probes.all(),
- "did not observe all outgoing LAN packets"
+ "did not observe all outgoing LAN packets: {detected_probes:?}"
);
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
@@ -133,15 +132,20 @@ pub async fn test_lockdown(
// Ensure all destinations are unreachable
//
+ let default_interface = rpc.get_default_interface().await?;
+
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination).await?;
- assert!(detected_probes.none(), "observed outgoing packets to LAN");
+ send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await?;
+ assert!(
+ detected_probes.none(),
+ "observed outgoing packets to LAN: {detected_probes:?}"
+ );
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination).await?;
assert!(
detected_probes.none(),
- "observed outgoing packets to internet"
+ "observed outgoing packets to internet: {detected_probes:?}"
);
//
@@ -160,17 +164,17 @@ pub async fn test_lockdown(
//
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await?;
assert!(
detected_probes.all(),
- "did not observe some outgoing packets"
+ "did not observe some outgoing packets: {detected_probes:?}"
);
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination).await?;
assert!(
detected_probes.none(),
- "observed outgoing packets to internet"
+ "observed outgoing packets to internet: {detected_probes:?}"
);
//
@@ -191,10 +195,10 @@ pub async fn test_lockdown(
// Send traffic outside the tunnel to sanity check that the internet is *not* reachable via non-
// tunnel interfaces.
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination).await?;
+ send_guest_probes(rpc.clone(), default_interface, inet_destination).await?;
assert!(
detected_probes.none(),
- "observed outgoing packets to internet"
+ "observed outgoing packets to internet: {detected_probes:?}"
);
//
@@ -205,7 +209,5 @@ pub async fn test_lockdown(
.await
.expect("failed to disable lockdown mode");
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
diff --git a/test/test-manager/src/tests/tunnel.rs b/test/test-manager/src/tests/tunnel.rs
index 1f1d61670e..6f759d7826 100644
--- a/test/test-manager/src/tests/tunnel.rs
+++ b/test/test-manager/src/tests/tunnel.rs
@@ -10,14 +10,13 @@ use mullvad_types::relay_constraints::{
OpenVpnConstraints, RelayConstraints, RelaySettings, SelectedObfuscation, TransportPort,
Udp2TcpObfuscationSettings, WireguardConstraints,
};
-use mullvad_types::relay_list::{Relay, RelayEndpointData};
use mullvad_types::wireguard;
use pnet_packet::ip::IpNextHeaderProtocols;
use talpid_types::net::{TransportProtocol, TunnelType};
use test_macro::test_function;
use test_rpc::meta::Os;
use test_rpc::mullvad_daemon::ServiceStatus;
-use test_rpc::{Interface, ServiceClient};
+use test_rpc::ServiceClient;
/// Set up an OpenVPN tunnel, UDP as well as TCP.
/// This test fails if a working tunnel cannot be set up.
@@ -123,18 +122,14 @@ pub async fn test_wireguard_tunnel(
Ok(())
}
-/// Use udp2tcp obfuscation. This test connects to a
-/// WireGuard relay over TCP. It fails if no outgoing TCP
-/// traffic to the relay is observed on the expected port.
+/// Use udp2tcp obfuscation. This test connects to a WireGuard relay over TCP. It fails if no
+/// outgoing TCP traffic to the relay is observed on the expected port.
#[test_function]
pub async fn test_udp2tcp_tunnel(
_: TestContext,
rpc: ServiceClient,
mut mullvad_client: ManagementServiceClient,
) -> Result<(), Error> {
- // TODO: check if src <-> target / tcp is observed (only)
- // TODO: ping a public IP on the fake network (not possible using real relay)
-
mullvad_client
.set_obfuscation_settings(types::ObfuscationSettings::from(ObfuscationSettings {
selected_obfuscation: SelectedObfuscation::Udp2Tcp,
@@ -158,18 +153,19 @@ pub async fn test_udp2tcp_tunnel(
connect_and_wait(&mut mullvad_client).await?;
+ let endpoint = match helpers::get_tunnel_state(&mut mullvad_client).await {
+ mullvad_types::states::TunnelState::Connected { endpoint, .. } => endpoint.endpoint,
+ _ => panic!("unexpected tunnel state"),
+ };
+
//
// Set up packet monitor
//
- let guest_ip = rpc
- .get_interface_ip(Interface::NonTunnel)
- .await
- .expect("failed to obtain inet interface IP");
-
let monitor = start_packet_monitor(
move |packet| {
- packet.source.ip() != guest_ip || (packet.protocol == IpNextHeaderProtocols::Tcp)
+ packet.destination.ip() == endpoint.address.ip()
+ && packet.protocol == IpNextHeaderProtocols::Tcp
},
MonitorOptions::default(),
)
@@ -185,9 +181,10 @@ pub async fn test_udp2tcp_tunnel(
);
let monitor_result = monitor.into_result().await.unwrap();
- assert_eq!(monitor_result.discarded_packets, 0);
-
- disconnect_and_wait(&mut mullvad_client).await?;
+ assert!(
+ !monitor_result.packets.is_empty(),
+ "detected no tcp traffic",
+ );
Ok(())
}
@@ -235,22 +232,19 @@ pub async fn test_bridge(
log::info!("Connect to OpenVPN relay via bridge");
- connect_and_wait(&mut mullvad_client)
- .await
- .expect("connect_and_wait");
+ connect_and_wait(&mut mullvad_client).await?;
- let tunnel = helpers::get_tunnel_state(&mut mullvad_client).await;
- let (entry, exit) = match tunnel {
+ let (entry, exit) = match helpers::get_tunnel_state(&mut mullvad_client).await {
mullvad_types::states::TunnelState::Connected { endpoint, .. } => {
(endpoint.proxy.unwrap().endpoint, endpoint.endpoint)
}
- _ => return Err(Error::DaemonError("daemon entered error state".to_string())),
+ _ => panic!("unexpected tunnel state"),
};
log::info!(
- "Selected entry bridge {entry_ip} & exit relay {exit_ip}",
- entry_ip = entry.address.ip().to_string(),
- exit_ip = exit.address.ip().to_string()
+ "Selected entry bridge {entry_addr} & exit relay {exit_addr}",
+ entry_addr = entry.address,
+ exit_addr = exit.address
);
// Start recording outgoing packets. Their destination will be verified
@@ -284,14 +278,11 @@ pub async fn test_bridge(
"detected no traffic to entry server",
);
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
/// Test whether WireGuard multihop works. This fails if:
-/// * No outgoing traffic to the entry relay is
-/// observed from the SUT.
+/// * No outgoing traffic to the entry relay is observed from the SUT.
/// * The conncheck reports an unexpected exit relay.
#[test_function]
pub async fn test_multihop(
@@ -299,24 +290,12 @@ pub async fn test_multihop(
rpc: ServiceClient,
mut mullvad_client: ManagementServiceClient,
) -> Result<(), Error> {
- //
- // Set relays to use
- //
-
- log::info!("Select relay");
- let relay_filter = |relay: &Relay| {
- relay.active && matches!(relay.endpoint_data, RelayEndpointData::Wireguard(_))
- };
- let (entry, exit) = helpers::random_entry_and_exit(&mut mullvad_client, relay_filter).await?;
- let exit_constraint = helpers::into_constraint(&exit);
let wireguard_constraints = WireguardConstraints {
use_multihop: true,
- entry_location: helpers::into_constraint(&entry),
..Default::default()
};
let relay_settings = RelaySettings::Normal(RelayConstraints {
- location: exit_constraint,
wireguard_constraints,
..Default::default()
});
@@ -329,25 +308,32 @@ pub async fn test_multihop(
// Connect
//
- let monitor = start_packet_monitor(
- move |packet| {
- packet.destination.ip() == entry.ipv4_addr_in
- && packet.protocol == IpNextHeaderProtocols::Udp
- },
- MonitorOptions::default(),
- )
- .await;
+ log::info!("Connect using WG multihop");
connect_and_wait(&mut mullvad_client).await?;
+ let (entry, exit) = match helpers::get_tunnel_state(&mut mullvad_client).await {
+ mullvad_types::states::TunnelState::Connected { endpoint, .. } => {
+ (endpoint.entry_endpoint.unwrap(), endpoint.endpoint)
+ }
+ _ => panic!("unexpected tunnel state"),
+ };
+
+ log::info!(
+ "Selected entry {entry_addr} & exit relay {exit_addr}",
+ entry_addr = entry.address,
+ exit_addr = exit.address
+ );
+
//
- // Verify entry IP
+ // Record outgoing packets to the entry relay
//
- log::info!("Verifying entry server");
-
- let monitor_result = monitor.into_result().await.unwrap();
- assert!(!monitor_result.packets.is_empty(), "no matching packets",);
+ let monitor = start_packet_monitor(
+ move |packet| packet.destination.ip() == entry.address.ip(),
+ MonitorOptions::default(),
+ )
+ .await;
//
// Verify exit IP
@@ -358,7 +344,14 @@ pub async fn test_multihop(
"expected Mullvad exit IP"
);
- disconnect_and_wait(&mut mullvad_client).await?;
+ //
+ // Verify entry IP
+ //
+
+ log::info!("Verifying entry server");
+
+ let monitor_result = monitor.into_result().await.unwrap();
+ assert!(!monitor_result.packets.is_empty(), "no matching packets",);
Ok(())
}
@@ -473,7 +466,7 @@ pub async fn test_quantum_resistant_tunnel(
//
connect_and_wait(&mut mullvad_client).await?;
- check_tunnel_psk(&rpc, false).await;
+ check_tunnel_psk(&rpc, &mullvad_client, false).await;
log::info!("Setting tunnel protocol to WireGuard");
@@ -497,7 +490,7 @@ pub async fn test_quantum_resistant_tunnel(
//
connect_and_wait(&mut mullvad_client).await?;
- check_tunnel_psk(&rpc, true).await;
+ check_tunnel_psk(&rpc, &mullvad_client, true).await;
assert!(
helpers::using_mullvad_exit(&rpc).await,
@@ -507,11 +500,14 @@ pub async fn test_quantum_resistant_tunnel(
Ok(())
}
-async fn check_tunnel_psk(rpc: &ServiceClient, should_have_psk: bool) {
+async fn check_tunnel_psk(
+ rpc: &ServiceClient,
+ mullvad_client: &ManagementServiceClient,
+ should_have_psk: bool,
+) {
match rpc.get_os().await.expect("failed to get OS") {
Os::Linux => {
- let name = rpc
- .get_interface_name(Interface::Tunnel)
+ let name = helpers::get_tunnel_interface(mullvad_client.clone())
.await
.expect("failed to get tun name");
let output = rpc
diff --git a/test/test-manager/src/tests/tunnel_state.rs b/test/test-manager/src/tests/tunnel_state.rs
index 87fda3b685..eb78828fd0 100644
--- a/test/test-manager/src/tests/tunnel_state.rs
+++ b/test/test-manager/src/tests/tunnel_state.rs
@@ -1,6 +1,6 @@
use super::helpers::{
- self, connect_and_wait, disconnect_and_wait, get_tunnel_state, send_guest_probes,
- set_relay_settings, unreachable_wireguard_tunnel, wait_for_tunnel_state,
+ self, connect_and_wait, get_tunnel_state, send_guest_probes, set_relay_settings,
+ unreachable_wireguard_tunnel, wait_for_tunnel_state,
};
use super::{ui, Error, TestContext};
use crate::assert_tunnel_state;
@@ -17,7 +17,7 @@ use mullvad_types::{
use std::net::{IpAddr, SocketAddr};
use talpid_types::net::{Endpoint, TransportProtocol, TunnelEndpoint, TunnelType};
use test_macro::test_function;
-use test_rpc::{Interface, ServiceClient};
+use test_rpc::ServiceClient;
/// Verify that outgoing TCP, UDP, and ICMP packets can be observed
/// in the disconnected state. The purpose is mostly to rule prevent
@@ -40,8 +40,13 @@ pub async fn test_disconnected_state(
log::info!("Sending packets to {inet_destination}");
+ let non_tunnel_interface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to obtain non-tun interface");
+
let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination).await?;
+ send_guest_probes(rpc.clone(), non_tunnel_interface, inet_destination).await?;
assert!(
detected_probes.all(),
"did not see (all) outgoing packets to destination: {detected_probes:?}",
@@ -118,26 +123,31 @@ pub async fn test_connecting_state(
// Leak test
//
+ let non_tunnel_interface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to obtain non-tun interface");
+
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination)
+ send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), inet_destination)
.await?
.none(),
"observed unexpected outgoing packets (inet)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination)
+ send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), lan_destination)
.await?
.none(),
"observed unexpected outgoing packets (lan)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_dns)
+ send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), inet_dns)
.await?
.none(),
"observed unexpected outgoing packets (DNS, inet)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_dns)
+ send_guest_probes(rpc.clone(), non_tunnel_interface, lan_dns)
.await?
.none(),
"observed unexpected outgoing packets (DNS, lan)"
@@ -145,14 +155,6 @@ pub async fn test_connecting_state(
assert_tunnel_state!(&mut mullvad_client, TunnelState::Connecting { .. });
- //
- // Disconnect
- //
-
- log::info!("Disconnecting");
-
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
@@ -201,39 +203,36 @@ pub async fn test_error_state(
// Leak test
//
+ let default_interface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to obtain non-tun interface");
+
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination)
+ send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination)
.await?
.none(),
"observed unexpected outgoing packets (inet)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_destination)
+ send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination)
.await?
.none(),
"observed unexpected outgoing packets (lan)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_dns)
+ send_guest_probes(rpc.clone(), default_interface.clone(), inet_dns)
.await?
.none(),
"observed unexpected outgoing packets (DNS, inet)"
);
assert!(
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), lan_dns)
+ send_guest_probes(rpc.clone(), default_interface, lan_dns)
.await?
.none(),
"observed unexpected outgoing packets (DNS, lan)"
);
- //
- // Disconnect
- //
-
- log::info!("Disconnecting");
-
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
@@ -318,11 +317,15 @@ pub async fn test_connected_state(
log::info!("Test whether outgoing non-tunnel traffic is blocked");
- let detected_probes =
- send_guest_probes(rpc.clone(), Some(Interface::NonTunnel), inet_destination).await?;
+ let nontun_iface = rpc
+ .get_default_interface()
+ .await
+ .expect("failed to find non-tun interface");
+
+ let detected_probes = send_guest_probes(rpc.clone(), nontun_iface, inet_destination).await?;
assert!(
detected_probes.none(),
- "observed unexpected outgoing packets"
+ "observed unexpected outgoing packets: {detected_probes:?}"
);
assert!(
@@ -330,7 +333,5 @@ pub async fn test_connected_state(
"expected Mullvad exit IP"
);
- disconnect_and_wait(&mut mullvad_client).await?;
-
Ok(())
}
diff --git a/test/test-rpc/src/client.rs b/test/test-rpc/src/client.rs
index 387d0a2435..6be77afb40 100644
--- a/test/test-rpc/src/client.rs
+++ b/test/test-rpc/src/client.rs
@@ -17,8 +17,6 @@ pub struct ServiceClient {
client: service::ServiceClient,
}
-// TODO: implement wrapper methods using macro on Service trait
-
impl ServiceClient {
pub fn new(
connection_handle: transport::ConnectionHandle,
@@ -156,7 +154,7 @@ impl ServiceClient {
/// Send TCP packet
pub async fn send_tcp(
&self,
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), Error> {
@@ -168,7 +166,7 @@ impl ServiceClient {
/// Send UDP packet
pub async fn send_udp(
&self,
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), Error> {
@@ -180,7 +178,7 @@ impl ServiceClient {
/// Send ICMP
pub async fn send_ping(
&self,
- interface: Option<Interface>,
+ interface: Option<String>,
destination: IpAddr,
) -> Result<(), Error> {
self.client
@@ -196,16 +194,16 @@ impl ServiceClient {
}
/// Returns the IP of the given interface.
- pub async fn get_interface_name(&self, interface: Interface) -> Result<String, Error> {
+ pub async fn get_interface_ip(&self, interface: String) -> Result<IpAddr, Error> {
self.client
- .get_interface_name(tarpc::context::current(), interface)
+ .get_interface_ip(tarpc::context::current(), interface)
.await?
}
- /// Returns the IP of the given interface.
- pub async fn get_interface_ip(&self, interface: Interface) -> Result<IpAddr, Error> {
+ /// Returns the name of the default non-tunnel interface
+ pub async fn get_default_interface(&self) -> Result<String, Error> {
self.client
- .get_interface_ip(tarpc::context::current(), interface)
+ .get_default_interface(tarpc::context::current())
.await?
}
diff --git a/test/test-rpc/src/lib.rs b/test/test-rpc/src/lib.rs
index 2fd4411f49..6968a3c613 100644
--- a/test/test-rpc/src/lib.rs
+++ b/test/test-rpc/src/lib.rs
@@ -55,12 +55,6 @@ pub enum Error {
Timeout,
}
-#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy)]
-pub enum Interface {
- Tunnel,
- NonTunnel,
-}
-
/// Response from am.i.mullvad.net
#[derive(Debug, Serialize, Deserialize)]
pub struct AmIMullvad {
@@ -128,29 +122,29 @@ mod service {
/// Send TCP packet
async fn send_tcp(
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), Error>;
/// Send UDP packet
async fn send_udp(
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), Error>;
/// Send ICMP
- async fn send_ping(interface: Option<Interface>, destination: IpAddr) -> Result<(), Error>;
+ async fn send_ping(interface: Option<String>, destination: IpAddr) -> Result<(), Error>;
/// Fetch the current location.
async fn geoip_lookup(mullvad_host: String) -> Result<AmIMullvad, Error>;
- /// Returns the name of the given interface.
- async fn get_interface_name(interface: Interface) -> Result<String, Error>;
-
/// Returns the IP of the given interface.
- async fn get_interface_ip(interface: Interface) -> Result<IpAddr, Error>;
+ async fn get_interface_ip(interface: String) -> Result<IpAddr, Error>;
+
+ /// Returns the name of the default interface.
+ async fn get_default_interface() -> Result<String, Error>;
/// Perform DNS resolution.
async fn resolve_hostname(hostname: String) -> Result<Vec<SocketAddr>, Error>;
diff --git a/test/test-runner/src/main.rs b/test/test-runner/src/main.rs
index 8d7991d6fa..ebf0d1e474 100644
--- a/test/test-runner/src/main.rs
+++ b/test/test-runner/src/main.rs
@@ -13,7 +13,7 @@ use test_rpc::{
mullvad_daemon::{ServiceStatus, SOCKET_PATH},
package::Package,
transport::GrpcForwarder,
- AppTrace, Interface, Service,
+ AppTrace, Service,
};
use tokio::sync::broadcast::error::TryRecvError;
use tokio::{
@@ -117,7 +117,7 @@ impl Service for TestServer {
async fn send_tcp(
self,
_: context::Context,
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), test_rpc::Error> {
@@ -127,7 +127,7 @@ impl Service for TestServer {
async fn send_udp(
self,
_: context::Context,
- interface: Option<Interface>,
+ interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), test_rpc::Error> {
@@ -137,10 +137,10 @@ impl Service for TestServer {
async fn send_ping(
self,
_: context::Context,
- interface: Option<Interface>,
+ interface: Option<String>,
destination: IpAddr,
) -> Result<(), test_rpc::Error> {
- net::send_ping(interface, destination).await
+ net::send_ping(interface.as_ref().map(String::as_str), destination).await
}
async fn geoip_lookup(
@@ -165,20 +165,16 @@ impl Service for TestServer {
.collect())
}
- async fn get_interface_name(
- self,
- _: context::Context,
- interface: Interface,
- ) -> Result<String, test_rpc::Error> {
- Ok(net::get_interface_name(interface).to_owned())
- }
-
async fn get_interface_ip(
self,
_: context::Context,
- interface: Interface,
+ interface: String,
) -> Result<IpAddr, test_rpc::Error> {
- net::get_interface_ip(interface)
+ net::get_interface_ip(&interface).await
+ }
+
+ async fn get_default_interface(self, _: context::Context) -> Result<String, test_rpc::Error> {
+ Ok(net::get_default_interface().to_owned())
}
async fn poll_output(
diff --git a/test/test-runner/src/net.rs b/test/test-runner/src/net.rs
index 851a2f2951..f40aece4c9 100644
--- a/test/test-runner/src/net.rs
+++ b/test/test-runner/src/net.rs
@@ -2,27 +2,14 @@ use socket2::SockAddr;
#[cfg(target_os = "macos")]
use std::{ffi::CString, num::NonZeroU32};
use std::{
+ io::Write,
net::{IpAddr, SocketAddr},
process::Output,
};
-use test_rpc::Interface;
-use tokio::{
- io::AsyncWriteExt,
- net::{TcpStream, UdpSocket},
- process::Command,
-};
-
-#[cfg(target_os = "linux")]
-const TUNNEL_INTERFACE: &str = "wg-mullvad";
-
-#[cfg(target_os = "windows")]
-const TUNNEL_INTERFACE: &str = "Mullvad";
-
-#[cfg(target_os = "macos")]
-const TUNNEL_INTERFACE: &str = "utun3";
+use tokio::process::Command;
pub async fn send_tcp(
- bind_interface: Option<Interface>,
+ bind_interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), test_rpc::Error> {
@@ -36,14 +23,7 @@ pub async fn send_tcp(
test_rpc::Error::SendTcp
})?;
- sock.set_nonblocking(true).map_err(|error| {
- log::error!("Failed to set non-blocking TCP socket: {error}");
- test_rpc::Error::SendTcp
- })?;
-
if let Some(iface) = bind_interface {
- let iface = get_interface_name(iface);
-
#[cfg(target_os = "macos")]
let interface_index = unsafe {
let name = CString::new(iface).unwrap();
@@ -71,35 +51,32 @@ pub async fn send_tcp(
log::trace!("Bind interface {iface} is ignored on Windows")
}
- sock.bind(&SockAddr::from(bind_addr)).map_err(|error| {
- log::error!("Failed to bind TCP socket to {bind_addr}: {error}");
- test_rpc::Error::SendTcp
- })?;
-
log::debug!("Connecting from {bind_addr} to {destination}/TCP");
- sock.connect(&SockAddr::from(destination))
- .map_err(|error| {
- log::error!("Failed to connect to {destination}: {error}");
+ tokio::task::spawn_blocking(move || {
+ sock.bind(&SockAddr::from(bind_addr)).map_err(|error| {
+ log::error!("Failed to bind TCP socket to {bind_addr}: {error}");
test_rpc::Error::SendTcp
})?;
- let std_stream = std::net::TcpStream::from(sock);
- let mut stream = TcpStream::from_std(std_stream).map_err(|error| {
- log::error!("Failed to convert to TCP stream to tokio stream: {error}");
- test_rpc::Error::SendTcp
- })?;
-
- stream.write_all(b"hello").await.map_err(|error| {
- log::error!("Failed to send message to {destination}: {error}");
- test_rpc::Error::SendTcp
- })?;
+ sock.connect(&SockAddr::from(destination))
+ .map_err(|error| {
+ log::error!("Failed to connect to {destination}: {error}");
+ test_rpc::Error::SendTcp
+ })?;
- Ok(())
+ let mut stream = std::net::TcpStream::from(sock);
+ stream.write_all(b"hello").map_err(|error| {
+ log::error!("Failed to send message to {destination}: {error}");
+ test_rpc::Error::SendTcp
+ })
+ })
+ .await
+ .unwrap()
}
pub async fn send_udp(
- bind_interface: Option<Interface>,
+ bind_interface: Option<String>,
bind_addr: SocketAddr,
destination: SocketAddr,
) -> Result<(), test_rpc::Error> {
@@ -113,14 +90,7 @@ pub async fn send_udp(
test_rpc::Error::SendUdp
})?;
- sock.set_nonblocking(true).map_err(|error| {
- log::error!("Failed to set non-blocking UDP socket: {error}");
- test_rpc::Error::SendUdp
- })?;
-
if let Some(iface) = bind_interface {
- let iface = get_interface_name(iface);
-
#[cfg(target_os = "macos")]
let interface_index = unsafe {
let name = CString::new(iface).unwrap();
@@ -148,32 +118,28 @@ pub async fn send_udp(
log::trace!("Bind interface {iface} is ignored on Windows")
}
- sock.bind(&SockAddr::from(bind_addr)).map_err(|error| {
- log::error!("Failed to bind UDP socket to {bind_addr}: {error}");
- test_rpc::Error::SendUdp
- })?;
+ let _ = tokio::task::spawn_blocking(move || {
+ sock.bind(&SockAddr::from(bind_addr)).map_err(|error| {
+ log::error!("Failed to bind UDP socket to {bind_addr}: {error}");
+ test_rpc::Error::SendUdp
+ })?;
- log::debug!("Send message from {bind_addr} to {destination}/UDP");
+ log::debug!("Send message from {bind_addr} to {destination}/UDP");
- let std_socket = std::net::UdpSocket::from(sock);
- let tokio_socket = UdpSocket::from_std(std_socket).map_err(|error| {
- log::error!("Failed to convert to UDP socket to tokio socket: {error}");
- test_rpc::Error::SendUdp
- })?;
-
- tokio_socket
- .send_to(b"hello", destination)
- .await
- .map_err(|error| {
+ let std_socket = std::net::UdpSocket::from(sock);
+ std_socket.send_to(b"hello", destination).map_err(|error| {
log::error!("Failed to send message to {destination}: {error}");
test_rpc::Error::SendUdp
- })?;
+ })
+ })
+ .await
+ .unwrap()?;
Ok(())
}
pub async fn send_ping(
- interface: Option<Interface>,
+ interface: Option<&str>,
destination: IpAddr,
) -> Result<(), test_rpc::Error> {
#[cfg(target_os = "windows")]
@@ -202,22 +168,8 @@ pub async fn send_ping(
cmd.args(["-c", "1"]);
match interface {
- Some(Interface::Tunnel) => {
- log::info!("Pinging {destination} in tunnel");
-
- #[cfg(target_os = "windows")]
- if let Some(source_ip) = source_ip {
- cmd.args(["-S", &source_ip.to_string()]);
- }
-
- #[cfg(target_os = "windows")]
- cmd.args(["-I", TUNNEL_INTERFACE]);
-
- #[cfg(target_os = "macos")]
- cmd.args(["-b", TUNNEL_INTERFACE]);
- }
- Some(Interface::NonTunnel) => {
- log::info!("Pinging {destination} outside tunnel");
+ Some(interface) => {
+ log::info!("Pinging {destination} on interface {interface}");
#[cfg(target_os = "windows")]
if let Some(source_ip) = source_ip {
@@ -225,10 +177,10 @@ pub async fn send_ping(
}
#[cfg(target_os = "linux")]
- cmd.args(["-I", non_tunnel_interface()]);
+ cmd.args(["-I", interface]);
#[cfg(target_os = "macos")]
- cmd.args(["-b", non_tunnel_interface()]);
+ cmd.args(["-b", interface]);
}
None => log::info!("Pinging {destination}"),
}
@@ -250,18 +202,16 @@ pub async fn send_ping(
}
#[cfg(unix)]
-pub fn get_interface_ip(interface: Interface) -> Result<IpAddr, test_rpc::Error> {
+pub async fn get_interface_ip(interface: &str) -> Result<IpAddr, test_rpc::Error> {
// TODO: IPv6
use std::net::Ipv4Addr;
- let alias = get_interface_name(interface);
-
let addrs = nix::ifaddrs::getifaddrs().map_err(|error| {
log::error!("Failed to obtain interfaces: {}", error);
test_rpc::Error::Syscall
})?;
for addr in addrs {
- if addr.interface_name == alias {
+ if addr.interface_name == interface {
if let Some(address) = addr.address {
if let Some(sockaddr) = address.as_sockaddr_in() {
return Ok(IpAddr::V4(Ipv4Addr::from(sockaddr.ip())));
@@ -274,15 +224,8 @@ pub fn get_interface_ip(interface: Interface) -> Result<IpAddr, test_rpc::Error>
Err(test_rpc::Error::InterfaceNotFound)
}
-pub fn get_interface_name(interface: Interface) -> &'static str {
- match interface {
- Interface::Tunnel => TUNNEL_INTERFACE,
- Interface::NonTunnel => non_tunnel_interface(),
- }
-}
-
#[cfg(target_os = "windows")]
-pub fn get_interface_ip(interface: Interface) -> Result<IpAddr, test_rpc::Error> {
+pub async fn get_interface_ip(interface: &str) -> Result<IpAddr, test_rpc::Error> {
// TODO: IPv6
get_interface_ip_for_family(interface, talpid_windows::net::AddressFamily::Ipv4)
@@ -292,24 +235,19 @@ pub fn get_interface_ip(interface: Interface) -> Result<IpAddr, test_rpc::Error>
#[cfg(target_os = "windows")]
fn get_interface_ip_for_family(
- interface: Interface,
+ interface: &str,
family: talpid_windows::net::AddressFamily,
) -> Result<Option<IpAddr>, ()> {
- let interface = match interface {
- Interface::NonTunnel => non_tunnel_interface(),
- Interface::Tunnel => TUNNEL_INTERFACE,
- };
- let interface_alias = talpid_windows::net::luid_from_alias(interface).map_err(|error| {
+ let luid = talpid_windows::net::luid_from_alias(interface).map_err(|error| {
log::error!("Failed to obtain interface LUID: {error}");
})?;
-
- talpid_windows::net::get_ip_address_for_interface(family, interface_alias).map_err(|error| {
+ talpid_windows::net::get_ip_address_for_interface(family, luid).map_err(|error| {
log::error!("Failed to obtain interface IP: {error}");
})
}
#[cfg(target_os = "windows")]
-fn non_tunnel_interface() -> &'static str {
+pub fn get_default_interface() -> &'static str {
use once_cell::sync::OnceCell;
use talpid_platform_metadata::WindowsVersion;
@@ -326,12 +264,12 @@ fn non_tunnel_interface() -> &'static str {
}
#[cfg(target_os = "linux")]
-fn non_tunnel_interface() -> &'static str {
+pub fn get_default_interface() -> &'static str {
"ens3"
}
#[cfg(target_os = "macos")]
-fn non_tunnel_interface() -> &'static str {
+pub fn get_default_interface() -> &'static str {
"en0"
}