The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl
#############################################################################
## wpbl helper script
## Copyright (C) 2004  Martin Ward  http://www.cse.dmu.ac.uk/~mward/
## Email: martin@gkc.org.uk
##
## 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.
#############################################################################
#
# Check the sender's IP address against the wpbl list
# Add "X-WPBL: BLOCK (ip)" or "X-WPBL: OK (ip)" as appropriate
#
# Usage: wpbl_check < msg > output
#

use strict;
use warnings;

(my $myname = $0) =~ s|(.*/)*||;	# strip path component from name
my $Usage = "Usage: $myname < msg > output\n";
# Check for zeroarguments:
die $Usage unless (@ARGV == 0);

my $HOME = $ENV{'HOME'} || $ENV{'LOGDIR'} ||
		(getpwuid($<))[7] || die "You're homeless!\n";

my $base = "$HOME/.wpbl";
my $exclude = "$base/data/exclude";
my $blocks  = "$base/data/wpbl-blocks.cidr";
my $source  = "rsync://rsync.wpbl.info/wpbl/wpbl-blocks.cidr";

undef $/;

# If $blocks is older than 0.042 days (just over one hour), then re-fetch it:
if (-M $blocks > 0.042) {
  system "rsync -q -z $source $blocks";
  # In case the rsync failed, touch the file so that we won't try to fetch
  # it again for another hour at least:
  system "touch $blocks";
}

# Compute a regexp of IPs to exclude:
my $excl_pat = "";
open(EX, $exclude) or die "Can't read $exclude: $!\n";
for (split(/\n/, <EX>)) {
  s/#.*$//;
  next unless /\S/;
  s/\s+//g;
  s/\./\\./g;
  $excl_pat .= "$_|";
}
# Remove trailing |
$excl_pat =~ s/\|$//;
$excl_pat = "^($excl_pat)";


open(IN, "$blocks") or die "Can't read $blocks: $!\n";
my @block = grep { /^\d+\.\d+\.\d+\.\d+$/ } split(/\s+/, <IN>);
close(IN);

# Add spam entries from logfiles to blocks:
opendir(DIR, $base) or die "Can't read directory $base: $!\n";
foreach my $log (grep { /^log/ } readdir (DIR)) {
  open(IN, "$base/$log") or die "Can't read $base/$log: $!\n";
  my @spam = grep { /^spam\s+\d+\.\d+\.\d+\.\d+/ } split(/\n/, <IN>);
  close(IN);
  s/^spam (\d+\.\d+\.\d+\.\d+)\s*/$1/ for (@spam);
  push(@block, @spam);
}


$_ = join("", <STDIN>);
# Trim body if present:
my $body = "";
$body = $1 if s/\n(\n.*)/\n/s;

# Join broken header lines:
s/\n[ \t]+/ /g;

# Get list of IPs in Received lines:
my @ips = /\nReceived:.*?\[(\d+\.\d+\.\d+\.\d+)\]/g;

# Delete exclusions:
@ips = grep { !/$excl_pat/ } @ips;

# Check that we found an IP (could be a local email):

my $tags = "";
if (@ips) {
  if (grep { $ips[0] eq $_ } @block) {
    # Sender IP is in block list
    $tags .= "X-WPBL: BLOCK ($ips[0])\n";
  } else {
    $tags .= "X-WPBL: OK ($ips[0])\n";
  }
} else {
  $tags .= "X-WPBL: OK (no ip)\n";
}

print $_, $tags, $body;