Skip to content

Commit

Permalink
use network-types crate (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitris authored Feb 17, 2023
1 parent f3cc391 commit 32e69a3
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 93 deletions.
19 changes: 8 additions & 11 deletions tcbpftest-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
2 changes: 1 addition & 1 deletion tcbpftest-ebpf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
186 changes: 113 additions & 73 deletions tcbpftest-ebpf/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
#![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;

#[allow(non_upper_case_globals)]
#[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!()
Expand All @@ -38,89 +39,128 @@ pub fn tcbpftest(ctx: TcContext) -> i32 {
}
}

const ETH_P_IP: u16 = 0x0800;
const ETH_HDR_LEN: usize = mem::size_of::<ethhdr>();
const IP_HDR_LEN: usize = mem::size_of::<iphdr>();
const IPPROTO_TCP: u8 = 6;
const IPPROTO_UDP: u8 = 17;

unsafe fn try_tcbpftest(ctx: TcContext) -> Result<i32, i64> {
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::<u8>(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<T>(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::<T>();

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::<ethhdr>();
// const IP_HDR_LEN: usize = mem::size_of::<iphdr>();
//
// 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::<u8>(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<T>(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::<T>();

// if start + offset + len > end {
// return Err(());
// }

// Ok((start + offset) as *const T)
// }
13 changes: 5 additions & 8 deletions tcbpftest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);
}
}
Expand Down

0 comments on commit 32e69a3

Please sign in to comment.