From bff697dc174a18999186b4bbd2493372007ff669 Mon Sep 17 00:00:00 2001 From: ppom Date: Mon, 5 Feb 2024 12:00:00 +0100 Subject: [PATCH] Add support for nftables --- .gitignore | 1 + Makefile | 21 ++--- {ip46tables.d => helpers_c}/ip46tables.c | 0 helpers_c/nft46.c | 97 ++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 9 deletions(-) rename {ip46tables.d => helpers_c}/ip46tables.c (100%) create mode 100644 helpers_c/nft46.c diff --git a/.gitignore b/.gitignore index 2c1daf4..6f59e6c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /deb *.deb *.minisig +*.qcow2 diff --git a/Makefile b/Makefile index c7b31d7..cefd9a3 100644 --- a/Makefile +++ b/Makefile @@ -3,22 +3,24 @@ PREFIX ?= /usr/local BINDIR = $(PREFIX)/bin SYSTEMDDIR ?= /etc/systemd -all: reaction ip46tables +all: reaction ip46tables nft46 clean: rm -f reaction ip46tables reaction.deb deb reaction.minisig ip46tables.minisig reaction.deb.minisig -ip46tables: ip46tables.d/ip46tables.c - $(CC) -s -static ip46tables.d/ip46tables.c -o ip46tables +ip46tables: helpers_c/ip46tables.c + $(CC) -s -static helpers_c/ip46tables.c -o ip46tables + +nft46: helpers_c/nft46.c + $(CC) -s -static helpers_c/nft46.c -o nft46 reaction: app/* reaction.go go.mod go.sum CGO_ENABLED=0 go build -buildvcs=false -ldflags "-s -X main.version=`git tag --sort=v:refname | tail -n1` -X main.commit=`git rev-parse --short HEAD`" -reaction.deb: reaction ip46tables - chmod +x reaction ip46tables +reaction.deb: reaction ip46tables nft46 + chmod +x reaction ip46tables nft46 mkdir -p deb/reaction/usr/bin/ deb/reaction/usr/sbin/ deb/reaction/lib/systemd/system/ - cp reaction deb/reaction/usr/bin/ - cp ip46tables deb/reaction/usr/sbin/ + cp reaction ip46tables nft46 deb/reaction/usr/bin/ cp config/reaction.debian.service deb/reaction/lib/systemd/system/reaction.service cp -r DEBIAN/ deb/reaction/DEBIAN sed -e "s/LAST_TAG/`git tag --sort=v:refname | tail -n1`/" -e "s/Version: v/Version: /" -i deb/reaction/DEBIAN/* @@ -26,12 +28,13 @@ reaction.deb: reaction ip46tables mv deb/reaction.deb reaction.deb rm -rf deb/ -signatures: reaction.deb reaction ip46tables - minisign -Sm ip46tables reaction reaction.deb +signatures: reaction.deb reaction ip46tables nft46 + minisign -Sm ip46tables nft46 reaction reaction.deb install: all install -m755 reaction $(DESTDIR)$(BINDIR) install -m755 ip46tables $(DESTDIR)$(BINDIR) + install -m755 nft46 $(DESTDIR)$(BINDIR) install_systemd: install install -m644 config/reaction.debian.service $(SYSTEMDDIR)/system/reaction.service diff --git a/ip46tables.d/ip46tables.c b/helpers_c/ip46tables.c similarity index 100% rename from ip46tables.d/ip46tables.c rename to helpers_c/ip46tables.c diff --git a/helpers_c/nft46.c b/helpers_c/nft46.c new file mode 100644 index 0000000..1df7c15 --- /dev/null +++ b/helpers_c/nft46.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include +#include +#include + +// nft46 'add element inet reaction ipvXbans { 1.2.3.4 }' → nft 'add element inet reaction ipv4bans { 1.2.3.4 }' +// nft46 'add element inet reaction ipvXbans { a:b::c:d }' → nft 'add element inet reaction ipv6bans { a:b::c:d }' +// +// the character X is replaced by 4 or 6 depending on the address family of the specified IP +// +// Limitations: +// - nft46 must receive exactly one argument +// - only one IP must be given per command +// - the IP must be between { braces } + +int isIPv4(char *tab, int len) { + int i; + // IPv4 addresses are at least 7 chars long + if (len < 7 || !isdigit(tab[0]) || !isdigit(tab[len-1])) { + return 0; + } + // Each char must be a digit or a dot between 2 digits + for (i=1; i= 'a' && tab[i] <= 'f') && !(tab[i] >= 'A' && tab[i] <= 'F')) { + return 0; + } + } + return 1; +} + +int findchar(char *tab, char c, int i, int len) { + while (i < len && tab[i] != c) i++; + if (i == len) { + printf("nft46: one %c must be present", c); + exit(1); + } + return i; +} + +void adapt_args(char *tab) { + int i, len, X, startIP, endIP, startedIP; + X = startIP = endIP = -1; + startedIP = 0; + len = strlen(tab); + i = 0; + X = i = findchar(tab, 'X', i, len); + startIP = i = findchar(tab, '{', i, len); + while (startIP + 1 <= (i = findchar(tab, ' ', i, len))) startIP = i + 1; + i = startIP; + endIP = i = findchar(tab, ' ', i, len) - 1; + + if (isIPv4(tab+startIP, endIP-startIP+1)) { + tab[X] = '4'; + return; + } + + if (isIPv6(tab+startIP, endIP-startIP+1)) { + tab[X] = '6'; + return; + } + + printf("nft46: no IP address found\n"); + exit(1); +} + +int exec(char *str, char **argv) { + argv[0] = str; + execvp(str, argv); + // returns only if fails + printf("nft46: exec failed %d\n", errno); +} + +int main(int argc, char **argv) { + if (argc != 2) { + printf("nft46: Exactly one argument must be given\n"); + exit(1); + } + adapt_args(argv[1]); + exec("nft", argv); +}