support routing table for ios/macos
This commit is contained in:
		
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -1855,7 +1855,7 @@ dependencies = [
 | 
			
		||||
 "security-framework-sys",
 | 
			
		||||
 "serde 1.0.133",
 | 
			
		||||
 "serde_cbor",
 | 
			
		||||
 "serial_test 0.4.0",
 | 
			
		||||
 "serial_test 0.5.1",
 | 
			
		||||
 "simplelog",
 | 
			
		||||
 "snailquote",
 | 
			
		||||
 "tempfile",
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ fi
 | 
			
		||||
rustup target add aarch64-apple-darwin aarch64-apple-ios x86_64-apple-darwin x86_64-apple-ios
 | 
			
		||||
 | 
			
		||||
echo Manual Step:
 | 
			
		||||
echo   install +ios-arm64-nightly-YYYY-MM-DD toolchain for bitcode from https://github.com/getditto/rust-bitcode/releases/latest and unzip
 | 
			
		||||
echo   install +ios-arm64-1.57.0 toolchain for bitcode from https://github.com/getditto/rust-bitcode/releases/latest and unzip
 | 
			
		||||
echo   xattr -d -r com.apple.quarantine .
 | 
			
		||||
echo   ./install.sh
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,10 @@ ifstructs = "^0"
 | 
			
		||||
[target.'cfg(any(target_os = "android",target_os = "linux"))'.dependencies]
 | 
			
		||||
rtnetlink = { version = "^0", default-features = false, features = [ "smol_socket" ] }
 | 
			
		||||
 | 
			
		||||
# Dependencies for MacOS and iOS
 | 
			
		||||
#[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
 | 
			
		||||
# XXX
 | 
			
		||||
 | 
			
		||||
# Dependencies for iOS
 | 
			
		||||
[target.'cfg(target_os = "ios")'.dependencies]
 | 
			
		||||
simplelog = { version = "^0", optional = true }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ do
 | 
			
		||||
    if [ "$arch" == "arm64" ]; then
 | 
			
		||||
        echo arm64
 | 
			
		||||
        CARGO_TARGET=aarch64-apple-ios
 | 
			
		||||
        CARGO_TOOLCHAIN=+ios-arm64-nightly-2021-06-12
 | 
			
		||||
        CARGO_TOOLCHAIN=+ios-arm64-1.57.0
 | 
			
		||||
        #CARGO_TOOLCHAIN=
 | 
			
		||||
    elif [ "$arch" == "x86_64" ]; then
 | 
			
		||||
        echo x86_64
 | 
			
		||||
@@ -25,6 +25,6 @@ do
 | 
			
		||||
        echo Unsupported ARCH: $arch
 | 
			
		||||
        continue
 | 
			
		||||
    fi
 | 
			
		||||
    env -i PATH=/usr/bin:/bin:/usr/local/bin ~/.cargo/bin/cargo $CARGO_TOOLCHAIN build $EXTRA_CARGO_OPTIONS --target $CARGO_TARGET --manifest-path $CARGO_MANIFEST_PATH
 | 
			
		||||
    env -i PATH=/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin ~/.cargo/bin/cargo $CARGO_TOOLCHAIN build $EXTRA_CARGO_OPTIONS --target $CARGO_TARGET --manifest-path $CARGO_MANIFEST_PATH
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,487 @@
 | 
			
		||||
use super::*;
 | 
			
		||||
use libc::{
 | 
			
		||||
    close, freeifaddrs, getifaddrs, if_nametoindex, ifaddrs, ioctl, pid_t, sockaddr, sockaddr_in6,
 | 
			
		||||
    socket, sysctl, time_t, AF_INET6, CTL_NET, IFF_BROADCAST, IFF_LOOPBACK, IFF_RUNNING, IFNAMSIZ,
 | 
			
		||||
    NET_RT_FLAGS, PF_ROUTE, RTAX_DST, RTAX_GATEWAY, RTAX_MAX, RTA_DST, RTA_GATEWAY, RTF_GATEWAY,
 | 
			
		||||
    SOCK_DGRAM,
 | 
			
		||||
};
 | 
			
		||||
use sockaddr_tools::SockAddr;
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::io;
 | 
			
		||||
use std::os::raw::{c_int, c_uchar, c_ulong, c_ushort, c_void};
 | 
			
		||||
 | 
			
		||||
//const SIOCGIFFLAGS:c_ulong = 0xC0206911;
 | 
			
		||||
const SIOCGIFAFLAG_IN6: c_ulong = 0xC1206949;
 | 
			
		||||
const IN6_IFF_TEMPORARY: c_ushort = 0x0080;
 | 
			
		||||
const IN6_IFF_DEPRECATED: c_ushort = 0x0010;
 | 
			
		||||
const IN6_IFF_DYNAMIC: c_ushort = 0x0100;
 | 
			
		||||
 | 
			
		||||
macro_rules! set_name {
 | 
			
		||||
    ($name_field:expr, $name_str:expr) => {{
 | 
			
		||||
        let name_c = &::std::ffi::CString::new($name_str.to_owned()).map_err(|_| {
 | 
			
		||||
            ::std::io::Error::new(
 | 
			
		||||
                ::std::io::ErrorKind::InvalidInput,
 | 
			
		||||
                "malformed interface name",
 | 
			
		||||
            )
 | 
			
		||||
        })?;
 | 
			
		||||
        let name_slice = name_c.as_bytes_with_nul();
 | 
			
		||||
        if name_slice.len() > IFNAMSIZ {
 | 
			
		||||
            return Err(io::Error::new(::std::io::ErrorKind::InvalidInput, ""));
 | 
			
		||||
        }
 | 
			
		||||
        $name_field[..name_slice.len()].clone_from_slice(name_slice);
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
macro_rules! round_up {
 | 
			
		||||
    ($a:expr) => {
 | 
			
		||||
        if $a > 0 {
 | 
			
		||||
            1 + (($a - 1) | 3)
 | 
			
		||||
        } else {
 | 
			
		||||
            4
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct rt_msghdr {
 | 
			
		||||
    rtm_msglen: c_ushort,
 | 
			
		||||
    rtm_version: c_uchar,
 | 
			
		||||
    rtm_type: c_uchar,
 | 
			
		||||
    rtm_index: c_ushort,
 | 
			
		||||
    rtm_flags: c_int,
 | 
			
		||||
    rtm_addrs: c_int,
 | 
			
		||||
    rtm_pid: pid_t,
 | 
			
		||||
    rtm_seq: c_int,
 | 
			
		||||
    rtm_errno: c_int,
 | 
			
		||||
    rtm_use: c_int,
 | 
			
		||||
    rtm_inits: u32,
 | 
			
		||||
    rtm_rmx: rt_metrics,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct rt_metrics {
 | 
			
		||||
    rmx_locks: u32,
 | 
			
		||||
    rmx_mtu: u32,
 | 
			
		||||
    rmx_hopcount: u32,
 | 
			
		||||
    rmx_expire: i32,
 | 
			
		||||
    rmx_recvpipe: u32,
 | 
			
		||||
    rmx_sendpipe: u32,
 | 
			
		||||
    rmx_ssthresh: u32,
 | 
			
		||||
    rmx_rtt: u32,
 | 
			
		||||
    rmx_rttvar: u32,
 | 
			
		||||
    rmx_pksent: u32,
 | 
			
		||||
    rmx_state: u32,
 | 
			
		||||
    rmx_filler: [u32; 3],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct in6_addrlifetime {
 | 
			
		||||
    ia6t_expire: time_t,
 | 
			
		||||
    ia6t_preferred: time_t,
 | 
			
		||||
    ia6t_vltime: u32,
 | 
			
		||||
    ia6t_pltime: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct in6_ifstat {
 | 
			
		||||
    ifs6_in_receive: u64,
 | 
			
		||||
    ifs6_in_hdrerr: u64,
 | 
			
		||||
    ifs6_in_toobig: u64,
 | 
			
		||||
    ifs6_in_noroute: u64,
 | 
			
		||||
    ifs6_in_addrerr: u64,
 | 
			
		||||
    ifs6_in_protounknown: u64,
 | 
			
		||||
    ifs6_in_truncated: u64,
 | 
			
		||||
    ifs6_in_discard: u64,
 | 
			
		||||
    ifs6_in_deliver: u64,
 | 
			
		||||
    ifs6_out_forward: u64,
 | 
			
		||||
    ifs6_out_request: u64,
 | 
			
		||||
    ifs6_out_discard: u64,
 | 
			
		||||
    ifs6_out_fragok: u64,
 | 
			
		||||
    ifs6_out_fragfail: u64,
 | 
			
		||||
    ifs6_out_fragcreat: u64,
 | 
			
		||||
    ifs6_reass_reqd: u64,
 | 
			
		||||
    ifs6_reass_ok: u64,
 | 
			
		||||
    ifs6_atmfrag_rcvd: u64,
 | 
			
		||||
    ifs6_reass_fail: u64,
 | 
			
		||||
    ifs6_in_mcast: u64,
 | 
			
		||||
    ifs6_out_mcast: u64,
 | 
			
		||||
    ifs6_cantfoward_icmp6: u64,
 | 
			
		||||
    ifs6_addr_expiry_cnt: u64,
 | 
			
		||||
    ifs6_pfx_expiry_cnt: u64,
 | 
			
		||||
    ifs6_defrtr_expiry_cnt: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct icmp6_ifstat {
 | 
			
		||||
    ifs6_in_msg: u64,
 | 
			
		||||
    ifs6_in_error: u64,
 | 
			
		||||
    ifs6_in_dstunreach: u64,
 | 
			
		||||
    ifs6_in_adminprohib: u64,
 | 
			
		||||
    ifs6_in_timeexceed: u64,
 | 
			
		||||
    ifs6_in_paramprob: u64,
 | 
			
		||||
    ifs6_in_pkttoobig: u64,
 | 
			
		||||
    ifs6_in_echo: u64,
 | 
			
		||||
    ifs6_in_echoreply: u64,
 | 
			
		||||
    ifs6_in_routersolicit: u64,
 | 
			
		||||
    ifs6_in_routeradvert: u64,
 | 
			
		||||
    ifs6_in_neighborsolicit: u64,
 | 
			
		||||
    ifs6_in_neighboradvert: u64,
 | 
			
		||||
    ifs6_in_redirect: u64,
 | 
			
		||||
    ifs6_in_mldquery: u64,
 | 
			
		||||
    ifs6_in_mldreport: u64,
 | 
			
		||||
    ifs6_in_mlddone: u64,
 | 
			
		||||
    ifs6_out_msg: u64,
 | 
			
		||||
    ifs6_out_error: u64,
 | 
			
		||||
    ifs6_out_dstunreach: u64,
 | 
			
		||||
    ifs6_out_adminprohib: u64,
 | 
			
		||||
    ifs6_out_timeexceed: u64,
 | 
			
		||||
    ifs6_out_paramprob: u64,
 | 
			
		||||
    ifs6_out_pkttoobig: u64,
 | 
			
		||||
    ifs6_out_echo: u64,
 | 
			
		||||
    ifs6_out_echoreply: u64,
 | 
			
		||||
    ifs6_out_routersolicit: u64,
 | 
			
		||||
    ifs6_out_routeradvert: u64,
 | 
			
		||||
    ifs6_out_neighborsolicit: u64,
 | 
			
		||||
    ifs6_out_neighboradvert: u64,
 | 
			
		||||
    ifs6_out_redirect: u64,
 | 
			
		||||
    ifs6_out_mldquery: u64,
 | 
			
		||||
    ifs6_out_mldreport: u64,
 | 
			
		||||
    ifs6_out_mlddone: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
union IfrIfru {
 | 
			
		||||
    ifru_addr: sockaddr_in6,
 | 
			
		||||
    ifru_dstaddr: sockaddr_in6,
 | 
			
		||||
    ifru_flags: c_int,
 | 
			
		||||
    ifru_flags6: c_int,
 | 
			
		||||
    ifru_metric: c_int,
 | 
			
		||||
    ifru_intval: c_int,
 | 
			
		||||
    ifru_data: *mut c_uchar, // caddr_t
 | 
			
		||||
    ifru_lifetime: in6_addrlifetime,
 | 
			
		||||
    ifru_stat: in6_ifstat,
 | 
			
		||||
    ifru_icmp6stat: icmp6_ifstat,
 | 
			
		||||
    ifru_scope_id: [u32; 16],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
struct in6_ifreq {
 | 
			
		||||
    ifr_name: [c_uchar; IFNAMSIZ],
 | 
			
		||||
    ifr_ifru: IfrIfru,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl in6_ifreq {
 | 
			
		||||
    pub fn from_name(name: &str) -> io::Result<Self> {
 | 
			
		||||
        let mut req: in6_ifreq = unsafe { mem::zeroed() };
 | 
			
		||||
        req.set_name(name)?;
 | 
			
		||||
        Ok(req)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn set_name(&mut self, name: &str) -> io::Result<()> {
 | 
			
		||||
        set_name!(self.ifr_name, name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn set_addr(&mut self, addr: sockaddr_in6) {
 | 
			
		||||
        self.ifr_ifru.ifru_addr = addr;
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_flags6(&self) -> c_ushort {
 | 
			
		||||
        unsafe { self.ifr_ifru.ifru_flags6 as c_ushort }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn do_broadcast(ifaddr: &ifaddrs) -> Option<IpAddr> {
 | 
			
		||||
    sockaddr_tools::to_ipaddr(ifaddr.ifa_dstaddr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
pub struct IfAddrs {
 | 
			
		||||
    inner: *mut ifaddrs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IfAddrs {
 | 
			
		||||
    #[allow(unsafe_code, clippy::new_ret_no_self)]
 | 
			
		||||
    pub fn new() -> io::Result<Self> {
 | 
			
		||||
        let mut ifaddrs = mem::MaybeUninit::uninit();
 | 
			
		||||
 | 
			
		||||
        unsafe {
 | 
			
		||||
            if -1 == getifaddrs(ifaddrs.as_mut_ptr()) {
 | 
			
		||||
                return Err(io::Error::last_os_error());
 | 
			
		||||
            }
 | 
			
		||||
            Ok(Self {
 | 
			
		||||
                inner: ifaddrs.assume_init(),
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn iter(&self) -> IfAddrsIterator {
 | 
			
		||||
        IfAddrsIterator { next: self.inner }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for IfAddrs {
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            freeifaddrs(self.inner);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct IfAddrsIterator {
 | 
			
		||||
    next: *mut ifaddrs,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Iterator for IfAddrsIterator {
 | 
			
		||||
    type Item = ifaddrs;
 | 
			
		||||
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    fn next(&mut self) -> Option<Self::Item> {
 | 
			
		||||
        if self.next.is_null() {
 | 
			
		||||
            return None;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Some(unsafe {
 | 
			
		||||
            let result = *self.next;
 | 
			
		||||
            self.next = (*self.next).ifa_next;
 | 
			
		||||
 | 
			
		||||
            result
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
pub struct PlatformSupportApple {
 | 
			
		||||
    //
 | 
			
		||||
    default_route_interfaces: BTreeSet<u32>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PlatformSupportApple {
 | 
			
		||||
    pub fn new() -> Result<Self, String> {
 | 
			
		||||
        Ok(PlatformSupportApple {})
 | 
			
		||||
        Ok(PlatformSupportApple {
 | 
			
		||||
            default_route_interfaces: BTreeSet::new(),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn refresh_default_route_interfaces(&mut self) -> Result<(), String> {
 | 
			
		||||
        self.default_route_interfaces.clear();
 | 
			
		||||
 | 
			
		||||
        let mut mib = [CTL_NET, PF_ROUTE, 0, 0, NET_RT_FLAGS, RTF_GATEWAY];
 | 
			
		||||
        let mut sa_tab: [*const sockaddr; RTAX_MAX as usize] =
 | 
			
		||||
            [std::ptr::null(); RTAX_MAX as usize];
 | 
			
		||||
        let mut rt_buf_len = 0usize;
 | 
			
		||||
 | 
			
		||||
        // Get memory size for mib result
 | 
			
		||||
        if unsafe {
 | 
			
		||||
            sysctl(
 | 
			
		||||
                mib.as_mut_ptr(),
 | 
			
		||||
                mib.len() as u32,
 | 
			
		||||
                std::ptr::null_mut(),
 | 
			
		||||
                &mut rt_buf_len as *mut usize,
 | 
			
		||||
                std::ptr::null_mut(),
 | 
			
		||||
                0,
 | 
			
		||||
            )
 | 
			
		||||
        } < 0
 | 
			
		||||
        {
 | 
			
		||||
            return Err("Unable to get memory size for routing table".to_owned());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Allocate a buffer
 | 
			
		||||
        let mut rt_buf = vec![0u8; rt_buf_len];
 | 
			
		||||
 | 
			
		||||
        // Get mib result
 | 
			
		||||
        if unsafe {
 | 
			
		||||
            sysctl(
 | 
			
		||||
                mib.as_mut_ptr(),
 | 
			
		||||
                mib.len() as u32,
 | 
			
		||||
                rt_buf.as_mut_ptr() as *mut c_void,
 | 
			
		||||
                &mut rt_buf_len as *mut usize,
 | 
			
		||||
                std::ptr::null_mut(),
 | 
			
		||||
                0,
 | 
			
		||||
            )
 | 
			
		||||
        } < 0
 | 
			
		||||
        {
 | 
			
		||||
            return Err("Unable to get memory size for routing table".to_owned());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Process each routing message
 | 
			
		||||
        let mut mib_ptr = rt_buf.as_ptr();
 | 
			
		||||
        let mib_end = unsafe { mib_ptr.add(rt_buf_len) };
 | 
			
		||||
        while mib_ptr < mib_end {
 | 
			
		||||
            let rt = mib_ptr as *const rt_msghdr;
 | 
			
		||||
            let mut sa = unsafe { rt.add(1) } as *const sockaddr;
 | 
			
		||||
            let rtm_addrs = unsafe { (*rt).rtm_addrs };
 | 
			
		||||
            let intf_index = unsafe { (*rt).rtm_index } as u32;
 | 
			
		||||
 | 
			
		||||
            // Fill in sockaddr table
 | 
			
		||||
            for i in 0..(RTAX_MAX as usize) {
 | 
			
		||||
                if rtm_addrs & (1 << i) != 0 {
 | 
			
		||||
                    sa_tab[i] = sa;
 | 
			
		||||
                    sa = unsafe {
 | 
			
		||||
                        let sa_len = (*sa).sa_len;
 | 
			
		||||
                        sa = ((sa as *const u8).add(round_up!(sa_len as usize))) as *const sockaddr;
 | 
			
		||||
                        sa
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Look for gateways
 | 
			
		||||
            if rtm_addrs & (RTA_DST | RTA_GATEWAY) == (RTA_DST | RTA_GATEWAY) {
 | 
			
		||||
                // Only interested in AF_INET and AF_INET6 address families
 | 
			
		||||
                // SockAddr::new() takes care of this for us
 | 
			
		||||
                let saddr_dst = match SockAddr::new(sa_tab[RTAX_DST as usize]) {
 | 
			
		||||
                    Some(a) => a,
 | 
			
		||||
                    None => continue,
 | 
			
		||||
                };
 | 
			
		||||
                let _saddr_gateway = match SockAddr::new(sa_tab[RTAX_GATEWAY as usize]) {
 | 
			
		||||
                    Some(a) => a,
 | 
			
		||||
                    None => continue,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // Look for default gateways
 | 
			
		||||
                let dst_ipaddr = match saddr_dst.as_ipaddr() {
 | 
			
		||||
                    Some(a) => a,
 | 
			
		||||
                    None => continue,
 | 
			
		||||
                };
 | 
			
		||||
                if dst_ipaddr.is_unspecified() {
 | 
			
		||||
                    self.default_route_interfaces.insert(intf_index);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            mib_ptr = unsafe { mib_ptr.add((*rt).rtm_msglen.into()) };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_interface_flags(&self, index: u32, flags: c_int) -> Result<InterfaceFlags, String> {
 | 
			
		||||
        Ok(InterfaceFlags {
 | 
			
		||||
            is_loopback: (flags & IFF_LOOPBACK) != 0,
 | 
			
		||||
            is_running: (flags & IFF_RUNNING) != 0,
 | 
			
		||||
            has_default_route: self.default_route_interfaces.contains(&index),
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_address_flags(ifname: &str, addr: sockaddr_in6) -> Result<AddressFlags, String> {
 | 
			
		||||
        let mut req = in6_ifreq::from_name(&ifname).unwrap();
 | 
			
		||||
        req.set_addr(addr);
 | 
			
		||||
 | 
			
		||||
        let sock = unsafe { socket(AF_INET6, SOCK_DGRAM, 0) };
 | 
			
		||||
        if sock < 0 {
 | 
			
		||||
            return Err(format!("Socket error {:?}", io::Error::last_os_error()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let res = unsafe { ioctl(sock, SIOCGIFAFLAG_IN6, &mut req) };
 | 
			
		||||
        unsafe { close(sock) };
 | 
			
		||||
        if res < 0 {
 | 
			
		||||
            return Err(format!(
 | 
			
		||||
                "SIOCGIFAFLAG_IN6 failed with error on device '{}': {:?}",
 | 
			
		||||
                ifname,
 | 
			
		||||
                io::Error::last_os_error()
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let flags = req.get_flags6();
 | 
			
		||||
 | 
			
		||||
        Ok(AddressFlags {
 | 
			
		||||
            is_temporary: (flags & IN6_IFF_TEMPORARY) != 0,
 | 
			
		||||
            is_dynamic: (flags & IN6_IFF_DYNAMIC) != 0,
 | 
			
		||||
            is_deprecated: (flags & IN6_IFF_DEPRECATED) != 0,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn get_interfaces(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        interfaces: &mut BTreeMap<String, NetworkInterface>,
 | 
			
		||||
    ) -> Result<(), String> {
 | 
			
		||||
        //
 | 
			
		||||
        self.refresh_default_route_interfaces().await?;
 | 
			
		||||
 | 
			
		||||
        // If we have no routes, this isn't going to work
 | 
			
		||||
        if self.default_route_interfaces.is_empty() {
 | 
			
		||||
            return Err("no routes available for NetworkInterfaces".to_owned());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Ask for all the addresses we have
 | 
			
		||||
        let ifaddrs = IfAddrs::new().map_err(map_to_string)?;
 | 
			
		||||
        for ifaddr in ifaddrs.iter() {
 | 
			
		||||
            // Get the interface name
 | 
			
		||||
            let ifname = unsafe { CStr::from_ptr(ifaddr.ifa_name) }
 | 
			
		||||
                .to_string_lossy()
 | 
			
		||||
                .into_owned();
 | 
			
		||||
 | 
			
		||||
            // Get the interface index
 | 
			
		||||
            let ifindex = unsafe { if_nametoindex(ifaddr.ifa_name) };
 | 
			
		||||
 | 
			
		||||
            // Map the name to a NetworkInterface
 | 
			
		||||
            if !interfaces.contains_key(&ifname) {
 | 
			
		||||
                // If we have no NetworkInterface yet, make one
 | 
			
		||||
                let flags = self.get_interface_flags(ifindex, ifaddr.ifa_flags as c_int)?;
 | 
			
		||||
                interfaces.insert(ifname.clone(), NetworkInterface::new(ifname.clone(), flags));
 | 
			
		||||
            }
 | 
			
		||||
            let intf = interfaces.get_mut(&ifname).unwrap();
 | 
			
		||||
 | 
			
		||||
            let mut address_flags = AddressFlags::default();
 | 
			
		||||
 | 
			
		||||
            let intf_addr = match sockaddr_tools::to_ipaddr(ifaddr.ifa_addr) {
 | 
			
		||||
                None => continue,
 | 
			
		||||
                Some(IpAddr::V4(ipv4_addr)) => {
 | 
			
		||||
                    let netmask = match sockaddr_tools::to_ipaddr(ifaddr.ifa_netmask) {
 | 
			
		||||
                        Some(IpAddr::V4(netmask)) => netmask,
 | 
			
		||||
                        _ => Ipv4Addr::new(0, 0, 0, 0),
 | 
			
		||||
                    };
 | 
			
		||||
                    let broadcast = if (ifaddr.ifa_flags & (IFF_BROADCAST as u32)) != 0 {
 | 
			
		||||
                        match do_broadcast(&ifaddr) {
 | 
			
		||||
                            Some(IpAddr::V4(broadcast)) => Some(broadcast),
 | 
			
		||||
                            _ => None,
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        None
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    IfAddr::V4(Ifv4Addr {
 | 
			
		||||
                        ip: ipv4_addr,
 | 
			
		||||
                        netmask,
 | 
			
		||||
                        broadcast,
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
                Some(IpAddr::V6(ipv6_addr)) => {
 | 
			
		||||
                    let netmask = match sockaddr_tools::to_ipaddr(ifaddr.ifa_netmask) {
 | 
			
		||||
                        Some(IpAddr::V6(netmask)) => netmask,
 | 
			
		||||
                        _ => Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0),
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    // Get address flags for ipv6
 | 
			
		||||
                    address_flags = match Self::get_address_flags(
 | 
			
		||||
                        &ifname,
 | 
			
		||||
                        SockAddr::new(ifaddr.ifa_addr).unwrap().sa_in6(),
 | 
			
		||||
                    ) {
 | 
			
		||||
                        Ok(v) => v,
 | 
			
		||||
                        Err(e) => {
 | 
			
		||||
                            log_net!(error "{}", e);
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    IfAddr::V6(Ifv6Addr {
 | 
			
		||||
                        ip: ipv6_addr,
 | 
			
		||||
                        netmask,
 | 
			
		||||
                        broadcast: None,
 | 
			
		||||
                    })
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Add to the list
 | 
			
		||||
            intf.addrs
 | 
			
		||||
                .push(InterfaceAddress::new(intf_addr, address_flags));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,146 +0,0 @@
 | 
			
		||||
use super::*;
 | 
			
		||||
use crate::xx::*;
 | 
			
		||||
use jni::objects::JValue;
 | 
			
		||||
use std::io;
 | 
			
		||||
 | 
			
		||||
macro_rules! call_method_checked {
 | 
			
		||||
    ($env:expr, $obj:expr, $name:expr, $sig:expr, $args:expr, $kind:ident) => {
 | 
			
		||||
        $env.call_method($obj, $name, $sig, $args)
 | 
			
		||||
            .map_err(|e| {
 | 
			
		||||
                io::Error::new(
 | 
			
		||||
                    io::ErrorKind::Other,
 | 
			
		||||
                    format!("call_method {} {} failed: {}", $name, $sig, e),
 | 
			
		||||
                )
 | 
			
		||||
            })?
 | 
			
		||||
            .$kind()
 | 
			
		||||
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn get_if_addrs() -> io::Result<Vec<Interface>> {
 | 
			
		||||
    let aglock = ANDROID_GLOBALS.lock();
 | 
			
		||||
    let ag = aglock.as_ref().unwrap();
 | 
			
		||||
    let env = ag.vm.attach_current_thread().unwrap();
 | 
			
		||||
 | 
			
		||||
    let niclass = env.find_class("java/net/NetworkInterface").unwrap();
 | 
			
		||||
    let intfenum = env
 | 
			
		||||
        .call_static_method(
 | 
			
		||||
            niclass,
 | 
			
		||||
            "getNetworkInterfaces",
 | 
			
		||||
            "()Ljava/util/Enumeration;",
 | 
			
		||||
            &[],
 | 
			
		||||
        )
 | 
			
		||||
        .unwrap()
 | 
			
		||||
        .l()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    let mut out: Vec<Interface> = Vec::new();
 | 
			
		||||
    while call_method_checked!(env, intfenum, "hasMoreElements", "()Z", &[], z) {
 | 
			
		||||
        let intf =
 | 
			
		||||
            call_method_checked!(env, intfenum, "nextElement", "()Ljava/lang/Object;", &[], l);
 | 
			
		||||
 | 
			
		||||
        let nameobj = call_method_checked!(env, intf, "getName", "()Ljava/lang/String;", &[], l);
 | 
			
		||||
        let name_jstrval = env.get_string(JString::from(nameobj)).unwrap();
 | 
			
		||||
        let name = String::from(name_jstrval.to_string_lossy());
 | 
			
		||||
 | 
			
		||||
        let intfaddrs = call_method_checked!(
 | 
			
		||||
            env,
 | 
			
		||||
            intf,
 | 
			
		||||
            "getInterfaceAddresses",
 | 
			
		||||
            "()Ljava/util/List;",
 | 
			
		||||
            &[],
 | 
			
		||||
            l
 | 
			
		||||
        );
 | 
			
		||||
        let size = call_method_checked!(env, intfaddrs, "size", "()I", &[], i);
 | 
			
		||||
        for i in 0..size {
 | 
			
		||||
            let intfaddr = call_method_checked!(
 | 
			
		||||
                env,
 | 
			
		||||
                intfaddrs,
 | 
			
		||||
                "get",
 | 
			
		||||
                "(I)Ljava/lang/Object;",
 | 
			
		||||
                &[JValue::Int(i)],
 | 
			
		||||
                l
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            let ia_addr = call_method_checked!(
 | 
			
		||||
                env,
 | 
			
		||||
                intfaddr,
 | 
			
		||||
                "getAddress",
 | 
			
		||||
                "()Ljava/net/InetAddress;",
 | 
			
		||||
                &[],
 | 
			
		||||
                l
 | 
			
		||||
            );
 | 
			
		||||
            let ia_bcst = call_method_checked!(
 | 
			
		||||
                env,
 | 
			
		||||
                intfaddr,
 | 
			
		||||
                "getBroadcast",
 | 
			
		||||
                "()Ljava/net/InetAddress;",
 | 
			
		||||
                &[],
 | 
			
		||||
                l
 | 
			
		||||
            );
 | 
			
		||||
            let ia_plen =
 | 
			
		||||
                call_method_checked!(env, intfaddr, "getNetworkPrefixLength", "()S", &[], s);
 | 
			
		||||
 | 
			
		||||
            let ia_addr_bytearray =
 | 
			
		||||
                call_method_checked!(env, ia_addr, "getAddress", "()[B", &[], l);
 | 
			
		||||
            let ia_addr_bytearray_len = env.get_array_length(*ia_addr_bytearray).unwrap();
 | 
			
		||||
            let addr: IfAddr;
 | 
			
		||||
            if ia_addr_bytearray_len == 4 {
 | 
			
		||||
                let mut ia_addr_bytes_v4 = [0i8; 4];
 | 
			
		||||
                env.get_byte_array_region(*ia_addr_bytearray, 0, &mut ia_addr_bytes_v4)
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
 | 
			
		||||
                let broadcast = if !env.is_same_object(ia_bcst, JObject::null()).unwrap() {
 | 
			
		||||
                    let ia_bcst_bytearray =
 | 
			
		||||
                        call_method_checked!(env, ia_bcst, "getAddress", "()[B", &[], l);
 | 
			
		||||
                    let ia_bcst_bytearray_len = env.get_array_length(*ia_bcst_bytearray).unwrap();
 | 
			
		||||
                    if ia_bcst_bytearray_len != 4 {
 | 
			
		||||
                        warn!(
 | 
			
		||||
                            "mismatched inet4 broadcast address length: {}",
 | 
			
		||||
                            ia_bcst_bytearray_len
 | 
			
		||||
                        );
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let mut ia_bsct_bytes_v4 = [0i8; 4];
 | 
			
		||||
                    env.get_byte_array_region(*ia_bcst_bytearray, 0, &mut ia_bsct_bytes_v4)
 | 
			
		||||
                        .unwrap();
 | 
			
		||||
 | 
			
		||||
                    Some(Ipv4Addr::from(convert_to_unsigned_4(ia_bsct_bytes_v4)))
 | 
			
		||||
                } else {
 | 
			
		||||
                    None
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut ia_netmask_bytes_v4 = [0u8; 4];
 | 
			
		||||
                get_netmask_from_prefix_length_v4(&mut ia_netmask_bytes_v4, ia_plen);
 | 
			
		||||
                addr = IfAddr::V4(Ifv4Addr {
 | 
			
		||||
                    ip: Ipv4Addr::from(convert_to_unsigned_4(ia_addr_bytes_v4)),
 | 
			
		||||
                    netmask: Ipv4Addr::from(ia_netmask_bytes_v4),
 | 
			
		||||
                    broadcast: broadcast,
 | 
			
		||||
                });
 | 
			
		||||
            } else if ia_addr_bytearray_len == 16 {
 | 
			
		||||
                let mut ia_addr_bytes_v6 = [0i8; 16];
 | 
			
		||||
                env.get_byte_array_region(*ia_addr_bytearray, 0, &mut ia_addr_bytes_v6)
 | 
			
		||||
                    .unwrap();
 | 
			
		||||
 | 
			
		||||
                let mut ia_netmask_bytes_v6 = [0u8; 16];
 | 
			
		||||
                get_netmask_from_prefix_length_v6(&mut ia_netmask_bytes_v6, ia_plen);
 | 
			
		||||
                addr = IfAddr::V6(Ifv6Addr {
 | 
			
		||||
                    ip: Ipv6Addr::from(convert_to_unsigned_16(ia_addr_bytes_v6)),
 | 
			
		||||
                    netmask: Ipv6Addr::from(ia_netmask_bytes_v6),
 | 
			
		||||
                    broadcast: None,
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                warn!("weird inet address length: {}", ia_addr_bytearray_len);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            let elem = Interface {
 | 
			
		||||
                name: name.clone(),
 | 
			
		||||
                addr: addr,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            out.push(elem);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(out)
 | 
			
		||||
}
 | 
			
		||||
@@ -1,232 +0,0 @@
 | 
			
		||||
#![allow(dead_code)]
 | 
			
		||||
use super::*;
 | 
			
		||||
use crate::xx::*;
 | 
			
		||||
use hex::FromHex;
 | 
			
		||||
use if_addrs::{IfAddr, Ifv4Addr, Ifv6Addr};
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::{BufRead, BufReader, Error, ErrorKind};
 | 
			
		||||
use std::net::{Ipv4Addr, Ipv6Addr};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ProcNetIpv6RouteEntry {
 | 
			
		||||
    dest_network: Ipv6Addr,
 | 
			
		||||
    dest_prefix: u8,
 | 
			
		||||
    src_network: Ipv6Addr,
 | 
			
		||||
    src_prefix: u8,
 | 
			
		||||
    next_hop: Ipv6Addr,
 | 
			
		||||
    metric: u32,
 | 
			
		||||
    ref_count: u32,
 | 
			
		||||
    use_count: u32,
 | 
			
		||||
    flags: u32,
 | 
			
		||||
    intf_name: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ProcNetRouteEntry {
 | 
			
		||||
    iface: String,
 | 
			
		||||
    destination: Ipv4Addr,
 | 
			
		||||
    gateway: Ipv4Addr,
 | 
			
		||||
    flags: u16,
 | 
			
		||||
    ref_count: u32,
 | 
			
		||||
    use_count: u32,
 | 
			
		||||
    metric: u32,
 | 
			
		||||
    mask: Ipv4Addr,
 | 
			
		||||
    mtu: u32,
 | 
			
		||||
    window: u32,
 | 
			
		||||
    irtt: u32,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct PlatformSupport {
 | 
			
		||||
    proc_net_ipv6_route: Vec<ProcNetIpv6RouteEntry>,
 | 
			
		||||
    proc_net_route: Vec<ProcNetRouteEntry>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl PlatformSupport {
 | 
			
		||||
    fn parse_proc_net_ipv6_route() -> Result<Vec<ProcNetIpv6RouteEntry>, Error> {
 | 
			
		||||
        let file = File::open("/proc/net/ipv6_route")?;
 | 
			
		||||
        let reader = BufReader::new(file);
 | 
			
		||||
        let mut ipv6_route: Vec<ProcNetIpv6RouteEntry> = Vec::new();
 | 
			
		||||
        for line in reader.lines() {
 | 
			
		||||
            let line = line?;
 | 
			
		||||
            let line: Vec<&str> = line.split_ascii_whitespace().collect();
 | 
			
		||||
            if line.len() != 10 {
 | 
			
		||||
                return Err(Error::new(
 | 
			
		||||
                    ErrorKind::InvalidData,
 | 
			
		||||
                    "Unexpected number of columns in /proc/net/ipv6_route",
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let entry =
 | 
			
		||||
                ProcNetIpv6RouteEntry {
 | 
			
		||||
                    dest_network: Ipv6Addr::from(<[u8; 16]>::from_hex(line[0]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse dest_network")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    dest_prefix: <[u8; 1]>::from_hex(line[1]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse dest_prefix")
 | 
			
		||||
                    })?[0],
 | 
			
		||||
                    src_network: Ipv6Addr::from(<[u8; 16]>::from_hex(line[2]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse src_network")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    src_prefix: <[u8; 1]>::from_hex(line[3]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse src_prefix")
 | 
			
		||||
                    })?[0],
 | 
			
		||||
                    next_hop: Ipv6Addr::from(<[u8; 16]>::from_hex(line[4]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse next_hop")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    metric: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse metric")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    ref_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[6]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse ref_count")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    use_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[7]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse use_count")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    flags: u32::from_be_bytes(<[u8; 4]>::from_hex(line[8]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse flags")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    intf_name: String::from(line[9]),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            ipv6_route.push(entry)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(ipv6_route)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_proc_net_route() -> Result<Vec<ProcNetRouteEntry>, Error> {
 | 
			
		||||
        let file = File::open("/proc/net/route")?;
 | 
			
		||||
        let reader = BufReader::new(file);
 | 
			
		||||
        let mut route: Vec<ProcNetRouteEntry> = Vec::new();
 | 
			
		||||
        let mut first = false;
 | 
			
		||||
        for line in reader.lines() {
 | 
			
		||||
            let line = line?;
 | 
			
		||||
            let line: Vec<&str> = line.split_ascii_whitespace().collect();
 | 
			
		||||
            if line.len() != 11 {
 | 
			
		||||
                return Err(Error::new(
 | 
			
		||||
                    ErrorKind::InvalidData,
 | 
			
		||||
                    "Unexpected number of columns in /proc/net/route",
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            if first {
 | 
			
		||||
                if line
 | 
			
		||||
                    != [
 | 
			
		||||
                        "Iface",
 | 
			
		||||
                        "Destination",
 | 
			
		||||
                        "Gateway",
 | 
			
		||||
                        "Flags",
 | 
			
		||||
                        "RefCnt",
 | 
			
		||||
                        "Use",
 | 
			
		||||
                        "Metric",
 | 
			
		||||
                        "Mask",
 | 
			
		||||
                        "MTU",
 | 
			
		||||
                        "Window",
 | 
			
		||||
                        "IRTT",
 | 
			
		||||
                    ]
 | 
			
		||||
                {
 | 
			
		||||
                    return Err(Error::new(
 | 
			
		||||
                        ErrorKind::InvalidData,
 | 
			
		||||
                        format!("Unexpected columns in /proc/net/route: {:?}", line),
 | 
			
		||||
                    ));
 | 
			
		||||
                }
 | 
			
		||||
                first = false;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            let entry =
 | 
			
		||||
                ProcNetRouteEntry {
 | 
			
		||||
                    iface: String::from(line[0]),
 | 
			
		||||
 | 
			
		||||
                    destination: Ipv4Addr::from(u32::from_le_bytes(
 | 
			
		||||
                        <[u8; 4]>::from_hex(line[0]).map_err(|_| {
 | 
			
		||||
                            Error::new(ErrorKind::InvalidData, "Unable to parse destination")
 | 
			
		||||
                        })?,
 | 
			
		||||
                    )),
 | 
			
		||||
                    gateway: Ipv4Addr::from(u32::from_le_bytes(
 | 
			
		||||
                        <[u8; 4]>::from_hex(line[0]).map_err(|_| {
 | 
			
		||||
                            Error::new(ErrorKind::InvalidData, "Unable to parse gateway")
 | 
			
		||||
                        })?,
 | 
			
		||||
                    )),
 | 
			
		||||
                    flags: u16::from_be_bytes(<[u8; 2]>::from_hex(line[8]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse flags")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    ref_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[6]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse ref_count")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    use_count: u32::from_be_bytes(<[u8; 4]>::from_hex(line[7]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse use_count")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    metric: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse metric")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    mask: Ipv4Addr::from(u32::from_le_bytes(
 | 
			
		||||
                        <[u8; 4]>::from_hex(line[0]).map_err(|_| {
 | 
			
		||||
                            Error::new(ErrorKind::InvalidData, "Unable to parse mask")
 | 
			
		||||
                        })?,
 | 
			
		||||
                    )),
 | 
			
		||||
                    mtu: u32::from_be_bytes(
 | 
			
		||||
                        <[u8; 4]>::from_hex(line[5]).map_err(|_| {
 | 
			
		||||
                            Error::new(ErrorKind::InvalidData, "Unable to parse mtu")
 | 
			
		||||
                        })?,
 | 
			
		||||
                    ),
 | 
			
		||||
                    window: u32::from_be_bytes(<[u8; 4]>::from_hex(line[5]).map_err(|_| {
 | 
			
		||||
                        Error::new(ErrorKind::InvalidData, "Unable to parse window")
 | 
			
		||||
                    })?),
 | 
			
		||||
                    irtt: u32::from_be_bytes(
 | 
			
		||||
                        <[u8; 4]>::from_hex(line[5]).map_err(|_| {
 | 
			
		||||
                            Error::new(ErrorKind::InvalidData, "Unable to parse irtt")
 | 
			
		||||
                        })?,
 | 
			
		||||
                    ),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            route.push(entry)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(route)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn new() -> Result<Self, Error> {
 | 
			
		||||
        // Read /proc/net/ipv6_route
 | 
			
		||||
        let proc_net_ipv6_route = Self::parse_proc_net_ipv6_route().unwrap_or_default();
 | 
			
		||||
        // Read /proc/net/route
 | 
			
		||||
        let proc_net_route = Self::parse_proc_net_route().unwrap_or_default();
 | 
			
		||||
 | 
			
		||||
        trace!("proc_net_ipv6_route: {:#?}", proc_net_ipv6_route);
 | 
			
		||||
        trace!("proc_net_route: {:#?}", proc_net_route);
 | 
			
		||||
 | 
			
		||||
        // At least one routing table must be available
 | 
			
		||||
        if proc_net_ipv6_route.is_empty() && proc_net_route.is_empty() {
 | 
			
		||||
            return Err(Error::new(
 | 
			
		||||
                ErrorKind::InvalidData,
 | 
			
		||||
                "No routing tables available",
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            proc_net_ipv6_route,
 | 
			
		||||
            proc_net_route,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn has_default_route(&self, name: &str) -> bool {
 | 
			
		||||
        for e in &self.proc_net_ipv6_route {
 | 
			
		||||
            if e.intf_name == name && e.dest_prefix == 0u8 {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for e in &self.proc_net_route {
 | 
			
		||||
            if e.iface == name && e.mask == Ipv4Addr::new(0, 0, 0, 0) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        false
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_address_flags(&self, _addr: &IfAddr) -> AddressFlags {
 | 
			
		||||
        AddressFlags {
 | 
			
		||||
            is_temporary: false,
 | 
			
		||||
            is_dynamic: false,
 | 
			
		||||
            is_deprecated: false,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
use crate::xx::*;
 | 
			
		||||
use crate::*;
 | 
			
		||||
use core::fmt;
 | 
			
		||||
mod tools;
 | 
			
		||||
 | 
			
		||||
cfg_if::cfg_if! {
 | 
			
		||||
    if #[cfg(any(target_os = "linux", target_os = "android"))] {
 | 
			
		||||
@@ -12,6 +11,7 @@ cfg_if::cfg_if! {
 | 
			
		||||
        use windows::PlatformSupportWindows as PlatformSupport;
 | 
			
		||||
    } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
 | 
			
		||||
        mod apple;
 | 
			
		||||
        mod sockaddr_tools;
 | 
			
		||||
        use apple::PlatformSupportApple as PlatformSupport;
 | 
			
		||||
    } else {
 | 
			
		||||
        compile_error!("No network interfaces support for this platform!");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,117 @@
 | 
			
		||||
// Copyright 2018 MaidSafe.net limited.
 | 
			
		||||
//
 | 
			
		||||
// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
 | 
			
		||||
// http://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
 | 
			
		||||
// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
 | 
			
		||||
// modified, or distributed except according to those terms. Please review the Licences for the
 | 
			
		||||
// specific language governing permissions and limitations relating to use of the SAFE Network
 | 
			
		||||
// Software.
 | 
			
		||||
 | 
			
		||||
#[cfg(not(windows))]
 | 
			
		||||
use libc::{sockaddr, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6};
 | 
			
		||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
 | 
			
		||||
use std::ptr::NonNull;
 | 
			
		||||
#[cfg(windows)]
 | 
			
		||||
use winapi::{
 | 
			
		||||
    shared::ws2def::{AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in},
 | 
			
		||||
    shared::ws2ipdef::SOCKADDR_IN6 as sockaddr_in6,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub fn to_ipaddr(sockaddr: *const sockaddr) -> Option<IpAddr> {
 | 
			
		||||
    if sockaddr.is_null() {
 | 
			
		||||
        return None;
 | 
			
		||||
    }
 | 
			
		||||
    SockAddr::new(sockaddr)?.as_ipaddr()
 | 
			
		||||
}
 | 
			
		||||
pub enum SockAddrIn {
 | 
			
		||||
    In(sockaddr_in),
 | 
			
		||||
    In6(sockaddr_in6),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wrapper around a sockaddr pointer. Guaranteed to not be null.
 | 
			
		||||
pub struct SockAddr {
 | 
			
		||||
    inner: NonNull<sockaddr>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SockAddr {
 | 
			
		||||
    #[allow(clippy::new_ret_no_self)]
 | 
			
		||||
    pub fn new(sockaddr: *const sockaddr) -> Option<Self> {
 | 
			
		||||
        NonNull::new(sockaddr as *mut _).map(|inner| Self { inner })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(windows))]
 | 
			
		||||
    pub fn as_ipaddr(&self) -> Option<IpAddr> {
 | 
			
		||||
        match self.sockaddr_in() {
 | 
			
		||||
            Some(SockAddrIn::In(sa)) => Some(IpAddr::V4(Ipv4Addr::new(
 | 
			
		||||
                ((sa.sin_addr.s_addr) & 255) as u8,
 | 
			
		||||
                ((sa.sin_addr.s_addr >> 8) & 255) as u8,
 | 
			
		||||
                ((sa.sin_addr.s_addr >> 16) & 255) as u8,
 | 
			
		||||
                ((sa.sin_addr.s_addr >> 24) & 255) as u8,
 | 
			
		||||
            ))),
 | 
			
		||||
            Some(SockAddrIn::In6(sa)) => {
 | 
			
		||||
                // Ignore all fe80:: addresses as these are link locals
 | 
			
		||||
                if sa.sin6_addr.s6_addr[0] == 0xfe && sa.sin6_addr.s6_addr[1] == 0x80 {
 | 
			
		||||
                    return None;
 | 
			
		||||
                }
 | 
			
		||||
                Some(IpAddr::V6(Ipv6Addr::from(sa.sin6_addr.s6_addr)))
 | 
			
		||||
            }
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(windows)]
 | 
			
		||||
    pub fn as_ipaddr(&self) -> Option<IpAddr> {
 | 
			
		||||
        match self.sockaddr_in() {
 | 
			
		||||
            Some(SockAddrIn::In(sa)) => {
 | 
			
		||||
                let s_addr = unsafe { sa.sin_addr.S_un.S_addr() };
 | 
			
		||||
                // Ignore all 169.254.x.x addresses as these are not active interfaces
 | 
			
		||||
                if s_addr & 65535 == 0xfea9 {
 | 
			
		||||
                    return None;
 | 
			
		||||
                }
 | 
			
		||||
                Some(IpAddr::V4(Ipv4Addr::new(
 | 
			
		||||
                    ((s_addr >> 0) & 255u32) as u8,
 | 
			
		||||
                    ((s_addr >> 8) & 255u32) as u8,
 | 
			
		||||
                    ((s_addr >> 16) & 255u32) as u8,
 | 
			
		||||
                    ((s_addr >> 24) & 255u32) as u8,
 | 
			
		||||
                )))
 | 
			
		||||
            }
 | 
			
		||||
            Some(SockAddrIn::In6(sa)) => {
 | 
			
		||||
                let s6_addr = unsafe { sa.sin6_addr.u.Byte() };
 | 
			
		||||
                // Ignore all fe80:: addresses as these are link locals
 | 
			
		||||
                if s6_addr[0] == 0xfe && s6_addr[1] == 0x80 {
 | 
			
		||||
                    return None;
 | 
			
		||||
                }
 | 
			
		||||
                Some(IpAddr::V6(Ipv6Addr::from(s6_addr.clone())))
 | 
			
		||||
            }
 | 
			
		||||
            None => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn sockaddr_in(&self) -> Option<SockAddrIn> {
 | 
			
		||||
        const AF_INET_U32: u32 = AF_INET as u32;
 | 
			
		||||
        const AF_INET6_U32: u32 = AF_INET6 as u32;
 | 
			
		||||
 | 
			
		||||
        match self.sa_family() {
 | 
			
		||||
            AF_INET_U32 => Some(SockAddrIn::In(self.sa_in())),
 | 
			
		||||
            AF_INET6_U32 => Some(SockAddrIn::In6(self.sa_in6())),
 | 
			
		||||
            _ => None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    pub fn sa_family(&self) -> u32 {
 | 
			
		||||
        unsafe { u32::from(self.inner.as_ref().sa_family) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    #[allow(clippy::cast_ptr_alignment)]
 | 
			
		||||
    pub fn sa_in(&self) -> sockaddr_in {
 | 
			
		||||
        unsafe { *(self.inner.as_ptr() as *const sockaddr_in) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(unsafe_code)]
 | 
			
		||||
    #[allow(clippy::cast_ptr_alignment)]
 | 
			
		||||
    pub fn sa_in6(&self) -> sockaddr_in6 {
 | 
			
		||||
        unsafe { *(self.inner.as_ptr() as *const sockaddr_in6) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -18,8 +18,8 @@
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
		4317C6BA2694A675009C717F /* veilidcore-tests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "veilidcore-tests-Bridging-Header.h"; sourceTree = "<group>"; };
 | 
			
		||||
		4317C6BB2694A676009C717F /* veilid-core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = veilid-core.h; sourceTree = "<group>"; };
 | 
			
		||||
		4317C6BC2694A676009C717F /* veilid-core.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = veilid-core.c; sourceTree = "<group>"; };
 | 
			
		||||
		4317C6BB2694A676009C717F /* veilid-core.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "veilid-core.h"; sourceTree = "<group>"; };
 | 
			
		||||
		4317C6BC2694A676009C717F /* veilid-core.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "veilid-core.c"; sourceTree = "<group>"; };
 | 
			
		||||
		43C436AC268904AC002D11C5 /* veilidcore-tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "veilidcore-tests.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		43C436AF268904AC002D11C5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 | 
			
		||||
		43C436B1268904AC002D11C5 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
 | 
			
		||||
@@ -339,11 +339,11 @@
 | 
			
		||||
				);
 | 
			
		||||
				OTHER_LDFLAGS = "";
 | 
			
		||||
				"OTHER_LDFLAGS[sdk=iphoneos*]" = (
 | 
			
		||||
					"-L../../../../target/aarch64-apple-ios/debug",
 | 
			
		||||
					"-L../../../../../target/aarch64-apple-ios/debug",
 | 
			
		||||
					"-lveilid_core",
 | 
			
		||||
				);
 | 
			
		||||
				"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
 | 
			
		||||
					"-L../../../../target/x86_64-apple-ios/debug",
 | 
			
		||||
					"-L../../../../../target/x86_64-apple-ios/debug",
 | 
			
		||||
					"-lveilid_core",
 | 
			
		||||
				);
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = "com.veilid.veilidcore-tests";
 | 
			
		||||
@@ -371,11 +371,11 @@
 | 
			
		||||
				);
 | 
			
		||||
				OTHER_LDFLAGS = "";
 | 
			
		||||
				"OTHER_LDFLAGS[sdk=iphoneos*]" = (
 | 
			
		||||
					"-L../../../../target/aarch64-apple-ios/release",
 | 
			
		||||
					"-L../../../../../target/aarch64-apple-ios/release",
 | 
			
		||||
					"-lveilid_core",
 | 
			
		||||
				);
 | 
			
		||||
				"OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
 | 
			
		||||
					"-L../../../../target/x86_64-apple-ios/release",
 | 
			
		||||
					"-L../../../../../target/x86_64-apple-ios/release",
 | 
			
		||||
					"-lveilid_core",
 | 
			
		||||
				);
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = "com.veilid.veilidcore-tests";
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user