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', {
position = 'chain-prepend',
position = 'chain-pre',
chain = 'dstnat',
})

View File

@ -1,16 +1,16 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-ebtables-limit-arp
PKG_NAME:=gluon-nftables-limit-arp
include ../gluon.mk
define Package/gluon-ebtables-limit-arp
TITLE:=Ebtables limiter for ARP packets
DEPENDS:=+gluon-core +gluon-ebtables gluon-mesh-batman-adv
define Package/gluon-nftables-limit-arp
TITLE:=nftables limiter for ARP packets
DEPENDS:=+gluon-core +gluon-nftables +gluon-mesh-batman-adv
endef
define Package/gluon-ebtables-limit-arp/description
Gluon community wifi mesh firmware framework: Ebtables rules to
define Package/gluon-nftables-limit-arp/description
Gluon community wifi mesh firmware framework: nftables rules to
rate-limit ARP packets.
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.
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
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
smart devices scanning the whole IP range. Which could create
a significant amount of overhead for all participants so far.
Note that this package currently only supports batman.
endef
define Package/gluon-ebtables-limit-arp/install
define Package/gluon-nftables-limit-arp/install
$(Gluon/Build/Install)
$(INSTALL_DIR) $(1)/usr/sbin/
$(CP) $(PKG_BUILD_DIR)/gluon-arp-limiter $(1)/usr/sbin/gluon-arp-limiter
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_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)]))
@ -39,13 +39,13 @@ static void ebt_ip_call(char *mod, struct in_addr ip)
int ret;
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));
ret = system(str);
if (ret)
fprintf(stderr,
"%i: Calling ebtables for DAT failed with status %i\n",
"%i: Calling nft for DAT failed with status %i\n",
clock, ret);
}
@ -53,7 +53,7 @@ static void ip_node_destructor(struct addr_list *node)
{
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)
@ -62,40 +62,22 @@ static void ebt_mac_limit_call(char *mod, struct mac_addr *mac)
int ret;
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));
ret = system(str);
if (ret)
fprintf(stderr,
"%i: Calling ebtables 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",
"%i: Calling nft for TL failed with status %i\n",
clock, ret);
}
static void ebt_mac_call(char *mod, struct mac_addr *mac)
{
if (!strncmp(mod, "-D", strlen(mod))) {
ebt_mac_ret_call(mod, mac, 0);
if (!strncmp(mod, "delete", strlen(mod))) {
ebt_mac_limit_call(mod, mac);
} else {
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;
ebt_mac_call("-D", mac);
ebt_mac_call("delete", mac);
}
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)
return;
ebt_ip_call("-I", ip);
ebt_ip_call("add", ip);
}
static void ebt_add_mac(struct mac_addr *mac)
@ -152,7 +134,7 @@ static void ebt_add_mac(struct mac_addr *mac)
if (ret)
return;
ebt_mac_call("-I", mac);
ebt_mac_call("add", mac);
}
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);
return;
}
while (1) {
pline = fgets(line, sizeof(line), fp);
if (!pline) {
@ -257,18 +239,18 @@ static void ebt_tl_update(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)
fprintf(stderr, "Error flushing ARP_LIMIT_DATCHECK\n");
fprintf(stderr, "Error flushing arplimit datips set\n");
}
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)
fprintf(stderr, "Error flushing ARP_LIMIT_TLCHECK\n");
fprintf(stderr, "Error flushing arplimit limitmac\n");
}
int main(int argc, char *argv[])