diff --git a/test/integration-ebpf/Cargo.toml b/test/integration-ebpf/Cargo.toml index b4146daa..2c5e7b2e 100644 --- a/test/integration-ebpf/Cargo.toml +++ b/test/integration-ebpf/Cargo.toml @@ -11,6 +11,7 @@ edition.workspace = true [dependencies] aya-ebpf = { path = "../../ebpf/aya-ebpf" } aya-log-ebpf = { path = "../../ebpf/aya-log-ebpf" } +network-types = "0.0.6" [build-dependencies] which = { workspace = true } @@ -59,3 +60,7 @@ path = "src/xdp_sec.rs" [[bin]] name = "ring_buf" path = "src/ring_buf.rs" + +[[bin]] +name = "memmove_test" +path = "src/memmove_test.rs" diff --git a/test/integration-ebpf/src/memmove_test.rs b/test/integration-ebpf/src/memmove_test.rs new file mode 100644 index 00000000..c4461f77 --- /dev/null +++ b/test/integration-ebpf/src/memmove_test.rs @@ -0,0 +1,61 @@ +#![no_std] +#![no_main] + +use core::mem; + +use aya_ebpf::{ + bindings::{xdp_action, BPF_F_NO_PREALLOC}, + macros::{map, xdp}, + maps::HashMap, + programs::XdpContext, +}; +use network_types::{ + eth::{EthHdr, EtherType}, + ip::Ipv6Hdr, +}; + +#[inline(always)] +fn ptr_at(ctx: &XdpContext, offset: usize) -> Result<*const T, ()> { + let start = ctx.data(); + let end = ctx.data_end(); + let len = mem::size_of::(); + + if start + offset + len > end { + return Err(()); + } + + Ok((start + offset) as *const T) +} + +struct Value { + pub orig_ip: [u8; 16], +} + +#[map] +static RULES: HashMap = HashMap::::with_max_entries(1, BPF_F_NO_PREALLOC); + +#[xdp] +pub fn do_dnat(ctx: XdpContext) -> u32 { + try_do_dnat(ctx).unwrap_or(xdp_action::XDP_DROP) +} + +fn try_do_dnat(ctx: XdpContext) -> Result { + let index = 0; + if let Some(nat) = unsafe { RULES.get(&index) } { + let hproto: *const EtherType = ptr_at(&ctx, mem::offset_of!(EthHdr, ether_type))?; + match unsafe { *hproto } { + EtherType::Ipv6 => { + let ip_hdr: *const Ipv6Hdr = ptr_at(&ctx, EthHdr::LEN)?; + unsafe { (*ip_hdr.cast_mut()).dst_addr.in6_u.u6_addr8 = nat.orig_ip }; + } + _ => return Ok(xdp_action::XDP_PASS), + } + } + Ok(xdp_action::XDP_PASS) +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/test/integration-test/src/lib.rs b/test/integration-test/src/lib.rs index d4708033..4b55f3a1 100644 --- a/test/integration-test/src/lib.rs +++ b/test/integration-test/src/lib.rs @@ -22,6 +22,7 @@ pub const BPF_PROBE_READ: &[u8] = pub const REDIRECT: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/redirect")); pub const XDP_SEC: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/xdp_sec")); pub const RING_BUF: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/ring_buf")); +pub const MEMMOVE_TEST: &[u8] = include_bytes_aligned!(concat!(env!("OUT_DIR"), "/memmove_test")); #[cfg(test)] mod tests; diff --git a/test/integration-test/src/tests/load.rs b/test/integration-test/src/tests/load.rs index ffc8ddf7..8ff13757 100644 --- a/test/integration-test/src/tests/load.rs +++ b/test/integration-test/src/tests/load.rs @@ -282,6 +282,15 @@ fn unload_kprobe() { assert_unloaded("test_kprobe"); } +#[test] +fn memmove() { + let mut bpf = Ebpf::load(crate::MEMMOVE_TEST).unwrap(); + let prog: &mut Xdp = bpf.program_mut("do_dnat").unwrap().try_into().unwrap(); + + prog.load().unwrap(); + assert_loaded("do_dnat"); +} + #[test] fn basic_tracepoint() { let mut bpf = Ebpf::load(crate::TEST).unwrap();