Skip to content

Commit 28f8778

Browse files
Make payload of connection checker configurable
1 parent 909560f commit 28f8778

File tree

4 files changed

+48
-18
lines changed

4 files changed

+48
-18
lines changed

test/connection-checker/src/cli.rs

+4
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ pub struct Opt {
3333
/// Timeout for leak check network connections (in millis).
3434
#[clap(long, default_value = "1000")]
3535
pub leak_timeout: u64,
36+
37+
/// Junk data for each UDP and TCP packet
38+
#[clap(long, requires = "leak")]
39+
pub payload: Option<String>,
3640
}

test/connection-checker/src/net.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@ pub fn send_tcp(opt: &Opt, destination: SocketAddr) -> eyre::Result<()> {
3131
sock.connect_timeout(&socket2::SockAddr::from(destination), timeout)
3232
.wrap_err(eyre!("Failed to connect to {destination}"))?;
3333

34+
let payload = opt
35+
.payload
36+
.as_ref()
37+
.map(String::as_bytes)
38+
.unwrap_or(PAYLOAD);
3439
let mut stream = std::net::TcpStream::from(sock);
3540
stream
36-
.write_all(PAYLOAD)
41+
.write_all(payload)
3742
.wrap_err(eyre!("Failed to send message to {destination}"))?;
3843

3944
Ok(())
4045
}
4146

42-
pub fn send_udp(_opt: &Opt, destination: SocketAddr) -> Result<(), eyre::Error> {
47+
pub fn send_udp(opt: &Opt, destination: SocketAddr) -> Result<(), eyre::Error> {
4348
let bind_addr: SocketAddr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0);
4449

4550
eprintln!("Leaking UDP packets to {destination}");
@@ -54,11 +59,15 @@ pub fn send_udp(_opt: &Opt, destination: SocketAddr) -> Result<(), eyre::Error>
5459
sock.bind(&socket2::SockAddr::from(bind_addr))
5560
.wrap_err(eyre!("Failed to bind UDP socket to {bind_addr}"))?;
5661

57-
//log::debug!("Send message from {bind_addr} to {destination}/UDP");
62+
let payload = opt
63+
.payload
64+
.as_ref()
65+
.map(String::as_bytes)
66+
.unwrap_or(PAYLOAD);
5867

5968
let std_socket = std::net::UdpSocket::from(sock);
6069
std_socket
61-
.send_to(PAYLOAD, destination)
70+
.send_to(payload, destination)
6271
.wrap_err(eyre!("Failed to send message to {destination}"))?;
6372

6473
Ok(())

test/test-manager/src/tests/helpers.rs

+24-8
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,9 @@ pub struct ConnChecker {
715715

716716
/// Whether the process should be split when spawned. Needed on Linux.
717717
split: bool,
718+
719+
/// Some arbitrary payload
720+
payload: Option<String>,
718721
}
719722

720723
pub struct ConnCheckerHandle<'a> {
@@ -756,37 +759,50 @@ impl ConnChecker {
756759
leak_destination,
757760
split: false,
758761
executable_path,
762+
payload: None,
759763
}
760764
}
761765

766+
/// Set a custom magic payload that the connection checker binary should use when leak-testing.
767+
pub fn payload(&mut self, payload: impl Into<String>) {
768+
self.payload = Some(payload.into())
769+
}
770+
762771
/// Spawn the connecton checker process and return a handle to it.
763772
///
764773
/// Dropping the handle will stop the process.
765774
/// **NOTE**: The handle must be dropped from a tokio runtime context.
766775
pub async fn spawn(&mut self) -> anyhow::Result<ConnCheckerHandle<'_>> {
767776
log::debug!("spawning connection checker");
768777

769-
let opts = SpawnOpts {
770-
attach_stdin: true,
771-
attach_stdout: true,
772-
args: [
778+
let opts = {
779+
let mut args = [
773780
"--interactive",
774781
"--timeout",
775782
&AM_I_MULLVAD_TIMEOUT_MS.to_string(),
776783
// try to leak traffic to LEAK_DESTINATION
777784
"--leak",
778785
&self.leak_destination.to_string(),
779-
//TODO(markus): Remove
780-
//&LEAK_DESTINATION.to_string(),
781786
"--leak-timeout",
782787
&LEAK_TIMEOUT_MS.to_string(),
783788
"--leak-tcp",
784789
"--leak-udp",
785790
"--leak-icmp",
786791
]
787792
.map(String::from)
788-
.to_vec(),
789-
..SpawnOpts::new(&self.executable_path)
793+
.to_vec();
794+
795+
if let Some(payload) = &self.payload {
796+
args.push("--payload".to_string());
797+
args.push(payload.clone());
798+
};
799+
800+
SpawnOpts {
801+
attach_stdin: true,
802+
attach_stdout: true,
803+
args,
804+
..SpawnOpts::new(&self.executable_path)
805+
}
790806
};
791807

792808
let pid = self.rpc.spawn(opts).await?;

test/test-manager/src/tests/tunnel.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -847,30 +847,31 @@ pub async fn test_mul_02_002(
847847

848848
// Step 2 - Start a network monitor snooping the outbound network interface for some
849849
// identifiable payload
850-
// FIXME: This needs to be kept in sync with the magic payload string defined in `connection_cheker::net`.
851-
// An easy fix would be to make the payload for `ConnCheck` configurable.
852-
let unique_identifier = b"Hello there!";
850+
let unique_identifier = "Hello there!";
853851
let identify_rogue_packet = move |packet: &ParsedPacket| {
854852
packet
855853
.payload
856854
.windows(unique_identifier.len())
857-
.any(|window| window == unique_identifier)
855+
.any(|window| window == unique_identifier.as_bytes())
858856
};
859857
let rogue_packet_monitor =
860858
start_packet_monitor(identify_rogue_packet, MonitorOptions::default()).await;
861859

862-
// Step 3 - Start the rogue program which will try to leak traffic to the chosen relay endpoint
860+
// Step 3 - Start the rogue program which will try to leak the unique identifier payload
861+
// to the chosen relay endpoint
863862
let mut checker = ConnChecker::new(rpc.clone(), mullvad_client.clone(), target_endpoint);
863+
checker.payload(unique_identifier);
864864
let mut conn_artist = checker.spawn().await?;
865865
// Before proceeding, assert that the method of detecting identifiable packets work.
866866
conn_artist.check_connection().await?;
867-
let monitor_result = rogue_packet_monitor.into_result().await.unwrap();
867+
let monitor_result = rogue_packet_monitor.into_result().await?;
868868

869869
log::info!("Checking that the identifiable payload was detectable without encryption");
870870
ensure!(
871871
!monitor_result.packets.is_empty(),
872872
"Did not observe rogue packets! The method seems to be broken"
873873
);
874+
log::info!("The identifiable payload was detected! (that's good)");
874875

875876
// Step 4 - Finally, connect to a tunnel and assert that no outgoing traffic contains the
876877
// payload in plain text.

0 commit comments

Comments
 (0)