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 <robert.hogberg@gmail.com>
This commit is contained in:
Robert Högberg 2023-10-10 23:25:34 +02:00
parent 5f998af5ee
commit 8a2f8231fb
2 changed files with 61 additions and 25 deletions

View file

@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=yate PKG_NAME:=yate
PKG_VERSION:=6.4.0-1 PKG_VERSION:=6.4.0-1
PKG_RELEASE:=2 PKG_RELEASE:=3
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=http://yate.null.ro/tarballs/yate6/ PKG_SOURCE_URL:=http://yate.null.ro/tarballs/yate6/

View file

@ -1,21 +1,43 @@
#!/usr/bin/perl #!/usr/bin/perl
# This yate module will monitor failed authentications and send the source # This yate script will monitor authentication requests and update an
# IP addresses of users who fail to authenticate to the iptables extension # nftables set with IP addresses of users who consistently fail to
# "recent" for filtering. # 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 # The nftables set has to exist before launching yate.
# 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:
# #
# 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 # set yate_denylist {
# authenticate 5 consecutive times within the last hour. # type ipv4_addr
# timeout 12h
# }
# #
# To enable this script in yate, add this script to the [scripts] section # chain yate_filter {
# in /etc/yate/extmodule.conf. # 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; use strict;
@ -23,28 +45,42 @@ use warnings;
use lib '/usr/share/yate/scripts'; use lib '/usr/share/yate/scripts';
use Yate; use Yate;
my $RECENT_LIST_NAME = '/proc/net/xt_recent/yate_auth_failures'; my %ip_auth_failures = ();
sub OnAuthenticationRequest($) { sub OnAuthenticationRequest($) {
my $yate = shift; 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_ip = $yate->param('ip_host');
my $remote_device = $yate->param('device') || '<unknown>';
if ($yate->header('processed') eq 'true') { if ($yate->header('processed') eq 'true') {
# Successful authentication, forget previous failures $yate->output("banbrutes: Successful authentication from $remote_ip");
`echo -$remote_ip > $RECENT_LIST_NAME`; delete $ip_auth_failures{$remote_ip};
return; 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(); my $yate = new Yate();
$yate->install_watcher("user.auth", \&OnAuthenticationRequest);
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->listen(); $yate->listen();