From 32e69a3abdf09d0cf91f0a770f45c6a7a31d7543 Mon Sep 17 00:00:00 2001 From: Dmitry Savintsev Date: Fri, 17 Feb 2023 16:11:26 +0100 Subject: [PATCH] use network-types crate (#17) --- tcbpftest-common/src/lib.rs | 19 ++-- tcbpftest-ebpf/Cargo.toml | 2 +- tcbpftest-ebpf/src/main.rs | 186 ++++++++++++++++++++++-------------- tcbpftest/src/main.rs | 13 +-- 4 files changed, 127 insertions(+), 93 deletions(-) diff --git a/tcbpftest-common/src/lib.rs b/tcbpftest-common/src/lib.rs index dc8f69a..89ee731 100644 --- a/tcbpftest-common/src/lib.rs +++ b/tcbpftest-common/src/lib.rs @@ -3,17 +3,14 @@ #[repr(C)] #[derive(Clone, Copy)] pub struct PacketLog { - pub len: u32, // packet length - pub ctx_len: u32, // skb length - pub src_addr: u32, // ipv4 source IP address - pub dest_addr: u32, // ipv4 destination IP address - pub eth_proto: u32, // Ethernet protocol - pub eth_proto2: u32, // skb->protocol, same as above - pub ip_proto: u32, // ipv4 protocol - pub remote_port: u32, // TCP or UDP remote port (sport for ingress) - pub remote_port2: u32, - pub local_port: u32, // TCP or UDP local port (dport for ingress) - pub local_port2: u32, + pub len: u32, // packet length + pub ctx_len: u32, // skb length + pub src_addr: u32, // ipv4 source IP address + pub dest_addr: u32, // ipv4 destination IP address + pub eth_proto: u32, // Ethernet protocol + pub ip_proto: u32, // ipv4 protocol + pub sport: u32, // TCP or UDP remote port (sport for ingress) + pub dport: u32, // TCP or UDP local port (dport for ingress) pub udp_len: u32, } diff --git a/tcbpftest-ebpf/Cargo.toml b/tcbpftest-ebpf/Cargo.toml index 13bb57a..ea67096 100644 --- a/tcbpftest-ebpf/Cargo.toml +++ b/tcbpftest-ebpf/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] aya-bpf = { git = "http://github.com/aya-rs/aya", branch = "main" } -memoffset = "0.8" +network-types = "0.0.4" tcbpftest-common = { path = "../tcbpftest-common" } [[bin]] diff --git a/tcbpftest-ebpf/src/main.rs b/tcbpftest-ebpf/src/main.rs index af374f0..bc4481f 100644 --- a/tcbpftest-ebpf/src/main.rs +++ b/tcbpftest-ebpf/src/main.rs @@ -1,16 +1,20 @@ #![no_std] #![no_main] -use aya_bpf::bindings::__sk_buff; -use aya_bpf::helpers::bpf_skb_pull_data; use aya_bpf::{ + bindings::TC_ACT_PIPE, macros::{classifier, map}, maps::PerfEventArray, programs::TcContext, - BpfContext, }; -use core::mem; -use memoffset::offset_of; + +use network_types::{ + eth::{EthHdr, EtherType}, + ip::IpProto, + ip::Ipv4Hdr, + tcp::TcpHdr, + udp::UdpHdr, +}; use tcbpftest_common::PacketLog; @@ -18,9 +22,6 @@ use tcbpftest_common::PacketLog; #[allow(non_snake_case)] #[allow(non_camel_case_types)] #[allow(dead_code)] -mod bindings; -use bindings::{ethhdr, iphdr, tcphdr, udphdr}; - #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { unreachable!() @@ -38,89 +39,128 @@ pub fn tcbpftest(ctx: TcContext) -> i32 { } } -const ETH_P_IP: u16 = 0x0800; -const ETH_HDR_LEN: usize = mem::size_of::(); -const IP_HDR_LEN: usize = mem::size_of::(); -const IPPROTO_TCP: u8 = 6; -const IPPROTO_UDP: u8 = 17; - unsafe fn try_tcbpftest(ctx: TcContext) -> Result { - let ctx_len = ctx.len(); - let skb = ctx.as_ptr() as *mut __sk_buff; - if bpf_skb_pull_data(skb, ctx_len) != 0 { - return Err(199); - } - // get the ethernet header proto field as well as the IP protocol one - let eth_proto = u16::from_be(ctx.load(offset_of!(ethhdr, h_proto))?); - let eth_proto2 = u32::from_be((*skb).protocol); - let ip_proto = ctx.load::(ETH_HDR_LEN + offset_of!(iphdr, protocol))?; - if !(eth_proto == ETH_P_IP && (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP)) { - return Ok(0); + let ethhdr: EthHdr = ctx.load(0).map_err(|_| -1)?; + match ethhdr.ether_type { + EtherType::Ipv4 => {} + _ => return Ok(TC_ACT_PIPE), } - let length = u16::from_be(ctx.load(ETH_HDR_LEN + offset_of!(iphdr, tot_len))?); - let saddr = u32::from_be(ctx.load(ETH_HDR_LEN + offset_of!(iphdr, saddr))?); - let daddr = u32::from_be(ctx.load(ETH_HDR_LEN + offset_of!(iphdr, daddr))?); - let rem_port2 = u16::from_be(ctx.load(ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, source))?); - let loc_port2 = u16::from_be(ctx.load(ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, dest))?); + let ipv4hdr: Ipv4Hdr = ctx.load(EthHdr::LEN).map_err(|_| -1)?; - let rem_port_val: u16; - let loc_port_val: u16; - unsafe { - rem_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, source)) { - Err(_) => return Err(197), - Ok(val) => *val, - }; - loc_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, dest)) { - Err(_) => return Err(198), - Ok(val) => *val, - }; - } - let rem_port = u16::from_be(rem_port_val); - let loc_port = u16::from_be(loc_port_val); + let saddr = u32::from_be(ipv4hdr.src_addr); + let daddr = u32::from_be(ipv4hdr.dst_addr); let mut udp_len_val: u16 = 0; - if ip_proto == IPPROTO_UDP { - unsafe { - udp_len_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(udphdr, len)) { - Err(_) => return Err(197), - Ok(val) => *val, - }; + let sport: u16; + let dport: u16; + match ipv4hdr.proto { + IpProto::Tcp => { + let tcphdr: TcpHdr = ctx.load(EthHdr::LEN + Ipv4Hdr::LEN).map_err(|_| -1)?; + + // pass unless the SYN flag is set and ACK - not set + if tcphdr.syn() == 0 || tcphdr.ack() != 0 { + return Ok(TC_ACT_PIPE); + } + sport = u16::from_be(tcphdr.source); + dport = u16::from_be(tcphdr.dest); } - } + IpProto::Udp => { + let udphdr: UdpHdr = ctx.load(EthHdr::LEN + Ipv4Hdr::LEN).map_err(|_| -1)?; + sport = u16::from_be(udphdr.source); + dport = u16::from_be(udphdr.dest); + udp_len_val = udphdr.len; + } + _ => return Ok(TC_ACT_PIPE), + }; let log_entry = PacketLog { - len: length as u32, - ctx_len: ctx_len, + len: u16::from_be(ipv4hdr.tot_len) as u32, + ctx_len: ctx.len(), src_addr: saddr, dest_addr: daddr, - eth_proto: eth_proto as u32, - eth_proto2: eth_proto2 as u32, - ip_proto: ip_proto as u32, - remote_port: rem_port as u32, - remote_port2: rem_port2 as u32, - local_port: loc_port as u32, - local_port2: loc_port2 as u32, + eth_proto: u16::from_be(ethhdr.ether_type as u16) as u32, + ip_proto: u16::from_be(ipv4hdr.proto as u16) as u32, + sport: sport as u32, + dport: dport as u32, udp_len: u16::from_be(udp_len_val) as u32, }; unsafe { EVENTS.output(&ctx, &log_entry, 0); } - Ok(0) + Ok(TC_ACT_PIPE) } // TODO: add en example with using the bpf_skb_pull_data helper and then ptr_at // -#[inline(always)] -unsafe fn ptr_at(ctx: &TcContext, offset: usize) -> Result<*const T, ()> { - let raw_skb = ctx.as_ptr() as *const __sk_buff; - let start = (*raw_skb).data as usize; - let end = (*raw_skb).data_end as usize; - let len = mem::size_of::(); - - if start + offset + len > end { - return Err(()); - } +// use aya_bpf::helpers::bpf_skb_pull_data; +// +// mod bindings; +// use bindings::{ethhdr, iphdr, tcphdr, udphdr}; +// +// const ETH_HDR_LEN: usize = mem::size_of::(); +// const IP_HDR_LEN: usize = mem::size_of::(); +// +// let ctx_len = ctx.len(); +// let skb = ctx.as_ptr() as *mut __sk_buff; +// if bpf_skb_pull_data(skb, ctx_len) != 0 { +// return Err(199); +// } +// get the ethernet header proto field as well as the IP protocol one +// let eth_proto = u16::from_be(ctx.load(offset_of!(ethhdr, h_proto))?); +// let eth_proto2 = u32::from_be((*skb).protocol); +// let ip_proto = ctx.load::(ETH_HDR_LEN + offset_of!(iphdr, protocol))?; +// let saddr = u32::from_be(ctx.load(ETH_HDR_LEN + offset_of!(iphdr, saddr))?); +// let daddr = u32::from_be(ctx.load(ETH_HDR_LEN + offset_of!(iphdr, daddr))?); +// let rem_port_val: u16; +// let loc_port_val: u16; +// unsafe { +// rem_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, source)) { +// Err(_) => return Err(197), +// Ok(val) => *val, +// }; +// loc_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, dest)) { +// Err(_) => return Err(198), +// Ok(val) => *val, +// }; +// } +// let rem_port = u16::from_be(rem_port_val); +// let loc_port = u16::from_be(loc_port_val); - Ok((start + offset) as *const T) -} +// let mut udp_len_val: u16 = 0; +// if ipv4hdr.proto == IpProto::Udp { +// unsafe { +// udp_len_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(udphdr, len)) { +// Err(_) => return Err(197), +// Ok(val) => *val, +// }; +// } +// } +// let rem_port_val: u16; +// let loc_port_val: u16; +// unsafe { +// rem_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, source)) { +// Err(_) => return Err(197), +// Ok(val) => *val, +// }; +// loc_port_val = match ptr_at(&ctx, ETH_HDR_LEN + IP_HDR_LEN + offset_of!(tcphdr, dest)) { +// Err(_) => return Err(198), +// Ok(val) => *val, +// }; +// } +// let rem_port = u16::from_be(rem_port_val); +// let loc_port = u16::from_be(loc_port_val); + +// #[inline(always)] +// unsafe fn ptr_at(ctx: &TcContext, offset: usize) -> Result<*const T, ()> { +// let raw_skb = ctx.as_ptr() as *const __sk_buff; +// let start = (*raw_skb).data as usize; +// let end = (*raw_skb).data_end as usize; +// let len = mem::size_of::(); + +// if start + offset + len > end { +// return Err(()); +// } + +// Ok((start + offset) as *const T) +// } diff --git a/tcbpftest/src/main.rs b/tcbpftest/src/main.rs index efd8eb4..023ae17 100644 --- a/tcbpftest/src/main.rs +++ b/tcbpftest/src/main.rs @@ -75,19 +75,16 @@ async fn main() -> Result<(), anyhow::Error> { let ptr = buf.as_ptr() as *const PacketLog; let data = unsafe { ptr.read_unaligned() }; println!( - "LOG: LEN {}, CTX_LEN {}, UDP_LEN {}, SRC_IP {}, DEST_IP {}, ETH_PROTO 0x{:X}, ETH_PROTO2 0x{:X}, IP_PROTO {}, REMOTE_PORT {}, REMOTE_PORT2 {}, LOCAL_PORT {}, LOCAL_PORT2 {}", + "LOG: LEN {}, CTX_LEN {}, UDP_LEN {}, SRC_IP {}, DEST_IP {}, ETH_PROTO 0x{:X}, IP_PROTO {}, SRC_PORT {}, DEST_PORT {}", data.len, data.ctx_len, data.udp_len, Ipv4Addr::from(data.src_addr), Ipv4Addr::from(data.dest_addr), - data.eth_proto, - data.eth_proto2, - data.ip_proto, - data.remote_port, - data.remote_port2, - data.local_port, - data.local_port2, + data.eth_proto, + data.ip_proto, + data.sport, + data.dport, ); } }