Add Support for IPV6 and Arbitrary Server Address
Add IPV6 support for Apple Devices Note: Works in GUI not CLI Adds Support for Arbitrary Server Address
This commit is contained in:
parent
cca5999214
commit
2088ae6ede
20 changed files with 276 additions and 56 deletions
|
|
@ -21,7 +21,7 @@ pub struct TunOptions {
|
|||
/// (Apple) Retrieve the tun interface
|
||||
pub tun_retrieve: bool,
|
||||
/// (Linux) The IP address of the tun interface.
|
||||
pub address: Option<String>,
|
||||
pub address: Vec<String>,
|
||||
}
|
||||
|
||||
impl TunOptions {
|
||||
|
|
@ -44,8 +44,8 @@ impl TunOptions {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn address(mut self, address: impl ToString) -> Self {
|
||||
self.address = Some(address.to_string());
|
||||
pub fn address(mut self, address: Vec<impl ToString>) -> Self {
|
||||
self.address = address.iter().map(|x| x.to_string()).collect();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ impl SysControlSocket for socket2::Socket {
|
|||
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| {
|
||||
socket2::SockAddr::try_init(|addr_storage, len| {
|
||||
*len = size_of::<sys::sockaddr_ctl>() as u32;
|
||||
|
||||
let addr: &mut sys::sockaddr_ctl = &mut *addr_storage.cast();
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
use std::{
|
||||
io::{Error, IoSlice},
|
||||
mem,
|
||||
net::{Ipv4Addr, 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, writev, AF_INET, AF_INET6, sockaddr_in6};
|
||||
use nix::sys::socket::SockaddrIn6;
|
||||
use socket2::{Domain, SockAddr, Socket, Type};
|
||||
use tracing::{self, instrument};
|
||||
|
||||
|
|
@ -49,7 +47,7 @@ impl TunInterface {
|
|||
pub fn retrieve() -> Option<TunInterface> {
|
||||
(3..100)
|
||||
.filter_map(|fd| unsafe {
|
||||
let peer_addr = socket2::SockAddr::init(|storage, len| {
|
||||
let peer_addr = socket2::SockAddr::try_init(|storage, len| {
|
||||
*len = mem::size_of::<sys::sockaddr_ctl>() as u32;
|
||||
libc::getpeername(fd, storage as *mut _, len);
|
||||
Ok(())
|
||||
|
|
@ -71,9 +69,12 @@ impl TunInterface {
|
|||
|
||||
#[throws]
|
||||
fn configure(&self, options: TunOptions) {
|
||||
if let Some(addr) = options.address {
|
||||
if let Ok(addr) = addr.parse() {
|
||||
self.set_ipv4_addr(addr)?;
|
||||
for addr in options.address{
|
||||
if let Ok(addr) = addr.parse::<IpAddr>() {
|
||||
match addr {
|
||||
IpAddr::V4(addr) => {self.set_ipv4_addr(addr)?}
|
||||
IpAddr::V6(addr) => {self.set_ipv6_addr(addr)?}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -117,6 +118,14 @@ impl TunInterface {
|
|||
iff
|
||||
}
|
||||
|
||||
#[throws]
|
||||
#[instrument]
|
||||
fn in6_ifreq(&self) -> sys::in6_ifreq {
|
||||
let mut iff: sys::in6_ifreq = unsafe { mem::zeroed() };
|
||||
iff.ifr_name = string_to_ifname(&self.name()?);
|
||||
iff
|
||||
}
|
||||
|
||||
#[throws]
|
||||
#[instrument]
|
||||
pub fn set_ipv4_addr(&self, addr: Ipv4Addr) {
|
||||
|
|
@ -136,6 +145,21 @@ impl TunInterface {
|
|||
Ipv4Addr::from(u32::from_be(addr.sin_addr.s_addr))
|
||||
}
|
||||
|
||||
#[throws]
|
||||
pub fn set_ipv6_addr(&self, addr: Ipv6Addr) {
|
||||
// let addr = SockAddr::from(SocketAddrV6::new(addr, 0, 0, 0));
|
||||
// println!("addr: {:?}", addr);
|
||||
// let mut iff = self.in6_ifreq()?;
|
||||
// let sto = addr.as_storage();
|
||||
// let ifadddr_ptr: *const sockaddr_in6 = addr_of!(sto).cast();
|
||||
// iff.ifr_ifru.ifru_addr = unsafe { *ifadddr_ptr };
|
||||
// println!("ifru addr set");
|
||||
// println!("{:?}", sys::SIOCSIFADDR_IN6);
|
||||
// self.perform6(|fd| unsafe { sys::if_set_addr6(fd, &iff) })?;
|
||||
// tracing::info!("ipv6_addr_set");
|
||||
tracing::warn!("Setting IPV6 address on MacOS CLI mode is not supported yet.");
|
||||
}
|
||||
|
||||
#[throws]
|
||||
fn perform<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
|
||||
let span = tracing::info_span!("perform", fd = self.as_raw_fd());
|
||||
|
|
@ -145,6 +169,15 @@ impl TunInterface {
|
|||
perform(socket.as_raw_fd())?
|
||||
}
|
||||
|
||||
#[throws]
|
||||
fn perform6<R>(&self, perform: impl FnOnce(RawFd) -> Result<R, nix::Error>) -> R {
|
||||
let span = tracing::info_span!("perform6", fd = self.as_raw_fd());
|
||||
let _enter = span.enter();
|
||||
|
||||
let socket = Socket::new(Domain::IPV6, Type::DGRAM, None)?;
|
||||
perform(socket.as_raw_fd())?
|
||||
}
|
||||
|
||||
#[throws]
|
||||
#[instrument]
|
||||
pub fn mtu(&self) -> i32 {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::mem;
|
||||
|
||||
use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr};
|
||||
use libc::{c_char, c_int, c_short, c_uint, c_ulong, sockaddr, sockaddr_in6, time_t};
|
||||
pub use libc::{
|
||||
c_void,
|
||||
sockaddr_ctl,
|
||||
|
|
@ -23,6 +23,7 @@ pub const UTUN_CONTROL_NAME: &str = "com.apple.net.utun_control";
|
|||
pub const UTUN_OPT_IFNAME: libc::c_int = 2;
|
||||
|
||||
pub const MAX_KCTL_NAME: usize = 96;
|
||||
pub const SCOPE6_ID_MAX: usize = 16;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -74,7 +75,107 @@ pub struct ifreq {
|
|||
pub ifr_ifru: ifr_ifru,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct in6_addrlifetime{
|
||||
pub ia6t_expire: time_t,
|
||||
pub ia6t_preferred: time_t,
|
||||
pub ia6t_vltime: u32,
|
||||
pub ia6t_pltime: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct in6_ifstat {
|
||||
pub ifs6_in_receive: u64,
|
||||
pub ifs6_in_hdrerr: u64,
|
||||
pub ifs6_in_toobig: u64,
|
||||
pub ifs6_in_noroute: u64,
|
||||
pub ifs6_in_addrerr: u64,
|
||||
pub ifs6_in_protounknown: u64,
|
||||
pub ifs6_in_truncated: u64,
|
||||
pub ifs6_in_discard: u64,
|
||||
pub ifs6_in_deliver: u64,
|
||||
pub ifs6_out_forward: u64,
|
||||
pub ifs6_out_request: u64,
|
||||
pub ifs6_out_discard: u64,
|
||||
pub ifs6_out_fragok: u64,
|
||||
pub ifs6_out_fragfail: u64,
|
||||
pub ifs6_out_fragcreat: u64,
|
||||
pub ifs6_reass_reqd: u64,
|
||||
pub ifs6_reass_ok: u64,
|
||||
pub ifs6_atmfrag_rcvd: u64,
|
||||
pub ifs6_reass_fail: u64,
|
||||
pub ifs6_in_mcast: u64,
|
||||
pub ifs6_out_mcast: u64,
|
||||
pub ifs6_cantfoward_icmp6: u64,
|
||||
pub ifs6_addr_expiry_cnt: u64,
|
||||
pub ifs6_pfx_expiry_cnt: u64,
|
||||
pub ifs6_defrtr_expiry_cnt: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct icmp6_ifstat {
|
||||
pub ifs6_in_msg: u64,
|
||||
pub ifs6_in_error: u64,
|
||||
pub ifs6_in_dstunreach: u64,
|
||||
pub ifs6_in_adminprohib: u64,
|
||||
pub ifs6_in_timeexceed: u64,
|
||||
pub ifs6_in_paramprob: u64,
|
||||
pub ifs6_in_pkttoobig: u64,
|
||||
pub ifs6_in_echo: u64,
|
||||
pub ifs6_in_echoreply: u64,
|
||||
pub ifs6_in_routersolicit: u64,
|
||||
pub ifs6_in_routeradvert: u64,
|
||||
pub ifs6_in_neighborsolicit: u64,
|
||||
pub ifs6_in_neighboradvert: u64,
|
||||
pub ifs6_in_redirect: u64,
|
||||
pub ifs6_in_mldquery: u64,
|
||||
pub ifs6_in_mldreport: u64,
|
||||
pub ifs6_in_mlddone: u64,
|
||||
pub ifs6_out_msg: u64,
|
||||
pub ifs6_out_error: u64,
|
||||
pub ifs6_out_dstunreach: u64,
|
||||
pub ifs6_out_adminprohib: u64,
|
||||
pub ifs6_out_timeexceed: u64,
|
||||
pub ifs6_out_paramprob: u64,
|
||||
pub ifs6_out_pkttoobig: u64,
|
||||
pub ifs6_out_echo: u64,
|
||||
pub ifs6_out_echoreply: u64,
|
||||
pub ifs6_out_routersolicit: u64,
|
||||
pub ifs6_out_routeradvert: u64,
|
||||
pub ifs6_out_neighborsolicit: u64,
|
||||
pub ifs6_out_neighboradvert: u64,
|
||||
pub ifs6_out_redirect: u64,
|
||||
pub ifs6_out_mldquery: u64,
|
||||
pub ifs6_out_mldreport: u64,
|
||||
pub ifs6_out_mlddone: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub union ifr_ifru6 {
|
||||
pub ifru_addr: sockaddr_in6,
|
||||
pub ifru_dstaddr: sockaddr_in6,
|
||||
pub ifru_flags: c_int,
|
||||
pub ifru_flags6: c_int,
|
||||
pub ifru_metric: c_int,
|
||||
pub ifru_intval: c_int,
|
||||
pub ifru_data: *mut c_char,
|
||||
pub ifru_lifetime: in6_addrlifetime, // ifru_lifetime
|
||||
pub ifru_stat: in6_ifstat,
|
||||
pub ifru_icmp6stat: icmp6_ifstat,
|
||||
pub ifru_scope_id: [u32; SCOPE6_ID_MAX]
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct in6_ifreq {
|
||||
pub ifr_name: [c_char; IFNAMSIZ],
|
||||
pub ifr_ifru: ifr_ifru6,
|
||||
}
|
||||
|
||||
pub const SIOCSIFADDR: c_ulong = request_code_write!(b'i', 12, mem::size_of::<ifreq>());
|
||||
pub const SIOCSIFADDR_IN6: c_ulong = request_code_write!(b'i', 12, mem::size_of::<in6_ifreq>());
|
||||
pub const SIOCGIFMTU: c_ulong = request_code_readwrite!(b'i', 51, mem::size_of::<ifreq>());
|
||||
pub const SIOCSIFMTU: c_ulong = request_code_write!(b'i', 52, mem::size_of::<ifreq>());
|
||||
pub const SIOCGIFNETMASK: c_ulong = request_code_readwrite!(b'i', 37, mem::size_of::<ifreq>());
|
||||
|
|
@ -97,5 +198,6 @@ ioctl_read_bad!(if_get_addr, libc::SIOCGIFADDR, ifreq);
|
|||
ioctl_read_bad!(if_get_mtu, SIOCGIFMTU, ifreq);
|
||||
ioctl_read_bad!(if_get_netmask, SIOCGIFNETMASK, ifreq);
|
||||
ioctl_write_ptr_bad!(if_set_addr, SIOCSIFADDR, ifreq);
|
||||
ioctl_write_ptr_bad!(if_set_addr6, SIOCSIFADDR_IN6, in6_ifreq);
|
||||
ioctl_write_ptr_bad!(if_set_mtu, SIOCSIFMTU, ifreq);
|
||||
ioctl_write_ptr_bad!(if_set_netmask, SIOCSIFNETMASK, ifreq);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue