diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-11-22 16:18:18 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-11-22 16:18:18 +0100 |
| commit | f7eb43c9170176a59019f5ba3eb5bed08c413058 (patch) | |
| tree | 5e358a22218210c560c44006585cf411d1ddb23b /test/test-manager | |
| parent | 6b0b627bc042da11496bd0ced8662557962572ef (diff) | |
| parent | 56970baac0773952d2153dc0719faa1bc699ad91 (diff) | |
| download | mullvadvpn-f7eb43c9170176a59019f5ba3eb5bed08c413058.tar.xz mullvadvpn-f7eb43c9170176a59019f5ba3eb5bed08c413058.zip | |
Merge branch 'fix-macos-tests' into main
Diffstat (limited to 'test/test-manager')
| -rw-r--r-- | test/test-manager/src/tests/account.rs | 3 | ||||
| -rw-r--r-- | test/test-manager/src/tests/dns.rs | 84 | ||||
| -rw-r--r-- | test/test-manager/src/tests/helpers.rs | 69 | ||||
| -rw-r--r-- | test/test-manager/src/tests/install.rs | 10 | ||||
| -rw-r--r-- | test/test-manager/src/tests/mod.rs | 1 | ||||
| -rw-r--r-- | test/test-manager/src/tests/settings.rs | 42 | ||||
| -rw-r--r-- | test/test-manager/src/tests/tunnel.rs | 118 | ||||
| -rw-r--r-- | test/test-manager/src/tests/tunnel_state.rs | 67 |
8 files changed, 205 insertions, 189 deletions
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(()) } |
