if-addrs-0.10.1/.cargo_vcs_info.json0000644000000001360000000000100126040ustar { "git": { "sha1": "947c6342681b047b48b5f53eb75049881d2dfa20" }, "path_in_vcs": "" }if-addrs-0.10.1/.github/workflows/CI.yml000064400000000000000000000033241046102023000160110ustar 00000000000000on: [push, pull_request] name: CI jobs: check: name: Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - uses: actions-rs/cargo@v1 with: command: check test: name: Test Suite runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] rust: ["1.46.0", stable] steps: - uses: actions/checkout@v2 - uses: maxim-lobanov/setup-xcode@v1 if: ${{ matrix.os == 'macos-latest' && matrix.rust == '1.46.0' }} with: xcode-version: 13 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: ${{ matrix.rust }} override: true - name: Build uses: actions-rs/cargo@v1 with: command: build - name: Test uses: actions-rs/cargo@v1 with: command: test args: -- --show-output fmt: name: Rustfmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: stable override: true - run: rustup component add rustfmt - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy_check: name: Clippy Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - run: rustup component add clippy - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} args: --all-features if-addrs-0.10.1/.github/workflows/Cross.yml000064400000000000000000000022711046102023000166070ustar 00000000000000# We could use `@actions-rs/cargo` Action ability to automatically install `cross` tool # in order to compile our application for some unusual targets. on: [push, pull_request] name: Cross-compile jobs: build: name: Build runs-on: ubuntu-latest strategy: matrix: target: - aarch64-linux-android steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable target: ${{ matrix.target }} override: true - uses: actions-rs/cargo@v1 with: use-cross: true command: build args: --target=${{ matrix.target }} ios: name: iOS Build runs-on: macos-latest strategy: matrix: target: - aarch64-apple-ios - x86_64-apple-ios steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: stable target: ${{ matrix.target }} override: true - uses: actions-rs/cargo@v1 with: use-cross: true command: build args: --target=${{ matrix.target }} if-addrs-0.10.1/.gitignore000064400000000000000000000002711046102023000133640ustar 00000000000000*.exe *.lock *.rsproj tags* build/ build-tests/ target/ /.idea tests/tmp* src/tmp* /.project *.bootstrap.cache /bin/ # Generated by Editors *~ *.bk *.sublime-* *.swp # Misc .DS_Store if-addrs-0.10.1/CHANGELOG.md000064400000000000000000000022521046102023000132060ustar 00000000000000# if-addrs - Change Log ## [0.7.0] - Fix support for Android 11 - Drop support for Android `<` 7 ## [0.6.7] - Add support for haiku ## [0.6.6] - Add support for illumos ## [0.6.5] - Drop `unwrap` dev dependency ## [0.6.4] - Support Rust 1.40.0 ## [0.6.3] - Fix Android build with Rust 2018 edition ## [0.6.2] - Fix Android build and add CI check ## [0.6.1] - Fixed Windows build issue after `winapi 0.3` upgrade ## [0.6.0] - forked from get_if_addrs - Rename to if-addrs - Replace `gcc` crate with `cc` crate - Upgrade `winapi` crate to 0.3 ## [0.5.3] - Update dependency version of get_if_addrs-sys to 0.1.1 - Update dependency version of c_linked_list to 1.1.1 ## [0.5.2] - Fix incorrect parsing of IPv6 addresses ## [0.5.1] - Fixed nullptr deref in unsafe code - Use Rust 1.24.0 stable / 2018-02-05 nightly - Use Clippy 0.0.186 ## [0.5.0] - Use rust 1.22.1 stable / 2017-12-02 nightly - rustfmt 0.9.0 and clippy-0.0.175 ## [0.4.1] - Fix build for android ## [0.4.0] - Replaced ip::IpAddr with std::IpAddr - Changed to support BSD - Updated lints - Documentation fixes ## [0.3.1] - Fix build on ARM ## [0.3.0] - Added a method on the interface object to get the ip addresses if-addrs-0.10.1/Cargo.lock0000644000000046110000000000100105610ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "if-addrs" version = "0.10.1" dependencies = [ "libc", "windows-sys", ] [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" 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", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" if-addrs-0.10.1/Cargo.toml0000644000000022330000000000100106020ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "if-addrs" version = "0.10.1" authors = [ "MaidSafe Developers ", "Messense Lv ", ] description = "Return interface IP addresses on Posix and windows systems" readme = "README.md" license = "MIT OR BSD-3-Clause" repository = "https://github.com/messense/if-addrs" [features] link-local = [] [target."cfg(not(target_os = \"windows\"))".dependencies.libc] version = "0.2" [target."cfg(target_os = \"windows\")".dependencies.windows-sys] version = "0.45.0" features = [ "Win32_Foundation", "Win32_System_Memory", "Win32_Networking_WinSock", "Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", ] if-addrs-0.10.1/Cargo.toml.orig000064400000000000000000000012601046102023000142620ustar 00000000000000[package] authors = ["MaidSafe Developers ", "Messense Lv "] description = "Return interface IP addresses on Posix and windows systems" license = "MIT OR BSD-3-Clause" name = "if-addrs" readme = "README.md" repository = "https://github.com/messense/if-addrs" version = "0.10.1" edition = "2018" [target.'cfg(not(target_os = "windows"))'.dependencies] libc = "0.2" [target.'cfg(target_os = "windows")'.dependencies.windows-sys] version = "0.45.0" features = [ "Win32_Foundation", "Win32_System_Memory", "Win32_Networking_WinSock", "Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", ] [features] link-local = []if-addrs-0.10.1/LICENSE-BSD000064400000000000000000000027221046102023000130120ustar 00000000000000Copyright 2018 MaidSafe.net limited. Copyright 2020 messense Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. if-addrs-0.10.1/LICENSE-MIT000064400000000000000000000020751046102023000130340ustar 00000000000000Copyright 2018 MaidSafe.net limited. Copyright 2020 messense Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. if-addrs-0.10.1/README.md000064400000000000000000000013621046102023000126550ustar 00000000000000# if-addrs https://crates.io/crates/if-addrs ## Overview Retrieve network interface info for all interfaces on the system. ```rust // List all of the machine's network interfaces for iface in if_addrs::get_if_addrs().unwrap() { println!("{:#?}", iface); } ``` ## Todo Items * Create an API for responding to changes in network interfaces. ## License This SAFE Network library is dual-licensed under the Modified BSD ([LICENSE-BSD](LICENSE-BSD) https://opensource.org/licenses/BSD-3-Clause) or the MIT license ([LICENSE-MIT](LICENSE-MIT) http://opensource.org/licenses/MIT) at your option. ## Contribution Copyrights in the SAFE Network are retained by their contributors. No copyright assignment is required to contribute to this project. if-addrs-0.10.1/examples/list_interfaces.rs000064400000000000000000000012601046102023000167350ustar 00000000000000// Copyright 2018 MaidSafe.net limited. // // This SAFE Network Software is licensed to you under the MIT license or the Modified BSD license , at your option. This file may not be copied, // modified, or distributed except according to those terms. Please review the Licences for the // specific language governing permissions and limitations relating to use of the SAFE Network // Software. //! List interface example. use if_addrs; fn main() { let ifaces = if_addrs::get_if_addrs().unwrap(); println!("Got list of interfaces"); println!("{:#?}", ifaces); } if-addrs-0.10.1/src/lib.rs000064400000000000000000000435061046102023000133070ustar 00000000000000// Copyright 2018 MaidSafe.net limited. // // This SAFE Network Software is licensed to you under the MIT license or the Modified BSD license , at your option. This file may not be copied, // modified, or distributed except according to those terms. Please review the Licences for the // specific language governing permissions and limitations relating to use of the SAFE Network // Software. #[cfg(not(windows))] mod posix; mod sockaddr; #[cfg(windows)] mod windows; use std::io; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// Details about an interface on this host. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct Interface { /// The name of the interface. pub name: String, /// The address details of the interface. pub addr: IfAddr, /// The index of the interface. pub index: Option, } impl Interface { /// Check whether this is a loopback interface. pub fn is_loopback(&self) -> bool { self.addr.is_loopback() } /// Check whether this is a link local interface. pub fn is_link_local(&self) -> bool { self.addr.is_link_local() } /// Get the IP address of this interface. pub fn ip(&self) -> IpAddr { self.addr.ip() } } /// Details about the address of an interface on this host. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub enum IfAddr { /// This is an Ipv4 interface. V4(Ifv4Addr), /// This is an Ipv6 interface. V6(Ifv6Addr), } impl IfAddr { /// Check whether this is a loopback address. pub fn is_loopback(&self) -> bool { match *self { IfAddr::V4(ref ifv4_addr) => ifv4_addr.is_loopback(), IfAddr::V6(ref ifv6_addr) => ifv6_addr.is_loopback(), } } /// Check whether this is a link local interface. pub fn is_link_local(&self) -> bool { match *self { IfAddr::V4(ref ifv4_addr) => ifv4_addr.is_link_local(), IfAddr::V6(ref ifv6_addr) => ifv6_addr.is_link_local(), } } /// Get the IP address of this interface address. pub fn ip(&self) -> IpAddr { match *self { IfAddr::V4(ref ifv4_addr) => IpAddr::V4(ifv4_addr.ip), IfAddr::V6(ref ifv6_addr) => IpAddr::V6(ifv6_addr.ip), } } } /// Details about the ipv4 address of an interface on this host. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct Ifv4Addr { /// The IP address of the interface. pub ip: Ipv4Addr, /// The netmask of the interface. pub netmask: Ipv4Addr, /// The broadcast address of the interface. pub broadcast: Option, } impl Ifv4Addr { /// Check whether this is a loopback address. pub fn is_loopback(&self) -> bool { self.ip.octets()[0] == 127 } /// Check whether this is a link local address. pub fn is_link_local(&self) -> bool { self.ip.is_link_local() } } /// Details about the ipv6 address of an interface on this host. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct Ifv6Addr { /// The IP address of the interface. pub ip: Ipv6Addr, /// The netmask of the interface. pub netmask: Ipv6Addr, /// The broadcast address of the interface. pub broadcast: Option, } impl Ifv6Addr { /// Check whether this is a loopback address. pub fn is_loopback(&self) -> bool { self.ip.segments() == [0, 0, 0, 0, 0, 0, 0, 1] } /// Check whether this is a link local address. pub fn is_link_local(&self) -> bool { let bytes = self.ip.octets(); bytes[0] == 0xfe && bytes[1] == 0x80 } } #[cfg(not(windows))] mod getifaddrs_posix { use libc::if_nametoindex; use super::{IfAddr, Ifv4Addr, Ifv6Addr, Interface}; use crate::posix::{self as ifaddrs, IfAddrs}; use crate::sockaddr; use std::ffi::CStr; use std::io; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// Return a vector of IP details for all the valid interfaces on this host. #[allow(unsafe_code)] pub fn get_if_addrs() -> io::Result> { let mut ret = Vec::::new(); let ifaddrs = IfAddrs::new()?; for ifaddr in ifaddrs.iter() { let addr = match sockaddr::to_ipaddr(ifaddr.ifa_addr) { None => continue, Some(IpAddr::V4(ipv4_addr)) => { let netmask = match sockaddr::to_ipaddr(ifaddr.ifa_netmask) { Some(IpAddr::V4(netmask)) => netmask, _ => Ipv4Addr::new(0, 0, 0, 0), }; let broadcast = if (ifaddr.ifa_flags & 2) != 0 { match ifaddrs::do_broadcast(&ifaddr) { Some(IpAddr::V4(broadcast)) => Some(broadcast), _ => None, } } else { None }; IfAddr::V4(Ifv4Addr { ip: ipv4_addr, netmask, broadcast, }) } Some(IpAddr::V6(ipv6_addr)) => { let netmask = match sockaddr::to_ipaddr(ifaddr.ifa_netmask) { Some(IpAddr::V6(netmask)) => netmask, _ => Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), }; let broadcast = if (ifaddr.ifa_flags & 2) != 0 { match ifaddrs::do_broadcast(&ifaddr) { Some(IpAddr::V6(broadcast)) => Some(broadcast), _ => None, } } else { None }; IfAddr::V6(Ifv6Addr { ip: ipv6_addr, netmask, broadcast, }) } }; let name = unsafe { CStr::from_ptr(ifaddr.ifa_name) } .to_string_lossy() .into_owned(); let index = { let index = unsafe { if_nametoindex(ifaddr.ifa_name) }; // From `man if_nametoindex 3`: // The if_nametoindex() function maps the interface name specified in ifname to its // corresponding index. If the specified interface does not exist, it returns 0. if index == 0 { None } else { Some(index) } }; ret.push(Interface { name, addr, index }); } Ok(ret) } } /// Get a list of all the network interfaces on this machine along with their IP info. #[cfg(not(windows))] pub fn get_if_addrs() -> io::Result> { getifaddrs_posix::get_if_addrs() } #[cfg(windows)] mod getifaddrs_windows { use super::{IfAddr, Ifv4Addr, Ifv6Addr, Interface}; use crate::sockaddr; use crate::windows::IfAddrs; use std::io; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use windows_sys::Win32::Networking::WinSock::IpDadStatePreferred; /// Return a vector of IP details for all the valid interfaces on this host. pub fn get_if_addrs() -> io::Result> { let mut ret = Vec::::new(); let ifaddrs = IfAddrs::new()?; for ifaddr in ifaddrs.iter() { for addr in ifaddr.unicast_addresses() { if addr.DadState != IpDadStatePreferred { continue; } let addr = match sockaddr::to_ipaddr(addr.Address.lpSockaddr) { None => continue, Some(IpAddr::V4(ipv4_addr)) => { let mut item_netmask = Ipv4Addr::new(0, 0, 0, 0); let mut item_broadcast = None; // Search prefixes for a prefix matching addr 'prefixloopv4: for prefix in ifaddr.prefixes() { let ipprefix = sockaddr::to_ipaddr(prefix.Address.lpSockaddr); match ipprefix { Some(IpAddr::V4(ref a)) => { let mut netmask: [u8; 4] = [0; 4]; for (n, netmask_elt) in netmask .iter_mut() .enumerate() .take((prefix.PrefixLength as usize + 7) / 8) { let x_byte = ipv4_addr.octets()[n]; let y_byte = a.octets()[n]; for m in 0..8 { if (n * 8) + m > prefix.PrefixLength as usize { break; } let bit = 1 << (7 - m); if (x_byte & bit) == (y_byte & bit) { *netmask_elt |= bit; } else { continue 'prefixloopv4; } } } item_netmask = Ipv4Addr::new( netmask[0], netmask[1], netmask[2], netmask[3], ); let mut broadcast: [u8; 4] = ipv4_addr.octets(); for n in 0..4 { broadcast[n] |= !netmask[n]; } item_broadcast = Some(Ipv4Addr::new( broadcast[0], broadcast[1], broadcast[2], broadcast[3], )); break 'prefixloopv4; } _ => continue, }; } IfAddr::V4(Ifv4Addr { ip: ipv4_addr, netmask: item_netmask, broadcast: item_broadcast, }) } Some(IpAddr::V6(ipv6_addr)) => { let mut item_netmask = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); // Search prefixes for a prefix matching addr 'prefixloopv6: for prefix in ifaddr.prefixes() { let ipprefix = sockaddr::to_ipaddr(prefix.Address.lpSockaddr); match ipprefix { Some(IpAddr::V6(ref a)) => { // Iterate the bits in the prefix, if they all match this prefix // is the right one, else try the next prefix let mut netmask: [u16; 8] = [0; 8]; for (n, netmask_elt) in netmask .iter_mut() .enumerate() .take((prefix.PrefixLength as usize + 15) / 16) { let x_word = ipv6_addr.segments()[n]; let y_word = a.segments()[n]; for m in 0..16 { if (n * 16) + m > prefix.PrefixLength as usize { break; } let bit = 1 << (15 - m); if (x_word & bit) == (y_word & bit) { *netmask_elt |= bit; } else { continue 'prefixloopv6; } } } item_netmask = Ipv6Addr::new( netmask[0], netmask[1], netmask[2], netmask[3], netmask[4], netmask[5], netmask[6], netmask[7], ); break 'prefixloopv6; } _ => continue, }; } IfAddr::V6(Ifv6Addr { ip: ipv6_addr, netmask: item_netmask, broadcast: None, }) } }; let index = match addr { IfAddr::V4(_) => ifaddr.ipv4_index(), IfAddr::V6(_) => ifaddr.ipv6_index(), }; ret.push(Interface { name: ifaddr.name(), addr, index, }); } } Ok(ret) } } #[cfg(windows)] /// Get address pub fn get_if_addrs() -> io::Result> { getifaddrs_windows::get_if_addrs() } #[cfg(test)] mod tests { use super::{get_if_addrs, Interface}; use std::io::Read; use std::net::{IpAddr, Ipv4Addr}; use std::process::{Command, Stdio}; use std::str::FromStr; use std::thread; use std::time::Duration; fn list_system_interfaces(cmd: &str, arg: &str) -> String { let start_cmd = if arg == "" { Command::new(cmd).stdout(Stdio::piped()).spawn() } else { Command::new(cmd).arg(arg).stdout(Stdio::piped()).spawn() }; let mut process = match start_cmd { Err(why) => { println!("couldn't start cmd {} : {}", cmd, why.to_string()); return "".to_string(); } Ok(process) => process, }; thread::sleep(Duration::from_millis(1000)); let _ = process.kill(); let result: Vec = process .stdout .unwrap() .bytes() .map(|x| x.unwrap()) .collect(); String::from_utf8(result).unwrap() } #[cfg(windows)] fn list_system_addrs() -> Vec { use std::net::Ipv6Addr; list_system_interfaces("ipconfig", "") .lines() .filter_map(|line| { println!("{}", line); if line.contains("Address") && !line.contains("Link-local") { let addr_s: Vec<&str> = line.split(" : ").collect(); if line.contains("IPv6") { return Some(IpAddr::V6(Ipv6Addr::from_str(addr_s[1]).unwrap())); } else if line.contains("IPv4") { return Some(IpAddr::V4(Ipv4Addr::from_str(addr_s[1]).unwrap())); } } None }) .collect() } #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))] fn list_system_addrs() -> Vec { list_system_interfaces("ip", "addr") .lines() .filter_map(|line| { println!("{}", line); if line.contains("inet ") { let addr_s: Vec<&str> = line.split_whitespace().collect(); let addr: Vec<&str> = addr_s[1].split('/').collect(); return Some(IpAddr::V4(Ipv4Addr::from_str(addr[0]).unwrap())); } None }) .collect() } #[cfg(any(target_os = "freebsd", target_os = "macos", target_os = "ios"))] fn list_system_addrs() -> Vec { list_system_interfaces("ifconfig", "") .lines() .filter_map(|line| { println!("{}", line); if line.contains("inet ") { let addr_s: Vec<&str> = line.split_whitespace().collect(); return Some(IpAddr::V4(Ipv4Addr::from_str(addr_s[1]).unwrap())); } None }) .collect() } #[test] fn test_get_if_addrs() { let ifaces = get_if_addrs().unwrap(); println!("Local interfaces:"); println!("{:#?}", ifaces); // at least one loop back address assert!( 1 <= ifaces .iter() .filter(|interface| interface.is_loopback()) .count() ); // if index is set, it is non-zero for interface in &ifaces { if let Some(idx) = interface.index { assert!(idx > 0); } } // one address of IpV4(127.0.0.1) let is_loopback = |interface: &&Interface| interface.addr.ip() == IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); assert_eq!(1, ifaces.iter().filter(is_loopback).count()); // each system address shall be listed let system_addrs = list_system_addrs(); assert!(!system_addrs.is_empty()); for addr in system_addrs { let mut listed = false; println!("\n checking whether {:?} has been properly listed \n", addr); for interface in &ifaces { if interface.addr.ip() == addr { listed = true; } assert!(interface.index.is_some()); } assert!(listed); } } } if-addrs-0.10.1/src/posix.rs000064400000000000000000000042251046102023000136760ustar 00000000000000// Copyright 2018 MaidSafe.net limited. // // This SAFE Network Software is licensed to you under the MIT license or the Modified BSD license , at your option. This file may not be copied, // modified, or distributed except according to those terms. Please review the Licences for the // specific language governing permissions and limitations relating to use of the SAFE Network // Software. use crate::sockaddr; use libc::{freeifaddrs, getifaddrs, ifaddrs}; use std::net::IpAddr; use std::{io, mem}; #[cfg(any(target_os = "linux", target_os = "android", target_os = "nacl"))] pub fn do_broadcast(ifaddr: &ifaddrs) -> Option { sockaddr::to_ipaddr(ifaddr.ifa_ifu) } #[cfg(any( target_os = "freebsd", target_os = "haiku", target_os = "illumos", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd" ))] pub fn do_broadcast(ifaddr: &ifaddrs) -> Option { sockaddr::to_ipaddr(ifaddr.ifa_dstaddr) } pub struct IfAddrs { inner: *mut ifaddrs, } impl IfAddrs { #[allow(unsafe_code, clippy::new_ret_no_self)] pub fn new() -> io::Result { let mut ifaddrs = mem::MaybeUninit::uninit(); unsafe { if -1 == getifaddrs(ifaddrs.as_mut_ptr()) { return Err(io::Error::last_os_error()); } Ok(Self { inner: ifaddrs.assume_init(), }) } } pub fn iter(&self) -> IfAddrsIterator { IfAddrsIterator { next: self.inner } } } impl Drop for IfAddrs { #[allow(unsafe_code)] fn drop(&mut self) { unsafe { freeifaddrs(self.inner); } } } pub struct IfAddrsIterator { next: *mut ifaddrs, } impl Iterator for IfAddrsIterator { type Item = ifaddrs; #[allow(unsafe_code)] fn next(&mut self) -> Option { if self.next.is_null() { return None; }; Some(unsafe { let result = *self.next; self.next = (*self.next).ifa_next; result }) } } if-addrs-0.10.1/src/sockaddr.rs000064400000000000000000000075731046102023000143370ustar 00000000000000// Copyright 2018 MaidSafe.net limited. // // This SAFE Network Software is licensed to you under the MIT license or the Modified BSD license , at your option. This file may not be copied, // modified, or distributed except according to those terms. Please review the Licences for the // specific language governing permissions and limitations relating to use of the SAFE Network // Software. #[cfg(not(windows))] use libc::{sockaddr, sockaddr_in, sockaddr_in6, AF_INET, AF_INET6}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::ptr::NonNull; #[cfg(windows)] use windows_sys::Win32::Networking::WinSock::{ AF_INET, AF_INET6, SOCKADDR as sockaddr, SOCKADDR_IN as sockaddr_in, SOCKADDR_IN6 as sockaddr_in6, }; pub fn to_ipaddr(sockaddr: *const sockaddr) -> Option { if sockaddr.is_null() { return None; } SockAddr::new(sockaddr)?.as_ipaddr() } // Wrapper around a sockaddr pointer. Guaranteed to not be null. struct SockAddr { inner: NonNull, } impl SockAddr { #[allow(clippy::new_ret_no_self)] fn new(sockaddr: *const sockaddr) -> Option { NonNull::new(sockaddr as *mut _).map(|inner| Self { inner }) } #[cfg(not(windows))] fn as_ipaddr(&self) -> Option { match self.sockaddr_in() { Some(SockAddrIn::In(sa)) => { let b = sa.sin_addr.s_addr.to_ne_bytes(); Some(IpAddr::V4(Ipv4Addr::new(b[0], b[1], b[2], b[3]))) } Some(SockAddrIn::In6(sa)) => { // Ignore all fe80:: addresses as these are link locals #[cfg(not(feature = "link-local"))] if sa.sin6_addr.s6_addr[0] == 0xfe && sa.sin6_addr.s6_addr[1] == 0x80 { return None; } Some(IpAddr::V6(Ipv6Addr::from(sa.sin6_addr.s6_addr))) } None => None, } } #[cfg(windows)] fn as_ipaddr(&self) -> Option { match self.sockaddr_in() { Some(SockAddrIn::In(sa)) => { let s_addr = unsafe { sa.sin_addr.S_un.S_addr }; // Ignore all 169.254.x.x addresses as these are not active interfaces #[cfg(not(feature = "link-local"))] if s_addr & 65535 == 0xfea9 { return None; } let b = s_addr.to_ne_bytes(); Some(IpAddr::V4(Ipv4Addr::new(b[0], b[1], b[2], b[3]))) } Some(SockAddrIn::In6(sa)) => { let s6_addr = unsafe { sa.sin6_addr.u.Byte }; // Ignore all fe80:: addresses as these are link locals #[cfg(not(feature = "link-local"))] if s6_addr[0] == 0xfe && s6_addr[1] == 0x80 { return None; } Some(IpAddr::V6(Ipv6Addr::from(s6_addr.clone()))) } None => None, } } fn sockaddr_in(&self) -> Option { const AF_INET_U32: u32 = AF_INET as u32; const AF_INET6_U32: u32 = AF_INET6 as u32; match self.sa_family() { AF_INET_U32 => Some(SockAddrIn::In(self.sa_in())), AF_INET6_U32 => Some(SockAddrIn::In6(self.sa_in6())), _ => None, } } #[allow(unsafe_code)] fn sa_family(&self) -> u32 { unsafe { u32::from(self.inner.as_ref().sa_family) } } #[allow(unsafe_code)] #[allow(clippy::cast_ptr_alignment)] fn sa_in(&self) -> sockaddr_in { unsafe { *(self.inner.as_ptr() as *const sockaddr_in) } } #[allow(unsafe_code)] #[allow(clippy::cast_ptr_alignment)] fn sa_in6(&self) -> sockaddr_in6 { unsafe { *(self.inner.as_ptr() as *const sockaddr_in6) } } } enum SockAddrIn { In(sockaddr_in), In6(sockaddr_in6), } if-addrs-0.10.1/src/windows.rs000064400000000000000000000127401046102023000142270ustar 00000000000000// Copyright 2018 MaidSafe.net limited. // // This SAFE Network Software is licensed to you under the MIT license or the Modified BSD license , at your option. This file may not be copied, // modified, or distributed except according to those terms. Please review the Licences for the // specific language governing permissions and limitations relating to use of the SAFE Network // Software. use std::ffi::CStr; use std::{io, ptr}; use windows_sys::Win32::Foundation::{ERROR_BUFFER_OVERFLOW, ERROR_SUCCESS}; use windows_sys::Win32::NetworkManagement::IpHelper::{ GetAdaptersAddresses, GAA_FLAG_INCLUDE_PREFIX, GAA_FLAG_SKIP_ANYCAST, GAA_FLAG_SKIP_DNS_SERVER, GAA_FLAG_SKIP_FRIENDLY_NAME, GAA_FLAG_SKIP_MULTICAST, IP_ADAPTER_ADDRESSES_LH, IP_ADAPTER_PREFIX_XP, IP_ADAPTER_UNICAST_ADDRESS_LH, }; use windows_sys::Win32::System::Memory::{ GetProcessHeap, HeapAlloc, HeapFree, HEAP_NONE, HEAP_ZERO_MEMORY, }; #[repr(transparent)] pub struct IpAdapterAddresses(*const IP_ADAPTER_ADDRESSES_LH); impl IpAdapterAddresses { #[allow(unsafe_code)] pub fn name(&self) -> String { unsafe { CStr::from_ptr((*self.0).AdapterName as _) } .to_string_lossy() .into_owned() } pub fn ipv4_index(&self) -> Option { let if_index = unsafe { (*self.0).Anonymous1.Anonymous.IfIndex }; if if_index == 0 { None } else { Some(if_index) } } pub fn ipv6_index(&self) -> Option { let if_index = unsafe { (*self.0).Ipv6IfIndex }; if if_index == 0 { None } else { Some(if_index) } } pub fn prefixes(&self) -> PrefixesIterator { PrefixesIterator { _head: unsafe { &*self.0 }, next: unsafe { (*self.0).FirstPrefix }, } } pub fn unicast_addresses(&self) -> UnicastAddressesIterator { UnicastAddressesIterator { _head: unsafe { &*self.0 }, next: unsafe { (*self.0).FirstUnicastAddress }, } } } pub struct IfAddrs { inner: IpAdapterAddresses, } impl IfAddrs { #[allow(unsafe_code)] pub fn new() -> io::Result { let mut buffersize = 15000; let mut ifaddrs: *mut IP_ADAPTER_ADDRESSES_LH; loop { unsafe { ifaddrs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffersize as _) as *mut IP_ADAPTER_ADDRESSES_LH; if ifaddrs.is_null() { panic!("Failed to allocate buffer in get_if_addrs()"); } let retcode = GetAdaptersAddresses( 0, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_FRIENDLY_NAME, ptr::null_mut(), ifaddrs, &mut buffersize, ); match retcode { ERROR_SUCCESS => break, ERROR_BUFFER_OVERFLOW => { HeapFree(GetProcessHeap(), HEAP_NONE, ifaddrs as _); buffersize *= 2; continue; } _ => { HeapFree(GetProcessHeap(), HEAP_NONE, ifaddrs as _); return Err(io::Error::last_os_error()); } } } } Ok(Self { inner: IpAdapterAddresses(ifaddrs), }) } pub fn iter(&self) -> IfAddrsIterator { IfAddrsIterator { _head: self, next: self.inner.0, } } } impl Drop for IfAddrs { #[allow(unsafe_code)] fn drop(&mut self) { unsafe { HeapFree(GetProcessHeap(), HEAP_NONE, self.inner.0 as _); } } } pub struct IfAddrsIterator<'a> { _head: &'a IfAddrs, next: *const IP_ADAPTER_ADDRESSES_LH, } impl<'a> Iterator for IfAddrsIterator<'a> { type Item = IpAdapterAddresses; #[allow(unsafe_code)] fn next(&mut self) -> Option { if self.next.is_null() { return None; }; Some(unsafe { let result = &*self.next; self.next = (*self.next).Next; IpAdapterAddresses(result) }) } } pub struct PrefixesIterator<'a> { _head: &'a IP_ADAPTER_ADDRESSES_LH, next: *const IP_ADAPTER_PREFIX_XP, } impl<'a> Iterator for PrefixesIterator<'a> { type Item = &'a IP_ADAPTER_PREFIX_XP; #[allow(unsafe_code)] fn next(&mut self) -> Option { if self.next.is_null() { return None; }; Some(unsafe { let result = &*self.next; self.next = (*self.next).Next; result }) } } pub struct UnicastAddressesIterator<'a> { _head: &'a IP_ADAPTER_ADDRESSES_LH, next: *const IP_ADAPTER_UNICAST_ADDRESS_LH, } impl<'a> Iterator for UnicastAddressesIterator<'a> { type Item = &'a IP_ADAPTER_UNICAST_ADDRESS_LH; #[allow(unsafe_code)] fn next(&mut self) -> Option { if self.next.is_null() { return None; }; Some(unsafe { let result = &*self.next; self.next = (*self.next).Next; result }) } }