android fixes

This commit is contained in:
John Smith
2022-01-06 08:41:36 -05:00
parent ffe0a42dd3
commit e412e47474
6 changed files with 148 additions and 44 deletions

View File

@@ -79,8 +79,10 @@ pub struct InterfaceFlags {
/// Some of the flags associated with an address.
#[derive(Debug, Default, PartialEq, Eq, Ord, PartialOrd, Hash, Clone, Copy)]
pub struct AddressFlags {
pub is_temporary: bool,
// common flags
pub is_dynamic: bool,
// ipv6 flags
pub is_temporary: bool,
pub is_deprecated: bool,
}
@@ -90,6 +92,84 @@ pub struct InterfaceAddress {
flags: AddressFlags,
}
use core::cmp::Ordering;
impl Ord for InterfaceAddress {
fn cmp(&self, other: &Self) -> Ordering {
match (&self.if_addr, &other.if_addr) {
(IfAddr::V4(a), IfAddr::V4(b)) => {
// global scope addresses are better
let ret = ipv4addr_is_global(&a.ip).cmp(&ipv4addr_is_global(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// local scope addresses are better
let ret = ipv4addr_is_private(&a.ip).cmp(&ipv4addr_is_private(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// non-dynamic addresses are better
let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
if ret != Ordering::Equal {
return ret;
}
}
(IfAddr::V6(a), IfAddr::V6(b)) => {
// non-deprecated addresses are better
let ret = (!self.flags.is_deprecated).cmp(&!other.flags.is_deprecated);
if ret != Ordering::Equal {
return ret;
}
// non-temporary address are better
let ret = (!self.flags.is_temporary).cmp(&!other.flags.is_temporary);
if ret != Ordering::Equal {
return ret;
}
// global scope addresses are better
let ret = ipv6addr_is_global(&a.ip).cmp(&ipv6addr_is_global(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// unique local unicast addresses are better
let ret = ipv6addr_is_unique_local(&a.ip).cmp(&ipv6addr_is_unique_local(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// unicast site local addresses are better
let ret = ipv6addr_is_unicast_site_local(&a.ip)
.cmp(&ipv6addr_is_unicast_site_local(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// unicast link local addresses are better
let ret = ipv6addr_is_unicast_link_local(&a.ip)
.cmp(&ipv6addr_is_unicast_link_local(&b.ip));
if ret != Ordering::Equal {
return ret;
}
// non-dynamic addresses are better
let ret = (!self.flags.is_dynamic).cmp(&!other.flags.is_dynamic);
if ret != Ordering::Equal {
return ret;
}
}
(IfAddr::V4(_), IfAddr::V6(_)) => return Ordering::Less,
(IfAddr::V6(_), IfAddr::V4(_)) => return Ordering::Greater,
}
// stable sort
let ret = self.if_addr.cmp(&other.if_addr);
if ret != Ordering::Equal {
return ret;
}
self.flags.cmp(&other.flags)
}
}
impl PartialOrd for InterfaceAddress {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[allow(dead_code)]
impl InterfaceAddress {
pub fn new(if_addr: IfAddr, flags: AddressFlags) -> Self {
@@ -158,33 +238,35 @@ impl NetworkInterface {
}
pub fn primary_ipv4(&self) -> Option<Ipv4Addr> {
// see if we have a non-dynamic address to use first
let mut best_dynamic: Option<Ipv4Addr> = None;
for x in self.addrs.iter() {
if let IfAddr::V4(a) = x.if_addr() {
if !x.is_dynamic() {
return Some(a.ip);
} else if best_dynamic.is_none() {
best_dynamic = Some(a.ip);
}
}
}
best_dynamic
let mut ipv4addrs: Vec<&InterfaceAddress> = self
.addrs
.iter()
.filter(|a| matches!(a.if_addr(), IfAddr::V4(_)))
.collect();
ipv4addrs.sort();
ipv4addrs
.last()
.map(|x| match x.if_addr() {
IfAddr::V4(v4) => Some(v4.ip),
_ => None,
})
.flatten()
}
pub fn primary_ipv6(&self) -> Option<Ipv6Addr> {
let mut best_dynamic: Option<Ipv6Addr> = None;
for x in self.addrs.iter() {
if let IfAddr::V6(a) = x.if_addr() {
if x.is_temporary() || x.is_deprecated() {
if !x.is_dynamic() {
return Some(a.ip);
} else if best_dynamic.is_none() {
best_dynamic = Some(a.ip);
}
}
}
}
best_dynamic
let mut ipv6addrs: Vec<&InterfaceAddress> = self
.addrs
.iter()
.filter(|a| matches!(a.if_addr(), IfAddr::V6(_)))
.collect();
ipv6addrs.sort();
ipv6addrs
.last()
.map(|x| match x.if_addr() {
IfAddr::V6(v6) => Some(v6.ip),
_ => None,
})
.flatten()
}
}

View File

@@ -4,11 +4,13 @@ use alloc::collections::btree_map::Entry;
use futures_util::stream::TryStreamExt;
use ifstructs::ifreq;
use libc::{
close, if_indextoname, ioctl, socket, IFA_F_DADFAILED, IFA_F_DEPRECATED, IFA_F_PERMANENT,
IFA_F_TEMPORARY, IFA_F_TENTATIVE, IFF_LOOPBACK, IFF_RUNNING, IF_NAMESIZE, SIOCGIFFLAGS,
close, if_indextoname, ioctl, socket, IFF_LOOPBACK, IFF_RUNNING, IF_NAMESIZE, SIOCGIFFLAGS,
SOCK_DGRAM,
};
use rtnetlink::packet::{nlas::address::Nla, AddressMessage, AF_INET, AF_INET6};
use rtnetlink::packet::{
nlas::address::Nla, AddressMessage, AF_INET, AF_INET6, IFA_F_DADFAILED, IFA_F_DEPRECATED,
IFA_F_PERMANENT, IFA_F_TEMPORARY, IFA_F_TENTATIVE,
};
use rtnetlink::{new_connection_with_socket, sys::SmolSocket, Handle, IpVersion};
use std::convert::TryInto;
use std::ffi::CStr;
@@ -18,9 +20,18 @@ use tools::*;
fn get_interface_name(index: u32) -> Result<String, String> {
let mut ifnamebuf = [0u8; (IF_NAMESIZE + 1)];
if unsafe { if_indextoname(index, ifnamebuf.as_mut_ptr() as *mut i8) }.is_null() {
return Err("if_indextoname returned null".to_owned());
cfg_if! {
if #[cfg(all(target_os = "android", target_arch = "aarch64"))] {
if unsafe { if_indextoname(index, ifnamebuf.as_mut_ptr()) }.is_null() {
return Err("if_indextoname returned null".to_owned());
}
} else {
if unsafe { if_indextoname(index, ifnamebuf.as_mut_ptr() as *mut i8) }.is_null() {
return Err("if_indextoname returned null".to_owned());
}
}
}
let ifnamebuflen = ifnamebuf
.iter()
.position(|c| *c == 0u8)
@@ -95,7 +106,13 @@ impl PlatformSupportNetlink {
return Err(io::Error::last_os_error()).map_err(map_to_string);
}
let res = unsafe { ioctl(sock, SIOCGIFFLAGS, &mut req) };
cfg_if! {
if #[cfg(target_os = "android")] {
let res = unsafe { ioctl(sock, SIOCGIFFLAGS as i32, &mut req) };
} else {
let res = unsafe { ioctl(sock, SIOCGIFFLAGS, &mut req) };
}
}
unsafe { close(sock) };
if res < 0 {
return Err(io::Error::last_os_error()).map_err(map_to_string);