IPBlock question
Jeff A. Earickson
jaearick at COLBY.EDU
Fri Jun 4 16:17:36 IST 2004
Hi,
Try the attached perl script for analysis of the contents of your
IPBlock list.
Jeff Earickson
Colby College
On Fri, 4 Jun 2004, Julian Field wrote:
> Date: Fri, 4 Jun 2004 16:06:38 +0100
> From: Julian Field <mailscanner at ECS.SOTON.AC.UK>
> Reply-To: MailScanner mailing list <MAILSCANNER at JISCMAIL.AC.UK>
> To: MAILSCANNER at JISCMAIL.AC.UK
> Subject: Re: IPBlock question
>
> Strings is not a reliable way to read the contents of a DB file.
>
> At 15:09 04/06/2004, you wrote:
> >Hi All,
> >
> > I have set up the module so entries are being added to the access.db.
> >This works fine. However the Cronjob perl script copied off the end of
> >CustomConfig.pm which runs hourly does not seem to remove old entries
> >properly.
> >
> >What happens is that if I run strings /etc/mail/access.db I get the
> >entries for hostnames and IPs added. Then if I run the IPBlock cleaner
> >and run the strings command again it will sometimes not remove the entry
> >from the access.db and sometimes remove part of the string. E.g. will
> >remove the last segment up to the last '.' of an IP or hostname. It does
> >however seem to remove them from the IPBlock.db file and log that lines
> >were removed from the access file.
> >
> >Obvious things I have tried are:
> > 1. Making sure the $Refusal line matches in the CustomConfig.pm
> > and the
> >cron script.
> > 2. I have reduced the $OneHour to 1 so it should in theory remove
> >entries one second old (just for testing but I have waited an hour and
> >tested too).
> > 3. I have rewritten the $Refusal so there are no special chars (:// in
> >a URL was taken out).
> > 4. Ran a separate file to the main access.db for testing.
> >
> >I'm running:
> > Fedora Core 1
> > MailScanner 4.31.6-1 rpm
> > sendmail-8.12.11 (built from src not rpm)
> > perl 5.8.3-16 rpm
> >
> >Incidentally it was doing this in 4.29-7 before I upgraded earlier today.
> >
> >Thanks in advance.
> >
> >Matt
> >--
> >
> >[root at mail-gw mail]# strings IPBaccess.db
> >"550 Site blocked by MailScanner due to excessive email see
> >www.sovision.com"
> >194.105.69.87
> >"550 Site blocked by MailScanner due to excessive email see
> >www.sovision.com"
> >barney.gwork.org
> >[root at mail-gw mail]# /usr/local/sbin/IPB
> >IPBedit.pl IPBlock-clean.pl
> >[root at mail-gw mail]# /usr/local/sbin/IPBlock-clean.pl
> >[root at mail-gw mail]# Jun 4 14:41:29 mail-gw IPBlock[2551]: Deleted 2
> >entries from sendmail access database
> >
> >[root at mail-gw mail]# strings IPBaccess.db
> >"550 Site blocked by MailScanner due to excessive email see
> >www.sovision.com"
> >194.105.69.87
> >"550 Site blocked by MailScanner due to excessive email see
> >www.sovision.com"
> >barney.gwork.org
> >
> >-------------------------- MailScanner list ----------------------
> >To leave, send leave mailscanner to jiscmail at jiscmail.ac.uk
> >Before posting, please see the Most Asked Questions at
> >http://www.mailscanner.biz/maq/ and the archives at
> >http://www.jiscmail.ac.uk/lists/mailscanner.html
>
> --
> Julian Field
> www.MailScanner.info
> MailScanner thanks transtec Computers for their support
>
> PGP footprint: EE81 D763 3DB0 0BFD E1DC 7222 11F6 5947 1415 B654
>
> -------------------------- MailScanner list ----------------------
> To leave, send leave mailscanner to jiscmail at jiscmail.ac.uk
> Before posting, please see the Most Asked Questions at
> http://www.mailscanner.biz/maq/ and the archives at
> http://www.jiscmail.ac.uk/lists/mailscanner.html
>
-------------------------- MailScanner list ----------------------
To leave, send leave mailscanner to jiscmail at jiscmail.ac.uk
Before posting, please see the Most Asked Questions at
http://www.mailscanner.biz/maq/ and the archives at
http://www.jiscmail.ac.uk/lists/mailscanner.html
-------------- next part --------------
#!/usr/bin/perl -I/usr/lib/MailScanner
#
# MailScanner - SMTP E-Mail Virus Scanner
# Copyright (C) 2002 Julian Field
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# The author, Julian Field, can be contacted by email at
# Jules at JulianField.net
# or by paper mail at
# Julian Field
# Dept of Electronics & Computer Science
# University of Southampton
# Southampton
# SO17 1BJ
# United Kingdom
#
use Net::CIDR;
use FileHandle;
use Fcntl qw(:DEFAULT :flock);
use Getopt::Std;
BEGIN { @AnyDBM_File::ISA = qw(DB_File GDBM_File NDBM_File SDBM_File) }
use AnyDBM_File;
#use strict 'vars';
#use strict 'refs';
#no strict 'subs'; # Allow bare words for parameter %'s
#---subroutine prototypes
sub sort_criterion();
sub parseargs();
my $OneHour = 3600; # seconds
my $WhitelistFile= '/etc/MailScanner/IPBlock.conf';
my $LockFile = '/var/spool/MailScanner/IPBlock.lock';
my $BlockDB = '/var/spool/MailScanner/IPBlock.db';
my $AccessDB = '/etc/mail/db/access.db';
my $Refusal = '"550 Site blocked by MailScanner due to excessive email"';
#---parse command line to get number of lines to print
#---default is all lines
parseargs();
#---read in the IPBlock.conf file
my $LimitsH = new FileHandle;
$LimitsH->open($WhitelistFile) or die;
$counter = 0;
while(<$LimitsH>) {
chomp;
s/#.*$//;
s/^\s*//g;
s/\s*$//g;
next if /^$/;
($cidr, $limit) = split;
$cidr =~ s/\s//g;
$limit = 0 unless defined $limit;
my @cidrlist = undef;
if ($cidr =~ /-/) {
# It looks like 152.78.67.0-152.78.69.255
@cidrlist = Net::CIDR::range2cidr($cidr);
} elsif ($cidr =~ /\//) {
# It looks like 152.78.0.0/16 or 152.78/16 or 152.78/255.255.0.0
my($network, $bits, $count);
($network, $bits) = split(/\//, $cidr);
$network =~ s/\.$//; # Delete any trailing dot
$count = split(/\./, $network);
$network .= '.0' x (4-$count); # Fill out the CIDR for Net::CIDR
# 152.78 now looks like 152.78.0.0
if ($bits =~ /\./) {
# It's like 152.78.0.0/255.255.0.0
push @cidrlist, Net::CIDR::addrandmask2cidr($network, $bits);
} else {
# It's like 152.78.0.0/16
push @cidrlist, "$network/$bits";
}
} elsif ($cidr =~ /default/i) {
# It is the default value used when nothing else matches
$DefaultMaxMessagesPerHour = $limit;
} else {
# Must just be an IP address or look like 152.78 or 152.78.
$cidr =~ s/\.$//; # Delete any trailing dot
my $count = split(/\./, $cidr);
$cidr .= '.0' x (4-$count);
push @cidrlist, "$cidr/" . ($count*8);
}
# Build the map from CIDR to message limit
foreach (@cidrlist) {
next unless $_;
#print STDERR "IPBlock: adding $_\n";
$CIDRtoLimit{$_} = $limit;
push @CIDRlist, $_;
}
$counter++;
}
close($LimitsH);
#
# Lock out everything else for the whole of this script
#
my $LockFileH = new FileHandle;
openlock($LockFileH, ">$LockFile");
#
# Find all the entries to be deleted from the BlockDB file.
#
#Bind to BlockDB
my(%BlockDB, %AccessDB);
tie %BlockDB, "AnyDBM_File", $BlockDB, O_RDWR, 0644
or BailOut("Failed to open $BlockDB, it may not exist yet, $!");
tie %AccessDB, "AnyDBM_File", $AccessDB, O_RDWR, 0644
or BailOut("Failed to open $AccessDB, have you got the path wrong? $!");
# Read and print IPBlock DB
my $now = time;
my(@ips, $ip, $value, $hostname, $count, $time, $donealready, $flag);
my $countrec = 0;
my $countdel = 0;
my $countblk = 0;
print "MailScanner IP Blocking Summary\n";
printf("S %15s: %s %s\n","IP Number","mesgs/limit","Hostname");
print "--------------------------------------------------------------\n";
@ips = sort { sort_criterion() } (keys %BlockDB);
foreach $ip (@ips)
{
($hostname, $count, $time, $donealready) = split(/,/, $BlockDB{$ip});
# Is it more than an hour old, or has time_t wrapped (happens in year 2036)
#print STDERR "Examining record for $ip, $count, $time\n";
$countrec++;
$flag = " ";
if ($time>$now || $now>=$time+$OneHour) {
$flag = "-";
$countdel++;
}
if ($AccessDB{$ip} eq $Refusal) {
$flag = "*";
$countblk++;
}
#---look for CIDR and print if less than print limit
if($countrec <= $opt_n)
{
#---find the limit per CIDR rule for this IP
my($cidrkey, $foundcidr, $foundit, $limit);
$foundit = 0;
foreach $cidrkey (@CIDRlist) {
#print STDERR "Looking for $ip in $cidrkey\n";
if (Net::CIDR::cidrlookup($ip, $cidrkey)) {
#print STDERR "Found it\n";
$foundit = 1;
$foundcidr = $cidrkey;
last;
}
}
# If we didn't find it, use the default value
$limit = $foundit ? $CIDRtoLimit{$foundcidr} : $DefaultMaxMessagesPerHour;
#print STDERR "Limit of $foundcidr is $limit\n";
$fraction = sprintf("%d/%d",$count,$limit);
printf("%1s %15s: %11s %s\n",$flag,$ip,$fraction,$hostname);
}
}
print "--------------------------------------------------------------\n";
printf("%5d DB records in IPBlock database\n",$countrec);
printf("%5d DB records scheduled for deletion, next cron job (-)\n",$countdel);
printf("%5d DB records listed in sendmail access db file (*)\n",$countblk);
# Unlock and close the DB file
untie %BlockDB;
untie %AccessDB;
unlockclose($LockFileH);
exit 0;
sub openlock {
my($fh, $fn) = @_;
if (open($fh, $fn)) {
flock($fh, LOCK_EX) or die;
} else {
die "Died opening $fn, $!";
}
}
sub unlockclose {
my($fh) = @_;
flock($fh, LOCK_UN);
close ($fh);
}
sub BailOut {
warn "@_, $!";
exit 1;
}
sub parseargs()
#---parse the command line arguments
{
$opt_n = 999999;
getopts("n:");
if($#ARGV ne -1)
{
print "Usage is: $0 [-n number]\n";
print "\t-n is the number of lines to print out\n";
exit 1;
}
}
sub sort_criterion()
#---sorts according to message count, biggest to smallest
{
my($counta, $countb);
(undef, $counta, undef, undef) = split /,/, $BlockDB{$a};
(undef, $countb, undef, undef) = split /,/, $BlockDB{$b};
return($countb <=> $counta);
}
More information about the MailScanner
mailing list