bring back dlopen

main
dignifiedquire 2 years ago
parent 64e265889a
commit 7a257095ba
  1. 3
      Cargo.toml
  2. 47
      src/interface/android.rs
  3. 20
      src/interface/unix.rs

@ -14,6 +14,9 @@ license = "MIT"
libc = "0.2" libc = "0.2"
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
# DL Open
dlopen = "0.1.8"
once_cell = "1.17.1"
# netlink # netlink
netlink-packet-core = "0.5" netlink-packet-core = "0.5"
netlink-packet-route = "0.15" netlink-packet-route = "0.15"

@ -1,10 +1,49 @@
use crate::interface::Interface; use once_cell::sync::OnceCell;
pub fn unix_interfaces() -> Vec<Interface> { pub fn get_libc_ifaddrs() -> Option<(
netlink::unix_interfaces() 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<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"))
} }
mod netlink { pub mod netlink {
//! Netlink based getifaddrs. //! Netlink based getifaddrs.
//! //!
//! Based on the logic found in https://git.musl-libc.org/cgit/musl/tree/src/network/getifaddrs.c //! Based on the logic found in https://git.musl-libc.org/cgit/musl/tree/src/network/getifaddrs.c

@ -198,17 +198,29 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Opti
} }
} }
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub fn unix_interfaces() -> Vec<Interface> { pub fn unix_interfaces() -> Vec<Interface> {
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"))] #[cfg(not(target_os = "android"))]
pub fn unix_interfaces() -> Vec<Interface> { pub fn unix_interfaces() -> Vec<Interface> {
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<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() };
@ -304,7 +316,7 @@ pub fn unix_interfaces() -> Vec<Interface> {
addr = addr_ref.ifa_next; addr = addr_ref.ifa_next;
} }
unsafe { unsafe {
libc::freeifaddrs(addrs); 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();

Loading…
Cancel
Save