From 7a257095bac009c4be0b93c2979801624fdd337b Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Mon, 13 Mar 2023 18:05:55 +0100 Subject: [PATCH] bring back dlopen --- Cargo.toml | 3 +++ src/interface/android.rs | 47 ++++++++++++++++++++++++++++++++++++---- src/interface/unix.rs | 20 +++++++++++++---- 3 files changed, 62 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0fffd3f..13f4421 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,9 @@ license = "MIT" libc = "0.2" [target.'cfg(target_os = "android")'.dependencies] +# DL Open +dlopen = "0.1.8" +once_cell = "1.17.1" # netlink netlink-packet-core = "0.5" netlink-packet-route = "0.15" diff --git a/src/interface/android.rs b/src/interface/android.rs index ab2084a..6f0535c 100644 --- a/src/interface/android.rs +++ b/src/interface/android.rs @@ -1,10 +1,49 @@ -use crate::interface::Interface; +use once_cell::sync::OnceCell; -pub fn unix_interfaces() -> Vec { - netlink::unix_interfaces() +pub fn get_libc_ifaddrs() -> Option<( + unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int, + unsafe extern "C" fn(*mut libc::ifaddrs), +)> { + match (get_getifaddrs(), get_freeifaddrs()) { + (Some(a), Some(b)) => Some((a, b)), + _ => None, + } +} + +fn load_symbol(sym: &'static str) -> Option { + 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::(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 libc::c_int> { + static INSTANCE: OnceCell< + Option libc::c_int>, + > = OnceCell::new(); + + *INSTANCE.get_or_init(|| load_symbol("getifaddrs")) +} + +fn get_freeifaddrs() -> Option { + static INSTANCE: OnceCell> = OnceCell::new(); + + *INSTANCE.get_or_init(|| load_symbol("freeifaddrs")) } -mod netlink { +pub mod netlink { //! Netlink based getifaddrs. //! //! Based on the logic found in https://git.musl-libc.org/cgit/musl/tree/src/network/getifaddrs.c diff --git a/src/interface/unix.rs b/src/interface/unix.rs index b91dcbe..7a6a839 100644 --- a/src/interface/unix.rs +++ b/src/interface/unix.rs @@ -198,17 +198,29 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option, Opti } } - #[cfg(target_os = "android")] pub fn unix_interfaces() -> Vec { - super::android::unix_interfaces() + use super::android; + + if let Some((getifaddrs, freeifaddrs)) = android::get_libc_ifaddrs() { + return unix_interfaces_inner(getifaddrs, freeifaddrs); + } + + android::netlink::unix_interfaces() } #[cfg(not(target_os = "android"))] pub fn unix_interfaces() -> Vec { + unix_interfaces_inner(libc::getifaddrs, libc::freeifaddrs) +} + +fn unix_interfaces_inner( + getifaddrs: unsafe extern "C" fn(*mut *mut libc::ifaddrs) -> libc::c_int, + freeifaddrs: unsafe extern "C" fn(*mut libc::ifaddrs), +) -> Vec { let mut ifaces: Vec = vec![]; 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; } let addrs = unsafe { addrs.assume_init() }; @@ -304,7 +316,7 @@ pub fn unix_interfaces() -> Vec { addr = addr_ref.ifa_next; } unsafe { - libc::freeifaddrs(addrs); + freeifaddrs(addrs); } for iface in &mut ifaces { let name = CString::new(iface.name.as_bytes()).unwrap();