Skip to content

Commit 0e0edda

Browse files
committed
support SO_USER_COOKIE on FreeBSD
1 parent 0d79278 commit 0e0edda

File tree

6 files changed

+82
-0
lines changed

6 files changed

+82
-0
lines changed

crates/shadowsocks-service/src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,9 @@ pub struct Config {
10211021
/// Set `SO_MARK` socket option for outbound sockets
10221022
#[cfg(any(target_os = "linux", target_os = "android"))]
10231023
pub outbound_fwmark: Option<u32>,
1024+
/// Set `SO_USER_COOKIE` socket option for outbound sockets
1025+
#[cfg(target_os = "freebsd")]
1026+
pub outbound_user_cookie: Option<u32>,
10241027
/// Set `SO_BINDTODEVICE` (Linux), `IP_BOUND_IF` (BSD), `IP_UNICAST_IF` (Windows) socket option for outbound sockets
10251028
pub outbound_bind_interface: Option<String>,
10261029
/// Outbound sockets will `bind` to this address
@@ -1146,6 +1149,8 @@ impl Config {
11461149

11471150
#[cfg(any(target_os = "linux", target_os = "android"))]
11481151
outbound_fwmark: None,
1152+
#[cfg(target_os = "freebsd")]
1153+
outbound_user_cookie: None,
11491154
outbound_bind_interface: None,
11501155
outbound_bind_addr: None,
11511156
#[cfg(target_os = "android")]

crates/shadowsocks/src/net/option.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ pub struct ConnectOpts {
2929
#[cfg(any(target_os = "linux", target_os = "android"))]
3030
pub fwmark: Option<u32>,
3131

32+
/// FreeBSD SO_USER_COOKIE
33+
/// https://www.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2
34+
#[cfg(target_os = "freebsd")]
35+
pub user_cookie: Option<u32>,
36+
3237
/// An IPC unix socket path for sending file descriptors to call `VpnService.protect`
3338
///
3439
/// This is an [Android shadowsocks implementation](https://github.com/shadowsocks/shadowsocks-android) specific feature

crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@ impl TcpStream {
3535
SocketAddr::V6(..) => TcpSocket::new_v6()?,
3636
};
3737

38+
// Set SO_USER_COOKIE for mark-based routing on FreeBSD
39+
if let Some(user_cookie) = opts.user_cookie {
40+
let ret = unsafe {
41+
libc::setsockopt(
42+
socket.as_raw_fd(),
43+
libc::SOL_SOCKET,
44+
libc::SO_USER_COOKIE,
45+
&user_cookie as *const _ as *const _,
46+
mem::size_of_val(&user_cookie) as libc::socklen_t,
47+
)
48+
};
49+
if ret != 0 {
50+
let err = io::Error::last_os_error();
51+
error!("set SO_USER_COOKIE error: {}", err);
52+
return Err(err);
53+
}
54+
}
55+
3856
set_common_sockopt_for_connect(addr, &socket, opts)?;
3957

4058
if !opts.tcp.fastopen {

src/service/local.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
213213
);
214214
}
215215

216+
#[cfg(target_os = "freebsd")]
217+
{
218+
app = app.arg(
219+
Arg::new("OUTBOUND_USER_COOKIE")
220+
.long("outbound-user-cookie")
221+
.takes_value(true)
222+
.validator(validator::validate_u32)
223+
.help("Set SO_USER_COOKIE option for outbound sockets"),
224+
);
225+
}
226+
216227
#[cfg(feature = "local-redir")]
217228
{
218229
if RedirType::tcp_default() != RedirType::NotSupported {
@@ -637,6 +648,13 @@ pub fn main(matches: &ArgMatches) {
637648
Err(err) => err.exit(),
638649
}
639650

651+
#[cfg(target_os = "freebsd")]
652+
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
653+
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
654+
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
655+
Err(err) => err.exit(),
656+
}
657+
640658
match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
641659
Ok(iface) => config.outbound_bind_interface = Some(iface),
642660
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}

src/service/manager.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
176176
);
177177
}
178178

179+
#[cfg(target_os = "freebsd")]
180+
{
181+
app = app.arg(
182+
Arg::new("OUTBOUND_USER_COOKIE")
183+
.long("outbound-user-cookie")
184+
.takes_value(true)
185+
.validator(validator::validate_u32)
186+
.help("Set SO_USER_COOKIE option for outbound sockets"),
187+
);
188+
}
189+
179190
#[cfg(feature = "multi-threaded")]
180191
{
181192
app = app
@@ -269,6 +280,13 @@ pub fn main(matches: &ArgMatches) {
269280
Err(err) => err.exit(),
270281
}
271282

283+
#[cfg(target_os = "freebsd")]
284+
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
285+
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
286+
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
287+
Err(err) => err.exit(),
288+
}
289+
272290
match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
273291
Ok(iface) => config.outbound_bind_interface = Some(iface),
274292
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}

src/service/server.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
189189
);
190190
}
191191

192+
#[cfg(target_os = "freebsd")]
193+
{
194+
app = app.arg(
195+
Arg::new("OUTBOUND_USER_COOKIE")
196+
.long("outbound-user-cookie")
197+
.takes_value(true)
198+
.validator(validator::validate_u32)
199+
.help("Set SO_USER_COOKIE option for outbound sockets"),
200+
);
201+
}
202+
192203
#[cfg(feature = "multi-threaded")]
193204
{
194205
app = app
@@ -331,6 +342,13 @@ pub fn main(matches: &ArgMatches) {
331342
Err(err) => err.exit(),
332343
}
333344

345+
#[cfg(target_os = "freebsd")]
346+
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
347+
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
348+
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
349+
Err(err) => err.exit(),
350+
}
351+
334352
match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
335353
Ok(iface) => config.outbound_bind_interface = Some(iface),
336354
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}

0 commit comments

Comments
 (0)