Skip to content

Commit

Permalink
Fix test_split_tunnel
Browse files Browse the repository at this point in the history
Raw ICMP isn't allowed on all platforms for unprivileged users.
Instead:

* Use SOCK_DGRAM, where possible
* Use 'ping' command, since SOCK_DGRAM isn't allowed on some older
  Linux distros.
  • Loading branch information
dlon committed Aug 29, 2024
1 parent f1d9dd3 commit 31637ab
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 17 deletions.
8 changes: 4 additions & 4 deletions test/connection-checker/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub struct Opt {
#[clap(short, long)]
pub interactive: bool,

/// Timeout for network connection to am.i.mullvad (in millis).
#[clap(short, long, default_value = "3000")]
/// Timeout for network connection to am.i.mullvad (in seconds).
#[clap(short, long, default_value = "3")]
pub timeout: u64,

/// Try to send some junk data over TCP to <leak>.
Expand All @@ -30,8 +30,8 @@ pub struct Opt {
#[clap(long)]
pub leak: Option<SocketAddr>,

/// Timeout for leak check network connections (in millis).
#[clap(long, default_value = "1000")]
/// Timeout for leak check network connections (in seconds).
#[clap(long, default_value = "1")]
pub leak_timeout: u64,

/// Junk data for each UDP and TCP packet
Expand Down
2 changes: 1 addition & 1 deletion test/connection-checker/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn am_i_mullvad(opt: &Opt) -> eyre::Result<bool> {
let client = Client::new();
let response: Response = client
.get(url)
.timeout(Duration::from_millis(opt.timeout))
.timeout(Duration::from_secs(opt.timeout))
.send()
.and_then(|r| r.json())
.wrap_err_with(|| eyre!("Failed to GET {url}"))?;
Expand Down
58 changes: 55 additions & 3 deletions test/connection-checker/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn send_tcp(opt: &Opt, destination: SocketAddr) -> eyre::Result<()> {
sock.bind(&socket2::SockAddr::from(bind_addr))
.wrap_err(eyre!("Failed to bind TCP socket to {bind_addr}"))?;

let timeout = Duration::from_millis(opt.leak_timeout);
let timeout = Duration::from_secs(opt.leak_timeout);
sock.set_write_timeout(Some(timeout))?;
sock.set_read_timeout(Some(timeout))?;

Expand Down Expand Up @@ -60,12 +60,13 @@ pub fn send_udp(opt: &Opt, destination: SocketAddr) -> Result<(), eyre::Error> {
Ok(())
}

#[cfg(target_os = "windows")]
pub fn send_ping(opt: &Opt, destination: IpAddr) -> eyre::Result<()> {
eprintln!("Leaking IMCP packets to {destination}");
eprintln!("Leaking ICMP packets to {destination}");

ping::ping(
destination,
Some(Duration::from_millis(opt.leak_timeout)),
Some(Duration::from_secs(opt.leak_timeout)),
None,
None,
None,
Expand All @@ -74,3 +75,54 @@ pub fn send_ping(opt: &Opt, destination: IpAddr) -> eyre::Result<()> {

Ok(())
}

#[cfg(target_os = "macos")]
pub fn send_ping(opt: &Opt, destination: IpAddr) -> eyre::Result<()> {
eprintln!("Leaking ICMP packets to {destination}");

// On macOS, use dgramsock (SOCK_DGRAM) instead of the default sock type (SOCK_RAW),
// so that we don't need root privileges. Naturally, this does not work for Windows.
ping::dgramsock::ping(
destination,
Some(Duration::from_secs(opt.leak_timeout)),
None,
None,
None,
None,
)?;

Ok(())
}

// Older Linux distributions don't allow unprivileged users to send ICMP packets, even for
// SOCK_DGRAM sockets. We use the ping command (which has capabilities/setuid set) to get around
// that.
#[cfg(target_os = "linux")]
pub fn send_ping(opt: &Opt, destination: IpAddr) -> eyre::Result<()> {
eprintln!("Leaking ICMP packets to {destination}");

let mut cmd = std::process::Command::new("ping");

let timeout_sec = opt.leak_timeout.to_string();

cmd.args(["-c", "1", "-W", &timeout_sec, &destination.to_string()]);

let output = cmd.output().wrap_err(eyre!(
"Failed to execute ping for destination {destination}"
))?;

if !output.status.success() {
eprintln!(
"ping stdout:\n\n{}",
std::str::from_utf8(&output.stdout).unwrap_or("invalid utf8")
);
eprintln!(
"ping stderr:\n\n{}",
std::str::from_utf8(&output.stderr).unwrap_or("invalid utf8")
);

return Err(eyre!("ping for destination {destination} failed"));
}

Ok(())
}
3 changes: 3 additions & 0 deletions test/scripts/ssh-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ function install_packages_apt {
echo "Installing required apt packages"
apt update
apt install -yf xvfb wireguard-tools curl
if ! which ping &>/dev/null; then
apt install -yf iputils-ping
fi
curl -fsSL https://get.docker.com | sh
}

Expand Down
18 changes: 9 additions & 9 deletions test/test-manager/src/tests/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ pub const THROTTLE_RETRY_DELAY: Duration = Duration::from_secs(120);
const CHECKER_FILENAME_WINDOWS: &str = "connection-checker.exe";
const CHECKER_FILENAME_UNIX: &str = "connection-checker";

const AM_I_MULLVAD_TIMEOUT_MS: u64 = 10000;
const LEAK_TIMEOUT_MS: u64 = 500;
const AM_I_MULLVAD_TIMEOUT_S: u64 = 10;
const LEAK_TIMEOUT_S: u64 = 1;

/// Timeout of [ConnCheckerHandle::check_connection].
const CONN_CHECKER_TIMEOUT: Duration = Duration::from_millis(
AM_I_MULLVAD_TIMEOUT_MS // https://am.i.mullvad.net timeout
+ LEAK_TIMEOUT_MS // leak-tcp timeout
+ LEAK_TIMEOUT_MS // leak-icmp timeout
+ 1000, // plus some extra grace time
const CONN_CHECKER_TIMEOUT: Duration = Duration::from_secs(
AM_I_MULLVAD_TIMEOUT_S // https://am.i.mullvad.net timeout
+ LEAK_TIMEOUT_S // leak-tcp timeout
+ LEAK_TIMEOUT_S // leak-icmp timeout
+ 1, // plus some extra grace time
);

#[macro_export]
Expand Down Expand Up @@ -957,12 +957,12 @@ impl ConnChecker {
let mut args = [
"--interactive",
"--timeout",
&AM_I_MULLVAD_TIMEOUT_MS.to_string(),
&AM_I_MULLVAD_TIMEOUT_S.to_string(),
// try to leak traffic to LEAK_DESTINATION
"--leak",
&self.leak_destination.to_string(),
"--leak-timeout",
&LEAK_TIMEOUT_MS.to_string(),
&LEAK_TIMEOUT_S.to_string(),
"--leak-tcp",
"--leak-udp",
"--leak-icmp",
Expand Down

0 comments on commit 31637ab

Please sign in to comment.