1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
use anyhow::Context;
use mullvad_management_interface::MullvadProxyClient;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use test_macro::test_function;
use test_rpc::{ServiceClient, meta::OsVersion};
use super::{
TestContext,
helpers::{self, ConnChecker},
ui,
};
const LEAK_DESTINATION: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), 1337);
/// Test that split tunneling works by asserting the following:
/// - Splitting a process shouldn't do anything if tunnel is not connected.
/// - A split process should never push traffic through the tunnel.
/// - Splitting/unsplitting should work regardless if process is running.
#[test_function]
pub async fn test_split_tunnel(
_ctx: TestContext,
rpc: ServiceClient,
mut mullvad_client: MullvadProxyClient,
) -> anyhow::Result<()> {
// Skip test on macOS 12, since the feature is unsupported
if is_macos_12_or_lower(&rpc).await? {
return Ok(());
}
let mut checker = ConnChecker::new(rpc.clone(), mullvad_client.clone(), LEAK_DESTINATION);
// Test that program is behaving when we are disconnected
(checker.spawn().await?.assert_insecure().await)
.with_context(|| "Test disconnected and unsplit")?;
checker.split().await?;
(checker.spawn().await?.assert_insecure().await)
.with_context(|| "Test disconnected and split")?;
checker.unsplit().await?;
// Test that program is behaving being split/unsplit while running and we are disconnected
let mut handle = checker.spawn().await?;
handle.split().await?;
(handle.assert_insecure().await)
.with_context(|| "Test disconnected and being split while running")?;
handle.unsplit().await?;
(handle.assert_insecure().await)
.with_context(|| "Test disconnected and being unsplit while running")?;
drop(handle);
helpers::connect_and_wait(&mut mullvad_client).await?;
// Test running an unsplit program
checker
.spawn()
.await?
.assert_secure()
.await
.with_context(|| "Test connected and unsplit")?;
// Test running a split program
checker.split().await?;
checker
.spawn()
.await?
.assert_insecure()
.await
.with_context(|| "Test connected and split")?;
checker.unsplit().await?;
// Test splitting and unsplitting a program while it's running
let mut handle = checker.spawn().await?;
(handle.assert_secure().await).with_context(|| "Test connected and unsplit (again)")?;
handle.split().await?;
(handle.assert_insecure().await)
.with_context(|| "Test connected and being split while running")?;
handle.unsplit().await?;
(handle.assert_secure().await)
.with_context(|| "Test connected and being unsplit while running")?;
Ok(())
}
/// Test that split tunneling works by asserting the following:
/// - Splitting a process shouldn't do anything if tunnel is not connected.
/// - A split process should never push traffic through the tunnel.
/// - Splitting/unsplitting should work regardless if process is running.
#[test_function(target_os = "macos")]
pub async fn test_split_tunnel_ui(
_ctx: TestContext,
rpc: ServiceClient,
_: MullvadProxyClient,
) -> anyhow::Result<()> {
// Skip test on macOS 12, since the feature is unsupported
if is_macos_12_or_lower(&rpc).await? {
return Ok(());
}
let ui_result = ui::run_test(&rpc, &["macos-split-tunneling.spec"])
.await
.unwrap();
assert!(ui_result.success());
Ok(())
}
async fn is_macos_12_or_lower(rpc: &ServiceClient) -> anyhow::Result<bool> {
match rpc.get_os_version().await.context("Detect OS version")? {
OsVersion::Macos(version) if version.major <= 12 => Ok(true),
_ => Ok(false),
}
}
|