All checks were successful
continuous-integration/drone/push Build is passing
228 lines
6.4 KiB
Rust
228 lines
6.4 KiB
Rust
use crate::constants;
|
|
use nix::sys::socket::{AddressFamily, SockaddrLike};
|
|
use std::collections::HashMap;
|
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
use std::process::Command;
|
|
use std::str::FromStr;
|
|
use sysinfo::Networks;
|
|
|
|
pub fn extract_ipv4(ip: IpAddr) -> Ipv4Addr {
|
|
match ip {
|
|
IpAddr::V4(i) => i,
|
|
IpAddr::V6(_) => {
|
|
panic!("IPv6 found in IPv4 definition!")
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn extract_ipv6(ip: IpAddr) -> Ipv6Addr {
|
|
match ip {
|
|
IpAddr::V4(_) => {
|
|
panic!("IPv4 found in IPv6 definition!")
|
|
}
|
|
IpAddr::V6(i) => i,
|
|
}
|
|
}
|
|
|
|
pub fn is_ipv4_address_valid<D: AsRef<str>>(ip: D) -> bool {
|
|
Ipv4Addr::from_str(ip.as_ref()).is_ok()
|
|
}
|
|
|
|
pub fn is_ipv6_address_valid<D: AsRef<str>>(ip: D) -> bool {
|
|
Ipv6Addr::from_str(ip.as_ref()).is_ok()
|
|
}
|
|
|
|
pub fn is_ipv4_mask_valid(mask: u8) -> bool {
|
|
mask <= 32
|
|
}
|
|
|
|
pub fn is_ipv6_mask_valid(mask: u8) -> bool {
|
|
mask <= 128
|
|
}
|
|
|
|
pub fn is_mask_valid(ipv: usize, mask: u8) -> bool {
|
|
match ipv {
|
|
4 => is_ipv4_mask_valid(mask),
|
|
6 => is_ipv6_mask_valid(mask),
|
|
_ => panic!("Unsupported IP version"),
|
|
}
|
|
}
|
|
|
|
pub fn is_mac_address_valid<D: AsRef<str>>(mac: D) -> bool {
|
|
lazy_regex::regex!("^([a-fA-F0-9]{2}[:-]){5}[a-fA-F0-9]{2}$").is_match(mac.as_ref())
|
|
}
|
|
|
|
pub fn is_net_interface_name_valid<D: AsRef<str>>(int: D) -> bool {
|
|
lazy_regex::regex!("^[a-zA-Z0-9]+$").is_match(int.as_ref())
|
|
}
|
|
|
|
/// Get the list of available network interfaces
|
|
pub fn net_list() -> Vec<String> {
|
|
let mut networks = Networks::new();
|
|
networks.refresh(true);
|
|
|
|
networks
|
|
.list()
|
|
.iter()
|
|
.map(|n| n.0.to_string())
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
/// Get the list of available network interfaces associated with their IP address
|
|
pub fn net_list_and_ips() -> anyhow::Result<HashMap<String, Vec<IpAddr>>> {
|
|
let addrs = nix::ifaddrs::getifaddrs()?;
|
|
|
|
let mut res = HashMap::new();
|
|
|
|
for ifaddr in addrs {
|
|
let address = match ifaddr.address {
|
|
Some(address) => address,
|
|
None => {
|
|
log::debug!(
|
|
"Interface {} has an unsupported address family",
|
|
ifaddr.interface_name
|
|
);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
let addr_str = match address.family() {
|
|
Some(AddressFamily::Inet) => {
|
|
let address = address.to_string();
|
|
address
|
|
.split_once(':')
|
|
.map(|a| a.0)
|
|
.unwrap_or(&address)
|
|
.to_string()
|
|
}
|
|
Some(AddressFamily::Inet6) => {
|
|
let address = address.to_string();
|
|
let address = address
|
|
.split_once(']')
|
|
.map(|a| a.0)
|
|
.unwrap_or(&address)
|
|
.to_string();
|
|
|
|
let address = address
|
|
.split_once('%')
|
|
.map(|a| a.0)
|
|
.unwrap_or(&address)
|
|
.to_string();
|
|
|
|
address.strip_prefix('[').unwrap_or(&address).to_string()
|
|
}
|
|
_ => {
|
|
log::debug!(
|
|
"Interface {} has an unsupported address family {:?}",
|
|
ifaddr.interface_name,
|
|
address.family()
|
|
);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
log::debug!(
|
|
"Process ip {addr_str} for interface {}",
|
|
ifaddr.interface_name
|
|
);
|
|
|
|
let ip = IpAddr::from_str(&addr_str)?;
|
|
|
|
if !res.contains_key(&ifaddr.interface_name) {
|
|
res.insert(ifaddr.interface_name.to_string(), Vec::with_capacity(1));
|
|
}
|
|
|
|
res.get_mut(&ifaddr.interface_name).unwrap().push(ip);
|
|
}
|
|
|
|
Ok(res)
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct IPBridgeInfo {
|
|
ifname: String,
|
|
}
|
|
|
|
/// Get the list of bridge interfaces
|
|
pub fn bridges_list() -> anyhow::Result<Vec<String>> {
|
|
let mut cmd = Command::new(constants::PROGRAM_IP);
|
|
cmd.args(["-json", "link", "show", "type", "bridge"]);
|
|
let output = cmd.output()?;
|
|
if !output.status.success() {
|
|
anyhow::bail!(
|
|
"{} failed, status: {}, stderr: {}",
|
|
constants::PROGRAM_IP,
|
|
output.status,
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|
|
|
|
// Parse JSON result
|
|
let res: Vec<IPBridgeInfo> = serde_json::from_str(&String::from_utf8_lossy(&output.stdout))?;
|
|
|
|
Ok(res.iter().map(|ip| ip.ifname.clone()).collect())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::utils::net_utils::{
|
|
is_ipv4_address_valid, is_ipv6_address_valid, is_mac_address_valid, is_mask_valid,
|
|
is_net_interface_name_valid,
|
|
};
|
|
|
|
#[test]
|
|
fn test_is_mac_address_valid() {
|
|
assert!(is_mac_address_valid("FF:FF:FF:FF:FF:FF"));
|
|
assert!(is_mac_address_valid("02:42:a4:6e:f2:be"));
|
|
|
|
assert!(!is_mac_address_valid("tata"));
|
|
assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FZ"));
|
|
assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FF:FF"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_ipv4_address_valid() {
|
|
assert!(is_ipv4_address_valid("10.0.0.1"));
|
|
assert!(is_ipv4_address_valid("2.56.58.156"));
|
|
|
|
assert!(!is_ipv4_address_valid("tata"));
|
|
assert!(!is_ipv4_address_valid("1.25.25.288"));
|
|
assert!(!is_ipv4_address_valid("5.5.5.5.5"));
|
|
assert!(!is_ipv4_address_valid("fe80::"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_ipv6_address_valid() {
|
|
assert!(is_ipv6_address_valid("fe80::"));
|
|
assert!(is_ipv6_address_valid("fe80:dd::"));
|
|
assert!(is_ipv6_address_valid("00:00:00:00:00::"));
|
|
assert!(is_ipv6_address_valid("0:0:0:0:0:0:0:0"));
|
|
|
|
assert!(!is_ipv6_address_valid("tata"));
|
|
assert!(!is_ipv6_address_valid("2.56.58.156"));
|
|
assert!(!is_ipv6_address_valid("fe::dd::dd"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_mask_valid() {
|
|
assert!(is_mask_valid(4, 25));
|
|
assert!(is_mask_valid(4, 32));
|
|
assert!(is_mask_valid(6, 32));
|
|
assert!(is_mask_valid(6, 34));
|
|
|
|
assert!(!is_mask_valid(4, 34));
|
|
assert!(is_mask_valid(6, 69));
|
|
assert!(is_mask_valid(6, 128));
|
|
assert!(!is_mask_valid(6, 129));
|
|
}
|
|
|
|
#[test]
|
|
fn test_is_net_interface_name_valid() {
|
|
assert!(is_net_interface_name_valid("eth0"));
|
|
assert!(is_net_interface_name_valid("enp0s25"));
|
|
|
|
assert!(!is_net_interface_name_valid("enp0s25 "));
|
|
assert!(!is_net_interface_name_valid("@enp0s25 "));
|
|
}
|
|
}
|