use std::fmt;
use std::net::{IpAddr, SocketAddr};
use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::process::ProcessInfo;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Link {
pub name: String,
pub index: u32,
pub kind: LinkKind,
pub mac: Option<MacAddr>,
pub mtu: u32,
pub state: OperState,
pub linkmode: LinkMode,
pub flags: LinkFlags,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LinkKind {
Ethernet,
Wifi,
Loopback,
Bridge,
Veth,
Tun,
Tap,
Wireguard,
Vlan,
Bond,
Other(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum OperState {
Up,
Down,
Dormant,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum LinkMode {
Default,
Dormant,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct LinkFlags(pub Vec<String>);
impl LinkFlags {
pub fn has(&self, flag: &str) -> bool {
self.0.iter().any(|f| f.eq_ignore_ascii_case(flag))
}
pub fn is_loopback(&self) -> bool {
self.has("LOOPBACK")
}
pub fn lower_up(&self) -> bool {
self.has("LOWER_UP")
}
pub fn no_carrier(&self) -> bool {
self.has("NO-CARRIER")
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacAddr(pub [u8; 6]);
impl fmt::Debug for MacAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for MacAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let b = self.0;
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
b[0], b[1], b[2], b[3], b[4], b[5]
)
}
}
impl std::str::FromStr for MacAddr {
type Err = MacAddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut out = [0u8; 6];
let parts: Vec<&str> = s.split([':', '-']).collect();
if parts.len() != 6 {
return Err(MacAddrParseError);
}
for (i, p) in parts.iter().enumerate() {
out[i] = u8::from_str_radix(p, 16).map_err(|_| MacAddrParseError)?;
}
Ok(MacAddr(out))
}
}
impl Serialize for MacAddr {
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
s.collect_str(self)
}
}
impl<'de> Deserialize<'de> for MacAddr {
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
s.parse().map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("invalid MAC address")]
pub struct MacAddrParseError;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Addr {
pub ip: IpAddr,
pub prefix: u8,
pub scope: AddrScope,
pub dynamic: bool,
pub temporary: bool,
pub deprecated: bool,
pub mngtmpaddr: bool,
pub noprefixroute: bool,
pub valid_lft: Lifetime,
pub preferred_lft: Lifetime,
pub label: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AddrScope {
Global,
Link,
Host,
Site,
Nowhere,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Lifetime {
Forever,
Seconds(u32),
}
impl Lifetime {
pub fn is_expired(self) -> bool {
matches!(self, Lifetime::Seconds(0))
}
pub fn as_duration(self) -> Option<Duration> {
match self {
Lifetime::Forever => None,
Lifetime::Seconds(s) => Some(Duration::from_secs(u64::from(s))),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Route {
pub dst: RouteDst,
pub gateway: Option<IpAddr>,
pub oif: Option<String>,
pub metric: Option<u32>,
pub table: u32,
pub protocol: String,
pub scope: RouteScope,
pub prefsrc: Option<IpAddr>,
pub flags: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RouteDst {
Default,
Prefix { ip: IpAddr, prefix: u8 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum RouteScope {
Global,
Universe,
Site,
Link,
Host,
Nowhere,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Neighbor {
pub ip: IpAddr,
pub lladdr: Option<MacAddr>,
pub oif: String,
pub state: NeighState,
pub is_router: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum NeighState {
Incomplete,
Reachable,
Stale,
Delay,
Probe,
Failed,
Permanent,
Noarp,
None,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Socket {
pub proto: L4Proto,
pub local: SocketAddr,
pub remote: Option<SocketAddr>,
pub state: TcpState,
pub process: ProcessInfo,
pub bound_iface: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum L4Proto {
Tcp,
Udp,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum TcpState {
Listen,
Established,
SynSent,
SynRecv,
FinWait1,
FinWait2,
TimeWait,
Close,
CloseWait,
LastAck,
Closing,
Unconn,
Unknown,
}