libarp/
interfaces.rs

1use pnet::datalink::{
2    channel, interfaces, Channel, DataLinkReceiver, DataLinkSender, NetworkInterface,
3};
4use std::{
5    io::{Error, ErrorKind},
6    net::{IpAddr, Ipv4Addr},
7    time::Duration,
8};
9
10/// Represents a network interface.
11/// Wraps pnet's `NetworkInterface` struct for better convenience.
12#[derive(Clone, PartialEq, Eq, Debug, Hash)]
13pub struct Interface {
14    network_interface: NetworkInterface,
15}
16
17impl Interface {
18    /// Selects the first "best-suited" interface found.
19    pub fn new() -> Result<Self, Error> {
20        match Interface::get_interface_by_guess() {
21            Some(iface) => Ok(Interface {
22                network_interface: iface,
23            }),
24            None => Err(Error::new(
25                ErrorKind::NotConnected,
26                "Could not get any network interface.",
27            )),
28        }
29    }
30
31    /// Selects the interface with the name `interface_name`.
32    pub fn new_by_name(interface_name: &str) -> Option<Self> {
33        let iface = Interface::get_interface_by_name(&interface_name);
34
35        match iface {
36            Some(iface) => Some(Interface {
37                network_interface: iface,
38            }),
39            None => None,
40        }
41    }
42
43    /// Returns the IPv4 address of the interface.
44    pub fn get_ip(&self) -> Result<Ipv4Addr, Error> {
45        let ip = self
46            .network_interface
47            .ips
48            .iter()
49            .find(|ip| ip.is_ipv4())
50            .map(|ip| match ip.ip() {
51                IpAddr::V4(ip) => Some(ip),
52                _ => None,
53            })
54            .unwrap_or(None);
55
56        match ip {
57            Some(ip) => Ok(ip),
58            None => Err(Error::new(
59                ErrorKind::AddrNotAvailable,
60                "Currently selected interface does not have any IP address assigned.",
61            )),
62        }
63    }
64
65    /// Returns the MAC address assigned to the interface.
66    pub fn get_mac(&self) -> Result<MacAddr, Error> {
67        match self.network_interface.mac {
68            Some(mac) => Ok(mac.into()),
69            None => Err(Error::new(
70                ErrorKind::AddrNotAvailable,
71                "Currently selected interface does not have any MAC address assigned.",
72            )),
73        }
74    }
75
76    /// Returns the raw `pnet` interface instance related to the interface.
77    pub fn get_raw_interface(&self) -> &NetworkInterface {
78        &self.network_interface
79    }
80
81    /// Creates and returns a new Ethernet (tx, rx) channel pair on the interface.
82    pub fn create_tx_rx_channels(
83        &self,
84    ) -> Result<(Box<dyn DataLinkSender>, Box<dyn DataLinkReceiver>), Error> {
85        let channel_config = pnet::datalink::Config {
86            read_timeout: Some(Duration::ZERO),
87            ..Default::default()
88        };
89
90        match channel(&self.get_raw_interface(), channel_config) {
91            Ok(Channel::Ethernet(tx, rx)) => Ok((tx, rx)),
92            Ok(_) => return Err(Error::new(ErrorKind::Other, "Unknown channel type")),
93            Err(err) => return Err(err),
94        }
95    }
96
97    fn get_all_interfaces() -> Vec<NetworkInterface> {
98        interfaces()
99    }
100
101    fn get_interface_by_guess() -> Option<NetworkInterface> {
102        let considered_ifaces = Interface::get_all_interfaces()
103            .into_iter()
104            .filter(|iface| !iface.is_loopback() && iface.is_up() && !iface.ips.is_empty())
105            .collect::<Vec<NetworkInterface>>();
106
107        match considered_ifaces.first() {
108            Some(iface) => Some(iface.clone()),
109            None => None,
110        }
111    }
112
113    fn get_interface_by_name(name: &str) -> Option<NetworkInterface> {
114        let considered_ifaces = Interface::get_all_interfaces()
115            .into_iter()
116            .filter(|iface| iface.name == *name)
117            .collect::<Vec<NetworkInterface>>();
118
119        match considered_ifaces.first() {
120            Some(iface) => Some(iface.clone()),
121            None => None,
122        }
123    }
124}
125
126/// Redefinition of the pnet `MacAddr`, so that as a user pnet does not need to be imported
127#[derive(PartialEq, Eq, Clone, Copy)]
128pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);
129
130impl MacAddr {
131    pub fn new(a: u8, b: u8, c: u8, d: u8, e: u8, f: u8) -> Self {
132        MacAddr(a, b, c, d, e, f)
133    }
134}
135
136impl std::fmt::Display for MacAddr {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        write!(
139            f,
140            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
141            self.0, self.1, self.2, self.3, self.4, self.5
142        )
143    }
144}
145
146impl From<pnet::util::MacAddr> for MacAddr {
147    fn from(pnet_mac_addr: pnet::util::MacAddr) -> Self {
148        MacAddr(
149            pnet_mac_addr.0,
150            pnet_mac_addr.1,
151            pnet_mac_addr.2,
152            pnet_mac_addr.3,
153            pnet_mac_addr.4,
154            pnet_mac_addr.5,
155        )
156    }
157}
158
159impl From<MacAddr> for pnet::util::MacAddr {
160    fn from(mac_addr: MacAddr) -> Self {
161        pnet::util::MacAddr(
162            mac_addr.0, mac_addr.1, mac_addr.2, mac_addr.3, mac_addr.4, mac_addr.5,
163        )
164    }
165}