wip
This commit is contained in:
parent
b37086e8f6
commit
1a13b77295
20 changed files with 767 additions and 468 deletions
56
tun/src/unix/apple/kern_control.rs
Normal file
56
tun/src/unix/apple/kern_control.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use fehler::throws;
|
||||
use libc::{sockaddr_ctl, AF_SYSTEM, AF_SYS_CONTROL};
|
||||
use std::io::Error;
|
||||
use std::mem::size_of;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
|
||||
/// Trait to connect to kernel extensions on Apple platforms
|
||||
///
|
||||
/// Pulled from XNU source: https://github.com/apple/darwin-xnu/blob/main/bsd/sys/kern_control.h
|
||||
pub trait SysControlSocket {
|
||||
#[throws]
|
||||
fn resolve(&self, name: &str, index: u32) -> socket2::SockAddr;
|
||||
}
|
||||
|
||||
impl SysControlSocket for socket2::Socket {
|
||||
#[throws]
|
||||
fn resolve(&self, name: &str, index: u32) -> socket2::SockAddr {
|
||||
let mut info = sys::ctl_info {
|
||||
ctl_id: 0,
|
||||
ctl_name: [0; 96],
|
||||
};
|
||||
info.ctl_name[..name.len()].copy_from_slice(name.as_bytes());
|
||||
|
||||
unsafe { sys::resolve_ctl_info(self.as_raw_fd(), &mut info as *mut sys::ctl_info)? };
|
||||
|
||||
let (_, addr) = unsafe {
|
||||
socket2::SockAddr::init(|addr_storage, len| {
|
||||
*len = size_of::<sockaddr_ctl>() as u32;
|
||||
|
||||
let mut addr: &mut sockaddr_ctl = &mut *addr_storage.cast();
|
||||
addr.sc_len = *len as u8;
|
||||
addr.sc_family = AF_SYSTEM as u8;
|
||||
addr.ss_sysaddr = AF_SYS_CONTROL as u16;
|
||||
addr.sc_id = info.ctl_id;
|
||||
addr.sc_unit = index;
|
||||
Ok(())
|
||||
})
|
||||
}?;
|
||||
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
mod sys {
|
||||
use nix::ioctl_readwrite;
|
||||
|
||||
const MAX_KCTL_NAME: usize = 96;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ctl_info {
|
||||
pub ctl_id: u32,
|
||||
pub ctl_name: [u8; MAX_KCTL_NAME],
|
||||
}
|
||||
|
||||
ioctl_readwrite!(resolve_ctl_info, b'N', 3, ctl_info);
|
||||
}
|
||||
98
tun/src/unix/apple/mod.rs
Normal file
98
tun/src/unix/apple/mod.rs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
use fehler::throws;
|
||||
use libc::c_char;
|
||||
use socket2::{Domain, SockAddr};
|
||||
use std::mem;
|
||||
use std::net::SocketAddrV4;
|
||||
use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
|
||||
|
||||
mod kern_control;
|
||||
mod sys;
|
||||
|
||||
pub use super::queue::TunQueue;
|
||||
|
||||
use super::{ifname_to_string, string_to_ifname};
|
||||
use kern_control::SysControlSocket;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TunInterface {
|
||||
pub(crate) socket: socket2::Socket,
|
||||
}
|
||||
|
||||
impl TunInterface {
|
||||
#[throws]
|
||||
pub fn new() -> TunInterface {
|
||||
TunInterface::connect(0)?
|
||||
}
|
||||
|
||||
#[throws]
|
||||
fn connect(index: u32) -> TunInterface {
|
||||
use socket2::{Domain, Protocol, Socket, Type};
|
||||
|
||||
let socket = Socket::new(
|
||||
Domain::from(libc::AF_SYSTEM),
|
||||
Type::DGRAM,
|
||||
Some(Protocol::from(libc::SYSPROTO_CONTROL)),
|
||||
)?;
|
||||
let addr = socket.resolve(sys::UTUN_CONTROL_NAME, index)?;
|
||||
socket.connect(&addr)?;
|
||||
|
||||
TunInterface { socket }
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub fn name(&self) -> String {
|
||||
let mut buf = [0 as c_char; libc::IFNAMSIZ];
|
||||
let mut len = buf.len() as libc::socklen_t;
|
||||
sys::syscall!(getsockopt(
|
||||
self.as_raw_fd(),
|
||||
libc::SYSPROTO_CONTROL,
|
||||
sys::UTUN_OPT_IFNAME,
|
||||
buf.as_mut_ptr() as *mut libc::c_void,
|
||||
&mut len,
|
||||
))?;
|
||||
ifname_to_string(buf)
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub fn index(&self) -> i32 {
|
||||
let socket = Socket::new(Domain::IPV4, Type::DGRAM, None)?;
|
||||
unsafe {
|
||||
let mut iff: libc::ifreq = mem::zeroed();
|
||||
iff.ifr_name = string_to_ifname(self.name()?);
|
||||
sys::if_get_index(socket.as_raw_fd(), &mut iff)?;
|
||||
iff.ifr_ifru.ifru_ifindex
|
||||
}
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub fn set_addr(&self, addr: IpAddr) {
|
||||
match addr {
|
||||
IpAddr::V4(addr) => self.set_ipv4_addr(addr)?,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub fn set_ipv4_addr(&self, addr: Ipv4Addr) {
|
||||
let socket = Socket::new(Domain::IPV4, Type::DGRAM, None)?;
|
||||
let addr = SockAddr::from(SocketAddrV4::new(addr, 0));
|
||||
unsafe {
|
||||
let mut iff: libc::ifreq = mem::zeroed();
|
||||
iff.ifr_name = string_to_ifname(self.name()?);
|
||||
iff.ifr_ifru.ifru_addr = *addr.as_ptr();
|
||||
sys::if_set_addr(socket.as_raw_fd(), &iff)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for TunInterface {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.socket.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for TunInterface {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.socket.into_raw_fd()
|
||||
}
|
||||
}
|
||||
22
tun/src/unix/apple/sys.rs
Normal file
22
tun/src/unix/apple/sys.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
|
||||
pub const UTUN_OPT_IFNAME: libc::c_int = 2;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ifreq {}
|
||||
|
||||
/// Copied from https://github.com/rust-lang/socket2/blob/61314a231f73964b3db969ef72c0e9479df320f3/src/sys/unix.rs#L168-L178
|
||||
/// getsockopt is not exposed by socket2
|
||||
#[macro_export]
|
||||
macro_rules! syscall {
|
||||
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
|
||||
#[allow(unused_unsafe)]
|
||||
let res = unsafe { libc::$fn($($arg, )*) };
|
||||
if res == -1 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
pub use syscall;
|
||||
Loading…
Add table
Add a link
Reference in a new issue