diff --git a/crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs b/crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs index c852c9d68499..2ff16a084038 100644 --- a/crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs +++ b/crates/shadowsocks-service/src/local/redir/sys/unix/bsd_pf.rs @@ -2,28 +2,40 @@ use std::{ io::{self, Error, ErrorKind}, - mem, net::SocketAddr, - ptr, }; use cfg_if::cfg_if; -use log::trace; use nix::ioctl_readwrite; use once_cell::sync::Lazy; -use socket2::{Protocol, SockAddr}; + +use super::pfvar::{ + pfioc_natlook, + pfioc_states +}; +use log::trace; use super::pfvar::{ in6_addr, in_addr, - pf_addr, - pfioc_natlook, - pfioc_states, - pfsync_state, sockaddr_in, sockaddr_in6, PF_OUT, }; +use std::{ + ptr, + mem +}; +use socket2::{Protocol, SockAddr}; + +cfg_if! { + if #[cfg(not(target_os = "freebsd"))] { + use super::pfvar::{ + pf_addr, + pfsync_state + }; + } +} ioctl_readwrite!(ioc_natlook, 'D', 23, pfioc_natlook); ioctl_readwrite!(ioc_getstates, 'D', 25, pfioc_states); @@ -56,12 +68,21 @@ impl PacketFilter { Ok(PacketFilter { fd }) } } - + pub fn natlook(&self, bind_addr: &SocketAddr, peer_addr: &SocketAddr, proto: Protocol) -> io::Result { - match proto { - Protocol::TCP => self.tcp_natlook(bind_addr, peer_addr, proto), - Protocol::UDP => self.udp_natlook(bind_addr, peer_addr, proto), - _ => Err(io::ErrorKind::InvalidInput.into()), + cfg_if! { + if #[cfg(target_os = "freebsd")] { + match proto { + Protocol::TCP => self.tcp_natlook(bind_addr, peer_addr, proto), + _ => Err(io::ErrorKind::InvalidInput.into()), + } + } else { + match proto { + Protocol::TCP => self.tcp_natlook(bind_addr, peer_addr, proto), + Protocol::UDP => self.udp_natlook(bind_addr, peer_addr, proto), + _ => Err(io::ErrorKind::InvalidInput.into()), + } + } } } @@ -209,158 +230,161 @@ impl PacketFilter { Ok(dst_addr.as_socket().expect("SocketAddr")) } } + cfg_if! { + if #[cfg(not(target_os = "freebsd"))] { + fn udp_natlook(&self, bind_addr: &SocketAddr, peer_addr: &SocketAddr, _proto: Protocol) -> io::Result { + unsafe { + // Get all states + // https://man.freebsd.org/cgi/man.cgi?query=pf&sektion=4&manpath=OpenBSD + // DIOCGETSTATES + + let mut states: pfioc_states = mem::zeroed(); + let mut states_buffer = vec![0u8; 8192]; + + loop { + states.ps_len = states_buffer.len() as _; + states.ps_u.psu_buf = states_buffer.as_mut_ptr() as *mut _; + + if let Err(err) = ioc_getstates(self.fd, &mut states) { + return Err(Error::from_raw_os_error(err as i32)); + } - fn udp_natlook(&self, bind_addr: &SocketAddr, peer_addr: &SocketAddr, _proto: Protocol) -> io::Result { - unsafe { - // Get all states - // https://man.freebsd.org/cgi/man.cgi?query=pf&sektion=4&manpath=OpenBSD - // DIOCGETSTATES - - let mut states: pfioc_states = mem::zeroed(); - let mut states_buffer = vec![0u8; 8192]; - - loop { - states.ps_len = states_buffer.len() as _; - states.ps_u.psu_buf = states_buffer.as_mut_ptr() as *mut _; - - if let Err(err) = ioc_getstates(self.fd, &mut states) { - return Err(Error::from_raw_os_error(err as i32)); - } - - if states.ps_len as usize <= states_buffer.len() { - break; - } - - // Resize to fit all states - // > On exit, ps_len is always set to the total size re- - // > quired to hold all state table entries - states_buffer.resize(states.ps_len as usize, 0); - } - - let bind_addr_sockaddr = SockAddr::from(*bind_addr); - let peer_addr_sockaddr = SockAddr::from(*peer_addr); + if states.ps_len as usize <= states_buffer.len() { + break; + } - let mut bind_addr_pfaddr: pf_addr = mem::zeroed(); - let mut peer_addr_pfaddr: pf_addr = mem::zeroed(); + // Resize to fit all states + // > On exit, ps_len is always set to the total size re- + // > quired to hold all state table entries + states_buffer.resize(states.ps_len as usize, 0); + } - match bind_addr_sockaddr.family() as libc::c_int { - libc::AF_INET => { - let sockaddr: *const sockaddr_in = bind_addr_sockaddr.as_ptr() as *const _; - ptr::write_unaligned::( - ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _, - (*sockaddr).sin_addr, - ); - } - libc::AF_INET6 => { - let sockaddr: *const sockaddr_in6 = bind_addr_sockaddr.as_ptr() as *const _; - ptr::write_unaligned::( - ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _, - (*sockaddr).sin6_addr, - ); - } - _ => unreachable!("bind_addr family = {}", bind_addr_sockaddr.family()), - } + let bind_addr_sockaddr = SockAddr::from(*bind_addr); + let peer_addr_sockaddr = SockAddr::from(*peer_addr); - match peer_addr_sockaddr.family() as libc::c_int { - libc::AF_INET => { - let sockaddr: *const sockaddr_in = peer_addr_sockaddr.as_ptr() as *const _; - ptr::write_unaligned::( - ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _, - (*sockaddr).sin_addr, - ); - } - libc::AF_INET6 => { - let sockaddr: *const sockaddr_in6 = peer_addr_sockaddr.as_ptr() as *const _; - ptr::write_unaligned::( - ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _, - (*sockaddr).sin6_addr, - ); - } - _ => unreachable!("peer_addr family = {}", peer_addr_sockaddr.family()), - } + let mut bind_addr_pfaddr: pf_addr = mem::zeroed(); + let mut peer_addr_pfaddr: pf_addr = mem::zeroed(); - let states_count = states.ps_len as usize / mem::size_of::(); - for i in 0..states_count { - let state = &*(states.ps_u.psu_states.add(i)); + match bind_addr_sockaddr.family() as libc::c_int { + libc::AF_INET => { + let sockaddr: *const sockaddr_in = bind_addr_sockaddr.as_ptr() as *const _; + ptr::write_unaligned::( + ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _, + (*sockaddr).sin_addr, + ); + } + libc::AF_INET6 => { + let sockaddr: *const sockaddr_in6 = bind_addr_sockaddr.as_ptr() as *const _; + ptr::write_unaligned::( + ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _, + (*sockaddr).sin6_addr, + ); + } + _ => unreachable!("bind_addr family = {}", bind_addr_sockaddr.family()), + } - if state.proto == libc::IPPROTO_UDP as u8 { - cfg_if! { - if #[cfg(any(target_os = "macos", target_os = "ios"))] { - let dst_port = state.lan.xport.port; - let src_port = state.ext_gwy.xport.port; - let actual_dst_port = state.gwy.xport.port; - } else { - let dst_port = state.lan.port; - let src_port = state.ext_gwy.port; - let actual_dst_port = state.gwy.port; + match peer_addr_sockaddr.family() as libc::c_int { + libc::AF_INET => { + let sockaddr: *const sockaddr_in = peer_addr_sockaddr.as_ptr() as *const _; + ptr::write_unaligned::( + ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _, + (*sockaddr).sin_addr, + ); + } + libc::AF_INET6 => { + let sockaddr: *const sockaddr_in6 = peer_addr_sockaddr.as_ptr() as *const _; + ptr::write_unaligned::( + ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _, + (*sockaddr).sin6_addr, + ); } + _ => unreachable!("peer_addr family = {}", peer_addr_sockaddr.family()), } - let dst_addr_eq = libc::memcmp( - &bind_addr_pfaddr as *const _ as *const _, - ptr::addr_of!(state.lan.addr.pfa) as *const _, - mem::size_of::(), - ) == 0; - let src_addr_eq = libc::memcmp( - &peer_addr_pfaddr as *const _ as *const _, - ptr::addr_of!(state.ext_gwy.addr.pfa) as *const _, - mem::size_of::(), - ) == 0; - - if src_addr_eq && src_port == peer_addr.port() && dst_addr_eq && dst_port == bind_addr.port() { - let actual_dst_addr = match state.af_gwy as libc::c_int { - libc::AF_INET => { - let (_, actual_dst_addr) = SockAddr::try_init(|sockaddr, len| { - let addr = &mut *(sockaddr as *mut sockaddr_in); - addr.sin_family = libc::AF_INET as libc::sa_family_t; - ptr::write_unaligned::( - ptr::addr_of_mut!(addr.sin_addr), - ptr::read_unaligned::(ptr::addr_of!(state.gwy.addr.pfa) as *const _), - ); - addr.sin_port = actual_dst_port as libc::in_port_t; - - ptr::write(len, mem::size_of::() as libc::socklen_t); - Ok(()) - }) - .unwrap(); - - actual_dst_addr + let states_count = states.ps_len as usize / mem::size_of::(); + for i in 0..states_count { + let state = &*(states.ps_u.psu_states.add(i)); + + if state.proto == libc::IPPROTO_UDP as u8 { + cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + let dst_port = state.lan.xport.port; + let src_port = state.ext_gwy.xport.port; + let actual_dst_port = state.gwy.xport.port; + } else { + let dst_port = state.lan.port; + let src_port = state.ext_gwy.port; + let actual_dst_port = state.gwy.port; + } } - libc::AF_INET6 => { - let (_, actual_dst_addr) = SockAddr::try_init(|sockaddr, len| { - let addr = &mut *(sockaddr as *mut sockaddr_in6); - addr.sin6_family = libc::AF_INET6 as libc::sa_family_t; - ptr::write_unaligned::( - ptr::addr_of_mut!(addr.sin6_addr), - ptr::read_unaligned::(ptr::addr_of!(state.gwy.addr.pfa) as *const _), - ); - addr.sin6_port = actual_dst_port as libc::in_port_t; - - ptr::write(len, mem::size_of::() as libc::socklen_t); - Ok(()) - }) - .unwrap(); - - actual_dst_addr - } - _ => { - return Err(io::Error::new( - ErrorKind::Other, - format!("state.af_gwy {} is not a valid address family", state.af_gwy), - )); - } - }; - return Ok(actual_dst_addr.as_socket().expect("SocketAddr")); + let dst_addr_eq = libc::memcmp( + &bind_addr_pfaddr as *const _ as *const _, + ptr::addr_of!(state.lan.addr.pfa) as *const _, + mem::size_of::(), + ) == 0; + let src_addr_eq = libc::memcmp( + &peer_addr_pfaddr as *const _ as *const _, + ptr::addr_of!(state.ext_gwy.addr.pfa) as *const _, + mem::size_of::(), + ) == 0; + + if src_addr_eq && src_port == peer_addr.port() && dst_addr_eq && dst_port == bind_addr.port() { + let actual_dst_addr = match state.af_gwy as libc::c_int { + libc::AF_INET => { + let (_, actual_dst_addr) = SockAddr::try_init(|sockaddr, len| { + let addr = &mut *(sockaddr as *mut sockaddr_in); + addr.sin_family = libc::AF_INET as libc::sa_family_t; + ptr::write_unaligned::( + ptr::addr_of_mut!(addr.sin_addr), + ptr::read_unaligned::(ptr::addr_of!(state.gwy.addr.pfa) as *const _), + ); + addr.sin_port = actual_dst_port as libc::in_port_t; + + ptr::write(len, mem::size_of::() as libc::socklen_t); + Ok(()) + }) + .unwrap(); + + actual_dst_addr + } + libc::AF_INET6 => { + let (_, actual_dst_addr) = SockAddr::try_init(|sockaddr, len| { + let addr = &mut *(sockaddr as *mut sockaddr_in6); + addr.sin6_family = libc::AF_INET6 as libc::sa_family_t; + ptr::write_unaligned::( + ptr::addr_of_mut!(addr.sin6_addr), + ptr::read_unaligned::(ptr::addr_of!(state.gwy.addr.pfa) as *const _), + ); + addr.sin6_port = actual_dst_port as libc::in_port_t; + + ptr::write(len, mem::size_of::() as libc::socklen_t); + Ok(()) + }) + .unwrap(); + + actual_dst_addr + } + _ => { + return Err(io::Error::new( + ErrorKind::Other, + format!("state.af_gwy {} is not a valid address family", state.af_gwy), + )); + } + }; + + return Ok(actual_dst_addr.as_socket().expect("SocketAddr")); + } + } } } - } - } - Err(io::Error::new( - ErrorKind::Other, - format!("natlook UDP binding {}, {} not found", bind_addr, peer_addr), - )) + Err(io::Error::new( + ErrorKind::Other, + format!("natlook UDP binding {}, {} not found", bind_addr, peer_addr), + )) + } + } } } diff --git a/crates/shadowsocks-service/src/local/redir/sys/unix/pfvar_bindgen_freebsd.rs b/crates/shadowsocks-service/src/local/redir/sys/unix/pfvar_bindgen_freebsd.rs index e6282cc26353..fa900ea9f3ca 100644 --- a/crates/shadowsocks-service/src/local/redir/sys/unix/pfvar_bindgen_freebsd.rs +++ b/crates/shadowsocks-service/src/local/redir/sys/unix/pfvar_bindgen_freebsd.rs @@ -11945,7 +11945,7 @@ fn bindgen_test_layout_pf_status() { #[repr(C)] #[derive(Copy, Clone)] pub struct pf_addr { - pub __bindgen_anon_1: pf_addr__bindgen_ty_1, + pub pfa: pf_addr__bindgen_ty_1, } #[repr(C)] #[derive(Copy, Clone)] diff --git a/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs b/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs index 345ea19feb8b..bba6140058f6 100644 --- a/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs +++ b/crates/shadowsocks-service/src/local/redir/udprelay/sys/unix/bsd.rs @@ -7,7 +7,6 @@ use std::{ task::{Context, Poll}, }; -use async_trait::async_trait; use cfg_if::cfg_if; use futures::{future::poll_fn, ready}; use log::{error, trace, warn}; @@ -18,15 +17,11 @@ use tokio::io::unix::AsyncFd; use crate::{ config::RedirType, local::redir::{ - redir_ext::{RedirSocketOpts, UdpSocketRedirExt}, + redir_ext::{RedirSocketOpts, UdpSocketRedir}, sys::set_ipv6_only, }, }; -pub fn check_support_tproxy() -> io::Result<()> { - Ok(()) -} - pub struct UdpRedirSocket { io: AsyncFd, } @@ -273,6 +268,8 @@ fn set_disable_ip_fragmentation(level: libc::c_int, socket: &Socket) -> io::Resu // sys/netinet6/in6.h const IPV6_DONTFRAG: libc::c_int = 62; // bool; disable IPv6 fragmentation + let enable: libc::c_int = 1; + let opt = match level { libc::IPPROTO_IP => IP_DONTFRAG, libc::IPPROTO_IPV6 => IPV6_DONTFRAG, @@ -297,26 +294,20 @@ fn set_disable_ip_fragmentation(level: libc::c_int, socket: &Socket) -> io::Resu } fn set_socket_before_bind(addr: &SocketAddr, socket: &Socket) -> io::Result<()> { - let fd = socket.as_raw_fd(); - - let enable: libc::c_int = 1; - - unsafe { - // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE - let level = match *addr { - SocketAddr::V4(..) => libc::IPPROTO_IP, - SocketAddr::V6(..) => libc::IPPROTO_IPV6, - }; + // https://www.freebsd.org/cgi/man.cgi?query=ip&sektion=4&manpath=FreeBSD+9.0-RELEASE + let level = match *addr { + SocketAddr::V4(..) => libc::IPPROTO_IP, + SocketAddr::V6(..) => libc::IPPROTO_IPV6, + }; - // 1. BINDANY - set_bindany(level, socket)?; + // 1. BINDANY + set_bindany(level, socket)?; - // 2. set ORIGDSTADDR for retrieving original destination address - set_ip_origdstaddr(level, socket)?; + // 2. set ORIGDSTADDR for retrieving original destination address + set_ip_origdstaddr(level, socket)?; - // 3. disable IP fragmentation - set_disable_ip_fragmentation(level, socket)?; - } + // 3. disable IP fragmentation + set_disable_ip_fragmentation(level, socket)?; Ok(()) } @@ -333,7 +324,11 @@ fn get_destination_addr(msg: &libc::msghdr) -> io::Result { let rcmsg = &*cmsg; match (rcmsg.cmsg_level, rcmsg.cmsg_type) { (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { - ptr::copy_nonoverlapping(libc::CMSG_DATA(cmsg), dst_addr, mem::size_of::()); + ptr::copy_nonoverlapping( + libc::CMSG_DATA(cmsg), + dst_addr as *mut _, + mem::size_of::() + ); *dst_addr_len = mem::size_of::() as libc::socklen_t; return Ok(()); @@ -387,7 +382,11 @@ fn recv_dest_from(socket: &UdpSocket, buf: &mut [u8]) -> io::Result<(usize, Sock } let (_, src_saddr) = SockAddr::try_init(|a, l| { - ptr::copy_nonoverlapping(msg.msg_name, a, msg.msg_namelen as usize); + ptr::copy_nonoverlapping( + msg.msg_name, + a as *mut _, + msg.msg_namelen as usize + ); *l = msg.msg_namelen; Ok(()) })?;