Fix: FreeBSD Building (#1528)

* Fix: FreeBSD Building

* Fix: FreeBSD Building. TCP natlook return

* Fix: FreeBSD Building. My mistake...
This commit is contained in:
splurge103
2024-05-18 21:09:32 +08:00
committed by GitHub
parent 7aed79b201
commit 6d67524534
3 changed files with 198 additions and 175 deletions
@@ -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(())
})?;