feat: try to dynamically load libc.so on Android

main
dignifiedquire 2 years ago
parent 8f22d88792
commit a8bed97314
  1. 4
      Cargo.toml
  2. 64
      src/interface/android.rs
  3. 10
      src/interface/linux.rs
  4. 56
      src/interface/mod.rs
  5. 110
      src/interface/unix.rs

@ -13,6 +13,10 @@ license = "MIT"
[dependencies] [dependencies]
libc = "0.2" libc = "0.2"
[target.'cfg(target_os = "android")'.dependencies]
dlopen = "0.1.8"
once_cell = "1.17.1"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
memalloc = "0.1.0" memalloc = "0.1.0"

@ -0,0 +1,64 @@
use once_cell::sync::OnceCell;
fn load_symbol<T>(sym: &'static str) -> Option<T> {
const LIB_NAME: &str = "libc.so";
println!("loading symbol: {} from {}", sym, LIB_NAME);
match dlopen::raw::Library::open(LIB_NAME) {
Ok(lib) => match unsafe { lib.symbol::<T>(sym) } {
Ok(val) => Some(val),
Err(err) => {
eprintln!("failed to load symbol {} from {}: {:?}", sym, LIB_NAME, err);
None
}
},
Err(err) => {
eprintln!("failed to load {}: {:?}", LIB_NAME, err);
None
}
}
}
fn get_getifaddrs() -> Option<unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int> {
static INSTANCE: OnceCell<
Option<unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int>,
> = OnceCell::new();
*INSTANCE.get_or_init(|| load_symbol("getifaddrs"))
}
fn get_freeifaddrs() -> Option<unsafe extern "C" fn(*mut libc::ifaddrs)> {
static INSTANCE: OnceCell<Option<unsafe extern "C" fn(*mut libc::ifaddrs)>> = OnceCell::new();
*INSTANCE.get_or_init(|| load_symbol("freeifaddrs"))
}
pub unsafe fn getifaddrs(ifap: *mut *mut libc::ifaddrs) -> libc::c_int {
// Android is complicated
// API 24+ contains the getifaddrs and freeifaddrs functions but the NDK doesn't
// expose those functions in ifaddrs.h when the minimum supported SDK is lower than 24
// and therefore we need to load them manually.
if let Some(dyn_getifaddrs) = get_getifaddrs() {
return dyn_getifaddrs(ifap);
}
// If API < 24 (or we can't load libc for some other reason), we fallback to using netlink
netlink_getifaddrs(ifap)
}
pub unsafe fn freeifaddrs(ifa: *mut libc::ifaddrs) {
if let Some(dyn_freeifaddrs) = get_freeifaddrs() {
return dyn_freeifaddrs(ifa);
}
netlink_freeifaddrs(ifa)
}
unsafe fn netlink_getifaddrs(ifap: *mut *mut libc::ifaddrs) -> libc::c_int {
todo!()
}
unsafe fn netlink_freeifaddrs(ifa: *mut libc::ifaddrs) {
todo!()
}

@ -1,6 +1,6 @@
use crate::interface::InterfaceType;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fs::read_to_string; use std::fs::read_to_string;
use crate::interface::InterfaceType;
pub fn get_interface_type(if_name: String) -> InterfaceType { pub fn get_interface_type(if_name: String) -> InterfaceType {
let if_type_path: String = format!("/sys/class/net/{}/type", if_name); let if_type_path: String = format!("/sys/class/net/{}/type", if_name);
@ -11,12 +11,12 @@ pub fn get_interface_type(if_name: String) -> InterfaceType {
match if_type_string.parse::<u32>() { match if_type_string.parse::<u32>() {
Ok(if_type) => { Ok(if_type) => {
return InterfaceType::try_from(if_type).unwrap_or(InterfaceType::Unknown); return InterfaceType::try_from(if_type).unwrap_or(InterfaceType::Unknown);
}, }
Err(_) => { Err(_) => {
return InterfaceType::Unknown; return InterfaceType::Unknown;
} }
} }
}, }
Err(_) => { Err(_) => {
return InterfaceType::Unknown; return InterfaceType::Unknown;
} }
@ -33,12 +33,12 @@ pub fn get_interface_speed(if_name: String) -> Option<u64> {
Ok(if_speed) => { Ok(if_speed) => {
// Convert Mbps to bps // Convert Mbps to bps
return Some(if_speed * 1000000); return Some(if_speed * 1000000);
}, }
Err(_) => { Err(_) => {
return None; return None;
} }
} }
}, }
Err(_) => { Err(_) => {
return None; return None;
} }

@ -4,9 +4,25 @@ pub use self::shared::*;
mod types; mod types;
pub use self::types::*; pub use self::types::*;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios", target_os = "android"))] #[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "openbsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "ios",
target_os = "android"
))]
mod unix; mod unix;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "ios", target_os = "android"))] #[cfg(any(
target_os = "linux",
target_os = "macos",
target_os = "openbsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "ios",
target_os = "android"
))]
use self::unix::*; use self::unix::*;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
@ -17,12 +33,15 @@ use self::windows::*;
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
mod linux; mod linux;
#[cfg(target_os = "android")]
mod android;
#[cfg(any(target_os = "macos", target_os = "ios"))] #[cfg(any(target_os = "macos", target_os = "ios"))]
mod macos; mod macos;
use std::net::IpAddr; use crate::gateway::Gateway;
use crate::ip::{Ipv4Net, Ipv6Net}; use crate::ip::{Ipv4Net, Ipv6Net};
use crate::gateway::{Gateway}; use std::net::IpAddr;
/// Structure of MAC address /// Structure of MAC address
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -31,7 +50,9 @@ pub struct MacAddr(u8, u8, u8, u8, u8, u8);
impl MacAddr { impl MacAddr {
/// Construct a new MacAddr instance from the given octets /// Construct a new MacAddr instance from the given octets
pub fn new(octets: [u8; 6]) -> MacAddr { pub fn new(octets: [u8; 6]) -> MacAddr {
MacAddr(octets[0], octets[1], octets[2], octets[3], octets[4], octets[5]) MacAddr(
octets[0], octets[1], octets[2], octets[3], octets[4], octets[5],
)
} }
/// Returns an array of MAC address octets /// Returns an array of MAC address octets
pub fn octets(&self) -> [u8; 6] { pub fn octets(&self) -> [u8; 6] {
@ -39,7 +60,10 @@ impl MacAddr {
} }
/// Return a formatted string of MAC address /// Return a formatted string of MAC address
pub fn address(&self) -> String { pub fn address(&self) -> String {
format!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", self.0,self.1,self.2,self.3,self.4,self.5) format!(
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
self.0, self.1, self.2, self.3, self.4, self.5
)
} }
/// Construct an all-zero MacAddr instance /// Construct an all-zero MacAddr instance
pub fn zero() -> MacAddr { pub fn zero() -> MacAddr {
@ -48,7 +72,7 @@ impl MacAddr {
/// Construct a new MacAddr instance from a colon-separated string of hex format /// Construct a new MacAddr instance from a colon-separated string of hex format
pub fn from_hex_format(hex_mac_addr: &str) -> MacAddr { pub fn from_hex_format(hex_mac_addr: &str) -> MacAddr {
if hex_mac_addr.len() != 17 { if hex_mac_addr.len() != 17 {
return MacAddr(0,0,0,0,0,0) return MacAddr(0, 0, 0, 0, 0, 0);
} }
let fields: Vec<&str> = hex_mac_addr.split(":").collect(); let fields: Vec<&str> = hex_mac_addr.split(":").collect();
let o1: u8 = u8::from_str_radix(&fields[0], 0x10).unwrap_or(0); let o1: u8 = u8::from_str_radix(&fields[0], 0x10).unwrap_or(0);
@ -63,7 +87,11 @@ impl MacAddr {
impl std::fmt::Display for MacAddr { impl std::fmt::Display for MacAddr {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let _ = write!(f,"{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}",self.0,self.1,self.2,self.3,self.4,self.5); let _ = write!(
f,
"{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}:{:<02x}",
self.0, self.1, self.2, self.3, self.4, self.5
);
Ok(()) Ok(())
} }
} }
@ -110,12 +138,12 @@ pub fn get_default_interface() -> Result<Interface, String> {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Ok(iface); return Ok(iface);
} }
}, }
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Ok(iface); return Ok(iface);
} }
}, }
} }
} }
Err(String::from("Default Interface not found")) Err(String::from("Default Interface not found"))
@ -134,12 +162,12 @@ pub fn get_default_interface_index() -> Option<u32> {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Some(iface.index); return Some(iface.index);
} }
}, }
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Some(iface.index); return Some(iface.index);
} }
}, }
} }
} }
None None
@ -158,12 +186,12 @@ pub fn get_default_interface_name() -> Option<String> {
if iface.ipv4.iter().any(|x| x.addr == local_ipv4) { if iface.ipv4.iter().any(|x| x.addr == local_ipv4) {
return Some(iface.name); return Some(iface.name);
} }
}, }
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
return Some(iface.name); return Some(iface.name);
} }
}, }
} }
} }
None None

@ -1,16 +1,19 @@
use super::Interface; use super::Interface;
use super::MacAddr; use super::MacAddr;
use crate::sys;
use crate::gateway; use crate::gateway;
use crate::ip::{Ipv4Net, Ipv6Net}; use crate::ip::{Ipv4Net, Ipv6Net};
use crate::sys;
use crate::interface::InterfaceType;
use libc; use libc;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::mem::{self, MaybeUninit}; use std::mem::{self, MaybeUninit};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::os::raw::c_char; use std::os::raw::c_char;
use std::str::from_utf8_unchecked; use std::str::from_utf8_unchecked;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::interface::InterfaceType; #[cfg(target_os = "android")]
use super::android::{freeifaddrs, getifaddrs};
#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))] #[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
pub fn interfaces() -> Vec<Interface> { pub fn interfaces() -> Vec<Interface> {
@ -26,21 +29,21 @@ pub fn interfaces() -> Vec<Interface> {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
} }
} }
interfaces interfaces
@ -64,21 +67,21 @@ pub fn interfaces() -> Vec<Interface> {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
match gateway::unix::get_default_gateway(iface.name.clone()) { match gateway::unix::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
} }
} }
interfaces interfaces
@ -104,21 +107,21 @@ pub fn interfaces() -> Vec<Interface> {
match gateway::linux::get_default_gateway(iface.name.clone()) { match gateway::linux::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
IpAddr::V6(local_ipv6) => { IpAddr::V6(local_ipv6) => {
if iface.ipv6.iter().any(|x| x.addr == local_ipv6) { if iface.ipv6.iter().any(|x| x.addr == local_ipv6) {
match gateway::linux::get_default_gateway(iface.name.clone()) { match gateway::linux::get_default_gateway(iface.name.clone()) {
Ok(gateway) => { Ok(gateway) => {
iface.gateway = Some(gateway); iface.gateway = Some(gateway);
}, }
Err(_) => {}, Err(_) => {}
}
} }
} }
},
} }
} }
interfaces interfaces
@ -144,10 +147,8 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Opti
(Some(mac), None) (Some(mac), None)
} else { } else {
let addr = sys::sockaddr_to_addr( let addr =
mem::transmute(sa), sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
mem::size_of::<libc::sockaddr_storage>(),
);
match addr { match addr {
Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))), Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
@ -158,7 +159,13 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Opti
} }
} }
#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd", target_os = "macos", target_os = "ios"))] #[cfg(any(
target_os = "openbsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "macos",
target_os = "ios"
))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) { fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
use crate::bpf; use crate::bpf;
use std::net::SocketAddr; use std::net::SocketAddr;
@ -180,10 +187,8 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Opti
(Some(mac), None) (Some(mac), None)
} else { } else {
let addr = sys::sockaddr_to_addr( let addr =
mem::transmute(sa), sys::sockaddr_to_addr(mem::transmute(sa), mem::size_of::<libc::sockaddr_storage>());
mem::size_of::<libc::sockaddr_storage>(),
);
match addr { match addr {
Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))), Ok(SocketAddr::V4(sa)) => (None, Some(IpAddr::V4(*sa.ip()))),
@ -197,7 +202,7 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Opti
pub fn unix_interfaces() -> Vec<Interface> { pub fn unix_interfaces() -> Vec<Interface> {
let mut ifaces: Vec<Interface> = vec![]; let mut ifaces: Vec<Interface> = vec![];
let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit();
if unsafe { libc::getifaddrs(addrs.as_mut_ptr()) } != 0 { if unsafe { getifaddrs(addrs.as_mut_ptr()) } != 0 {
return ifaces; return ifaces;
} }
let addrs = unsafe { addrs.assume_init() }; let addrs = unsafe { addrs.assume_init() };
@ -215,30 +220,26 @@ pub fn unix_interfaces() -> Vec<Interface> {
match ip { match ip {
IpAddr::V4(ipv4) => { IpAddr::V4(ipv4) => {
let netmask: Ipv4Addr = match netmask { let netmask: Ipv4Addr = match netmask {
Some(netmask) => { Some(netmask) => match netmask {
match netmask {
IpAddr::V4(netmask) => netmask, IpAddr::V4(netmask) => netmask,
IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED, IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
}
}, },
None => Ipv4Addr::UNSPECIFIED, None => Ipv4Addr::UNSPECIFIED,
}; };
let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask); let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
ini_ipv4.push(ipv4_net); ini_ipv4.push(ipv4_net);
}, }
IpAddr::V6(ipv6) => { IpAddr::V6(ipv6) => {
let netmask: Ipv6Addr = match netmask { let netmask: Ipv6Addr = match netmask {
Some(netmask) => { Some(netmask) => match netmask {
match netmask {
IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED, IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
IpAddr::V6(netmask) => netmask, IpAddr::V6(netmask) => netmask,
}
}, },
None => Ipv6Addr::UNSPECIFIED, None => Ipv6Addr::UNSPECIFIED,
}; };
let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask); let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
ini_ipv6.push(ipv6_net); ini_ipv6.push(ipv6_net);
}, }
} }
} }
let interface: Interface = Interface { let interface: Interface = Interface {
@ -265,30 +266,26 @@ pub fn unix_interfaces() -> Vec<Interface> {
match ip { match ip {
IpAddr::V4(ipv4) => { IpAddr::V4(ipv4) => {
let netmask: Ipv4Addr = match netmask { let netmask: Ipv4Addr = match netmask {
Some(netmask) => { Some(netmask) => match netmask {
match netmask {
IpAddr::V4(netmask) => netmask, IpAddr::V4(netmask) => netmask,
IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED, IpAddr::V6(_) => Ipv4Addr::UNSPECIFIED,
}
}, },
None => Ipv4Addr::UNSPECIFIED, None => Ipv4Addr::UNSPECIFIED,
}; };
let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask); let ipv4_net: Ipv4Net = Ipv4Net::new_with_netmask(ipv4, netmask);
iface.ipv4.push(ipv4_net); iface.ipv4.push(ipv4_net);
}, }
IpAddr::V6(ipv6) => { IpAddr::V6(ipv6) => {
let netmask: Ipv6Addr = match netmask { let netmask: Ipv6Addr = match netmask {
Some(netmask) => { Some(netmask) => match netmask {
match netmask {
IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED, IpAddr::V4(_) => Ipv6Addr::UNSPECIFIED,
IpAddr::V6(netmask) => netmask, IpAddr::V6(netmask) => netmask,
}
}, },
None => Ipv6Addr::UNSPECIFIED, None => Ipv6Addr::UNSPECIFIED,
}; };
let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask); let ipv6_net: Ipv6Net = Ipv6Net::new_with_netmask(ipv6, netmask);
iface.ipv6.push(ipv6_net); iface.ipv6.push(ipv6_net);
}, }
} }
} }
found = true; found = true;
@ -299,14 +296,29 @@ pub fn unix_interfaces() -> Vec<Interface> {
} }
addr = addr_ref.ifa_next; addr = addr_ref.ifa_next;
} }
unsafe{ libc::freeifaddrs(addrs); } unsafe {
freeifaddrs(addrs);
}
for iface in &mut ifaces { for iface in &mut ifaces {
let name = CString::new(iface.name.as_bytes()).unwrap(); let name = CString::new(iface.name.as_bytes()).unwrap();
unsafe { iface.index = libc::if_nametoindex(name.as_ptr()); } unsafe {
iface.index = libc::if_nametoindex(name.as_ptr());
}
} }
ifaces ifaces
} }
#[cfg(not(target_os = "android"))]
unsafe fn getifaddrs(ifap: *mut *mut libc::ifaddrs) -> libc::c_int {
// Not android, everything is easy
libc::getifaddrs(ifap)
}
#[cfg(not(target_os = "android"))]
unsafe fn freeifaddrs(ifa: *mut libc::ifaddrs) {
libc::freeifaddrs(ifa);
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

Loading…
Cancel
Save