Re: Quick Postfix Question [OT] On Wed, Feb 27, 2008 at 2:50 PM, Bob Proulx  wrote:
> Marc Perkel wrote:
>  > It appears that Postfix only does DNS blacklists and not whitelists
>  > then. I was going to publish my whitelist and Postfix instructions but I
>  > guess I can't do that.
>
>  That would be a better question for the postfix-users list.  Probably
>  the way to do this is with the check_policy_service functionality.
>  The "permit" action should permit the request.  I haven't created my
>  own policy daemon though and so this is an academically derived
>  answer.  According to the manual "Policy delegation is now the
>  preferred method for adding policies to Postfix."
>
>  Bob
>
>

Here's a hacked up version of postfix-policyd that uses the results
from the hostkarma rbl.
I'm sure it can be improved upon, but it works for me.




# postfix-policyd-spf-perl
# http://www.openspf.org/Software
# version 2.004
#
# (C) 2007      Scott Kitterman 
# (C) 2007      Julian Mehnle 
# (C) 2003-2004 Meng Weng Wong 
#
#    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.,
#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


#  hacked up to query hostkama
#  by aaron 



use strict;

use IO::Handle;
use IO::Socket;
use Sys::Syslog qw(:DEFAULT setlogsock);
use NetAddr::IP;
use Net::DNS;
use Fcntl;


require "/etc/eps/config.pl";

# ----------------------------------------------------------
#                      configuration
# ----------------------------------------------------------



# Adding more handlers is easy:
my @HANDLERS = (
    {
        name => 'hostkarma_lookup',
        code => \\&hostkarma_lookup
    },

);

my $VERBOSE = 0;

my $DEFAULT_RESPONSE = 'DUNNO';

#
# Syslogging options for verbose mode and for fatal errors.
# NOTE: comment out the $syslog_socktype line if syslogging does not
# work on your system.
#

my $syslog_socktype = 'unix'; # inet, unix, stream, console
my $syslog_facility = 'mail';
my $syslog_options  = 'pid';
my $syslog_ident    = 'postfix/hk_lookup';

use constant localhost_addresses => map(
    NetAddr::IP->new($_),
    qw(  127.0.0.0/8  ::ffff:127.0.0.0/104  ::1  )
);  # Does Postfix ever say "client_address=::ffff:"?

use constant relay_addresses => map(
    NetAddr::IP->new($_),
    qw(  69.13.218.0/25 72.35.73.193/32 )
); # add addresses to qw (  ) above separated by spaces using CIDR notation.

my %results_cache;  # by message instance

my $dns  = Net::DNS::Resolver->new;


# ----------------------------------------------------------
#                      initialization
# ----------------------------------------------------------

#
# Log an error and abort.
#
sub fatal_exit {
    syslog(err     => "fatal_exit: @_");
    syslog(warning => "fatal_exit: @_");
    syslog(info    => "fatal_exit: @_");
    die("fatal: @_");
}

#
# Unbuffer standard output.
#
STDOUT->autoflush(1);

#
# This process runs as a daemon, so it can't log to a terminal. Use
# syslog so that people can actually see our messages.
#
setlogsock($syslog_socktype);
openlog($syslog_ident, $syslog_options, $syslog_facility);

# ----------------------------------------------------------
#                           main
# ----------------------------------------------------------

#
# Receive a bunch of attributes, evaluate the policy, send the result.
#
my %attr;
while () {
    chomp;

    if (/=/) {
        my ($key, $value) =split (/=/, $_, 2);
        $attr{$key} = $value;
        next;
    }
    elsif (length) {
        syslog(warning => sprintf("warning: ignoring garbage: %.100s", $_));
        next;
    }

    if ($VERBOSE) {
        for (sort keys %attr) {
            syslog(debug => "Attribute: %s=%s", $_, $attr{$_});
        }
    }

    my $message_instance = $attr{instance};
    my $cache = defined($message_instance) ?
$results_cache{$message_instance} ||= {} : {};

    my $action = $DEFAULT_RESPONSE;

    foreach my $handler (@HANDLERS) {
        my $handler_name = $handler->{name};
        my $handler_code = $handler->{code};

        my $response = $handler_code->(attr => \\%attr, cache => $cache);

        if ($VERBOSE) {
            syslog(debug => "handler %s: %s", $handler_name, $response);
        }

        # Pick whatever response is not 'DUNNO'
        if ($response and $response !~ /^DUNNO/i) {
 #           syslog(info => "handler %s: is decisive.", $handler_name);
            $action = $response;
            last;
        }
    }

    syslog(info => "%s: Policy action=%s", $attr{queue_id}, $action);

    STDOUT->print("action=$action\\n\\n");
    %attr = ();
}


# ---------------------------------------
# hostkarma lookup
# ---------------------------------------

sub hostkarma_lookup
{
 local %_ = @_;
 my %attr = %{ $_{attr} };

 my $result = "DUNNO";
 my $color = "pink";

 if ( $attr{client_address} =~ m/(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/ )
 {
  my $laddr = "$4.$3.$2.$1.hostkarma.junkemailfilter.com";

  my $query = $dns->query($laddr, "A");

  if ($query)
  {
   foreach my $rr (grep { $_->type eq 'A' } $query->answer)
   {
    if ($rr->address eq '127.0.0.1')
    {
     # whitelisted
     $result = "OK";
     $color = "white";
    }
    elsif ($rr->address eq '127.0.0.2')
    {
     # blacklisted
     $result = "REJECT $attr{client_address} is blacklisted at
hostkarma.junkemailfilter.com";
     $color = "black";
    }
    elsif ($rr->address eq '127.0.0.3')
    {
     # yellow listed
     $result = "PREPEND X-Hostkarma: Yellowlisted ($attr{client_address})";
     $color = "yellow";
    }
    elsif ($rr->address eq '127.0.0.4')
    {
     # brown listed
     $result = "PREPEND X-Hostkarma: Brownlisted ($attr{client_address})";
     $color = "brown";
    }
#   syslog(info => "%s: HostKarma says %s is %s listed",
$attr{queue_id}, $attr{client_address}, $color );
   }
  }
 }
 return($result);
}


