Example Source Code

darkgrey.pl

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;