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#[derive(Clone, Eq, PartialEq, Hash, Debug)]
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57pub struct Interface {
58 pub index: u32,
61 pub name: String,
64 pub friendly_name: Option<String>,
68 pub description: Option<String>,
72 pub if_type: InterfaceType,
74 pub mac_addr: Option<MacAddr>,
76 pub ipv4: Vec<Ipv4Net>,
78 pub ipv6: Vec<Ipv6Net>,
80 pub ipv6_scope_ids: Vec<u32>,
87 pub flags: u32,
89 pub transmit_speed: Option<u64>,
92 pub receive_speed: Option<u64>,
95 #[cfg(feature = "gateway")]
99 pub gateway: Option<NetworkDevice>,
100 #[cfg(feature = "gateway")]
102 pub dns_servers: Vec<IpAddr>,
103 pub mtu: Option<u32>,
105 #[cfg(feature = "gateway")]
107 pub default: bool,
108}
109
110impl Interface {
111 #[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 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 pub fn is_up(&self) -> bool {
166 self.flags & (sys::IFF_UP as u32) != 0
167 }
168 pub fn is_loopback(&self) -> bool {
170 self.flags & (sys::IFF_LOOPBACK as u32) != 0
171 }
172 pub fn is_point_to_point(&self) -> bool {
174 self.flags & (sys::IFF_POINTOPOINT as u32) != 0
175 }
176 pub fn is_multicast(&self) -> bool {
178 self.flags & (sys::IFF_MULTICAST as u32) != 0
179 }
180 pub fn is_broadcast(&self) -> bool {
182 self.flags & (sys::IFF_BROADCAST as u32) != 0
183 }
184 pub fn is_tun(&self) -> bool {
186 self.is_up() && self.is_point_to_point() && !self.is_broadcast() && !self.is_loopback()
187 }
188 pub fn is_running(&self) -> bool {
190 is_running(&self)
191 }
192 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#[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
230pub 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 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 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 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 assert_eq!(loopback.ipv6.len(), loopback.ipv6_scope_ids.len());
299
300 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 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}