From 8a2f8231fbf64a00948c2b4a255d955e54946cb4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Robert=20H=C3=B6gberg?= Date: Tue, 10 Oct 2023 23:25:34 +0200 Subject: [PATCH 1/1] yate: Update yate script to use an nftables set MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit By using an nftables set in this script it's easier to install and use this script now that OpenWrt uses nftables by default. Signed-off-by: Robert Högberg --- net/yate/Makefile | 2 +- net/yate/files/banbrutes.pl | 84 ++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/net/yate/Makefile b/net/yate/Makefile index ef64265..a672b60 100644 --- a/net/yate/Makefile +++ b/net/yate/Makefile @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=yate PKG_VERSION:=6.4.0-1 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=http://yate.null.ro/tarballs/yate6/ diff --git a/net/yate/files/banbrutes.pl b/net/yate/files/banbrutes.pl index fa1bb3d..aefaa5e 100755 --- a/net/yate/files/banbrutes.pl +++ b/net/yate/files/banbrutes.pl @@ -1,21 +1,43 @@ #!/usr/bin/perl -# This yate module will monitor failed authentications and send the source -# IP addresses of users who fail to authenticate to the iptables extension -# "recent" for filtering. +# This yate script will monitor authentication requests and update an +# nftables set with IP addresses of users who consistently fail to +# authenticate. The nftables set can then be used in OpenWrt's +# firewall configuration to block these IP addresses. # -# You have to have the iptables extension "recent" installed and you need to -# create and reference a "recent" list in your firewall configuration. -# For most people it's probably enough to add this custom firewall rule -# to /etc/firewall.user: +# The nftables set has to exist before launching yate. # -# iptables -A input_rule -m recent --name yate_auth_failures --rcheck --seconds 3600 --hitcount 5 -j DROP +# Here's an example configuration that creates an nftables set, where +# entries expire after 12 hours, and configures the OpenWrt firewall +# to drop packets where the source IP address is in the set. Put this +# in /etc/nftables.d/99-yate.nft: # -# This line will drop all incoming traffic from users who have failed to -# authenticate 5 consecutive times within the last hour. +# set yate_denylist { +# type ipv4_addr +# timeout 12h +# } # -# To enable this script in yate, add this script to the [scripts] section -# in /etc/yate/extmodule.conf. +# chain yate_filter { +# type filter hook input priority -1; policy accept; +# ip saddr @yate_denylist counter drop comment "Drop packets from bad SIP clients" +# } +# +# +# To enable this script in yate, add it to the [scripts] section in +# /etc/yate/extmodule.conf. +# +# You can tweak how tolerant this script should be by modifying the +# constants below. + +# A user's IP address will be added to the nftables set if there are +# more than MAX_AUTH_FAILURES consecutive authentication failures in +# MAX_AUTH_FAILURES_TIME_PERIOD seconds. +my $MAX_AUTH_FAILURES = 5; +my $MAX_AUTH_FAILURES_TIME_PERIOD = 3600; # seconds + +# The name of the nftables table and set where IP addresses are added. +my $NFTABLES_TABLE = 'inet fw4'; +my $NFTABLES_SET = 'yate_denylist'; use strict; @@ -23,28 +45,42 @@ use warnings; use lib '/usr/share/yate/scripts'; use Yate; -my $RECENT_LIST_NAME = '/proc/net/xt_recent/yate_auth_failures'; +my %ip_auth_failures = (); sub OnAuthenticationRequest($) { my $yate = shift; + + # Forget any expired failed authentications + foreach my $ip (keys(%ip_auth_failures)) { + my $failures = \@{$ip_auth_failures{$ip}}; + while (@$failures && + time() - @$failures[0] > $MAX_AUTH_FAILURES_TIME_PERIOD) { + shift(@$failures); + } + + if (!@$failures) { + delete $ip_auth_failures{$ip}; + } + } + my $remote_ip = $yate->param('ip_host'); + my $remote_device = $yate->param('device') || ''; if ($yate->header('processed') eq 'true') { - # Successful authentication, forget previous failures - `echo -$remote_ip > $RECENT_LIST_NAME`; + $yate->output("banbrutes: Successful authentication from $remote_ip"); + delete $ip_auth_failures{$remote_ip}; return; } - `echo +$remote_ip > $RECENT_LIST_NAME`; + $yate->output("banbrutes: Failed authentication from $remote_ip"); + push(@{$ip_auth_failures{$remote_ip}}, time()); + if (scalar(@{$ip_auth_failures{$remote_ip}}) > $MAX_AUTH_FAILURES) { + $yate->output("banbrutes: Adding $remote_ip to nftables set $NFTABLES_SET (remote device: $remote_device)"); + `nft add element $NFTABLES_TABLE $NFTABLES_SET { $remote_ip }`; + delete $ip_auth_failures{$remote_ip}; + } } - my $yate = new Yate(); - -if (! -f $RECENT_LIST_NAME) { - $yate->output("iptables recent list $RECENT_LIST_NAME does not exist"); - exit 1; -} - -$yate->install_watcher('user.auth', \&OnAuthenticationRequest); +$yate->install_watcher("user.auth", \&OnAuthenticationRequest); $yate->listen(); -- 2.30.2