From a13f69ce9f26ea2b95be1e6de1f14f50ab7065d8 Mon Sep 17 00:00:00 2001 From: Dirk Koopman Date: Mon, 27 Mar 2023 20:04:51 +0100 Subject: [PATCH] add cmd ratelimits, restore regex is_ipaddr --- Changes | 16 +++++++++++++ perl/DXChannel.pm | 4 +++- perl/DXCommandmode.pm | 26 +++++++++++++++++---- perl/DXDebug.pm | 1 + perl/DXUtil.pm | 54 +++++++++++++++++++++++++------------------ perl/cluster.pl | 2 +- 6 files changed, 75 insertions(+), 28 deletions(-) diff --git a/Changes b/Changes index d33326e9..6cf31108 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,19 @@ +24Mar23======================================================================= +1. Restore perl regex version of is_ipaddr. This *should* allow windows + updates to work again. +2. Added cmd entry rate limiting. If a user sends X commmands in Y secs then + they are disconnected without notice. The defaults are X + ($DXCommandmode::maxcmdcount) = 16 and Y ($DXCommandmode::cmdinterval) = 9. + + These can be changed by the startup script. + + These default values are set generously deliberately to allow certain user + programs to get with the program and reduce the number of cmds that they + issue on connection down to something reasonable. For instance, I cannot + see why things like name, qth, lat/long/QRA (amongst several other sticky + user attributes that only need to be entered once) are sent on every login. + + These default values WILL reduce over time. 23Mar23======================================================================= 1. Fix DXCIDR brokenness introduced recently, speeded up DXCIDR::sort, allow sh/badip 2a05:dfc7:402a::1 45.134.225.96 159.69.38.160 to test individual diff --git a/perl/DXChannel.pm b/perl/DXChannel.pm index e60ce6c6..ceaaf551 100644 --- a/perl/DXChannel.pm +++ b/perl/DXChannel.pm @@ -52,6 +52,8 @@ $count = 0; beep => '0,Want Beeps,yesno', build => '1,Node Build', call => '0,Callsign', + cmdcount => '5,Cmds in cmdinterval', + cmdintstart => '5,Cmd int start,atime', cluster => '5,Cluster data', conf => '0,In Conference?,yesno', conn => '9,Msg Conn ref', @@ -66,7 +68,7 @@ $count = 0; enhanced => '5,Enhanced Client,yesno', errors => '9,Errors', func => '5,Function', - group => '0,Access Group,parray', # used to create a group of users/nodes for some purpose or other. + group => '0,Access Group,parray',# used to create a group of users/nodes for some purpose or other. gtk => '5,Using GTK,yesno', handle_xml => '9,Handles XML,yesno', here => '0,Here?,yesno', diff --git a/perl/DXCommandmode.pm b/perl/DXCommandmode.pm index dfaaa3e3..567b9456 100644 --- a/perl/DXCommandmode.pm +++ b/perl/DXCommandmode.pm @@ -50,7 +50,7 @@ use DXCIDR; use strict; use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase %nothereslug $maxbadcount $msgpolltime $default_pagelth $cmdimportdir $users $maxusers - $maxcmdlth + $maxcmdlth $maxcmdcount $cmdinterval ); %Cache = (); # cache of dynamically loaded routine's mod times @@ -64,8 +64,9 @@ $cmdimportdir = "$main::root/cmd_import"; # the base directory for importing com # this does not exist as default, you need to create it manually $users = 0; # no of users on this node currently $maxusers = 0; # max no users on this node for this run - $maxcmdlth = 512; # max length of incoming cmd line (including the command and any arguments +$maxcmdcount = 16; # max no cmds entering $cmdinterval seconds +$cmdinterval = 9; # if user enters more than $maxcmdcount in $cmdinterval seconds, they are logged off # # obtain a new connection this is derived from dxchannel @@ -254,6 +255,10 @@ sub start $self->lastmsgpoll($main::systime); $self->{user_interval} = $self->user->user_interval || $main::user_interval; # allow user to change idle time between prompts $self->prompt; + + $self->{cmdintstart} = 0; # set when systime > this + cmdinterval and a command entered, cmdcount set to 0 + $self->{cmdcount} = 0; # incremented on a coming in. If this value > $maxcmdcount, disconnect + } # @@ -365,8 +370,7 @@ sub normal for (@{$self->{talklist}}) { if ($self->{state} eq 'talk') { $self->send_talks($_, $l); - } - else { + } else { send_chats($self, $_, $l) } } @@ -417,6 +421,20 @@ sub normal # } else { my @cmd = split /\s*\\n\s*/, $cmdline; foreach my $l (@cmd) { + + # rate limiting code + + if (($self->{cmdintstart} + $cmdinterval <= $main::systime) || $self->{inscript}) { + $self->{cmdintstart} = $main::systime; + $self->{cmdcount} = 1; + dbg("$self->{call} started cmdinterval") if isdbg('cmdcount'); + } else { + if (++$self->{cmdcount} > $maxcmdcount) { + LogDbg('baduser', qq{User $self->{call} sent $self->{cmdcount} (>= $maxcmdcount) cmds in $cmdinterval seconds starting at } . atime($self->{cmdintstart}) . ", disconnected" ); + $self->disconnect; + } + dbg("$self->{call} cmd: '$l' cmdcount = $self->{cmdcount} in $cmdinterval secs") if isdbg('cmdcount'); + } $self->send_ans(run_cmd($self, $l)); } # } diff --git a/perl/DXDebug.pm b/perl/DXDebug.pm index 83e49259..3ab7c770 100644 --- a/perl/DXDebug.pm +++ b/perl/DXDebug.pm @@ -25,6 +25,7 @@ package DXDebug; use 5.10.1; +use warnings; require Exporter; @ISA = qw(Exporter); diff --git a/perl/DXUtil.pm b/perl/DXUtil.pm index d23c27cf..b60b0b0b 100644 --- a/perl/DXUtil.pm +++ b/perl/DXUtil.pm @@ -15,8 +15,6 @@ use File::Copy; use Data::Dumper; use Time::HiRes qw(gettimeofday tv_interval); use Text::Wrap; -use Socket qw(AF_INET6 AF_INET inet_pton); - use strict; use vars qw(@month %patmap $pi $d2r $r2d @ISA @EXPORT); @@ -46,14 +44,24 @@ $pi = 3.141592653589; $d2r = ($pi/180); $r2d = (180/$pi); -our $ptonok; -BEGIN { - $ptonok = !defined inet_pton(AF_INET, '016.17.184.1') - && !defined inet_pton(AF_INET6, '2067::1:') - # Some old versions of Socket are hopelessly broken - && length(inet_pton(AF_INET, '1.1.1.1')) == 4; -} +# BEGIN { +# our $enable_ptonok = 0; +# our $ptonok; + + +# if ($enable_ptonok && !$main::is_win) { +# eval {require Socket; Socket->import(qw(AF_INET6 AF_INET inet_pton)); }; +# unless ($@) { +# $ptonok = !defined inet_pton(AF_INET, '016.17.184.1') +# && !defined inet_pton(AF_INET6, '2067::1:') +# # Some old versions of Socket are hopelessly broken +# && length(inet_pton(AF_INET, '1.1.1.1')) == 4; +# } +# } +# } + + # a full time for logging and other purposes sub atime @@ -458,23 +466,23 @@ sub is_latlong sub is_ipaddr { $_[0] =~ s|/\d+$||; - if ($ptonok) { - if ($_[0] =~ /:/) { - if (inet_pton(AF_INET6, $_[0])) { - return ($_[0] =~ /([:0-9a-f]+)/); - } - } else { - if (inet_pton(AF_INET, $_[0])) { - return ($_[0] =~ /([\.\d]+)/); - } - } - } else { + # if ($ptonok) { + # if ($_[0] =~ /:/) { + # if (inet_pton(AF_INET6, $_[0])) { + # return ($_[0] =~ /([:0-9a-f]+)/); + # } + # } else { + # if (inet_pton(AF_INET, $_[0])) { + # return ($_[0] =~ /([\.\d]+)/); + # } + # } + # } else { if ($_[0] =~ /:/) { - return ($_[0] =~ /^(:?:?(?:[0-9a-f]{1,4}\:)?(?:\:[0-9a-f]{1,4}(?:\:\:)?){1,8})$/i); + return ($_[0] =~ /^((?:\:?\:?[0-9a-f]{0,4}){1,8}\:?\:?)$/i); } else { return ($_[0] =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/); } - } +# } return undef; } @@ -646,3 +654,5 @@ sub is_numeric { return $_[0] =~ /^[\.\d]+$/; } + +1; diff --git a/perl/cluster.pl b/perl/cluster.pl index c2e32b5f..f7c85a6f 100755 --- a/perl/cluster.pl +++ b/perl/cluster.pl @@ -115,7 +115,6 @@ use Mojolicious 7.26; use Mojo::IOLoop; $DOWARN = 1; -use DXDebug; use Msg; use IntMsg; use Internet; @@ -169,6 +168,7 @@ use IsoTime; use BPQMsg; use RBN; use DXCIDR; +use DXDebug; use Data::Dumper; use IO::File; -- 2.34.1