From: Robert Högberg Date: Tue, 10 Oct 2023 21:25:34 +0000 (+0200) Subject: yate: Update yate script to use an nftables set X-Git-Url: http://git.openwrt.org/?p=feed%2Ftelephony.git;a=commitdiff_plain;h=8a2f8231fbf64a00948c2b4a255d955e54946cb4 yate: Update yate script to use an nftables set 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 --- 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();