mirror of https://github.com/aya-rs/aya
Create greened-test.rs
parent
aa240baadf
commit
7c4bfd1bd4
@ -0,0 +1,217 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use aya_ebpf::{
|
||||
bindings::{
|
||||
xdp_action::{self, XDP_DROP, XDP_PASS},
|
||||
BPF_F_NO_PREALLOC,
|
||||
},
|
||||
helpers::bpf_ktime_get_ns,
|
||||
macros::{map, xdp},
|
||||
maps::HashMap,
|
||||
programs::XdpContext,
|
||||
};
|
||||
use aya_log_ebpf::info;
|
||||
use core::mem;
|
||||
use network_types::{
|
||||
eth::{EthHdr, EtherType},
|
||||
ip::{IpProto, Ipv4Hdr},
|
||||
tcp::TcpHdr,
|
||||
};
|
||||
#[xdp]
|
||||
pub fn xdp_syncookie(ctx: XdpContext) -> u32 {
|
||||
match try_xdp_syncookie(ctx) {
|
||||
Ok(ret) => ret,
|
||||
Err(_) => xdp_action::XDP_ABORTED,
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct TupleIPv4 {
|
||||
pub src_address: u32,
|
||||
pub dst_address: u32,
|
||||
pub dst_port: u16,
|
||||
}
|
||||
impl TupleIPv4 {
|
||||
fn new(ipv4hdr: *mut Ipv4Hdr, tcphdr: *mut TcpHdr) -> TupleIPv4 {
|
||||
unsafe {
|
||||
TupleIPv4 {
|
||||
src_address: (*ipv4hdr).src_addr,
|
||||
dst_address: (*ipv4hdr).dst_addr,
|
||||
dst_port: (*tcphdr).dest,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[map]
|
||||
static VERIFIED_TUPLES_V4: HashMap<TupleIPv4, u8> = HashMap::<TupleIPv4, u8>::with_max_entries(1000000, BPF_F_NO_PREALLOC);
|
||||
|
||||
#[map]
|
||||
pub static IPS_WHO_HAS_SENT_SYN_BUT_DIDNT_SEND_ACK_YET: HashMap<u32, u8> = HashMap::<u32, u8>::with_max_entries(2000000, BPF_F_NO_PREALLOC);
|
||||
|
||||
fn try_xdp_syncookie(ctx: XdpContext) -> Result<u32, ()> {
|
||||
let ethhdr: *mut EthHdr = unsafe { ptr_at_mut(&ctx, 0)? };
|
||||
if unsafe { (*ethhdr).ether_type } != EtherType::Ipv4 {
|
||||
return Ok(XDP_PASS);
|
||||
}
|
||||
let ipv4hdr: *mut Ipv4Hdr = unsafe { ptr_at_mut(&ctx, EthHdr::LEN)? };
|
||||
let src_addr = u32::from_be(unsafe { (*ipv4hdr).src_addr });
|
||||
if unsafe { (*ipv4hdr).proto } != IpProto::Tcp {
|
||||
return Ok(XDP_PASS);
|
||||
}
|
||||
unsafe {
|
||||
let tcphdr: *mut TcpHdr = ptr_at_mut(&ctx, EthHdr::LEN + Ipv4Hdr::LEN)?;
|
||||
|
||||
if 25565 != u16::from_be((*tcphdr).dest) {
|
||||
return Ok(XDP_PASS);
|
||||
}
|
||||
info!(&ctx, "-------------{:i}-------------", src_addr,);
|
||||
let data_payload_len = u16::from_be((*ipv4hdr).tot_len) as u32 - (*ipv4hdr).ihl() as u32 * 4 - (*tcphdr).doff() as u32 * 4;
|
||||
|
||||
if is_handshake_syn_packet(tcphdr, &data_payload_len) {
|
||||
handle_syn_packet(&ctx, ipv4hdr, tcphdr, &data_payload_len, &src_addr)
|
||||
} else if is_handshake_ack_packet(tcphdr, (*ipv4hdr).src_addr, &data_payload_len) {
|
||||
handle_ack_packet(&ctx, ipv4hdr, tcphdr, &data_payload_len, &src_addr)
|
||||
} else {
|
||||
let tuple_ipv4 = TupleIPv4::new(ipv4hdr, tcphdr);
|
||||
|
||||
info!(
|
||||
&ctx,
|
||||
"{} non-handshake received tuple {:i} {:i} {}, {} {} {}",
|
||||
bpf_ktime_get_ns(),
|
||||
u32::from_be(tuple_ipv4.src_address),
|
||||
u32::from_be(tuple_ipv4.dst_address),
|
||||
u16::from_be(tuple_ipv4.dst_port),
|
||||
tuple_ipv4.src_address,
|
||||
tuple_ipv4.dst_address,
|
||||
tuple_ipv4.dst_port,
|
||||
);
|
||||
if VERIFIED_TUPLES_V4.get(&tuple_ipv4).is_some() {
|
||||
info!(&ctx, "tuple was in the map");
|
||||
return Ok(XDP_DROP);
|
||||
} else {
|
||||
info!(&ctx, "tuple was not in the map", src_addr);
|
||||
Ok(XDP_PASS)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn handle_syn_packet(ctx: &XdpContext, ipv4hdr: *mut Ipv4Hdr, tcphdr: *mut TcpHdr, data_payload_len: &u32, src_addr: &u32) -> Result<u32, ()> {
|
||||
info!(
|
||||
ctx,
|
||||
"Received SYN packet {:i} seq {} ack_seq {} data_len {}",
|
||||
*src_addr,
|
||||
u32::from_be((*tcphdr).seq),
|
||||
u32::from_be((*tcphdr).ack_seq),
|
||||
*data_payload_len,
|
||||
);
|
||||
if IPS_WHO_HAS_SENT_SYN_BUT_DIDNT_SEND_ACK_YET.insert(&(*ipv4hdr).src_addr, &0, 0).is_err() {
|
||||
info!(ctx, "Exceeded amount of syn map limit. just increase it...............................");
|
||||
return Ok(XDP_DROP);
|
||||
}
|
||||
Ok(XDP_PASS)
|
||||
}
|
||||
|
||||
unsafe fn handle_ack_packet(ctx: &XdpContext, ipv4hdr: *mut Ipv4Hdr, tcphdr: *mut TcpHdr, data_payload_len: &u32, src_addr: &u32) -> Result<u32, ()> {
|
||||
info!(
|
||||
ctx,
|
||||
"Received ACK packet {:i}, seq {} ack_seq {} len: {}",
|
||||
*src_addr,
|
||||
u32::from_be((*tcphdr).seq),
|
||||
u32::from_be((*tcphdr).ack_seq),
|
||||
*data_payload_len
|
||||
);
|
||||
let tuple_ipv4 = TupleIPv4::new(ipv4hdr, tcphdr);
|
||||
|
||||
info!(
|
||||
ctx,
|
||||
"{} received tuple {:i} {:i} {}, {} {} {}",
|
||||
bpf_ktime_get_ns(),
|
||||
u32::from_be(tuple_ipv4.src_address),
|
||||
u32::from_be(tuple_ipv4.dst_address),
|
||||
u16::from_be(tuple_ipv4.dst_port),
|
||||
tuple_ipv4.src_address,
|
||||
tuple_ipv4.dst_address,
|
||||
tuple_ipv4.dst_port,
|
||||
);
|
||||
info!(
|
||||
ctx,
|
||||
"{} stored tuple {:i} {:i} {}, {} {} {}",
|
||||
bpf_ktime_get_ns(),
|
||||
u32::from_be(tuple_ipv4.src_address),
|
||||
u32::from_be(tuple_ipv4.dst_address),
|
||||
u16::from_be(tuple_ipv4.dst_port),
|
||||
tuple_ipv4.src_address,
|
||||
tuple_ipv4.dst_address,
|
||||
tuple_ipv4.dst_port,
|
||||
);
|
||||
if VERIFIED_TUPLES_V4.insert(&tuple_ipv4, &0, 0).is_err() {
|
||||
info!(ctx, "Exceded max amount of tuple entries. connections might get dropped.");
|
||||
return Ok(XDP_DROP);
|
||||
}
|
||||
|
||||
Ok(XDP_PASS)
|
||||
}
|
||||
#[panic_handler]
|
||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||
unsafe { core::hint::unreachable_unchecked() }
|
||||
}
|
||||
#[inline(always)]
|
||||
pub unsafe fn ptr_at<T>(ctx: &XdpContext, offset: usize) -> Result<*const T, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let len = mem::size_of::<T>();
|
||||
|
||||
if start + offset + len > end {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let ptr = (start + offset) as *const T;
|
||||
Ok(&*ptr)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn ptr_at_mut<T>(ctx: &XdpContext, offset: usize) -> Result<*mut T, ()> {
|
||||
let start = ctx.data();
|
||||
let end = ctx.data_end();
|
||||
let len = mem::size_of::<T>();
|
||||
|
||||
if start + offset + len > end {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let ptr = (start + offset) as *mut T;
|
||||
Ok(ptr)
|
||||
}
|
||||
fn is_handshake_syn_packet(tcphdr: *mut TcpHdr, data_payload_len: &u32) -> bool {
|
||||
unsafe {
|
||||
(*tcphdr).ack() == 0
|
||||
&& (*tcphdr).syn() == 1
|
||||
&& data_payload_len == &0
|
||||
&& (*tcphdr).fin() == 0
|
||||
&& (*tcphdr).rst() == 0
|
||||
&& (*tcphdr).psh() == 0
|
||||
&& (*tcphdr).urg() == 0
|
||||
&& (*tcphdr).cwr() == 0
|
||||
&& (*tcphdr).ece() == 0
|
||||
}
|
||||
}
|
||||
fn is_handshake_ack_packet(tcphdr: *mut TcpHdr, src_addr: u32, data_payload_len: &u32) -> bool {
|
||||
unsafe {
|
||||
let result = IPS_WHO_HAS_SENT_SYN_BUT_DIDNT_SEND_ACK_YET.get(&src_addr).is_some()
|
||||
&& (*tcphdr).ack() == 1
|
||||
&& (*tcphdr).syn() == 0
|
||||
&& data_payload_len == &0
|
||||
&& (*tcphdr).fin() == 0
|
||||
&& (*tcphdr).rst() == 0
|
||||
&& (*tcphdr).psh() == 0
|
||||
&& (*tcphdr).urg() == 0
|
||||
&& (*tcphdr).cwr() == 0
|
||||
&& (*tcphdr).ece() == 0;
|
||||
if result {
|
||||
IPS_WHO_HAS_SENT_SYN_BUT_DIDNT_SEND_ACK_YET.remove(&src_addr).unwrap_or_default();
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue