From 5c59fba42796eaf33ecc9d24aab9f95a0e347f7b Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 16 Jun 2024 22:39:37 +0800 Subject: [PATCH] fix(shadowsocks): check IPv4-mapped-IPv6 compatiblity with UDP socket - ref #1543 --- crates/shadowsocks/src/net/sys/mod.rs | 40 ++++++++++++--------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/crates/shadowsocks/src/net/sys/mod.rs b/crates/shadowsocks/src/net/sys/mod.rs index c45bcd6eb7c8..19c004833076 100644 --- a/crates/shadowsocks/src/net/sys/mod.rs +++ b/crates/shadowsocks/src/net/sys/mod.rs @@ -1,7 +1,6 @@ use std::{ io::{self, ErrorKind}, net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, - time::Duration, }; use cfg_if::cfg_if; @@ -177,39 +176,34 @@ static IP_STACK_CAPABILITIES: Lazy = Lazy::new(|| { }); fn check_ipv4_mapped_ipv6_capability() -> io::Result<()> { + // https://stackoverflow.com/questions/30184377/how-to-detect-if-dual-stack-socket-is-supported + let local_host = SockAddr::from(SocketAddr::new(Ipv4Addr::LOCALHOST.to_ipv6_mapped().into(), 0)); + let local_host_53 = SockAddr::from(SocketAddr::new(Ipv4Addr::LOCALHOST.to_ipv6_mapped().into(), 53)); - let socket1 = Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP))?; - socket1.set_only_v6(false)?; - socket1.bind(&local_host)?; - socket1.listen(128)?; + let socket = Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::UDP))?; + socket.set_only_v6(false)?; + socket.bind(&local_host)?; + socket.connect(&local_host_53)?; - let socket1_address = socket1.local_addr()?; - match socket1_address.as_socket() { + // getsockname() + let local_addr = socket.local_addr()?; + match local_addr.as_socket() { None => return Err(io::Error::new(ErrorKind::Other, "invalid local_addr")), - Some(socket_addr) => match socket_addr { - SocketAddr::V4(..) => { - return Err(io::Error::new( - ErrorKind::Other, - "local_addr shouldn't be an IPv4 address", - )); - } - SocketAddr::V6(ref v6) => { - if let None = v6.ip().to_ipv4_mapped() { + Some(addr) => match addr { + SocketAddr::V4(..) => return Err(io::Error::new(ErrorKind::Other, "local_addr returned an IPv4 address")), + SocketAddr::V6(v6) => match v6.ip().to_ipv4_mapped() { + Some(_) => {} + None => { return Err(io::Error::new( ErrorKind::Other, - "local_addr is not an IPv4-mapped-IPv6 address", + "local_addr returned an non IPv4-mapped-IPv6 address", )); } - } + }, }, } - let socket2 = Socket::new(Domain::IPV6, Type::STREAM, Some(Protocol::TCP))?; - socket2.set_only_v6(false)?; - socket2.bind(&local_host)?; - socket2.connect_timeout(&socket1_address, Duration::from_secs(1))?; - Ok(()) }