From 9276cf88af5455582f0595e363e54cfb27ddb353 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Mon, 18 Apr 2022 23:45:16 +0800 Subject: [PATCH] UDP IPv6 outbound socket should disable IPV6_V6ONLY --- crates/shadowsocks/src/net/sys/mod.rs | 4 ++-- .../shadowsocks/src/net/sys/unix/bsd/freebsd.rs | 15 +++++++++++++-- crates/shadowsocks/src/net/sys/unix/bsd/macos.rs | 15 +++++++++++++-- crates/shadowsocks/src/net/sys/unix/linux/mod.rs | 15 +++++++++++++-- crates/shadowsocks/src/net/sys/windows/mod.rs | 12 +++++++++++- 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/crates/shadowsocks/src/net/sys/mod.rs b/crates/shadowsocks/src/net/sys/mod.rs index 4e6a32787487..0f5ac079a8b4 100644 --- a/crates/shadowsocks/src/net/sys/mod.rs +++ b/crates/shadowsocks/src/net/sys/mod.rs @@ -100,7 +100,7 @@ fn socket_bind_dual_stack_inner(socket: &Socket, addr: &SocketAddr, ipv6_only: b socket.bind(&saddr)?; } else { if let Err(err) = socket.set_only_v6(false) { - warn!("failed to set IPV6_V6ONLY: false for listener, error: {}", err); + warn!("failed to set IPV6_V6ONLY: false for socket, error: {}", err); // This is not a fatal error, just warn and skip } @@ -115,7 +115,7 @@ fn socket_bind_dual_stack_inner(socket: &Socket, addr: &SocketAddr, ipv6_only: b ); if let Err(err) = socket.set_only_v6(true) { - warn!("failed to set IPV6_V6ONLY: true for listener, error: {}", err); + warn!("failed to set IPV6_V6ONLY: true for socket, error: {}", err); // This is not a fatal error, just warn and skip } diff --git a/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs b/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs index 7abbbcfddb8f..245c8bc94d45 100644 --- a/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs +++ b/crates/shadowsocks/src/net/sys/unix/bsd/freebsd.rs @@ -9,6 +9,7 @@ use std::{ use log::{error, warn}; use pin_project::pin_project; +use socket2::{Domain, Protocol, Socket, Type}; use tokio::{ io::{AsyncRead, AsyncWrite, ReadBuf}, net::{TcpSocket, TcpStream as TokioTcpStream, UdpSocket}, @@ -16,7 +17,7 @@ use tokio::{ use tokio_tfo::TfoStream; use crate::net::{ - sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect}, + sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect, socket_bind_dual_stack}, AddrFamily, ConnectOpts, }; @@ -223,7 +224,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; - let socket = UdpSocket::bind(bind_addr).await?; + let socket = if af != AddrFamily::Ipv6 { + UdpSocket::bind(bind_addr).await? + } else { + let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, &bind_addr, false)?; + + // UdpSocket::from_std requires socket to be non-blocked + socket.set_nonblocking(true)?; + UdpSocket::from_std(socket.into())? + }; + if let Err(err) = set_disable_ip_fragmentation(af, &socket) { warn!("failed to disable IP fragmentation, error: {}", err); } diff --git a/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs b/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs index 2c78a7f5ee86..36ad3099f4a1 100644 --- a/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs +++ b/crates/shadowsocks/src/net/sys/unix/bsd/macos.rs @@ -10,6 +10,7 @@ use std::{ use log::{error, warn}; use pin_project::pin_project; +use socket2::{Domain, Protocol, Socket, Type}; use tokio::{ io::{AsyncRead, AsyncWrite, ReadBuf}, net::{TcpSocket, TcpStream as TokioTcpStream, UdpSocket}, @@ -17,7 +18,7 @@ use tokio::{ use tokio_tfo::TfoStream; use crate::net::{ - sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect}, + sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect, socket_bind_dual_stack}, AddrFamily, ConnectOpts, }; @@ -250,7 +251,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; - let socket = UdpSocket::bind(bind_addr).await?; + let socket = if af != AddrFamily::Ipv6 { + UdpSocket::bind(bind_addr).await? + } else { + let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, &bind_addr, false)?; + + // UdpSocket::from_std requires socket to be non-blocked + socket.set_nonblocking(true)?; + UdpSocket::from_std(socket.into())? + }; + if let Err(err) = set_disable_ip_fragmentation(af, &socket) { warn!("failed to disable IP fragmentation, error: {}", err); } diff --git a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs index cd487412604f..4c6969510968 100644 --- a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs +++ b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs @@ -10,6 +10,7 @@ use std::{ use cfg_if::cfg_if; use log::{error, warn}; use pin_project::pin_project; +use socket2::{Domain, Protocol, Socket, Type}; use tokio::{ io::{AsyncRead, AsyncWrite, ReadBuf}, net::{TcpSocket, TcpStream as TokioTcpStream, UdpSocket}, @@ -17,7 +18,7 @@ use tokio::{ use tokio_tfo::TfoStream; use crate::net::{ - sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect}, + sys::{set_common_sockopt_after_connect, set_common_sockopt_for_connect, socket_bind_dual_stack}, AddrFamily, ConnectOpts, }; @@ -245,7 +246,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, config: &ConnectOpts) -> (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; - let socket = UdpSocket::bind(bind_addr).await?; + let socket = if af != AddrFamily::Ipv6 { + UdpSocket::bind(bind_addr).await? + } else { + let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, &bind_addr, false)?; + + // UdpSocket::from_std requires socket to be non-blocked + socket.set_nonblocking(true)?; + UdpSocket::from_std(socket.into())? + }; + if let Err(err) = set_disable_ip_fragmentation(af, &socket) { warn!("failed to disable IP fragmentation, error: {}", err); } diff --git a/crates/shadowsocks/src/net/sys/windows/mod.rs b/crates/shadowsocks/src/net/sys/windows/mod.rs index f4489ce35a9c..f87cacc7302f 100644 --- a/crates/shadowsocks/src/net/sys/windows/mod.rs +++ b/crates/shadowsocks/src/net/sys/windows/mod.rs @@ -368,7 +368,17 @@ pub async fn create_outbound_udp_socket(af: AddrFamily, opts: &ConnectOpts) -> i (AddrFamily::Ipv6, ..) => SocketAddr::new(Ipv6Addr::UNSPECIFIED.into(), 0), }; - let socket = UdpSocket::bind(bind_addr).await?; + let socket = if af != AddrFamily::Ipv6 { + UdpSocket::bind(addr).await? + } else { + let socket = Socket::new(Domain::for_address(bind_addr), Type::DGRAM, Some(Protocol::UDP))?; + socket_bind_dual_stack(&socket, &bind_addr, false)?; + + // UdpSocket::from_std requires socket to be non-blocked + socket.set_nonblocking(true)?; + UdpSocket::from_std(socket.into())? + }; + if let Err(err) = set_disable_ip_fragmentation(af, &socket) { warn!("failed to disable IP fragmentation, error: {}", err); }