netdev/interface/
mod.rs

1#[cfg(feature = "gateway")]
2mod shared;
3#[cfg(feature = "gateway")]
4pub use self::shared::*;
5
6mod types;
7pub use self::types::*;
8
9#[cfg(any(
10    target_os = "linux",
11    target_os = "macos",
12    target_os = "openbsd",
13    target_os = "freebsd",
14    target_os = "netbsd",
15    target_os = "ios",
16    target_os = "android"
17))]
18mod unix;
19#[cfg(any(
20    target_os = "linux",
21    target_os = "macos",
22    target_os = "openbsd",
23    target_os = "freebsd",
24    target_os = "netbsd",
25    target_os = "ios",
26    target_os = "android"
27))]
28use self::unix::*;
29
30#[cfg(target_os = "windows")]
31mod windows;
32#[cfg(target_os = "windows")]
33use self::windows::*;
34
35#[cfg(feature = "serde")]
36use serde::{Deserialize, Serialize};
37
38#[cfg(any(target_os = "linux", target_os = "android"))]
39mod linux;
40
41#[cfg(target_os = "android")]
42mod android;
43
44#[cfg(any(target_os = "macos", target_os = "ios"))]
45mod macos;
46#[cfg(feature = "gateway")]
47use crate::device::NetworkDevice;
48use crate::ipnet::{Ipv4Net, Ipv6Net};
49use crate::mac::MacAddr;
50use crate::sys;
51#[cfg(feature = "gateway")]
52use std::net::IpAddr;
53
54/// Structure of Network Interface information
55#[derive(Clone, Eq, PartialEq, Hash, Debug)]
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57pub struct Interface {
58    /// Index of network interface. This is an integer which uniquely identifies the interface
59    /// on this machine.
60    pub index: u32,
61    /// Machine-readable name of the network interface. On unix-like OSs, this is the interface
62    /// name, like 'eth0' or 'eno1'. On Windows, this is the interface's GUID as a string.
63    pub name: String,
64    /// Friendly name of network interface. On Windows, this is the network adapter configured
65    /// name, e.g. "Ethernet 5" or "Wi-Fi". On Mac, this is the interface display name,
66    /// such as "Ethernet" or "FireWire". If no friendly name is available, this is left as None.
67    pub friendly_name: Option<String>,
68    /// Description of the network interface. On Windows, this is the network adapter model, such
69    /// as "Realtek USB GbE Family Controller #4" or "Software Loopback Interface 1". Currently
70    /// this is not available on platforms other than Windows.
71    pub description: Option<String>,
72    /// Interface Type
73    pub if_type: InterfaceType,
74    /// MAC address of network interface
75    pub mac_addr: Option<MacAddr>,
76    /// List of Ipv4Nets (IPv4 address + netmask) for the network interface
77    pub ipv4: Vec<Ipv4Net>,
78    /// List of Ipv6Nets (IPv6 address + netmask) for the network interface
79    pub ipv6: Vec<Ipv6Net>,
80    /// List of IPv6 Scope IDs for each of the corresponding elements in the ipv6 address vector.
81    /// The Scope ID is an integer which uniquely identifies this interface address on the system,
82    /// and must be provided when using link-local addressing to specify which interface
83    /// you wish to use. The scope ID can be the same as the interface index, but is not
84    /// required to be by the standard.
85    /// The scope ID can also be referred to as the zone index.
86    pub ipv6_scope_ids: Vec<u32>,
87    /// Flags for the network interface (OS Specific)
88    pub flags: u32,
89    /// Speed in bits per second of the transmit for the network interface, if known.
90    /// Currently only supported on Linux, Android, and Windows.
91    pub transmit_speed: Option<u64>,
92    /// Speed in bits per second of the receive for the network interface.
93    /// Currently only supported on Linux, Android, and Windows.
94    pub receive_speed: Option<u64>,
95    /// Default gateway for the network interface. This is the address of the router to which
96    /// IP packets are forwarded when they need to be sent to a device outside
97    /// of the local network.
98    #[cfg(feature = "gateway")]
99    pub gateway: Option<NetworkDevice>,
100    /// DNS server addresses for the network interface
101    #[cfg(feature = "gateway")]
102    pub dns_servers: Vec<IpAddr>,
103    /// Maximum Transmission Unit (MTU) for the network interface
104    pub mtu: Option<u32>,
105    /// Whether this is the default interface for accessing the Internet.
106    #[cfg(feature = "gateway")]
107    pub default: bool,
108}
109
110impl Interface {
111    /// Construct a new default Interface instance
112    #[cfg(feature = "gateway")]
113    pub fn default() -> Result<Interface, String> {
114        let interfaces: Vec<Interface> = interfaces();
115        for iface in &interfaces {
116            if iface.default {
117                return Ok(iface.clone());
118            }
119        }
120        let local_ip: IpAddr = match get_local_ipaddr() {
121            Some(local_ip) => local_ip,
122            None => return Err(String::from("Local IP address not found")),
123        };
124        for iface in interfaces {
125            match local_ip {
126                IpAddr::V4(local_ipv4) => {
127                    if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) {
128                        return Ok(iface);
129                    }
130                }
131                IpAddr::V6(local_ipv6) => {
132                    if iface.ipv6.iter().any(|x| x.addr() == local_ipv6) {
133                        return Ok(iface);
134                    }
135                }
136            }
137        }
138        Err(String::from("Default Interface not found"))
139    }
140    // Construct a dummy Interface instance
141    pub fn dummy() -> Interface {
142        Interface {
143            index: 0,
144            name: String::new(),
145            friendly_name: None,
146            description: None,
147            if_type: InterfaceType::Unknown,
148            mac_addr: None,
149            ipv4: Vec::new(),
150            ipv6: Vec::new(),
151            ipv6_scope_ids: Vec::new(),
152            flags: 0,
153            transmit_speed: None,
154            receive_speed: None,
155            #[cfg(feature = "gateway")]
156            gateway: None,
157            #[cfg(feature = "gateway")]
158            dns_servers: Vec::new(),
159            mtu: None,
160            #[cfg(feature = "gateway")]
161            default: false,
162        }
163    }
164    /// Check if the network interface is up
165    pub fn is_up(&self) -> bool {
166        self.flags & (sys::IFF_UP as u32) != 0
167    }
168    /// Check if the network interface is a Loopback interface
169    pub fn is_loopback(&self) -> bool {
170        self.flags & (sys::IFF_LOOPBACK as u32) != 0
171    }
172    /// Check if the network interface is a Point-to-Point interface
173    pub fn is_point_to_point(&self) -> bool {
174        self.flags & (sys::IFF_POINTOPOINT as u32) != 0
175    }
176    /// Check if the network interface is a Multicast interface
177    pub fn is_multicast(&self) -> bool {
178        self.flags & (sys::IFF_MULTICAST as u32) != 0
179    }
180    /// Check if the network interface is a Broadcast interface
181    pub fn is_broadcast(&self) -> bool {
182        self.flags & (sys::IFF_BROADCAST as u32) != 0
183    }
184    /// Check if the network interface is a TUN interface
185    pub fn is_tun(&self) -> bool {
186        self.is_up() && self.is_point_to_point() && !self.is_broadcast() && !self.is_loopback()
187    }
188    /// Check if the network interface is running and ready to send/receive packets
189    pub fn is_running(&self) -> bool {
190        is_running(&self)
191    }
192    /// Check if the network interface is a physical interface
193    pub fn is_physical(&self) -> bool {
194        is_physical_interface(&self)
195            && !crate::db::oui::is_virtual_mac(&self.mac_addr.unwrap_or(MacAddr::zero()))
196            && !crate::db::oui::is_known_loopback_mac(&self.mac_addr.unwrap_or(MacAddr::zero()))
197    }
198}
199
200/// Get default Network Interface
201#[cfg(feature = "gateway")]
202pub fn get_default_interface() -> Result<Interface, String> {
203    let interfaces: Vec<Interface> = interfaces();
204    for iface in &interfaces {
205        if iface.default {
206            return Ok(iface.clone());
207        }
208    }
209    let local_ip: IpAddr = match get_local_ipaddr() {
210        Some(local_ip) => local_ip,
211        None => return Err(String::from("Local IP address not found")),
212    };
213    for iface in interfaces {
214        match local_ip {
215            IpAddr::V4(local_ipv4) => {
216                if iface.ipv4.iter().any(|x| x.addr() == local_ipv4) {
217                    return Ok(iface);
218                }
219            }
220            IpAddr::V6(local_ipv6) => {
221                if iface.ipv6.iter().any(|x| x.addr() == local_ipv6) {
222                    return Ok(iface);
223                }
224            }
225        }
226    }
227    Err(String::from("Default Interface not found"))
228}
229
230/// Get a list of available Network Interfaces
231pub fn get_interfaces() -> Vec<Interface> {
232    interfaces()
233}
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238    #[test]
239    fn test_interfaces() {
240        let interfaces = get_interfaces();
241        for interface in interfaces {
242            println!("{:#?}", interface);
243        }
244    }
245    #[test]
246    #[cfg(feature = "gateway")]
247    fn test_default_interface() {
248        println!("{:#?}", get_default_interface());
249    }
250
251    #[test]
252    fn sanity_check_loopback() {
253        let interfaces = get_interfaces();
254
255        assert!(interfaces.len() >= 2, "There should be at least 2 network interfaces on any machine, the loopback and one other one");
256
257        // Try and find the loopback interface
258        let loopback_interfaces: Vec<&Interface> = interfaces
259            .iter()
260            .filter(|iface| iface.if_type == InterfaceType::Loopback)
261            .collect();
262        assert_eq!(
263            loopback_interfaces.len(),
264            1,
265            "There should be exactly one loopback interface on the machine"
266        );
267        let loopback = loopback_interfaces[0];
268
269        // Make sure that 127.0.0.1 is one of loopback's IPv4 addresses
270        let loopback_expected_ipv4: std::net::Ipv4Addr = "127.0.0.1".parse().unwrap();
271        let matching_ipv4s: Vec<&Ipv4Net> = loopback
272            .ipv4
273            .iter()
274            .filter(|&ipv4_net| ipv4_net.addr() == loopback_expected_ipv4)
275            .collect();
276        assert_eq!(
277            matching_ipv4s.len(),
278            1,
279            "The loopback interface should have IP 127.0.0.1"
280        );
281        println!("Found IP {:?} on the loopback interface", matching_ipv4s[0]);
282
283        // Make sure that ::1 is one of loopback's IPv6 addresses
284        let loopback_expected_ipv6: std::net::Ipv6Addr = "::1".parse().unwrap();
285        let matching_ipv6s: Vec<&Ipv6Net> = loopback
286            .ipv6
287            .iter()
288            .filter(|&ipv6_net| ipv6_net.addr() == loopback_expected_ipv6)
289            .collect();
290        assert_eq!(
291            matching_ipv6s.len(),
292            1,
293            "The loopback interface should have IP ::1"
294        );
295        println!("Found IP {:?} on the loopback interface", matching_ipv6s[0]);
296
297        // Make sure that the loopback interface has the same number of scope IDs as it does IPv6 addresses
298        assert_eq!(loopback.ipv6.len(), loopback.ipv6_scope_ids.len());
299
300        // Check flags
301        assert!(
302            loopback.is_running(),
303            "Loopback interface should be running!"
304        );
305        assert!(
306            !loopback.is_physical(),
307            "Loopback interface should not be physical!"
308        );
309
310        // Make sure that, if the loopback interface has a MAC, it has a known loopback MAC
311        match loopback.mac_addr {
312            Some(mac) => assert!(
313                crate::db::oui::is_known_loopback_mac(&mac),
314                "Loopback interface MAC not a known loopback MAC"
315            ),
316            None => {}
317        }
318    }
319}