server:policyd-weight

policyd-weight

Policyd-weight ist ein E-Mail-Filter für den Postfix Mail Transfer Agent der von Robert Felber in Perl entwickelt wurde. Policyd-weight untersucht die Mail bei der Einlieferung anhand des Envelope Sender, des Envelope To und der HELO-Daten, die während des SMTP-Handshakes übertragen werden und vergibt für verschiedene Kriterien Punkte. Dabei werden zum Beispiel Realtime Blackhole Listen abgefragt oder die DNS-Konfiguration des Absenders überprüft. Für jeden Regelverstoß gibt es negative Punkte und ab einer bestimmten Wertung wird die Mail abgelehnt.

Wird die Mail akzeptiert wird sie üblicherweise noch anderen Antispammaßnahmen unterzogen. Da policyd-weight nicht mit der kompletten Mail arbeitet werden Ressourcen des Servers gespart.

Quelle: Wikipedia.

Wenn keine Datei /etc/policyd-weight.conf existiert gelten die Standard-einstellungen die im Programm hinterlegt sind. Die unten aufgeführten Einstellungen (könnten je nach Programmversionen anders lauten) erzeugt der folgenden Befehl und speichert diese gleich in /etc/policyd-weight.conf ab.

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

Zu Einstellungen siehe auch:

man 5 policyd-weight.conf

:!: Leider kommt es vor das Blacklists nicht mehr weiterbetrieben werden und dann eine Antwort liefern die von policyd-weight als „IP-Adresse ist dort gelistet“ interpretiert werden. In der aktuellen Version bei Debian ist dies aktuell bei rbl.ipv6-world.net der Fall:

'rbl.ipv6-world.net',     4.25,          0,        'IPv6_RBL'

Diese Zeile führt dazu das JEDE mail automatisch 4,25 Punkte mehr zugewiesen bekommt was einige schlecht konfigurierte Server über die Ablehnungsschwelle bringt. Deshalb sollte diese Zeile entfernt werden!

Das gleiche gilt für die nicht existente Liste dnsbl.njabl.org:

'dnsbl.njabl.org',        4.25,       -1.5,        'BL_NJABL'

In den Logdateien tauschen diese Einträge mit IN_IPv6_RBL=4.25 und NOT_IN_BL_NJABL=-1.5 auf, wobei letzteres sogar „postiv“ wirkt weil der Scorte um 1,5 Punkte gesenkt wird. In dem Augenblick allerdings wo diese Liste auch alle positiv zurückmeldet wird daraus ein Problem das man schon jetzt beheben sollte.

Siehe auch Debian Bug #641227 und Postfixbuch-users Policyd-weight und IPv6_RBL generiert false-positives sowie Debian Bug #471645.

Manche Organisation bekommen es nicht hin, ein standardkonformes Mailsetup vorzunehmen. Insbesondere wenn die komplette Versandinfrastruktur ausgelagert ist und mails von Servern eingeliefert werden die nicht im MX Record der Domain stehen bzw. auch nicht aus den selben IP-Netz stammen sieht es für einen restriktiv eingestellten Spamfilter so aus, also ob jemand vorgibt in Namen dritter mails zuzustellen für die er nicht autorisiert wurde.

Das sieht dann bei policyd-weight z. B. so aus:

FROM/MX_MATCHES_NOT_HELO(DOMAIN)=2.062
CLIENT_NOT_MX/A_FROM_DOMAIN=5.75
CLIENT/24_NOT_MX/A_FROM_DOMAIN=5.75

Da macht schonmal 13,562 unnötige Punkte in der Bewertung, ist man dann noch auf eine Blacklist gerutscht bzw. macht einen weiteren Konfigurationfehler dann wird die ganze Kommunikation blockiert.

Da solche Organisationen selten einsichtig sind ist man wahrscheinlich gezwungen eine Ausnahmeregel einzurichten. Hier im Beispiel für „sloppy-mail-setup.de“ wird die Domain von allen Checks bis auf die Blacklists ausgeschlossen:

  @dnsbl_checks_only_regexps = (
    # qr/[^.]*(exch|smtp|mx|mail).*\..*\../,
    # qr/yahoo.com$/
     qr/sloppy-mail-setup.de$/,
);

Im Protokoll steht dann folgendes:

X-policyd-weight:  NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_IX_MANITU=-1.5 (only DNSBL check requested (regex-nr: 3))

Wer selbst Mailserver betreibt wird (aus Arbeitsvermeidungs- oder anderen Gründen) versucht sein policy-weightd für manche Kunden (Empfängerdomains) zu deaktivieren. Das geht nicht direkt in policyd-weight weil er damit zum lügen angehalten werden soll: Für bestimmte Empfänger würde er den Absenderserver immer in Ordnung finden (egal was der anstellt hat), für den Rest korrekt antworten (Absenderserver sieht aus wie ein Spammer). Das macht so keinen Sinn.

Es gibt diesen Weg so etwas dennoch zu bauen:

Der MTA (Postfix etc. der policyd-weight fragt) muss mails für den Empfänger generell whitelisten: Im Falle von Postfix wäre ein Eintrag bei „check_recipient_access“ nötig („foobar.de OK“). Damit würde Postfix an dieser Stelle die mail annehmen und policyd-weight muss nicht selektiv Unsinn erzählen. Die Spam-Rate für diese Domain wird wahrscheinlich merklich ansteigen weil der wichtige Spamcheck übersprungen wird. Das whitelisting muss allerdings vor der policyd-weight-Abfrage stehen.

Alternativ (meine Empfehlung) doch die Störenfriede einzeln whitelisten (so viele dürften es wohl auch nicht sein?) so dass immerhin blacklist-Tests für den Empfänger durchgeführt werden (weniger Spam), aber die kaputten mail-Versender dennoch mails abladen können:

@dnsbl_checks_only_regexps = (
   # broken senders:
     qr/DEFEKTER-SERVER1.com$/,
     qr/DEFEKTER-SERVER2.com$/
)
# ----------------------------------------------------------------
#  policyd-weight configuration (defaults) Version 0.1.15 devel-1 
# ----------------------------------------------------------------


   $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_IF_REJECT, 
                                    # 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)
                                    # If ON request that ALL clients are only
                                    # checked against RBLs

   @dnsbl_checks_only_regexps = (
    # qr/[^.]*(exch|smtp|mx|mail).*\..*\../,
    # qr/yahoo.com$/
);                                  # specify a comma-separated list of regexps
                                    # for client hostnames which shall only
                                    # be RBL checked. This does not work for
                                    # postfix' "unknown" clients.
                                    # The usage of this should not be the norm
                                    # and is a tool for people which like to
                                    # shoot in their own foot.
                                    # DEFAULT: empty
                                    

   $LOG_BAD_RBL_ONLY  = 1;          # 1: ON (default), 0: OFF
                                    # When set to ON it logs only RBLs which
                                    # affect scoring (positive or negative)
                                    
## DNSBL settings
   @dnsbl_score = (
#    HOST,                    HIT SCORE,  MISS SCORE,  LOG NAME
    'pbl.spamhaus.org',       3.25,          0,        'DYN_PBL_SPAMHAUS',
    'sbl-xbl.spamhaus.org',   4.35,       -1.5,        'SBL_XBL_SPAMHAUS',
    'bl.spamcop.net',         3.75,       -1.5,        'SPAMCOP',
    'ix.dnsbl.manitu.net',    4.35,       -1.5,        'IX_MANITU',
);

   $MAXDNSBLHITS  = 2;  # If Client IP is listed in MORE
                        # DNSBLS than this var, it gets
                        # REJECTed immediately

   $MAXDNSBLSCORE = 8;  # 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',              4,        0,        'AHBL',
    'dsn.rfc-ignorant.org',        3.5,      0,        'DSN_RFCI',
    'postmaster.rfc-ignorant.org', 0.1,      0,        'PM_RFCI',
    'abuse.rfc-ignorant.org',      0.1,      0,        'ABUSE_RFCI'
);

   $BL_ERROR_SKIP     = 2;  # skip a RBL if this RBL had this many continuous
                            # errors

   $BL_SKIP_RELEASE   = 10; # skip a RBL for that many times

## cache stuff
   $LOCKPATH          = '/var/run/policyd-weight/';    # must be a directory (add
                                                    # trailing slash)

   $SPATH             = $LOCKPATH.'/polw.sock';     # socket path for the cache
                                                    # daemon. 

   $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       = 2000; # set to 0 to disable caching for spam results. 
                            # To this level the cache will be cleaned.

   $CACHEMAXSIZE    = 4000; # 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    = 1000; # set to 0 to disable caching of HAM. To this number
                            # of entries the cache will be cleaned

   $POSCACHEMAXSIZE = 2000; # at this number of entries cleanup takes place

   $POSCACHEMSG     = 'using cached result';

   $PTTL            = 60;   # after PTTL requests the HAM entry must
                            # succeed one time the RBL checks again

   $PTIME           = '3h'; # after $PTIME in HAM Cache the client
                            # must pass one time the RBL checks again.
                            # Values must be nonfractal. Accepted
                            # time-units: s, m, h, d

   $TEMP_PTIME      = '1d'; # The client must pass this time the RBL
                            # checks in order to be listed as hard-HAM
                            # After this time the client will pass
                            # immediately for PTTL within PTIME


## DNS settings
   $DNS_RETRIES     = 2;    # Retries for ONE DNS-Lookup

   $DNS_RETRY_IVAL  = 2;    # Retry-interval for ONE DNS-Lookup

   $MAXDNSERR       = 3;    # max error count for unresponded queries
                            # in a complete policy query

   $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


   $NS              = '';   # A list of space separated NS IPs
                            # This overrides resolv.conf settings
                            # Example: $NS = '1.2.3.4 1.2.3.5';
                            # DEFAULT: empty


   $IPC_TIMEOUT     = 2;    # timeout for receiving from cache instance

   $TRY_BALANCE     = 0;    # If set to 1 policyd-weight closes connections
                            # to smtpd clients in order to avoid too many
                            # established connections to one policyd-weight
                            # child

# scores for checks, WARNING: they may manipulate eachother
# or be factors for other scores.
#                                       HIT score, MISS 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               = (2.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.5,        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    );
   @enforce_dyndns_score             = (3,          0    );


   $VERBOSE = 0;

   $ADD_X_HEADER        = 1;    # Switch on or off an additional 
                                # X-policyd-weight: header
                                # DEFAULT: on


   $DEFAULT_RESPONSE    = 'DUNNO default'; # Fallback response in case
                                           # the weighted check didn't
                                           # return any response (should never
                                           # appear).



#
# 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";