mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
refactor: Refactor packet parsing and event handling for better speed (#5)
This commit is contained in:
parent
688314da66
commit
c4598970a2
@ -1,5 +1,3 @@
|
||||
use crate::model::event::Event;
|
||||
use crate::define::offset::*;
|
||||
use aya_ebpf::helpers::bpf_ktime_get_ns;
|
||||
use network_types::{
|
||||
eth::{EthHdr, EtherType},
|
||||
@ -8,7 +6,12 @@ use network_types::{
|
||||
udp::UdpHdr,
|
||||
};
|
||||
|
||||
pub fn parse_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
use crate::{
|
||||
define::offset::*,
|
||||
model::event::{Event, IPv4Event, IPv6Event},
|
||||
};
|
||||
|
||||
pub fn parse_packet(start: usize, end: usize, target: *mut Event) -> Result<(), ()> {
|
||||
unsafe {
|
||||
if start + ETHER_HEADER_END > end {
|
||||
return Err(());
|
||||
@ -16,70 +19,112 @@ pub fn parse_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
let eth = &*((start + ETHER_HEADER_START) as *const EthHdr);
|
||||
let ether_type = eth.ether_type().map_err(|_| ())?;
|
||||
match ether_type {
|
||||
EtherType::Ipv4 => parse_ipv4_packet(start, end),
|
||||
EtherType::Ipv6 => parse_ipv6_packet(start, end),
|
||||
EtherType::Ipv4 => parse_ipv4_packet(start, end, target),
|
||||
EtherType::Ipv6 => parse_ipv6_packet(start, end, target),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn parse_ipv4_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
unsafe fn parse_ipv4_packet(start: usize, end: usize, target: *mut Event) -> Result<(), ()> {
|
||||
unsafe {
|
||||
if start + IPV4_HEADER_END > end {
|
||||
return Err(());
|
||||
}
|
||||
let ipv4 = &*((start + IPV4_HEADER_START) as *const Ipv4Hdr);
|
||||
let protocol = ipv4.proto;
|
||||
let source_ip = u32::from_be_bytes(ipv4.src_addr);
|
||||
let destination_ip = u32::from_be_bytes(ipv4.dst_addr);
|
||||
|
||||
let (source_port, destination_port) = match protocol {
|
||||
let ipv4 = &*((start + IPV4_HEADER_START) as *const Ipv4Hdr);
|
||||
|
||||
let (source_port, destination_port) = match ipv4.proto {
|
||||
IpProto::Tcp => parse_tcp_port(start, end, IPV4_TCP_HEADER_START, IPV4_TCP_HEADER_END)?,
|
||||
IpProto::Udp => parse_udp_port(start, end, IPV4_UDP_HEADER_START, IPV4_UDP_HEADER_END)?,
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
Ok(Event {
|
||||
eth_type: EtherType::Ipv4,
|
||||
protocol,
|
||||
source_ip: source_ip as u128,
|
||||
destination_ip: destination_ip as u128,
|
||||
*(target as *mut u32) = 0;
|
||||
|
||||
let ipv4_data_ptr = (target as *mut u8).add(16);
|
||||
|
||||
core::ptr::write(ipv4_data_ptr as *mut IpProto, ipv4.proto);
|
||||
core::ptr::copy_nonoverlapping(
|
||||
ipv4.src_addr.as_ptr(),
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, source_ip)),
|
||||
4,
|
||||
);
|
||||
core::ptr::copy_nonoverlapping(
|
||||
ipv4.dst_addr.as_ptr(),
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, destination_ip)),
|
||||
4,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, source_port)) as *mut u16,
|
||||
source_port,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, destination_port)) as *mut u16,
|
||||
destination_port,
|
||||
len: (end - start) as u32,
|
||||
timestamp: bpf_ktime_get_ns(),
|
||||
})
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, len)) as *mut u32,
|
||||
(end - start) as u32,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv4_data_ptr.add(core::mem::offset_of!(IPv4Event, timestamp)) as *mut u64,
|
||||
bpf_ktime_get_ns(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn parse_ipv6_packet(start: usize, end: usize) -> Result<Event, ()> {
|
||||
unsafe fn parse_ipv6_packet(start: usize, end: usize, target: *mut Event) -> Result<(), ()> {
|
||||
unsafe {
|
||||
if start + IPV6_HEADER_END > end {
|
||||
return Err(());
|
||||
}
|
||||
let ipv6 = &*((start + IPV6_HEADER_START) as *const Ipv6Hdr);
|
||||
let protocol = ipv6.next_hdr;
|
||||
let source_ip = u128::from_be_bytes(ipv6.src_addr);
|
||||
let destination_ip = u128::from_be_bytes(ipv6.dst_addr);
|
||||
|
||||
let (source_port, destination_port) = match protocol {
|
||||
let ipv6 = &*((start + IPV6_HEADER_START) as *const Ipv6Hdr);
|
||||
|
||||
let (source_port, destination_port) = match ipv6.next_hdr {
|
||||
IpProto::Tcp => parse_tcp_port(start, end, IPV6_TCP_HEADER_START, IPV6_TCP_HEADER_END)?,
|
||||
IpProto::Udp => parse_udp_port(start, end, IPV6_UDP_HEADER_START, IPV6_UDP_HEADER_END)?,
|
||||
_ => return Err(()),
|
||||
};
|
||||
|
||||
Ok(Event {
|
||||
eth_type: EtherType::Ipv6,
|
||||
protocol,
|
||||
source_ip,
|
||||
destination_ip,
|
||||
*(target as *mut u32) = 1;
|
||||
|
||||
let ipv6_data_ptr = (target as *mut u8).add(16);
|
||||
|
||||
core::ptr::write(ipv6_data_ptr as *mut IpProto, ipv6.next_hdr);
|
||||
core::ptr::copy_nonoverlapping(
|
||||
ipv6.src_addr.as_ptr(),
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, source_ip)),
|
||||
16,
|
||||
);
|
||||
core::ptr::copy_nonoverlapping(
|
||||
ipv6.dst_addr.as_ptr(),
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, destination_ip)),
|
||||
16,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, source_port)) as *mut u16,
|
||||
source_port,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, destination_port)) as *mut u16,
|
||||
destination_port,
|
||||
len: (end - start) as u32,
|
||||
timestamp: bpf_ktime_get_ns(),
|
||||
})
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, len)) as *mut u32,
|
||||
(end - start) as u32,
|
||||
);
|
||||
core::ptr::write(
|
||||
ipv6_data_ptr.add(core::mem::offset_of!(IPv6Event, timestamp)) as *mut u64,
|
||||
bpf_ktime_get_ns(),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,72 +1,14 @@
|
||||
use crate::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
use network_types::eth::EtherType;
|
||||
use network_types::ip::IpProto;
|
||||
|
||||
pub struct Event {
|
||||
pub eth_type: EtherType,
|
||||
pub protocol: IpProto,
|
||||
pub source_ip: u128,
|
||||
pub destination_ip: u128,
|
||||
pub source_port: u16,
|
||||
pub destination_port: u16,
|
||||
pub len: u32,
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
#[inline(always)]
|
||||
pub fn to_ipv4_event(&self) -> IPv4Event {
|
||||
IPv4Event {
|
||||
protocol: self.protocol,
|
||||
source_ip: self.source_ip as u32,
|
||||
destination_ip: self.destination_ip as u32,
|
||||
source_port: self.source_port,
|
||||
destination_port: self.destination_port,
|
||||
len: self.len,
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn to_ipv6_event(&self) -> IPv6Event {
|
||||
IPv6Event {
|
||||
protocol: self.protocol,
|
||||
source_ip: self.source_ip,
|
||||
destination_ip: self.destination_ip,
|
||||
source_port: self.source_port,
|
||||
destination_port: self.destination_port,
|
||||
len: self.len,
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_ipv4_event(self) -> IPv4Event {
|
||||
IPv4Event {
|
||||
protocol: self.protocol,
|
||||
source_ip: self.source_ip as u32,
|
||||
destination_ip: self.destination_ip as u32,
|
||||
source_port: self.source_port,
|
||||
destination_port: self.destination_port,
|
||||
len: self.len,
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn into_ipv6_event(self) -> IPv6Event {
|
||||
IPv6Event {
|
||||
protocol: self.protocol,
|
||||
source_ip: self.source_ip,
|
||||
destination_ip: self.destination_ip,
|
||||
source_port: self.source_port,
|
||||
destination_port: self.destination_port,
|
||||
len: self.len,
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
}
|
||||
use crate::model::ip_address::{AddrPortV4, AddrPortV6};
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub enum Event {
|
||||
IPv4(IPv4Event),
|
||||
IPv6(IPv6Event),
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub struct IPv4Event {
|
||||
pub protocol: IpProto,
|
||||
pub source_ip: u32,
|
||||
@ -79,7 +21,7 @@ pub struct IPv4Event {
|
||||
|
||||
impl IPv4Event {
|
||||
#[inline(always)]
|
||||
pub fn get_source(&self) -> AddrPortV4 {
|
||||
pub fn source_addr(&self) -> AddrPortV4 {
|
||||
AddrPortV4 {
|
||||
ip: self.source_ip,
|
||||
port: self.source_port,
|
||||
@ -87,7 +29,7 @@ impl IPv4Event {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_destination(&self) -> AddrPortV4 {
|
||||
pub fn destination_addr(&self) -> AddrPortV4 {
|
||||
AddrPortV4 {
|
||||
ip: self.destination_ip,
|
||||
port: self.destination_port,
|
||||
@ -95,6 +37,7 @@ impl IPv4Event {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub struct IPv6Event {
|
||||
pub protocol: IpProto,
|
||||
pub source_ip: u128,
|
||||
@ -107,7 +50,7 @@ pub struct IPv6Event {
|
||||
|
||||
impl IPv6Event {
|
||||
#[inline(always)]
|
||||
pub fn get_source(&self) -> AddrPortV6 {
|
||||
pub fn source_addr(&self) -> AddrPortV6 {
|
||||
AddrPortV6 {
|
||||
ip: self.source_ip,
|
||||
port: self.source_port,
|
||||
@ -115,7 +58,7 @@ impl IPv6Event {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_destination(&self) -> AddrPortV6 {
|
||||
pub fn destination_addr(&self) -> AddrPortV6 {
|
||||
AddrPortV6 {
|
||||
ip: self.destination_ip,
|
||||
port: self.destination_port,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use crate::define::other::STANDARD_MTU;
|
||||
use crate::model::event::{Event, IPv4Event, IPv6Event};
|
||||
use network_types::eth::EtherType;
|
||||
use crate::{
|
||||
define::other::STANDARD_MTU,
|
||||
model::event::Event,
|
||||
};
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub struct Packet {
|
||||
@ -10,39 +11,6 @@ pub struct Packet {
|
||||
|
||||
impl Packet {
|
||||
pub fn new(event: Event, raw_data: [u8; STANDARD_MTU]) -> Self {
|
||||
Self {
|
||||
event,
|
||||
raw_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ether_type(&self) -> EtherType {
|
||||
self.event.eth_type
|
||||
}
|
||||
|
||||
pub fn into_ipv4_packet(self) -> IPv4Packet {
|
||||
IPv4Packet {
|
||||
event: self.event.into_ipv4_event(),
|
||||
raw_data: self.raw_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_ipv6_packet(self) -> IPv6Packet {
|
||||
IPv6Packet {
|
||||
event: self.event.into_ipv6_event(),
|
||||
raw_data: self.raw_data,
|
||||
}
|
||||
Self { event, raw_data }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub struct IPv4Packet {
|
||||
pub event: IPv4Event,
|
||||
pub raw_data: [u8; STANDARD_MTU],
|
||||
}
|
||||
|
||||
#[repr(C, align(8))]
|
||||
pub struct IPv6Packet {
|
||||
pub event: IPv6Event,
|
||||
pub raw_data: [u8; STANDARD_MTU],
|
||||
}
|
||||
|
||||
@ -32,8 +32,8 @@ static IPV6_INGRESS_DST_1HOUR: LruHashMap<AddrPortV6, FlowStats> = LruHashMap::w
|
||||
|
||||
pub fn ipv4_update_stats(event: &IPv4Event) {
|
||||
unsafe {
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1MIN, &source, event);
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_10MIN, &source, event);
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1HOUR, &source, event);
|
||||
@ -45,8 +45,8 @@ pub fn ipv4_update_stats(event: &IPv4Event) {
|
||||
|
||||
pub fn ipv6_update_stats(event: &IPv6Event) {
|
||||
unsafe {
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1MIN, &source, event);
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_10MIN, &source, event);
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1HOUR, &source, event);
|
||||
|
||||
@ -3,12 +3,14 @@
|
||||
mod action;
|
||||
|
||||
use action::statistics;
|
||||
use aya_ebpf::macros::{map, xdp};
|
||||
use aya_ebpf::maps::{PerCpuArray, ProgramArray};
|
||||
use aya_ebpf::{bindings::xdp_action, programs::XdpContext};
|
||||
use aya_ebpf::{
|
||||
bindings::xdp_action,
|
||||
macros::{map, xdp},
|
||||
maps::{PerCpuArray, ProgramArray},
|
||||
programs::XdpContext,
|
||||
};
|
||||
use aya_log_ebpf::error;
|
||||
use net_guardia_common::ebpf::parsing;
|
||||
use net_guardia_common::model::event::Event;
|
||||
use net_guardia_common::{ebpf::parsing, model::event::Event};
|
||||
use network_types::eth::EtherType;
|
||||
|
||||
#[map]
|
||||
@ -18,49 +20,38 @@ static PARSED_PACKET: PerCpuArray<Event> = PerCpuArray::with_max_entries(1, 0);
|
||||
|
||||
#[xdp]
|
||||
pub fn net_guardia(ctx: XdpContext) -> u32 {
|
||||
match unsafe { parsing(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
}
|
||||
unsafe { packet_intake(ctx).unwrap_or(xdp_action::XDP_PASS) }
|
||||
}
|
||||
|
||||
unsafe fn parsing(ctx: XdpContext) -> Result<u32, ()> {
|
||||
unsafe {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let event = parsing::parse_packet(start, end)?;
|
||||
let ptr = PARSED_PACKET.get_ptr_mut(0).ok_or(())?;
|
||||
let parsed_packet = ptr.as_mut().ok_or(())?;
|
||||
*parsed_packet = event;
|
||||
if PROGRAM_ARRAY.tail_call(&ctx, 0).is_err() {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
Err(())
|
||||
unsafe fn packet_intake(ctx: XdpContext) -> Result<u32, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let ptr = PARSED_PACKET.get_ptr_mut(0).ok_or(())?;
|
||||
parsing::parse_packet(start, end, ptr)?;
|
||||
if unsafe { PROGRAM_ARRAY.tail_call(&ctx, 0).is_err() } {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
Ok(xdp_action::XDP_PASS)
|
||||
}
|
||||
|
||||
#[xdp]
|
||||
pub fn statistics(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_statistics(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
unsafe {
|
||||
try_statistics(ctx).unwrap_or(xdp_action::XDP_PASS)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn try_statistics(_: XdpContext) -> Result<u32, ()> {
|
||||
unsafe {
|
||||
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();
|
||||
statistics::ipv4_update_stats(&event);
|
||||
let parsed_packet = &*ptr;
|
||||
match parsed_packet {
|
||||
Event::IPv4(event) => {
|
||||
statistics::ipv4_update_stats(event);
|
||||
}
|
||||
EtherType::Ipv6 => {
|
||||
let event = parsed_packet.into_ipv6_event();
|
||||
statistics::ipv6_update_stats(&event);
|
||||
Event::IPv6(event) => {
|
||||
statistics::ipv6_update_stats(event);
|
||||
}
|
||||
_ => Err(())?,
|
||||
}
|
||||
Ok(xdp_action::XDP_PASS)
|
||||
}
|
||||
|
||||
@ -28,18 +28,18 @@ static IPV4_SSH_BLACK_LIST: HashMap<IPv4, PlaceHolder> = HashMap::with_max_entri
|
||||
#[map]
|
||||
static IPV6_SSH_BLACK_LIST: HashMap<IPv6, PlaceHolder> = HashMap::with_max_entries(MAX_RULES as u32, 0);
|
||||
|
||||
pub fn ipv4_service_rule_violation(start: usize, end: usize, event: IPv4Event) -> bool {
|
||||
pub fn ipv4_service_rule_violation(start: usize, end: usize, event: &IPv4Event) -> bool {
|
||||
let protocol = event.protocol;
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv4_http_service_violation(start, end, &protocol, &destination)
|
||||
|| ipv4_ssh_service_violation(&source, &destination)
|
||||
}
|
||||
|
||||
pub fn ipv6_service_rule_violation(start: usize, end: usize, event: IPv6Event) -> bool {
|
||||
pub fn ipv6_service_rule_violation(start: usize, end: usize, event: &IPv6Event) -> bool {
|
||||
let protocol = event.protocol;
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv6_http_service_violation(start, end, &protocol, &destination)
|
||||
|| ipv6_ssh_service_violation(&source, &destination)
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
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};
|
||||
@ -33,9 +32,8 @@ static IPV6_INGRESS_DST_1HOUR: LruHashMap<AddrPortV6, FlowStats> = LruHashMap::w
|
||||
|
||||
pub fn ipv4_update_stats(event: &IPv4Event) {
|
||||
unsafe {
|
||||
let now = bpf_ktime_get_ns();
|
||||
let source = event.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1MIN, &source, event);
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_10MIN, &source, event);
|
||||
ipv4_update_flow_stats(&IPV4_INGRESS_SRC_1HOUR, &source, event);
|
||||
@ -47,9 +45,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.get_source();
|
||||
let destination = event.get_destination();
|
||||
let source = event.source_addr();
|
||||
let destination = event.destination_addr();
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1MIN, &source, event);
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_10MIN, &source, event);
|
||||
ipv6_update_flow_status(&IPV6_INGRESS_SRC_1HOUR, &source, event);
|
||||
|
||||
@ -1,21 +1,24 @@
|
||||
use aya_ebpf::macros::map;
|
||||
use aya_ebpf::maps::RingBuf;
|
||||
use net_guardia_common::define::other::STANDARD_MTU;
|
||||
use net_guardia_common::define::setting::MAX_BUFFERED_PACKETS;
|
||||
use net_guardia_common::model::event::Event;
|
||||
use net_guardia_common::model::packet::Packet;
|
||||
use aya_ebpf::{macros::map, maps::RingBuf};
|
||||
use net_guardia_common::{
|
||||
define::{other::STANDARD_MTU, setting::MAX_BUFFERED_PACKETS},
|
||||
model::{event::Event, packet::Packet},
|
||||
};
|
||||
|
||||
#[map]
|
||||
static PACKET_RING: RingBuf = RingBuf::with_byte_size((MAX_BUFFERED_PACKETS * STANDARD_MTU) as u32, 0);
|
||||
|
||||
pub fn transmission(start: usize, end: usize, event: Event) -> Result<(), ()> {
|
||||
if end - start != STANDARD_MTU {
|
||||
pub fn transmission(start: usize, end: usize, event: *mut Event) -> Result<(), ()> {
|
||||
if start + STANDARD_MTU > end {
|
||||
return Err(());
|
||||
}
|
||||
if let Some(mut entry) = PACKET_RING.reserve::<Packet>(0) {
|
||||
unsafe {
|
||||
let packet_ptr = entry.as_mut_ptr();
|
||||
core::ptr::write(&mut (*packet_ptr).event, event);
|
||||
core::ptr::copy_nonoverlapping(
|
||||
event as *const u8,
|
||||
&mut (*packet_ptr).event as *mut Event as *mut u8,
|
||||
size_of::<Event>(),
|
||||
);
|
||||
core::ptr::copy_nonoverlapping(start as *const u8, (*packet_ptr).raw_data.as_mut_ptr(), STANDARD_MTU);
|
||||
}
|
||||
entry.submit(0);
|
||||
|
||||
@ -12,7 +12,6 @@ use aya_ebpf::{
|
||||
use aya_log_ebpf::error;
|
||||
use net_guardia_common::ebpf::parsing;
|
||||
use net_guardia_common::model::event::Event;
|
||||
use network_types::eth::EtherType;
|
||||
|
||||
#[map]
|
||||
static PROGRAM_ARRAY: ProgramArray = ProgramArray::with_max_entries(8, 0);
|
||||
@ -21,59 +20,51 @@ static PARSED_PACKET: PerCpuArray<Event> = PerCpuArray::with_max_entries(1, 0);
|
||||
|
||||
#[xdp]
|
||||
pub fn net_guardia(ctx: XdpContext) -> u32 {
|
||||
match unsafe { parsing(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
unsafe {
|
||||
packet_intake(ctx).unwrap_or(xdp_action::XDP_PASS)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn parsing(ctx: XdpContext) -> Result<u32, ()> {
|
||||
unsafe {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let event = parsing::parse_packet(start, end)?;
|
||||
let ptr = PARSED_PACKET.get_ptr_mut(0).ok_or(())?;
|
||||
let parsed_packet = ptr.as_mut().ok_or(())?;
|
||||
*parsed_packet = event;
|
||||
if PROGRAM_ARRAY.tail_call(&ctx, 0).is_err() {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
Err(())
|
||||
unsafe fn packet_intake(ctx: XdpContext) -> Result<u32, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let ptr = PARSED_PACKET.get_ptr_mut(0).ok_or(())?;
|
||||
parsing::parse_packet(start, end, ptr)?;
|
||||
transmission::transmission(start, end, ptr)?;
|
||||
if unsafe { PROGRAM_ARRAY.tail_call(&ctx, 0).is_err() } {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
Ok(xdp_action::XDP_PASS)
|
||||
}
|
||||
|
||||
#[xdp]
|
||||
pub fn access_control(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_access_control(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
unsafe {
|
||||
try_access_control(ctx).unwrap_or(xdp_action::XDP_PASS)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn try_access_control(ctx: XdpContext) -> Result<u32, ()> {
|
||||
unsafe {
|
||||
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 access_control::ipv4_is_whitelisted(&event) {
|
||||
let parsed_packet = &*ptr;
|
||||
match parsed_packet {
|
||||
Event::IPv4(event) => {
|
||||
if access_control::ipv4_is_whitelisted(event) {
|
||||
return Ok(xdp_action::XDP_PASS);
|
||||
}
|
||||
if access_control::ipv4_is_blacklisted(&event) {
|
||||
if access_control::ipv4_is_blacklisted(event) {
|
||||
return Ok(xdp_action::XDP_DROP);
|
||||
}
|
||||
}
|
||||
EtherType::Ipv6 => {
|
||||
let event = parsed_packet.into_ipv6_event();
|
||||
if access_control::ipv6_is_whitelisted(&event) {
|
||||
Event::IPv6(event) => {
|
||||
if access_control::ipv6_is_whitelisted(event) {
|
||||
return Ok(xdp_action::XDP_PASS);
|
||||
}
|
||||
if access_control::ipv6_is_blacklisted(&event) {
|
||||
if access_control::ipv6_is_blacklisted(event) {
|
||||
return Ok(xdp_action::XDP_DROP);
|
||||
}
|
||||
}
|
||||
_ => Err(())?,
|
||||
}
|
||||
if PROGRAM_ARRAY.tail_call(&ctx, 1).is_err() {
|
||||
error!(&ctx, "Tail call failed");
|
||||
@ -84,9 +75,8 @@ unsafe fn try_access_control(ctx: XdpContext) -> Result<u32, ()> {
|
||||
|
||||
#[xdp]
|
||||
pub fn service(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_service(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
unsafe {
|
||||
try_service(ctx).unwrap_or(xdp_action::XDP_PASS)
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,21 +85,18 @@ unsafe fn try_service(ctx: XdpContext) -> Result<u32, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
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();
|
||||
let parsed_packet = &*ptr;
|
||||
match parsed_packet {
|
||||
Event::IPv4(event) => {
|
||||
if service::ipv4_service_rule_violation(start, end, event) {
|
||||
return Ok(xdp_action::XDP_DROP);
|
||||
}
|
||||
}
|
||||
EtherType::Ipv6 => {
|
||||
let event = parsed_packet.into_ipv6_event();
|
||||
Event::IPv6(event) => {
|
||||
if service::ipv6_service_rule_violation(start, end, event) {
|
||||
return Ok(xdp_action::XDP_DROP);
|
||||
}
|
||||
}
|
||||
_ => Err(())?,
|
||||
}
|
||||
if PROGRAM_ARRAY.tail_call(&ctx, 2).is_err() {
|
||||
error!(&ctx, "Tail call failed");
|
||||
@ -118,48 +105,24 @@ unsafe fn try_service(ctx: XdpContext) -> Result<u32, ()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[xdp]
|
||||
pub fn transmission(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_transmission(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn try_transmission(ctx: XdpContext) -> Result<u32, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let ptr = PARSED_PACKET.get_ptr(0).ok_or(())?;
|
||||
let parsed_packet = ptr.read();
|
||||
transmission::transmission(start, end, parsed_packet)?;
|
||||
if unsafe { PROGRAM_ARRAY.tail_call(&ctx, 3).is_err() } {
|
||||
error!(&ctx, "Tail call failed");
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
#[xdp]
|
||||
pub fn statistics(ctx: XdpContext) -> u32 {
|
||||
match unsafe { try_statistics(ctx) } {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_PASS,
|
||||
unsafe {
|
||||
try_statistics(ctx).unwrap_or(xdp_action::XDP_PASS)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn try_statistics(_: XdpContext) -> Result<u32, ()> {
|
||||
unsafe {
|
||||
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();
|
||||
let parsed_packet = &*ptr;
|
||||
match parsed_packet {
|
||||
Event::IPv4(event) => {
|
||||
statistics::ipv4_update_stats(&event);
|
||||
}
|
||||
EtherType::Ipv6 => {
|
||||
let event = parsed_packet.into_ipv6_event();
|
||||
Event::IPv6(event) => {
|
||||
statistics::ipv6_update_stats(&event);
|
||||
}
|
||||
_ => Err(())?,
|
||||
}
|
||||
Ok(xdp_action::XDP_PASS)
|
||||
}
|
||||
|
||||
@ -91,8 +91,7 @@ impl System {
|
||||
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 ingress_ebpf, &mut ingress_program_array, "transmission", 3)?;
|
||||
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "statistics", 4)?;
|
||||
Self::load_program(&mut ingress_ebpf, &mut ingress_program_array, "statistics", 2)?;
|
||||
Ok((ingress_ebpf, ingress_program_array))
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user