summaryrefslogtreecommitdiffhomepage
path: root/test/test-manager/src/tests/windows.rs
blob: 09238259697b27c8e55b3ed3a7c868b37b4f2b16 (plain)
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Windows-specific tests.

use anyhow::{Context, ensure};
use mullvad_management_interface::MullvadProxyClient;
use mullvad_types::states::TunnelState;
use test_macro::test_function;
use test_rpc::ServiceClient;

use crate::tests::helpers::{geoip_lookup_with_retries, wait_for_tunnel_state};

use super::TestContext;

/// Test that, on a failed upgrade, blocking firewall rules are cleared on a reboot.
#[test_function(target_os = "windows")]
async fn test_clearing_blocked_state_on_failed_upgrade(
    _: TestContext,
    mut rpc: ServiceClient,
    mut mullvad_client: MullvadProxyClient,
) -> anyhow::Result<()> {
    // Assert that the below settings are disabled. If they are not,
    // then blocking firewall rules *will* persist after a reboot.
    {
        let settings = mullvad_client.get_settings().await?;
        ensure!(
            !settings.lockdown_mode,
            "Block when disconnected should be disabled"
        );
        ensure!(!settings.auto_connect, "Auto connect should be disabled");
    }

    log::info!("Connecting to tunnel to enter secured state");
    // This is necessary to ensure that the firewall rules are applied
    // Note that we do not need to wait for the tunnel to be fully connected
    mullvad_client
        .connect_tunnel()
        .await
        .context("failed to begin connecting")?;
    log::info!("Waiting for tunnel state to be Connected or Error");
    wait_for_tunnel_state(mullvad_client.clone(), |state| {
        matches!(
            state,
            TunnelState::Connected { .. } | TunnelState::Error(..)
        )
    })
    .await?;
    log::info!("Preparing daemon for restart (simulate failed upgrade)");
    mullvad_client
        .prepare_restart_v2(false)
        .await
        .context("Failed to prepare restart")?;

    // Simulate that the daemon has been uninstalled, by disabling the system service.
    // We cannot actually uninstall the daemon here, because it would remove the blocking firewall rules,
    // regardless of having called `prepare_restart_v2`.
    log::info!("Disabling Mullvad daemon system service");
    rpc.disable_mullvad_daemon().await?;
    rpc.stop_mullvad_daemon().await?;

    // Make sure that blocking firewall rules are active - there should be no leaks (yet) 💦❌
    log::info!("Checking that blocking firewall rules are active...");
    let geoip = geoip_lookup_with_retries(&rpc).await;
    ensure!(
        geoip.is_err(),
        "Device is leaking with geo IP '{:?}'- blocking rules have not applied properly",
        geoip.unwrap()
    );
    // Reboot - we expect desperate users to take this measure
    log::info!("Rebooting device...");
    rpc.reboot().await?;
    // The conn check should now fail - the firewall filters should have been removed at this point 💦💦💦
    log::info!("Checking connectivity after reboot (should be online, but not secured)");
    let mullvad_exit_ip = geoip_lookup_with_retries(&rpc)
        .await
        .context("Device is offline after reboot")?
        .mullvad_exit_ip;
    ensure!(!mullvad_exit_ip, "Should *not* be a Mullvad Exit IP");

    Ok(())
}

/// Test that, on a failed upgrade when `Auto-connect` is enabled, blocking firewall rules are *not* cleared on a reboot.
#[test_function(target_os = "windows")]
async fn test_not_clearing_blocked_state_on_failed_upgrade_with_lockdown_mode(
    _: TestContext,
    mut rpc: ServiceClient,
    mut mullvad_client: MullvadProxyClient,
) -> anyhow::Result<()> {
    // Make sure that lockdown mode is enabled.
    // If it is not, then blocking firewall rules *will not* persist after a reboot.
    {
        mullvad_client.set_lockdown_mode(true).await?;
        let settings = mullvad_client.get_settings().await?;
        ensure!(
            settings.lockdown_mode,
            "Block when disconnected should be enabled"
        );
        ensure!(!settings.auto_connect, "Auto connect should be disabled");
    }

    log::info!("Waiting for tunnel state to be Disconnected with lockdown enabled");
    wait_for_tunnel_state(mullvad_client.clone(), |state| {
        matches!(
            state,
            TunnelState::Disconnected { locked_down, .. }  if *locked_down
        )
    })
    .await?;
    log::info!("Preparing daemon for restart (simulate failed upgrade)");
    mullvad_client
        .prepare_restart_v2(false)
        .await
        .context("Failed to prepare restart")?;

    // Simulate that the daemon has been uninstalled, by disabling the system service.
    // We cannot actually uninstall the daemon here, because it would remove the blocking firewall rules,
    // regardless of having called `prepare_restart_v2`.
    log::info!("Disabling Mullvad daemon system service");
    rpc.disable_mullvad_daemon().await?;
    rpc.stop_mullvad_daemon().await?;

    // Make sure that blocking firewall rules are active - there should be no leaks 💦❌
    log::info!("Checking that blocking firewall rules are active...");
    let blocked = geoip_lookup_with_retries(&rpc).await.is_err();
    ensure!(
        blocked,
        "Device is leaking - blocking rules have not applied properly"
    );
    // Reboot - we expect desperate users to take this measure
    log::info!("Rebooting device...");
    rpc.reboot().await?;

    // The conn check should now fail - the firewall filters should *not* have been removed at this point 💦❌
    log::info!("Checking connectivity after reboot (should be blocked)");
    let blocked = geoip_lookup_with_retries(&rpc).await.is_err();
    ensure!(
        blocked,
        "Device is leaking - blocking rules have not applied properly"
    );

    Ok(())
}