use std::net::{IpAddr, SocketAddr};
use serde::{Deserialize, Serialize};
use crate::diag::FirewallVerdict;
use crate::link::{L4Proto, TcpState};
use crate::process::ProcessInfo;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Service {
pub port: u16,
pub proto: L4Proto,
pub bind: BindScope,
pub process: ProcessInfo,
pub exposure: Exposure,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum BindScope {
AnyAddress,
Loopback,
SpecificInterface(String),
SpecificAddress(IpAddr),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Exposure {
LocalOnly,
LanOnly,
Exposed,
Unknown,
}
impl Exposure {
pub fn from_scope_and_verdict(bind: &BindScope, verdict: FirewallVerdict) -> Self {
match bind {
BindScope::Loopback => Exposure::LocalOnly,
BindScope::SpecificAddress(ip) if ip.is_loopback() => Exposure::LocalOnly,
_ => match verdict {
FirewallVerdict::Allow => Exposure::Exposed,
FirewallVerdict::Drop | FirewallVerdict::Reject => Exposure::LanOnly,
FirewallVerdict::NoMatch | FirewallVerdict::Unknown => Exposure::Unknown,
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Flow {
pub proto: L4Proto,
pub local: SocketAddr,
pub remote: SocketAddr,
pub state: TcpState,
pub process: ProcessInfo,
pub bytes_in: u64,
pub bytes_out: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub rtt_us: Option<u32>,
}