Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix failing macOS DNS tests, and truncate log files in tests #5346

Merged
merged 6 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/desktop-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
Expand All @@ -30,6 +32,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
Expand All @@ -45,6 +49,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-tags: true
- name: Run end-to-end tests
shell: bash -ieo pipefail {0}
run: |
Expand Down
2 changes: 1 addition & 1 deletion test/ci-runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ echo "* Building test runner"
echo "**********************************"

# Clean up packages. Try to keep ones that match the versions we're testing
find "$PACKAGES_DIR/" -type f ! \( -name "*${OLD_APP_VERSION}_*" -o -name "*${OLD_APP_VERSION}.*" -o -name "*${NEW_APP_VERSION}*" \) -delete || true
find "$PACKAGES_DIR/" -type f ! \( -name "*${OLD_APP_VERSION}*" -o -name "*${commit}*" \) -delete || true

function build_test_runner {
local target=""
Expand Down
109 changes: 62 additions & 47 deletions test/test-manager/src/tests/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,51 +212,61 @@ async fn leak_test_dns(
// We should observe 2 outgoing packets to the whitelisted destination
// on port 53, and only inside the desired interface.

spoof_packets(
rpc,
Some(Interface::Tunnel),
tun_bind_addr,
whitelisted_dest,
);
spoof_packets(
rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
whitelisted_dest,
);

spoof_packets(
rpc,
Some(Interface::Tunnel),
tun_bind_addr,
blocked_dest_local,
);
spoof_packets(
rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
blocked_dest_local,
);

spoof_packets(
rpc,
Some(Interface::Tunnel),
tun_bind_addr,
blocked_dest_public,
);
spoof_packets(
rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
blocked_dest_public,
);
let rpc = rpc.clone();
let probes = tokio::spawn(async move {
tokio::join!(
// send to allowed dest
spoof_packets(
&rpc,
Some(Interface::Tunnel),
tun_bind_addr,
whitelisted_dest,
),
spoof_packets(
&rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
whitelisted_dest,
),
// send to blocked local dest
spoof_packets(
&rpc,
Some(Interface::Tunnel),
tun_bind_addr,
blocked_dest_local,
),
spoof_packets(
&rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
blocked_dest_local,
),
// send to blocked public dest
spoof_packets(
&rpc,
Some(Interface::Tunnel),
tun_bind_addr,
blocked_dest_public,
),
spoof_packets(
&rpc,
Some(Interface::NonTunnel),
guest_bind_addr,
blocked_dest_public,
),
)
});

if use_tun {
//
// Examine tunnel traffic
//

let tunnel_result = tunnel_monitor.wait().await.unwrap();

probes.abort();
let _ = probes.await;

assert!(
tunnel_result.packets.len() >= 2,
"expected at least 2 in-tunnel packets to allowed destination only"
Expand All @@ -282,6 +292,9 @@ async fn leak_test_dns(
} else {
let non_tunnel_result = non_tunnel_monitor.wait().await.unwrap();

probes.abort();
let _ = probes.await;

//
// Examine tunnel traffic
//
Expand Down Expand Up @@ -605,6 +618,7 @@ async fn run_dns_config_test<
);

handle.abort();
let _ = handle.await;

Ok(())
}
Expand Down Expand Up @@ -647,22 +661,23 @@ async fn connect_local_wg_relay(mullvad_client: &mut ManagementServiceClient) ->
Ok(())
}

fn spoof_packets(
async fn spoof_packets(
rpc: &ServiceClient,
interface: Option<Interface>,
bind_addr: SocketAddr,
dest: SocketAddr,
) {
let rpc1 = rpc.clone();
let rpc2 = rpc.clone();
tokio::spawn(async move {
let tcp_rpc = rpc.clone();
let tcp_send = async move {
log::debug!("sending to {}/tcp from {}", dest, bind_addr);
let _ = rpc1.send_tcp(interface, bind_addr, dest).await;
});
tokio::spawn(async move {
let _ = tcp_rpc.send_tcp(interface, bind_addr, dest).await;
};
let udp_rpc = rpc.clone();
let udp_send = async move {
log::debug!("sending to {}/udp from {}", dest, bind_addr);
let _ = rpc2.send_udp(interface, bind_addr, dest).await;
});
let _ = udp_rpc.send_udp(interface, bind_addr, dest).await;
};
let _ = tokio::join!(tcp_send, udp_send);
}

type ShouldContinue = bool;
Expand Down
70 changes: 45 additions & 25 deletions test/test-manager/src/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,33 +79,16 @@ pub async fn send_guest_probes(
)
.await;

let bind_addr = if let Some(interface) = interface {
SocketAddr::new(
rpc.get_interface_ip(interface)
.await
.expect("failed to obtain interface IP"),
0,
)
} else {
"0.0.0.0:0".parse().unwrap()
};

let send_handle = tokio::spawn(async move {
let tcp_rpc = rpc.clone();
let udp_rpc = rpc.clone();
tokio::spawn(async move {
let _ = tcp_rpc.send_tcp(interface, bind_addr, destination).await;
});
tokio::spawn(async move {
let _ = udp_rpc.send_udp(interface, bind_addr, destination).await;
});
ping_with_timeout(&rpc, destination.ip(), interface).await?;
Ok::<(), Error>(())
});
let send_handle = tokio::spawn(send_guest_probes_without_monitor(
rpc,
interface,
destination,
));

let monitor_result = pktmon.wait().await.unwrap();

send_handle.abort();
let _ = send_handle.await;

let mut result = ProbeResult::default();

Expand All @@ -127,6 +110,31 @@ pub async fn send_guest_probes(
Ok(result)
}

/// 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>,
destination: SocketAddr,
) {
let bind_addr = if let Some(interface) = interface {
SocketAddr::new(
rpc.get_interface_ip(interface)
.await
.expect("failed to obtain interface IP"),
0,
)
} else {
"0.0.0.0:0".parse().unwrap()
};

let tcp_rpc = rpc.clone();
let tcp_send = async move { tcp_rpc.send_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 icmp = async move { ping_with_timeout(&rpc, destination.ip(), interface).await };
let _ = tokio::join!(tcp_send, udp_send, icmp);
}

pub async fn ping_with_timeout(
rpc: &ServiceClient,
dest: IpAddr,
Expand Down Expand Up @@ -274,11 +282,23 @@ pub async fn geoip_lookup_with_retries(rpc: &ServiceClient) -> Result<AmIMullvad
}
}

pub struct AbortOnDrop<T>(pub tokio::task::JoinHandle<T>);
pub struct AbortOnDrop<T>(Option<tokio::task::JoinHandle<T>>);

impl<T> AbortOnDrop<T> {
pub fn new(inner: tokio::task::JoinHandle<T>) -> AbortOnDrop<T> {
AbortOnDrop(Some(inner))
}

pub fn into_inner(mut self) -> tokio::task::JoinHandle<T> {
self.0.take().unwrap()
}
}

impl<T> Drop for AbortOnDrop<T> {
fn drop(&mut self) {
self.0.abort();
if let Some(task) = self.0.take() {
task.abort();
}
}
}

Expand Down
19 changes: 12 additions & 7 deletions test/test-manager/src/tests/install.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::helpers::{get_package_desc, ping_with_timeout, AbortOnDrop};
use super::helpers::{get_package_desc, AbortOnDrop};
use super::{Error, TestContext};

use super::config::TEST_CONFIG;
Expand Down Expand Up @@ -48,7 +48,6 @@ pub async fn test_install_previous_app(_: TestContext, rpc: ServiceClient) -> Re
#[test_function(priority = -190)]
pub async fn test_upgrade_app(ctx: TestContext, rpc: ServiceClient) -> Result<(), Error> {
let inet_destination: SocketAddr = "1.1.1.1:1337".parse().unwrap();
let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();

// Verify that daemon is running
if rpc.mullvad_daemon_get_status().await? != ServiceStatus::Running {
Expand Down Expand Up @@ -122,11 +121,14 @@ pub async fn test_upgrade_app(ctx: TestContext, rpc: ServiceClient) -> Result<()
.await;

let ping_rpc = rpc.clone();
let abort_on_drop = AbortOnDrop(tokio::spawn(async move {
let probe_sender = AbortOnDrop::new(tokio::spawn(async move {
loop {
let _ = ping_rpc.send_tcp(None, bind_addr, inet_destination).await;
let _ = ping_rpc.send_udp(None, bind_addr, inet_destination).await;
let _ = ping_with_timeout(&ping_rpc, inet_destination.ip(), None).await;
super::helpers::send_guest_probes_without_monitor(
ping_rpc.clone(),
None,
inet_destination,
)
.await;
tokio::time::sleep(Duration::from_secs(1)).await;
}
}));
Expand All @@ -147,7 +149,10 @@ pub async fn test_upgrade_app(ctx: TestContext, rpc: ServiceClient) -> Result<()
//
// Check if any traffic was observed
//
drop(abort_on_drop);
let probe_sender = probe_sender.into_inner();
probe_sender.abort();
let _ = probe_sender.await;

let monitor_result = monitor.into_result().await.unwrap();
assert_eq!(
monitor_result.packets.len(),
Expand Down
Loading
Loading