diff --git a/tun/src/unix/apple/mod.rs b/tun/src/unix/apple/mod.rs index 74e93ebb..687b58f7 100644 --- a/tun/src/unix/apple/mod.rs +++ b/tun/src/unix/apple/mod.rs @@ -1,13 +1,11 @@ -use std::{ - io::{Error, IoSlice}, - mem, - net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4}, - os::fd::{AsRawFd, FromRawFd, RawFd}, -}; +use std::{io::{Error, IoSlice}, mem, net::{Ipv4Addr, SocketAddrV4}, os::fd::{AsRawFd, FromRawFd, RawFd}, ptr}; +use std::net::{IpAddr, Ipv6Addr, SocketAddrV6}; +use std::ptr::addr_of; use byteorder::{ByteOrder, NetworkEndian}; use fehler::throws; -use libc::{c_char, iovec, writev, AF_INET, AF_INET6}; +use libc::{c_char, iovec, sockaddr_in6, writev, AF_INET, AF_INET6}; +use nix::sys::socket::SockaddrIn6; use socket2::{Domain, SockAddr, Socket, Type}; use tracing::{self, instrument}; diff --git a/tun/src/unix/linux/mod.rs b/tun/src/unix/linux/mod.rs index 60d63410..9ff964e7 100644 --- a/tun/src/unix/linux/mod.rs +++ b/tun/src/unix/linux/mod.rs @@ -2,7 +2,7 @@ use std::{ fs::OpenOptions, io::{Error, Write}, mem, - net::{Ipv4Addr, Ipv6Addr, SocketAddrV4}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4}, os::{ fd::RawFd, unix::io::{AsRawFd, FromRawFd, IntoRawFd}, @@ -15,7 +15,7 @@ use socket2::{Domain, SockAddr, Socket, Type}; use tracing::{info, instrument}; use super::{ifname_to_string, string_to_ifname}; -use crate::TunOptions; +use crate::{syscall, TunOptions}; mod sys; @@ -114,6 +114,25 @@ impl TunInterface { Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr)) } + #[throws] + #[instrument] + pub fn ipv6_addrs(&self) -> Vec { + let ip_addrs = self.ip_addrs()?; + let mut ipv6_addrs: Vec = vec![]; + + for ip_addr in ip_addrs.iter() { + if ip_addr.is_ipv6() { + match ip_addr { + IpAddr::V6(addr) => { + ipv6_addrs.push(*addr); + } + _ => {} + } + } + } + ipv6_addrs + } + #[throws] #[instrument] pub fn set_broadcast_addr(&self, addr: Ipv4Addr) { diff --git a/tun/src/unix/linux/sys.rs b/tun/src/unix/linux/sys.rs index e12c8ec4..96f73263 100644 --- a/tun/src/unix/linux/sys.rs +++ b/tun/src/unix/linux/sys.rs @@ -24,3 +24,13 @@ ioctl_write_ptr_bad!(if_set_addr6, libc::SIOCSIFADDR, libc::in6_ifreq); ioctl_write_ptr_bad!(if_set_brdaddr, libc::SIOCSIFBRDADDR, libc::ifreq); ioctl_write_ptr_bad!(if_set_mtu, libc::SIOCSIFMTU, libc::ifreq); ioctl_write_ptr_bad!(if_set_netmask, libc::SIOCSIFNETMASK, libc::ifreq); + +#[macro_export] +macro_rules! syscall { + ($call: ident ( $($arg: expr),* $(,)* ) ) => {{ + match unsafe { ::libc::$call($($arg, )*) } { + -1 => Err(::std::io::Error::last_os_error()), + res => Ok(res), + } + }}; +} \ No newline at end of file diff --git a/tun/src/unix/mod.rs b/tun/src/unix/mod.rs index ae0b77a5..d1cadd45 100644 --- a/tun/src/unix/mod.rs +++ b/tun/src/unix/mod.rs @@ -1,11 +1,16 @@ use std::{ + ffi::CStr, io::Error, + mem, mem::MaybeUninit, + net::{IpAddr, SocketAddr}, os::fd::{AsRawFd, FromRawFd, IntoRawFd, RawFd}, }; use tracing::instrument; +use crate::syscall; + mod queue; #[cfg(target_vendor = "apple")] @@ -60,6 +65,47 @@ impl TunInterface { pub fn set_nonblocking(&mut self, nb: bool) { self.socket.set_nonblocking(nb)?; } + + #[throws] + #[instrument] + pub fn ip_addrs(&self) -> Vec { + let mut result: Vec = vec![]; + let mut addrs: *mut libc::ifaddrs = std::ptr::null_mut(); + let if_name = self.name()?; + syscall!(getifaddrs(&mut addrs as *mut _))?; + unsafe { + while !addrs.is_null() { + let addr = &*addrs; + addrs = addr.ifa_next; + + let name = CStr::from_ptr(addr.ifa_name).to_str().unwrap(); + if if_name != name { + continue; + } + let family = (*addr.ifa_addr).sa_family; + let addr_len = match family as i32 { + libc::AF_INET => mem::size_of::(), + libc::AF_INET6 => mem::size_of::(), + _ => continue, + }; + + let (_, sock_addr) = socket2::SockAddr::try_init(|addr_storage, len| { + *len = addr_len as u32; + std::ptr::copy_nonoverlapping( + addr.ifa_addr as *const libc::c_void, + addr_storage as *mut _, + addr_len, + ); + Ok(()) + })?; + + if let Some(socket_addr) = sock_addr.as_socket() { + result.push(socket_addr.ip()); + } + } + } + result + } } #[instrument] diff --git a/tun/tests/configure.rs b/tun/tests/configure.rs index e7e2c6de..49a48598 100644 --- a/tun/tests/configure.rs +++ b/tun/tests/configure.rs @@ -47,9 +47,8 @@ fn test_set_get_ipv6() { let addr = Ipv6Addr::new(1, 1, 1, 1, 1, 1, 1, 1); tun.set_ipv6_addr(addr)?; - - // let result = tun.ipv6_addr()?; - // assert_eq!(addr, result); + let result = tun.ipv6_addrs()?[0]; + assert_eq!(addr, result); } #[test]