add cmd ratelimits, restore regex is_ipaddr
authorDirk Koopman <djk@tobit.co.uk>
Mon, 27 Mar 2023 19:04:51 +0000 (20:04 +0100)
committerDirk Koopman <djk@tobit.co.uk>
Mon, 27 Mar 2023 19:04:51 +0000 (20:04 +0100)
Changes
perl/DXChannel.pm
perl/DXCommandmode.pm
perl/DXDebug.pm
perl/DXUtil.pm
perl/cluster.pl

diff --git a/Changes b/Changes
index d33326e94553432f5047f63de3ae611531667173..6cf311084844bb4801b37a4b398aae23cfd5e308 100644 (file)
--- 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
index e60ce6c6be307e382420bb74a9828d9427780312..ceaaf551907c0b8aaee3e19a55737c58bf92df6f 100644 (file)
@@ -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',
index dfaaa3e34887454ffe047c14b9a397fb70aa27e3..567b94560589ccc25672aa10c46e444167b0bc74 100644 (file)
@@ -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));
                }
 #              }
index 83e49259863e0f7259cfcae0fa4702e536d7a2a6..3ab7c77084693ec3ff41bbfae672a800fba90ddb 100644 (file)
@@ -25,6 +25,7 @@
 package DXDebug;
 
 use 5.10.1;
+use warnings;
 
 require Exporter;
 @ISA = qw(Exporter);
index d23c27cfa5e3d73e4d3c21fae04aef16d6d08a9e..b60b0b0b1de4c444e301f86aa04404ed3d666b61 100644 (file)
@@ -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;
index c2e32b5f6a1206aa510d11f9f3efb5aee47faaf3..f7c85a6f9a18ad2bb4fe12672eb5cdba06c4002d 100755 (executable)
@@ -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;