Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ The default protected ports are 25000 to 26000, if you want to change that,
fully remove the arguments from the `/c/build.sh` file or change them to the port range you need.
Then recompile the project. The xdp filter will now filter on the specified port range or on 25565 if nothing is specified.

# Whitelist
You can whitelist IP addresses or CIDR ranges by adding them to the `whitelist.conf` file in the same directory as the executable.
The whitelist is loaded at startup.
Format:
```
127.0.0.1
192.168.0.0/24
```

# More
BungeeCord plugin that utilizes this filter to block ips that are causing exceptions
https://github.com/Outfluencer/Minecraft-XDP-eBPF-Server-Addon/
20 changes: 20 additions & 0 deletions c/minecraft_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@
// Minecraft server port
const __u16 ETH_IP_PROTO = __constant_htons(ETH_P_IP);

struct ipv4_lpm_key {
__u32 prefixlen;
__u32 data;
};

struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 1024);
__type(key, struct ipv4_lpm_key);
__type(value, __u32);
__uint(map_flags, BPF_F_NO_PREALLOC);
__uint(pinning, LIBBPF_PIN_BY_NAME);
} whitelist_map SEC(".maps");

struct
{
__uint(type, BPF_MAP_TYPE_LRU_HASH);
Expand Down Expand Up @@ -377,6 +391,12 @@ __s32 minecraft_filter(struct xdp_md *ctx)

__u32 src_ip = ip->saddr;

// Whitelist check
struct ipv4_lpm_key lpm_key = { .prefixlen = 32, .data = src_ip };
if (bpf_map_lookup_elem(&whitelist_map, &lpm_key)) {
return XDP_PASS;
}

// stateless new connection checks
if (tcp->syn)
{
Expand Down
47 changes: 46 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::Result;
use aya::{
Ebpf, include_bytes_aligned,
maps::{HashMap, MapData, PerCpuArray, PerCpuValues},
maps::{HashMap, MapData, PerCpuArray, PerCpuValues, LpmTrie, lpm_trie::Key},
programs::{Xdp, XdpFlags},
};
use common::{Ipv4FlowKey, Statistics};
Expand All @@ -17,6 +17,10 @@ use std::{
},
thread,
time::Duration,
fs::File,
io::{BufRead, BufReader},
net::Ipv4Addr,
str::FromStr,
};
use clap::Parser;
use file_rotate::{FileRotate, ContentLimit, compression::Compression, suffix::AppendCount};
Expand Down Expand Up @@ -249,6 +253,47 @@ fn load(
info!("Found map: {}", name);
}

// Load whitelist
let mut whitelist_map = {
let map = ebpf
.take_map("whitelist_map")
.ok_or_else(|| anyhow::anyhow!("Can't take map 'whitelist_map'"))?;
LpmTrie::<MapData, u32, u32>::try_from(map)?
};

info!("Loading whitelist from whitelist.conf...");
if let Ok(file) = File::open("whitelist.conf") {
let reader = BufReader::new(file);
for line in reader.lines() {
if let Ok(line) = line {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}

let (ip_str, prefix_len) = if let Some((ip, prefix)) = line.split_once('/') {
(ip, u32::from_str(prefix).unwrap_or(32))
} else {
(line, 32)
};

if let Ok(ip_addr) = Ipv4Addr::from_str(ip_str) {
let key = u32::from(ip_addr).to_be();
let lpm_key = Key::new(prefix_len, key);
if let Err(e) = whitelist_map.insert(&lpm_key, 1, 0) {
error!("Failed to add {}/{} to whitelist: {}", ip_str, prefix_len, e);
} else {
info!("Added {}/{} to whitelist", ip_str, prefix_len);
}
} else {
error!("Invalid IP address in whitelist: {}", ip_str);
}
}
}
} else {
error!("Could not open whitelist.conf - whitelist will be empty");
}

let player_connection_map = {
let map = ebpf
.take_map("player_connection_map")
Expand Down
7 changes: 7 additions & 0 deletions whitelist.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Whitelist configuration
# Add IP addresses or CIDR ranges to whitelist
# Examples:
# 192.168.1.100
# 10.0.0.0/24

127.0.0.1