I decided to stop using my hacky perl script for Postfix policyd stuff as it’s ages since I wrote any perl … and instead use postscreen the other day.
Postscreen setup – was fairly easy – there’s a load of config below.
Gotchas – spamhaus doesn’t like you if you might be sending your DNS through a public resolver (E.g. 8.8.8.8) – so you need to do an =127.0.0.[1..11] to it.
It also logs quite a lot.
Current Postfix postscreen main.cf config :
postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = zen.spamhaus.org=127.0.0.[2..11]*2
bl.spamcop.net*1
b.barracudacentral.org=127.0.0.2*1
bl.spameatingmonkey.net*1
bl.mailspike.net*1
tor.ahnl.org*1
dnsbl.justspam.org=127.0.0.2*1
bip.virusfree.cz*1
spam.dnsbl.sorbs.net=127.0.0.6*1
postscreen_greet_action = enforce
postscreen_greet_wait = 5s
postscreen_greet_ttl = 2d
postscreen_blacklist_action = drop
postscreen_dnsbl_ttl = 2h
SMTP Auth whitelisting …
My server allows people to send out authenticated on port 25, but postscreen doesn’t seem to be aware of this when it runs; so such people may be blocked by their IP being in a DNS Blacklist … and therefore need explicitly whitelisting via a dovecot postlogin script (example below) which if used, requires the postscreen_access_list to change to be something like :
postscreen_access_list = permit_mynetworks
cidr:/etc/postfix/postscreen_access.cidr
mysql:/etc/postfix/mysql/check_mail_log.cf
and /etc/postfix/mysql/check_mail_log.cf looks like :
user = mail_log
password = something
hosts = 127.0.0.1
dbname = mail_log
query = SELECT 'permit' FROM mail_log WHERE ip_address = '%s' UNION SELECT 'dunno' LIMIT 1 ;
The dovecot config change(s) are – in /etc/dovecot/dovecot.conf
....
service pop3 {
executable = pop3 postlogin
}
service imap {
executable = imap postlogin
}
service postlogin {
executable = script-login /etc/dovecot/postlogin.sh
user = $default_internal_user
unix_listener postlogin {
}
}
....
and /etc/dovecot/postlogin.sh looks a bit like :
#!/bin/bash
if [ "x${IP}" != "x" ]; then
if [ ! "$IP" = "127.0.0.1" ]; then
echo "INSERT INTO mail_log (username, ip_address) VALUES ('$USER', '$IP')" | mysql --defaults-extra-file=/etc/dovecot/mysql.cnf mail_log
fi
fi
exec "$@"
exit 0
The /etc/dovecot/postlogin.sh will need to be executable.
/etc/dovecot/mysql.cnf just looks like a normal MySQL cnf file –
[client]
user = mail_log
password = something
database = mail_log
CREATE TABLE `mail_log` (
`username` varchar(255) NOT NULL,
`ip_address` varchar(255) NOT NULL,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY `mlip` (`ip_address`(191)),
KEY `dt_idx` (`dt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
and that being the SQL schema.
Ideally I suppose you’d add a cron job to prune entries in mail_log older than a set time, and probably have a unique key on username with some sort of “INSERT INTO x ON DUPLICATE … ” change to the postlogin.sh script above.