Skip to content

Commit

Permalink
Merge pull request #3 from matissecallewaert/feature/ebpf-hello-world
Browse files Browse the repository at this point in the history
Feature/ebpf hello world
  • Loading branch information
matissecallewaert authored Feb 20, 2024
2 parents b10802c + a8dd54b commit 756cc85
Show file tree
Hide file tree
Showing 30 changed files with 808 additions and 92 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 --"
24 changes: 20 additions & 4 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Rust
name: Rust Aya eBPF CI

on:
push:
Expand All @@ -16,7 +16,23 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Build

- name: Set up Rust
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
components: rust-src, llvm-tools-preview
override: true

- name: Install bpf-linker
run: cargo install bpf-linker

- name: Build ingress eBPF program
run: cargo xtask ingress-ebpf

- name: Build egress eBPF program
run: cargo xtask egress-ebpf

- name: Build userspace program
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generated by Cargo
# will have compiled files and executables
/target/
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
Expand Down
13 changes: 2 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,2 @@
[package]
name = "nids-feature-extraction-tool"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.5.0", features = ["derive"] }
csv = "1.3.0"
serde = { version = "1.0.196", features = ["derive"] }
[workspace]
members = ["feature-extraction-tool", "common", "xtask"]
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,70 @@
# Real-Time Adaptive Feature Extraction for ML-Based Network Intrusion Detection

This is a feature extraction tool build in Rust using eBPF for network intrusion detection

## Install:

### Prerequisites

Make sure you have Rust installed:

```bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

Installing nightly:

```bash
rustup install stable
rustup toolchain install nightly --component rust-src
```

Installing the bpf linker
This is highly dependent on your operating system, just follow the error messages and install the requirements. For llvm you need version 18, make sure that Polly is installed with it.

```bash
sudo apt install llvm
sudo apt install llvm-dev
sudo apt install libzstd-dev
```

Make sure you are in the project root directory
```bash
cargo install --no-default-features bpf-linker
```

When you are running Ubuntu 20.04 LTS you need to run this command to avoid bugs:

```bash
sudo apt install linux-tools-5.8.0-63-generic
export PATH=/usr/lib/linux-tools/5.8.0-63-generic:$PATH
```

### Building the project

To build the eBPF programs:

```bash
cargo xtask ingress-ebpf
cargo xtask egress-ebpf
```

To build the user space programs:

```bash
cargo build
```

### Running the project

To run the program:

```bash
RUST_LOG=info cargo xtask run -- realtime <interface>
```

To now the other possibilities, run this command:

```bash
RUST_LOG=info cargo xtask run -- help
```
14 changes: 14 additions & 0 deletions common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "common"
version = "0.1.0"
edition = "2021"

[features]
default = []
user = [ "aya" ]

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

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

#[repr(C)]
#[derive(Clone, Copy)]
pub struct PacketLog {
pub ipv4_destination: u32,
pub ipv4_source: u32,
pub port_destination: u16,
pub port_source: u16,
}

#[cfg(feature = "user")]
unsafe impl aya::Pod for PacketLog {}
6 changes: 6 additions & 0 deletions egress-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"]
34 changes: 34 additions & 0 deletions egress-ebpf/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "egress-ebpf"
version = "0.1.0"
edition = "2021"

[dependencies]
aya-bpf = { git = "https://github.com/aya-rs/aya" }
aya-log-ebpf = { git = "https://github.com/aya-rs/aya" }
common = { path = "../common" }
memoffset = "0.8"
network-types = "0.0.4"

[[bin]]
name = "feature-extraction-tool-egress"
path = "src/main.rs"

[profile.dev]
opt-level = 3
debug = false
debug-assertions = false
overflow-checks = false
lto = true
panic = "abort"
incremental = false
codegen-units = 1
rpath = false

[profile.release]
lto = true
panic = "abort"
codegen-units = 1

[workspace]
members = []
2 changes: 2 additions & 0 deletions egress-ebpf/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"
75 changes: 75 additions & 0 deletions egress-ebpf/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#![no_std]
#![no_main]
#![allow(nonstandard_style, dead_code)]

use aya_bpf::{
bindings::TC_ACT_PIPE,
macros::{classifier, map},
maps::PerfEventArray,
programs::TcContext,
};

use common::PacketLog;

use network_types::{
eth::{EthHdr, EtherType},
ip::{IpProto, Ipv4Hdr},
tcp::TcpHdr,
udp::UdpHdr,
};

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

#[map]
static EVENTS_EGRESS: PerfEventArray<PacketLog> = PerfEventArray::with_max_entries(1024, 0);

#[classifier]
pub fn tc_flow_track(ctx: TcContext) -> i32 {
match try_tc_flow_track(ctx) {
Ok(ret) => ret,
Err(_) => TC_ACT_PIPE,
}
}

fn try_tc_flow_track(ctx: TcContext) -> Result<i32, ()> {
let ethhdr: EthHdr = ctx.load(0).map_err(|_| ())?;
match ethhdr.ether_type {
EtherType::Ipv4 => {}
_ => return Ok(TC_ACT_PIPE),
}

let ipv4hdr: Ipv4Hdr = ctx.load(EthHdr::LEN).map_err(|_| ())?;
let ipv4_destination = u32::from_be(ipv4hdr.dst_addr);
let ipv4_source = u32::from_be(ipv4hdr.src_addr);

let source_port;
let destination_port;
match ipv4hdr.proto {
IpProto::Tcp => {
let tcphdr: TcpHdr = ctx.load(EthHdr::LEN + Ipv4Hdr::LEN).map_err(|_| ())?;
source_port = u16::from_be(tcphdr.source);
destination_port = u16::from_be(tcphdr.dest);
}
IpProto::Udp => {
let udphdr: UdpHdr = ctx.load(EthHdr::LEN + Ipv4Hdr::LEN).map_err(|_| ())?;
source_port = u16::from_be(udphdr.source);
destination_port = u16::from_be(udphdr.dest);
}
_ => return Ok(TC_ACT_PIPE),
};

let flow = PacketLog {
ipv4_destination: ipv4_destination,
ipv4_source: ipv4_source,
port_destination: destination_port,
port_source: source_port,
};

// the zero value is a flag
EVENTS_EGRESS.output(&ctx, &flow, 0);

Ok(TC_ACT_PIPE)
}
30 changes: 30 additions & 0 deletions feature-extraction-tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "nids-feature-extraction-tool"
version = "0.1.0"
edition = "2021"
publish = false

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "4.5.0", features = ["derive"] }
csv = "1.3.0"
serde = { version = "1.0.196", features = ["derive"] }
aya = { git = "https://github.com/aya-rs/aya", features = ["async_tokio"] }
aya-log = { git = "https://github.com/aya-rs/aya"}
common = { path = "../common", features = ["user"] }
anyhow = "1"
log = "0.4"
tokio = { version = "1.25", features = [
"macros",
"rt",
"rt-multi-thread",
"net",
"signal",
] }
bytes = "1"
env_logger = "0.11"

[[bin]]
name = "feature-extraction-tool"
path = "src/main.rs"
5 changes: 4 additions & 1 deletion src/args.rs → feature-extraction-tool/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ pub struct Cli {
#[derive(Debug, Subcommand)]
pub enum Commands {
/// Real-time feature extraction
Realtime,
Realtime {
/// The network interface to capture packets from
interface: String,
},

/// Feature extraction from a dataset
Dataset {
Expand Down
Loading

0 comments on commit 756cc85

Please sign in to comment.