Skip to content

Commit

Permalink
Merge branch 'fix/test_bridge'
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusPettersson98 committed Nov 17, 2023
2 parents 9574c5f + 04d0d6a commit 0a82036
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 89 deletions.
51 changes: 29 additions & 22 deletions test/test-manager/src/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ use crate::network_monitor::{start_packet_monitor, MonitorOptions};
use futures::StreamExt;
use mullvad_management_interface::{types, ManagementServiceClient};
use mullvad_types::{
location::Location,
relay_constraints::{
BridgeState, Constraint, GeographicLocationConstraint, LocationConstraint,
BridgeSettings, BridgeState, Constraint, GeographicLocationConstraint, LocationConstraint,
ObfuscationSettings, OpenVpnConstraints, RelayConstraints, RelaySettings,
WireguardConstraints,
},
relay_list::{Relay, RelayList},
states::TunnelState,
};
use pnet_packet::ip::IpNextHeaderProtocols;
Expand Down Expand Up @@ -378,6 +380,19 @@ pub async fn set_relay_settings(
Ok(())
}

pub async fn set_bridge_settings(
mullvad_client: &mut ManagementServiceClient,
bridge_settings: BridgeSettings,
) -> Result<(), Error> {
let new_settings = types::BridgeSettings::from(bridge_settings);

mullvad_client
.set_bridge_settings(new_settings)
.await
.map_err(|error| Error::DaemonError(format!("Failed to set bridge settings: {}", error)))?;
Ok(())
}

pub async fn get_tunnel_state(mullvad_client: &mut ManagementServiceClient) -> TunnelState {
let state = mullvad_client
.get_tunnel_state(())
Expand Down Expand Up @@ -442,9 +457,9 @@ pub fn unreachable_wireguard_tunnel() -> talpid_types::net::wireguard::Connectio
pub async fn random_entry_and_exit<Filter>(
mullvad_client: &mut ManagementServiceClient,
criteria: Filter,
) -> Result<(types::Relay, types::Relay), Error>
) -> Result<(Relay, Relay), Error>
where
Filter: Fn(&types::Relay) -> bool,
Filter: Fn(&Relay) -> bool,
{
use itertools::Itertools;
// Pluck the first 2 relays and return them as a tuple.
Expand All @@ -465,43 +480,35 @@ where
pub async fn filter_relays<Filter>(
mullvad_client: &mut ManagementServiceClient,
criteria: Filter,
) -> Result<Vec<types::Relay>, Error>
) -> Result<Vec<Relay>, Error>
where
Filter: Fn(&types::Relay) -> bool,
Filter: Fn(&Relay) -> bool,
{
let relaylist = mullvad_client
let relay_list: RelayList = mullvad_client
.get_relay_locations(())
.await
.map_err(|error| Error::DaemonError(format!("Failed to obtain relay list: {}", error)))?
.into_inner();
.into_inner()
.try_into()?;

Ok(flatten_relaylist(relaylist)
.into_iter()
.filter(criteria)
Ok(relay_list
.relays()
.filter(|relay| criteria(relay))
.cloned()
.collect())
}

/// Dig out the [`Relay`]s contained in a [`RelayList`].
pub fn flatten_relaylist(relays: types::RelayList) -> Vec<types::Relay> {
relays
.countries
.iter()
.flat_map(|country| country.cities.clone())
.flat_map(|city| city.relays)
.collect()
}

/// Convenience function for constructing a constraint from a given [`Relay`].
///
/// # Panics
///
/// The relay must have a location set.
pub fn into_constraint(relay: &types::Relay) -> Constraint<LocationConstraint> {
pub fn into_constraint(relay: &Relay) -> Constraint<LocationConstraint> {
relay
.location
.as_ref()
.map(
|types::Location {
|Location {
country_code,
city_code,
..
Expand Down
10 changes: 8 additions & 2 deletions test/test-manager/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use test_rpc::ServiceClient;

use futures::future::BoxFuture;

use mullvad_management_interface::{types::Settings, ManagementServiceClient};
use mullvad_management_interface::{
types::{self, Settings},
ManagementServiceClient,
};
use once_cell::sync::OnceCell;
use std::time::Duration;

Expand All @@ -37,7 +40,7 @@ pub type TestWrapperFunction = Box<
) -> BoxFuture<'static, Result<(), Error>>,
>;

#[derive(err_derive::Error, Debug, PartialEq, Eq)]
#[derive(err_derive::Error, Debug)]
pub enum Error {
#[error(display = "RPC call failed")]
Rpc(#[source] test_rpc::Error),
Expand All @@ -57,6 +60,9 @@ pub enum Error {
#[error(display = "The daemon returned an error: {}", _0)]
DaemonError(String),

#[error(display = "Failed to parse gRPC response")]
InvalidGrpcResponse(#[error(source)] types::FromProtobufTypeError),

#[error(display = "An error occurred: {}", _0)]
Other(String),
}
Expand Down
111 changes: 55 additions & 56 deletions test/test-manager/src/tests/tunnel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::helpers::{self, connect_and_wait, disconnect_and_wait, set_relay_settings};
use super::helpers::{
self, connect_and_wait, disconnect_and_wait, set_bridge_settings, set_relay_settings,
};
use super::{Error, TestContext};
use std::net::IpAddr;

use crate::network_monitor::{start_packet_monitor, MonitorOptions};
use mullvad_management_interface::{types, ManagementServiceClient};
Expand All @@ -9,6 +10,7 @@ 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};
Expand Down Expand Up @@ -200,88 +202,86 @@ pub async fn test_bridge(
rpc: ServiceClient,
mut mullvad_client: ManagementServiceClient,
) -> Result<(), Error> {
log::info!("Select relay");
let bridge_filter = |bridge: &types::Relay| {
bridge.active && bridge.endpoint_type == i32::from(types::relay::RelayType::Bridge)
};
let ovpn_filter = |relay: &types::Relay| {
relay.active && relay.endpoint_type == i32::from(types::relay::RelayType::Openvpn)
};
let entry = helpers::filter_relays(&mut mullvad_client, bridge_filter)
.await?
.pop()
.unwrap();
let exit = helpers::filter_relays(&mut mullvad_client, ovpn_filter)
.await?
.pop()
.unwrap();

//
// Enable bridge mode
//

log::info!("Updating bridge settings");

mullvad_client
.set_bridge_state(types::BridgeState::from(BridgeState::On))
.await
.expect("failed to enable bridge mode");

mullvad_client
.set_bridge_settings(types::BridgeSettings::from(BridgeSettings::Normal(
BridgeConstraints {
location: helpers::into_constraint(&entry),
..Default::default()
},
)))
.await
.expect("failed to update bridge settings");

let relay_settings = RelaySettings::Normal(RelayConstraints {
location: helpers::into_constraint(&exit),
tunnel_protocol: Constraint::Only(TunnelType::OpenVpn),
..Default::default()
});
set_bridge_settings(
&mut mullvad_client,
BridgeSettings::Normal(BridgeConstraints::default()),
)
.await
.expect("failed to update bridge settings");

set_relay_settings(&mut mullvad_client, relay_settings)
.await
.expect("failed to update relay settings");
set_relay_settings(
&mut mullvad_client,
RelaySettings::Normal(RelayConstraints {
tunnel_protocol: Constraint::Only(TunnelType::OpenVpn),
..Default::default()
}),
)
.await
.expect("failed to update relay settings");

//
// Connect to VPN
//

log::info!("Connect to OpenVPN relay via bridge");

connect_and_wait(&mut mullvad_client)
.await
.expect("connect_and_wait");

let tunnel = helpers::get_tunnel_state(&mut mullvad_client).await;
let (entry, exit) = match tunnel {
mullvad_types::states::TunnelState::Connected { endpoint, .. } => {
(endpoint.proxy.unwrap().endpoint, endpoint.endpoint)
}
_ => return Err(Error::DaemonError("daemon entered error state".to_string())),
};

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()
);

// Start recording outgoing packets. Their destination will be verified
// against the bridge's IP address later.
let monitor = start_packet_monitor(
move |packet| packet.destination.ip() == entry.ipv4_addr_in.parse::<IpAddr>().unwrap(),
move |packet| packet.destination.ip() == entry.address.ip(),
MonitorOptions::default(),
)
.await;

connect_and_wait(&mut mullvad_client)
.await
.expect("connect_and_wait");

//
// Verify entry IP
// Verify exit IP
//

log::info!("Verifying entry server");
log::info!("Verifying exit server");

let monitor_result = monitor.into_result().await.unwrap();
assert!(
!monitor_result.packets.is_empty(),
"detected no traffic to entry server",
helpers::using_mullvad_exit(&rpc).await,
"expected Mullvad exit IP"
);

//
// Verify exit IP
// Verify entry IP
//

log::info!("Verifying entry server");

let monitor_result = monitor.into_result().await.unwrap();
assert!(
helpers::using_mullvad_exit(&rpc).await,
"expected Mullvad exit IP"
!monitor_result.packets.is_empty(),
"detected no traffic to entry server",
);

disconnect_and_wait(&mut mullvad_client).await?;
Expand All @@ -304,8 +304,8 @@ pub async fn test_multihop(
//

log::info!("Select relay");
let relay_filter = |relay: &types::Relay| {
relay.active && relay.endpoint_type == i32::from(types::relay::RelayType::Wireguard)
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);
Expand All @@ -331,7 +331,7 @@ pub async fn test_multihop(

let monitor = start_packet_monitor(
move |packet| {
packet.destination.ip() == entry.ipv4_addr_in.parse::<IpAddr>().unwrap()
packet.destination.ip() == entry.ipv4_addr_in
&& packet.protocol == IpNextHeaderProtocols::Udp
},
MonitorOptions::default(),
Expand Down Expand Up @@ -565,9 +565,8 @@ pub async fn test_quantum_resistant_multihop_udp2tcp_tunnel(
wireguard_constraints: WireguardConstraints {
use_multihop: true,
..Default::default()
}
.into(),
tunnel_protocol: Constraint::Only(TunnelType::Wireguard).into(),
},
tunnel_protocol: Constraint::Only(TunnelType::Wireguard),
..Default::default()
},
)))
Expand Down
11 changes: 6 additions & 5 deletions test/test-manager/src/tests/tunnel_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use super::{ui, Error, TestContext};
use crate::assert_tunnel_state;
use crate::vm::network::DUMMY_LAN_INTERFACE_IP;

use mullvad_management_interface::{types, ManagementServiceClient};
use mullvad_management_interface::ManagementServiceClient;
use mullvad_types::relay_constraints::GeographicLocationConstraint;
use mullvad_types::relay_list::{Relay, RelayEndpointData};
use mullvad_types::CustomTunnelEndpoint;
use mullvad_types::{
relay_constraints::{Constraint, LocationConstraint, RelayConstraints, RelaySettings},
states::TunnelState,
};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::{IpAddr, SocketAddr};
use talpid_types::net::{Endpoint, TransportProtocol, TunnelEndpoint, TunnelType};
use test_macro::test_function;
use test_rpc::{Interface, ServiceClient};
Expand Down Expand Up @@ -257,8 +258,8 @@ pub async fn test_connected_state(

log::info!("Select relay");

let relay_filter = |relay: &types::Relay| {
relay.active && relay.endpoint_type == i32::from(types::relay::RelayType::Wireguard)
let relay_filter = |relay: &Relay| {
relay.active && matches!(relay.endpoint_data, RelayEndpointData::Wireguard(_))
};

let relay = helpers::filter_relays(&mut mullvad_client, relay_filter)
Expand Down Expand Up @@ -306,7 +307,7 @@ pub async fn test_connected_state(
},
..
} => {
assert_eq!(*addr.ip(), relay.ipv4_addr_in.parse::<Ipv4Addr>().unwrap());
assert_eq!(*addr.ip(), relay.ipv4_addr_in);
}
actual => panic!("unexpected tunnel state: {:?}", actual),
}
Expand Down
9 changes: 5 additions & 4 deletions test/test-manager/src/tests/ui.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::config::TEST_CONFIG;
use super::helpers;
use super::{Error, TestContext};
use mullvad_management_interface::{types, ManagementServiceClient};
use mullvad_management_interface::ManagementServiceClient;
use mullvad_types::relay_constraints::{RelayConstraints, RelaySettings};
use mullvad_types::relay_list::{Relay, RelayEndpointData};
use std::{
collections::BTreeMap,
fmt::Debug,
Expand Down Expand Up @@ -87,8 +88,8 @@ pub async fn test_ui_tunnel_settings(
) -> Result<(), Error> {
// tunnel-state.spec precondition: a single WireGuard relay should be selected
log::info!("Select WireGuard relay");
let entry = helpers::filter_relays(&mut mullvad_client, |relay: &types::Relay| {
relay.active && relay.endpoint_type == i32::from(types::relay::RelayType::Wireguard)
let entry = helpers::filter_relays(&mut mullvad_client, |relay: &Relay| {
relay.active && matches!(relay.endpoint_data, RelayEndpointData::Wireguard(_))
})
.await?
.pop()
Expand All @@ -109,7 +110,7 @@ pub async fn test_ui_tunnel_settings(
&["tunnel-state.spec"],
[
("HOSTNAME", entry.hostname.as_str()),
("IN_IP", entry.ipv4_addr_in.as_str()),
("IN_IP", &entry.ipv4_addr_in.to_string()),
(
"CONNECTION_CHECK_URL",
&format!("https://am.i.{}", TEST_CONFIG.mullvad_host),
Expand Down

0 comments on commit 0a82036

Please sign in to comment.