Skip to content

Commit 6da0761

Browse files
committed
Allow IP fragmentation for outbound UDP sockets
1 parent 1e6f28c commit 6da0761

File tree

9 files changed

+51
-8
lines changed

9 files changed

+51
-8
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ Example configuration:
815815
"outbound_bind_interface": "eth1",
816816
// Outbound socket bind() to this IP (choose a specific interface)
817817
"outbound_bind_addr": "11.22.33.44",
818+
// Outbound UDP socket allows IP fragmentation (default false)
819+
"outbound_udp_allow_fragmentation": false
818820

819821
// Balancer customization
820822
"balancer": {

crates/shadowsocks-service/src/config.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ struct SSConfig {
215215
#[serde(skip_serializing_if = "Option::is_none")]
216216
outbound_bind_interface: Option<String>,
217217

218+
#[serde(skip_serializing_if = "Option::is_none")]
219+
outbound_udp_allow_fragmentation: Option<bool>,
220+
218221
#[serde(skip_serializing_if = "Option::is_none")]
219222
security: Option<SSSecurityConfig>,
220223

@@ -401,6 +404,9 @@ struct SSServerExtConfig {
401404

402405
#[serde(skip_serializing_if = "Option::is_none")]
403406
outbound_bind_interface: Option<String>,
407+
408+
#[serde(skip_serializing_if = "Option::is_none")]
409+
outbound_udp_allow_fragmentation: Option<bool>,
404410
}
405411

406412
#[cfg(feature = "local-online-config")]
@@ -1240,6 +1246,7 @@ pub struct ServerInstanceConfig {
12401246
pub outbound_fwmark: Option<u32>,
12411247
pub outbound_bind_addr: Option<IpAddr>,
12421248
pub outbound_bind_interface: Option<String>,
1249+
pub outbound_udp_allow_fragmentation: Option<bool>,
12431250
}
12441251

12451252
impl ServerInstanceConfig {
@@ -1252,6 +1259,7 @@ impl ServerInstanceConfig {
12521259
outbound_fwmark: None,
12531260
outbound_bind_addr: None,
12541261
outbound_bind_interface: None,
1262+
outbound_udp_allow_fragmentation: None,
12551263
}
12561264
}
12571265
}
@@ -1336,6 +1344,8 @@ pub struct Config {
13361344
pub outbound_bind_interface: Option<String>,
13371345
/// Outbound sockets will `bind` to this address
13381346
pub outbound_bind_addr: Option<IpAddr>,
1347+
/// Outbound UDP sockets allow IP fragmentation
1348+
pub outbound_udp_allow_fragmentation: bool,
13391349
/// Path to protect callback unix address, only for Android
13401350
#[cfg(target_os = "android")]
13411351
pub outbound_vpn_protect_path: Option<PathBuf>,
@@ -1480,6 +1490,7 @@ impl Config {
14801490
outbound_user_cookie: None,
14811491
outbound_bind_interface: None,
14821492
outbound_bind_addr: None,
1493+
outbound_udp_allow_fragmentation: false,
14831494
#[cfg(target_os = "android")]
14841495
outbound_vpn_protect_path: None,
14851496

@@ -1999,6 +2010,7 @@ impl Config {
19992010
outbound_fwmark: config.outbound_fwmark,
20002011
outbound_bind_addr,
20012012
outbound_bind_interface: config.outbound_bind_interface.clone(),
2013+
outbound_udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,
20022014
};
20032015

20042016
nconfig.server.push(server_instance);
@@ -2192,6 +2204,7 @@ impl Config {
21922204
outbound_fwmark: config.outbound_fwmark,
21932205
outbound_bind_addr,
21942206
outbound_bind_interface: config.outbound_bind_interface.clone(),
2207+
outbound_udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,
21952208
};
21962209

21972210
if let Some(acl_path) = svr.acl {
@@ -2222,6 +2235,10 @@ impl Config {
22222235
server_instance.outbound_bind_interface = Some(outbound_bind_interface.clone());
22232236
}
22242237

2238+
if let Some(outbound_udp_allow_fragmentation) = svr.outbound_udp_allow_fragmentation {
2239+
server_instance.outbound_udp_allow_fragmentation = Some(outbound_udp_allow_fragmentation);
2240+
}
2241+
22252242
nconfig.server.push(server_instance);
22262243
}
22272244
}
@@ -2387,6 +2404,10 @@ impl Config {
23872404
// Bind device / interface
23882405
nconfig.outbound_bind_interface = config.outbound_bind_interface;
23892406

2407+
if let Some(b) = config.outbound_udp_allow_fragmentation {
2408+
nconfig.outbound_udp_allow_fragmentation = b;
2409+
}
2410+
23902411
// Security
23912412
if let Some(sec) = config.security {
23922413
if let Some(replay_attack) = sec.replay_attack {
@@ -3045,6 +3066,7 @@ impl fmt::Display for Config {
30453066
outbound_fwmark: inst.outbound_fwmark,
30463067
outbound_bind_addr: inst.outbound_bind_addr,
30473068
outbound_bind_interface: inst.outbound_bind_interface.clone(),
3069+
outbound_udp_allow_fragmentation: inst.outbound_udp_allow_fragmentation,
30483070
});
30493071
}
30503072

@@ -3149,6 +3171,7 @@ impl fmt::Display for Config {
31493171

31503172
jconf.outbound_bind_addr = self.outbound_bind_addr.map(|i| i.to_string());
31513173
jconf.outbound_bind_interface.clone_from(&self.outbound_bind_interface);
3174+
jconf.outbound_udp_allow_fragmentation = Some(self.outbound_udp_allow_fragmentation);
31523175

31533176
// Security
31543177
if self.security.replay_attack.policy != ReplayAttackPolicy::default() {

crates/shadowsocks-service/src/manager/server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ impl Manager {
388388
outbound_fwmark: None,
389389
outbound_bind_addr: None,
390390
outbound_bind_interface: None,
391+
outbound_udp_allow_fragmentation: None,
391392
};
392393

393394
let mut config = Config::new(ConfigType::Server);

crates/shadowsocks-service/src/server/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub async fn run(config: Config) -> io::Result<()> {
6666

6767
bind_local_addr: config.outbound_bind_addr.map(|ip| SocketAddr::new(ip, 0)),
6868
bind_interface: config.outbound_bind_interface,
69+
udp_allow_fragmentation: config.outbound_udp_allow_fragmentation,
6970

7071
..Default::default()
7172
};
@@ -120,6 +121,10 @@ pub async fn run(config: Config) -> io::Result<()> {
120121
connect_opts.bind_interface = Some(bind_interface);
121122
}
122123

124+
if let Some(udp_allow_fragmentation) = inst.outbound_udp_allow_fragmentation {
125+
connect_opts.udp_allow_fragmentation = udp_allow_fragmentation;
126+
}
127+
123128
server_builder.set_connect_opts(connect_opts);
124129
server_builder.set_accept_opts(accept_opts);
125130

crates/shadowsocks/src/net/option.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ pub struct ConnectOpts {
6565
/// Outbound socket binds to interface
6666
pub bind_interface: Option<String>,
6767

68+
/// Outbound UDP socket allows IP fragmentation
69+
pub udp_allow_fragmentation: bool,
70+
6871
/// TCP options
6972
pub tcp: TcpSocketOpts,
7073

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, _config: &ConnectO
251251
UdpSocket::from_std(socket.into())?
252252
};
253253

254-
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
255-
warn!("failed to disable IP fragmentation, error: {}", err);
254+
if ! config.udp_allow_fragmentation {
255+
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
256+
warn!("failed to disable IP fragmentation, error: {}", err);
257+
}
256258
}
257259

258260
Ok(socket)

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp
379379
UdpSocket::from_std(socket.into())?
380380
};
381381

382-
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
383-
warn!("failed to disable IP fragmentation, error: {}", err);
382+
if ! config.udp_allow_fragmentation {
383+
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
384+
warn!("failed to disable IP fragmentation, error: {}", err);
385+
}
384386
}
385387

386388
// Set IP_BOUND_IF for BSD-like

crates/shadowsocks/src/net/sys/unix/linux/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp
310310
UdpSocket::from_std(socket.into())?
311311
};
312312

313-
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
314-
warn!("failed to disable IP fragmentation, error: {}", err);
313+
if ! config.udp_allow_fragmentation {
314+
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
315+
warn!("failed to disable IP fragmentation, error: {}", err);
316+
}
315317
}
316318

317319
// Any traffic except localhost should be protected

crates/shadowsocks/src/net/sys/windows/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -498,9 +498,12 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, opts: &ConnectOpts
498498
socket.set_nonblocking(true)?;
499499
let socket = UdpSocket::from_std(socket.into())?;
500500

501-
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
502-
warn!("failed to disable IP fragmentation, error: {}", err);
501+
if ! opts.udp_allow_fragmentation {
502+
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
503+
warn!("failed to disable IP fragmentation, error: {}", err);
504+
}
503505
}
506+
504507
disable_connection_reset(&socket)?;
505508

506509
Ok(socket)

0 commit comments

Comments
 (0)