Allow IP fragmentation for outbound UDP sockets

This commit is contained in:
Tom Ryan
2024-11-29 12:01:09 +11:00
parent 1e6f28cd6f
commit 6da076116f
9 changed files with 51 additions and 8 deletions

View File

@@ -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": {

View File

@@ -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>,
@@ -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")]
@@ -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 {
@@ -1252,6 +1259,7 @@ impl ServerInstanceConfig {
outbound_fwmark: None,
outbound_bind_addr: None,
outbound_bind_interface: None,
outbound_udp_allow_fragmentation: None,
}
}
}
@@ -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>,
@@ -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,
@@ -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);
@@ -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 {
@@ -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);
}
}
@@ -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 {
@@ -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,
});
}
@@ -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() {

View File

@@ -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);

View File

@@ -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()
};
@@ -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);

View File

@@ -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,
/// TCP options
pub tcp: TcpSocketOpts,

View File

@@ -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 {
if let Err(err) = set_disable_ip_fragmentation(af, &socket) {
warn!("failed to disable IP fragmentation, error: {}", err);
}
}
Ok(socket)

View File

@@ -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

View File

@@ -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

View File

@@ -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)