use std::net::IpAddr;
mod error;
pub use error::Error;
#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use crate::linux::*;
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
pub mod unix;
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
pub use crate::unix::*;
#[cfg(target_family = "windows")]
pub mod windows;
#[cfg(target_family = "windows")]
pub use crate::windows::*;
pub fn local_ip() -> Result<IpAddr, Error> {
#[cfg(target_os = "linux")]
{
crate::linux::local_ip()
}
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
{
let ifas = crate::unix::list_afinet_netifas_info()?;
ifas.into_iter()
.find_map(|ifa| {
if !ifa.is_loopback && ifa.addr.is_ipv4() && !ifa.is_mobile_data() {
Some(ifa.addr)
} else {
None
}
})
.ok_or(Error::LocalIpAddressNotFound)
}
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Networking::WinSock::AF_INET;
let ip_addresses = crate::windows::list_local_ip_addresses(AF_INET)?;
ip_addresses
.into_iter()
.find(|ip_address| matches!(ip_address, IpAddr::V4(_)))
.ok_or(Error::LocalIpAddressNotFound)
}
#[cfg(not(any(
target_os = "linux",
target_os = "windows",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "android",
target_os = "ios",
)))]
{
Err(Error::PlatformNotSupported(
std::env::consts::OS.to_string(),
))
}
}
pub fn local_ipv6() -> Result<IpAddr, Error> {
#[cfg(target_os = "linux")]
{
crate::linux::local_ipv6()
}
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
{
let ifas = crate::unix::list_afinet_netifas_info()?;
ifas.into_iter()
.find_map(|ifa| {
if !ifa.is_loopback && ifa.addr.is_ipv6() && !ifa.is_mobile_data() {
Some(ifa.addr)
} else {
None
}
})
.ok_or(Error::LocalIpAddressNotFound)
}
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Networking::WinSock::AF_INET6;
let ip_addresses = crate::windows::list_local_ip_addresses(AF_INET6)?;
ip_addresses
.into_iter()
.find(|ip_address| matches!(ip_address, IpAddr::V6(_)))
.ok_or(Error::LocalIpAddressNotFound)
}
#[cfg(not(any(
target_os = "linux",
target_os = "windows",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "android",
target_os = "ios",
)))]
{
Err(Error::PlatformNotSupported(
std::env::consts::OS.to_string(),
))
}
}
#[cfg(not(any(
target_os = "linux",
target_os = "windows",
target_os = "macos",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "android",
target_os = "ios",
)))]
pub fn list_afinet_netifas() -> Result<Vec<(String, IpAddr)>, Error> {
Err(Error::PlatformNotSupported(
std::env::consts::OS.to_string(),
))
}
mod tests {
#[allow(unused_imports)]
use super::*;
#[test]
#[cfg(target_os = "linux")]
fn find_local_ip() {
let my_local_ip = local_ip();
println!("Linux 'local_ip': {:?}", my_local_ip);
assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
}
#[test]
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
fn find_local_ip() {
let my_local_ip = local_ip();
println!("Unix 'local_ip': {:?}", my_local_ip);
assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
}
#[test]
#[cfg(target_os = "windows")]
fn find_local_ip() {
let my_local_ip = local_ip();
println!("Windows 'local_ip': {:?}", my_local_ip);
assert!(matches!(my_local_ip, Ok(IpAddr::V4(_))));
}
#[test]
#[cfg(target_os = "linux")]
fn find_network_interfaces() {
let network_interfaces = list_afinet_netifas();
println!("Linux 'list_afinet_netifas': {:?}", network_interfaces);
assert!(network_interfaces.is_ok());
assert!(!network_interfaces.unwrap().is_empty());
}
#[test]
#[cfg(any(
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd",
target_os = "dragonfly",
target_os = "macos",
target_os = "android",
target_os = "ios",
))]
fn find_network_interfaces() {
let network_interfaces = list_afinet_netifas();
assert!(network_interfaces.is_ok());
assert!(!network_interfaces.unwrap().is_empty());
}
#[test]
#[cfg(target_os = "windows")]
fn find_network_interfaces() {
let network_interfaces = list_afinet_netifas();
assert!(network_interfaces.is_ok());
assert!(!network_interfaces.unwrap().is_empty());
}
}