> Has anyone got any kind of working parts they could share to
> block these zombie connections at the IP level?

Mark -- here are two things I've tried -- neither are great, but they  
are starting points, perhaps others would like to take these and  
modify / improve them?  I'm hesitant to put these out there, because  
they're very alpha / test-quality; really, more should be done to make  
them more robust. But, they've worked for me, and I'd be delighted if  
someone else wants to pick up from here and improve them.


I've been finding that the zombies come from all over the place, and  
generally, any given zombie doesn't try more than a few attempts.



First attempt: find all connections that have been active for 5  
minutes or longer, and kill them. This catches connections that are  
tarpitted. It also catches connections that are taking a long time to  
send data, potentially legit; in our case, I'm happy killing anything  
that can't transmit 10 MB of data within 5 minutes.

Since most the zombies only seem to try a few times from any IP, this  
seems to work quite well -- i.e. there's nothing here that prevents re- 
connects, but zombies don't seem to attempt reconnects currently.

This is designed to be run from cron once a minute.

> #!/usr/bin/perl
>
> $MAX_AGE = 300;
>
> @jobs = `ps -eo ppid,lstart,cmd | grep 'submit esmtp dns' | grep -v  
> grep`; # We need submit's parent process id, since that's what we  
> need to kill -- hence ppid, not pid
>
> use Date::Parse;
>
> while ($job = pop @jobs) {
>       if ($job =~ /([0-9]+)\s+(.*)\s+submit esmtp dns(.*)/) {
>               $ppid = $1;
>               $age = time() - str2time($2);
>               $connectionInfo = $3;
>               $connectionInfo =~ /([0-9\.]+)\]\)/;
>               $ipAddr = $1;
>               $connectionInfo =~ s/^\;\s+//;
>               if ($age > $MAX_AGE && $age < 7200) { # 7200 isn't necessary, 
> but  
> sanity check in case something changes and this breaks -- wouldn't  
> want to randomly kill wrong things
>                       print "Killing submit[$ipAddr] -- $ppid ($age seconds 
> for  
> $connectionInfo)\n";
>                       `kill $ppid`;
>               }
>       }
> }



Second attempt:  Read maillog in real time and selectively block IPs  
that are attempting to send to too many invalid users or are otherwise  
blocked and retrying. This doesn't seem to work so well in practice,  
because the zombies are coming from all over the place, so this just  
generates a really large iptables list.

This is designed to run in the background. You should periodically  
flush the iptables list (SMTPBLOCK in this example), so that it  
doesn't grow unbounded.


> #!/usr/bin/perl
>
> close(STDOUT);
> open(STDOUT, ">>/var/log/smtp-graylist") || print STDERR "failed to  
> open stdout: $!";
>
> close(STDERR);
> open(STDERR, ">>/var/log/smtp-graylist") || print "failed to open  
> stderr";
>
> close(STDIN);
>
> # Exit parent process (so we run like a daemon):
> if (fork() != 0) {
>       exit(0);
> }
>
>
> $sleepCount = 60;
> $loopCount = 0;
> while (1) {
>       $loopCount++;
>       if ($loopCount > 5000) { $loopCount = 0; %IP_SCORES = {}; }
>
>       if ($sleepCount >= 60) {
>               close FILE;
>               open (FILE, "/var/log/maillog") || die "Can't read maillog: $!";
>               seek(FILE,0,2);
>               $sleepCount = 0;
>       }
>       seek(FILE,0,1);
>       $ret = read(FILE, $thisRead, 8192);
>       if ($ret != 0) {
>               @lines = split(/\n/, $thisRead);
>               foreach $line (@lines) { examineMaillogLine($line); }
>               $sleepCount = 0;
>       } else {
>               sleep(1);
>               $sleepCount++;
>       }
> }
>
>
> sub examineMaillogLine {
>       my ($line) = @_;
>       unless ($line =~ /\:ffff\:([0-9\.]+)/) { return; } # Example line:  
> ip=[::ffff:10.101.187.210]
>       my $ip = $1;
>       if ($line =~ / 511 /) { $IP_SCORES{$ip} += 5; }
>       elsif ($line =~ /513 Relaying denied/) { $IP_SCORES{$ip}++; }
>       elsif ($line =~ /550 User unknown/) { $IP_SCORES{$ip}++; }
>       elsif ($line =~ /502 ESMTP command error/) { $IP_SCORES{$ip} += 4; }
>       else { return; }
>
>       if ($IP_SCORES{$ip} >= 10) {
>               `/sbin/iptables -A SMTPBLOCK -s $ip -p tcp --dport 25 -j DROP`;
>       }
> }


------------------------------------------------------------------------------
Register Now & Save for Velocity, the Web Performance & Operations 
Conference from O'Reilly Media. Velocity features a full day of 
expert-led, hands-on workshops and two days of sessions from industry 
leaders in dedicated Performance & Operations tracks. Use code vel09scf 
and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf
_______________________________________________
courier-users mailing list
[email protected]
Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users

Reply via email to