blob: 0863662c67a7e0739218907a1dfcac77929c3bbc (
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
|
//! A TCP stream with a low MSS set. This prevents incorrectly configured MTU from causing
//! fragmentation/packet loss. This is only supported on non-Windows targets.
//!
//! On windows this solution does not work. So on Windows we instead temporarily lower the MTU
//! while negotiating the ephemeral peer. This code lives in `talpid-wireguard/src/ephemeral.rs`
//! These two solutions to the same problem should probably be refactored to end up closer
//! to each other.
use std::io;
use std::net::SocketAddr;
use tokio::net::TcpSocket as StdTcpSocket;
use tokio::net::TcpStream;
#[cfg(unix)]
mod sys {
use super::*;
use nix::sys::socket::{setsockopt, sockopt::TcpMaxSeg};
use std::os::fd::AsFd;
/// MTU to set on the tunnel config client socket. We want a low value to prevent fragmentation.
/// Especially on Android, we've found that the real MTU is often lower than the default MTU, and
/// we cannot lower it further. This causes the outer packets to be dropped. Also, MTU detection
/// will likely occur after the PQ handshake, so we cannot assume that the MTU is already
/// correctly configured.
/// This is set to the lowest possible IPv4 MTU.
const CONFIG_CLIENT_MTU: u16 = 576;
pub struct TcpSocket {
socket: StdTcpSocket,
}
impl TcpSocket {
pub fn new() -> io::Result<Self> {
let socket = StdTcpSocket::new_v4()?;
try_set_tcp_sock_mtu(&socket);
Ok(Self { socket })
}
pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
self.socket.connect(addr).await
}
}
fn try_set_tcp_sock_mtu(sock: &impl AsFd) {
let mss = u32::from(desired_mss());
log::debug!("Tunnel config TCP socket MSS: {mss}");
if let Err(e) = setsockopt(sock, TcpMaxSeg, &mss) {
log::error!("Failed to set MSS on tunnel config TCP socket: {e}");
};
}
const fn desired_mss() -> u16 {
const IPV4_HEADER_SIZE: u16 = 20;
const MAX_TCP_HEADER_SIZE: u16 = 60;
let mtu = CONFIG_CLIENT_MTU.saturating_sub(IPV4_HEADER_SIZE);
mtu.saturating_sub(MAX_TCP_HEADER_SIZE)
}
}
#[cfg(windows)]
mod sys {
use super::*;
pub struct TcpSocket {
socket: StdTcpSocket,
}
impl TcpSocket {
pub fn new() -> io::Result<Self> {
Ok(Self {
socket: StdTcpSocket::new_v4()?,
})
}
pub async fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> {
self.socket.connect(addr).await
}
}
}
pub use sys::*;
|