#!/usr/bin/perl # This script parses mail sent to spam trap addresses and adds the IP # address from the last hop to the blocklist. The headers are saved # to check back on later. I can also pipe messages through it from mutt. # The received header checks for connecting IP address assume that # qmail is being used and that there are no local relays or MXs. use CDB_File; $LOCK_SH = 1; $LOCK_EX = 2; $LOCK_NB = 4; $LOCK_UN = 8; umask 022; chdir '/var/www/html/robot'; $header = ''; $ip = ''; while () { last if m/^$/; $header .= $_; if ($ip eq '' && m/^received:.*\((\d+\.\d+\.\d+\.\d+)\)\n$/i) { $ip = $1; } } while () {}; exit(0) if $ENV{'SENDER'} eq ''; exit(0) unless $ip != ''; exit(0) unless $ip !~ '^127\.'; # See if this IP was flagged already. $new = 1; $new = 0 if -e "ip1/$ip"; if (!open(IP,">ip1/$ip")) { exit(0); } # Save message headers for later reference. print IP "$header"; close(IP); # If the IP address isn't new we don't need to rebuild the database. exit(0) unless $new; # If some other process is already waiting to do an update, no need for us # to also wait. if (!open(WAITLOCK, 'waitlock')) { exit(0); } if (($t = flock(WAITLOCK, $LOCK_EX | $LOCK_NB)) == 0) { exit(0); } # Wait until any running update has been completed to avoid wasted effort. if (!open(BASELOCK, 'baselock')) { print "Unable to open base lock\n"; exit(0); } if (($t = flock(BASELOCK, $LOCK_EX)) == 0) { exit(0); } # Once we start, free up the wait lock. flock(WAITLOCK, $LOCK_UN); # Use a format compatible with rbldns. opendir(IP, 'ip1'); while ($ip = readdir(IP)) { if ($ip =~ m/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) { $key = pack 'CCCCC', $1, $2, $3, $4, 32; $ip{$key} = ''; } elsif ($ip =~ m/^(\d+)\.(\d+)\.(\d+)$/) { $key = pack 'CCCCC', $1, $2, $3, 0, 24; $ip{$key} = ''; } elsif ($ip =~ m/^(\d+)\.(\d+)$/) { $key = pack 'CCCCC', $1, $2, 0, 0, 16; $ip{$key} = ''; } } $ip{''} = (pack 'CCCC', 127, 0, 0, 10) . 'Spam block'; CDB_File::create %ip, 'data1/data.cdb', "data1/data.cdb.$$";