mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
refactor: Remove Ebpf* type, replace with normal struct with Pod trait (#2)
This commit is contained in:
parent
f021c8ebe2
commit
d01045e74a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1193,6 +1193,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"aya",
|
||||
"network-types",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -20,6 +20,8 @@ libc = { version = "0.2.159", default-features = false }
|
||||
log = { version = "0.4.22", default-features = false }
|
||||
tokio = { version = "1.40.0", default-features = false }
|
||||
which = { version = "7.0.0", default-features = false }
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
network-types = "0.0.7"
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
@ -5,11 +5,12 @@ edition = "2024"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
user = ["aya"]
|
||||
user = ["aya", "serde"]
|
||||
|
||||
[dependencies]
|
||||
aya = { workspace = true, optional = true }
|
||||
network-types = "0.0.7"
|
||||
serde = { workspace = true, optional = true }
|
||||
network-types = { workspace = true }
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#![no_std]
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
extern crate std;
|
||||
|
||||
pub mod model;
|
||||
|
||||
/// Maximum number of statistics entries that can be stored
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
use network_types::eth::EtherType;
|
||||
use crate::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
|
||||
use network_types::ip::IpProto;
|
||||
|
||||
pub struct Event {
|
||||
@ -10,7 +10,7 @@ pub struct Event {
|
||||
pub source_port: u16,
|
||||
pub destination_port: u16,
|
||||
pub len: u32,
|
||||
pub timestamp: u64
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
@ -74,18 +74,24 @@ pub struct IPv4Event {
|
||||
pub source_port: u16,
|
||||
pub destination_port: u16,
|
||||
pub len: u32,
|
||||
pub timestamp: u64
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl IPv4Event {
|
||||
#[inline(always)]
|
||||
pub fn get_source(&self) -> EbpfAddrPortV4 {
|
||||
[self.source_ip, self.source_port as u32]
|
||||
pub fn get_source(&self) -> AddrPortV4 {
|
||||
AddrPortV4 {
|
||||
ip: self.source_ip,
|
||||
port: self.source_port,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_destination(&self) -> EbpfAddrPortV4 {
|
||||
[self.destination_ip, self.destination_port as u32]
|
||||
pub fn get_destination(&self) -> AddrPortV4 {
|
||||
AddrPortV4 {
|
||||
ip: self.destination_ip,
|
||||
port: self.destination_port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,17 +102,23 @@ pub struct IPv6Event {
|
||||
pub source_port: u16,
|
||||
pub destination_port: u16,
|
||||
pub len: u32,
|
||||
pub timestamp: u64
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl IPv6Event {
|
||||
#[inline(always)]
|
||||
pub fn get_source(&self) -> EbpfAddrPortV6 {
|
||||
[self.source_ip, self.source_port as u128]
|
||||
pub fn get_source(&self) -> AddrPortV6 {
|
||||
AddrPortV6 {
|
||||
ip: self.source_ip,
|
||||
port: self.source_port,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_destination(&self) -> EbpfAddrPortV6 {
|
||||
[self.destination_ip, self.destination_port as u128]
|
||||
pub fn get_destination(&self) -> AddrPortV6 {
|
||||
AddrPortV6 {
|
||||
ip: self.destination_ip,
|
||||
port: self.destination_port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,37 +1,26 @@
|
||||
/// Network flow statistics tracking bytes, packets count, and timing
|
||||
///
|
||||
/// # Layout
|
||||
/// ```text
|
||||
/// [0]: Total bytes count (u64)
|
||||
/// [1]: Total packets count (u64)
|
||||
/// [2]: Last seen timestamp (u64) in nanoseconds from system boot
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// // Create new flow status
|
||||
/// let now = bpf_ktime_get_ns();
|
||||
/// let status: FlowStats = [
|
||||
/// 1500, // 1500 bytes
|
||||
/// 1, // 1 packet
|
||||
/// now, // Current timestamp
|
||||
/// ];
|
||||
///
|
||||
/// // Update existing flow
|
||||
/// status[0] += packet_size; // Add bytes
|
||||
/// status[1] += 1; // Increment packet count
|
||||
/// status[2] = new_timestamp; // Update last seen
|
||||
/// ```
|
||||
///
|
||||
/// # Notes
|
||||
/// - All counters are monotonically increasing
|
||||
/// - Timestamp uses kernel time (bpf_ktime_get_ns)
|
||||
/// - Counters may wrap around on very high traffic flows
|
||||
///
|
||||
/// # Memory Layout
|
||||
/// ```text
|
||||
/// [0]: [------------------- Bytes (64 bits) ------------------]
|
||||
/// [1]: [------------------ Packets (64 bits) -----------------]
|
||||
/// [2]: [----------------- Timestamp (64 bits) ----------------]
|
||||
/// ```
|
||||
pub type EbpfFlowStats = [u64; 3];
|
||||
#[cfg(feature = "user")]
|
||||
use aya::Pod;
|
||||
#[cfg(feature = "user")]
|
||||
use serde::Serialize;
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Clone, Copy)]
|
||||
#[cfg_attr(feature = "user", derive(Serialize, Debug))]
|
||||
pub struct FlowStats {
|
||||
pub bytes: u64,
|
||||
pub packets: u64,
|
||||
pub last_seen: u64,
|
||||
}
|
||||
|
||||
impl FlowStats {
|
||||
pub fn new(bytes: u64, packets: u64, last_seen: u64) -> Self {
|
||||
Self {
|
||||
bytes,
|
||||
packets,
|
||||
last_seen,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
unsafe impl Pod for FlowStats {}
|
||||
|
||||
@ -1,22 +1,55 @@
|
||||
/// HTTP methods bitmap type for eBPF programs.
|
||||
///
|
||||
/// Each bit represents whether a specific HTTP method is allowed:
|
||||
/// - Bit 0: GET (0b0000_0000_0000_0001)
|
||||
/// - Bit 1: POST (0b0000_0000_0000_0010)
|
||||
/// - Bit 2: PUT (0b0000_0000_0000_0100)
|
||||
/// - Bit 3: DELETE (0b0000_0000_0000_1000)
|
||||
/// - Bit 4: HEAD (0b0000_0000_0001_0000)
|
||||
/// - Bit 5: OPTIONS (0b0000_0000_0010_0000)
|
||||
/// - Bit 6: PATCH (0b0000_0000_0100_0000)
|
||||
/// - Bit 7: TRACE (0b0000_0000_1000_0000)
|
||||
/// - Bit 8: CONNECT (0b0000_0001_0000_0000)
|
||||
///
|
||||
/// # Examples
|
||||
/// ```ignore
|
||||
/// // Allow GET and POST
|
||||
/// let methods: EbpfHttpMethod = 0b0000_0000_0000_0011;
|
||||
///
|
||||
/// // Allow all common methods (GET, POST, PUT, DELETE, PATCH)
|
||||
/// let methods: EbpfHttpMethod = 0b0000_0000_0100_1111;
|
||||
/// ```
|
||||
pub type EbpfHttpMethod = u16;
|
||||
#[cfg(feature = "user")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(all(feature = "user"))]
|
||||
use std::vec::Vec;
|
||||
|
||||
pub type HttpMethodBitmap = u16;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "user", derive(Serialize, Deserialize, Debug, Eq, PartialEq))]
|
||||
pub enum HttpMethod {
|
||||
GET = 0b0000_0000_0000_0001,
|
||||
POST = 0b0000_0000_0000_0010,
|
||||
PUT = 0b0000_0000_0000_0100,
|
||||
DELETE = 0b0000_0000_0000_1000,
|
||||
HEAD = 0b0000_0000_0001_0000,
|
||||
OPTIONS = 0b0000_0000_0010_0000,
|
||||
PATCH = 0b0000_0000_0100_0000,
|
||||
TRACE = 0b0000_0000_1000_0000,
|
||||
CONNECT = 0b0000_0001_0000_0000,
|
||||
}
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
impl HttpMethod {
|
||||
pub fn convert_from_bitmap(http_method_bitmap: HttpMethodBitmap) -> Vec<HttpMethod> {
|
||||
let value = http_method_bitmap as u16;
|
||||
let mut http_methods = Vec::new();
|
||||
|
||||
let all_methods = [
|
||||
HttpMethod::GET,
|
||||
HttpMethod::POST,
|
||||
HttpMethod::PUT,
|
||||
HttpMethod::DELETE,
|
||||
HttpMethod::HEAD,
|
||||
HttpMethod::OPTIONS,
|
||||
HttpMethod::PATCH,
|
||||
HttpMethod::TRACE,
|
||||
HttpMethod::CONNECT,
|
||||
];
|
||||
|
||||
for method in all_methods {
|
||||
if value & (method as u16) != 0 {
|
||||
http_methods.push(method);
|
||||
}
|
||||
}
|
||||
http_methods
|
||||
}
|
||||
|
||||
pub fn convert_to_bitmap(http_methods: Vec<HttpMethod>) -> HttpMethodBitmap {
|
||||
let mut ebpf_http_method = 0_u16;
|
||||
for http_method in http_methods {
|
||||
ebpf_http_method |= http_method as u16;
|
||||
}
|
||||
ebpf_http_method
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,98 +1,44 @@
|
||||
/// IPv4 address stored as a u32 in network byte order (big-endian)
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// let ip_bytes = [192, 168, 1, 1];
|
||||
/// let ip: IPv4 = u32::from_be_bytes(ip_bytes);
|
||||
/// ```
|
||||
#[cfg(feature = "user")]
|
||||
use aya::Pod;
|
||||
|
||||
pub type IPv4 = u32;
|
||||
|
||||
/// IPv6 address stored as a u128 in network byte order (big-endian)
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// let ip_bytes = [
|
||||
/// 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
/// ];
|
||||
/// let ip: IPv6 = u128::from_be_bytes(ip_bytes);
|
||||
/// ```
|
||||
pub type IPv6 = u128;
|
||||
|
||||
/// Network port number stored as a u16
|
||||
///
|
||||
/// Valid values range from 0 to 65535 (inclusive).
|
||||
/// Common well-known ports are 0-1023, registered ports are 1024-49151,
|
||||
/// and dynamic/private ports are 49152-65535.
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// let http_port: Port = 80;
|
||||
/// let https_port: Port = 443;
|
||||
/// let dynamic_port: Port = 49152;
|
||||
/// ```
|
||||
pub type Port = u16;
|
||||
|
||||
/// Network endpoint identifier combining IP address and port number
|
||||
///
|
||||
/// # Layout
|
||||
/// ```text
|
||||
/// [0]: IPv4 address (u32) in network byte order
|
||||
/// [1]: Port number (u16) in network byte order, stored in lower 16 bits
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// // Create key for 192.168.1.1:8080
|
||||
/// let ip_bytes = [192, 168, 1, 1];
|
||||
/// let ip = u32::from_be_bytes(ip_bytes);
|
||||
/// let port = 8080_u16;
|
||||
/// let key: EbpfAddrPortV4 = [ip, port as u32];
|
||||
/// ```
|
||||
///
|
||||
/// # Note
|
||||
/// - IP address should be in network byte order (big-endian)
|
||||
/// - Port number is stored in the lower 16 bits of the second u32
|
||||
/// - Upper 16 bits of second u32 are unused and should be zero
|
||||
///
|
||||
/// # Memory Layout
|
||||
/// ```text
|
||||
/// [0]: [------------ IP Address (32 bits) ------------]
|
||||
/// [1]: [-- Unused (16 bits) --][--- Port (16 bits) ---]
|
||||
/// ```
|
||||
pub type EbpfAddrPortV4 = [u32; 2];
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AddrPortV4 {
|
||||
pub ip: IPv4,
|
||||
pub port: Port,
|
||||
}
|
||||
|
||||
/// Network endpoint identifier combining IPv6 address and port number
|
||||
///
|
||||
/// A compact representation of an IPv6 endpoint using two u128 values,
|
||||
/// storing the IP address and port number in network byte order.
|
||||
///
|
||||
/// # Layout
|
||||
/// ```text
|
||||
/// [0]: IPv6 address (u128) in network byte order
|
||||
/// [1]: Port number (u16) in network byte order, stored in lower 16 bits
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
/// ```ignore
|
||||
/// // Create key for 2001:db8::1:8080
|
||||
/// let ip_bytes = [
|
||||
/// 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
/// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
|
||||
/// ];
|
||||
/// let ip = u128::from_be_bytes(ip_bytes);
|
||||
/// let port = 8080_u16;
|
||||
/// let key: EbpfAddrPortV6 = [ip, port as u128];
|
||||
/// ```
|
||||
///
|
||||
/// # Notes
|
||||
/// - IP address should be in network byte order (big-endian)
|
||||
/// - Port number is stored in the lower 16 bits of the second u128
|
||||
/// - Upper 112 bits of second u128 are unused and should be zero
|
||||
///
|
||||
/// # Memory Layout
|
||||
/// ```text
|
||||
/// [0]: [---------------------- IPv6 Address (128 bits) ----------------------]
|
||||
/// [1]: [-------------- Unused (112 bits) --------------][-- Port (16 bits) --]
|
||||
/// ```
|
||||
pub type EbpfAddrPortV6 = [u128; 2];
|
||||
impl AddrPortV4 {
|
||||
pub fn new(ip: IPv4, port: Port) -> Self {
|
||||
AddrPortV4 {
|
||||
ip,
|
||||
port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
unsafe impl Pod for AddrPortV4 {}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AddrPortV6 {
|
||||
pub ip: IPv6,
|
||||
pub port: Port,
|
||||
}
|
||||
|
||||
impl AddrPortV6 {
|
||||
pub fn new(ip: IPv6, port: Port) -> Self {
|
||||
AddrPortV6 {
|
||||
ip,
|
||||
port,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "user")]
|
||||
unsafe impl Pod for AddrPortV6 {}
|
||||
|
||||
@ -2,5 +2,6 @@ pub mod event;
|
||||
pub mod flow_stats;
|
||||
pub mod http_method;
|
||||
pub mod ip_address;
|
||||
pub mod packet;
|
||||
pub mod placeholder;
|
||||
pub mod pseudo_header;
|
||||
|
||||
4
net-guardia-common/src/model/packet.rs
Normal file
4
net-guardia-common/src/model/packet.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[repr(C)]
|
||||
struct Ipv4Packet {
|
||||
|
||||
}
|
||||
@ -8,7 +8,7 @@ net-guardia-common = { path = "../net-guardia-common" }
|
||||
|
||||
aya-ebpf = { workspace = true }
|
||||
aya-log-ebpf = { workspace = true }
|
||||
network-types = "0.0.7"
|
||||
network-types = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
which = { workspace = true }
|
||||
|
||||
@ -2,89 +2,93 @@ use aya_ebpf::helpers::bpf_ktime_get_ns;
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::LruHashMap;
|
||||
use net_guardia_common::model::event::{IPv4Event, IPv6Event};
|
||||
use net_guardia_common::model::flow_stats::EbpfFlowStats;
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
|
||||
use net_guardia_common::model::flow_stats::FlowStats;
|
||||
use net_guardia_common::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
use net_guardia_common::MAX_STATS;
|
||||
|
||||
#[map]
|
||||
static IPV4_EGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_1MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_EGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_10MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_EGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_1HOUR: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_1MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_10MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_1HOUR: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_EGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_1MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_EGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_10MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_EGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_1HOUR: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_1MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_10MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_EGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_1HOUR: LruHashMap<AddrPortV6, FlowStats> =
|
||||
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];
|
||||
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);
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipv6_update_stats(event: &IPv6Event) {
|
||||
unsafe {
|
||||
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_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);
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn ipv4_update_flow_stats(
|
||||
map: &LruHashMap<EbpfAddrPortV4, EbpfFlowStats>,
|
||||
key: &EbpfAddrPortV4,
|
||||
map: &LruHashMap<AddrPortV4, FlowStats>,
|
||||
key: &AddrPortV4,
|
||||
event: &IPv4Event,
|
||||
now: u64,
|
||||
) {
|
||||
unsafe {
|
||||
if let Some(status) = map.get_ptr_mut(key) {
|
||||
(*status)[0] += event.len as u64;
|
||||
(*status)[1] += 1;
|
||||
(*status)[2] = now;
|
||||
(*status).bytes += event.len as u64;
|
||||
(*status).packets += 1;
|
||||
(*status).last_seen = now;
|
||||
} else {
|
||||
let new_stats = [event.len as u64, 1, now];
|
||||
let new_stats = FlowStats {
|
||||
bytes: event.len as u64,
|
||||
packets: 1,
|
||||
last_seen: now
|
||||
};
|
||||
let _ = map.insert(key, &new_stats, 0);
|
||||
}
|
||||
}
|
||||
@ -92,18 +96,22 @@ unsafe fn ipv4_update_flow_stats(
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn ipv6_update_flow_status(
|
||||
map: &LruHashMap<EbpfAddrPortV6, EbpfFlowStats>,
|
||||
key: &EbpfAddrPortV6,
|
||||
map: &LruHashMap<AddrPortV6, FlowStats>,
|
||||
key: &AddrPortV6,
|
||||
event: &IPv6Event,
|
||||
now: u64,
|
||||
) {
|
||||
unsafe {
|
||||
if let Some(status) = map.get_ptr_mut(key) {
|
||||
(*status)[0] += event.len as u64;
|
||||
(*status)[1] += 1;
|
||||
(*status)[2] = now;
|
||||
(*status).bytes += event.len as u64;
|
||||
(*status).packets += 1;
|
||||
(*status).last_seen = now;
|
||||
} else {
|
||||
let new_stats = [event.len as u64, 1, now];
|
||||
let new_stats = FlowStats {
|
||||
bytes: event.len as u64,
|
||||
packets: 1,
|
||||
last_seen: now
|
||||
};
|
||||
let _ = map.insert(key, &new_stats, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ pub fn parse_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
match eth.ether_type {
|
||||
EtherType::Ipv4 => parse_ipv4_packet(start, end),
|
||||
EtherType::Ipv6 => parse_ipv6_packet(start, end),
|
||||
_ => Err(())
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,24 +83,22 @@ pub fn parse_ipv6_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
|
||||
#[inline(always)]
|
||||
fn parse_tcp_port(start: usize, end: usize, offset: usize) -> Result<(u16, u16), ()> {
|
||||
let tcp: *const TcpHdr = (start + offset) as *const TcpHdr;
|
||||
if start + offset + size_of::<TcpHdr>() > end {
|
||||
return Err(());
|
||||
unsafe {
|
||||
let tcp: *const TcpHdr = (start + offset) as *const TcpHdr;
|
||||
if start + offset + size_of::<TcpHdr>() > end {
|
||||
return Err(());
|
||||
}
|
||||
Ok(((*tcp).source, (*tcp).dest))
|
||||
}
|
||||
Ok((
|
||||
u16::from_be(unsafe { (*tcp).source }),
|
||||
u16::from_be(unsafe { (*tcp).dest }),
|
||||
))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn parse_udp_port(start: usize, end: usize, offset: usize) -> Result<(u16, u16), ()> {
|
||||
let udp: *const UdpHdr = (start + offset) as *const UdpHdr;
|
||||
if start + offset + size_of::<UdpHdr>() > end {
|
||||
return Err(());
|
||||
unsafe {
|
||||
let udp: *const UdpHdr = (start + offset) as *const UdpHdr;
|
||||
if start + offset + size_of::<UdpHdr>() > end {
|
||||
return Err(());
|
||||
}
|
||||
Ok(((*udp).source, (*udp).dest))
|
||||
}
|
||||
Ok((
|
||||
u16::from_be(unsafe { (*udp).source }),
|
||||
u16::from_be(unsafe { (*udp).dest }),
|
||||
))
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ net-guardia-common = { path = "../net-guardia-common" }
|
||||
|
||||
aya-ebpf = { workspace = true }
|
||||
aya-log-ebpf = { workspace = true }
|
||||
network-types = "0.0.7"
|
||||
network-types = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
which = { workspace = true }
|
||||
|
||||
@ -1,169 +0,0 @@
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::{HashMap, LruHashMap};
|
||||
use net_guardia_common::model::event::{IPv4Event, IPv6Event};
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6, IPv4, IPv6};
|
||||
use net_guardia_common::model::placeholder::PlaceHolder;
|
||||
use net_guardia_common::{MAX_PORT_ACCESS, MAX_RULES};
|
||||
|
||||
const PORT_EXPIRE_TIME: u64 = 60_000_000_000;
|
||||
|
||||
#[map]
|
||||
static IPV4_ACTIVE_PORTS: LruHashMap<IPv4, [u16; MAX_PORT_ACCESS]> = LruHashMap::with_max_entries(10000, 0);
|
||||
#[map]
|
||||
static IPV4_PORT_TIMESTAMPS: LruHashMap<EbpfAddrPortV4, u64> = LruHashMap::with_max_entries(10000, 0);
|
||||
#[map]
|
||||
static IPV4_SCANNER_LIST: HashMap<IPv4, PlaceHolder> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
static IPV6_ACTIVE_PORTS: LruHashMap<IPv6, [u16; MAX_PORT_ACCESS]> = LruHashMap::with_max_entries(10000, 0);
|
||||
#[map]
|
||||
static IPV6_PORT_TIMESTAMPS: LruHashMap<EbpfAddrPortV6, u64> = LruHashMap::with_max_entries(10000, 0);
|
||||
#[map]
|
||||
static IPV6_SCANNER_LIST: HashMap<IPv6, PlaceHolder> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
|
||||
pub fn ipv4_is_attack(event: &IPv4Event) -> bool {
|
||||
unsafe {
|
||||
let ip = event.source_ip;
|
||||
let port = event.source_port;
|
||||
let current_time = event.timestamp;
|
||||
|
||||
if IPV4_SCANNER_LIST.get(&ip).is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let port_key = [ip, port as u32];
|
||||
let expire_time = current_time - PORT_EXPIRE_TIME;
|
||||
|
||||
if let Some(ports) = IPV4_ACTIVE_PORTS.get_ptr_mut(&ip) {
|
||||
let mut active_count = 1;
|
||||
let mut found_port = false;
|
||||
let mut empty_index = MAX_PORT_ACCESS;
|
||||
let mut expired_index = MAX_PORT_ACCESS;
|
||||
|
||||
for i in 0..MAX_PORT_ACCESS {
|
||||
let stored_port = (*ports)[i];
|
||||
if stored_port == port {
|
||||
found_port = true;
|
||||
let _ = IPV4_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
} else if stored_port == 0 {
|
||||
empty_index = i;
|
||||
} else if stored_port != 0 {
|
||||
let stored_key = [ip, stored_port as u32];
|
||||
if let Some(×tamp) = IPV4_PORT_TIMESTAMPS.get(&stored_key) {
|
||||
if timestamp > expire_time {
|
||||
active_count += 1;
|
||||
} else {
|
||||
(*ports)[i] = 0;
|
||||
let _ = IPV4_PORT_TIMESTAMPS.remove(&stored_key);
|
||||
expired_index = i;
|
||||
}
|
||||
} else {
|
||||
(*ports)[i] = 0;
|
||||
let _ = IPV4_PORT_TIMESTAMPS.remove(&stored_key);
|
||||
expired_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found_port {
|
||||
let insert_index = if empty_index != MAX_PORT_ACCESS {
|
||||
empty_index
|
||||
} else if expired_index != MAX_PORT_ACCESS {
|
||||
expired_index
|
||||
} else {
|
||||
let _ = IPV4_SCANNER_LIST.insert(&ip, &0_u8, 0);
|
||||
return true;
|
||||
};
|
||||
|
||||
(*ports)[insert_index] = port;
|
||||
let _ = IPV4_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
active_count += 1;
|
||||
}
|
||||
|
||||
if active_count == MAX_PORT_ACCESS {
|
||||
let _ = IPV4_SCANNER_LIST.insert(&ip, &0_u8, 0);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
let mut new_ports = [0u16; MAX_PORT_ACCESS];
|
||||
new_ports[0] = port;
|
||||
let _ = IPV4_ACTIVE_PORTS.insert(&ip, &new_ports, 0);
|
||||
let _ = IPV4_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ipv6_is_attack(event: &IPv6Event) -> bool {
|
||||
unsafe {
|
||||
let ip = event.source_ip;
|
||||
let port = event.source_port;
|
||||
let current_time = event.timestamp;
|
||||
|
||||
if IPV6_SCANNER_LIST.get(&ip).is_some() {
|
||||
return true;
|
||||
}
|
||||
|
||||
let port_key = [ip, port as u128];
|
||||
let expire_time = current_time - PORT_EXPIRE_TIME;
|
||||
|
||||
if let Some(ports) = IPV6_ACTIVE_PORTS.get_ptr_mut(&ip) {
|
||||
let mut active_count = 1;
|
||||
let mut found_port = false;
|
||||
let mut empty_index = MAX_PORT_ACCESS;
|
||||
let mut expired_index = MAX_PORT_ACCESS;
|
||||
|
||||
for i in 0..MAX_PORT_ACCESS {
|
||||
let stored_port = (*ports)[i];
|
||||
if stored_port == port {
|
||||
found_port = true;
|
||||
let _ = IPV6_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
} else if stored_port == 0 {
|
||||
empty_index = i;
|
||||
} else if stored_port != 0 {
|
||||
let stored_key = [ip, stored_port as u128];
|
||||
if let Some(×tamp) = IPV6_PORT_TIMESTAMPS.get(&stored_key) {
|
||||
if timestamp > expire_time {
|
||||
active_count += 1;
|
||||
} else {
|
||||
(*ports)[i] = 0;
|
||||
let _ = IPV6_PORT_TIMESTAMPS.remove(&stored_key);
|
||||
expired_index = i;
|
||||
}
|
||||
} else {
|
||||
(*ports)[i] = 0;
|
||||
let _ = IPV6_PORT_TIMESTAMPS.remove(&stored_key);
|
||||
expired_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found_port {
|
||||
let insert_index = if empty_index != MAX_PORT_ACCESS {
|
||||
empty_index
|
||||
} else if expired_index != MAX_PORT_ACCESS {
|
||||
expired_index
|
||||
} else {
|
||||
let _ = IPV6_SCANNER_LIST.insert(&ip, &0_u8, 0);
|
||||
return true;
|
||||
};
|
||||
|
||||
(*ports)[insert_index] = port;
|
||||
let _ = IPV6_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
active_count += 1;
|
||||
}
|
||||
|
||||
if active_count == MAX_PORT_ACCESS {
|
||||
let _ = IPV6_SCANNER_LIST.insert(&ip, &0_u8, 0);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
let mut new_ports = [0u16; MAX_PORT_ACCESS];
|
||||
new_ports[0] = port;
|
||||
let _ = IPV6_ACTIVE_PORTS.insert(&ip, &new_ports, 0);
|
||||
let _ = IPV6_PORT_TIMESTAMPS.insert(&port_key, ¤t_time, 0);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
pub mod access_control;
|
||||
pub mod defence;
|
||||
pub mod sampling;
|
||||
pub mod service;
|
||||
pub mod statistics;
|
||||
pub mod transmission;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::{Array, HashMap};
|
||||
use net_guardia_common::model::event::{IPv4Event, IPv6Event};
|
||||
use net_guardia_common::model::http_method::EbpfHttpMethod;
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6, IPv4, IPv6};
|
||||
use net_guardia_common::model::http_method::HttpMethodBitmap;
|
||||
use net_guardia_common::model::ip_address::*;
|
||||
use net_guardia_common::model::placeholder::PlaceHolder;
|
||||
use net_guardia_common::MAX_RULES;
|
||||
use network_types::eth::EthHdr;
|
||||
@ -10,19 +10,15 @@ use network_types::ip::{IpProto, Ipv4Hdr, Ipv6Hdr};
|
||||
use network_types::tcp::TcpHdr;
|
||||
|
||||
#[map]
|
||||
static IPV4_HTTP_SERVICE: HashMap<EbpfAddrPortV4, EbpfHttpMethod> =
|
||||
HashMap::with_max_entries(MAX_RULES, 0);
|
||||
static IPV4_HTTP_SERVICE: HashMap<AddrPortV4, HttpMethodBitmap> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
static IPV6_HTTP_SERVICE: HashMap<EbpfAddrPortV6, EbpfHttpMethod> =
|
||||
HashMap::with_max_entries(MAX_RULES, 0);
|
||||
static IPV6_HTTP_SERVICE: HashMap<AddrPortV6, HttpMethodBitmap> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
static SSH_WHITE_LIST_ENABLE: Array<PlaceHolder> = Array::with_max_entries(1, 0);
|
||||
#[map]
|
||||
static IPV4_SSH_SERVICE: HashMap<EbpfAddrPortV4, PlaceHolder> =
|
||||
HashMap::with_max_entries(MAX_RULES, 0);
|
||||
static IPV4_SSH_SERVICE: HashMap<AddrPortV4, PlaceHolder> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
static IPV6_SSH_SERVICE: HashMap<EbpfAddrPortV6, PlaceHolder> =
|
||||
HashMap::with_max_entries(MAX_RULES, 0);
|
||||
static IPV6_SSH_SERVICE: HashMap<AddrPortV6, PlaceHolder> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
static IPV4_SSH_WHITE_LIST: HashMap<IPv4, PlaceHolder> = HashMap::with_max_entries(MAX_RULES, 0);
|
||||
#[map]
|
||||
@ -53,7 +49,7 @@ fn ipv4_http_service_violation(
|
||||
start: usize,
|
||||
end: usize,
|
||||
protocol: &IpProto,
|
||||
destination: &EbpfAddrPortV4,
|
||||
destination: &AddrPortV4,
|
||||
) -> bool {
|
||||
match IPV4_HTTP_SERVICE.get_ptr_mut(destination) {
|
||||
Some(allow_method) => {
|
||||
@ -87,7 +83,7 @@ fn ipv6_http_service_violation(
|
||||
start: usize,
|
||||
end: usize,
|
||||
protocol: &IpProto,
|
||||
destination: &EbpfAddrPortV6,
|
||||
destination: &AddrPortV6,
|
||||
) -> bool {
|
||||
match IPV6_HTTP_SERVICE.get_ptr_mut(destination) {
|
||||
Some(allow_method) => {
|
||||
@ -117,7 +113,7 @@ fn ipv6_http_service_violation(
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_http_request_method(start: usize, end: usize, offset: usize) -> Option<EbpfHttpMethod> {
|
||||
fn get_http_request_method(start: usize, end: usize, offset: usize) -> Option<HttpMethodBitmap> {
|
||||
if start + offset + 8 > end {
|
||||
return None;
|
||||
}
|
||||
@ -137,13 +133,13 @@ fn get_http_request_method(start: usize, end: usize, offset: usize) -> Option<Eb
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ipv4_ssh_service_violation(source: &EbpfAddrPortV4, destination: &EbpfAddrPortV4) -> bool {
|
||||
fn ipv4_ssh_service_violation(source: &AddrPortV4, destination: &AddrPortV4) -> bool {
|
||||
unsafe {
|
||||
if IPV4_SSH_SERVICE.get(destination).is_some() {
|
||||
if SSH_WHITE_LIST_ENABLE.get(0).is_some() {
|
||||
IPV4_SSH_WHITE_LIST.get(&source[0]).is_none()
|
||||
IPV4_SSH_WHITE_LIST.get(&source.ip).is_none()
|
||||
} else {
|
||||
IPV4_SSH_BLACK_LIST.get(&source[0]).is_some()
|
||||
IPV4_SSH_BLACK_LIST.get(&source.ip).is_some()
|
||||
}
|
||||
} else {
|
||||
false
|
||||
@ -152,13 +148,13 @@ fn ipv4_ssh_service_violation(source: &EbpfAddrPortV4, destination: &EbpfAddrPor
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn ipv6_ssh_service_violation(source_ip: &EbpfAddrPortV6, destination: &EbpfAddrPortV6) -> bool {
|
||||
fn ipv6_ssh_service_violation(source_ip: &AddrPortV6, destination: &AddrPortV6) -> bool {
|
||||
unsafe {
|
||||
if IPV6_SSH_SERVICE.get(destination).is_some() {
|
||||
if SSH_WHITE_LIST_ENABLE.get(0).is_some() {
|
||||
IPV6_SSH_WHITE_LIST.get(&source_ip[0]).is_none()
|
||||
IPV6_SSH_WHITE_LIST.get(&source_ip.ip).is_none()
|
||||
} else {
|
||||
IPV6_SSH_BLACK_LIST.get(&source_ip[0]).is_some()
|
||||
IPV6_SSH_BLACK_LIST.get(&source_ip.ip).is_some()
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
||||
@ -2,52 +2,52 @@ use aya_ebpf::helpers::bpf_ktime_get_ns;
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::LruHashMap;
|
||||
use net_guardia_common::model::event::{IPv4Event, IPv6Event};
|
||||
use net_guardia_common::model::flow_stats::EbpfFlowStats;
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
|
||||
use net_guardia_common::model::flow_stats::FlowStats;
|
||||
use net_guardia_common::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
use net_guardia_common::MAX_STATS;
|
||||
|
||||
#[map]
|
||||
static IPV4_INGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_1MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_INGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_10MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_INGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_SRC_1HOUR: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_SRC_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_1MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_SRC_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_10MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_SRC_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_SRC_1HOUR: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_INGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_1MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_INGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_10MIN: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV4_INGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV4, EbpfFlowStats> =
|
||||
static IPV4_INGRESS_DST_1HOUR: LruHashMap<AddrPortV4, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_DST_1MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_1MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_DST_10MIN: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_10MIN: LruHashMap<AddrPortV6, FlowStats> =
|
||||
LruHashMap::with_max_entries(MAX_STATS, 0);
|
||||
#[map]
|
||||
static IPV6_INGRESS_DST_1HOUR: LruHashMap<EbpfAddrPortV6, EbpfFlowStats> =
|
||||
static IPV6_INGRESS_DST_1HOUR: LruHashMap<AddrPortV6, FlowStats> =
|
||||
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];
|
||||
let destination = [event.destination_ip, event.destination_port as u32];
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
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);
|
||||
@ -60,8 +60,8 @@ pub fn ipv4_update_stats(event: &IPv4Event) {
|
||||
pub fn ipv6_update_stats(event: &IPv6Event) {
|
||||
unsafe {
|
||||
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];
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
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);
|
||||
@ -73,18 +73,22 @@ pub fn ipv6_update_stats(event: &IPv6Event) {
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn ipv4_update_flow_stats(
|
||||
map: &LruHashMap<EbpfAddrPortV4, EbpfFlowStats>,
|
||||
key: &EbpfAddrPortV4,
|
||||
map: &LruHashMap<AddrPortV4, FlowStats>,
|
||||
key: &AddrPortV4,
|
||||
event: &IPv4Event,
|
||||
now: u64,
|
||||
) {
|
||||
unsafe {
|
||||
if let Some(status) = map.get_ptr_mut(key) {
|
||||
(*status)[0] += event.len as u64;
|
||||
(*status)[1] += 1;
|
||||
(*status)[2] = now;
|
||||
(*status).bytes += event.len as u64;
|
||||
(*status).packets += 1;
|
||||
(*status).last_seen = now;
|
||||
} else {
|
||||
let new_stats = [event.len as u64, 1, now];
|
||||
let new_stats = FlowStats {
|
||||
bytes: event.len as u64,
|
||||
packets: 1,
|
||||
last_seen: now
|
||||
};
|
||||
let _ = map.insert(key, &new_stats, 0);
|
||||
}
|
||||
}
|
||||
@ -92,18 +96,22 @@ unsafe fn ipv4_update_flow_stats(
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn ipv6_update_flow_status(
|
||||
map: &LruHashMap<EbpfAddrPortV6, EbpfFlowStats>,
|
||||
key: &EbpfAddrPortV6,
|
||||
map: &LruHashMap<AddrPortV6, FlowStats>,
|
||||
key: &AddrPortV6,
|
||||
event: &IPv6Event,
|
||||
now: u64,
|
||||
) {
|
||||
unsafe {
|
||||
if let Some(status) = map.get_ptr_mut(key) {
|
||||
(*status)[0] += event.len as u64;
|
||||
(*status)[1] += 1;
|
||||
(*status)[2] = now;
|
||||
(*status).bytes += event.len as u64;
|
||||
(*status).packets += 1;
|
||||
(*status).last_seen = now;
|
||||
} else {
|
||||
let new_stats = [event.len as u64, 1, now];
|
||||
let new_stats = FlowStats {
|
||||
bytes: event.len as u64,
|
||||
packets: 1,
|
||||
last_seen: now
|
||||
};
|
||||
let _ = map.insert(key, &new_stats, 0);
|
||||
}
|
||||
}
|
||||
|
||||
9
net-guardia-ingress-ebpf/src/action/transmission.rs
Normal file
9
net-guardia-ingress-ebpf/src/action/transmission.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::RingBuf;
|
||||
|
||||
#[map]
|
||||
static PACKET_RING: RingBuf = RingBuf::with_byte_size(4 * 1024 * 1024, 0);
|
||||
|
||||
pub fn transmission() {
|
||||
|
||||
}
|
||||
@ -3,14 +3,17 @@
|
||||
mod action;
|
||||
mod utils;
|
||||
|
||||
use action::{access_control, defence, statistics, service};
|
||||
use aya_ebpf::macros::{map, xdp};
|
||||
use aya_ebpf::maps::{PerCpuArray, ProgramArray};
|
||||
use aya_ebpf::{bindings::xdp_action, programs::XdpContext};
|
||||
use crate::action::{access_control, service, statistics};
|
||||
use crate::utils::parsing;
|
||||
use aya_ebpf::{
|
||||
bindings::xdp_action,
|
||||
macros::{map, xdp},
|
||||
maps::{PerCpuArray, ProgramArray},
|
||||
programs::XdpContext,
|
||||
};
|
||||
use aya_log_ebpf::error;
|
||||
use net_guardia_common::model::event::Event;
|
||||
use network_types::eth::EtherType;
|
||||
use utils::parsing;
|
||||
|
||||
#[map]
|
||||
static PROGRAM_ARRAY: ProgramArray = ProgramArray::with_max_entries(8, 0);
|
||||
@ -116,47 +119,15 @@ unsafe fn try_service(ctx: XdpContext) -> Result<u32, ()> {
|
||||
}
|
||||
}
|
||||
|
||||
// #[xdp]
|
||||
// pub fn defence(ctx: XdpContext) -> u32 {
|
||||
// match unsafe { try_defence(ctx) } {
|
||||
// Ok(ret) => ret,
|
||||
// Err(_) => xdp_action::XDP_PASS,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// unsafe fn try_defence(ctx: XdpContext) -> Result<u32, ()> {
|
||||
// let ptr = PARSED_PACKET.get_ptr(0).ok_or(())?;
|
||||
// let parsed_packet = ptr.read();
|
||||
// match parsed_packet.eth_type {
|
||||
// EtherType::Ipv4 => {
|
||||
// let event = parsed_packet.into_ipv4_event();
|
||||
// if defence::ipv4_is_attack(&event) {
|
||||
// return Ok(xdp_action::XDP_DROP);
|
||||
// }
|
||||
// }
|
||||
// EtherType::Ipv6 => {
|
||||
// let event = parsed_packet.into_ipv6_event();
|
||||
// if defence::ipv6_is_attack(&event) {
|
||||
// return Ok(xdp_action::XDP_DROP);
|
||||
// }
|
||||
// }
|
||||
// _ => Err(())?
|
||||
// }
|
||||
// if PROGRAM_ARRAY.tail_call(&ctx, 3).is_err() {
|
||||
// error!(&ctx, "Tail call failed");
|
||||
// }
|
||||
// Err(())
|
||||
// }
|
||||
|
||||
#[xdp]
|
||||
pub fn sampling(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_sampling(ctx) } {
|
||||
pub fn transmission(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_transmission(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn try_sampling(ctx: XdpContext) -> Result<u32, ()> {
|
||||
unsafe fn try_transmission(ctx: XdpContext) -> Result<u32, ()> {
|
||||
if unsafe { PROGRAM_ARRAY.tail_call(&ctx, 4).is_err() } {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
|
||||
12
net-guardia-ingress-ebpf/src/utils/define.rs
Normal file
12
net-guardia-ingress-ebpf/src/utils/define.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use network_types::eth::EthHdr;
|
||||
use network_types::ip::{Ipv4Hdr, Ipv6Hdr};
|
||||
use network_types::tcp::TcpHdr;
|
||||
use network_types::udp::UdpHdr;
|
||||
|
||||
pub const ETHER_HEADER_OFFSET: usize = size_of::<EthHdr>();
|
||||
pub const IPV4_HEADER_OFFSET: usize = ETHER_HEADER_OFFSET + size_of::<Ipv4Hdr>();
|
||||
pub const IPV6_HEADER_OFFSET: usize = ETHER_HEADER_OFFSET + size_of::<Ipv6Hdr>();
|
||||
pub const IPV4_TCP_HEADER_OFFSET: usize = IPV4_HEADER_OFFSET + size_of::<TcpHdr>();
|
||||
pub const IPV6_TCP_HEADER_OFFSET: usize = IPV6_HEADER_OFFSET + size_of::<TcpHdr>();
|
||||
pub const IPV4_UDP_HEADER_OFFSET: usize = IPV4_HEADER_OFFSET + size_of::<UdpHdr>();
|
||||
pub const IPV6_UDP_HEADER_OFFSET: usize = IPV6_HEADER_OFFSET + size_of::<UdpHdr>();
|
||||
@ -1 +1,2 @@
|
||||
pub mod parsing;
|
||||
mod define;
|
||||
|
||||
@ -9,9 +9,9 @@ net-guardia-common = { path = "../net-guardia-common", features = ["user"] }
|
||||
anyhow = { workspace = true, default-features = true }
|
||||
aya = { workspace = true }
|
||||
aya-log = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt", "rt-multi-thread", "net", "signal", "sync", "time", "fs"] }
|
||||
tokio = { workspace = true, features = ["full", "macros"] }
|
||||
libc = { workspace = true }
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde = { workspace = true }
|
||||
toml = "0.8.19"
|
||||
tracing = "0.1.41"
|
||||
thiserror = "2.0.3"
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
pub struct Defence {
|
||||
|
||||
}
|
||||
|
||||
impl Defence {
|
||||
pub async fn initialize() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,14 @@
|
||||
use crate::core::control::access_control::AccessControl;
|
||||
use crate::core::control::defence::Defence;
|
||||
use crate::core::control::sampling::Sampling;
|
||||
use crate::core::control::service::Service;
|
||||
|
||||
pub mod access_control;
|
||||
pub mod defence;
|
||||
pub mod service;
|
||||
pub mod sampling;
|
||||
|
||||
pub struct Control;
|
||||
|
||||
impl Control {
|
||||
pub async fn initialize() -> anyhow::Result<()> {
|
||||
AccessControl::initialize().await?;
|
||||
Defence::initialize().await?;
|
||||
Sampling::initialize().await?;
|
||||
Service::initialize().await
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
pub struct Sampling {
|
||||
|
||||
}
|
||||
|
||||
impl Sampling {
|
||||
pub async fn initialize() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,25 @@
|
||||
use crate::core::system::System;
|
||||
use crate::model::http_method::HttpMethod;
|
||||
use crate::utils::log_entry::ebpf::EbpfEntry;
|
||||
use crate::utils::log_entry::system::SystemEntry;
|
||||
use aya::maps::{Array as AyaArray, HashMap as AyaHashMap, MapData};
|
||||
use net_guardia_common::model::http_method::EbpfHttpMethod;
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6, IPv4, IPv6};
|
||||
use net_guardia_common::model::http_method::{HttpMethod, HttpMethodBitmap};
|
||||
use net_guardia_common::model::ip_address::{AddrPortV4, AddrPortV6, IPv4, IPv6};
|
||||
use net_guardia_common::model::placeholder::PlaceHolder;
|
||||
use std::collections::HashMap as StdHashMap;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use std::sync::OnceLock;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use tracing::{error, info};
|
||||
use crate::model::ip_address::IntoNative;
|
||||
|
||||
static SERVICE: OnceLock<RwLock<Service>> = OnceLock::new();
|
||||
|
||||
pub struct Service {
|
||||
ipv4_http_service: AyaHashMap<MapData, EbpfAddrPortV4, EbpfHttpMethod>,
|
||||
ipv6_http_service: AyaHashMap<MapData, EbpfAddrPortV6, EbpfHttpMethod>,
|
||||
ipv4_http_service: AyaHashMap<MapData, AddrPortV4, HttpMethodBitmap>,
|
||||
ipv6_http_service: AyaHashMap<MapData, AddrPortV6, HttpMethodBitmap>,
|
||||
ssh_white_list_enable: AyaArray<MapData, PlaceHolder>,
|
||||
ipv4_ssh_service: AyaHashMap<MapData, EbpfAddrPortV4, PlaceHolder>,
|
||||
ipv6_ssh_service: AyaHashMap<MapData, EbpfAddrPortV6, PlaceHolder>,
|
||||
ipv4_ssh_service: AyaHashMap<MapData, AddrPortV4, PlaceHolder>,
|
||||
ipv6_ssh_service: AyaHashMap<MapData, AddrPortV6, PlaceHolder>,
|
||||
ipv4_ssh_white_list: AyaHashMap<MapData, IPv4, PlaceHolder>,
|
||||
ipv6_ssh_white_list: AyaHashMap<MapData, IPv6, PlaceHolder>,
|
||||
ipv4_ssh_black_list: AyaHashMap<MapData, IPv4, PlaceHolder>,
|
||||
@ -83,11 +83,11 @@ impl Service {
|
||||
.iter()
|
||||
.filter_map(Result::ok)
|
||||
.map(|(key, value)| {
|
||||
let address = Ipv4Addr::from(key[0]);
|
||||
let port = key[1] as u16;
|
||||
let address = Ipv4Addr::from(key.ip);
|
||||
let port = key.port;
|
||||
(
|
||||
SocketAddrV4::new(address, port),
|
||||
HttpMethod::convert_from_ebpf(value),
|
||||
HttpMethod::convert_from_bitmap(value),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
@ -100,11 +100,11 @@ impl Service {
|
||||
.iter()
|
||||
.filter_map(Result::ok)
|
||||
.map(|(key, value)| {
|
||||
let address = Ipv6Addr::from(key[0]);
|
||||
let port = key[1] as u16;
|
||||
let address = Ipv6Addr::from(key.ip);
|
||||
let port = key.port;
|
||||
(
|
||||
SocketAddrV6::new(address, port, 0, 0),
|
||||
HttpMethod::convert_from_ebpf(value),
|
||||
HttpMethod::convert_from_bitmap(value),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
@ -116,8 +116,8 @@ impl Service {
|
||||
) -> anyhow::Result<()> {
|
||||
let ip: u32 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u32];
|
||||
let ebpf_method = HttpMethod::convert_to_ebpf(http_method);
|
||||
let addr_port = AddrPortV4::new(ip, port);
|
||||
let ebpf_method = HttpMethod::convert_to_bitmap(http_method);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv4_http_service
|
||||
@ -132,8 +132,8 @@ impl Service {
|
||||
) -> anyhow::Result<()> {
|
||||
let ip: u128 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u128];
|
||||
let ebpf_method = HttpMethod::convert_to_ebpf(http_method);
|
||||
let addr_port = AddrPortV6::new(ip, port);
|
||||
let ebpf_method = HttpMethod::convert_to_bitmap(http_method);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv6_http_service
|
||||
@ -148,10 +148,10 @@ impl Service {
|
||||
) -> anyhow::Result<()> {
|
||||
let ip: u32 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u32];
|
||||
let addr_port = AddrPortV4::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
if let Ok(current_http_method) = service.ipv4_http_service.get(&addr_port, 0) {
|
||||
let mut http_method = HttpMethod::convert_from_ebpf(current_http_method);
|
||||
let mut http_method = HttpMethod::convert_from_bitmap(current_http_method);
|
||||
http_method.retain(|method| !removed_http_method.contains(method));
|
||||
if http_method.is_empty() {
|
||||
service
|
||||
@ -159,7 +159,7 @@ impl Service {
|
||||
.remove(&addr_port)
|
||||
.map_err(|_| EbpfEntry::MapOperationError)?;
|
||||
} else {
|
||||
let new_http_method = HttpMethod::convert_to_ebpf(http_method);
|
||||
let new_http_method = HttpMethod::convert_to_bitmap(http_method);
|
||||
service
|
||||
.ipv4_http_service
|
||||
.insert(&addr_port, new_http_method, 0)
|
||||
@ -177,10 +177,10 @@ impl Service {
|
||||
) -> anyhow::Result<()> {
|
||||
let ip: u128 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u128];
|
||||
let addr_port = AddrPortV6::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
if let Ok(current_http_method) = service.ipv6_http_service.get(&addr_port, 0) {
|
||||
let mut http_method = HttpMethod::convert_from_ebpf(current_http_method);
|
||||
let mut http_method = HttpMethod::convert_from_bitmap(current_http_method);
|
||||
http_method.retain(|method| !removed_http_method.contains(method));
|
||||
if http_method.is_empty() {
|
||||
service
|
||||
@ -188,7 +188,7 @@ impl Service {
|
||||
.remove(&addr_port)
|
||||
.map_err(|_| EbpfEntry::MapOperationError)?;
|
||||
} else {
|
||||
let new_http_method = HttpMethod::convert_to_ebpf(http_method);
|
||||
let new_http_method = HttpMethod::convert_to_bitmap(http_method);
|
||||
service
|
||||
.ipv6_http_service
|
||||
.insert(&addr_port, new_http_method, 0)
|
||||
@ -238,7 +238,7 @@ impl Service {
|
||||
.ipv4_ssh_service
|
||||
.keys()
|
||||
.filter_map(Result::ok)
|
||||
.map(|key| SocketAddrV4::new(Ipv4Addr::from(key[0]), key[1] as u16))
|
||||
.map(|key| key.into_native())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -248,14 +248,14 @@ impl Service {
|
||||
.ipv6_ssh_service
|
||||
.keys()
|
||||
.filter_map(Result::ok)
|
||||
.map(|key| SocketAddrV6::new(Ipv6Addr::from(key[0]), key[1] as u16, 0, 0))
|
||||
.map(|key| key.into_native())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn add_ipv4_ssh_service(address: SocketAddrV4) -> anyhow::Result<()> {
|
||||
let ip: u32 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u32];
|
||||
let addr_port = AddrPortV4::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv4_ssh_service
|
||||
@ -267,7 +267,7 @@ impl Service {
|
||||
pub async fn add_ipv6_ssh_service(address: SocketAddrV6) -> anyhow::Result<()> {
|
||||
let ip: u128 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u128];
|
||||
let addr_port = AddrPortV6::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv6_ssh_service
|
||||
@ -279,7 +279,7 @@ impl Service {
|
||||
pub async fn remove_ipv4_ssh_service(address: SocketAddrV4) -> anyhow::Result<()> {
|
||||
let ip: u32 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u32];
|
||||
let addr_port = AddrPortV4::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv4_ssh_service
|
||||
@ -291,7 +291,7 @@ impl Service {
|
||||
pub async fn remove_ipv6_ssh_service(address: SocketAddrV6) -> anyhow::Result<()> {
|
||||
let ip: u128 = (*address.ip()).into();
|
||||
let port = address.port();
|
||||
let addr_port = [ip, port as u128];
|
||||
let addr_port = AddrPortV6::new(ip, port);
|
||||
let mut service = Service::instance_mut().await;
|
||||
service
|
||||
.ipv6_ssh_service
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
use crate::core::system::System;
|
||||
use crate::model::direction::{Direction, FlowDirection};
|
||||
use crate::model::flow_stats::FlowStats;
|
||||
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};
|
||||
use aya::Pod;
|
||||
use net_guardia_common::model::flow_stats::EbpfFlowStats;
|
||||
use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6};
|
||||
use net_guardia_common::model::flow_stats::FlowStats;
|
||||
use net_guardia_common::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
use std::collections::HashMap as StdHashMap;
|
||||
use std::net::{SocketAddrV4, SocketAddrV6};
|
||||
use std::sync::OnceLock;
|
||||
@ -18,8 +17,8 @@ static STATISTICS: OnceLock<RwLock<Statistics>> = OnceLock::new();
|
||||
|
||||
pub struct Statistics {
|
||||
terminate: bool,
|
||||
ipv4_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<EbpfAddrPortV4>>,
|
||||
ipv6_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<EbpfAddrPortV6>>,
|
||||
ipv4_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<AddrPortV4>>,
|
||||
ipv6_maps: StdHashMap<(Direction, FlowDirection, TimeType), FlowMap<AddrPortV6>>,
|
||||
}
|
||||
|
||||
impl Statistics {
|
||||
@ -197,7 +196,7 @@ impl Statistics {
|
||||
}
|
||||
|
||||
struct FlowMap<T> {
|
||||
map: AyaHashMap<MapData, T, EbpfFlowStats>,
|
||||
map: AyaHashMap<MapData, T, FlowStats>,
|
||||
}
|
||||
|
||||
impl<T: IntoNative + Pod> FlowMap<T> {
|
||||
@ -216,7 +215,7 @@ impl<T: IntoNative + Pod> FlowMap<T> {
|
||||
.filter_map(|result| {
|
||||
result
|
||||
.ok()
|
||||
.and_then(|(key, stats)| (now - stats[2] - boot_time > window).then_some(key))
|
||||
.and_then(|(key, stats)| (now - stats.last_seen - boot_time > window).then_some(key))
|
||||
})
|
||||
.collect();
|
||||
expired_keys.iter().for_each(|key| {
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
use serde::Serialize;
|
||||
use net_guardia_common::model::flow_stats::EbpfFlowStats;
|
||||
|
||||
#[derive(Serialize, Debug, Clone)]
|
||||
pub struct FlowStats {
|
||||
pub bytes: u64,
|
||||
pub packets: u64,
|
||||
pub last_seen: u64,
|
||||
}
|
||||
|
||||
impl From<EbpfFlowStats> for FlowStats {
|
||||
fn from(ebpf_flow_status: EbpfFlowStats) -> Self {
|
||||
FlowStats {
|
||||
bytes: ebpf_flow_status[0],
|
||||
packets: ebpf_flow_status[1],
|
||||
last_seen: ebpf_flow_status[2],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FlowStats> for EbpfFlowStats {
|
||||
fn from(flow_status: FlowStats) -> Self {
|
||||
[flow_status.bytes, flow_status.packets, flow_status.last_seen]
|
||||
}
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use net_guardia_common::model::http_method::EbpfHttpMethod;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum HttpMethod {
|
||||
GET = 0b0000_0000_0000_0001,
|
||||
POST = 0b0000_0000_0000_0010,
|
||||
PUT = 0b0000_0000_0000_0100,
|
||||
DELETE = 0b0000_0000_0000_1000,
|
||||
HEAD = 0b0000_0000_0001_0000,
|
||||
OPTIONS = 0b0000_0000_0010_0000,
|
||||
PATCH = 0b0000_0000_0100_0000,
|
||||
TRACE = 0b0000_0000_1000_0000,
|
||||
CONNECT = 0b0000_0001_0000_0000,
|
||||
}
|
||||
|
||||
impl HttpMethod {
|
||||
pub fn convert_from_ebpf(ebpf_http_methods: EbpfHttpMethod) -> Vec<HttpMethod> {
|
||||
let value = ebpf_http_methods as u16;
|
||||
let mut http_methods = Vec::new();
|
||||
|
||||
let all_methods = [
|
||||
HttpMethod::GET,
|
||||
HttpMethod::POST,
|
||||
HttpMethod::PUT,
|
||||
HttpMethod::DELETE,
|
||||
HttpMethod::HEAD,
|
||||
HttpMethod::OPTIONS,
|
||||
HttpMethod::PATCH,
|
||||
HttpMethod::TRACE,
|
||||
HttpMethod::CONNECT,
|
||||
];
|
||||
|
||||
for method in all_methods {
|
||||
if value & (method as u16) != 0 {
|
||||
http_methods.push(method);
|
||||
}
|
||||
}
|
||||
http_methods
|
||||
}
|
||||
|
||||
pub fn convert_to_ebpf(http_methods: Vec<HttpMethod>) -> EbpfHttpMethod {
|
||||
let mut ebpf_http_method = 0_u16;
|
||||
for http_method in http_methods {
|
||||
ebpf_http_method |= http_method as u16;
|
||||
}
|
||||
ebpf_http_method
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
use net_guardia_common::model::ip_address::{IPv4, IPv6, EbpfAddrPortV4, EbpfAddrPortV6};
|
||||
use net_guardia_common::model::ip_address::*;
|
||||
use std::hash::Hash;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
|
||||
@ -23,18 +23,18 @@ impl IntoNative for IPv6 {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoNative for EbpfAddrPortV4 {
|
||||
impl IntoNative for AddrPortV4 {
|
||||
type Native = SocketAddrV4;
|
||||
|
||||
fn into_native(self) -> Self::Native {
|
||||
SocketAddrV4::new(Ipv4Addr::from(self[0]), self[1] as u16)
|
||||
SocketAddrV4::new(Ipv4Addr::from(self.ip), self.port)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoNative for EbpfAddrPortV6 {
|
||||
impl IntoNative for AddrPortV6 {
|
||||
type Native = SocketAddrV6;
|
||||
|
||||
fn into_native(self) -> Self::Native {
|
||||
SocketAddrV6::new(Ipv6Addr::from(self[0]), self[1] as u16, 0, 0)
|
||||
SocketAddrV6::new(Ipv6Addr::from(self.ip), self.port, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
pub mod alert;
|
||||
pub mod config;
|
||||
pub mod direction;
|
||||
pub mod flow_stats;
|
||||
pub mod http_method;
|
||||
pub mod ip_address;
|
||||
pub mod list_type;
|
||||
pub mod time_type;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
pub mod log_entry;
|
||||
pub mod definition;
|
||||
pub mod ip_address;
|
||||
pub mod logging;
|
||||
pub mod static_files;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::core::control::service::Service;
|
||||
use crate::model::http_method::HttpMethod;
|
||||
use actix_web::{delete, get, post, put, web, HttpResponse, Responder, Scope};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};
|
||||
use net_guardia_common::model::http_method::HttpMethod;
|
||||
|
||||
pub fn initialize() -> Scope {
|
||||
web::scope("/service")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user