This is a perl script I use for doing a "darkgrey" list on spammers.
I'll have more detail as I start completing stuff here on the website.
#!/usr/bin/perl -wT
#
# darkgrey.pl
# returns 0, non-zero, or -1 based on queries and updates to a mysql db.
# zero = ok, not greylisted
# non-zero = greylist time left in seconds
# -1 = program failure (file open or sql query)
#
# to be called from mailfromd;
# set mypath "/path/to/darkgrey.pl"
# set myquery "query " . $client_addr
# set cmd "%mypath %myquery\n"
# set fd open(|&%cmd)
# set result getline(fd)
#
# call: /path/darkgrey.pl query-type dotted-ip
#
# query: returns darkgrey time left for ip, or zero
# update: updates or inserts ip with darkgrey time, default 48 hours
# delete: removes ip record
# smash: updates or inserts ip with darkgrey time of 7 days
#
# (update,delete,smash) returns 0 on sucess, -1 on failure
#
# -- darkgrey.sql
# CREATE TABLE `darkgrey` (
# `ip` varchar(20) NOT NULL,
# `time` int(10) NOT NULL,
# `host` varchar(80) NOT NULL default 'NXDOMAIN',
# PRIMARY KEY (`ip`)
# ) ENGINE=MyISAM DEFAULT CHARSET=latin1
# --
#
# Dave Helton Sept 17, 2011
use strict;
use DBI();
use POSIX;
use Net::Nslookup;
my ($dbh, $sth, $sql, $days);
my (@args);
my $darkgrey_host="NXDOMAIN";
$days = 2; # 48 hours
my $time_now = time();
my $user = "testuser";
my $password = "password";
my $database = "testdb";
my $host = "localhost";
my $dsn = "DBI:mysql:database=$database;host=$host";
@args = @ARGV;
# returns -1 if args are wrong
if ($args[0] eq "") {
print "-1\n";
$|=1;
exit;
}
if( $args[1] !~ /([0-9]{1,3}\.){3}[0-9]{1,3}/) {
print "-1\n";
$|=1;
exit;
}
sub removeip {
$sql = "DELETE FROM darkgrey WHERE ip=" . $dbh->quote($args[1]);
$sth = $dbh->prepare($sql);
$sth->execute();
# if empty set, return zero, no match
if($sth->rows == 1) {
print "0\n"; # return sucess to caller
} else {
print "-1\n"; # return fail to caller
}
}
sub update {
$darkgrey_host = nslookup(host=>$args[1], type=>"PTR");
if(!defined($darkgrey_host)) {
$darkgrey_host = "NXDOMAIN";
}
my $darkgrey_time = $time_now + ($days * 86400);
$dbh->do("INSERT INTO darkgrey (ip, time, host) VALUES(" .
$dbh->quote($args[1]) . ", " . $dbh->quote($darkgrey_time) .
", " . $dbh->quote($darkgrey_host) .
") ON DUPLICATE KEY UPDATE time=" . $dbh->quote($darkgrey_time) );
print "0\n"; # return sucess to caller
}
# get IP and TIME from mysql
sub query {
$sql = "SELECT * FROM darkgrey WHERE ip=" . $dbh->quote($args[1]) . " LIMIT 1";
$sth = $dbh->prepare($sql);
$sth->execute();
my $row = $sth->fetchrow_hashref();
# if empty set, return zero, no match
if($sth->rows == 0) {
print "0\n"; # return sucess to caller
} else {
# if match
if ($row->{'time'} > $time_now) { # if darkgrey is greater than now
print "$row->{'time'}\n";
} else {
print "0\n"; # expired
}
$sth->finish;
} # end if num rows
} # end query
$dbh = DBI->connect($dsn, $user, $password, {'RaiseError' => 1} )
or die "could not connect to db: $!\n";
if ($dbh->{'error'}) {
print STDERR "darkgrey db error: " . $dbh->{'error'} .
", ERR#: " . $dbh->{'errno'} . "\n";
};
if ($args[0] eq "update") {
update();
}
if ($args[0] eq "smash") {
$days=7;
update();
}
if ($args[0] eq "query") {
query();
}
if ($args[0] eq "delete") {
removeip();
}
# print STDERR "Disconnecting\n";
$dbh->disconnect();
# flush output
$| = 1;