sysinfo/common/network.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::collections::HashMap;
4use std::fmt;
5use std::net::{AddrParseError, IpAddr};
6use std::num::ParseIntError;
7use std::str::FromStr;
8
9use crate::{NetworkDataInner, NetworksInner};
10
11/// Interacting with network interfaces.
12///
13/// ```no_run
14/// use sysinfo::Networks;
15///
16/// let networks = Networks::new_with_refreshed_list();
17/// for (interface_name, network) in &networks {
18/// println!("[{interface_name}]: {network:?}");
19/// }
20/// ```
21pub struct Networks {
22 pub(crate) inner: NetworksInner,
23}
24
25impl<'a> IntoIterator for &'a Networks {
26 type Item = (&'a String, &'a NetworkData);
27 type IntoIter = std::collections::hash_map::Iter<'a, String, NetworkData>;
28
29 fn into_iter(self) -> Self::IntoIter {
30 self.iter()
31 }
32}
33
34impl Default for Networks {
35 fn default() -> Self {
36 Networks::new()
37 }
38}
39
40impl Networks {
41 /// Creates a new empty [`Networks`][crate::Networks] type.
42 ///
43 /// If you want it to be filled directly, take a look at [`Networks::new_with_refreshed_list`].
44 ///
45 /// ```no_run
46 /// use sysinfo::Networks;
47 ///
48 /// let mut networks = Networks::new();
49 /// networks.refresh(true);
50 /// for (interface_name, network) in &networks {
51 /// println!("[{interface_name}]: {network:?}");
52 /// }
53 /// ```
54 pub fn new() -> Self {
55 Self {
56 inner: NetworksInner::new(),
57 }
58 }
59
60 /// Creates a new [`Networks`][crate::Networks] type with the network interfaces
61 /// list loaded.
62 ///
63 /// ```no_run
64 /// use sysinfo::Networks;
65 ///
66 /// let networks = Networks::new_with_refreshed_list();
67 /// for network in &networks {
68 /// println!("{network:?}");
69 /// }
70 /// ```
71 pub fn new_with_refreshed_list() -> Self {
72 let mut networks = Self::new();
73 networks.refresh(false);
74 networks
75 }
76
77 /// Returns the network interfaces map.
78 ///
79 /// ```no_run
80 /// use sysinfo::Networks;
81 ///
82 /// let networks = Networks::new_with_refreshed_list();
83 /// for network in networks.list() {
84 /// println!("{network:?}");
85 /// }
86 /// ```
87 pub fn list(&self) -> &HashMap<String, NetworkData> {
88 self.inner.list()
89 }
90
91 /// Refreshes the network interfaces.
92 ///
93 /// ```no_run
94 /// use sysinfo::Networks;
95 ///
96 /// let mut networks = Networks::new_with_refreshed_list();
97 /// // Wait some time...? Then refresh the data of each network.
98 /// networks.refresh(true);
99 /// ```
100 pub fn refresh(&mut self, remove_not_listed_interfaces: bool) {
101 self.inner.refresh(remove_not_listed_interfaces)
102 }
103}
104
105impl std::ops::Deref for Networks {
106 type Target = HashMap<String, NetworkData>;
107
108 fn deref(&self) -> &Self::Target {
109 self.list()
110 }
111}
112
113/// Getting volume of received and transmitted data.
114///
115/// ```no_run
116/// use sysinfo::Networks;
117///
118/// let networks = Networks::new_with_refreshed_list();
119/// for (interface_name, network) in &networks {
120/// println!("[{interface_name}] {network:?}");
121/// }
122/// ```
123pub struct NetworkData {
124 pub(crate) inner: NetworkDataInner,
125}
126
127impl NetworkData {
128 /// Returns the number of received bytes since the last refresh.
129 ///
130 /// If you want the total number of bytes received, take a look at the
131 /// [`total_received`](NetworkData::total_received) method.
132 ///
133 /// ```no_run
134 /// use sysinfo::Networks;
135 /// use std::{thread, time};
136 ///
137 /// let mut networks = Networks::new_with_refreshed_list();
138 /// // Waiting a bit to get data from network...
139 /// thread::sleep(time::Duration::from_millis(10));
140 /// // Refreshing again to generate diff.
141 /// networks.refresh(true);
142 ///
143 /// for (interface_name, network) in &networks {
144 /// println!("in: {} B", network.received());
145 /// }
146 /// ```
147 pub fn received(&self) -> u64 {
148 self.inner.received()
149 }
150
151 /// Returns the total number of received bytes.
152 ///
153 /// If you want the amount of received bytes since the last refresh, take a look at the
154 /// [`received`](NetworkData::received) method.
155 ///
156 /// ```no_run
157 /// use sysinfo::Networks;
158 ///
159 /// let networks = Networks::new_with_refreshed_list();
160 /// for (interface_name, network) in &networks {
161 /// println!("in: {} B", network.total_received());
162 /// }
163 /// ```
164 pub fn total_received(&self) -> u64 {
165 self.inner.total_received()
166 }
167
168 /// Returns the number of transmitted bytes since the last refresh.
169 ///
170 /// If you want the total number of bytes transmitted, take a look at the
171 /// [`total_transmitted`](NetworkData::total_transmitted) method.
172 ///
173 /// ```no_run
174 /// use sysinfo::Networks;
175 /// use std::{thread, time};
176 ///
177 /// let mut networks = Networks::new_with_refreshed_list();
178 /// // Waiting a bit to get data from network...
179 /// thread::sleep(time::Duration::from_millis(10));
180 /// // Refreshing again to generate diff.
181 /// networks.refresh(true);
182 ///
183 /// for (interface_name, network) in &networks {
184 /// println!("out: {} B", network.transmitted());
185 /// }
186 /// ```
187 pub fn transmitted(&self) -> u64 {
188 self.inner.transmitted()
189 }
190
191 /// Returns the total number of transmitted bytes.
192 ///
193 /// If you want the amount of transmitted bytes since the last refresh, take a look at the
194 /// [`transmitted`](NetworkData::transmitted) method.
195 ///
196 /// ```no_run
197 /// use sysinfo::Networks;
198 ///
199 /// let networks = Networks::new_with_refreshed_list();
200 /// for (interface_name, network) in &networks {
201 /// println!("out: {} B", network.total_transmitted());
202 /// }
203 /// ```
204 pub fn total_transmitted(&self) -> u64 {
205 self.inner.total_transmitted()
206 }
207
208 /// Returns the number of incoming packets since the last refresh.
209 ///
210 /// If you want the total number of packets received, take a look at the
211 /// [`total_packets_received`](NetworkData::total_packets_received) method.
212 ///
213 /// ```no_run
214 /// use sysinfo::Networks;
215 /// use std::{thread, time};
216 ///
217 /// let mut networks = Networks::new_with_refreshed_list();
218 /// // Waiting a bit to get data from network...
219 /// thread::sleep(time::Duration::from_millis(10));
220 /// // Refreshing again to generate diff.
221 /// networks.refresh(true);
222 ///
223 /// for (interface_name, network) in &networks {
224 /// println!("in: {}", network.packets_received());
225 /// }
226 /// ```
227 pub fn packets_received(&self) -> u64 {
228 self.inner.packets_received()
229 }
230
231 /// Returns the total number of incoming packets.
232 ///
233 /// If you want the amount of received packets since the last refresh, take a look at the
234 /// [`packets_received`](NetworkData::packets_received) method.
235 ///
236 /// ```no_run
237 /// use sysinfo::Networks;
238 ///
239 /// let networks = Networks::new_with_refreshed_list();
240 /// for (interface_name, network) in &networks {
241 /// println!("in: {}", network.total_packets_received());
242 /// }
243 /// ```
244 pub fn total_packets_received(&self) -> u64 {
245 self.inner.total_packets_received()
246 }
247
248 /// Returns the number of outcoming packets since the last refresh.
249 ///
250 /// If you want the total number of packets transmitted, take a look at the
251 /// [`total_packets_transmitted`](NetworkData::total_packets_transmitted) method.
252 ///
253 /// ```no_run
254 /// use sysinfo::Networks;
255 /// use std::{thread, time};
256 ///
257 /// let mut networks = Networks::new_with_refreshed_list();
258 /// // Waiting a bit to get data from network...
259 /// thread::sleep(time::Duration::from_millis(10));
260 /// // Refreshing again to generate diff.
261 /// networks.refresh(true);
262 ///
263 /// for (interface_name, network) in &networks {
264 /// println!("out: {}", network.packets_transmitted());
265 /// }
266 /// ```
267 pub fn packets_transmitted(&self) -> u64 {
268 self.inner.packets_transmitted()
269 }
270
271 /// Returns the total number of outcoming packets.
272 ///
273 /// If you want the amount of transmitted packets since the last refresh, take a look at the
274 /// [`packets_transmitted`](NetworkData::packets_transmitted) method.
275 ///
276 /// ```no_run
277 /// use sysinfo::Networks;
278 ///
279 /// let networks = Networks::new_with_refreshed_list();
280 /// for (interface_name, network) in &networks {
281 /// println!("out: {}", network.total_packets_transmitted());
282 /// }
283 /// ```
284 pub fn total_packets_transmitted(&self) -> u64 {
285 self.inner.total_packets_transmitted()
286 }
287
288 /// Returns the number of incoming errors since the last refresh.
289 ///
290 /// If you want the total number of errors on received packets, take a look at the
291 /// [`total_errors_on_received`](NetworkData::total_errors_on_received) method.
292 ///
293 /// ```no_run
294 /// use sysinfo::Networks;
295 /// use std::{thread, time};
296 ///
297 /// let mut networks = Networks::new_with_refreshed_list();
298 /// // Waiting a bit to get data from network...
299 /// thread::sleep(time::Duration::from_millis(10));
300 /// // Refreshing again to generate diff.
301 /// networks.refresh(true);
302 ///
303 /// for (interface_name, network) in &networks {
304 /// println!("in: {}", network.errors_on_received());
305 /// }
306 /// ```
307 pub fn errors_on_received(&self) -> u64 {
308 self.inner.errors_on_received()
309 }
310
311 /// Returns the total number of incoming errors.
312 ///
313 /// If you want the amount of errors on received packets since the last refresh, take a look at
314 /// the [`errors_on_received`](NetworkData::errors_on_received) method.
315 ///
316 /// ```no_run
317 /// use sysinfo::Networks;
318 ///
319 /// let networks = Networks::new_with_refreshed_list();
320 /// for (interface_name, network) in &networks {
321 /// println!("in: {}", network.total_errors_on_received());
322 /// }
323 /// ```
324 pub fn total_errors_on_received(&self) -> u64 {
325 self.inner.total_errors_on_received()
326 }
327
328 /// Returns the number of outcoming errors since the last refresh.
329 ///
330 /// If you want the total number of errors on transmitted packets, take a look at the
331 /// [`total_errors_on_transmitted`](NetworkData::total_errors_on_transmitted) method.
332 ///
333 /// ```no_run
334 /// use sysinfo::Networks;
335 /// use std::{thread, time};
336 ///
337 /// let mut networks = Networks::new_with_refreshed_list();
338 /// // Waiting a bit to get data from network...
339 /// thread::sleep(time::Duration::from_millis(10));
340 /// // Refreshing again to generate diff.
341 /// networks.refresh(true);
342 ///
343 /// for (interface_name, network) in &networks {
344 /// println!("out: {}", network.errors_on_transmitted());
345 /// }
346 /// ```
347 pub fn errors_on_transmitted(&self) -> u64 {
348 self.inner.errors_on_transmitted()
349 }
350
351 /// Returns the total number of outcoming errors.
352 ///
353 /// If you want the amount of errors on transmitted packets since the last refresh, take a look at
354 /// the [`errors_on_transmitted`](NetworkData::errors_on_transmitted) method.
355 ///
356 /// ```no_run
357 /// use sysinfo::Networks;
358 ///
359 /// let networks = Networks::new_with_refreshed_list();
360 /// for (interface_name, network) in &networks {
361 /// println!("out: {}", network.total_errors_on_transmitted());
362 /// }
363 /// ```
364 pub fn total_errors_on_transmitted(&self) -> u64 {
365 self.inner.total_errors_on_transmitted()
366 }
367
368 /// Returns the MAC address associated to current interface.
369 ///
370 /// ```no_run
371 /// use sysinfo::Networks;
372 ///
373 /// let mut networks = Networks::new_with_refreshed_list();
374 /// for (interface_name, network) in &networks {
375 /// println!("MAC address: {}", network.mac_address());
376 /// }
377 /// ```
378 pub fn mac_address(&self) -> MacAddr {
379 self.inner.mac_address()
380 }
381
382 /// Returns the Ip Networks associated to current interface.
383 ///
384 /// ```no_run
385 /// use sysinfo::Networks;
386 ///
387 /// let mut networks = Networks::new_with_refreshed_list();
388 /// for (interface_name, network) in &networks {
389 /// println!("Ip Networks: {:?}", network.ip_networks());
390 /// }
391 /// ```
392 pub fn ip_networks(&self) -> &[IpNetwork] {
393 self.inner.ip_networks()
394 }
395
396 /// Returns the Maximum Transfer Unit (MTU) of the interface.
397 ///
398 /// ```no_run
399 /// use sysinfo::Networks;
400 ///
401 /// let mut networks = Networks::new_with_refreshed_list();
402 /// for (interface_name, network) in &networks {
403 /// println!("mtu: {}", network.mtu());
404 /// }
405 /// ```
406 pub fn mtu(&self) -> u64 {
407 self.inner.mtu()
408 }
409
410 /// Returns the operational state of the interface.
411 ///
412 /// The operational state indicates whether the interface is able to pass packets or not.
413 /// For details on the individual states see the documentation of the [`InterfaceOperationalState`] enum and its variants.
414 ///
415 /// ```no_run
416 /// use sysinfo::Networks;
417 ///
418 /// let mut networks = Networks::new_with_refreshed_list();
419 /// for (interface_name, network) in &networks {
420 /// println!("operational state: {}", network.operational_state());
421 /// }
422 /// ```
423 pub fn operational_state(&self) -> InterfaceOperationalState {
424 self.inner.operational_state()
425 }
426}
427
428/// MAC address for network interface.
429///
430/// It is returned by [`NetworkData::mac_address`][crate::NetworkData::mac_address].
431#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
432#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
433pub struct MacAddr(pub [u8; 6]);
434
435impl MacAddr {
436 /// A `MacAddr` with all bytes set to `0`.
437 pub const UNSPECIFIED: Self = MacAddr([0; 6]);
438
439 /// Checks if this `MacAddr` has all bytes equal to `0`.
440 pub fn is_unspecified(&self) -> bool {
441 self == &MacAddr::UNSPECIFIED
442 }
443}
444
445impl fmt::Display for MacAddr {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 let data = &self.0;
448 write!(
449 f,
450 "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
451 data[0], data[1], data[2], data[3], data[4], data[5],
452 )
453 }
454}
455
456/// Error type returned from `MacAddr::from_str` implementation.
457#[derive(Debug, Clone, PartialEq, Eq)]
458pub enum MacAddrFromStrError {
459 /// A number is not in hexadecimal format.
460 IntError(ParseIntError),
461 /// Input is not of format `{02X}:{02X}:{02X}:{02X}:{02X}:{02X}`.
462 InvalidAddrFormat,
463}
464
465impl FromStr for MacAddr {
466 type Err = MacAddrFromStrError;
467
468 fn from_str(s: &str) -> Result<Self, Self::Err> {
469 let mut parts = s
470 .split(':')
471 .map(|s| u8::from_str_radix(s, 16).map_err(MacAddrFromStrError::IntError));
472
473 let Some(data0) = parts.next() else {
474 return Err(MacAddrFromStrError::InvalidAddrFormat);
475 };
476 let Some(data1) = parts.next() else {
477 return Err(MacAddrFromStrError::InvalidAddrFormat);
478 };
479 let Some(data2) = parts.next() else {
480 return Err(MacAddrFromStrError::InvalidAddrFormat);
481 };
482 let Some(data3) = parts.next() else {
483 return Err(MacAddrFromStrError::InvalidAddrFormat);
484 };
485 let Some(data4) = parts.next() else {
486 return Err(MacAddrFromStrError::InvalidAddrFormat);
487 };
488 let Some(data5) = parts.next() else {
489 return Err(MacAddrFromStrError::InvalidAddrFormat);
490 };
491
492 if parts.next().is_some() {
493 return Err(MacAddrFromStrError::InvalidAddrFormat);
494 }
495
496 Ok(MacAddr([data0?, data1?, data2?, data3?, data4?, data5?]))
497 }
498}
499
500impl core::fmt::Display for MacAddrFromStrError {
501 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
502 match self {
503 Self::IntError(error) => write!(f, "a number is not in hexadecimal format: {error}"),
504 Self::InvalidAddrFormat => f.write_str("invalid address format"),
505 }
506 }
507}
508
509impl core::error::Error for MacAddrFromStrError {}
510
511/// IP networks address for network interface.
512///
513/// It is returned by [`NetworkData::ip_networks`][crate::NetworkData::ip_networks].
514#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
515#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
516pub struct IpNetwork {
517 /// The IP of the network interface.
518 pub addr: IpAddr,
519 /// The netmask, prefix of the IP address.
520 pub prefix: u8,
521}
522
523impl fmt::Display for IpNetwork {
524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525 write!(f, "{}/{}", self.addr, self.prefix)
526 }
527}
528
529/// Error type returned from `MacAddr::from_str` implementation.
530#[derive(Debug, Clone, PartialEq, Eq)]
531pub enum IpNetworkFromStrError {
532 /// Prefix is not an integer.
533 PrefixError(ParseIntError),
534 /// Failed to parse IP address.
535 AddrParseError(AddrParseError),
536 /// Input is not of format `[IP address]/[number]`.
537 InvalidAddrFormat,
538}
539
540impl FromStr for IpNetwork {
541 type Err = IpNetworkFromStrError;
542
543 #[allow(clippy::from_str_radix_10)]
544 fn from_str(s: &str) -> Result<Self, Self::Err> {
545 let mut parts = s.split('/');
546
547 let Some(addr) = parts.next() else {
548 return Err(IpNetworkFromStrError::InvalidAddrFormat);
549 };
550 let Some(prefix) = parts.next() else {
551 return Err(IpNetworkFromStrError::InvalidAddrFormat);
552 };
553 if parts.next().is_some() {
554 return Err(IpNetworkFromStrError::InvalidAddrFormat);
555 }
556
557 Ok(IpNetwork {
558 addr: IpAddr::from_str(addr).map_err(IpNetworkFromStrError::AddrParseError)?,
559 prefix: u8::from_str_radix(prefix, 10).map_err(IpNetworkFromStrError::PrefixError)?,
560 })
561 }
562}
563
564impl core::fmt::Display for IpNetworkFromStrError {
565 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
566 match self {
567 Self::PrefixError(error) => write!(f, "prefix is not an integer: {error}"),
568 Self::AddrParseError(error) => write!(f, "failed to parse IP address: {error}"),
569 Self::InvalidAddrFormat => {
570 f.write_str("invalid address format, should `[IP address]/[number]`")
571 }
572 }
573 }
574}
575
576impl core::error::Error for IpNetworkFromStrError {}
577
578/// The operational state of some interface based on `IfOperStatus`
579/// from [RFC2863].
580///
581/// Not all states are supported by all systems.
582///
583/// If you want to only distinguish between potentially operational and not operational you
584/// likely want to:
585/// - treat [`Up`][Self::Up], [`Dormant`][Self::Dormant] and [`Unknown`][Self::Unknown] as potentially operational
586/// - treat [`Down`][Self::Down], [`Testing`][Self::Testing], [`NotPresent`][Self::NotPresent] and [`LowerLayerDown`][Self::LowerLayerDown] as not operational
587///
588/// [RFC2863]: https://datatracker.ietf.org/doc/html/rfc2863#section-3.1.12
589///
590// windows: https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.operationalstatus?view=net-10.0
591// linux: https://docs.kernel.org/networking/operstates.html#tlv-ifla-operstate
592// discriminants based on windows
593#[non_exhaustive]
594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
595pub enum InterfaceOperationalState {
596 #[doc(hidden)]
597 #[non_exhaustive]
598 /// InterfaceOperationalState is unsupported or had an unrecognized value
599 Other,
600 /// The interface is able to pass packets.
601 Up = 1,
602 /// The interface is unable to pass packets.
603 ///
604 /// ## Examples
605 /// - an error condition has occurred
606 /// - the interface is disabled
607 Down = 2,
608 /// The interface is unable to pass packets.
609 /// The interface is performing some test(s).
610 /// Presumably it will change into another appropriate state once testing completes.
611 ///
612 /// ## Examples
613 /// - driver self-test
614 /// - media (e.g. cable) test
615 Testing = 3,
616 /// The state of the interface is unknown.
617 /// The interface may or may not be usable.
618 ///
619 /// ## Examples
620 /// - on linux the loopback interface (localhost, 127.0.0.1/8, ::1/128) typically has this state
621 Unknown = 4,
622 /// The interface is unable to pass packets.
623 /// It is in a "pending state" waiting for some external event.
624 /// When the event occurs the interface will prusumably change into the `Up`` state.
625 ///
626 /// ## Examples
627 /// - an "on-demand" interface might be waiting for a package in the transmit queue to establish a connection.
628 /// - an interface might be waiting for the remote system to establish a connection
629 /// - waiting for 802.1X protocol to establish a connection
630 Dormant = 5,
631 /// The interface is unable to pass packets.
632 /// A (hardware) component is not present.
633 ///
634 /// This is a refinement on `Down`.
635 ///
636 /// ## Examples
637 /// - hot-swap module is currently not installed
638 /// - pre-configured interface is not yet installed
639 /// - an interface has been removed but is still configured
640 NotPresent = 6,
641 /// The interface is unable to pass packets.
642 /// This interface depends on one or more interfaces and at least one of these interfaces prevents this interface from being `Up`.
643 ///
644 /// This is a refinement on `Down`.
645 ///
646 /// ## Examples
647 /// - a VPN interface depends on any physical interface being up but the physical interface is testing the cable to determine the available speed
648 /// - a single virtual interface that aggregates multiple physical interfaces but all physical interfaces are down
649 LowerLayerDown = 7,
650}
651
652impl fmt::Display for InterfaceOperationalState {
653 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
654 // see /sys/class/net/<iface>/operstate section at https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net
655 f.write_str(match self {
656 InterfaceOperationalState::Other => "other",
657 InterfaceOperationalState::Up => "up",
658 InterfaceOperationalState::Down => "down",
659 InterfaceOperationalState::Testing => "testing",
660 InterfaceOperationalState::Unknown => "unknown",
661 InterfaceOperationalState::Dormant => "dormant",
662 InterfaceOperationalState::NotPresent => "notpresent",
663 InterfaceOperationalState::LowerLayerDown => "lowerlayerdown",
664 })
665 }
666}
667
668#[cfg(test)]
669mod tests {
670 use crate::*;
671 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
672 use std::str::FromStr;
673
674 // Ensure that the `Display` and `Debug` traits are implemented on the `MacAddr` struct
675 #[test]
676 fn check_display_impl_mac_address() {
677 println!(
678 "{} {:?}",
679 MacAddr([0x1, 0x2, 0x3, 0x4, 0x5, 0x6]),
680 MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf])
681 );
682 }
683
684 #[test]
685 fn check_mac_address_is_unspecified_true() {
686 assert!(MacAddr::UNSPECIFIED.is_unspecified());
687 assert!(MacAddr([0; 6]).is_unspecified());
688 }
689
690 #[test]
691 fn check_mac_address_is_unspecified_false() {
692 assert!(!MacAddr([1, 2, 3, 4, 5, 6]).is_unspecified());
693 }
694
695 #[test]
696 fn check_mac_address_conversions() {
697 let mac = MacAddr([0xa, 0xb, 0xc, 0xd, 0xe, 0xf]);
698
699 let mac_s = mac.to_string();
700 assert_eq!("0a:0b:0c:0d:0e:0f", mac_s);
701 assert_eq!(Ok(mac), MacAddr::from_str(&mac_s));
702
703 assert_eq!(
704 MacAddr::from_str("0a:0b:0c:0d:0e:0f:01"),
705 Err(MacAddrFromStrError::InvalidAddrFormat)
706 );
707 assert_eq!(
708 MacAddr::from_str("0a:0b:0c:0d:0e"),
709 Err(MacAddrFromStrError::InvalidAddrFormat)
710 );
711 }
712
713 // Ensure that the `Display` and `Debug` traits are implemented on the `IpNetwork` struct
714 #[test]
715 fn check_display_impl_ip_network_ipv4() {
716 println!(
717 "{} {:?}",
718 IpNetwork {
719 addr: IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)),
720 prefix: 3
721 },
722 IpNetwork {
723 addr: IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)),
724 prefix: 21
725 }
726 );
727 }
728
729 #[test]
730 fn check_display_impl_ip_network_ipv6() {
731 println!(
732 "{} {:?}",
733 IpNetwork {
734 addr: IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)),
735 prefix: 127
736 },
737 IpNetwork {
738 addr: IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)),
739 prefix: 120
740 }
741 )
742 }
743
744 #[test]
745 fn check_ip_networks() {
746 if !IS_SUPPORTED_SYSTEM {
747 return;
748 }
749 let networks = Networks::new_with_refreshed_list();
750 if networks.iter().any(|(_, n)| !n.ip_networks().is_empty()) {
751 return;
752 }
753 panic!("Networks should have at least one IP network ");
754 }
755
756 #[test]
757 fn check_ip_network_conversions() {
758 let addr = IpNetwork {
759 addr: IpAddr::from(Ipv6Addr::new(0xff, 0xa, 0x8, 0x12, 0x7, 0xc, 0xa, 0xb)),
760 prefix: 12,
761 };
762
763 let addr_s = addr.to_string();
764 assert_eq!("ff:a:8:12:7:c:a:b/12", addr_s);
765 assert_eq!(Ok(addr), IpNetwork::from_str(&addr_s));
766
767 let addr = IpNetwork {
768 addr: IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)),
769 prefix: 21,
770 };
771
772 let addr_s = addr.to_string();
773 assert_eq!("255.255.255.0/21", addr_s);
774 assert_eq!(Ok(addr), IpNetwork::from_str(&addr_s));
775
776 assert_eq!(
777 IpNetwork::from_str("ff:a:8:12:7:c:a:b"),
778 Err(IpNetworkFromStrError::InvalidAddrFormat)
779 );
780 assert_eq!(
781 IpNetwork::from_str("ff:a:8:12:7:c:a:b/12/12"),
782 Err(IpNetworkFromStrError::InvalidAddrFormat)
783 );
784 match IpNetwork::from_str("0a:0b:0c:0d:0e/12") {
785 Err(IpNetworkFromStrError::AddrParseError(_)) => {}
786 x => panic!("expected `IpNetworkFromStrError::AddrParseError`, found {x:?}"),
787 }
788 }
789}