From e6d2436a977f37768de5c2b3ee621c4271a66e36 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Tue, 5 Mar 2024 16:27:27 +0800 Subject: [PATCH 01/12] feat: add ip networks for interface --- Cargo.lock | 180 +++++++++++++++++++++++++++++++--- Cargo.toml | 5 + src/common.rs | 15 +++ src/lib.rs | 1 + src/network.rs | 8 +- src/serde.rs | 1 + src/unix/apple/network.rs | 9 ++ src/unix/freebsd/network.rs | 7 ++ src/unix/linux/network.rs | 7 ++ src/unix/network_helper.rs | 13 ++- src/unknown/network.rs | 4 + src/windows/network.rs | 5 + src/windows/network_helper.rs | 18 ++++ 13 files changed, 258 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2b5f7656a..a1eea0f21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -73,6 +73,27 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + [[package]] name = "itoa" version = "1.0.10" @@ -91,6 +112,12 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + [[package]] name = "ntapi" version = "0.4.1" @@ -106,6 +133,38 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "pnet_base" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5854abf0067ebbd3967f7d45ebc8976ff577ff0c7bd101c4973ae3c70f98fe" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417c0becd1b573f6d544f73671070b039051e5ad819cc64aa96377b536128d00" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -163,7 +222,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -203,6 +262,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "syn" version = "2.0.48" @@ -220,9 +289,12 @@ version = "0.30.6" dependencies = [ "cfg-if", "core-foundation-sys", + "ipconfig", + "ipnetwork", "libc", "ntapi", "once_cell", + "pnet_datalink", "rayon", "serde", "serde_json", @@ -240,7 +312,7 @@ dependencies = [ "fastrand", "redox_syscall", "rustix", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -249,6 +321,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "widestring" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" + [[package]] name = "winapi" version = "0.3.9" @@ -278,7 +356,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets", + "windows-targets 0.52.0", ] [[package]] @@ -287,7 +365,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -296,7 +383,22 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -305,53 +407,105 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] diff --git a/Cargo.toml b/Cargo.toml index c4cbe423b..458350d1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,12 +43,17 @@ rustdoc-args = ["--generate-link-to-definition"] cfg-if = "1.0" rayon = { version = "^1.8", optional = true } serde = { version = "^1.0.190", optional = true } +ipnetwork = "0.20" [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies] once_cell = "1.18" +[target.'cfg(unix)'.dependencies] +pnet_datalink = "0.34" + [target.'cfg(windows)'.dependencies] ntapi = "0.4" +ipconfig = "0.3.2" windows = { version = "0.52", features = [ "Wdk_System_SystemInformation", "Wdk_System_SystemServices", diff --git a/src/common.rs b/src/common.rs index 40bbfa10b..e18cf9c69 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,6 +5,7 @@ use crate::{ SystemInner, UserInner, }; +use ipnetwork::IpNetwork; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; @@ -2328,6 +2329,20 @@ impl NetworkData { pub fn mac_address(&self) -> MacAddr { self.inner.mac_address() } + + /// Returns the Ip Networks associated to current interface. + /// + /// ```no_run + /// use sysinfo::Networks; + /// + /// let mut networks = Networks::new_with_refreshed_list(); + /// for (interface_name, network) in &networks { + /// println!("Ip Networks: {}", network.ip_networks()); + /// } + /// ``` + pub fn ip_networks(&self) -> &[IpNetwork] { + self.inner.ip_networks() + } } /// Struct containing a disk information. diff --git a/src/lib.rs b/src/lib.rs index 7b23e4201..53e6e98ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ pub(crate) use crate::sys::{ NetworksInner, ProcessInner, SystemInner, UserInner, }; pub use crate::sys::{IS_SUPPORTED_SYSTEM, MINIMUM_CPU_UPDATE_INTERVAL, SUPPORTED_SIGNALS}; +pub use ipnetwork::IpNetwork; #[cfg(feature = "c-interface")] pub use crate::c_interface::*; diff --git a/src/network.rs b/src/network.rs index d7cdcec0c..02eabd4bf 100644 --- a/src/network.rs +++ b/src/network.rs @@ -2,11 +2,17 @@ use std::collections::HashMap; -use crate::network_helper::get_interface_address; +use crate::network_helper::{get_interface_address, get_interface_ip_networks}; use crate::NetworkData; /// Interface addresses are OS-independent pub(crate) fn refresh_networks_addresses(interfaces: &mut HashMap) { + let ip_network_map = get_interface_ip_networks(); + for (interface_name, ip_networks) in ip_network_map { + if let Some(interface) = interfaces.get_mut(&interface_name) { + interface.inner.ip_networks = ip_networks; + } + } match get_interface_address() { Ok(ifa_iterator) => { for (name, ifa) in ifa_iterator { diff --git a/src/serde.rs b/src/serde.rs index 1b273b43c..bb6304842 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -286,6 +286,7 @@ impl Serialize for crate::NetworkData { &self.total_errors_on_transmitted(), )?; state.serialize_field("mac_address", &self.mac_address())?; + state.serialize_field("ip_networks", &self.ip_networks())?; state.end() } diff --git a/src/unix/apple/network.rs b/src/unix/apple/network.rs index 78fcf50b7..6b1489691 100644 --- a/src/unix/apple/network.rs +++ b/src/unix/apple/network.rs @@ -5,6 +5,8 @@ use libc::{self, c_char, if_msghdr2, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFIN use std::collections::{hash_map, HashMap}; use std::ptr::null_mut; +use ipnetwork::IpNetwork; + use crate::common::MacAddr; use crate::network::refresh_networks_addresses; use crate::NetworkData; @@ -167,6 +169,7 @@ impl NetworksInner { old_errors_out: errors_out, updated: true, mac_addr: MacAddr::UNSPECIFIED, + ip_networks: vec![], }, }); } @@ -194,6 +197,8 @@ pub(crate) struct NetworkDataInner { updated: bool, /// MAC address pub(crate) mac_addr: MacAddr, + /// IP networks + pub(crate) ip_networks: Vec, } impl NetworkDataInner { @@ -248,4 +253,8 @@ impl NetworkDataInner { pub(crate) fn mac_address(&self) -> MacAddr { self.mac_addr } + + pub(crate) fn ip_networks(&self) -> &[IpNetwork] { + &self.ip_networks + } } diff --git a/src/unix/freebsd/network.rs b/src/unix/freebsd/network.rs index 35e9da62b..d144a797d 100644 --- a/src/unix/freebsd/network.rs +++ b/src/unix/freebsd/network.rs @@ -115,6 +115,7 @@ impl NetworksInner { old_ifi_oerrors: 0, updated: true, mac_addr: MacAddr::UNSPECIFIED, + ip_networks: vec![], }, }); } @@ -149,6 +150,8 @@ pub(crate) struct NetworkDataInner { updated: bool, /// MAC address pub(crate) mac_addr: MacAddr, + /// IP networks + pub(crate) ip_networks: Vec, } impl NetworkDataInner { @@ -203,4 +206,8 @@ impl NetworkDataInner { pub(crate) fn mac_address(&self) -> MacAddr { self.mac_addr } + + pub(crate) fn ip_networks(&self) -> &[IpNetwork] { + &self.ip_networks + } } diff --git a/src/unix/linux/network.rs b/src/unix/linux/network.rs index da7040982..1fe3b60ee 100644 --- a/src/unix/linux/network.rs +++ b/src/unix/linux/network.rs @@ -1,5 +1,6 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use ipnetwork::IpNetwork; use std::collections::{hash_map, HashMap}; use std::io::Read; use std::path::Path; @@ -95,6 +96,7 @@ fn refresh_networks_list_from_sysfs( tx_errors, old_tx_errors: tx_errors, mac_addr: MacAddr::UNSPECIFIED, + ip_networks: vec![], // rx_compressed, // old_rx_compressed: rx_compressed, // tx_compressed, @@ -163,6 +165,7 @@ pub(crate) struct NetworkDataInner { old_tx_errors: u64, /// MAC address pub(crate) mac_addr: MacAddr, + pub(crate) ip_networks: Vec, // /// Indicates the number of compressed packets received by this // /// network device. This value might only be relevant for interfaces // /// that support packet compression (e.g: PPP). @@ -271,6 +274,10 @@ impl NetworkDataInner { pub(crate) fn mac_address(&self) -> MacAddr { self.mac_addr } + + pub(crate) fn ip_networks(&self) -> &[IpNetwork] { + &self.ip_networks + } } #[cfg(test)] diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index d9570c1b1..23883194e 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -1,8 +1,12 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use crate::common::MacAddr; +use std::collections::HashMap; use std::ptr::null_mut; +use ipnetwork::IpNetwork; + +use crate::common::MacAddr; + /// This iterator yields an interface name and address. pub(crate) struct InterfaceAddressIterator { /// Pointer to the current `ifaddrs` struct. @@ -116,3 +120,10 @@ pub(crate) fn get_interface_address() -> Result HashMap> { + pnet_datalink::interfaces() + .into_iter() + .map(|i| (i.name, i.ips)) + .collect() +} diff --git a/src/unknown/network.rs b/src/unknown/network.rs index d6159d24a..7a391d79e 100644 --- a/src/unknown/network.rs +++ b/src/unknown/network.rs @@ -79,4 +79,8 @@ impl NetworkDataInner { pub(crate) fn mac_address(&self) -> MacAddr { MacAddr::UNSPECIFIED } + + pub(crate) fn ip_networks(&self) -> &[IpNetwork] { + &[] + } } diff --git a/src/windows/network.rs b/src/windows/network.rs index fb7490f26..a0d09178b 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -200,6 +200,7 @@ pub(crate) struct NetworkDataInner { old_errors_out: u64, updated: bool, pub(crate) mac_addr: MacAddr, + pub(crate) ip_networks: Vec, } impl NetworkDataInner { @@ -254,4 +255,8 @@ impl NetworkDataInner { pub(crate) fn mac_address(&self) -> MacAddr { self.mac_addr } + + pub(crate) fn ip_networks(&self) -> &[IpNetwork] { + &self.ip_networks + } } diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 18752ecc3..9e951c01e 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -1,5 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use ipnetwork::IpNetwork; +use std::collections::HashMap; use std::ptr::null_mut; use windows::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_SUCCESS}; @@ -105,3 +107,19 @@ pub(crate) fn get_interface_address() -> Result HashMap> { + ipconfig::get_adapters() + .unwrap_or(vec![]) + .into_iter() + .map(|a| { + ( + a.friendly_name().to_owned(), + a.prefixes() + .into_iter() + .map(|(addr, prefix)| IpNetwork::new(addr, prefix)) + .collect(), + ) + }) + .collect(); +} From a864c3e5e4afb4409994bd5069be025e05938b4f Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Tue, 5 Mar 2024 17:19:53 +0800 Subject: [PATCH 02/12] fix: fix cross compile error --- src/common.rs | 2 +- src/unix/apple/network.rs | 5 ++--- src/unix/freebsd/network.rs | 3 ++- src/unknown/network.rs | 1 + src/windows/network.rs | 2 ++ src/windows/network_helper.rs | 8 ++++---- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/common.rs b/src/common.rs index e18cf9c69..cc311a481 100644 --- a/src/common.rs +++ b/src/common.rs @@ -2337,7 +2337,7 @@ impl NetworkData { /// /// let mut networks = Networks::new_with_refreshed_list(); /// for (interface_name, network) in &networks { - /// println!("Ip Networks: {}", network.ip_networks()); + /// println!("Ip Networks: {:?}", network.ip_networks()); /// } /// ``` pub fn ip_networks(&self) -> &[IpNetwork] { diff --git a/src/unix/apple/network.rs b/src/unix/apple/network.rs index 6b1489691..d48f084c1 100644 --- a/src/unix/apple/network.rs +++ b/src/unix/apple/network.rs @@ -5,10 +5,9 @@ use libc::{self, c_char, if_msghdr2, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFIN use std::collections::{hash_map, HashMap}; use std::ptr::null_mut; -use ipnetwork::IpNetwork; - use crate::common::MacAddr; use crate::network::refresh_networks_addresses; +use crate::IpNetwork; use crate::NetworkData; macro_rules! old_and_new { @@ -198,7 +197,7 @@ pub(crate) struct NetworkDataInner { /// MAC address pub(crate) mac_addr: MacAddr, /// IP networks - pub(crate) ip_networks: Vec, + pub(crate) ip_networks: Vec, } impl NetworkDataInner { diff --git a/src/unix/freebsd/network.rs b/src/unix/freebsd/network.rs index d144a797d..644eed90b 100644 --- a/src/unix/freebsd/network.rs +++ b/src/unix/freebsd/network.rs @@ -6,6 +6,7 @@ use std::mem::MaybeUninit; use super::utils; use crate::common::MacAddr; use crate::network::refresh_networks_addresses; +use crate::IpNetwork; use crate::NetworkData; macro_rules! old_and_new { @@ -151,7 +152,7 @@ pub(crate) struct NetworkDataInner { /// MAC address pub(crate) mac_addr: MacAddr, /// IP networks - pub(crate) ip_networks: Vec, + pub(crate) ip_networks: Vec, } impl NetworkDataInner { diff --git a/src/unknown/network.rs b/src/unknown/network.rs index 7a391d79e..917320a65 100644 --- a/src/unknown/network.rs +++ b/src/unknown/network.rs @@ -2,6 +2,7 @@ use crate::common::MacAddr; use crate::NetworkData; +use crate::IpNetwork; use std::collections::HashMap; diff --git a/src/windows/network.rs b/src/windows/network.rs index a0d09178b..e89db787d 100644 --- a/src/windows/network.rs +++ b/src/windows/network.rs @@ -2,6 +2,7 @@ use crate::common::MacAddr; use crate::network::refresh_networks_addresses; +use crate::IpNetwork; use crate::NetworkData; use std::collections::{hash_map, HashMap}; @@ -137,6 +138,7 @@ impl NetworksInner { errors_out: ptr.OutErrors, old_errors_out: ptr.OutErrors, mac_addr: MacAddr::UNSPECIFIED, + ip_networks: vec![], updated: true, }, }); diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 9e951c01e..b3671a294 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -108,7 +108,7 @@ pub(crate) fn get_interface_address() -> Result HashMap> { +pub(crate) fn get_interface_ip_networks() -> HashMap> { ipconfig::get_adapters() .unwrap_or(vec![]) .into_iter() @@ -116,10 +116,10 @@ pub(crate) fn get_interface_ip_network() -> HashMap> { ( a.friendly_name().to_owned(), a.prefixes() - .into_iter() - .map(|(addr, prefix)| IpNetwork::new(addr, prefix)) + .iter() + .filter_map(|(addr, prefix)| IpNetwork::new(*addr, *prefix as u8).ok()) .collect(), ) }) - .collect(); + .collect() } From 269a64396a987feb61b6e31aa8ab32665bfa14b4 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Tue, 5 Mar 2024 17:46:21 +0800 Subject: [PATCH 03/12] chore: update clippy and fmt check --- src/unknown/network.rs | 2 +- src/windows/network_helper.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unknown/network.rs b/src/unknown/network.rs index 917320a65..8c657e3f3 100644 --- a/src/unknown/network.rs +++ b/src/unknown/network.rs @@ -1,8 +1,8 @@ // Take a look at the license at the top of the repository in the LICENSE file. use crate::common::MacAddr; -use crate::NetworkData; use crate::IpNetwork; +use crate::NetworkData; use std::collections::HashMap; diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index b3671a294..4958644f2 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -110,7 +110,7 @@ pub(crate) fn get_interface_address() -> Result HashMap> { ipconfig::get_adapters() - .unwrap_or(vec![]) + .unwrap_or_default() .into_iter() .map(|a| { ( From 10ea6b1ffb4979220e02b4c2e040749b9b16be74 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Wed, 6 Mar 2024 18:06:25 +0800 Subject: [PATCH 04/12] refactor: not use crates for getting interface ip networks --- Cargo.lock | 180 ++-------------------- Cargo.toml | 5 - src/common.rs | 35 ++++- src/lib.rs | 25 +++- src/network.rs | 5 +- src/serde.rs | 14 ++ src/unix/linux/network.rs | 3 +- src/unix/network_helper.rs | 271 +++++++++++++++++++++++++++++++++- src/windows/network_helper.rs | 84 ++++++++--- 9 files changed, 412 insertions(+), 210 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1eea0f21..2b5f7656a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -73,27 +73,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2", - "widestring", - "windows-sys 0.48.0", - "winreg", -] - -[[package]] -name = "ipnetwork" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" -dependencies = [ - "serde", -] - [[package]] name = "itoa" version = "1.0.10" @@ -112,12 +91,6 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" -[[package]] -name = "no-std-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" - [[package]] name = "ntapi" version = "0.4.1" @@ -133,38 +106,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "pnet_base" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cf6fb3ab38b68d01ab2aea03ed3d1132b4868fa4e06285f29f16da01c5f4c" -dependencies = [ - "no-std-net", -] - -[[package]] -name = "pnet_datalink" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad5854abf0067ebbd3967f7d45ebc8976ff577ff0c7bd101c4973ae3c70f98fe" -dependencies = [ - "ipnetwork", - "libc", - "pnet_base", - "pnet_sys", - "winapi", -] - -[[package]] -name = "pnet_sys" -version = "0.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "417c0becd1b573f6d544f73671070b039051e5ad819cc64aa96377b536128d00" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "proc-macro2" version = "1.0.78" @@ -222,7 +163,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -262,16 +203,6 @@ dependencies = [ "serde", ] -[[package]] -name = "socket2" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "syn" version = "2.0.48" @@ -289,12 +220,9 @@ version = "0.30.6" dependencies = [ "cfg-if", "core-foundation-sys", - "ipconfig", - "ipnetwork", "libc", "ntapi", "once_cell", - "pnet_datalink", "rayon", "serde", "serde_json", @@ -312,7 +240,7 @@ dependencies = [ "fastrand", "redox_syscall", "rustix", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -321,12 +249,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "widestring" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8" - [[package]] name = "winapi" version = "0.3.9" @@ -356,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.52.0", + "windows-targets", ] [[package]] @@ -365,16 +287,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -383,22 +296,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -407,105 +305,53 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] diff --git a/Cargo.toml b/Cargo.toml index 458350d1f..c4cbe423b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,17 +43,12 @@ rustdoc-args = ["--generate-link-to-definition"] cfg-if = "1.0" rayon = { version = "^1.8", optional = true } serde = { version = "^1.0.190", optional = true } -ipnetwork = "0.20" [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies] once_cell = "1.18" -[target.'cfg(unix)'.dependencies] -pnet_datalink = "0.34" - [target.'cfg(windows)'.dependencies] ntapi = "0.4" -ipconfig = "0.3.2" windows = { version = "0.52", features = [ "Wdk_System_SystemInformation", "Wdk_System_SystemServices", diff --git a/src/common.rs b/src/common.rs index cc311a481..594027815 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,12 +5,13 @@ use crate::{ SystemInner, UserInner, }; -use ipnetwork::IpNetwork; use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; use std::ffi::OsStr; use std::fmt; +use std::fmt::Formatter; +use std::net::IpAddr; use std::path::Path; use std::str::FromStr; @@ -3650,6 +3651,38 @@ impl fmt::Display for MacAddr { } } +/// Ip networks address for network interface. +/// +/// It is returned by [`NetworkData::ip_networks`][crate::NetworkData::ip_networks]. +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct IpNetwork { + addr: IpAddr, + prefix: u8, +} + +impl IpNetwork { + /// build new IpNetwork + pub fn new(addr: IpAddr, prefix: u8) -> Self { + Self { addr, prefix } + } + + /// return the addr of the IpNetwork + pub fn addr(&self) -> IpAddr { + self.addr + } + + /// return the prefix of the IpNetwork + pub fn prefix(&self) -> u8 { + self.prefix + } +} + +impl fmt::Display for IpNetwork { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", self.addr, self.prefix) + } +} + /// Interacting with components. /// /// ```no_run diff --git a/src/lib.rs b/src/lib.rs index 53e6e98ed..1cc0cbf26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,9 +52,9 @@ cfg_if::cfg_if! { pub use crate::common::{ get_current_pid, CGroupLimits, Component, Components, Cpu, CpuRefreshKind, Disk, DiskKind, - DiskUsage, Disks, Gid, Group, Groups, LoadAvg, MacAddr, MemoryRefreshKind, NetworkData, - Networks, Pid, Process, ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, System, - ThreadKind, Uid, UpdateKind, User, Users, + DiskUsage, Disks, Gid, Group, Groups, IpNetwork, LoadAvg, MacAddr, MemoryRefreshKind, + NetworkData, Networks, Pid, Process, ProcessRefreshKind, ProcessStatus, RefreshKind, Signal, + System, ThreadKind, Uid, UpdateKind, User, Users, }; pub(crate) use crate::common::GroupInner; @@ -63,7 +63,6 @@ pub(crate) use crate::sys::{ NetworksInner, ProcessInner, SystemInner, UserInner, }; pub use crate::sys::{IS_SUPPORTED_SYSTEM, MINIMUM_CPU_UPDATE_INTERVAL, SUPPORTED_SIGNALS}; -pub use ipnetwork::IpNetwork; #[cfg(feature = "c-interface")] pub use crate::c_interface::*; @@ -178,6 +177,7 @@ mod doctest { #[cfg(test)] mod test { + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::*; #[cfg(feature = "unknown-ci")] @@ -544,6 +544,23 @@ mod test { assert!(!MacAddr([1, 2, 3, 4, 5, 6]).is_unspecified()); } + // Ensure that the `Display` and `Debug` traits are implemented on the `IpNetwork` struct + #[test] + fn check_display_impl_ip_network_ipv4() { + println!("{} {:?}", + IpNetwork::new(IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)), 3), + IpNetwork::new(IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)), 21) + ); + } + + #[test] + fn check_display_impl_ip_network_ipv6() { + println!("{} {:?}", + IpNetwork::new(IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)), 127), + IpNetwork::new(IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)), 120) + ) + } + // This test exists to ensure that the `TryFrom` and `FromStr` traits are implemented // on `Uid`, `Gid` and `Pid`. #[allow(clippy::unnecessary_fallible_conversions)] diff --git a/src/network.rs b/src/network.rs index 02eabd4bf..4f0a72eb1 100644 --- a/src/network.rs +++ b/src/network.rs @@ -7,10 +7,9 @@ use crate::NetworkData; /// Interface addresses are OS-independent pub(crate) fn refresh_networks_addresses(interfaces: &mut HashMap) { - let ip_network_map = get_interface_ip_networks(); - for (interface_name, ip_networks) in ip_network_map { + for (interface_name, ip_networks) in get_interface_ip_networks() { if let Some(interface) = interfaces.get_mut(&interface_name) { - interface.inner.ip_networks = ip_networks; + interface.inner.ip_networks = ip_networks.into_iter().collect::>(); } } match get_interface_address() { diff --git a/src/serde.rs b/src/serde.rs index bb6304842..888081300 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -414,3 +414,17 @@ impl Serialize for crate::MacAddr { serializer.serialize_newtype_struct("MacAddr", &self.0) } } + +impl Serialize for crate::IpNetwork { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut state = serializer.serialize_struct("IpNetwork", 2)?; + + state.serialize_field("addr", &self.addr())?; + state.serialize_field("prefix", &self.prefix())?; + + state.end() + } +} diff --git a/src/unix/linux/network.rs b/src/unix/linux/network.rs index 1fe3b60ee..a428cc276 100644 --- a/src/unix/linux/network.rs +++ b/src/unix/linux/network.rs @@ -1,12 +1,11 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use ipnetwork::IpNetwork; use std::collections::{hash_map, HashMap}; use std::io::Read; use std::path::Path; use std::{fs::File, u8}; -use crate::common::MacAddr; +use crate::common::{IpNetwork, MacAddr}; use crate::network::refresh_networks_addresses; use crate::NetworkData; diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index 23883194e..1365ca3a3 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -1,11 +1,17 @@ // Take a look at the license at the top of the repository in the LICENSE file. use std::collections::HashMap; +use std::collections::HashSet; +use std::ffi::CStr; +use std::mem::MaybeUninit; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; +use std::os::raw::c_char; use std::ptr::null_mut; +use std::str::from_utf8_unchecked; +use std::{io, mem}; -use ipnetwork::IpNetwork; - -use crate::common::MacAddr; +use crate::common::{IpNetwork, MacAddr}; /// This iterator yields an interface name and address. pub(crate) struct InterfaceAddressIterator { @@ -121,9 +127,258 @@ pub(crate) fn get_interface_address() -> Result HashMap> { - pnet_datalink::interfaces() - .into_iter() - .map(|i| (i.name, i.ips)) - .collect() +pub(crate) fn get_interface_ip_networks() -> HashMap> { + let mut ifaces: HashMap> = HashMap::new(); + let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); + + // Safety: addrs.as_mut_ptr() is valid, it points to addrs. + if unsafe { libc::getifaddrs(addrs.as_mut_ptr()) } != 0 { + return ifaces; + } + + // Safety: If there was an error, we would have already returned. + // Therefore, getifaddrs has initialized `addrs`. + let addrs = unsafe { addrs.assume_init() }; + + let mut addr = addrs; + while !addr.is_null() { + // Safety: We assume that addr is valid for the lifetime of this loop + // body, and is not mutated. + let addr_ref: &libc::ifaddrs = unsafe { &*addr }; + + let c_str = addr_ref.ifa_name as *const c_char; + + // Safety: ifa_name is a null terminated interface name + let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; + + // Safety: Interfaces on unix must be valid UTF-8 + let name = unsafe { from_utf8_unchecked(bytes).to_owned() }; + let ip = sockaddr_to_network_addr(addr_ref.ifa_addr as *const libc::sockaddr); + let netmask = sockaddr_to_network_addr(addr_ref.ifa_netmask as *const libc::sockaddr); + let prefix = netmask + .and_then(|netmask| ip_mask_to_prefix(netmask).ok()) + .unwrap_or(0); + if let Some(ip) = ip { + ifaces + .entry(name) + .and_modify(|values| { + values.insert(IpNetwork::new(ip, prefix)); + }) + .or_insert(HashSet::from([IpNetwork::new(ip, prefix)])); + } + addr = addr_ref.ifa_next; + } + + // Safety: addrs has been previously allocated through getifaddrs + unsafe { + libc::freeifaddrs(addrs); + } + + ifaces +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> Option { + unsafe { + if sa.is_null() || (*sa).sa_family as libc::c_int == libc::AF_PACKET { + None + } else { + let addr = sockaddr_to_addr( + &*(sa as *const libc::sockaddr_storage), + mem::size_of::(), + ); + + match addr { + Ok(SocketAddr::V4(sa)) => Some(IpAddr::V4(*sa.ip())), + Ok(SocketAddr::V6(sa)) => Some(IpAddr::V6(*sa.ip())), + _ => None, + } + } + } +} +#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] +pub type InAddrType = libc::c_uint; +#[cfg(any(target_os = "illumos", target_os = "solaris"))] +pub type InAddrType = libc::c_ulonglong; + +fn sockaddr_to_addr(storage: &libc::sockaddr_storage, len: usize) -> io::Result { + match storage.ss_family as libc::c_int { + libc::AF_INET => { + assert!(len >= mem::size_of::()); + let storage: &libc::sockaddr_in = unsafe { mem::transmute(storage) }; + let ip = (storage.sin_addr.s_addr as InAddrType).to_be(); + let a = (ip >> 24) as u8; + let b = (ip >> 16) as u8; + let c = (ip >> 8) as u8; + let d = ip as u8; + let sockaddrv4 = SocketAddrV4::new(Ipv4Addr::new(a, b, c, d), storage.sin_port.to_be()); + Ok(SocketAddr::V4(sockaddrv4)) + } + libc::AF_INET6 => { + assert!(len >= mem::size_of::()); + let storage: &libc::sockaddr_in6 = unsafe { mem::transmute(storage) }; + let arr: [u16; 8] = unsafe { mem::transmute(storage.sin6_addr.s6_addr) }; + let ip = Ipv6Addr::new( + arr[0].to_be(), + arr[1].to_be(), + arr[2].to_be(), + arr[3].to_be(), + arr[4].to_be(), + arr[5].to_be(), + arr[6].to_be(), + arr[7].to_be(), + ); + Ok(SocketAddr::V6(SocketAddrV6::new( + ip, + storage.sin6_port.to_be(), + u32::from_be(storage.sin6_flowinfo), + storage.sin6_scope_id, + ))) + } + _ => Err(io::Error::new( + io::ErrorKind::InvalidData, + "expected IPv4 or IPv6 socket", + )), + } +} + +#[cfg(any( + target_os = "openbsd", + target_os = "freebsd", + target_os = "netbsd", + target_os = "illumos", + target_os = "solaris", + target_os = "macos", + target_os = "ios" +))] +fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> Option { + unsafe { + if sa.is_null() || (*sa).sa_family as libc::c_int == 18 { + None + } else { + let addr = + sockaddr_to_addr(mem::transmute(sa), mem::size_of::()); + + match addr { + Ok(SocketAddr::V4(sa)) => Some(IpAddr::V4(*sa.ip())), + Ok(SocketAddr::V6(sa)) => Some(IpAddr::V6(*sa.ip())), + _ => None, + } + } + } +} + +pub(crate) fn ip_mask_to_prefix(mask: IpAddr) -> Result { + match mask { + IpAddr::V4(mask) => ipv4_mask_to_prefix(mask), + IpAddr::V6(mask) => ipv6_mask_to_prefix(mask), + } +} + +pub(crate) fn ipv4_mask_to_prefix(mask: Ipv4Addr) -> Result { + let mask = u32::from(mask); + + let prefix = (!mask).leading_zeros() as u8; + if (u64::from(mask) << prefix) & 0xffff_ffff != 0 { + Err("invalid ipv4 prefix") + } else { + Ok(prefix) + } +} + +pub(crate) fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result { + let mask = mask.segments(); + let mut mask_iter = mask.iter(); + + // Count the number of set bits from the start of the address + let mut prefix = 0; + for &segment in &mut mask_iter { + if segment == 0xffff { + prefix += 16; + } else if segment == 0 { + // Prefix finishes on a segment boundary + break; + } else { + let prefix_bits = (!segment).leading_zeros() as u8; + // Check that the remainder of the bits are all unset + if segment << prefix_bits != 0 { + return Err("invalid ipv6 prefix"); + } + prefix += prefix_bits; + break; + } + } + + // Now check all the remaining bits are unset + for &segment in mask_iter { + if segment != 0 { + return Err("invalid ipv6 prefix"); + } + } + + Ok(prefix) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ipv4_mask() { + let mask = Ipv4Addr::new(255, 255, 255, 0); + let prefix = ipv4_mask_to_prefix(mask).unwrap(); + assert_eq!(prefix, 24); + } + + #[test] + fn ipv4_mask_another() { + let mask = Ipv4Addr::new(255, 255, 255, 128); + let prefix = ipv4_mask_to_prefix(mask).unwrap(); + assert_eq!(prefix, 25); + } + + #[test] + fn v4_mask_to_prefix_invalid() { + let mask = Ipv4Addr::new(255, 128, 255, 0); + assert!(ipv4_mask_to_prefix(mask).is_err()); + } + + #[test] + fn ipv6_mask() { + let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0); + let prefix = ipv6_mask_to_prefix(mask).unwrap(); + assert_eq!(prefix, 48); + } + + #[test] + fn ipv6_mask_invalid() { + let mask = Ipv6Addr::new(0, 0xffff, 0xffff, 0, 0, 0, 0, 0); + assert!(ipv6_mask_to_prefix(mask).is_err()); + } + + #[test] + fn ip_mask_enum_ipv4() { + let mask = IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)); + let prefix = ip_mask_to_prefix(mask).unwrap(); + assert_eq!(prefix, 24); + } + + #[test] + fn ip_mask_enum_ipv4_invalid() { + let mask = IpAddr::from(Ipv4Addr::new(255, 0, 255, 0)); + assert!(ip_mask_to_prefix(mask).is_err()); + } + + #[test] + fn ip_mask_enum_ipv6() { + let mask = IpAddr::from(Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0)); + let prefix = ip_mask_to_prefix(mask).unwrap(); + assert_eq!(prefix, 48); + } + + #[test] + fn ip_mask_enum_ipv6_invalid() { + let mask = IpAddr::from(Ipv6Addr::new(0xffff, 0xffff, 0xff00, 0xffff, 0, 0, 0, 0)); + assert!(ip_mask_to_prefix(mask).is_err()); + } } diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 4958644f2..895c71ea3 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -1,17 +1,19 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use ipnetwork::IpNetwork; -use std::collections::HashMap; -use std::ptr::null_mut; +use std::collections::{HashMap, HashSet}; +use std::net::IpAddr; +use std::ptr::{null_mut, NonNull}; use windows::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_SUCCESS}; use windows::Win32::NetworkManagement::IpHelper::{ GetAdaptersAddresses, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER, GAA_FLAG_SKIP_MULTICAST, - IP_ADAPTER_ADDRESSES_LH, + IP_ADAPTER_ADDRESSES_LH, IP_ADAPTER_UNICAST_ADDRESS_LH, +}; +use windows::Win32::Networking::WinSock::{ + AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR, SOCKADDR_IN, SOCKADDR_IN6, }; -use windows::Win32::Networking::WinSock::AF_UNSPEC; -use crate::common::MacAddr; +use crate::common::{IpNetwork, MacAddr}; /// this iterator yields an interface name and address pub(crate) struct InterfaceAddressIterator { @@ -66,6 +68,31 @@ impl Iterator for InterfaceAddressIterator { } } +impl InterfaceAddressIterator { + pub fn generate_ip_networks(&mut self) -> HashMap> { + let mut results = HashMap::new(); + while !self.adapter.is_null() { + unsafe { + let adapter = self.adapter; + // Move to the next adapter + self.adapter = (*adapter).Next; + if let Ok(interface_name) = (*adapter).FriendlyName.to_string() { + let ip_networks = get_ip_networks((*adapter).FirstUnicastAddress); + results.insert(interface_name, ip_networks); + } + } + } + results + } +} + +pub(crate) fn get_interface_ip_networks() -> HashMap> { + match get_interface_address() { + Ok(mut interface_iter) => interface_iter.generate_ip_networks(), + _ => HashMap::new(), + } +} + impl Drop for InterfaceAddressIterator { fn drop(&mut self) { unsafe { @@ -108,18 +135,35 @@ pub(crate) fn get_interface_address() -> Result HashMap> { - ipconfig::get_adapters() - .unwrap_or_default() - .into_iter() - .map(|a| { - ( - a.friendly_name().to_owned(), - a.prefixes() - .iter() - .filter_map(|(addr, prefix)| IpNetwork::new(*addr, *prefix as u8).ok()) - .collect(), - ) - }) - .collect() +fn get_ip_networks(mut prefixes_ptr: *mut IP_ADAPTER_UNICAST_ADDRESS_LH) -> HashSet { + let mut ip_networks = HashSet::new(); + while !prefixes_ptr.is_null() { + let prefix = unsafe { prefixes_ptr.read_unaligned() }; + if let Some(socket_address) = NonNull::new(prefix.Address.lpSockaddr) { + if let Some(ipaddr) = get_ip_address_from_socket_address(socket_address) { + ip_networks.insert(IpNetwork::new(ipaddr, prefix.OnLinkPrefixLength)); + } + } + prefixes_ptr = prefix.Next; + } + ip_networks +} + +/// Converts a Windows socket address to an ip address. +fn get_ip_address_from_socket_address(socket_address: NonNull) -> Option { + let socket_address_family = unsafe { socket_address.as_ref().sa_family }; + + if socket_address_family == AF_INET { + let socket_address = unsafe { socket_address.cast::().as_ref() }; + let address = unsafe { socket_address.sin_addr.S_un.S_addr }; + let ipv4_address = IpAddr::from(address.to_ne_bytes()); + Some(ipv4_address) + } else if socket_address_family == AF_INET6 { + let socket_address = unsafe { socket_address.cast::().as_ref() }; + let address = unsafe { socket_address.sin6_addr.u.Byte }; + let ipv6_address = IpAddr::from(address); + Some(ipv6_address) + } else { + None + } } From 42e6862a839f3879ed8286854da1930dadf2cc26 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Wed, 6 Mar 2024 18:10:38 +0800 Subject: [PATCH 05/12] style: change ip_address_from_socket_address if into match --- src/windows/network_helper.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 895c71ea3..cdbc0d85e 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -152,18 +152,19 @@ fn get_ip_networks(mut prefixes_ptr: *mut IP_ADAPTER_UNICAST_ADDRESS_LH) -> Hash /// Converts a Windows socket address to an ip address. fn get_ip_address_from_socket_address(socket_address: NonNull) -> Option { let socket_address_family = unsafe { socket_address.as_ref().sa_family }; - - if socket_address_family == AF_INET { - let socket_address = unsafe { socket_address.cast::().as_ref() }; - let address = unsafe { socket_address.sin_addr.S_un.S_addr }; - let ipv4_address = IpAddr::from(address.to_ne_bytes()); - Some(ipv4_address) - } else if socket_address_family == AF_INET6 { - let socket_address = unsafe { socket_address.cast::().as_ref() }; - let address = unsafe { socket_address.sin6_addr.u.Byte }; - let ipv6_address = IpAddr::from(address); - Some(ipv6_address) - } else { - None + match socket_address_family { + AF_INET => { + let socket_address = unsafe { socket_address.cast::().as_ref() }; + let address = unsafe { socket_address.sin_addr.S_un.S_addr }; + let ipv4_address = IpAddr::from(address.to_ne_bytes()); + Some(ipv4_address) + }, + AF_INET6 => { + let socket_address = unsafe { socket_address.cast::().as_ref() }; + let address = unsafe { socket_address.sin6_addr.u.Byte }; + let ipv6_address = IpAddr::from(address); + Some(ipv6_address) + }, + _ => None } } From 270a62181a2fd3590419e8f6cd82bd14a145be30 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Wed, 6 Mar 2024 18:18:51 +0800 Subject: [PATCH 06/12] chore: fix cargo fmt --- .gitignore | 3 ++- src/lib.rs | 18 +++++++++++++----- src/unix/network_helper.rs | 6 ++++-- src/windows/network_helper.rs | 6 +++--- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 3ebb7e4d0..3ed644a25 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,5 @@ rusty-tags.vi tags **.o -simple \ No newline at end of file +simple +.idea/ diff --git a/src/lib.rs b/src/lib.rs index 1cc0cbf26..238ff9565 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -177,8 +177,8 @@ mod doctest { #[cfg(test)] mod test { - use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::*; + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; #[cfg(feature = "unknown-ci")] #[test] @@ -547,7 +547,8 @@ mod test { // Ensure that the `Display` and `Debug` traits are implemented on the `IpNetwork` struct #[test] fn check_display_impl_ip_network_ipv4() { - println!("{} {:?}", + println!( + "{} {:?}", IpNetwork::new(IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)), 3), IpNetwork::new(IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)), 21) ); @@ -555,9 +556,16 @@ mod test { #[test] fn check_display_impl_ip_network_ipv6() { - println!("{} {:?}", - IpNetwork::new(IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)), 127), - IpNetwork::new(IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)), 120) + println!( + "{} {:?}", + IpNetwork::new( + IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)), + 127 + ), + IpNetwork::new( + IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)), + 120 + ) ) } diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index 1365ca3a3..a954e9099 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -256,8 +256,10 @@ fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> Option { if sa.is_null() || (*sa).sa_family as libc::c_int == 18 { None } else { - let addr = - sockaddr_to_addr(mem::transmute(sa), mem::size_of::()); + let addr = sockaddr_to_addr( + &*(sa as *const libc::sockaddr_storage), + mem::size_of::(), + ); match addr { Ok(SocketAddr::V4(sa)) => Some(IpAddr::V4(*sa.ip())), diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index cdbc0d85e..203d21771 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -158,13 +158,13 @@ fn get_ip_address_from_socket_address(socket_address: NonNull) -> Opti let address = unsafe { socket_address.sin_addr.S_un.S_addr }; let ipv4_address = IpAddr::from(address.to_ne_bytes()); Some(ipv4_address) - }, + } AF_INET6 => { let socket_address = unsafe { socket_address.cast::().as_ref() }; let address = unsafe { socket_address.sin6_addr.u.Byte }; let ipv6_address = IpAddr::from(address); Some(ipv6_address) - }, - _ => None + } + _ => None, } } From 4581843781cf8e15d503b958dad07d408a624740 Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Thu, 7 Mar 2024 10:51:16 +0800 Subject: [PATCH 07/12] test: add missing tests for ip networks --- src/lib.rs | 12 ++++++++++++ src/unix/network_helper.rs | 20 +++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 238ff9565..6a350b4a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -569,6 +569,18 @@ mod test { ) } + #[test] + fn check_ip_networks() { + if !IS_SUPPORTED_SYSTEM { + return; + } + let networks = Networks::new_with_refreshed_list(); + if networks.is_empty() || networks.iter().any(|(_, n)| !n.ip_networks().is_empty()) { + return; + } + panic!("Networks should have at least one IP network "); + } + // This test exists to ensure that the `TryFrom` and `FromStr` traits are implemented // on `Uid`, `Gid` and `Pid`. #[allow(clippy::unnecessary_fallible_conversions)] diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index a954e9099..8047f4a5f 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -128,31 +128,36 @@ pub(crate) fn get_interface_address() -> Result HashMap> { + unsafe { inner_interface_ip_networks() } +} + +unsafe fn inner_interface_ip_networks() -> HashMap> { let mut ifaces: HashMap> = HashMap::new(); let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); // Safety: addrs.as_mut_ptr() is valid, it points to addrs. - if unsafe { libc::getifaddrs(addrs.as_mut_ptr()) } != 0 { + if libc::getifaddrs(addrs.as_mut_ptr()) != 0 { + sysinfo_debug!("Failed to operate libc::getifaddrs as ifaddrs Uninitialized"); return ifaces; } // Safety: If there was an error, we would have already returned. // Therefore, getifaddrs has initialized `addrs`. - let addrs = unsafe { addrs.assume_init() }; + let addrs = addrs.assume_init(); let mut addr = addrs; while !addr.is_null() { // Safety: We assume that addr is valid for the lifetime of this loop // body, and is not mutated. - let addr_ref: &libc::ifaddrs = unsafe { &*addr }; + let addr_ref: &libc::ifaddrs = &*addr; let c_str = addr_ref.ifa_name as *const c_char; // Safety: ifa_name is a null terminated interface name - let bytes = unsafe { CStr::from_ptr(c_str).to_bytes() }; + let bytes = CStr::from_ptr(c_str).to_bytes(); // Safety: Interfaces on unix must be valid UTF-8 - let name = unsafe { from_utf8_unchecked(bytes).to_owned() }; + let name = from_utf8_unchecked(bytes).to_owned(); let ip = sockaddr_to_network_addr(addr_ref.ifa_addr as *const libc::sockaddr); let netmask = sockaddr_to_network_addr(addr_ref.ifa_netmask as *const libc::sockaddr); let prefix = netmask @@ -170,10 +175,7 @@ pub(crate) fn get_interface_ip_networks() -> HashMap> } // Safety: addrs has been previously allocated through getifaddrs - unsafe { - libc::freeifaddrs(addrs); - } - + libc::freeifaddrs(addrs); ifaces } From caeb4ec5117d5017ae153157c473a54cb4e525c4 Mon Sep 17 00:00:00 2001 From: gongzhengyang <2976560783@qq.com> Date: Fri, 8 Mar 2024 20:48:37 +0800 Subject: [PATCH 08/12] change IpNetwork fields pub, rm check ip_networks empty skip --- src/common.rs | 23 ++++------------------- src/lib.rs | 28 +++++++++++++++++----------- src/serde.rs | 4 ++-- src/unix/network_helper.rs | 4 ++-- src/windows/network_helper.rs | 5 ++++- 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/src/common.rs b/src/common.rs index 594027815..4709002a9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -3656,25 +3656,10 @@ impl fmt::Display for MacAddr { /// It is returned by [`NetworkData::ip_networks`][crate::NetworkData::ip_networks]. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct IpNetwork { - addr: IpAddr, - prefix: u8, -} - -impl IpNetwork { - /// build new IpNetwork - pub fn new(addr: IpAddr, prefix: u8) -> Self { - Self { addr, prefix } - } - - /// return the addr of the IpNetwork - pub fn addr(&self) -> IpAddr { - self.addr - } - - /// return the prefix of the IpNetwork - pub fn prefix(&self) -> u8 { - self.prefix - } + /// The ip of the network interface + pub addr: IpAddr, + /// The netmask, prefix of the ipaddress + pub prefix: u8, } impl fmt::Display for IpNetwork { diff --git a/src/lib.rs b/src/lib.rs index 6a350b4a0..cb17ed494 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -549,8 +549,14 @@ mod test { fn check_display_impl_ip_network_ipv4() { println!( "{} {:?}", - IpNetwork::new(IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)), 3), - IpNetwork::new(IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)), 21) + IpNetwork { + addr: IpAddr::from(Ipv4Addr::new(1, 2, 3, 4)), + prefix: 3 + }, + IpNetwork { + addr: IpAddr::from(Ipv4Addr::new(255, 255, 255, 0)), + prefix: 21 + } ); } @@ -558,14 +564,14 @@ mod test { fn check_display_impl_ip_network_ipv6() { println!( "{} {:?}", - IpNetwork::new( - IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)), - 127 - ), - IpNetwork::new( - IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)), - 120 - ) + IpNetwork { + addr: IpAddr::from(Ipv6Addr::new(0xffff, 0xaabb, 00, 0, 0, 0x000c, 11, 21)), + prefix: 127 + }, + IpNetwork { + addr: IpAddr::from(Ipv6Addr::new(0xffcc, 0, 0, 0xffcc, 0, 0xffff, 0, 0xccaa)), + prefix: 120 + } ) } @@ -575,7 +581,7 @@ mod test { return; } let networks = Networks::new_with_refreshed_list(); - if networks.is_empty() || networks.iter().any(|(_, n)| !n.ip_networks().is_empty()) { + if networks.iter().any(|(_, n)| !n.ip_networks().is_empty()) { return; } panic!("Networks should have at least one IP network "); diff --git a/src/serde.rs b/src/serde.rs index 888081300..81e7d5fb3 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -422,8 +422,8 @@ impl Serialize for crate::IpNetwork { { let mut state = serializer.serialize_struct("IpNetwork", 2)?; - state.serialize_field("addr", &self.addr())?; - state.serialize_field("prefix", &self.prefix())?; + state.serialize_field("addr", &self.addr)?; + state.serialize_field("prefix", &self.prefix)?; state.end() } diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index 8047f4a5f..86ff60809 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -167,9 +167,9 @@ unsafe fn inner_interface_ip_networks() -> HashMap> { ifaces .entry(name) .and_modify(|values| { - values.insert(IpNetwork::new(ip, prefix)); + values.insert(IpNetwork { addr: ip, prefix }); }) - .or_insert(HashSet::from([IpNetwork::new(ip, prefix)])); + .or_insert(HashSet::from([IpNetwork { addr: ip, prefix }])); } addr = addr_ref.ifa_next; } diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 203d21771..6a399d195 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -141,7 +141,10 @@ fn get_ip_networks(mut prefixes_ptr: *mut IP_ADAPTER_UNICAST_ADDRESS_LH) -> Hash let prefix = unsafe { prefixes_ptr.read_unaligned() }; if let Some(socket_address) = NonNull::new(prefix.Address.lpSockaddr) { if let Some(ipaddr) = get_ip_address_from_socket_address(socket_address) { - ip_networks.insert(IpNetwork::new(ipaddr, prefix.OnLinkPrefixLength)); + ip_networks.insert(IpNetwork { + addr: ipaddr, + prefix: prefix.OnLinkPrefixLength, + }); } } prefixes_ptr = prefix.Next; From edd48347e6766e2a47eb67a971d367ec5f1d3943 Mon Sep 17 00:00:00 2001 From: gongzhengyang <2976560783@qq.com> Date: Fri, 8 Mar 2024 21:21:19 +0800 Subject: [PATCH 09/12] fix: fix clippy warnings about to_owned() --- src/unix/apple/macos/process.rs | 8 ++++---- src/unix/linux/cpu.rs | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs index 1ea19186b..9a8584d10 100644 --- a/src/unix/apple/macos/process.rs +++ b/src/unix/apple/macos/process.rs @@ -403,11 +403,11 @@ unsafe fn get_exe_and_name_backup( let tmp = String::from_utf8_unchecked(buffer); let exe = PathBuf::from(tmp); if process.name.is_empty() { - process.name = exe + exe .file_name() .and_then(|x| x.to_str()) .unwrap_or("") - .to_owned(); + .clone_into(&mut process.name); } if exe_needs_update { process.exe = Some(exe); @@ -540,11 +540,11 @@ unsafe fn get_process_infos(process: &mut ProcessInner, refresh_kind: ProcessRef let (exe, proc_args) = get_exe(proc_args); if process.name.is_empty() { - process.name = exe + exe .file_name() .and_then(|x| x.to_str()) .unwrap_or("") - .to_owned(); + .to_owned().clone_into(&mut process.name); } if refresh_kind.exe().needs_update(|| process.exe.is_none()) { diff --git a/src/unix/linux/cpu.rs b/src/unix/linux/cpu.rs index 618b49273..36d60112b 100644 --- a/src/unix/linux/cpu.rs +++ b/src/unix/linux/cpu.rs @@ -104,8 +104,7 @@ impl CpusWrapper { } let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); if first { - self.global_cpu.inner.name = - to_str!(parts.next().unwrap_or(&[])).to_owned(); + to_str!(parts.next().unwrap_or(&[])).clone_into(&mut self.global_cpu.inner.name); } else { parts.next(); } From ff9a2c8286e8ab0e6723c7f9ed5ab7b8773232e6 Mon Sep 17 00:00:00 2001 From: gongzhengyang <2976560783@qq.com> Date: Fri, 8 Mar 2024 21:39:38 +0800 Subject: [PATCH 10/12] change get_interface_ip_networks function unsafe --- src/network.rs | 3 +- src/unix/apple/macos/process.rs | 9 +++-- src/unix/linux/cpu.rs | 3 +- src/unix/network_helper.rs | 6 +--- src/windows/network_helper.rs | 58 ++++++++++++++++----------------- 5 files changed, 37 insertions(+), 42 deletions(-) diff --git a/src/network.rs b/src/network.rs index 4f0a72eb1..88d9d74a8 100644 --- a/src/network.rs +++ b/src/network.rs @@ -7,7 +7,8 @@ use crate::NetworkData; /// Interface addresses are OS-independent pub(crate) fn refresh_networks_addresses(interfaces: &mut HashMap) { - for (interface_name, ip_networks) in get_interface_ip_networks() { + let interface_networks = unsafe { get_interface_ip_networks() }; + for (interface_name, ip_networks) in interface_networks { if let Some(interface) = interfaces.get_mut(&interface_name) { interface.inner.ip_networks = ip_networks.into_iter().collect::>(); } diff --git a/src/unix/apple/macos/process.rs b/src/unix/apple/macos/process.rs index 9a8584d10..d246d5d7b 100644 --- a/src/unix/apple/macos/process.rs +++ b/src/unix/apple/macos/process.rs @@ -403,8 +403,7 @@ unsafe fn get_exe_and_name_backup( let tmp = String::from_utf8_unchecked(buffer); let exe = PathBuf::from(tmp); if process.name.is_empty() { - exe - .file_name() + exe.file_name() .and_then(|x| x.to_str()) .unwrap_or("") .clone_into(&mut process.name); @@ -540,11 +539,11 @@ unsafe fn get_process_infos(process: &mut ProcessInner, refresh_kind: ProcessRef let (exe, proc_args) = get_exe(proc_args); if process.name.is_empty() { - exe - .file_name() + exe.file_name() .and_then(|x| x.to_str()) .unwrap_or("") - .to_owned().clone_into(&mut process.name); + .to_owned() + .clone_into(&mut process.name); } if refresh_kind.exe().needs_update(|| process.exe.is_none()) { diff --git a/src/unix/linux/cpu.rs b/src/unix/linux/cpu.rs index 36d60112b..af6210abe 100644 --- a/src/unix/linux/cpu.rs +++ b/src/unix/linux/cpu.rs @@ -104,7 +104,8 @@ impl CpusWrapper { } let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); if first { - to_str!(parts.next().unwrap_or(&[])).clone_into(&mut self.global_cpu.inner.name); + to_str!(parts.next().unwrap_or(&[])) + .clone_into(&mut self.global_cpu.inner.name); } else { parts.next(); } diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index 86ff60809..1cd560711 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -127,11 +127,7 @@ pub(crate) fn get_interface_address() -> Result HashMap> { - unsafe { inner_interface_ip_networks() } -} - -unsafe fn inner_interface_ip_networks() -> HashMap> { +pub(crate) unsafe fn get_interface_ip_networks() -> HashMap> { let mut ifaces: HashMap> = HashMap::new(); let mut addrs: MaybeUninit<*mut libc::ifaddrs> = MaybeUninit::uninit(); diff --git a/src/windows/network_helper.rs b/src/windows/network_helper.rs index 6a399d195..a7457eb09 100644 --- a/src/windows/network_helper.rs +++ b/src/windows/network_helper.rs @@ -86,7 +86,7 @@ impl InterfaceAddressIterator { } } -pub(crate) fn get_interface_ip_networks() -> HashMap> { +pub(crate) unsafe fn get_interface_ip_networks() -> HashMap> { match get_interface_address() { Ok(mut interface_iter) => interface_iter.generate_ip_networks(), _ => HashMap::new(), @@ -101,38 +101,36 @@ impl Drop for InterfaceAddressIterator { } } -pub(crate) fn get_interface_address() -> Result { - unsafe { - // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses#remarks - // A 15k buffer is recommended - let mut size: u32 = 15 * 1024; - let mut ret = ERROR_SUCCESS.0; - let mut iterator = InterfaceAddressIterator::new(); +pub(crate) unsafe fn get_interface_address() -> Result { + // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses#remarks + // A 15k buffer is recommended + let mut size: u32 = 15 * 1024; + let mut ret = ERROR_SUCCESS.0; + let mut iterator = InterfaceAddressIterator::new(); - // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses#examples - // Try to retrieve adapter information up to 3 times - for _ in 0..3 { - iterator = iterator.realloc(size as _)?; - ret = GetAdaptersAddresses( - AF_UNSPEC.0.into(), - GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, - None, - Some(iterator.buf), - &mut size, - ); - if ret == ERROR_SUCCESS.0 { - return Ok(iterator); - } else if ret != ERROR_BUFFER_OVERFLOW.0 { - break; - } - // if the given memory size is too small to hold the adapter information, - // the SizePointer returned will point to the required size of the buffer, - // and we should continue. - // Otherwise, break the loop and check the return code again + // https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses#examples + // Try to retrieve adapter information up to 3 times + for _ in 0..3 { + iterator = iterator.realloc(size as _)?; + ret = GetAdaptersAddresses( + AF_UNSPEC.0.into(), + GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, + None, + Some(iterator.buf), + &mut size, + ); + if ret == ERROR_SUCCESS.0 { + return Ok(iterator); + } else if ret != ERROR_BUFFER_OVERFLOW.0 { + break; } - - Err(format!("GetAdaptersAddresses() failed with code {ret}")) + // if the given memory size is too small to hold the adapter information, + // the SizePointer returned will point to the required size of the buffer, + // and we should continue. + // Otherwise, break the loop and check the return code again } + + Err(format!("GetAdaptersAddresses() failed with code {ret}")) } fn get_ip_networks(mut prefixes_ptr: *mut IP_ADAPTER_UNICAST_ADDRESS_LH) -> HashSet { From 06242f025f88f00b15eec6d85cc7222de8ef29c3 Mon Sep 17 00:00:00 2001 From: gongzhengyang <2976560783@qq.com> Date: Fri, 8 Mar 2024 21:49:51 +0800 Subject: [PATCH 11/12] fix: fix unsafe call get_interface_address on windows --- src/network.rs | 2 +- src/unix/network_helper.rs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/network.rs b/src/network.rs index 88d9d74a8..95695a5c8 100644 --- a/src/network.rs +++ b/src/network.rs @@ -13,7 +13,7 @@ pub(crate) fn refresh_networks_addresses(interfaces: &mut HashMap>(); } } - match get_interface_address() { + match unsafe { get_interface_address() } { Ok(ifa_iterator) => { for (name, ifa) in ifa_iterator { if let Some(interface) = interfaces.get_mut(&name) { diff --git a/src/unix/network_helper.rs b/src/unix/network_helper.rs index 1cd560711..0e4c3d36b 100644 --- a/src/unix/network_helper.rs +++ b/src/unix/network_helper.rs @@ -116,14 +116,12 @@ unsafe fn parse_interface_address(ifap: *const libc::ifaddrs) -> Option } /// Return an iterator on (interface_name, address) pairs -pub(crate) fn get_interface_address() -> Result { +pub(crate) unsafe fn get_interface_address() -> Result { let mut ifap = null_mut(); - unsafe { - if retry_eintr!(libc::getifaddrs(&mut ifap)) == 0 && !ifap.is_null() { - Ok(InterfaceAddressIterator { ifap, buf: ifap }) - } else { - Err("failed to call getifaddrs()".to_string()) - } + if retry_eintr!(libc::getifaddrs(&mut ifap)) == 0 && !ifap.is_null() { + Ok(InterfaceAddressIterator { ifap, buf: ifap }) + } else { + Err("failed to call getifaddrs()".to_string()) } } From c4cb4a5417ef5143c56e2d5df10e3e226d8cfc6b Mon Sep 17 00:00:00 2001 From: gongzhengyang <2976560783@qq.com> Date: Fri, 8 Mar 2024 22:17:04 +0800 Subject: [PATCH 12/12] fix: fix freebsd clippy lint --- src/unix/freebsd/system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/freebsd/system.rs b/src/unix/freebsd/system.rs index 8b8d66e9a..39ce92bc8 100644 --- a/src/unix/freebsd/system.rs +++ b/src/unix/freebsd/system.rs @@ -381,7 +381,7 @@ unsafe fn add_missing_proc_info( // First, we try to retrieve the name from the command line. let p = Path::new(&cmd[0]); if let Some(name) = p.file_name().and_then(|s| s.to_str()) { - proc_inner.name = name.to_owned(); + name.clone_into(&mut proc_inner.name); } if cmd_needs_update {