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
|
use anyhow::{Context, anyhow};
use std::{
io::Write,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
time::Duration,
};
use crate::cli::Opt;
pub fn send_tcp(opt: &Opt, destination: SocketAddr) -> anyhow::Result<()> {
eprintln!("Leaking TCP packets to {destination}");
let (family, bind_address) = match &destination {
SocketAddr::V4(_) => (socket2::Domain::IPV4, IpAddr::from(Ipv4Addr::UNSPECIFIED)),
SocketAddr::V6(_) => (socket2::Domain::IPV6, IpAddr::from(Ipv6Addr::UNSPECIFIED)),
};
let bind_address: SocketAddr = SocketAddr::new(bind_address, 0);
let sock = socket2::Socket::new(family, socket2::Type::STREAM, Some(socket2::Protocol::TCP))
.context(anyhow!("Failed to create TCP socket"))?;
sock.bind(&socket2::SockAddr::from(bind_address))
.context(anyhow!("Failed to bind TCP socket to {bind_address}"))?;
let timeout = Duration::from_secs(opt.leak_timeout);
sock.set_write_timeout(Some(timeout))?;
sock.set_read_timeout(Some(timeout))?;
sock.connect_timeout(&socket2::SockAddr::from(destination), timeout)
.context(anyhow!("Failed to connect to {destination}"))?;
let mut stream = std::net::TcpStream::from(sock);
stream
.write_all(opt.payload.as_bytes())
.context(anyhow!("Failed to send message to {destination}"))?;
Ok(())
}
pub fn send_udp(opt: &Opt, destination: SocketAddr) -> Result<(), anyhow::Error> {
eprintln!("Leaking UDP packets to {destination}");
let (family, bind_address) = match &destination {
SocketAddr::V4(_) => (socket2::Domain::IPV4, IpAddr::from(Ipv4Addr::UNSPECIFIED)),
SocketAddr::V6(_) => (socket2::Domain::IPV6, IpAddr::from(Ipv6Addr::UNSPECIFIED)),
};
let bind_address: SocketAddr = SocketAddr::new(bind_address, 0);
let sock = socket2::Socket::new(family, socket2::Type::DGRAM, Some(socket2::Protocol::UDP))
.context("Failed to create UDP socket")?;
sock.bind(&socket2::SockAddr::from(bind_address))
.context(anyhow!("Failed to bind UDP socket to {bind_address}"))?;
let std_socket = std::net::UdpSocket::from(sock);
std_socket
.send_to(opt.payload.as_bytes(), destination)
.context(anyhow!("Failed to send message to {destination}"))?;
Ok(())
}
#[cfg(target_os = "windows")]
pub fn send_ping(opt: &Opt, destination: IpAddr) -> anyhow::Result<()> {
eprintln!("Leaking ICMP packets to {destination}");
ping::ping(
destination,
Some(Duration::from_secs(opt.leak_timeout)),
None,
None,
None,
None,
)?;
Ok(())
}
#[cfg(target_os = "macos")]
pub fn send_ping(opt: &Opt, destination: IpAddr) -> anyhow::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) -> anyhow::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().context(anyhow!(
"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(anyhow!("ping for destination {destination} failed"));
}
Ok(())
}
|