shadowsocks/net/option.rs
1//! Options for connecting to remote server
2
3use std::{net::SocketAddr, time::Duration};
4
5/// Options for connecting to TCP remote server
6#[derive(Debug, Clone, Default)]
7pub struct TcpSocketOpts {
8 /// TCP socket's `SO_SNDBUF`
9 pub send_buffer_size: Option<u32>,
10
11 /// TCP socket's `SO_RCVBUF`
12 pub recv_buffer_size: Option<u32>,
13
14 /// `TCP_NODELAY`
15 pub nodelay: bool,
16
17 /// `TCP_FASTOPEN`, enables TFO
18 pub fastopen: bool,
19
20 /// `SO_KEEPALIVE` and sets `TCP_KEEPIDLE`, `TCP_KEEPINTVL` and `TCP_KEEPCNT` respectively,
21 /// enables keep-alive messages on connection-oriented sockets
22 pub keepalive: Option<Duration>,
23
24 /// Enable Multipath-TCP (mptcp)
25 /// https://en.wikipedia.org/wiki/Multipath_TCP
26 ///
27 /// Currently only supported on
28 /// - macOS (iOS, watchOS, ...) with Client Support only.
29 /// - Linux (>5.19)
30 pub mptcp: bool,
31}
32
33/// Options for UDP server
34#[derive(Debug, Clone, Default)]
35pub struct UdpSocketOpts {
36 /// Maximum Transmission Unit (MTU) for UDP socket `recv`
37 ///
38 /// NOTE: MTU includes IP header, UDP header, UDP payload
39 pub mtu: Option<usize>,
40
41 /// Outbound UDP socket allows IP fragmentation
42 pub allow_fragmentation: bool,
43}
44
45/// Options for connecting to remote server
46#[derive(Debug, Clone, Default)]
47pub struct ConnectOpts {
48 /// Linux mark based routing, going to set by `setsockopt` with `SO_MARK` option
49 #[cfg(any(target_os = "linux", target_os = "android"))]
50 pub fwmark: Option<u32>,
51
52 /// FreeBSD SO_USER_COOKIE
53 /// https://www.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2
54 #[cfg(target_os = "freebsd")]
55 pub user_cookie: Option<u32>,
56
57 /// An IPC unix socket path for sending file descriptors to call `VpnService.protect`
58 ///
59 /// This is an [Android shadowsocks implementation](https://github.com/shadowsocks/shadowsocks-android) specific feature
60 #[cfg(target_os = "android")]
61 pub vpn_protect_path: Option<std::path::PathBuf>,
62 /// A customizable socket protect implementation for Android for calling `VpnService.protect(fd)`
63 ///
64 /// see [`ConnectOpts::set_vpn_socket_protect`]
65 #[cfg(target_os = "android")]
66 pub vpn_socket_protect: Option<std::sync::Arc<Box<dyn android::SocketProtect + Send + Sync>>>,
67
68 /// Outbound socket binds to this IP address, mostly for choosing network interfaces
69 ///
70 /// It only affects sockets that trying to connect to addresses with the same family
71 pub bind_local_addr: Option<SocketAddr>,
72
73 /// Outbound socket binds to interface
74 pub bind_interface: Option<String>,
75
76 /// TCP options
77 pub tcp: TcpSocketOpts,
78
79 /// UDP options
80 pub udp: UdpSocketOpts,
81}
82
83/// Inbound connection options
84#[derive(Clone, Debug, Default)]
85pub struct AcceptOpts {
86 /// TCP options
87 pub tcp: TcpSocketOpts,
88
89 /// UDP options
90 pub udp: UdpSocketOpts,
91
92 /// Enable IPV6_V6ONLY option for socket
93 pub ipv6_only: bool,
94}
95
96#[cfg(target_os = "android")]
97impl ConnectOpts {
98 /// Set `vpn_protect_path` for Android VPNService.protect implementation
99 ///
100 /// Example:
101 ///
102 /// ```rust
103 /// // Sync function for calling `VpnService.protect(fd)`
104 /// opts.set_vpn_socket_protect(|fd| {
105 /// // Your implementation here
106 /// // For example, using `jni` to call Android's VpnService.protect(fd)
107 /// Ok(())
108 /// });
109 /// ```
110 pub fn set_vpn_socket_protect<F>(&mut self, f: F)
111 where
112 F: android::MakeSocketProtect + Send + Sync + 'static,
113 F::SocketProtectType: android::SocketProtect + Send + Sync + 'static,
114 {
115 self.vpn_socket_protect = Some(std::sync::Arc::new(Box::new(f.make_socket_protect())));
116 }
117}
118
119/// Android specific features
120#[cfg(target_os = "android")]
121pub mod android {
122 use sealed::sealed;
123 use std::{fmt, io, os::unix::io::RawFd};
124
125 /// Android VPN socket protect implemetation
126 #[sealed]
127 pub trait SocketProtect {
128 /// Protects the socket file descriptor by calling `VpnService.protect(fd)`
129 fn protect(&self, fd: RawFd) -> io::Result<()>;
130 }
131
132 impl fmt::Debug for dyn SocketProtect + Send + Sync {
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 f.debug_struct("SocketProtect").finish_non_exhaustive()
135 }
136 }
137
138 /// Creating an instance of `SocketProtect`
139 #[sealed]
140 pub trait MakeSocketProtect {
141 type SocketProtectType: SocketProtect;
142
143 /// Creates an instance of `SocketProtect`
144 fn make_socket_protect(self) -> Self::SocketProtectType;
145 }
146
147 /// A function that implements `SocketProtect` trait
148 pub struct SocketProtectFn<F> {
149 f: F,
150 }
151
152 #[sealed]
153 impl<F> SocketProtect for SocketProtectFn<F>
154 where
155 F: Fn(RawFd) -> io::Result<()> + Send + Sync + 'static,
156 {
157 fn protect(&self, fd: RawFd) -> io::Result<()> {
158 (self.f)(fd)
159 }
160 }
161
162 #[sealed]
163 impl<F> MakeSocketProtect for F
164 where
165 F: Fn(RawFd) -> io::Result<()> + Send + Sync + 'static,
166 {
167 type SocketProtectType = SocketProtectFn<F>;
168
169 fn make_socket_protect(self) -> Self::SocketProtectType {
170 SocketProtectFn { f: self }
171 }
172 }
173}