From e3d2ed077d25ea2224aec65e6851952865a3388e Mon Sep 17 00:00:00 2001 From: DaLaw2 Date: Sun, 1 Dec 2024 21:23:32 +0800 Subject: [PATCH] Add ssh service protect --- net-guardia-common/src/lib.rs | 2 +- net-guardia-common/src/model/mod.rs | 1 + net-guardia-common/src/model/placeholder.rs | 1 + net-guardia-ebpf/src/action/blocking.rs | 18 +---- .../src/action/{detect.rs => defence.rs} | 0 net-guardia-ebpf/src/action/mod.rs | 4 +- net-guardia-ebpf/src/action/service.rs | 75 +++++++++++++++---- net-guardia-ebpf/src/main.rs | 8 +- .../src/core/{blocking.rs => control.rs} | 2 +- net-guardia/src/core/mod.rs | 2 +- 10 files changed, 77 insertions(+), 36 deletions(-) create mode 100644 net-guardia-common/src/model/placeholder.rs rename net-guardia-ebpf/src/action/{detect.rs => defence.rs} (100%) rename net-guardia/src/core/{blocking.rs => control.rs} (93%) diff --git a/net-guardia-common/src/lib.rs b/net-guardia-common/src/lib.rs index 2ab52fd..f9b95f3 100644 --- a/net-guardia-common/src/lib.rs +++ b/net-guardia-common/src/lib.rs @@ -11,7 +11,7 @@ pub const MAX_STATS: u32 = 100000; /// /// Limits the number of rules that can be configured to ensure /// predictable performance and resource usage. -pub const MAX_RULES: u32 = 32; +pub const MAX_RULES: u32 = 1000; /// Maximum number of port-specific rules allowed /// /// Defines the upper limit for port-based filtering rules to maintain diff --git a/net-guardia-common/src/model/mod.rs b/net-guardia-common/src/model/mod.rs index 0e9362c..0b340bf 100644 --- a/net-guardia-common/src/model/mod.rs +++ b/net-guardia-common/src/model/mod.rs @@ -3,4 +3,5 @@ pub mod flow_stats; pub mod http_method; pub mod ip_address; pub mod packet_status; +pub mod placeholder; pub mod pseudo_header; diff --git a/net-guardia-common/src/model/placeholder.rs b/net-guardia-common/src/model/placeholder.rs new file mode 100644 index 0000000..b88edcb --- /dev/null +++ b/net-guardia-common/src/model/placeholder.rs @@ -0,0 +1 @@ +pub type PlaceHolder = u8; diff --git a/net-guardia-ebpf/src/action/blocking.rs b/net-guardia-ebpf/src/action/blocking.rs index 43ecb3e..f5575f0 100644 --- a/net-guardia-ebpf/src/action/blocking.rs +++ b/net-guardia-ebpf/src/action/blocking.rs @@ -5,40 +5,30 @@ use net_guardia_common::model::ip_address::{IPv4, IPv6, Port}; use net_guardia_common::{MAX_RULES, MAX_RULES_PORT}; #[map] -static BLOCKED_IPV4: HashMap = +static PERMANENT_BLACKLIST_IPV4: HashMap = HashMap::with_max_entries(MAX_RULES, 0); #[map] -static BLOCKED_IPV6: HashMap = +static PERMANENT_BLACKLIST_IPV6: HashMap = HashMap::with_max_entries(MAX_RULES, 0); pub fn should_block_ipv4(event: &IPv4Event) -> bool { unsafe { - if let Some(ports) = BLOCKED_IPV4.get(&event.source_ip) { + if let Some(ports) = PERMANENT_BLACKLIST_IPV4.get(&event.source_ip) { if is_port_blocked(ports, event.source_port) { return true; } } - if let Some(ports) = BLOCKED_IPV4.get(&event.destination_ip) { - if is_port_blocked(ports, event.destination_port) { - return true; - } - } } false } pub fn should_block_ipv6(event: &IPv6Event) -> bool { unsafe { - if let Some(ports) = BLOCKED_IPV6.get(&event.source_ip) { + if let Some(ports) = PERMANENT_BLACKLIST_IPV6.get(&event.source_ip) { if is_port_blocked(ports, event.source_port) { return true; } } - if let Some(ports) = BLOCKED_IPV6.get(&event.destination_ip) { - if is_port_blocked(ports, event.destination_port) { - return true; - } - } } false } diff --git a/net-guardia-ebpf/src/action/detect.rs b/net-guardia-ebpf/src/action/defence.rs similarity index 100% rename from net-guardia-ebpf/src/action/detect.rs rename to net-guardia-ebpf/src/action/defence.rs diff --git a/net-guardia-ebpf/src/action/mod.rs b/net-guardia-ebpf/src/action/mod.rs index 5ca9067..150adfc 100644 --- a/net-guardia-ebpf/src/action/mod.rs +++ b/net-guardia-ebpf/src/action/mod.rs @@ -1,5 +1,5 @@ -pub mod forward; pub mod blocking; -pub mod detect; +pub mod defence; +pub mod forward; pub mod monitor; pub mod service; diff --git a/net-guardia-ebpf/src/action/service.rs b/net-guardia-ebpf/src/action/service.rs index ef9099c..460fb5d 100644 --- a/net-guardia-ebpf/src/action/service.rs +++ b/net-guardia-ebpf/src/action/service.rs @@ -1,7 +1,8 @@ -use aya_ebpf::maps::HashMap; +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}; +use net_guardia_common::model::ip_address::{EbpfAddrPortV4, EbpfAddrPortV6, IPv4, IPv6}; +use net_guardia_common::model::placeholder::PlaceHolder; use net_guardia_common::MAX_RULES; static HTTP_SERVICE_V4: HashMap = @@ -9,35 +10,47 @@ static HTTP_SERVICE_V4: HashMap = static HTTP_SERVICE_V6: HashMap = HashMap::with_max_entries(MAX_RULES, 0); -pub fn ipv4_service_rule(event: &IPv4Event, start: usize, end: usize, offset: usize) -> bool { +static SSH_WHITE_LIST_ONLY: Array = Array::with_max_entries(1, 0); +static IPV4_SSH_SERVICE: HashMap = + HashMap::with_max_entries(MAX_RULES, 0); +static IPV6_SSH_SERVICE: HashMap = + HashMap::with_max_entries(MAX_RULES, 0); +static IPV4_SSH_WHITE_LIST: HashMap = HashMap::with_max_entries(MAX_RULES, 0); +static IPV6_SSH_WHITE_LIST: HashMap = HashMap::with_max_entries(MAX_RULES, 0); +static IPV4_SSH_BLACK_LIST: HashMap = HashMap::with_max_entries(MAX_RULES, 0); +static IPV6_SSH_BLACK_LIST: HashMap = HashMap::with_max_entries(MAX_RULES, 0); + +pub fn ipv4_service_rule_violation(event: &IPv4Event, start: usize, end: usize, offset: usize) -> bool { + let source = event.get_source(); let destination = event.get_destination(); - ipv4_http_service(destination, start, end, offset) + ipv4_http_service_violation(&destination, start, end, offset) || ipv4_ssh_service_violation(&source, &destination) } -pub fn ipv6_service_rule(event: &IPv6Event, start: usize, end: usize, offset: usize) -> bool { +pub fn ipv6_service_rule_violation(event: &IPv6Event, start: usize, end: usize, offset: usize) -> bool { + let source = event.get_source(); let destination = event.get_destination(); - ipv6_http_service(destination, start, end, offset) + ipv6_http_service_violation(&destination, start, end, offset) || ipv6_ssh_service_violation(&source, &destination) } #[inline(always)] -fn ipv4_http_service(addr_port: EbpfAddrPortV4, start: usize, end: usize, offset: usize) -> bool { - match HTTP_SERVICE_V4.get_ptr_mut(&addr_port) { +fn ipv4_http_service_violation(addr_port: &EbpfAddrPortV4, start: usize, end: usize, offset: usize) -> bool { + match HTTP_SERVICE_V4.get_ptr_mut(addr_port) { Some(allow_method) => match get_http_request_method(start, end, offset) { - Some(http_method) => unsafe { *allow_method & http_method != 0 }, - None => false, + Some(http_method) => unsafe { *allow_method & http_method == 0 }, + None => true, }, - None => true, + None => false, } } #[inline(always)] -fn ipv6_http_service(addr_port: EbpfAddrPortV6, start: usize, end: usize, offset: usize) -> bool { - match HTTP_SERVICE_V6.get_ptr_mut(&addr_port) { +fn ipv6_http_service_violation(addr_port: &EbpfAddrPortV6, start: usize, end: usize, offset: usize) -> bool { + match HTTP_SERVICE_V6.get_ptr_mut(addr_port) { Some(allow_method) => match get_http_request_method(start, end, offset) { - Some(http_method) => unsafe { *allow_method & http_method != 0 }, - None => false, + Some(http_method) => unsafe { *allow_method & http_method == 0 }, + None => true, }, - None => true, + None => false, } } @@ -60,3 +73,33 @@ fn get_http_request_method(start: usize, end: usize, offset: usize) -> Option None, } } + +#[inline(always)] +fn ipv4_ssh_service_violation(source_ip: &EbpfAddrPortV4, destination: &EbpfAddrPortV4) -> bool { + unsafe { + if IPV4_SSH_SERVICE.get(destination).is_some() { + if SSH_WHITE_LIST_ONLY.get(0).is_some() { + IPV4_SSH_WHITE_LIST.get(&source_ip[0]).is_none() + } else { + IPV4_SSH_BLACK_LIST.get(&source_ip[0]).is_some() + } + } else { + false + } + } +} + +#[inline(always)] +fn ipv6_ssh_service_violation(source_ip: &EbpfAddrPortV6, destination: &EbpfAddrPortV6) -> bool { + unsafe { + if IPV6_SSH_SERVICE.get(destination).is_some() { + if SSH_WHITE_LIST_ONLY.get(0).is_some() { + IPV6_SSH_WHITE_LIST.get(&source_ip[0]).is_none() + } else { + IPV6_SSH_BLACK_LIST.get(&source_ip[0]).is_some() + } + } else { + false + } + } +} diff --git a/net-guardia-ebpf/src/main.rs b/net-guardia-ebpf/src/main.rs index ccdc8e3..1812a55 100644 --- a/net-guardia-ebpf/src/main.rs +++ b/net-guardia-ebpf/src/main.rs @@ -10,6 +10,7 @@ use aya_ebpf::{bindings::xdp_action, macros::xdp, programs::XdpContext}; #[allow(unused_imports)] use aya_log_ebpf::info; use network_types::eth::EtherType; +use crate::action::service; #[xdp] pub fn net_guardia(ctx: XdpContext) -> u32 { @@ -29,7 +30,9 @@ fn try_net_guardia(ctx: XdpContext) -> Result { if blocking::should_block_ipv4(&event) { return Ok(xdp_action::XDP_DROP); } - + if service::ipv4_service_rule_violation(&event, start, end, offset) { + return Ok(xdp_action::XDP_DROP); + } monitor::update_stats_ipv4(&event); } EtherType::Ipv6 => { @@ -37,6 +40,9 @@ fn try_net_guardia(ctx: XdpContext) -> Result { if blocking::should_block_ipv6(&event) { return Ok(xdp_action::XDP_DROP); } + if service::ipv6_service_rule_violation(&event, start, end, offset) { + return Ok(xdp_action::XDP_DROP); + } monitor::update_stats_ipv6(&event); } _ => Err(())?, diff --git a/net-guardia/src/core/blocking.rs b/net-guardia/src/core/control.rs similarity index 93% rename from net-guardia/src/core/blocking.rs rename to net-guardia/src/core/control.rs index 0bb72b2..c40f28a 100644 --- a/net-guardia/src/core/blocking.rs +++ b/net-guardia/src/core/control.rs @@ -2,7 +2,7 @@ use aya::maps::{HashMap as AyaHashMap, MapData}; use net_guardia_common::MAX_RULES_PORT; use net_guardia_common::model::ip_address::{IPv4, IPv6, Port}; -pub struct Blocking { +pub struct Control { ipv4_black_list: AyaHashMap, ipv6_black_list: AyaHashMap, } diff --git a/net-guardia/src/core/mod.rs b/net-guardia/src/core/mod.rs index 5ce6dbb..c4c68a1 100644 --- a/net-guardia/src/core/mod.rs +++ b/net-guardia/src/core/mod.rs @@ -1,4 +1,4 @@ pub mod config_manager; +pub mod control; pub mod monitor; pub mod system; -mod blocking;