use std::fmt::Display;
#[derive(Clone)]
pub struct Network {
pub name: String,
pub inet: Option<String>,
pub broadcast: Option<String>,
pub netmask: Option<String>,
pub mac: Option<String>,
}
impl Display for Network {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut output = format!("name: {}", self.name);
if let Some(inet) = &self.inet {
output = format!("{}\ninet: {}", output, inet);
}
if let Some(broadcast) = &self.broadcast {
output = format!("{}\nbroadcast: {}", output, broadcast);
}
if let Some(netmask) = &self.netmask {
output = format!("{}\nnetmask: {}", output, netmask);
}
if let Some(mac) = &self.mac {
output = format!("{}\nmac: {}", output, mac);
}
write!(f, "{}", output)
}
}
fn get_ifconfig_text() -> Vec<String> {
let output = std::process::Command::new("ifconfig")
.output()
.expect("Failed to execute ifconfig.");
let ifconfig_text = String::from_utf8_lossy(&output.stdout).to_string();
ifconfig_text
.split("\n\n")
.map(|x| x.to_string())
.collect::<Vec<String>>()
}
pub fn parse_network(line: &str) -> Network {
let mut network = Network {
name: "".to_string(),
inet: None,
broadcast: None,
netmask: None,
mac: None,
};
network.name = line.split(':').collect::<Vec<&str>>()[0].to_string();
if let Some(inet) = line.split("inet ").collect::<Vec<&str>>().get(1) {
let mut inet = inet.to_string();
inet = inet.split(' ').collect::<Vec<&str>>()[0]
.to_string()
.replace('\n', "");
network.inet = Some(inet);
}
if let Some(broadcast) = line.split("broadcast ").collect::<Vec<&str>>().get(1) {
let mut broadcast = broadcast.to_string();
broadcast = broadcast.split(' ').collect::<Vec<&str>>()[0]
.to_string()
.replace('\n', "");
network.broadcast = Some(broadcast);
}
if let Some(netmask) = line.split("netmask ").collect::<Vec<&str>>().get(1) {
let mut netmask = netmask.to_string();
netmask = netmask.split(' ').collect::<Vec<&str>>()[0]
.to_string()
.replace('\n', "");
network.netmask = Some(netmask);
}
if let Some(mac) = line.split("ether ").collect::<Vec<&str>>().get(1) {
let mut mac = mac.to_string();
mac = mac.split(' ').collect::<Vec<&str>>()[0]
.to_string()
.replace('\n', "");
network.mac = Some(mac);
}
network
}
pub fn get_networks() -> Vec<Network> {
let mut networks = Vec::new();
get_ifconfig_text().iter().filter(|x| !x.is_empty()).for_each(|x| {
networks.push(parse_network(x));
});
networks
}
pub fn find_network(name: &str) -> Option<Network> {
get_networks().iter().find(|x| x.name.contains(name)).cloned()
}
pub fn get_wlan(identifier: Option<&str>) -> Vec<Network> {
get_networks()
.iter()
.filter(|x| {
(x.name.contains("wlan") || x.name.contains("wlp"))
&& x.inet.is_some() &&
match identifier {
Some(ref identifier) => x.name.contains(identifier),
None => true,
}
})
.cloned()
.collect::<Vec<Network>>()
}
pub fn get_ethernet(identifier: Option<&str>) -> Vec<Network> {
get_networks()
.iter()
.filter(|x| {
(x.name.contains("eth") || x.name.contains("enp"))
&& x.inet.is_some() &&
match identifier {
Some(ref identifier) => x.name.contains(identifier),
None => true,
}
})
.cloned()
.collect::<Vec<Network>>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn does_get_networks_work() {
let networks = get_networks();
assert!(!networks.is_empty());
}
#[test]
fn does_wlan_work(){
let wlan = get_wlan(None);
assert!(!wlan.is_empty())
}
}