forked from Mygod/slipstream-rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.rs
More file actions
124 lines (116 loc) · 4.24 KB
/
Copy pathsetup.rs
File metadata and controls
124 lines (116 loc) · 4.24 KB
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
use crate::error::ClientError;
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::net::{Ipv6Addr, SocketAddr, SocketAddrV6};
#[cfg(target_os = "android")]
use std::os::unix::io::AsRawFd;
use tokio::net::{lookup_host, TcpListener as TokioTcpListener, UdpSocket as TokioUdpSocket};
use tracing::warn;
pub(crate) fn compute_mtu(domain_len: usize) -> Result<u32, ClientError> {
if domain_len >= 240 {
return Err(ClientError::new(
"Domain name is too long for DNS transport",
));
}
let mtu = ((240.0 - domain_len as f64) / 1.6) as u32;
if mtu == 0 {
return Err(ClientError::new(
"MTU computed to zero; check domain length",
));
}
Ok(mtu)
}
pub(crate) async fn bind_udp_socket(android_vpn: bool) -> Result<TokioUdpSocket, ClientError> {
let bind_addr = SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0));
bind_udp_socket_addr(bind_addr, android_vpn)
}
pub(crate) async fn bind_tcp_listener(
host: &str,
port: u16,
) -> Result<TokioTcpListener, ClientError> {
let addrs: Vec<SocketAddr> = lookup_host((host, port)).await.map_err(map_io)?.collect();
if addrs.is_empty() {
return Err(ClientError::new(format!(
"No addresses resolved for {}:{}",
host, port
)));
}
let mut last_err = None;
for addr in addrs {
match bind_tcp_listener_addr(addr) {
Ok(listener) => return Ok(listener),
Err(err) => last_err = Some(err),
}
}
Err(last_err.unwrap_or_else(|| {
ClientError::new(format!("Failed to bind TCP listener on {}:{}", host, port))
}))
}
fn bind_tcp_listener_addr(addr: SocketAddr) -> Result<TokioTcpListener, ClientError> {
let domain = match addr {
SocketAddr::V4(_) => Domain::IPV4,
SocketAddr::V6(_) => Domain::IPV6,
};
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP)).map_err(map_io)?;
#[cfg(not(windows))]
if let Err(err) = socket.set_reuse_address(true) {
warn!("Failed to enable SO_REUSEADDR on {}: {}", addr, err);
}
if let SocketAddr::V6(_) = addr {
if let Err(err) = socket.set_only_v6(false) {
warn!(
"Failed to enable dual-stack TCP listener on {}: {}",
addr, err
);
}
}
let sock_addr = SockAddr::from(addr);
socket.bind(&sock_addr).map_err(map_io)?;
socket.listen(1024).map_err(map_io)?;
socket.set_nonblocking(true).map_err(map_io)?;
let std_listener: std::net::TcpListener = socket.into();
TokioTcpListener::from_std(std_listener).map_err(map_io)
}
fn bind_udp_socket_addr(addr: SocketAddr, android_vpn: bool) -> Result<TokioUdpSocket, ClientError> {
let domain = match addr {
SocketAddr::V4(_) => Domain::IPV4,
SocketAddr::V6(_) => Domain::IPV6,
};
let socket = Socket::new(domain, Type::DGRAM, Some(Protocol::UDP)).map_err(map_io)?;
if let SocketAddr::V6(_) = addr {
if let Err(err) = socket.set_only_v6(false) {
warn!(
"Failed to enable dual-stack UDP socket on {}: {}",
addr, err
);
}
}
let sock_addr = SockAddr::from(addr);
socket.bind(&sock_addr).map_err(map_io)?;
// Protect socket from VPN routing on Android
#[cfg(target_os = "android")]
if android_vpn {
let fd = socket.as_raw_fd();
match crate::android::protect_socket(fd) {
Ok(true) => {
tracing::info!("UDP socket protected from VPN routing");
}
Ok(false) => {
tracing::debug!("VPN protection not available (protect_path not found)");
}
Err(err) => {
return Err(ClientError::new(format!(
"Failed to protect UDP socket: {}",
err
)));
}
}
}
#[cfg(not(target_os = "android"))]
let _ = android_vpn; // Suppress unused warning on non-Android
socket.set_nonblocking(true).map_err(map_io)?;
let std_socket: std::net::UdpSocket = socket.into();
TokioUdpSocket::from_std(std_socket).map_err(map_io)
}
pub(crate) fn map_io(err: std::io::Error) -> ClientError {
ClientError::new(err.to_string())
}