mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 08:14:07 +00:00
fix: allow fragmentation for inbound UDP replies
This commit is contained in:
@@ -68,6 +68,7 @@ pub async fn run(config: Config) -> io::Result<()> {
|
||||
accept_opts.tcp.keepalive = config.keep_alive.or(Some(SERVER_DEFAULT_KEEPALIVE_TIMEOUT));
|
||||
accept_opts.tcp.mptcp = config.mptcp;
|
||||
accept_opts.udp.mtu = config.udp_mtu;
|
||||
accept_opts.udp.allow_fragmentation = config.outbound_udp_allow_fragmentation;
|
||||
|
||||
if let Some(resolver) =
|
||||
build_dns_resolver(config.dns, config.ipv6_first, config.dns_cache_size, &connect_opts).await
|
||||
|
||||
@@ -100,6 +100,7 @@ pub async fn run(config: Config) -> io::Result<()> {
|
||||
accept_opts.tcp.fastopen = config.fast_open;
|
||||
accept_opts.tcp.keepalive = config.keep_alive.or(Some(SERVER_DEFAULT_KEEPALIVE_TIMEOUT));
|
||||
accept_opts.tcp.mptcp = config.mptcp;
|
||||
accept_opts.udp.allow_fragmentation = config.outbound_udp_allow_fragmentation;
|
||||
accept_opts.udp.mtu = config.udp_mtu;
|
||||
|
||||
let resolver = build_dns_resolver(config.dns, config.ipv6_first, config.dns_cache_size, &connect_opts)
|
||||
@@ -118,7 +119,7 @@ pub async fn run(config: Config) -> io::Result<()> {
|
||||
}
|
||||
|
||||
let mut connect_opts = connect_opts.clone();
|
||||
let accept_opts = accept_opts.clone();
|
||||
let mut accept_opts = accept_opts.clone();
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
if let Some(fwmark) = inst.outbound_fwmark {
|
||||
@@ -140,6 +141,7 @@ pub async fn run(config: Config) -> io::Result<()> {
|
||||
|
||||
if let Some(udp_allow_fragmentation) = inst.outbound_udp_allow_fragmentation {
|
||||
connect_opts.udp.allow_fragmentation = udp_allow_fragmentation;
|
||||
accept_opts.udp.allow_fragmentation = udp_allow_fragmentation;
|
||||
}
|
||||
|
||||
let has_outbound_proxies = !inst.outbound_proxy.is_empty() || !config.outbound_proxy.is_empty();
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct UdpSocketOpts {
|
||||
/// NOTE: MTU includes IP header, UDP header, UDP payload
|
||||
pub mtu: Option<usize>,
|
||||
|
||||
/// Outbound UDP socket allows IP fragmentation
|
||||
/// UDP socket allows IP fragmentation
|
||||
pub allow_fragmentation: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,11 @@ cfg_if! {
|
||||
pub mod uds;
|
||||
|
||||
/// Create a `UdpSocket` binded to `addr`
|
||||
pub async fn create_inbound_udp_socket(addr: &SocketAddr, ipv6_only: bool) -> io::Result<UdpSocket> {
|
||||
pub async fn create_inbound_udp_socket(
|
||||
addr: &SocketAddr,
|
||||
ipv6_only: bool,
|
||||
allow_fragmentation: bool,
|
||||
) -> io::Result<UdpSocket> {
|
||||
let set_dual_stack = is_dual_stack_addr(addr);
|
||||
|
||||
let socket = if !set_dual_stack {
|
||||
@@ -48,7 +52,7 @@ pub async fn create_inbound_udp_socket(addr: &SocketAddr, ipv6_only: bool) -> io
|
||||
SocketAddr::V4(..) => AddrFamily::Ipv4,
|
||||
SocketAddr::V6(..) => AddrFamily::Ipv6,
|
||||
};
|
||||
if let Err(err) = set_disable_ip_fragmentation(addr_family, &socket) {
|
||||
if !allow_fragmentation && let Err(err) = set_disable_ip_fragmentation(addr_family, &socket) {
|
||||
warn!("failed to disable IP fragmentation, error: {}", err);
|
||||
}
|
||||
|
||||
|
||||
@@ -431,7 +431,11 @@ pub fn set_disable_ip_fragmentation<S: AsRawSocket>(af: AddrFamily, socket: &S)
|
||||
/// Create a `UdpSocket` binded to `addr`
|
||||
///
|
||||
/// It also disables `WSAECONNRESET` for UDP socket
|
||||
pub async fn create_inbound_udp_socket(addr: &SocketAddr, ipv6_only: bool) -> io::Result<UdpSocket> {
|
||||
pub async fn create_inbound_udp_socket(
|
||||
addr: &SocketAddr,
|
||||
ipv6_only: bool,
|
||||
allow_fragmentation: bool,
|
||||
) -> io::Result<UdpSocket> {
|
||||
let set_dual_stack = is_dual_stack_addr(addr);
|
||||
|
||||
let socket = if !set_dual_stack {
|
||||
@@ -449,7 +453,7 @@ pub async fn create_inbound_udp_socket(addr: &SocketAddr, ipv6_only: bool) -> io
|
||||
SocketAddr::V4(..) => AddrFamily::Ipv4,
|
||||
SocketAddr::V6(..) => AddrFamily::Ipv6,
|
||||
};
|
||||
if let Err(err) = set_disable_ip_fragmentation(addr_family, &socket) {
|
||||
if !allow_fragmentation && let Err(err) = set_disable_ip_fragmentation(addr_family, &socket) {
|
||||
warn!("failed to disable IP fragmentation, error: {}", err);
|
||||
}
|
||||
disable_connection_reset(&socket)?;
|
||||
|
||||
@@ -189,7 +189,7 @@ impl UdpSocket {
|
||||
|
||||
/// Binds to a specific address (inbound)
|
||||
pub async fn listen_with_opts(addr: &SocketAddr, opts: AcceptOpts) -> io::Result<Self> {
|
||||
let socket = create_inbound_udp_socket(addr, opts.ipv6_only).await?;
|
||||
let socket = create_inbound_udp_socket(addr, opts.ipv6_only, opts.udp.allow_fragmentation).await?;
|
||||
Ok(Self {
|
||||
socket,
|
||||
mtu: opts.udp.mtu,
|
||||
|
||||
@@ -8,10 +8,45 @@ use shadowsocks::{
|
||||
config::{ServerConfig, ServerType},
|
||||
context::{Context, SharedContext},
|
||||
crypto::CipherKind,
|
||||
net::UdpSocket as ShadowUdpSocket,
|
||||
net::{AcceptOpts, UdpSocket as ShadowUdpSocket},
|
||||
relay::{socks5::Address, udprelay::ProxySocket},
|
||||
};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn ipv4_mtu_discovery(socket: &ShadowUdpSocket) -> i32 {
|
||||
use std::{mem, os::fd::AsRawFd};
|
||||
|
||||
let mut value = 0;
|
||||
let mut value_len = mem::size_of_val(&value) as libc::socklen_t;
|
||||
let result = unsafe {
|
||||
libc::getsockopt(
|
||||
socket.as_raw_fd(),
|
||||
libc::IPPROTO_IP,
|
||||
libc::IP_MTU_DISCOVER,
|
||||
&mut value as *mut _ as *mut libc::c_void,
|
||||
&mut value_len,
|
||||
)
|
||||
};
|
||||
assert_eq!(result, 0);
|
||||
value
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[tokio::test]
|
||||
async fn inbound_udp_fragmentation_option() {
|
||||
let addr = "127.0.0.1:0".parse().unwrap();
|
||||
|
||||
let socket = ShadowUdpSocket::listen_with_opts(&addr, AcceptOpts::default())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(ipv4_mtu_discovery(&socket), libc::IP_PMTUDISC_DO);
|
||||
|
||||
let mut opts = AcceptOpts::default();
|
||||
opts.udp.allow_fragmentation = true;
|
||||
let socket = ShadowUdpSocket::listen_with_opts(&addr, opts).await.unwrap();
|
||||
assert_ne!(ipv4_mtu_discovery(&socket), libc::IP_PMTUDISC_DO);
|
||||
}
|
||||
|
||||
async fn handle_udp_server_client(
|
||||
peer_addr: SocketAddr,
|
||||
remote_addr: Address,
|
||||
|
||||
Reference in New Issue
Block a user