Skip to content

Commit

Permalink
support SO_USER_COOKIE on FreeBSD
Browse files Browse the repository at this point in the history
  • Loading branch information
zonyitoo committed Feb 8, 2022
1 parent 0d79278 commit 0e0edda
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 0 deletions.
5 changes: 5 additions & 0 deletions crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,9 @@ pub struct Config {
/// Set `SO_MARK` socket option for outbound sockets
#[cfg(any(target_os = "linux", target_os = "android"))]
pub outbound_fwmark: Option<u32>,
/// Set `SO_USER_COOKIE` socket option for outbound sockets
#[cfg(target_os = "freebsd")]
pub outbound_user_cookie: Option<u32>,
/// Set `SO_BINDTODEVICE` (Linux), `IP_BOUND_IF` (BSD), `IP_UNICAST_IF` (Windows) socket option for outbound sockets
pub outbound_bind_interface: Option<String>,
/// Outbound sockets will `bind` to this address
Expand Down Expand Up @@ -1146,6 +1149,8 @@ impl Config {

#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: None,
#[cfg(target_os = "freebsd")]
outbound_user_cookie: None,
outbound_bind_interface: None,
outbound_bind_addr: None,
#[cfg(target_os = "android")]
Expand Down
5 changes: 5 additions & 0 deletions crates/shadowsocks/src/net/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ pub struct ConnectOpts {
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fwmark: Option<u32>,

/// FreeBSD SO_USER_COOKIE
/// https://www.freebsd.org/cgi/man.cgi?query=setsockopt&sektion=2
#[cfg(target_os = "freebsd")]
pub user_cookie: Option<u32>,

/// An IPC unix socket path for sending file descriptors to call `VpnService.protect`
///
/// This is an [Android shadowsocks implementation](https://github.com/shadowsocks/shadowsocks-android) specific feature
Expand Down
18 changes: 18 additions & 0 deletions crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,24 @@ impl TcpStream {
SocketAddr::V6(..) => TcpSocket::new_v6()?,
};

// Set SO_USER_COOKIE for mark-based routing on FreeBSD
if let Some(user_cookie) = opts.user_cookie {
let ret = unsafe {
libc::setsockopt(
socket.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_USER_COOKIE,
&user_cookie as *const _ as *const _,
mem::size_of_val(&user_cookie) as libc::socklen_t,
)
};
if ret != 0 {
let err = io::Error::last_os_error();
error!("set SO_USER_COOKIE error: {}", err);
return Err(err);
}
}

set_common_sockopt_for_connect(addr, &socket, opts)?;

if !opts.tcp.fastopen {
Expand Down
18 changes: 18 additions & 0 deletions src/service/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
);
}

#[cfg(target_os = "freebsd")]
{
app = app.arg(
Arg::new("OUTBOUND_USER_COOKIE")
.long("outbound-user-cookie")
.takes_value(true)
.validator(validator::validate_u32)
.help("Set SO_USER_COOKIE option for outbound sockets"),
);
}

#[cfg(feature = "local-redir")]
{
if RedirType::tcp_default() != RedirType::NotSupported {
Expand Down Expand Up @@ -637,6 +648,13 @@ pub fn main(matches: &ArgMatches) {
Err(err) => err.exit(),
}

#[cfg(target_os = "freebsd")]
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Err(err) => err.exit(),
}

match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
Ok(iface) => config.outbound_bind_interface = Some(iface),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Expand Down
18 changes: 18 additions & 0 deletions src/service/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
);
}

#[cfg(target_os = "freebsd")]
{
app = app.arg(
Arg::new("OUTBOUND_USER_COOKIE")
.long("outbound-user-cookie")
.takes_value(true)
.validator(validator::validate_u32)
.help("Set SO_USER_COOKIE option for outbound sockets"),
);
}

#[cfg(feature = "multi-threaded")]
{
app = app
Expand Down Expand Up @@ -269,6 +280,13 @@ pub fn main(matches: &ArgMatches) {
Err(err) => err.exit(),
}

#[cfg(target_os = "freebsd")]
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Err(err) => err.exit(),
}

match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
Ok(iface) => config.outbound_bind_interface = Some(iface),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Expand Down
18 changes: 18 additions & 0 deletions src/service/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,17 @@ pub fn define_command_line_options(mut app: App<'_>) -> App<'_> {
);
}

#[cfg(target_os = "freebsd")]
{
app = app.arg(
Arg::new("OUTBOUND_USER_COOKIE")
.long("outbound-user-cookie")
.takes_value(true)
.validator(validator::validate_u32)
.help("Set SO_USER_COOKIE option for outbound sockets"),
);
}

#[cfg(feature = "multi-threaded")]
{
app = app
Expand Down Expand Up @@ -331,6 +342,13 @@ pub fn main(matches: &ArgMatches) {
Err(err) => err.exit(),
}

#[cfg(target_os = "freebsd")]
match matches.value_of_t::<u32>("OUTBOUND_USER_COOKIE") {
Ok(user_cookie) => config.outbound_user_cookie = Some(user_cookie),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Err(err) => err.exit(),
}

match matches.value_of_t::<String>("OUTBOUND_BIND_INTERFACE") {
Ok(iface) => config.outbound_bind_interface = Some(iface),
Err(ref err) if err.kind == ClapErrorKind::ArgumentNotFound => {}
Expand Down

0 comments on commit 0e0edda

Please sign in to comment.