mirror of
https://github.com/shadowsocks/shadowsocks-rust.git
synced 2026-11-06 08:14:07 +00:00
Fix: FreeBSD Building (#1528)
* Fix: FreeBSD Building * Fix: FreeBSD Building. TCP natlook return * Fix: FreeBSD Building. My mistake...
This commit is contained in:
@@ -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<SocketAddr> {
|
||||
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<SocketAddr> {
|
||||
unsafe {
|
||||
// Get all states
|
||||
// https://man.freebsd.org/cgi/man.cgi?query=pf&sektion=4&manpath=OpenBSD
|
||||
// DIOCGETSTATES
|
||||
|
||||
fn udp_natlook(&self, bind_addr: &SocketAddr, peer_addr: &SocketAddr, _proto: Protocol) -> io::Result<SocketAddr> {
|
||||
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];
|
||||
|
||||
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 _;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
let bind_addr_sockaddr = SockAddr::from(*bind_addr);
|
||||
let peer_addr_sockaddr = SockAddr::from(*peer_addr);
|
||||
let mut bind_addr_pfaddr: pf_addr = mem::zeroed();
|
||||
let mut peer_addr_pfaddr: pf_addr = mem::zeroed();
|
||||
|
||||
let mut bind_addr_pfaddr: pf_addr = mem::zeroed();
|
||||
let mut peer_addr_pfaddr: pf_addr = mem::zeroed();
|
||||
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::<in_addr>(
|
||||
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::<in6_addr>(
|
||||
ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _,
|
||||
(*sockaddr).sin6_addr,
|
||||
);
|
||||
}
|
||||
_ => unreachable!("bind_addr family = {}", bind_addr_sockaddr.family()),
|
||||
}
|
||||
|
||||
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::<in_addr>(
|
||||
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::<in6_addr>(
|
||||
ptr::addr_of_mut!(bind_addr_pfaddr.pfa) as *mut _,
|
||||
(*sockaddr).sin6_addr,
|
||||
);
|
||||
}
|
||||
_ => unreachable!("bind_addr family = {}", bind_addr_sockaddr.family()),
|
||||
}
|
||||
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::<in_addr>(
|
||||
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::<in6_addr>(
|
||||
ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _,
|
||||
(*sockaddr).sin6_addr,
|
||||
);
|
||||
}
|
||||
_ => unreachable!("peer_addr family = {}", peer_addr_sockaddr.family()),
|
||||
}
|
||||
|
||||
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::<in_addr>(
|
||||
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::<in6_addr>(
|
||||
ptr::addr_of_mut!(peer_addr_pfaddr.pfa) as *mut _,
|
||||
(*sockaddr).sin6_addr,
|
||||
);
|
||||
}
|
||||
_ => unreachable!("peer_addr family = {}", peer_addr_sockaddr.family()),
|
||||
}
|
||||
let states_count = states.ps_len as usize / mem::size_of::<pfsync_state>();
|
||||
for i in 0..states_count {
|
||||
let state = &*(states.ps_u.psu_states.add(i));
|
||||
|
||||
let states_count = states.ps_len as usize / mem::size_of::<pfsync_state>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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::<pf_addr>(),
|
||||
) == 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::<pf_addr>(),
|
||||
) == 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::<in_addr>(
|
||||
ptr::addr_of_mut!(addr.sin_addr),
|
||||
ptr::read_unaligned::<in_addr>(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::<sockaddr_in>() 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::<in6_addr>(
|
||||
ptr::addr_of_mut!(addr.sin6_addr),
|
||||
ptr::read_unaligned::<in6_addr>(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::<sockaddr_in6>() 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::<pf_addr>(),
|
||||
) == 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::<pf_addr>(),
|
||||
) == 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::<in_addr>(
|
||||
ptr::addr_of_mut!(addr.sin_addr),
|
||||
ptr::read_unaligned::<in_addr>(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::<sockaddr_in>() 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::<in6_addr>(
|
||||
ptr::addr_of_mut!(addr.sin6_addr),
|
||||
ptr::read_unaligned::<in6_addr>(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::<sockaddr_in6>() 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),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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<UdpSocket>,
|
||||
}
|
||||
@@ -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();
|
||||
// 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,
|
||||
};
|
||||
|
||||
let enable: libc::c_int = 1;
|
||||
// 1. BINDANY
|
||||
set_bindany(level, socket)?;
|
||||
|
||||
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,
|
||||
};
|
||||
// 2. set ORIGDSTADDR for retrieving original destination address
|
||||
set_ip_origdstaddr(level, socket)?;
|
||||
|
||||
// 1. BINDANY
|
||||
set_bindany(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<SocketAddr> {
|
||||
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::<libc::sockaddr_in>());
|
||||
ptr::copy_nonoverlapping(
|
||||
libc::CMSG_DATA(cmsg),
|
||||
dst_addr as *mut _,
|
||||
mem::size_of::<libc::sockaddr_in>()
|
||||
);
|
||||
*dst_addr_len = mem::size_of::<libc::sockaddr_in>() 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(())
|
||||
})?;
|
||||
|
||||
Reference in New Issue
Block a user