Skip to content

Commit

Permalink
Prevent ARP lookups during LAN tests
Browse files Browse the repository at this point in the history
  • Loading branch information
dlon committed Apr 10, 2024
1 parent c1950b6 commit 29fbc73
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 57 deletions.
6 changes: 3 additions & 3 deletions test/test-manager/src/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub async fn reboot(rpc: &mut ServiceClient) -> Result<(), Error> {
Ok(())
}

#[derive(Debug, Default)]
#[derive(Debug, Default, PartialEq)]
pub struct ProbeResult {
tcp: usize,
udp: usize,
Expand Down Expand Up @@ -121,7 +121,7 @@ pub async fn send_guest_probes(
rpc: ServiceClient,
interface: String,
destination: SocketAddr,
) -> Result<ProbeResult, Error> {
) -> ProbeResult {
const MONITOR_DURATION: Duration = Duration::from_secs(8);

let pktmon = start_packet_monitor(
Expand Down Expand Up @@ -162,7 +162,7 @@ pub async fn send_guest_probes(
}
}

Ok(result)
result
}

/// Send one probe per transport protocol to `destination` without running a packet monitor
Expand Down
65 changes: 29 additions & 36 deletions test/test-manager/src/tests/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ use super::{
helpers::{connect_and_wait, send_guest_probes},
Error, TestContext,
};
use crate::{assert_tunnel_state, vm::network::DUMMY_LAN_INTERFACE_IP};

use mullvad_management_interface::MullvadProxyClient;
use mullvad_types::states::TunnelState;
use std::net::{IpAddr, SocketAddr};
use std::net::SocketAddr;
use test_macro::test_function;
use test_rpc::ServiceClient;

Expand All @@ -22,12 +20,9 @@ pub async fn test_lan(
rpc: ServiceClient,
mut mullvad_client: MullvadProxyClient,
) -> Result<(), Error> {
let lan_destination = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 1234);

// Connect
//

connect_and_wait(&mut mullvad_client).await?;
// Take care not to use some bogus IP in the guest's subnet, lest we just send ARP requests
// These will fail if there's no actual host present
let lan_destination = "10.1.2.3:1234".parse().unwrap();

// Disable LAN sharing
//
Expand All @@ -39,14 +34,19 @@ pub async fn test_lan(
.await
.expect("failed to disable LAN sharing");

// Connect
//

connect_and_wait(&mut mullvad_client).await?;

// Ensure LAN is not reachable
//

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(), default_interface.clone(), lan_destination).await?;
send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await;
assert!(
detected_probes.none(),
"observed unexpected outgoing LAN packets: {detected_probes:?}"
Expand All @@ -65,10 +65,12 @@ pub async fn test_lan(
// Ensure LAN is reachable
//

// FIXME
tokio::time::sleep(std::time::Duration::from_secs(30)).await;

log::info!("Test whether outgoing LAN traffic is blocked");

let detected_probes =
send_guest_probes(rpc.clone(), default_interface, lan_destination).await?;
let detected_probes = send_guest_probes(rpc.clone(), default_interface, lan_destination).await;
assert!(
detected_probes.all(),
"did not observe all outgoing LAN packets: {detected_probes:?}"
Expand Down Expand Up @@ -96,19 +98,11 @@ pub async fn test_lockdown(
rpc: ServiceClient,
mut mullvad_client: MullvadProxyClient,
) -> Result<(), Error> {
let lan_destination: SocketAddr = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 1337);
// Take care not to use some bogus IP in the guest's subnet, lest we just send ARP requests
// These will fail if there's no actual host present
let lan_destination = "10.1.2.3:1234".parse().unwrap();
let inet_destination: SocketAddr = "1.1.1.1:1337".parse().unwrap();

log::info!("Verify tunnel state: disconnected");
assert_tunnel_state!(&mut mullvad_client, TunnelState::Disconnected { .. });

// Enable lockdown mode
//
mullvad_client
.set_block_when_disconnected(true)
.await
.expect("failed to enable lockdown mode");

// Disable LAN sharing
//

Expand All @@ -119,20 +113,27 @@ pub async fn test_lockdown(
.await
.expect("failed to disable LAN sharing");

// Enable lockdown mode
//
mullvad_client
.set_block_when_disconnected(true)
.await
.expect("failed to enable lockdown mode");

// Ensure all destinations are unreachable
//

let default_interface = rpc.get_default_interface().await?;

let detected_probes =
send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await?;
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(), default_interface.clone(), inet_destination).await?;
send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination).await;
assert!(
detected_probes.none(),
"observed outgoing packets to internet: {detected_probes:?}"
Expand All @@ -152,14 +153,14 @@ pub async fn test_lockdown(
//

let detected_probes =
send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await?;
send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination).await;
assert!(
detected_probes.all(),
"did not observe some outgoing packets: {detected_probes:?}"
);

let detected_probes =
send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination).await?;
send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination).await;
assert!(
detected_probes.none(),
"observed outgoing packets to internet: {detected_probes:?}"
Expand All @@ -180,19 +181,11 @@ 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(), default_interface, inet_destination).await?;
let detected_probes = send_guest_probes(rpc.clone(), default_interface, inet_destination).await;
assert!(
detected_probes.none(),
"observed outgoing packets to internet: {detected_probes:?}"
);

// Disable lockdown mode
//
mullvad_client
.set_block_when_disconnected(false)
.await
.expect("failed to disable lockdown mode");

Ok(())
}
37 changes: 19 additions & 18 deletions test/test-manager/src/tests/tunnel_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ use super::{
},
ui, Error, TestContext,
};
use crate::{
assert_tunnel_state, tests::helpers::ping_sized_with_timeout,
vm::network::DUMMY_LAN_INTERFACE_IP,
};
use crate::{assert_tunnel_state, tests::helpers::ping_sized_with_timeout};

use mullvad_management_interface::MullvadProxyClient;
use mullvad_relay_selector::query::builder::RelayQueryBuilder;
Expand Down Expand Up @@ -143,7 +140,7 @@ pub async fn test_disconnected_state(
.expect("failed to obtain non-tun interface");

let detected_probes =
send_guest_probes(rpc.clone(), non_tunnel_interface, 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:?}",
Expand Down Expand Up @@ -181,9 +178,11 @@ pub async fn test_connecting_state(
mut mullvad_client: MullvadProxyClient,
) -> Result<(), Error> {
let inet_destination = "1.1.1.1:1337".parse().unwrap();
let lan_destination: SocketAddr = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 1337);
// Take care not to use some bogus IP in the guest's subnet, lest we just send ARP requests
// These will fail if there's no actual host present
let lan_destination = "10.1.2.3:1234".parse().unwrap();
let inet_dns = "1.1.1.1:53".parse().unwrap();
let lan_dns: SocketAddr = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 53);
let lan_dns = "10.1.2.3:53".parse().unwrap();

log::info!("Verify tunnel state: disconnected");
assert_tunnel_state!(&mut mullvad_client, TunnelState::Disconnected { .. });
Expand Down Expand Up @@ -225,25 +224,25 @@ pub async fn test_connecting_state(

assert!(
send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), inet_destination)
.await?
.await
.none(),
"observed unexpected outgoing packets (inet)"
);
assert!(
send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), lan_destination)
.await?
.await
.none(),
"observed unexpected outgoing packets (lan)"
);
assert!(
send_guest_probes(rpc.clone(), non_tunnel_interface.clone(), inet_dns)
.await?
.await
.none(),
"observed unexpected outgoing packets (DNS, inet)"
);
assert!(
send_guest_probes(rpc.clone(), non_tunnel_interface, lan_dns)
.await?
.await
.none(),
"observed unexpected outgoing packets (DNS, lan)"
);
Expand All @@ -262,9 +261,11 @@ pub async fn test_error_state(
mut mullvad_client: MullvadProxyClient,
) -> Result<(), Error> {
let inet_destination = "1.1.1.1:1337".parse().unwrap();
let lan_destination: SocketAddr = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 1337);
// Take care not to use some bogus IP in the guest's subnet, lest we just send ARP requests
// These will fail if there's no actual host present
let lan_destination = "10.1.2.3:1234".parse().unwrap();
let inet_dns = "1.1.1.1:53".parse().unwrap();
let lan_dns: SocketAddr = SocketAddr::new(IpAddr::V4(DUMMY_LAN_INTERFACE_IP), 53);
let lan_dns = "10.1.2.3:53".parse().unwrap();

log::info!("Verify tunnel state: disconnected");
assert_tunnel_state!(&mut mullvad_client, TunnelState::Disconnected { .. });
Expand Down Expand Up @@ -303,25 +304,25 @@ pub async fn test_error_state(

assert!(
send_guest_probes(rpc.clone(), default_interface.clone(), inet_destination)
.await?
.await
.none(),
"observed unexpected outgoing packets (inet)"
);
assert!(
send_guest_probes(rpc.clone(), default_interface.clone(), lan_destination)
.await?
.await
.none(),
"observed unexpected outgoing packets (lan)"
);
assert!(
send_guest_probes(rpc.clone(), default_interface.clone(), inet_dns)
.await?
.await
.none(),
"observed unexpected outgoing packets (DNS, inet)"
);
assert!(
send_guest_probes(rpc.clone(), default_interface, lan_dns)
.await?
.await
.none(),
"observed unexpected outgoing packets (DNS, lan)"
);
Expand Down Expand Up @@ -389,7 +390,7 @@ pub async fn test_connected_state(
.await
.expect("failed to find non-tun interface");

let detected_probes = send_guest_probes(rpc.clone(), nontun_iface, inet_destination).await?;
let detected_probes = send_guest_probes(rpc.clone(), nontun_iface, inet_destination).await;
assert!(
detected_probes.none(),
"observed unexpected outgoing packets: {detected_probes:?}"
Expand Down

0 comments on commit 29fbc73

Please sign in to comment.