Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ system-configuration = "0.6"
serde_json = "1.0"

[features]
default = ["gateway"]
serde = ["dep:serde", "ipnet/serde"]
gateway = []

[[example]]
name = "list_interfaces"
Expand All @@ -46,12 +48,14 @@ path = "examples/list_interfaces.rs"
[[example]]
name = "default_interface"
path = "examples/default_interface.rs"
required-features = ["gateway"]

[[example]]
name = "default_gateway"
path = "examples/default_gateway.rs"
required-features = ["gateway"]

[[example]]
name = "serialize"
path = "examples/serialize.rs"
required-features = ["serde"]
required-features = ["serde", "gateway"]
3 changes: 3 additions & 0 deletions examples/list_interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ fn main() {

println!("\tTransmit Speed: {:?}", interface.transmit_speed);
println!("\tReceive Speed: {:?}", interface.receive_speed);
#[cfg(feature = "gateway")]
if let Some(gateway) = interface.gateway {
println!("Gateway");
println!("\tMAC Address: {}", gateway.mac_addr);
Expand All @@ -44,8 +45,10 @@ fn main() {
} else {
println!("Gateway: (Not found)");
}
#[cfg(feature = "gateway")]
println!("DNS Servers: {:?}", interface.dns_servers);
println!("MTU: {:?}", interface.mtu);
#[cfg(feature = "gateway")]
println!("Default: {}", interface.default);
println!();
}
Expand Down
3 changes: 3 additions & 0 deletions src/interface/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,12 @@ pub mod netlink {
flags: link_msg.header.flags.bits(),
transmit_speed: None,
receive_speed: None,
#[cfg(feature = "gateway")]
gateway: None,
#[cfg(feature = "gateway")]
dns_servers: Vec::new(),
mtu: None,
#[cfg(feature = "gateway")]
default: false,
};

Expand Down
14 changes: 13 additions & 1 deletion src/interface/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[cfg(feature = "gateway")]
mod shared;
#[cfg(feature = "gateway")]
pub use self::shared::*;

mod types;
Expand Down Expand Up @@ -41,11 +43,12 @@ mod android;

#[cfg(any(target_os = "macos", target_os = "ios"))]
mod macos;

#[cfg(feature = "gateway")]
use crate::device::NetworkDevice;
use crate::ipnet::{Ipv4Net, Ipv6Net};
use crate::mac::MacAddr;
use crate::sys;
#[cfg(feature = "gateway")]
use std::net::IpAddr;

/// Structure of Network Interface information
Expand Down Expand Up @@ -92,17 +95,21 @@ pub struct Interface {
/// Default gateway for the network interface. This is the address of the router to which
/// IP packets are forwarded when they need to be sent to a device outside
/// of the local network.
#[cfg(feature = "gateway")]
pub gateway: Option<NetworkDevice>,
/// DNS server addresses for the network interface
#[cfg(feature = "gateway")]
pub dns_servers: Vec<IpAddr>,
/// Maximum Transmission Unit (MTU) for the network interface
pub mtu: Option<u32>,
/// Whether this is the default interface for accessing the Internet.
#[cfg(feature = "gateway")]
pub default: bool,
}

impl Interface {
/// Construct a new default Interface instance
#[cfg(feature = "gateway")]
pub fn default() -> Result<Interface, String> {
let interfaces: Vec<Interface> = interfaces();
for iface in &interfaces {
Expand Down Expand Up @@ -145,9 +152,12 @@ impl Interface {
flags: 0,
transmit_speed: None,
receive_speed: None,
#[cfg(feature = "gateway")]
gateway: None,
#[cfg(feature = "gateway")]
dns_servers: Vec::new(),
mtu: None,
#[cfg(feature = "gateway")]
default: false,
}
}
Expand Down Expand Up @@ -188,6 +198,7 @@ impl Interface {
}

/// Get default Network Interface
#[cfg(feature = "gateway")]
pub fn get_default_interface() -> Result<Interface, String> {
let interfaces: Vec<Interface> = interfaces();
for iface in &interfaces {
Expand Down Expand Up @@ -232,6 +243,7 @@ mod tests {
}
}
#[test]
#[cfg(feature = "gateway")]
fn test_default_interface() {
println!("{:#?}", get_default_interface());
}
Expand Down
2 changes: 2 additions & 0 deletions src/interface/shared.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "gateway")]
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};

/// Retrieve the IP address of the default network interface.
Expand All @@ -16,6 +17,7 @@ use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
/// Returns:
/// - `Some(IpAddr)`: IP address of the default network interface if successful.
/// - `None`: If any error occurs during the operations.
#[cfg(feature = "gateway")]
pub fn get_local_ipaddr() -> Option<IpAddr> {
// Attempt to bind a UDP socket to an unspecified address and port.
let socket = match UdpSocket::bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0)) {
Expand Down
83 changes: 52 additions & 31 deletions src/interface/unix.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
use super::Interface;
use super::MacAddr;
#[cfg(feature = "gateway")]
use crate::gateway;
use crate::interface::InterfaceType;
use crate::ipnet::{Ipv4Net, Ipv6Net};
use crate::sys;
use libc;
use std::ffi::{CStr, CString};
use std::mem::{self, MaybeUninit};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::os::raw::c_char;
use std::str::from_utf8_unchecked;

#[cfg(feature = "gateway")]
use std::net::ToSocketAddrs;
#[cfg(feature = "gateway")]
pub fn get_system_dns_conf() -> Vec<IpAddr> {
use std::fs::read_to_string;
const PATH_RESOLV_CONF: &str = "/etc/resolv.conf";
Expand Down Expand Up @@ -48,31 +52,36 @@ pub fn interfaces() -> Vec<Interface> {

let type_map = macos::get_if_type_map();
let mut interfaces: Vec<Interface> = unix_interfaces();
#[cfg(feature = "gateway")]
let local_ip: IpAddr = match super::get_local_ipaddr() {
Some(local_ip) => local_ip,
None => return interfaces,
};
#[cfg(feature = "gateway")]
let gateway_map = gateway::macos::get_gateway_map();
for iface in &mut interfaces {
if let Some(sc_interface) = type_map.get(&iface.name) {
iface.if_type = sc_interface.interface_type;
iface.friendly_name = sc_interface.friendly_name.clone();
}
if let Some(gateway) = gateway_map.get(&iface.index) {
iface.gateway = Some(gateway.clone());
}
iface.ipv4.iter().for_each(|ipv4| {
if IpAddr::V4(ipv4.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
iface.ipv6.iter().for_each(|ipv6| {
if IpAddr::V6(ipv6.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
#[cfg(feature = "gateway")]
{
if let Some(gateway) = gateway_map.get(&iface.index) {
iface.gateway = Some(gateway.clone());
}
});
iface.ipv4.iter().for_each(|ipv4| {
if IpAddr::V4(ipv4.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
iface.ipv6.iter().for_each(|ipv6| {
if IpAddr::V6(ipv6.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
}
}
interfaces
}
Expand All @@ -82,19 +91,24 @@ pub fn interfaces() -> Vec<Interface> {
use super::linux;

let mut interfaces: Vec<Interface> = unix_interfaces();

#[cfg(feature = "gateway")]
let local_ip: IpAddr = match super::get_local_ipaddr() {
Some(local_ip) => local_ip,
None => return interfaces,
};
#[cfg(feature = "gateway")]
let gateway_map = gateway::linux::get_gateway_map();
for iface in &mut interfaces {
iface.if_type = linux::get_interface_type(iface.name.clone());
let if_speed: Option<u64> = linux::get_interface_speed(iface.name.clone());
iface.transmit_speed = if_speed;
iface.receive_speed = if_speed;
#[cfg(feature = "gateway")]
if let Some(gateway) = gateway_map.get(&iface.name) {
iface.gateway = Some(gateway.clone());
}
#[cfg(feature = "gateway")]
match local_ip {
IpAddr::V4(local_ipv4) => {
if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) {
Expand All @@ -116,27 +130,31 @@ pub fn interfaces() -> Vec<Interface> {
#[cfg(any(target_os = "openbsd", target_os = "freebsd", target_os = "netbsd"))]
pub fn interfaces() -> Vec<Interface> {
let mut interfaces: Vec<Interface> = unix_interfaces();
#[cfg(feature = "gateway")]
let local_ip: IpAddr = match super::get_local_ipaddr() {
Some(local_ip) => local_ip,
None => return interfaces,
};
let gateway_map = gateway::bsd::get_gateway_map();
for iface in &mut interfaces {
if let Some(gateway) = gateway_map.get(&iface.index) {
iface.gateway = Some(gateway.clone());
}
iface.ipv4.iter().for_each(|ipv4| {
if IpAddr::V4(ipv4.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
#[cfg(feature = "gateway")]
{
let gateway_map = gateway::bsd::get_gateway_map();
for iface in &mut interfaces {
if let Some(gateway) = gateway_map.get(&iface.index) {
iface.gateway = Some(gateway.clone());
}
});
iface.ipv6.iter().for_each(|ipv6| {
if IpAddr::V6(ipv6.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
iface.ipv4.iter().for_each(|ipv4| {
if IpAddr::V4(ipv4.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
iface.ipv6.iter().for_each(|ipv6| {
if IpAddr::V6(ipv6.addr()) == local_ip {
iface.dns_servers = get_system_dns_conf();
iface.default = true;
}
});
}
}
interfaces
}
Expand Down Expand Up @@ -457,9 +475,12 @@ fn unix_interfaces_inner(
flags: addr_ref.ifa_flags,
transmit_speed: None,
receive_speed: None,
#[cfg(feature = "gateway")]
gateway: None,
#[cfg(feature = "gateway")]
dns_servers: Vec::new(),
mtu: get_mtu(addr_ref, &name),
#[cfg(feature = "gateway")]
default: false,
};
ifaces.push(interface);
Expand Down
8 changes: 8 additions & 0 deletions src/interface/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,13 @@ pub fn interfaces() -> Vec<Interface> {
}
}
// Gateway
#[cfg(feature = "gateway")]
let gateway_ips: Vec<IpAddr> = unsafe { linked_list_iter!(&cur.FirstGatewayAddress) }
.filter_map(|cur_g| unsafe { socket_address_to_ipaddr(&cur_g.Address).0 })
.collect();
#[cfg(feature = "gateway")]
let mut default_gateway: NetworkDevice = NetworkDevice::new();
#[cfg(feature = "gateway")]
if flags & sys::IFF_UP != 0 {
for gateway_ip in gateway_ips {
match gateway_ip {
Expand All @@ -253,9 +256,11 @@ pub fn interfaces() -> Vec<Interface> {
}
}
// DNS Servers
#[cfg(feature = "gateway")]
let dns_servers: Vec<IpAddr> = unsafe { linked_list_iter!(&cur.FirstDnsServerAddress) }
.filter_map(|cur_d| unsafe { socket_address_to_ipaddr(&cur_d.Address).0 })
.collect();
#[cfg(feature = "gateway")]
let default: bool = match local_ip {
IpAddr::V4(local_ipv4) => ipv4_vec.iter().any(|x| x.addr() == local_ipv4),
IpAddr::V6(local_ipv6) => ipv6_vec.iter().any(|x| x.addr() == local_ipv6),
Expand All @@ -273,13 +278,16 @@ pub fn interfaces() -> Vec<Interface> {
flags,
transmit_speed: Some(cur.TransmitLinkSpeed),
receive_speed: Some(cur.ReceiveLinkSpeed),
#[cfg(feature = "gateway")]
gateway: if default_gateway.mac_addr == MacAddr::zero() {
None
} else {
Some(default_gateway)
},
#[cfg(feature = "gateway")]
dns_servers,
mtu: Some(cur.Mtu),
#[cfg(feature = "gateway")]
default,
};
Some(interface)
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
mod db;
pub mod device;
#[cfg(feature = "gateway")]
pub mod gateway;
pub mod interface;
pub mod mac;
mod sys;

pub use device::NetworkDevice;
#[cfg(feature = "gateway")]
pub use gateway::get_default_gateway;
#[cfg(feature = "gateway")]
pub use interface::get_default_interface;
pub use interface::get_interfaces;
pub use interface::Interface;
Expand Down
Loading