gluon-ebtables-limit-arp: switch to nftables

This commit is contained in:
Maciej Krüger 2023-04-26 00:39:03 +02:00
parent 3a7115149c
commit 72a9a2a042
No known key found for this signature in database
GPG Key ID: 0D948CE19CF49C5F
18 changed files with 94 additions and 52 deletions

View File

@ -1,3 +0,0 @@
chain('ARP_LIMIT', 'DROP')
chain('ARP_LIMIT_DATCHECK', 'RETURN')
chain('ARP_LIMIT_TLCHECK', 'RETURN')

View File

@ -1,6 +0,0 @@
rule('ARP_LIMIT -j ARP_LIMIT_DATCHECK')
rule('ARP_LIMIT --mark 0x2/0x2 -j RETURN')
rule('ARP_LIMIT -j ARP_LIMIT_TLCHECK')
rule('ARP_LIMIT --limit 1/sec --limit-burst 50 -j RETURN')
rule('FORWARD -p ARP --logical-out br-client -o bat0 --arp-op Request -j ARP_LIMIT')

View File

@ -1,4 +1,4 @@
include('mesh_vpn_dns', { include('mesh_vpn_dns', {
position = 'chain-prepend', position = 'chain-pre',
chain = 'dstnat', chain = 'dstnat',
}) })

View File

@ -1,16 +1,16 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-ebtables-limit-arp PKG_NAME:=gluon-nftables-limit-arp
include ../gluon.mk include ../gluon.mk
define Package/gluon-ebtables-limit-arp define Package/gluon-nftables-limit-arp
TITLE:=Ebtables limiter for ARP packets TITLE:=nftables limiter for ARP packets
DEPENDS:=+gluon-core +gluon-ebtables gluon-mesh-batman-adv DEPENDS:=+gluon-core +gluon-nftables +gluon-mesh-batman-adv
endef endef
define Package/gluon-ebtables-limit-arp/description define Package/gluon-nftables-limit-arp/description
Gluon community wifi mesh firmware framework: Ebtables rules to Gluon community wifi mesh firmware framework: nftables rules to
rate-limit ARP packets. rate-limit ARP packets.
This package adds filters to limit the amount of ARP Requests This package adds filters to limit the amount of ARP Requests
@ -19,7 +19,7 @@ define Package/gluon-ebtables-limit-arp/description
node in total. node in total.
A burst of up to 50 ARP Requests is allowed until the rate-limiting A burst of up to 50 ARP Requests is allowed until the rate-limiting
takes effect (see --limit-burst in the ebtables manpage). takes effect (see burst in the nft manpage).
Furthermore, ARP Requests with a target IP already present in the Furthermore, ARP Requests with a target IP already present in the
batman-adv DAT Cache are excluded from the rate-limiting, batman-adv DAT Cache are excluded from the rate-limiting,
@ -30,13 +30,15 @@ define Package/gluon-ebtables-limit-arp/description
However it should mitigate the problem of curious people or However it should mitigate the problem of curious people or
smart devices scanning the whole IP range. Which could create smart devices scanning the whole IP range. Which could create
a significant amount of overhead for all participants so far. a significant amount of overhead for all participants so far.
Note that this package currently only supports batman.
endef endef
define Package/gluon-ebtables-limit-arp/install define Package/gluon-nftables-limit-arp/install
$(Gluon/Build/Install) $(Gluon/Build/Install)
$(INSTALL_DIR) $(1)/usr/sbin/ $(INSTALL_DIR) $(1)/usr/sbin/
$(CP) $(PKG_BUILD_DIR)/gluon-arp-limiter $(1)/usr/sbin/gluon-arp-limiter $(CP) $(PKG_BUILD_DIR)/gluon-arp-limiter $(1)/usr/sbin/gluon-arp-limiter
endef endef
$(eval $(call BuildPackageGluon,gluon-ebtables-limit-arp)) $(eval $(call BuildPackageGluon,gluon-nftables-limit-arp))

View File

@ -0,0 +1,61 @@
set limitmac {
type ether_addr
}
set datips {
type ipv4_addr
}
# Rewrite arp packet target hardware address if target protocol address matches a given address.
# input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566 accept
# chain('ARP_LIMIT', 'DROP')
chain arplimit {
# obrname "br-client" \
# oifname "bat0" \
# arp operation request \
# counter
# match everything which will land on bridge br-client
# protocol type: ipv4
# hardware type: ethernet
# hardware address length: 6 byte mac
# protocol address length: 4 byte ipv4
# arp request
# source address is mac to be limited
# target address is not in DAT
# we're over the limit
# count
# obrname "br-client" \
# oifname "bat0" \
arp ptype 0x0800 \
arp htype 1 \
arp hlen 6 \
arp plen 4 \
arp operation request \
arp saddr ether @limitmac \
arp daddr ip != @datips \
limit rate over 6/minute burst 50 packets \
counter \
drop
# obrname "br-client" \
# oifname "bat0" \
arp ptype 0x0800 \
arp htype 1 \
arp hlen 6 \
arp plen 4 \
arp operation request \
arp saddr ether != @limitmac \
arp daddr ip != @datips \
limit rate over 1/second burst 50 packets \
counter \
drop
}
# chain('ARP_LIMIT_DATCHECK', 'RETURN')
# %s ARP_LIMIT_DATCHECK -p ARP --arp-ip-dst %s -j mark --mark-or 0x2 --mark-target RETURN
# chain('ARP_LIMIT_TLCHECK', 'RETURN')
# %s ARP_LIMIT_TLCHECK --source %s --limit 6/min --limit-burst 50 -j RETURN"
# %s ARP_LIMIT_TLCHECK (add ? "2" : "") --source %s -j DROP

View File

@ -0,0 +1,6 @@
-- include('limit_arp', {
-- position = 'ruleset-pre'
-- })
bridge_include_table('pre', 'limit_arp_chain')
bridge_rule('FORWARD', 'oifname "bat0" obrname "br-client" arp operation request counter jump arplimit')

View File

@ -14,7 +14,7 @@
#define BATCTL_DC "/usr/sbin/batctl dc -H -n" #define BATCTL_DC "/usr/sbin/batctl dc -H -n"
#define BATCTL_TL "/usr/sbin/batctl tl -H -n" #define BATCTL_TL "/usr/sbin/batctl tl -H -n"
#define EBTABLES "/usr/sbin/ebtables" #define NFTABLES "/usr/sbin/nft"
#define BUILD_BUG_ON(check) ((void)sizeof(int[1-2*!!(check)])) #define BUILD_BUG_ON(check) ((void)sizeof(int[1-2*!!(check)]))
@ -39,13 +39,13 @@ static void ebt_ip_call(char *mod, struct in_addr ip)
int ret; int ret;
snprintf(str, sizeof(str), snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_DATCHECK -p ARP --arp-ip-dst %s -j mark --mark-or 0x2 --mark-target RETURN", NFTABLES " %s element bridge gluon datips { %s }",
mod, inet_ntoa(ip)); mod, inet_ntoa(ip));
ret = system(str); ret = system(str);
if (ret) if (ret)
fprintf(stderr, fprintf(stderr,
"%i: Calling ebtables for DAT failed with status %i\n", "%i: Calling nft for DAT failed with status %i\n",
clock, ret); clock, ret);
} }
@ -53,7 +53,7 @@ static void ip_node_destructor(struct addr_list *node)
{ {
struct in_addr *ip = (struct in_addr *)node->addr; struct in_addr *ip = (struct in_addr *)node->addr;
ebt_ip_call("-D", *ip); ebt_ip_call("delete", *ip);
} }
static void ebt_mac_limit_call(char *mod, struct mac_addr *mac) static void ebt_mac_limit_call(char *mod, struct mac_addr *mac)
@ -62,40 +62,22 @@ static void ebt_mac_limit_call(char *mod, struct mac_addr *mac)
int ret; int ret;
snprintf(str, sizeof(str), snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_TLCHECK --source %s --limit 6/min --limit-burst 50 -j RETURN", NFTABLES " %s element bridge gluon limitmac { %s }",
mod, mac_ntoa(mac)); mod, mac_ntoa(mac));
ret = system(str); ret = system(str);
if (ret) if (ret)
fprintf(stderr, fprintf(stderr,
"%i: Calling ebtables for TL failed with status %i\n", "%i: Calling nft for TL failed with status %i\n",
clock, ret);
}
static void ebt_mac_ret_call(char *mod, struct mac_addr *mac, int add)
{
char str[128];
int ret;
snprintf(str, sizeof(str),
EBTABLES " %s ARP_LIMIT_TLCHECK %s --source %s -j DROP",
mod, add ? "2" : "", mac_ntoa(mac));
ret = system(str);
if (ret)
fprintf(stderr,
"%i: Calling ebtables for TL failed with status %i\n",
clock, ret); clock, ret);
} }
static void ebt_mac_call(char *mod, struct mac_addr *mac) static void ebt_mac_call(char *mod, struct mac_addr *mac)
{ {
if (!strncmp(mod, "-D", strlen(mod))) { if (!strncmp(mod, "delete", strlen(mod))) {
ebt_mac_ret_call(mod, mac, 0);
ebt_mac_limit_call(mod, mac); ebt_mac_limit_call(mod, mac);
} else { } else {
ebt_mac_limit_call(mod, mac); ebt_mac_limit_call(mod, mac);
ebt_mac_ret_call(mod, mac, 1);
} }
} }
@ -103,7 +85,7 @@ static void mac_node_destructor(struct addr_list *node)
{ {
struct mac_addr *mac = (struct mac_addr *)node->addr; struct mac_addr *mac = (struct mac_addr *)node->addr;
ebt_mac_call("-D", mac); ebt_mac_call("delete", mac);
} }
static int dat_parse_line(const char *line, struct in_addr *ip) static int dat_parse_line(const char *line, struct in_addr *ip)
@ -141,7 +123,7 @@ static void ebt_add_ip(struct in_addr ip)
if (ret) if (ret)
return; return;
ebt_ip_call("-I", ip); ebt_ip_call("add", ip);
} }
static void ebt_add_mac(struct mac_addr *mac) static void ebt_add_mac(struct mac_addr *mac)
@ -152,7 +134,7 @@ static void ebt_add_mac(struct mac_addr *mac)
if (ret) if (ret)
return; return;
ebt_mac_call("-I", mac); ebt_mac_call("add", mac);
} }
static void ebt_dat_update(void) static void ebt_dat_update(void)
@ -168,7 +150,7 @@ static void ebt_dat_update(void)
fprintf(stderr, "%i: Error: Could not call batctl dc\n", clock); fprintf(stderr, "%i: Error: Could not call batctl dc\n", clock);
return; return;
} }
while (1) { while (1) {
pline = fgets(line, sizeof(line), fp); pline = fgets(line, sizeof(line), fp);
if (!pline) { if (!pline) {
@ -257,18 +239,18 @@ static void ebt_tl_update(void)
static void ebt_dat_flush(void) static void ebt_dat_flush(void)
{ {
int ret = system(EBTABLES " -F ARP_LIMIT_DATCHECK"); int ret = system(NFTABLES " flush set bridge gluon datips");
if (ret) if (ret)
fprintf(stderr, "Error flushing ARP_LIMIT_DATCHECK\n"); fprintf(stderr, "Error flushing arplimit datips set\n");
} }
static void ebt_tl_flush(void) static void ebt_tl_flush(void)
{ {
int ret = system(EBTABLES " -F ARP_LIMIT_TLCHECK"); int ret = system(NFTABLES " flush set bridge gluon limitmac");
if (ret) if (ret)
fprintf(stderr, "Error flushing ARP_LIMIT_TLCHECK\n"); fprintf(stderr, "Error flushing arplimit limitmac\n");
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])