Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dmitris committed Jan 25, 2022
0 parents commit 8fdb654
Show file tree
Hide file tree
Showing 16 changed files with 596 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### https://raw.github.com/github/gitignore/master/Rust.gitignore

# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

.idea
.vscode
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["tcbpftest", "tcbpftest-common", "xtask"]
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# tcbpftest

## Prerequisites

1. Install a rust stable toolchain: `rustup install stable`
1. Install a rust nightly toolchain: `rustup install nightly`
1. Install bpf-linker: `cargo install bpf-linker`

## Build eBPF

```bash
cargo xtask build-ebpf
```

To perform a release build you can use the `--release` flag.
You may also change the target architecture with the `--target` flag

## Build Userspace

```bash
cargo build
```

## Run

```bash
sudo target/debug/tcbpftest
```
14 changes: 14 additions & 0 deletions tcbpftest-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "tcbpftest-common"
version = "0.1.0"
edition = "2018"

[features]
default = []
userspace = [ "aya" ]

[dependencies]
aya = { git = "https://github.com/aya-rs/aya", branch="main", optional=true }

[lib]
path = "src/lib.rs"
10 changes: 10 additions & 0 deletions tcbpftest-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![no_std]

#[repr(C)]
pub struct PacketLog {
pub len: u32, // packet length
pub src_addr: u32, // ipv4 source IP address
}

#[cfg(feature = "user")]
unsafe impl aya::Pod for PacketLog {}
6 changes: 6 additions & 0 deletions tcbpftest-ebpf/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[build]
target-dir = "../target"
target = "bpfel-unknown-none"

[unstable]
build-std = ["core"]
25 changes: 25 additions & 0 deletions tcbpftest-ebpf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "tcbpftest-ebpf"
version = "0.1.0"
edition = "2018"

[dependencies]
aya-bpf = { git = "http://github.com/aya-rs/aya", branch = "main" }
memoffset = "0.6.1"
tcbpftest-common = { path = "../tcbpftest-common" }

[[bin]]
name = "tcbpftest"
path = "src/main.rs"

[profile.dev]
panic = "abort"
debug = 1
opt-level = 2
overflow-checks = false

[profile.release]
panic = "abort"

[workspace]
members = []
189 changes: 189 additions & 0 deletions tcbpftest-ebpf/src/bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/* automatically generated by rust-bindgen 0.59.2 */

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage> {
storage: Storage,
}
impl<Storage> __BindgenBitfieldUnit<Storage> {
#[inline]
pub const fn new(storage: Storage) -> Self {
Self { storage }
}
}
impl<Storage> __BindgenBitfieldUnit<Storage>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[inline]
pub fn get_bit(&self, index: usize) -> bool {
debug_assert!(index / 8 < self.storage.as_ref().len());
let byte_index = index / 8;
let byte = self.storage.as_ref()[byte_index];
let bit_index = if cfg!(target_endian = "big") {
7 - (index % 8)
} else {
index % 8
};
let mask = 1 << bit_index;
byte & mask == mask
}
#[inline]
pub fn set_bit(&mut self, index: usize, val: bool) {
debug_assert!(index / 8 < self.storage.as_ref().len());
let byte_index = index / 8;
let byte = &mut self.storage.as_mut()[byte_index];
let bit_index = if cfg!(target_endian = "big") {
7 - (index % 8)
} else {
index % 8
};
let mask = 1 << bit_index;
if val {
*byte |= mask;
} else {
*byte &= !mask;
}
}
#[inline]
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
let mut val = 0;
for i in 0..(bit_width as usize) {
if self.get_bit(i + bit_offset) {
let index = if cfg!(target_endian = "big") {
bit_width as usize - 1 - i
} else {
i
};
val |= 1 << index;
}
}
val
}
#[inline]
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());
for i in 0..(bit_width as usize) {
let mask = 1 << i;
let val_bit_is_set = val & mask == mask;
let index = if cfg!(target_endian = "big") {
bit_width as usize - 1 - i
} else {
i
};
self.set_bit(index + bit_offset, val_bit_is_set);
}
}
}
pub type __u8 = ::aya_bpf::cty::c_uchar;
pub type __u16 = ::aya_bpf::cty::c_ushort;
pub type __u32 = ::aya_bpf::cty::c_uint;
pub type __be16 = __u16;
pub type __be32 = __u32;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct ethhdr {
pub h_dest: [::aya_bpf::cty::c_uchar; 6usize],
pub h_source: [::aya_bpf::cty::c_uchar; 6usize],
pub h_proto: __be16,
}
pub type __sum16 = __u16;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct iphdr {
pub _bitfield_align_1: [u8; 0],
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
pub tos: __u8,
pub tot_len: __be16,
pub id: __be16,
pub frag_off: __be16,
pub ttl: __u8,
pub protocol: __u8,
pub check: __sum16,
pub saddr: __be32,
pub daddr: __be32,
}
impl iphdr {
#[inline]
pub fn ihl(&self) -> __u8 {
unsafe { ::core::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u8) }
}
#[inline]
pub fn set_ihl(&mut self, val: __u8) {
unsafe {
let val: u8 = ::core::mem::transmute(val);
self._bitfield_1.set(0usize, 4u8, val as u64)
}
}
#[inline]
pub fn version(&self) -> __u8 {
unsafe { ::core::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u8) }
}
#[inline]
pub fn set_version(&mut self, val: __u8) {
unsafe {
let val: u8 = ::core::mem::transmute(val);
self._bitfield_1.set(4usize, 4u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(ihl: __u8, version: __u8) -> __BindgenBitfieldUnit<[u8; 1usize]> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default();
__bindgen_bitfield_unit.set(0usize, 4u8, {
let ihl: u8 = unsafe { ::core::mem::transmute(ihl) };
ihl as u64
});
__bindgen_bitfield_unit.set(4usize, 4u8, {
let version: u8 = unsafe { ::core::mem::transmute(version) };
version as u64
});
__bindgen_bitfield_unit
}
}

impl<Storage> __BindgenBitfieldUnit<Storage> {}
impl ethhdr {
pub fn h_dest(&self) -> Option<[::aya_bpf::cty::c_uchar; 6usize]> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.h_dest) }.ok()
}
pub fn h_source(&self) -> Option<[::aya_bpf::cty::c_uchar; 6usize]> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.h_source) }.ok()
}
pub fn h_proto(&self) -> Option<__be16> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.h_proto) }.ok()
}
}
impl iphdr {
pub fn tos(&self) -> Option<__u8> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.tos) }.ok()
}
pub fn tot_len(&self) -> Option<__be16> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.tot_len) }.ok()
}
pub fn id(&self) -> Option<__be16> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.id) }.ok()
}
pub fn frag_off(&self) -> Option<__be16> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.frag_off) }.ok()
}
pub fn ttl(&self) -> Option<__u8> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.ttl) }.ok()
}
pub fn protocol(&self) -> Option<__u8> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.protocol) }.ok()
}
pub fn check(&self) -> Option<__sum16> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.check) }.ok()
}
pub fn saddr(&self) -> Option<__be32> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.saddr) }.ok()
}
pub fn daddr(&self) -> Option<__be32> {
unsafe { ::aya_bpf::helpers::bpf_probe_read(&self.daddr) }.ok()
}
}
68 changes: 68 additions & 0 deletions tcbpftest-ebpf/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#![no_std]
#![no_main]

use aya_bpf::{
BpfContext,
macros::{map, classifier},
maps::PerfEventArray,
programs::SkBuffContext,
};
use aya_bpf::bindings::__sk_buff;

use core::convert::TryInto;
use core::mem;
use memoffset::offset_of;

use tcbpftest_common::PacketLog;

mod bindings;
use bindings::{ethhdr, iphdr};

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
unreachable!()
}

#[map(name = "EVENTS")]
static mut EVENTS: PerfEventArray<PacketLog> = PerfEventArray::<PacketLog>::with_max_entries(1024, 0);

#[classifier(name="tcbpftest")]
pub fn tcbpftest(ctx: SkBuffContext) -> i32 {
match unsafe { try_tcbpftest(ctx) } {
Ok(ret) => ret,
Err(_) => 123,
}
}

#[inline(always)]
unsafe fn ptr_at<T>(ctx: &SkBuffContext, 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)
}

unsafe fn try_tcbpftest(ctx: SkBuffContext) -> Result<i32, i64> {
let skb = ctx.as_ptr() as *const __sk_buff;
let offset : usize = 8;
let val = match ptr_at::<u16>(&ctx, offset) {
Err(_) => return Err(123),
Ok(v) => v,
};
let proto_bytes = u16::from_be(*val);
let log_entry = PacketLog {
len: u32::from_be((*skb).len),
proto: proto_bytes as u32,
};

unsafe {
EVENTS.output(&ctx, &log_entry, 0);
}
Ok(0)
}
21 changes: 21 additions & 0 deletions tcbpftest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "tcbpftest"
version = "0.1.0"
edition = "2018"
publish = false

[dependencies]
aya = { git = "https://github.com/aya-rs/aya", branch="main", features=["async_tokio"] }
tcbpftest-common = { path = "../tcbpftest-common", features=["userspace"] }
anyhow = "1.0.42"
bytes = "1.1"
ctrlc = "3.2"

structopt = { version = "0.3"}
tokio = { version = "1.5.0", features = ["macros", "rt", "rt-multi-thread", "net", "signal"] }
simplelog = "0.11"
log = "0.4"

[[bin]]
name = "tcbpftest"
path = "src/main.rs"
Loading

0 comments on commit 8fdb654

Please sign in to comment.