Postfix mit policyd-weight erweitern (Howto)

Nachdem wir Postfix im Finetuning Howto schon einige sehr wirkungsvolle Konfigurationsabschnitte unterbreitet haben kommt nun ergänzend noch ein Tool als Erweiterung dazu. Der policy-weight Daemon wird noch vor amavis aktiv und prüft die Mail bei Eintreffen bereits an der Haustüre auf ihren Spamgehalt. Dazu bedient es sich eines kleinen Netzwerkes, gegen dass die entsprechenden Anfragen gestartet werden. Ist ein Rechner innerhalb dieses Blacklist-Netzwerks bekannt, wird die Email nicht angenommen. Der Daemon kann die Ergebnisse zwischenspeichern, so dass nicht für jede Email ein erneuter Verbindungsaufbau nötig ist.

Wir erzeugen zunächst die Defaultconfig. Diese wird vom Programm selbst erstellt:

policyd-weight defaults > /etc/policyd-weight.conf

Der Parameter $MAXDNSBLHITS gibt an, wie oft eine IP Adresse in einer Blacklist auftauchen muss, bevor die Email verworfen wird. Hier sollte man mindestens 2 Eintragen, besser 3. Das hat den Hintergrund, dass auch öffentliche Server, die kein Spam versenden unter Umständen in diesen Listen auftauchen können. Bis zur Entfernung kann einige Zeit vergehen, so dass ein System in der einen Blacklist noch als Spammer gelistet ist, während alle anderen Blacklistanbieter ihre Daten schon aktualisiert haben.

$MAXDNSBLHITS  = 2;

Der folgende Parameter gibt die Score an, die nötig ist, damit eine Email verworfen wird.

$MAXDNSBLSCORE = 8;

In der /etc/postfix/main.cf von Postfix müssen wir noch folgende Zeile angeben, damit der Daemon mit Postfix interagieren kann. Bei der Anweisung handelt es sich um eine Option für den Abschnitt smtpd_recipient_restrictions:

check_policy_service inet:127.0.0.1:12525

Der enstprechende Abschnitt in der main.cf sieht dann wie folgt aus – vorrausgesetzt, die Anweisungen aus den vorherigen Howtos wurden komplett umgesetzt:

smtpd_recipient_restrictions =
        permit_mynetworks,
        reject_unknown_recipient_domain,
        permit_sasl_authenticated,
        reject_unauth_destination,
        reject_invalid_hostname,
        reject_non_fqdn_hostname,
        reject_non_fqdn_sender,
        reject_non_fqdn_recipient,
        reject_unknown_sender_domain,
        reject_unknown_recipient_domain,
        reject_unauth_pipelining,
        reject_unauth_destination,
        check_policy_service inet:127.0.0.1:12525

Hier dann noch meine komplette Konfigurationsdatei. Bitte den Zeilenumbruch bei der Konstante REJECTMSG entfernen: Konfigurationsdatei Policy-Weight Daemon

# ----------------------------------------------------------------
#  policyd-weight configuration (defaults) Version 0.1.14 beta
# ----------------------------------------------------------------
   $DEBUG        = 0;               # 1 or 0 - don't comment
   $REJECTMSG    = "550 Mail appeared to be SPAM or forged. Ask your Mail/DNS-Administrator to
		    correct HELO and DNS MX settings or to get removed from DNSBLs";
   $REJECTLEVEL  = 1;               # Mails with scores which exceed this
                                    # REJECTLEVEL will be rejected
   $DEFER_STRING = 'IN_SPAMCOP= BOGUS_MX=';
                                    # A space separated case-sensitive list of
                                    # strings on which if found in the $RET
                                    # logging-string policyd-weight changes
                                    # its action to $DEFER_ACTION in case
                                    # of rejects.
                                    # USE WITH CAUTION!
                                    # DEFAULT: "IN_SPAMCOP= BOGUS_MX="
   $DEFER_ACTION = '450';           # Possible values: DEFER_IF_PERMIT,
                                    # DEFER_IFREJECT,
                                    # 4xx response codes. See also access(5)
                                    # DEFAULT: 450
   $DEFER_LEVEL  = 5;               # DEFER mail only up to this level
                                    # scores greater than DEFER_LEVEL will be
                                    # rejected
                                    # DEFAULT: 5
   $DNSERRMSG         = '450 No DNS entries for your MTA, HELO and Domain. Contact YOUR administrator';
   $dnsbl_checks_only = 0;          # 1: ON, 0: OFF (default)
   $LOG_BAD_RBL_ONLY  = 1;          # 1: ON (default), 0: OFF
## DNSBL settings
   @dnsbl_score = (
#    HOST,                    BAD SCORE,  GOOD SCORE,   LOG NAME
    'dynablock.njabl.org',    3.25,          0,        'DYN_NJABL',
    'sbl-xbl.spamhaus.org',   4.35,       -1.5,        'SBL_XBL_SPAMHAUS',
    'bl.spamcop.net',         3.75,       -1.5,        'SPAMCOP',
    'dnsbl.njabl.org',        4.25,       -1.5,        'BL_NJABL',
    'list.dsbl.org',          4.35,          0,        'DSBL_ORG',
    'ix.dnsbl.manitu.net',    4.35,          0,        'IX_MANITU',
);
   $MAXDNSBLHITS  = 4;  # If Client IP is listed in MORE
                        # DNSBLS than this var, it gets
                        # REJECTed immediately
   $MAXDNSBLSCORE = 16;  # alternatively, if the score of
                        # DNSBLs is ABOVE this
                        # level, reject immediately
   $MAXDNSBLMSG   = '550 Your MTA is listed in too many DNSBLs';
## RHSBL settings
   @rhsbl_score = (
    'multi.surbl.org',             4,        0,        'SURBL',
    'rhsbl.ahbl.org',              1.8,      0,        'AHBL',
    'dsn.rfc-ignorant.org',        3.2,      0,        'DSN_RFCI',
    'postmaster.rfc-ignorant.org', 0.1,      0,        'PM_RFCI',
    'abuse.rfc-ignorant.org',      0.1,      0,        'ABUSE_RFCI'
);
## cache stuff
   $LOCKPATH          = '/tmp/.policyd-weight/';    # must be a directory (add
                                                    # trailing slash)
   $SPATH             = $LOCKPATH.'/polw.sock';
   $MAXIDLECACHE      = 60; # how many seconds the cache may be idle
                            # before starting maintenance routines
                            # NOTE: standard maintenance jobs happen
                            # regardless of this setting.
   $MAINTENANCE_LEVEL = 5;  # after this number of requests do following
                            # maintenance jobs:
                            # checking for config changes
# negative (i.e. SPAM) result cache settings ##################################
   $CACHESIZE       = 320;  # set to 0 to disable caching for spam results.
                            # To this level the cache gets shrunked on cleanups
   $CACHEMAXSIZE    = 480;  # at this number of entries cleanup takes place
   $CACHEREJECTMSG  = '550 temporarily blocked because of previous errors';
   $NTTL            = 1;    # after NTTL retries the cache entry is deleted
   $NTIME           = 30;   # client MUST NOT retry within this seconds in order
                            # to decrease TTL counter
# positve (i.,e. HAM) result cache settings ###################################
   $POSCACHESIZE    = 320;  # set to 0 to disable caching of HAM. On this level
                            # the cache gets shrunk on cleanups
   $POSCACHEMAXSIZE = 480;  # at this number of entries cleanup takes place
   $POSCACHEMSG     = 'using cached result';
   $PTTL            = 60;   # after PTTL request the HAM entry is deletet
                            # from cache and it must been reverified
## DNS settings
   $DNS_RETRIES     = 2;
   $DNS_RETRY_IVAL  = 2;
   $MAXDNSERR       = 3;    # max error count for unresponded queries
   $MAXDNSERRMSG    = 'passed - too many local DNS-errors';
   $PUDP            = 0;    # persistent udp connection for DNS queries.
                            # broken in Net::DNS version 0.51. Works with
                            # Net::DNS 0.53; DEFAULT: off
   $USE_NET_DNS     = 0;    # Force the usage of Net::DNS for RBL lookups.
                            # Normally policyd-weight tries to use a faster
                            # RBL lookup routine instead of Net::DNS
   $IPC_TIMEOUT     = 2;    # timeout for receiving from cache instance
# scores for checks, WARNING: they may manipulate eachother
# or be factors for other scores.
#                                       Bad score, Good Score
   @client_ip_eq_helo_score          = (1.5,       -1.25 );
   @helo_score                       = (1.5,       -2    );
   @helo_from_mx_eq_ip_score         = (1.5,       -3.1  );
   @helo_numeric_score               = (1.5,        0    );
   @from_match_regex_verified_helo   = (1,         -2    );
   @from_match_regex_unverified_helo = (1.6,       -1.5  );
   @from_match_regex_failed_helo     = (2.5,        0    );
   @helo_seems_dialup                = (1,          0    );
   @failed_helo_seems_dialup         = (2,          0    );
   @helo_ip_in_client_subnet         = (0,         -1.2  );
   @helo_ip_in_cl16_subnet           = (0,         -0.41 );
   @client_seems_dialup_score        = (3.75,       0    );
   @from_multiparted                 = (1.09,       0    );
   @from_anon                        = (1.17,       0    );
   @bogus_mx_score                   = (2.1,        0    );
   @random_sender_score              = (0.25,       0    );
   @rhsbl_penalty_score              = (3.1,        0    );
   $VERBOSE = 0;
   $ADD_X_HEADER        = 1;    # switch on or off an additional
                                # X-policyd-weight: header
                                # DEFAULT: on
   $DEFAULT_RESPONSE    = 'DUNNO default';
#
# Syslogging options for verbose mode and for fatal errors.
# NOTE: comment out the $syslog_socktype line if syslogging does not
# work on your system.
#
   $syslog_socktype = 'unix';   # inet, unix, stream, console
   $syslog_facility = "mail";
   $syslog_options  = "pid";
   $syslog_priority = "info";
   $syslog_ident    = "postfix/policyd-weight";
#
# Process Options
#
   $USER            = "polw";      # User must be a username, no UID
   $GROUP           = "";          # specify GROUP if necessary
                                   # DEFAULT: empty, will be initialized as
                                   # $USER
   $MAX_PROC        = 50;          # Upper limit if child processes
   $MIN_PROC        = 3;           # keep that minimum processes alive
   $TCP_PORT        = 12525;       # The TCP port on which policyd-weight
                                   # listens for policy requests from postfix
   $BIND_ADDRESS    = '127.0.0.1'; # IP-Address on which policyd-weight will
                                   # listen for requests.
                                   # You may only list ONE IP here, if you want
                                   # to listen on all IPs you need to say 'all'
                                   # here. Default is '127.0.0.1'.
                                   # You need to restart policyd-weight if you
                                   # change this.
   $SOMAXCONN       = 1024;        # Maximum of client connections
                                   # policyd-weight accepts
                                   # Default: 1024
   $CHILDIDLE       = 240;         # how many seconds a child may be idle before
                                   # it dies.
   $PIDFILE         = "/var/run/policyd-weight.pid";

About the author