On Mon, 5 Jul 2004 08:29:37 +0100
Matt Sergeant <[EMAIL PROTECTED]> wrote:
> On 4 Jul 2004, at 20:37, Devin Carraway wrote:
> > On Sun, Jul 04, 2004 at 07:40:51PM +0100, Mark Powell wrote:
> >>   Had some dialup joker today, opening 45 smtp connections and
> >doing> nothing on them, but a NOOP every 30s. Four hours later they
> >were all> still there, until I killed them and blocked the IP.
> >>   Can we have the possibility of a noop handler, so a plugin could 
> >> prevent
> >> this?
> >
> > Hm.  While we might as well have a no-op hook, the attacker could
> > have staged the same sort of attack with a gradual cycle of
> > mail/rcpt/rset commands.  A better countermeasure for this one would
> > be a per-client max-connections limit.  Won't do much against a
> > zombie attack, but it'd deal with this sort.
> 
> http://linux.voyager.hr/ucspi-tcp/tcpserver-limits-2004-03-27.diff
This diff adds a MAXCONNIP to qpsmtpd-forkserver. I set the default to 
my $MAXCONNIP = 5;

Diff is against qpsmtpd-forkserver 0.28

        Hanno
--- qpsmtpd-forkserver.orig     Mon Jul  5 18:05:23 2004
+++ qpsmtpd-forkserver  Mon Jul  5 18:04:39 2004
@@ -20,6 +20,7 @@
 my $PORT      = 25;                            # port number
 my $LOCALADDR = '0.0.0.0';             # ip address to bind to
 my $USER      = 'smtpd';               # user to suid to
+my $MAXCONNIP = 5;              # max simultaneous connections from one IP
 
 delete $ENV{ENV};
 $ENV{PATH} = '/bin:/usr/bin:/var/qmail/bin';
@@ -73,10 +74,30 @@
         # possible something condition...
         next;
     }
+    my ($port, $iaddr) = sockaddr_in($hisaddr);
+    if ($MAXCONNIP) {
+        my $num_conn = 0;
+        foreach my $rip (values %childstatus) {
+            if ($rip eq $iaddr) {
+                ++$num_conn;
+            }
+        }
+        ++$num_conn; # count this connection, too :)
+        if ($num_conn > $MAXCONNIP) {
+            my $rem_ip = inet_ntoa($iaddr);
+            ::log(LOGINFO,"Too many connections from $rem_ip: "
+                         ."$num_conn > $MAXCONNIP. Denying connection.");
+            $client->autoflush(1);
+            print $client "451 Sorry, too many connections from $rem_ip, try again 
later\r\n";
+            close $client;
+            next;
+        }
+    }
     my $pid = fork;
     if ($pid) {
         # parent
-        $childstatus{$pid} = 1;        # add to table
+        $childstatus{$pid} = $iaddr;   # add to table
+        # $childstatus{$pid} = 1;      # add to table
         $running++;
         close($client);
         next;
@@ -92,7 +113,7 @@
     my $localsockaddr = getsockname($client);
     my ($lport, $laddr) = sockaddr_in($localsockaddr);
     $ENV{TCPLOCALIP} = inet_ntoa($laddr);
-    my ($port, $iaddr) = sockaddr_in($hisaddr);
+    # my ($port, $iaddr) = sockaddr_in($hisaddr);
     $ENV{TCPREMOTEIP} = inet_ntoa($iaddr);
     $ENV{TCPREMOTEHOST} = gethostbyaddr($iaddr, AF_INET) || "Unknown";
 

Reply via email to