Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow IP fragmentation for outbound UDP sockets #1790

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,8 @@ Example configuration:
"outbound_bind_interface": "eth1",
// Outbound socket bind() to this IP (choose a specific interface)
"outbound_bind_addr": "11.22.33.44",
// Outbound UDP socket allows IP fragmentation (default false)
"outbound_udp_allow_fragmentation": false

// Balancer customization
"balancer": {
Expand Down
23 changes: 23 additions & 0 deletions crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ struct SSConfig {
#[serde(skip_serializing_if = "Option::is_none")]
outbound_bind_interface: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
outbound_udp_allow_fragmentation: Option<bool>,

#[serde(skip_serializing_if = "Option::is_none")]
security: Option<SSSecurityConfig>,

Expand Down Expand Up @@ -401,6 +404,9 @@ struct SSServerExtConfig {

#[serde(skip_serializing_if = "Option::is_none")]
outbound_bind_interface: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
outbound_udp_allow_fragmentation: Option<bool>,
}

#[cfg(feature = "local-online-config")]
Expand Down Expand Up @@ -1240,6 +1246,7 @@ pub struct ServerInstanceConfig {
pub outbound_fwmark: Option<u32>,
pub outbound_bind_addr: Option<IpAddr>,
pub outbound_bind_interface: Option<String>,
pub outbound_udp_allow_fragmentation: Option<bool>,
}

impl ServerInstanceConfig {
Expand All @@ -1252,6 +1259,7 @@ impl ServerInstanceConfig {
outbound_fwmark: None,
outbound_bind_addr: None,
outbound_bind_interface: None,
outbound_udp_allow_fragmentation: None,
}
}
}
Expand Down Expand Up @@ -1336,6 +1344,8 @@ pub struct Config {
pub outbound_bind_interface: Option<String>,
/// Outbound sockets will `bind` to this address
pub outbound_bind_addr: Option<IpAddr>,
/// Outbound UDP sockets allow IP fragmentation
pub outbound_udp_allow_fragmentation: bool,
/// Path to protect callback unix address, only for Android
#[cfg(target_os = "android")]
pub outbound_vpn_protect_path: Option<PathBuf>,
Expand Down Expand Up @@ -1480,6 +1490,7 @@ impl Config {
outbound_user_cookie: None,
outbound_bind_interface: None,
outbound_bind_addr: None,
outbound_udp_allow_fragmentation: false,
#[cfg(target_os = "android")]
outbound_vpn_protect_path: None,

Expand Down Expand Up @@ -1999,6 +2010,7 @@ impl Config {
outbound_fwmark: config.outbound_fwmark,
outbound_bind_addr,
outbound_bind_interface: config.outbound_bind_interface.clone(),
outbound_udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,
};

nconfig.server.push(server_instance);
Expand Down Expand Up @@ -2192,6 +2204,7 @@ impl Config {
outbound_fwmark: config.outbound_fwmark,
outbound_bind_addr,
outbound_bind_interface: config.outbound_bind_interface.clone(),
outbound_udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,
};

if let Some(acl_path) = svr.acl {
Expand Down Expand Up @@ -2222,6 +2235,10 @@ impl Config {
server_instance.outbound_bind_interface = Some(outbound_bind_interface.clone());
}

if let Some(outbound_udp_allow_fragmentation) = svr.outbound_udp_allow_fragmentation {
server_instance.outbound_udp_allow_fragmentation = Some(outbound_udp_allow_fragmentation);
}

nconfig.server.push(server_instance);
}
}
Expand Down Expand Up @@ -2387,6 +2404,10 @@ impl Config {
// Bind device / interface
nconfig.outbound_bind_interface = config.outbound_bind_interface;

if let Some(b) = config.outbound_udp_allow_fragmentation {
nconfig.outbound_udp_allow_fragmentation = b;
}

// Security
if let Some(sec) = config.security {
if let Some(replay_attack) = sec.replay_attack {
Expand Down Expand Up @@ -3045,6 +3066,7 @@ impl fmt::Display for Config {
outbound_fwmark: inst.outbound_fwmark,
outbound_bind_addr: inst.outbound_bind_addr,
outbound_bind_interface: inst.outbound_bind_interface.clone(),
outbound_udp_allow_fragmentation: inst.outbound_udp_allow_fragmentation,
});
}

Expand Down Expand Up @@ -3149,6 +3171,7 @@ impl fmt::Display for Config {

jconf.outbound_bind_addr = self.outbound_bind_addr.map(|i| i.to_string());
jconf.outbound_bind_interface.clone_from(&self.outbound_bind_interface);
jconf.outbound_udp_allow_fragmentation = Some(self.outbound_udp_allow_fragmentation);

// Security
if self.security.replay_attack.policy != ReplayAttackPolicy::default() {
Expand Down
1 change: 1 addition & 0 deletions crates/shadowsocks-service/src/manager/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ impl Manager {
outbound_fwmark: None,
outbound_bind_addr: None,
outbound_bind_interface: None,
outbound_udp_allow_fragmentation: None,
};

let mut config = Config::new(ConfigType::Server);
Expand Down
5 changes: 5 additions & 0 deletions crates/shadowsocks-service/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub async fn run(config: Config) -> io::Result<()> {

bind_local_addr: config.outbound_bind_addr.map(|ip| SocketAddr::new(ip, 0)),
bind_interface: config.outbound_bind_interface,
udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,

..Default::default()
};
Expand Down Expand Up @@ -120,6 +121,10 @@ pub async fn run(config: Config) -> io::Result<()> {
connect_opts.bind_interface = Some(bind_interface);
}

if let Some(udp_allow_fragmentation) = inst.outbound_udp_allow_fragmentation {
connect_opts.udp_allow_fragmentation = udp_allow_fragmentation;
}

server_builder.set_connect_opts(connect_opts);
server_builder.set_accept_opts(accept_opts);

Expand Down
3 changes: 3 additions & 0 deletions crates/shadowsocks/src/net/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ pub struct ConnectOpts {
/// Outbound socket binds to interface
pub bind_interface: Option<String>,

/// Outbound UDP socket allows IP fragmentation
pub udp_allow_fragmentation: bool,
zonyitoo marked this conversation as resolved.
Show resolved Hide resolved

/// TCP options
pub tcp: TcpSocketOpts,

Expand Down
6 changes: 4 additions & 2 deletions crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, _config: &ConnectO
UdpSocket::from_std(socket.into())?
};

if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
if ! config.udp_allow_fragmentation {
zonyitoo marked this conversation as resolved.
Show resolved Hide resolved
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
}

Ok(socket)
Expand Down
6 changes: 4 additions & 2 deletions crates/shadowsocks/src/net/sys/unix/bsd/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp
UdpSocket::from_std(socket.into())?
};

if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
if ! config.udp_allow_fragmentation {
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
}

// Set IP_BOUND_IF for BSD-like
Expand Down
6 changes: 4 additions & 2 deletions crates/shadowsocks/src/net/sys/unix/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp
UdpSocket::from_std(socket.into())?
};

if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
if ! config.udp_allow_fragmentation {
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
}

// Any traffic except localhost should be protected
Expand Down
7 changes: 5 additions & 2 deletions crates/shadowsocks/src/net/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,12 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, opts: &ConnectOpts
socket.set_nonblocking(true)?;
let socket = UdpSocket::from_std(socket.into())?;

if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
if ! opts.udp_allow_fragmentation {
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
}

disable_connection_reset(&socket)?;

Ok(socket)
Expand Down
Loading