Add egress full statistics support

This commit is contained in:
DaLaw2 2024-12-23 14:29:00 +08:00
parent ac829024f6
commit 7b8801a146
11 changed files with 237 additions and 183 deletions

View File

@ -7,31 +7,53 @@ use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
use net_guardia_common::MAX_STATS;
#[map]
static IPV4_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_EGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_EGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_EGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_EGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_EGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_EGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_EGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_EGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_EGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_EGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_EGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_EGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
pub fn ipv4_update_stats(event: &IPv4Event) {
unsafe {
let now = bpf_ktime_get_ns();
let source = [event.source_ip, event.source_port as u32];
ipv4_update_flow_stats(&IPV4_DST_1MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_DST_10MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_DST_1HOUR, &source, event, now);
let destination = [event.destination_ip, event.destination_port as u32];
ipv4_update_flow_stats(&IPV4_EGRESS_SRC_1MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_EGRESS_SRC_10MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_EGRESS_SRC_1HOUR, &source, event, now);
ipv4_update_flow_stats(&IPV4_EGRESS_DST_1MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_EGRESS_DST_10MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_EGRESS_DST_1HOUR, &destination, event, now);
}
}
@ -39,9 +61,13 @@ pub fn ipv6_update_stats(event: &IPv6Event) {
unsafe {
let now = bpf_ktime_get_ns();
let source = [event.source_ip, event.source_port as u128];
ipv6_update_flow_status(&IPV6_DST_1MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_DST_10MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_DST_1HOUR, &source, event, now);
let destination = [event.destination_ip, event.destination_port as u128];
ipv6_update_flow_status(&IPV6_EGRESS_SRC_1MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_EGRESS_SRC_10MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_EGRESS_SRC_1HOUR, &source, event, now);
ipv6_update_flow_status(&IPV6_EGRESS_DST_1MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_EGRESS_DST_10MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_EGRESS_DST_1HOUR, &destination, event, now);
}
}

View File

@ -7,40 +7,40 @@ use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
use net_guardia_common::MAX_STATS;
#[map]
static IPV4_SRC_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_SRC_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_SRC_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_SRC_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_SRC_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_SRC_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV4_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
static IPV4_INGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
#[map]
static IPV6_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
static IPV6_INGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
LruHashMap::with_max_entries(MAX_STATS, 0);
pub fn ipv4_update_stats(event: &IPv4Event) {
@ -48,12 +48,12 @@ pub fn ipv4_update_stats(event: &IPv4Event) {
let now = bpf_ktime_get_ns();
let source = [event.source_ip, event.source_port as u32];
let destination = [event.destination_ip, event.destination_port as u32];
ipv4_update_flow_stats(&IPV4_SRC_1MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_SRC_10MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_SRC_1HOUR, &source, event, now);
ipv4_update_flow_stats(&IPV4_DST_1MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_DST_10MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_DST_1HOUR, &destination, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_10MIN, &source, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1HOUR, &source, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_DST_1MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_DST_10MIN, &destination, event, now);
ipv4_update_flow_stats(&IPV4_INGRESS_DST_1HOUR, &destination, event, now);
}
}
@ -62,12 +62,12 @@ pub fn ipv6_update_stats(event: &IPv6Event) {
let now = bpf_ktime_get_ns();
let source = [event.source_ip, event.source_port as u128];
let destination = [event.destination_ip, event.destination_port as u128];
ipv6_update_flow_status(&IPV6_SRC_1MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_SRC_10MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_SRC_1HOUR, &source, event, now);
ipv6_update_flow_status(&IPV6_DST_1MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_DST_10MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_DST_1HOUR, &destination, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_SRC_10MIN, &source, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1HOUR, &source, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_DST_1MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_DST_10MIN, &destination, event, now);
ipv6_update_flow_status(&IPV6_INGRESS_DST_1HOUR, &destination, event, now);
}
}

View File

@ -23,25 +23,23 @@ impl ConfigManager {
}
fn load_config() -> anyhow::Result<Config> {
match fs::read_to_string("./config.toml") {
Ok(toml_string) => match toml::from_str::<ConfigTable>(&toml_string) {
Ok(config_table) => {
let config = config_table.config;
if !Self::validate(&config) {
error!("{}", SystemEntry::InvalidConfig);
Err(anyhow!(SystemEntry::InvalidConfig))
} else {
Ok(config)
}
}
Err(_) => {
error!("{}", SystemEntry::InvalidConfig);
Err(anyhow!(SystemEntry::InvalidConfig))
}
},
Err(_) => {
error!("{}", SystemEntry::ConfigNotFound);
let parse_result = (|| {
let toml_string = fs::read_to_string("./config.toml")
.map_err(|_| anyhow!(SystemEntry::ConfigNotFound))?;
let config_table = toml::from_str::<ConfigTable>(&toml_string)
.map_err(|_| anyhow!(SystemEntry::InvalidConfig))?;
let config = config_table.config;
if !Self::validate(&config) {
Err(anyhow!(SystemEntry::InvalidConfig))
} else {
Ok(config)
}
})();
match parse_result {
Ok(config) => Ok(config),
Err(err) => {
error!("{}", SystemEntry::InvalidConfig);
Err(err)
}
}
}
@ -60,6 +58,7 @@ impl ConfigManager {
once_lock.read().await.clone()
}
#[allow(dead_code)]
pub async fn update(config: Config) {
// Initialization has been ensured
let lock = SYNC_CONFIG.get().unwrap();

View File

@ -1,6 +1,6 @@
use crate::core::system::System;
use crate::model::direction::Direction;
use crate::model::ip_address::IpAddressType;
use crate::model::direction::FlowDirection;
use crate::model::ip_address::IntoNative;
use crate::model::list_type::ListType;
use crate::utils::ip_address::convert_ports_to_vec;
use crate::utils::log_entry::ebpf::EbpfEntry;
@ -18,26 +18,26 @@ use tracing::info;
static ACCESS_CONTROL: OnceLock<RwLock<AccessControl>> = OnceLock::new();
pub struct AccessControl {
ipv4_maps: StdHashMap<(Direction, ListType), AccessMap<IPv4>>,
ipv6_maps: StdHashMap<(Direction, ListType), AccessMap<IPv6>>,
ipv4_maps: StdHashMap<(FlowDirection, ListType), AccessMap<IPv4>>,
ipv6_maps: StdHashMap<(FlowDirection, ListType), AccessMap<IPv6>>,
}
impl AccessControl {
const MAP_CONFIGS: [((Direction, ListType), (&'static str, &'static str)); 4] = [
const MAP_CONFIGS: [((FlowDirection, ListType), (&'static str, &'static str)); 4] = [
(
(Direction::Source, ListType::White),
(FlowDirection::Source, ListType::White),
("IPV4_SRC_WHITELIST", "IPV6_SRC_WHITELIST"),
),
(
(Direction::Source, ListType::Black),
(FlowDirection::Source, ListType::Black),
("IPV4_SRC_BLACKLIST", "IPV6_SRC_BLACKLIST"),
),
(
(Direction::Destination, ListType::White),
(FlowDirection::Destination, ListType::White),
("IPV4_DST_WHITELIST", "IPV6_DST_WHITELIST"),
),
(
(Direction::Destination, ListType::Black),
(FlowDirection::Destination, ListType::Black),
("IPV4_DST_BLACKLIST", "IPV6_DST_BLACKLIST"),
),
];
@ -85,7 +85,7 @@ impl AccessControl {
}
pub async fn get_ipv4_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
) -> StdHashMap<Ipv4Addr, Vec<Port>> {
let access_list = AccessControl::instance().await;
@ -97,7 +97,7 @@ impl AccessControl {
}
pub async fn get_ipv6_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
) -> StdHashMap<Ipv6Addr, Vec<Port>> {
let access_list = AccessControl::instance().await;
@ -109,7 +109,7 @@ impl AccessControl {
}
pub async fn add_ipv4_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
address: SocketAddrV4,
) -> anyhow::Result<()> {
@ -124,7 +124,7 @@ impl AccessControl {
}
pub async fn add_ipv6_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
address: SocketAddrV6,
) -> anyhow::Result<()> {
@ -139,7 +139,7 @@ impl AccessControl {
}
pub async fn remove_ipv4_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
address: SocketAddrV4,
) -> anyhow::Result<()> {
@ -154,7 +154,7 @@ impl AccessControl {
}
pub async fn remove_ipv6_list(
direction: Direction,
direction: FlowDirection,
list_type: ListType,
address: SocketAddrV6,
) -> anyhow::Result<()> {
@ -173,7 +173,7 @@ struct AccessMap<T> {
map: AyaHashMap<MapData, T, [Port; MAX_RULES_PORT]>,
}
impl<T: IpAddressType + Pod> AccessMap<T> {
impl<T: IntoNative + Pod> AccessMap<T> {
fn get_list(&self) -> StdHashMap<T::Native, Vec<Port>> {
self.map
.iter()

View File

@ -1,7 +1,7 @@
use crate::core::system::System;
use crate::model::direction::Direction;
use crate::model::direction::{Direction, FlowDirection};
use crate::model::flow_stats::FlowStats;
use crate::model::ip_address::SocketAddressType;
use crate::model::ip_address::IntoNative;
use crate::model::time_type::TimeType;
use crate::utils::log_entry::system::SystemEntry;
use aya::maps::{HashMap as AyaHashMap, MapData};
@ -18,38 +18,62 @@ static STATISTICS: OnceLock<RwLock<Statistics>> = OnceLock::new();
pub struct Statistics {
terminate: bool,
ipv4_maps: StdHashMap<(Direction, TimeType), FlowMap<EbpfAddrPortV4>>,
ipv6_maps: StdHashMap<(Direction, TimeType), FlowMap<EbpfAddrPortV6>>,
ipv4_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<EbpfAddrPortV4>>,
ipv6_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<EbpfAddrPortV6>>,
}
impl Statistics {
const INGRESS_MAPS: [((Direction, TimeType), (&'static str, &'static str)); 3] = [
const INGRESS_MAPS: [((Direction, FlowDirection, TimeType), (&'static str, &'static str)); 6] = [
(
(Direction::Source, TimeType::_1Min),
("IPV4_SRC_1MIN", "IPV6_SRC_1MIN"),
(Direction::Ingress, FlowDirection::Source, TimeType::_1Min),
("IPV4_INGRESS_SRC_1MIN", "IPV6_INGRESS_SRC_1MIN"),
),
(
(Direction::Source, TimeType::_10Min),
("IPV4_SRC_10MIN", "IPV6_SRC_10MIN"),
(Direction::Ingress, FlowDirection::Source, TimeType::_10Min),
("IPV4_INGRESS_SRC_10MIN", "IPV6_INGRESS_SRC_10MIN"),
),
(
(Direction::Source, TimeType::_1Hour),
("IPV4_SRC_1HOUR", "IPV6_SRC_1HOUR"),
(Direction::Ingress, FlowDirection::Source, TimeType::_1Hour),
("IPV4_INGRESS_SRC_1HOUR", "IPV6_INGRESS_SRC_1HOUR"),
),
(
(Direction::Ingress, FlowDirection::Destination, TimeType::_1Min),
("IPV4_INGRESS_DST_1MIN", "IPV6_INGRESS_DST_1MIN"),
),
(
(Direction::Ingress, FlowDirection::Destination, TimeType::_10Min),
("IPV4_INGRESS_DST_10MIN", "IPV6_INGRESS_DST_10MIN"),
),
(
(Direction::Ingress, FlowDirection::Destination, TimeType::_1Hour),
("IPV4_INGRESS_DST_1HOUR", "IPV6_INGRESS_DST_1HOUR"),
),
];
const EGRESS_MAPS: [((Direction, TimeType), (&'static str, &'static str)); 3] = [
const EGRESS_MAPS: [((Direction, FlowDirection, TimeType), (&'static str, &'static str)); 6] = [
(
(Direction::Destination, TimeType::_1Min),
("IPV4_DST_1MIN", "IPV6_DST_1MIN"),
(Direction::Egress, FlowDirection::Source, TimeType::_1Min),
("IPV4_EGRESS_SRC_1MIN", "IPV6_EGRESS_SRC_1MIN"),
),
(
(Direction::Destination, TimeType::_10Min),
("IPV4_DST_10MIN", "IPV6_DST_10MIN"),
(Direction::Egress, FlowDirection::Source, TimeType::_10Min),
("IPV4_EGRESS_SRC_10MIN", "IPV6_EGRESS_SRC_10MIN"),
),
(
(Direction::Destination, TimeType::_1Hour),
("IPV4_DST_1HOUR", "IPV6_DST_1HOUR"),
(Direction::Egress, FlowDirection::Source, TimeType::_1Hour),
("IPV4_EGRESS_SRC_1HOUR", "IPV6_EGRESS_SRC_1HOUR"),
),
(
(Direction::Egress, FlowDirection::Destination, TimeType::_1Min),
("IPV4_EGRESS_DST_1MIN", "IPV6_EGRESS_DST_1MIN"),
),
(
(Direction::Egress, FlowDirection::Destination, TimeType::_10Min),
("IPV4_EGRESS_DST_10MIN", "IPV6_EGRESS_DST_10MIN"),
),
(
(Direction::Egress, FlowDirection::Destination, TimeType::_1Hour),
("IPV4_EGRESS_DST_1HOUR", "IPV6_EGRESS_DST_1HOUR"),
),
];
@ -88,12 +112,12 @@ impl Statistics {
},
);
}
let monitor = Statistics {
let statistics = Statistics {
terminate: false,
ipv4_maps,
ipv6_maps,
};
STATISTICS.get_or_init(|| RwLock::new(monitor));
STATISTICS.get_or_init(|| RwLock::new(statistics));
info!("{}", SystemEntry::InitializeComplete);
Ok(())
}
@ -124,47 +148,49 @@ impl Statistics {
}
pub async fn terminate() {
let mut monitor = Statistics::instance_mut().await;
monitor.terminate = true;
let mut statistics = Statistics::instance_mut().await;
statistics.terminate = true;
}
pub async fn cleanup_expired_flows() {
let mut monitor = Statistics::instance_mut().await;
let mut statistics = Statistics::instance_mut().await;
let boot_time = System::boot_time().await;
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos() as u64;
monitor
statistics
.ipv4_maps
.iter_mut()
.for_each(|((_, time_type), map)| map.cleanup(boot_time, now, time_type.duration()));
monitor
.for_each(|((_, _, time_type), map)| map.cleanup(boot_time, now, time_type.duration()));
statistics
.ipv6_maps
.iter_mut()
.for_each(|((_, time_type), map)| map.cleanup(boot_time, now, time_type.duration()));
.for_each(|((_, _, time_type), map)| map.cleanup(boot_time, now, time_type.duration()));
}
pub async fn get_ipv4_flow_data(
direction: Direction,
flow_direction: FlowDirection,
time_type: TimeType,
) -> StdHashMap<SocketAddrV4, FlowStats> {
let monitor = Statistics::instance().await;
monitor
let statistics = Statistics::instance().await;
statistics
.ipv4_maps
.get(&(direction, time_type))
.get(&(direction, flow_direction, time_type))
.map(|map| map.get_map())
.unwrap()
}
pub async fn get_ipv6_flow_data(
direction: Direction,
flow_direction: FlowDirection,
time_type: TimeType,
) -> StdHashMap<SocketAddrV6, FlowStats> {
let monitor = Statistics::instance().await;
monitor
let statistics = Statistics::instance().await;
statistics
.ipv6_maps
.get(&(direction, time_type))
.get(&(direction, flow_direction, time_type))
.map(|map| map.get_map())
.unwrap()
}
@ -174,7 +200,7 @@ struct FlowMap<T> {
map: AyaHashMap<MapData, T, EbpfFlowStats>,
}
impl<T: SocketAddressType + Pod> FlowMap<T> {
impl<T: IntoNative + Pod> FlowMap<T> {
fn get_map(&self) -> StdHashMap<T::Native, FlowStats> {
self.map
.iter()

View File

@ -46,31 +46,9 @@ impl System {
let egress_interface = config.egress_ifindex;
let boot_time = SystemInfo::boot_time() * 1_000_000_000;
Self::set_memory_limit()?;
let mut ingress_ebpf = Ebpf::load(aya::include_bytes_aligned!(concat!(
env!("OUT_DIR"),
"/net-guardia-ingress"
)))?;
let mut egress_ebpf = Ebpf::load(aya::include_bytes_aligned!(concat!(
env!("OUT_DIR"),
"/net-guardia-egress"
)))?;
if let Err(e) = aya_log::EbpfLogger::init(&mut ingress_ebpf) {
error!("{}", e);
warn!("{}", EbpfEntry::LoggerInitializeFailed);
}
if let Err(e) = aya_log::EbpfLogger::init(&mut egress_ebpf) {
error!("{}", e);
warn!("{}", EbpfEntry::LoggerInitializeFailed);
}
let mut ingress_program_array = ProgramArray::try_from(ingress_ebpf.take_map("PROGRAM_ARRAY").unwrap())?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "access_control", 0)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "service", 1)?;
// Self::load_program(&mut ebpf, &mut ingress_program_array, "defence", 2)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "sampling", 3)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "statistics", 4)?;
let (mut ingress_ebpf, ingress_program_array) = System::get_ingress_ebpf()?;
let ingress_program: &mut Xdp = ingress_ebpf.program_mut("net_guardia").unwrap().try_into()?;
let mut egress_program_array = ProgramArray::try_from(egress_ebpf.take_map("PROGRAM_ARRAY").unwrap())?;
Self::load_program(&mut egress_ebpf, &mut egress_program_array, "statistics", 0)?;
let (mut egress_ebpf, egress_program_array) = System::get_egress_ebpf()?;
let egress_program: &mut Xdp = egress_ebpf.program_mut("net_guardia").unwrap().try_into()?;
ingress_program.load()?;
ingress_program
@ -92,6 +70,38 @@ impl System {
Ok(())
}
fn get_ingress_ebpf() -> anyhow::Result<(Ebpf, ProgramArray<MapData>)> {
let mut ingress_ebpf = Ebpf::load(aya::include_bytes_aligned!(concat!(
env!("OUT_DIR"),
"/net-guardia-ingress"
)))?;
if let Err(e) = aya_log::EbpfLogger::init(&mut ingress_ebpf) {
error!("{}", e);
warn!("{}", EbpfEntry::LoggerInitializeFailed);
}
let mut ingress_program_array = ProgramArray::try_from(ingress_ebpf.take_map("PROGRAM_ARRAY").unwrap())?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "access_control", 0)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "service", 1)?;
// Self::load_program(&mut ebpf, &mut ingress_program_array, "defence", 2)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "sampling", 3)?;
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "statistics", 4)?;
Ok((ingress_ebpf, ingress_program_array))
}
fn get_egress_ebpf() -> anyhow::Result<(Ebpf, ProgramArray<MapData>)> {
let mut egress_ebpf = Ebpf::load(aya::include_bytes_aligned!(concat!(
env!("OUT_DIR"),
"/net-guardia-egress"
)))?;
if let Err(e) = aya_log::EbpfLogger::init(&mut egress_ebpf) {
error!("{}", e);
warn!("{}", EbpfEntry::LoggerInitializeFailed);
}
let mut egress_program_array = ProgramArray::try_from(egress_ebpf.take_map("PROGRAM_ARRAY").unwrap())?;
Self::load_program(&mut egress_ebpf, &mut egress_program_array, "statistics", 0)?;
Ok((egress_ebpf, egress_program_array))
}
fn set_memory_limit() -> anyhow::Result<()> {
let rlim = libc::rlimit {
rlim_cur: libc::RLIM_INFINITY,

View File

@ -3,6 +3,13 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum Direction {
Ingress,
Egress,
}
#[derive(Serialize, Deserialize, Copy, Clone, Eq, PartialEq, Hash)]
#[serde(rename_all = "lowercase")]
pub enum FlowDirection {
Source,
Destination,
}

View File

@ -2,62 +2,39 @@ use net_guardia_common::model::ip_address::{IPv4, IPv6, EbpfAddrPortV4, EbpfAddr
use std::hash::Hash;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
pub trait IpAddressType: Copy {
pub trait IntoNative: Copy {
type Native: Eq + PartialEq + Hash;
fn into_native(self) -> Self::Native;
fn from_native(native: Self::Native) -> Self;
}
impl IpAddressType for IPv4 {
impl IntoNative for IPv4 {
type Native = Ipv4Addr;
fn into_native(self) -> Self::Native {
Ipv4Addr::from(self)
}
fn from_native(native: Self::Native) -> Self {
native.into()
}
}
impl IpAddressType for IPv6 {
impl IntoNative for IPv6 {
type Native = Ipv6Addr;
fn into_native(self) -> Self::Native {
Ipv6Addr::from(self)
}
fn from_native(native: Self::Native) -> Self {
native.into()
}
}
pub trait SocketAddressType: Copy {
type Native: Eq + PartialEq + Hash;
fn into_native(self) -> Self::Native;
fn from_native(native: Self::Native) -> Self;
}
impl SocketAddressType for EbpfAddrPortV4 {
impl IntoNative for EbpfAddrPortV4 {
type Native = SocketAddrV4;
fn into_native(self) -> Self::Native {
SocketAddrV4::new(Ipv4Addr::from(self[0]), self[1] as u16)
}
fn from_native(native: Self::Native) -> Self {
[(*native.ip()).into(), native.port() as u32]
}
}
impl SocketAddressType for EbpfAddrPortV6 {
impl IntoNative for EbpfAddrPortV6 {
type Native = SocketAddrV6;
fn into_native(self) -> Self::Native {
SocketAddrV6::new(Ipv6Addr::from(self[0]), self[1] as u16, 0, 0)
}
fn from_native(native: Self::Native) -> Self {
[(*native.ip()).into(), native.port() as u128]
}
}

View File

@ -1,5 +1,5 @@
use crate::core::control::access_control::AccessControl;
use crate::model::direction::Direction;
use crate::model::direction::FlowDirection;
use crate::model::list_type::ListType;
use actix_web::{delete, get, put, web, HttpResponse, Responder, Scope};
use std::net::{SocketAddrV4, SocketAddrV6};
@ -15,21 +15,21 @@ pub fn initialize() -> Scope {
}
#[get("/ipv4/{direction}/{list_type}")]
async fn get_ipv4_list(path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn get_ipv4_list(path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let (direction, list_type) = path.into_inner();
let list = AccessControl::get_ipv4_list(direction, list_type).await;
HttpResponse::Ok().json(list)
}
#[get("/ipv6/{direction}/{list_type}")]
async fn get_ipv6_list(path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn get_ipv6_list(path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let (direction, list_type) = path.into_inner();
let list = AccessControl::get_ipv6_list(direction, list_type).await;
HttpResponse::Ok().json(list)
}
#[put("/ipv4/{direction}/{list_type}")]
async fn add_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn add_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let address = address.into_inner();
let (direction, list_type) = path.into_inner();
match AccessControl::add_ipv4_list(direction, list_type, address).await {
@ -39,7 +39,7 @@ async fn add_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(Direct
}
#[put("/ipv6/{direction}/{list_type}")]
async fn add_ipv6_list(address: web::Json<SocketAddrV6>, path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn add_ipv6_list(address: web::Json<SocketAddrV6>, path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let address = address.into_inner();
let (direction, list_type) = path.into_inner();
match AccessControl::add_ipv6_list(direction, list_type, address).await {
@ -49,7 +49,7 @@ async fn add_ipv6_list(address: web::Json<SocketAddrV6>, path: web::Path<(Direct
}
#[delete("/ipv4/{direction}/{list_type}")]
async fn remove_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn remove_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let address = address.into_inner();
let (direction, list_type) = path.into_inner();
match AccessControl::remove_ipv4_list(direction, list_type, address).await {
@ -59,7 +59,7 @@ async fn remove_ipv4_list(address: web::Json<SocketAddrV4>, path: web::Path<(Dir
}
#[delete("/ipv6/{direction}/{list_type}")]
async fn remove_ipv6_list(address: web::Json<SocketAddrV6>, path: web::Path<(Direction, ListType)>) -> impl Responder {
async fn remove_ipv6_list(address: web::Json<SocketAddrV6>, path: web::Path<(FlowDirection, ListType)>) -> impl Responder {
let address = address.into_inner();
let (direction, list_type) = path.into_inner();
match AccessControl::remove_ipv6_list(direction, list_type, address).await {

View File

@ -2,7 +2,7 @@ use crate::core::statistics::Statistics;
use crate::web::utils::flow_websocket::{IPv4FlowWebSocket, IPv6FlowWebSocket};
use actix_web::{get, web, Error, HttpRequest, HttpResponse, Responder, Scope};
use actix_web_actors::ws::start;
use crate::model::direction::Direction;
use crate::model::direction::{Direction, FlowDirection};
use crate::model::time_type::TimeType;
pub fn initialize() -> Scope {
@ -13,45 +13,46 @@ pub fn initialize() -> Scope {
.service(websocket_ipv6)
}
#[get("/get/ipv4/{direction}/{time_type}")]
async fn get_ipv4_flow(path: web::Path<(Direction, TimeType)>) -> impl Responder {
let (direction, time_type) = path.into_inner();
let flow_data = Statistics::get_ipv4_flow_data(direction, time_type).await;
#[get("/get/ipv4/{direction}/{flow_direction}/{time_type}")]
async fn get_ipv4_flow(path: web::Path<(Direction, FlowDirection, TimeType)>) -> impl Responder {
let (direction, flow_direction, time_type) = path.into_inner();
let flow_data = Statistics::get_ipv4_flow_data(direction, flow_direction, time_type).await;
HttpResponse::Ok().json(web::Json(flow_data))
}
#[get("/get/ipv6/{direction}/{time_type}")]
async fn get_ipv6_flow(path: web::Path<(Direction, TimeType)>) -> impl Responder {
let (direction, time_type) = path.into_inner();
let flow_data = Statistics::get_ipv6_flow_data(direction, time_type).await;
#[get("/get/ipv6/{direction}/{flow_direction}/{time_type}")]
async fn get_ipv6_flow(path: web::Path<(Direction, FlowDirection, TimeType)>) -> impl Responder {
let (direction, flow_direction, time_type) = path.into_inner();
let flow_data = Statistics::get_ipv6_flow_data(direction, flow_direction, time_type).await;
HttpResponse::Ok().json(web::Json(flow_data))
}
#[get("/websocket/ipv4/{direction}/{time_type}")]
#[get("/websocket/ipv4/{direction}/{flow_direction}/{time_type}")]
async fn websocket_ipv4(
req: HttpRequest,
stream: web::Payload,
path: web::Path<(Direction, TimeType)>,
path: web::Path<(Direction, FlowDirection, TimeType)>,
) -> Result<HttpResponse, Error> {
let (direction, time_type) = path.into_inner();
let (direction, flow_direction, time_type) = path.into_inner();
let websocket = IPv4FlowWebSocket {
direction,
flow_direction,
time_type,
interval: None,
};
start(websocket, &req, stream)
}
#[get("/websocket/ipv6/{direction}/{time_type}")]
#[get("/websocket/ipv6/{direction}/{flow_direction}/{time_type}")]
async fn websocket_ipv6(
req: HttpRequest,
stream: web::Payload,
path: web::Path<(Direction, TimeType)>,
path: web::Path<(Direction, FlowDirection, TimeType)>,
) -> Result<HttpResponse, Error> {
let (direction, time_type) = path.into_inner();
let (direction, flow_direction, time_type) = path.into_inner();
let websocket = IPv6FlowWebSocket {
direction,
flow_direction,
time_type,
interval: None,
};

View File

@ -1,13 +1,14 @@
use crate::core::config_manager::ConfigManager;
use crate::core::statistics::Statistics;
use crate::model::direction::{Direction, FlowDirection};
use crate::model::time_type::TimeType;
use actix::prelude::*;
use actix_web_actors::ws;
use std::time::Duration;
use crate::model::direction::Direction;
use crate::model::time_type::TimeType;
pub struct IPv4FlowWebSocket {
pub direction: Direction,
pub flow_direction: FlowDirection,
pub time_type: TimeType,
pub interval: Option<SpawnHandle>,
}
@ -20,8 +21,11 @@ impl Actor for IPv4FlowWebSocket {
let refresh_interval = Duration::from_secs(config.refresh_interval);
let interval = ctx.run_interval(refresh_interval, |actor, ctx| {
let direction = actor.direction.clone();
let flow_direction = actor.flow_direction.clone();
let time_type = actor.time_type.clone();
let future = async move { Statistics::get_ipv4_flow_data(direction, time_type).await };
let future = async move {
Statistics::get_ipv4_flow_data(direction, flow_direction, time_type).await
};
ctx.wait(future.into_actor(actor).map(|flow_data, _, ctx| {
if let Ok(json) = serde_json::to_string(&flow_data) {
ctx.text(json);
@ -54,6 +58,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for IPv4FlowWebSocket
pub struct IPv6FlowWebSocket {
pub direction: Direction,
pub flow_direction: FlowDirection,
pub time_type: TimeType,
pub interval: Option<SpawnHandle>,
}
@ -66,8 +71,11 @@ impl Actor for IPv6FlowWebSocket {
let refresh_interval = Duration::from_secs(config.refresh_interval);
let interval = ctx.run_interval(refresh_interval, |actor, ctx| {
let direction = actor.direction.clone();
let flow_direction = actor.flow_direction.clone();
let time_type = actor.time_type.clone();
let future = async move { Statistics::get_ipv6_flow_data(direction, time_type).await };
let future = async move {
Statistics::get_ipv6_flow_data(direction, flow_direction, time_type).await
};
ctx.wait(future.into_actor(actor).map(|flow_data, _, ctx| {
if let Ok(json) = serde_json::to_string(&flow_data) {
ctx.text(json);