mirror of
https://github.com/TrustTunnel/TrustTunnel.git
synced 2026-07-09 17:18:36 +00:00
Support building TrustTunnel on FreeBSD OS
A bunch of code fixes and adjustments to make TrustTunnel build cleanly on FreeBSD. Note that because of the `boringssl` version currently used by `quiche`, to build TrustTunnel on FreeBSD, one needs to set the BORING_BSSL_RUST_CPPLIB=c++ variable. This is to make the linker use libc++ from clang instead of libstdc++. A newer version of `boringssl` has a fix that makes this variable obsolete. Signed-off-by: Vladimir Krivopalov <vladimir.krivopalov@gmail.com>
This commit is contained in:
parent
dea1ca4376
commit
3fb64c910e
3 changed files with 100 additions and 3 deletions
|
|
@ -397,7 +397,7 @@ impl RawPacketStream {
|
|||
};
|
||||
|
||||
unsafe {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
let fd = libc::socket(family, libc::SOCK_RAW, protocol);
|
||||
#[cfg(target_os = "macos")]
|
||||
let fd = libc::socket(family, libc::SOCK_DGRAM, protocol);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef __linux__
|
||||
#include <linux/icmp.h>
|
||||
#endif
|
||||
#include <netinet/icmp6.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -49,7 +50,7 @@ int set_icmpv6_filter(int fd) {
|
|||
}
|
||||
|
||||
int bind_to_interface_by_index(int fd, int family, unsigned idx) {
|
||||
#ifndef __linux__
|
||||
#ifdef __APPLE__
|
||||
int level = IPPROTO_IP;
|
||||
int option = IP_BOUND_IF;
|
||||
if (family == AF_INET6) {
|
||||
|
|
@ -59,6 +60,7 @@ int bind_to_interface_by_index(int fd, int family, unsigned idx) {
|
|||
|
||||
return setsockopt(fd, level, option, &idx, sizeof(idx));
|
||||
#else
|
||||
/* Linux and FreeBSD don't have IP_BOUND_IF */
|
||||
(void)fd;
|
||||
(void)family;
|
||||
(void)idx;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,101 @@ pub(crate) fn bind_to_interface(
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
pub(crate) fn bind_to_interface(
|
||||
fd: libc::c_int,
|
||||
family: libc::c_int,
|
||||
name: &str,
|
||||
) -> io::Result<()> {
|
||||
use std::ffi::CString;
|
||||
|
||||
// FreeBSD doesn't have SO_BINDTODEVICE (Linux) or IP_BOUND_IF (macOS).
|
||||
// We bind the socket to the interface's IP address instead, which achieves
|
||||
// the same effect of restricting traffic to that interface.
|
||||
let c_name = CString::new(name).map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "invalid interface name")
|
||||
})?;
|
||||
|
||||
let mut ifaddrs: *mut libc::ifaddrs = std::ptr::null_mut();
|
||||
// SAFETY: getifaddrs writes to our pointer, which we'll free with freeifaddrs
|
||||
if unsafe { libc::getifaddrs(&mut ifaddrs) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
// RAII guard to ensure freeifaddrs is called
|
||||
struct IfAddrsGuard(*mut libc::ifaddrs);
|
||||
impl Drop for IfAddrsGuard {
|
||||
fn drop(&mut self) {
|
||||
// SAFETY: self.0 was allocated by getifaddrs
|
||||
unsafe { libc::freeifaddrs(self.0) };
|
||||
}
|
||||
}
|
||||
let _guard = IfAddrsGuard(ifaddrs);
|
||||
|
||||
let mut current = ifaddrs;
|
||||
let mut bind_addr: Option<libc::sockaddr_storage> = None;
|
||||
|
||||
while !current.is_null() {
|
||||
// SAFETY: current is not null (checked above) and points to valid ifaddrs from getifaddrs
|
||||
let ifa = unsafe { &*current };
|
||||
|
||||
let names_match = !ifa.ifa_name.is_null() && {
|
||||
// SAFETY: ifa_name is not null (checked above) and is a valid C string from getifaddrs
|
||||
unsafe { libc::strcmp(ifa.ifa_name, c_name.as_ptr()) == 0 }
|
||||
};
|
||||
|
||||
if names_match && !ifa.ifa_addr.is_null() {
|
||||
// SAFETY: ifa_addr is not null (checked above)
|
||||
let sa_family = unsafe { (*ifa.ifa_addr).sa_family } as libc::c_int;
|
||||
if sa_family == family {
|
||||
// SAFETY: zeroed sockaddr_storage is valid
|
||||
let mut storage: libc::sockaddr_storage = unsafe { std::mem::zeroed() };
|
||||
let len = if family == libc::AF_INET {
|
||||
std::mem::size_of::<libc::sockaddr_in>()
|
||||
} else {
|
||||
std::mem::size_of::<libc::sockaddr_in6>()
|
||||
};
|
||||
// SAFETY: ifa_addr points to valid sockaddr of the appropriate family,
|
||||
// and storage has enough space for either sockaddr_in or sockaddr_in6
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
ifa.ifa_addr as *const u8,
|
||||
&mut storage as *mut _ as *mut u8,
|
||||
len,
|
||||
);
|
||||
}
|
||||
bind_addr = Some(storage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = ifa.ifa_next;
|
||||
}
|
||||
|
||||
let storage = bind_addr.ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!(
|
||||
"no {} address found for interface {}",
|
||||
if family == libc::AF_INET { "IPv4" } else { "IPv6" },
|
||||
name
|
||||
),
|
||||
)
|
||||
})?;
|
||||
|
||||
let addr_len = if family == libc::AF_INET {
|
||||
std::mem::size_of::<libc::sockaddr_in>() as libc::socklen_t
|
||||
} else {
|
||||
std::mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t
|
||||
};
|
||||
|
||||
// SAFETY: storage contains a valid sockaddr_in or sockaddr_in6, fd is a valid socket
|
||||
if unsafe { libc::bind(fd, &storage as *const _ as *const libc::sockaddr, addr_len) } != 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn set_socket_ttl(fd: libc::c_int, is_ipv4: bool, ttl: u8) -> io::Result<()> {
|
||||
unsafe {
|
||||
let (level, name) = if is_ipv4 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue