From 87568927918ae7bf246bfa9d9e64f8d1c2b977a3 Mon Sep 17 00:00:00 2001 From: Christian Deacon Date: Sat, 22 Feb 2025 09:50:57 -0500 Subject: [PATCH] Restructure project and organize code. --- .gitignore | 1 - Makefile | 154 ++++++++++++--------- build/.gitignore | 3 + build/loader/.gitignore | 2 + build/xdp/.gitignore | 2 + src/common/all.h | 6 + src/common/config.h | 12 ++ src/common/constants.h | 7 + src/common/int_types.h | 17 +++ src/common/types.h | 134 ++++++++++++++++++ src/{xdpfw.c => loader/loader.c} | 28 ++-- src/{ => loader/utils}/cmdline.c | 0 src/{ => loader/utils}/cmdline.h | 0 src/{ => loader/utils}/config.c | 40 +++--- src/{ => loader/utils}/config.h | 10 +- src/{utils.h => loader/utils/helpers.c} | 14 +- src/loader/utils/helpers.h | 16 +++ src/xdp/helpers.h | 8 -- src/{xdpfw_kern.c => xdp/prog.c} | 25 ++-- src/xdp/{utils.h => utils/helpers.c} | 13 +- src/xdp/utils/helpers.h | 33 +++++ src/xdp/{ => utils}/maps.h | 17 +-- src/xdp/{rl.h => utils/rl.c} | 11 +- src/xdp/utils/rl.h | 12 ++ src/xdpfw.h | 172 ------------------------ 25 files changed, 403 insertions(+), 334 deletions(-) create mode 100644 build/.gitignore create mode 100644 build/loader/.gitignore create mode 100644 build/xdp/.gitignore create mode 100644 src/common/all.h create mode 100644 src/common/config.h create mode 100644 src/common/constants.h create mode 100644 src/common/int_types.h create mode 100644 src/common/types.h rename src/{xdpfw.c => loader/loader.c} (96%) rename src/{ => loader/utils}/cmdline.c (100%) rename src/{ => loader/utils}/cmdline.h (100%) rename src/{ => loader/utils}/config.c (92%) rename src/{ => loader/utils}/config.h (65%) rename src/{utils.h => loader/utils/helpers.c} (76%) create mode 100644 src/loader/utils/helpers.h delete mode 100644 src/xdp/helpers.h rename src/{xdpfw_kern.c => xdp/prog.c} (97%) rename src/xdp/{utils.h => utils/helpers.c} (53%) create mode 100644 src/xdp/utils/helpers.h rename src/xdp/{ => utils}/maps.h (83%) rename src/xdp/{rl.h => utils/rl.c} (93%) create mode 100644 src/xdp/utils/rl.h delete mode 100644 src/xdpfw.h diff --git a/.gitignore b/.gitignore index 93f6e7d..36e04aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .vscode/ -build/ xdpfw xdpfw.s xdpfw.conf \ No newline at end of file diff --git a/Makefile b/Makefile index 89ef96b..6d538c5 100644 --- a/Makefile +++ b/Makefile @@ -3,92 +3,124 @@ LLC = llc ARCH := $(shell uname -m | sed 's/x86_64/x86/') -# Main directories. -BUILDDIR = build -SRCDIR = src -MODULEDIR = modules +# Top-level directories. +BUILD_DIR = build +SRC_DIR = src +MODULES_DIR = modules -# XDP Tools directory. -XDPTOOLSDIR = $(MODULEDIR)/xdp-tools -XDPTOOLSHEADERS = $(XDPTOOLSDIR)/headers +# Common directories. +COMMON_DIR = $(SRC_DIR)/common +LOADER_DIR = $(SRC_DIR)/loader +XDP_DIR = $(SRC_DIR)/xdp + +# Additional build directories. +BUILD_LOADER_DIR = $(BUILD_DIR)/loader +BUILD_XDP_DIR = $(BUILD_DIR)/xdp + +# XDP Tools directories. +XDP_TOOLS_DIR = $(MODULES_DIR)/xdp-tools +XDP_TOOLS_HEADERS = $(XDP_TOOLS_DIR)/headers # LibXDP and LibBPF directories. -LIBXDPDIR = $(XDPTOOLSDIR)/lib/libxdp +LIBXDP_DIR = $(XDP_TOOLS_DIR)/lib/libxdp +LIBBPF_DIR = $(XDP_TOOLS_DIR)/lib/libbpf -LIBBPFDIR = $(XDPTOOLSDIR)/lib/libbpf -LIBBPFSRC = $(LIBBPFDIR)/src +LIBBPF_SRC = $(LIBBPF_DIR)/src # LibBPF objects. -LIBBPFOBJS = $(LIBBPFSRC)/staticobjs/bpf_prog_linfo.o $(LIBBPFSRC)/staticobjs/bpf.o $(LIBBPFSRC)/staticobjs/btf_dump.o -LIBBPFOBJS += $(LIBBPFSRC)/staticobjs/btf.o $(LIBBPFSRC)/staticobjs/gen_loader.o $(LIBBPFSRC)/staticobjs/hashmap.o -LIBBPFOBJS += $(LIBBPFSRC)/staticobjs/libbpf_errno.o $(LIBBPFSRC)/staticobjs/libbpf_probes.o $(LIBBPFSRC)/staticobjs/libbpf.o -LIBBPFOBJS += $(LIBBPFSRC)/staticobjs/linker.o $(LIBBPFSRC)/staticobjs/netlink.o $(LIBBPFSRC)/staticobjs/nlattr.o -LIBBPFOBJS += $(LIBBPFSRC)/staticobjs/relo_core.o $(LIBBPFSRC)/staticobjs/ringbuf.o $(LIBBPFSRC)/staticobjs/str_error.o -LIBBPFOBJS += $(LIBBPFSRC)/staticobjs/strset.o $(LIBBPFSRC)/staticobjs/usdt.o $(LIBBPFSRC)/staticobjs/zip.o +LIBBPF_OBJS = $(LIBBPF_SRC)/staticobjs/bpf_prog_linfo.o $(LIBBPF_SRC)/staticobjs/bpf.o $(LIBBPF_SRC)/staticobjs/btf_dump.o +LIBBPF_OBJS += $(LIBBPF_SRC)/staticobjs/btf.o $(LIBBPF_SRC)/staticobjs/gen_loader.o $(LIBBPF_SRC)/staticobjs/hashmap.o +LIBBPF_OBJS += $(LIBBPF_SRC)/staticobjs/libbpf_errno.o $(LIBBPF_SRC)/staticobjs/libbpf_probes.o $(LIBBPF_SRC)/staticobjs/libbpf.o +LIBBPF_OBJS += $(LIBBPF_SRC)/staticobjs/linker.o $(LIBBPF_SRC)/staticobjs/netlink.o $(LIBBPF_SRC)/staticobjs/nlattr.o +LIBBPF_OBJS += $(LIBBPF_SRC)/staticobjs/relo_core.o $(LIBBPF_SRC)/staticobjs/ringbuf.o $(LIBBPF_SRC)/staticobjs/str_error.o +LIBBPF_OBJS += $(LIBBPF_SRC)/staticobjs/strset.o $(LIBBPF_SRC)/staticobjs/usdt.o $(LIBBPF_SRC)/staticobjs/zip.o # LibXDP objects. # To Do: Figure out why static objects produces errors relating to unreferenced functions with dispatcher. -LIBXDPOBJS = $(LIBXDPDIR)/sharedobjs/xsk.o $(LIBXDPDIR)/sharedobjs/libxdp.o +LIBXDP_OBJS = $(LIBXDP_DIR)/sharedobjs/xsk.o $(LIBXDP_DIR)/sharedobjs/libxdp.o -# Main program's objects. -CONFIGSRC = config.c -CONFIGOBJ = config.o -CMDLINESRC = cmdline.c -CMDLINEOBJ = cmdline.o +# Loader directories. +LOADER_SRC = loader.c +LOADER_OUT = xdpfw -XDPFWSRC = xdpfw.c -XDPFWOUT = xdpfw +LOADER_UTILS_DIR = $(LOADER_DIR)/utils -XDPPROGSRC = xdpfw_kern.c -XDPPROGLL = xdpfw_kern.ll -XDPPROGOBJ = xdpfw_kern.o +# Loader utils. +LOADER_UTILS_CONFIG_SRC = config.c +LOADER_UTILS_CONFIG_OBJ = config.o -OBJS = $(BUILDDIR)/$(CONFIGOBJ) $(BUILDDIR)/$(CMDLINEOBJ) +LOADER_UTILS_CMDLINE_SRC = cmdline.c +LOADER_UTILS_CMDLINE_OBJ = cmdline.o -# LD flags and includes. -LDFLAGS += -lconfig -lelf -lz -INCS = -I $(SRCDIR) -I $(LIBBPFSRC) -INCS += -I /usr/include -I /usr/local/include +LOADER_UTILS_HELPERS_SRC = helpers.c +LOADER_UTILS_HELPERS_OBJ = helpers.o -# All chain. -all: xdpfw xdpfw_filter utils +# Loader objects. +LOADER_OBJS = $(LIBXDP_OBJS) $(LIBBPF_OBJS) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ) -# User space application chain. -xdpfw: utils libxdp $(OBJS) - mkdir -p $(BUILDDIR)/ - $(CC) $(LDFLAGS) $(INCS) -o $(BUILDDIR)/$(XDPFWOUT) $(LIBBPFOBJS) $(LIBXDPOBJS) $(OBJS) $(SRCDIR)/$(XDPFWSRC) +# XDP directories. +XDP_SRC = prog.c +XDP_OBJ = xdp_prog.o -# XDP program chain. -xdpfw_filter: - mkdir -p $(BUILDDIR)/ - $(CC) $(INCS) -D__BPF__ -D __BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign -Wno-compare-distinct-pointer-types -O2 -emit-llvm -c -g -o $(BUILDDIR)/$(XDPPROGLL) $(SRCDIR)/$(XDPPROGSRC) - $(LLC) -march=bpf -filetype=obj -o $(BUILDDIR)/$(XDPPROGOBJ) $(BUILDDIR)/$(XDPPROGLL) - -# Utils chain. -utils: - mkdir -p $(BUILDDIR)/ - $(CC) $(INCS) -O2 -c -o $(BUILDDIR)/$(CONFIGOBJ) $(SRCDIR)/$(CONFIGSRC) - $(CC) $(INCS) -O2 -c -o $(BUILDDIR)/$(CMDLINEOBJ) $(SRCDIR)/$(CMDLINESRC) +XDP_UTILS_DIR = $(XDP_DIR)/utils + +# XDP utils. +XDP_UTILS_HELPERS_SRC = helpers.c +XDP_UTILS_HELPERS_OBJ = helpers.o + +XDP_UTILS_RL_SRC = rl.c +XDP_UTILS_RL_OBJ = rl.o + +# Includes. +INCS = -I $(SRC_DIR) -I $(LIBBPF_SRC) -I /usr/include -I /usr/local/include +# Flags. +FLAGS = -O2 -g +FLAGS_LOADER = -lconfig -lelf -lz + +# All chains. +all: loader xdp + +# Loader program. +loader: libxdp loader_utils + $(CC) $(INCS) $(FLAGS) $(FLAGS_LOADER) -o $(BUILD_LOADER_DIR)/$(LOADER_OUT) $(LOADER_OBJS) $(LOADER_DIR)/$(LOADER_SRC) + +loader_utils: loader_utils_config loader_utils_cmdline loader_utils_helpers + +loader_utils_config: + $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CONFIG_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CONFIG_SRC) + +loader_utils_cmdline: + $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_CMDLINE_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_CMDLINE_SRC) + +loader_utils_helpers: + $(CC) $(INCS) $(FLAGS) -c -o $(BUILD_LOADER_DIR)/$(LOADER_UTILS_HELPERS_OBJ) $(LOADER_UTILS_DIR)/$(LOADER_UTILS_HELPERS_SRC) + +# XDP program. +xdp: + $(CC) $(INCS) $(FLAGS) -target bpf -c -o $(BUILD_XDP_DIR)/$(XDP_OBJ) $(XDP_DIR)/$(XDP_SRC) # LibXDP chain. We need to install objects here since our program relies on installed object files and such. libxdp: - $(MAKE) -C $(XDPTOOLSDIR) libxdp - sudo $(MAKE) -C $(LIBBPFSRC) install - sudo $(MAKE) -C $(LIBXDPDIR) install + $(MAKE) -C $(XDP_TOOLS_DIR) libxdp + sudo $(MAKE) -C $(LIBBPF_SRC) install + sudo $(MAKE) -C $(LIBXDP_DIR) install -# Clean chain. clean: - $(MAKE) -C $(LIBBPFSRC) clean - $(MAKE) -C $(XDPTOOLSDIR) clean - rm -f $(BUILDDIR)/*.o $(BUILDDIR)/*.bc - rm -f $(BUILDDIR)/$(XDPFWOUT) + $(MAKE) -C $(XDP_TOOLS_DIR) clean + $(MAKE) -C $(LIBBPF_SRC) clean + + find $(BUILD_DIR) -type f ! -name ".*" -exec rm -f {} + + find $(BUILD_LOADER_DIR) -type f ! -name ".*" -exec rm -f {} + + find $(BUILD_XDP_DIR) -type f ! -name ".*" -exec rm -f {} + -# Install chain. install: mkdir -p /etc/xdpfw/ cp -n xdpfw.conf.example /etc/xdpfw/xdpfw.conf - cp $(BUILDDIR)/$(XDPPROGOBJ) /etc/xdpfw/$(XDPPROGOBJ) - cp $(BUILDDIR)/$(XDPFWOUT) /usr/bin/$(XDPFWOUT) + + cp -f $(BUILD_LOADER_DIR)/$(LOADER_OUT) /usr/bin + cp -f $(BUILD_XDP_DIR)/$(XDP_OBJ) /etc/xdpfw + cp -n other/xdpfw.service /etc/systemd/system/ -.PHONY: libxdp all + +.PHONY: all libxdp .DEFAULT: all \ No newline at end of file diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..5d81bf7 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!*/ \ No newline at end of file diff --git a/build/loader/.gitignore b/build/loader/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/build/loader/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/build/xdp/.gitignore b/build/xdp/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/build/xdp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/src/common/all.h b/src/common/all.h new file mode 100644 index 0000000..ec7a9c9 --- /dev/null +++ b/src/common/all.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include +#include +#include \ No newline at end of file diff --git a/src/common/config.h b/src/common/config.h new file mode 100644 index 0000000..5055bee --- /dev/null +++ b/src/common/config.h @@ -0,0 +1,12 @@ +#pragma once + +// Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map. Commenting this line out should increase performance when blocking malicious traffic. +#define DOSTATSONBLOCKMAP + +// When this is defined, a check will occur inside the IPv4 and IPv6 filters. For IPv6 packets, if no IPv6 source/destination IP addresses are set, but there is an IPv4 address, it will ignore the filter. The same goes for IPv4, if there is no IPv4 source/destination IP addresses set, if an IPv6 address is set, it will ignore the filter. +#define ALLOWSINGLEIPV4V6 + +// If uncommented, rate limits for clients are determined using the source IP, port, and protocol instead of just the source IP. +// This allows for more precise rate limits (connection-specific instead of a single source IP). +// I decided not to include the destination IP/port because the source IP, port, and protocol should be represent a unique connection. +#define USE_FLOW_RL \ No newline at end of file diff --git a/src/common/constants.h b/src/common/constants.h new file mode 100644 index 0000000..8f77026 --- /dev/null +++ b/src/common/constants.h @@ -0,0 +1,7 @@ +#pragma once + +#define MAX_PCKT_LENGTH 65535 +#define MAX_FILTERS 60 +#define MAX_TRACK_IPS 100000 +#define MAX_CPUS 256 +#define NANO_TO_SEC 1000000000 \ No newline at end of file diff --git a/src/common/int_types.h b/src/common/int_types.h new file mode 100644 index 0000000..6f0c4ee --- /dev/null +++ b/src/common/int_types.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +typedef __uint128_t u128; +typedef __u64 u64; +typedef __u32 u32; +typedef __u16 u16; +typedef __u8 u8; + +typedef __s64 s64; +typedef __s32 s32; +typedef __s16 s16; + +typedef __be64 be64; +typedef __be32 be32; +typedef __be16 be16; \ No newline at end of file diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 0000000..208894e --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,134 @@ +#pragma once + +#include + +struct tcpopts +{ + unsigned int enabled : 1; + + unsigned int do_sport : 1; + u16 sport; + + unsigned int do_dport : 1; + u16 dport; + + // TCP flags. + unsigned int do_urg : 1; + unsigned int urg : 1; + + unsigned int do_ack : 1; + unsigned int ack : 1; + + unsigned int do_rst : 1; + unsigned int rst : 1; + + unsigned int do_psh : 1; + unsigned int psh : 1; + + unsigned int do_syn : 1; + unsigned int syn : 1; + + unsigned int do_fin : 1; + unsigned int fin : 1; + + unsigned int do_ece : 1; + unsigned int ece : 1; + + unsigned int do_cwr : 1; + unsigned int cwr : 1; +}; + +struct udpopts +{ + unsigned int enabled : 1; + + unsigned int do_sport : 1; + u16 sport; + + unsigned int do_dport : 1; + u16 dport; +}; + +struct icmpopts +{ + unsigned int enabled : 1; + + unsigned int do_code : 1; + u8 code; + + unsigned int do_type : 1; + u8 type; +}; + +struct filter +{ + u8 id; + + unsigned int enabled : 1; + + u8 action; + + u32 src_ip; + u8 src_cidr; + + u32 dst_ip; + u8 dst_cidr; + + u32 src_ip6[4]; + u32 dst_ip6[4]; + + unsigned int do_min_ttl : 1; + u8 min_ttl; + + unsigned int do_max_ttl : 1; + u8 max_ttl; + + unsigned int do_min_len : 1; + u16 min_len; + + unsigned int do_max_len : 1; + u16 max_len; + + unsigned int do_tos : 1; + u8 tos; + + unsigned int do_pps : 1; + __u64 pps; + + unsigned int do_bps : 1; + __u64 bps; + + __u64 blocktime; + + struct tcpopts tcpopts; + struct udpopts udpopts; + struct icmpopts icmpopts; +} __attribute__((__aligned__(8))); + +struct stats +{ + __u64 allowed; + __u64 dropped; + __u64 passed; +}; + +struct ip_stats +{ + __u64 pps; + __u64 bps; + __u64 next_update; +}; + +struct flow +{ + u32 ip; + u16 port; + u8 protocol; +}; + +struct flow6 +{ + u128 ip; + u16 port; + u8 protocol; +}; \ No newline at end of file diff --git a/src/xdpfw.c b/src/loader/loader.c similarity index 96% rename from src/xdpfw.c rename to src/loader/loader.c index f7401ee..4ba66a1 100644 --- a/src/xdpfw.c +++ b/src/loader/loader.c @@ -20,12 +20,14 @@ #include #include -#include -#include -#include +#include + +#include +#include +#include // Other variables. -static __u8 cont = 1; +static u8 cont = 1; static int filtersmap = -1; static int statsmap = -1; @@ -44,15 +46,15 @@ void SignalHndl(int tmp) void UpdateFilters(struct config *cfg) { // Loop through all filters and delete the map. We do this in the case rules were edited and were put out of order since the key doesn't uniquely map to a specific rule. - for (__u8 i = 0; i < MAX_FILTERS; i++) + for (u8 i = 0; i < MAX_FILTERS; i++) { - __u32 key = i; + u32 key = i; bpf_map_delete_elem(filtersmap, &key); } // Add a filter to the filter maps. - for (__u32 i = 0; i < MAX_FILTERS; i++) + for (u32 i = 0; i < MAX_FILTERS; i++) { // Check if we have a valid ID. if (cfg->filters[i].id < 1) @@ -96,7 +98,7 @@ int UpdateConfig(struct config *cfg, char *cfgfile) SetCfgDefaults(cfg); - for (__u16 i = 0; i < MAX_FILTERS; i++) + for (u16 i = 0; i < MAX_FILTERS; i++) { cfg->filters[i] = (struct filter) {0}; } @@ -178,11 +180,11 @@ struct xdp_program *LoadBpfObj(const char *filename) * * @return 0 on success and 1 on error. */ -int AttachXdp(struct xdp_program *prog, int ifidx, __u8 detach, struct cmdline *cmd) +int AttachXdp(struct xdp_program *prog, int ifidx, u8 detach, struct cmdline *cmd) { int err; - __u32 mode = XDP_MODE_NATIVE; + u32 mode = XDP_MODE_NATIVE; char *smode; smode = "DRV/native"; @@ -199,7 +201,7 @@ int AttachXdp(struct xdp_program *prog, int ifidx, __u8 detach, struct cmdline * mode = XDP_MODE_SKB; } - __u8 exit = 0; + u8 exit = 0; while (!exit) { @@ -427,7 +429,7 @@ int main(int argc, char *argv[]) } // XDP variables. - const char *filename = "/etc/xdpfw/xdpfw_kern.o"; + const char *filename = "/etc/xdpfw/xdp_prog.o"; // Load BPF object. struct xdp_program *prog = LoadBpfObj(filename); @@ -518,7 +520,7 @@ int main(int argc, char *argv[]) // Update stats. if (!cfg.nostats) { - __u32 key = 0; + u32 key = 0; struct stats stats[MAX_CPUS]; //memset(stats, 0, sizeof(struct stats) * MAX_CPUS); diff --git a/src/cmdline.c b/src/loader/utils/cmdline.c similarity index 100% rename from src/cmdline.c rename to src/loader/utils/cmdline.c diff --git a/src/cmdline.h b/src/loader/utils/cmdline.h similarity index 100% rename from src/cmdline.h rename to src/loader/utils/cmdline.h diff --git a/src/config.c b/src/loader/utils/config.c similarity index 92% rename from src/config.c rename to src/loader/utils/config.c index 2c28aa2..ca0013c 100644 --- a/src/config.c +++ b/src/loader/utils/config.c @@ -1,14 +1,6 @@ -#include -#include -#include -#include -#include +#include -#include - -#include -#include -#include +#include FILE *file; @@ -26,7 +18,7 @@ void SetCfgDefaults(struct config *cfg) cfg->nostats = 0; cfg->stdout_update_time = 1000; - for (__u16 i = 0; i < MAX_FILTERS; i++) + for (u16 i = 0; i < MAX_FILTERS; i++) { cfg->filters[i].id = 0; cfg->filters[i].enabled = 0; @@ -34,7 +26,7 @@ void SetCfgDefaults(struct config *cfg) cfg->filters[i].src_ip = 0; cfg->filters[i].dst_ip = 0; - for (__u8 j = 0; j < 4; j++) + for (u8 j = 0; j < 4; j++) { cfg->filters[i].src_ip6[j] = 0; cfg->filters[i].dst_ip6[j] = 0; @@ -197,7 +189,7 @@ int ReadCfg(struct config *cfg) // Set filter count. int filters = 0; - for (__u8 i = 0; i < config_setting_length(setting); i++) + for (u8 i = 0; i < config_setting_length(setting); i++) { config_setting_t* filter = config_setting_get_elem(setting, i); @@ -259,7 +251,7 @@ int ReadCfg(struct config *cfg) inet_pton(AF_INET6, sip6, &in); - for (__u8 j = 0; j < 4; j++) + for (u8 j = 0; j < 4; j++) { cfg->filters[i].src_ip6[j] = in.__in6_u.__u6_addr32[j]; } @@ -274,7 +266,7 @@ int ReadCfg(struct config *cfg) inet_pton(AF_INET6, dip6, &in); - for (__u8 j = 0; j < 4; j++) + for (u8 j = 0; j < 4; j++) { cfg->filters[i].dst_ip6[j] = in.__in6_u.__u6_addr32[j]; } @@ -285,7 +277,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int(filter, "min_ttl", &min_ttl)) { - cfg->filters[i].min_ttl = (__u8)min_ttl; + cfg->filters[i].min_ttl = (u8)min_ttl; cfg->filters[i].do_min_ttl = 1; } @@ -294,7 +286,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int(filter, "max_ttl", &max_ttl)) { - cfg->filters[i].max_ttl = (__u8)max_ttl; + cfg->filters[i].max_ttl = (u8)max_ttl; cfg->filters[i].do_max_ttl = 1; } @@ -321,7 +313,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int(filter, "tos", &tos)) { - cfg->filters[i].tos = (__u8)tos; + cfg->filters[i].tos = (u8)tos; cfg->filters[i].do_tos = 1; } @@ -369,7 +361,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int64(filter, "tcp_sport", &tcpsport)) { - cfg->filters[i].tcpopts.sport = (__u16)tcpsport; + cfg->filters[i].tcpopts.sport = (u16)tcpsport; cfg->filters[i].tcpopts.do_sport = 1; } @@ -378,7 +370,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int64(filter, "tcp_dport", &tcpdport)) { - cfg->filters[i].tcpopts.dport = (__u16)tcpdport; + cfg->filters[i].tcpopts.dport = (u16)tcpdport; cfg->filters[i].tcpopts.do_dport = 1; } @@ -469,7 +461,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int64(filter, "udp_sport", &udpsport)) { - cfg->filters[i].udpopts.sport = (__u16)udpsport; + cfg->filters[i].udpopts.sport = (u16)udpsport; cfg->filters[i].udpopts.do_sport = 1; } @@ -478,7 +470,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int64(filter, "udp_dport", &udpdport)) { - cfg->filters[i].udpopts.dport = (__u16)udpdport; + cfg->filters[i].udpopts.dport = (u16)udpdport; cfg->filters[i].udpopts.do_dport = 1; } @@ -496,7 +488,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int(filter, "icmp_code", &icmpcode)) { - cfg->filters[i].icmpopts.code = (__u8)icmpcode; + cfg->filters[i].icmpopts.code = (u8)icmpcode; cfg->filters[i].icmpopts.do_code = 1; } @@ -505,7 +497,7 @@ int ReadCfg(struct config *cfg) if (config_setting_lookup_int(filter, "icmp_type", &icmptype)) { - cfg->filters[i].icmpopts.type = (__u8)icmptype; + cfg->filters[i].icmpopts.type = (u8)icmptype; cfg->filters[i].icmpopts.do_type = 1; } diff --git a/src/config.h b/src/loader/utils/config.h similarity index 65% rename from src/config.h rename to src/loader/utils/config.h index fbac5a0..02ddeae 100644 --- a/src/config.h +++ b/src/loader/utils/config.h @@ -1,13 +1,19 @@ #pragma once +#include + +#include +#include +#include +#include #include -#include "xdpfw.h" +#include struct config { char *interface; - __u16 updatetime; + u16 updatetime; unsigned int nostats : 1; int stdout_update_time; struct filter filters[MAX_FILTERS]; diff --git a/src/utils.h b/src/loader/utils/helpers.c similarity index 76% rename from src/utils.h rename to src/loader/utils/helpers.c index 65a06af..a9cdcb7 100644 --- a/src/utils.h +++ b/src/loader/utils/helpers.c @@ -1,16 +1,4 @@ -#pragma once - -#include -#include -#include -#include -#include - -struct ip -{ - __u32 ip; - __u32 cidr; -}; +#include /** * Parses an IP string with CIDR support. Stores IP in network byte order in ip.ip and CIDR in ip.cidr. diff --git a/src/loader/utils/helpers.h b/src/loader/utils/helpers.h new file mode 100644 index 0000000..e8e37ff --- /dev/null +++ b/src/loader/utils/helpers.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include +#include +#include +#include + +struct ip +{ + u32 ip; + u32 cidr; +}; + +struct ip ParseIp(const char *ip); \ No newline at end of file diff --git a/src/xdp/helpers.h b/src/xdp/helpers.h deleted file mode 100644 index 2114f68..0000000 --- a/src/xdp/helpers.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include \ No newline at end of file diff --git a/src/xdpfw_kern.c b/src/xdp/prog.c similarity index 97% rename from src/xdpfw_kern.c rename to src/xdp/prog.c index 466d139..104fa14 100644 --- a/src/xdpfw_kern.c +++ b/src/xdp/prog.c @@ -8,13 +8,12 @@ #include #include -#include +#include -#include +#include +#include -#include -#include -#include +#include SEC("xdp_prog") int xdp_prog_main(struct xdp_md *ctx) @@ -38,13 +37,13 @@ int xdp_prog_main(struct xdp_md *ctx) return XDP_PASS; } - __u8 action = 0; + u8 action = 0; __u64 blocktime = 1; // Initialize IP headers. struct iphdr *iph = NULL; struct ipv6hdr *iph6 = NULL; - __u128 src_ip6 = 0; + u128 src_ip6 = 0; // Set IPv4 and IPv6 common variables. if (eth->h_proto == htons(ETH_P_IPV6)) @@ -75,7 +74,7 @@ int xdp_prog_main(struct xdp_md *ctx) } // Get stats map. - __u32 key = 0; + u32 key = 0; struct stats *stats = bpf_map_lookup_elem(&stats_map, &key); __u64 now = bpf_ktime_get_ns(); @@ -122,7 +121,7 @@ int xdp_prog_main(struct xdp_md *ctx) } // Retrieve total packet length. - __u16 pkt_len = data_end - data; + u16 pkt_len = data_end - data; // Parse layer-4 headers and determine source port and protocol. struct tcphdr *tcph = NULL; @@ -130,8 +129,8 @@ int xdp_prog_main(struct xdp_md *ctx) struct icmphdr *icmph = NULL; struct icmp6hdr *icmp6h = NULL; - __u16 src_port = 0; - __u8 protocol = 0; + u16 src_port = 0; + u8 protocol = 0; if (iph6) { @@ -241,9 +240,9 @@ int xdp_prog_main(struct xdp_md *ctx) UpdateIpStats(&pps, &bps, iph->saddr, src_port, protocol, pkt_len, now); } - for (__u8 i = 0; i < MAX_FILTERS; i++) + for (u8 i = 0; i < MAX_FILTERS; i++) { - __u32 key = i; + u32 key = i; struct filter *filter = bpf_map_lookup_elem(&filters_map, &key); diff --git a/src/xdp/utils.h b/src/xdp/utils/helpers.c similarity index 53% rename from src/xdp/utils.h rename to src/xdp/utils/helpers.c index bf90987..5d5da17 100644 --- a/src/xdp/utils.h +++ b/src/xdp/utils/helpers.c @@ -1,13 +1,4 @@ -#pragma once - -#include - -#include -#include - -#ifndef memcpy -#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) -#endif +#include /** * Checks if an IP is within a specific CIDR range. @@ -18,7 +9,7 @@ * * @return 1 on yes, 0 on no. */ -static __always_inline __u8 IsIpInRange(__u32 src_ip, __u32 net_ip, __u8 cidr) +static __always_inline u8 IsIpInRange(u32 src_ip, u32 net_ip, u8 cidr) { return !((src_ip ^ net_ip) & htonl(0xFFFFFFFFu << (32 - cidr))); } \ No newline at end of file diff --git a/src/xdp/utils/helpers.h b/src/xdp/utils/helpers.h new file mode 100644 index 0000000..dbd3992 --- /dev/null +++ b/src/xdp/utils/helpers.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define htons(x) ((__be16)___constant_swab16((x))) +#define ntohs(x) ((__be16)___constant_swab16((x))) +#define htonl(x) ((__be32)___constant_swab32((x))) +#define ntohl(x) ((__be32)___constant_swab32((x))) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define htons(x) (x) +#define ntohs(X) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#endif + +#ifndef memcpy +#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) +#endif + +static __always_inline u8 IsIpInRange(u32 src_ip, u32 net_ip, u8 cidr); + +#include "helpers.c" \ No newline at end of file diff --git a/src/xdp/maps.h b/src/xdp/utils/maps.h similarity index 83% rename from src/xdp/maps.h rename to src/xdp/utils/maps.h index 293fcb2..75aac07 100644 --- a/src/xdp/maps.h +++ b/src/xdp/utils/maps.h @@ -1,8 +1,9 @@ #pragma once -#include +#include +#include -#include +#include struct { @@ -14,7 +15,7 @@ struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, MAX_FILTERS); - __type(key, __u32); + __type(key, u32); __type(value, struct filter); } filters_map SEC(".maps"); @@ -22,7 +23,7 @@ struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); - __type(key, __u32); + __type(key, u32); __type(value, struct stats); } stats_map SEC(".maps"); @@ -33,7 +34,7 @@ struct #ifdef USE_FLOW_RL __type(key, struct flow); #else - __type(key, __u32); + __type(key, u32); #endif __type(value, struct ip_stats); } ip_stats_map SEC(".maps"); @@ -42,7 +43,7 @@ struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_TRACK_IPS); - __type(key, __u32); + __type(key, u32); __type(value, __u64); } ip_blacklist_map SEC(".maps"); @@ -53,7 +54,7 @@ struct #ifdef USE_FLOW_RL __type(key, struct flow6); #else - __type(key, __u128); + __type(key, u128); #endif __type(value, struct ip_stats); } ip6_stats_map SEC(".maps"); @@ -62,6 +63,6 @@ struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_TRACK_IPS); - __type(key, __u128); + __type(key, u128); __type(value, __u64); } ip6_blacklist_map SEC(".maps"); \ No newline at end of file diff --git a/src/xdp/rl.h b/src/xdp/utils/rl.c similarity index 93% rename from src/xdp/rl.h rename to src/xdp/utils/rl.c index 9687e07..8692036 100644 --- a/src/xdp/rl.h +++ b/src/xdp/utils/rl.c @@ -1,9 +1,4 @@ -#pragma once - -#include - -#include -#include +#include /** * Updates IPv4 client stats. @@ -18,7 +13,7 @@ * * @return void */ -static __always_inline void UpdateIpStats(__u64 *pps, __u64 *bps, __u32 ip, __u16 port, __u8 protocol, __u16 pkt_len, __u64 now) +static __always_inline void UpdateIpStats(__u64 *pps, __u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, __u64 now) { #ifdef USE_FLOW_RL struct flow key = {0}; @@ -83,7 +78,7 @@ static __always_inline void UpdateIpStats(__u64 *pps, __u64 *bps, __u32 ip, __u1 * * @return void */ -static __always_inline void UpdateIp6Stats(__u64 *pps, __u64 *bps, __u128 *ip, __u16 port, __u8 protocol, __u16 pkt_len, __u64 now) +static __always_inline void UpdateIp6Stats(__u64 *pps, __u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, __u64 now) { #ifdef USE_FLOW_RL struct flow6 key = {0}; diff --git a/src/xdp/utils/rl.h b/src/xdp/utils/rl.h new file mode 100644 index 0000000..f1b9c92 --- /dev/null +++ b/src/xdp/utils/rl.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include + +#include + +static __always_inline void UpdateIpStats(__u64 *pps, __u64 *bps, u32 ip, u16 port, u8 protocol, u16 pkt_len, __u64 now); +static __always_inline void UpdateIp6Stats(__u64 *pps, __u64 *bps, u128 *ip, u16 port, u8 protocol, u16 pkt_len, __u64 now); + +#include "rl.c" \ No newline at end of file diff --git a/src/xdpfw.h b/src/xdpfw.h deleted file mode 100644 index c2cfaa6..0000000 --- a/src/xdpfw.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once - -#include - -#define MAX_PCKT_LENGTH 65535 -#define MAX_FILTERS 60 -#define MAX_TRACK_IPS 100000 -#define MAX_CPUS 256 -#define NANO_TO_SEC 1000000000 - -#define __u128 __uint128_t - -// Additional options for XDP program. -//#define DEBUG - -// Feel free to comment this out if you don't want the `blocked` entry on the stats map to be incremented every single time a packet is dropped from the source IP being on the blocked map. Commenting this line out should increase performance when blocking malicious traffic. -#define DOSTATSONBLOCKMAP - -// When this is defined, a check will occur inside the IPv4 and IPv6 filters. For IPv6 packets, if no IPv6 source/destination IP addresses are set, but there is an IPv4 address, it will ignore the filter. The same goes for IPv4, if there is no IPv4 source/destination IP addresses set, if an IPv6 address is set, it will ignore the filter. -#define ALLOWSINGLEIPV4V6 - -// If uncommented, rate limits for clients are determined using the source IP, port, and protocol instead of just the source IP. -// This allows for more precise rate limits (connection-specific instead of a single source IP). -// I decided not to include the destination IP/port because the source IP, port, and protocol should be represent a unique connection. -#define USE_FLOW_RL - -#ifdef __BPF__ -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -#define htons(x) ((__be16)___constant_swab16((x))) -#define ntohs(x) ((__be16)___constant_swab16((x))) -#define htonl(x) ((__be32)___constant_swab32((x))) -#define ntohl(x) ((__be32)___constant_swab32((x))) -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define htons(x) (x) -#define ntohs(X) (x) -#define htonl(x) (x) -#define ntohl(x) (x) -#endif -#endif - -struct tcpopts -{ - unsigned int enabled : 1; - - unsigned int do_sport : 1; - __u16 sport; - - unsigned int do_dport : 1; - __u16 dport; - - // TCP flags. - unsigned int do_urg : 1; - unsigned int urg : 1; - - unsigned int do_ack : 1; - unsigned int ack : 1; - - unsigned int do_rst : 1; - unsigned int rst : 1; - - unsigned int do_psh : 1; - unsigned int psh : 1; - - unsigned int do_syn : 1; - unsigned int syn : 1; - - unsigned int do_fin : 1; - unsigned int fin : 1; - - unsigned int do_ece : 1; - unsigned int ece : 1; - - unsigned int do_cwr : 1; - unsigned int cwr : 1; -}; - -struct udpopts -{ - unsigned int enabled : 1; - - unsigned int do_sport : 1; - __u16 sport; - - unsigned int do_dport : 1; - __u16 dport; -}; - -struct icmpopts -{ - unsigned int enabled : 1; - - unsigned int do_code : 1; - __u8 code; - - unsigned int do_type : 1; - __u8 type; -}; - -struct filter -{ - __u8 id; - - unsigned int enabled : 1; - - __u8 action; - - __u32 src_ip; - __u8 src_cidr; - - __u32 dst_ip; - __u8 dst_cidr; - - __u32 src_ip6[4]; - __u32 dst_ip6[4]; - - unsigned int do_min_ttl : 1; - __u8 min_ttl; - - unsigned int do_max_ttl : 1; - __u8 max_ttl; - - unsigned int do_min_len : 1; - __u16 min_len; - - unsigned int do_max_len : 1; - __u16 max_len; - - unsigned int do_tos : 1; - int8_t tos; - - unsigned int do_pps : 1; - __u64 pps; - - unsigned int do_bps : 1; - __u64 bps; - - __u64 blocktime; - - struct tcpopts tcpopts; - struct udpopts udpopts; - struct icmpopts icmpopts; -} __attribute__((__aligned__(8))); - -struct stats -{ - __u64 allowed; - __u64 dropped; - __u64 passed; -}; - -struct ip_stats -{ - __u64 pps; - __u64 bps; - __u64 next_update; -}; - -struct flow -{ - __u32 ip; - __u16 port; - __u8 protocol; -}; - -struct flow6 -{ - __u128 ip; - __u16 port; - __u8 protocol; -}; \ No newline at end of file