check
------
we check
# id vmail uid=150(vmail) gid=8(mail) groups=8(mail),121(dovecot)
Sieve
cat /etc/dovecot/conf.d/90-sieve.conf | grep -v "#" | grep -v "^ *$" plugin { sieve_dir = ~/sieve sieve = ~/sieve/dovecot.sieve sieve_global_dir = /var/vmail/sieve sieve_before = /var/vmail/sieve/dovecot.sieve sieve_max_redirects = 30 sieve_vacation_send_from_recipient = yes }
Activate sieve for lmtp protocol
cat 10-director.conf | grep -v "^ *#" | grep -v "^ *$" service director { unix_listener login/director { } fifo_listener login/proxy-notify { } unix_listener director-userdb { } inet_listener { } } service imap-login { } service pop3-login { } protocol lmtp { mail_plugins = $mail_plugins sieve }
And for protocol lda
cat 15-lda.conf | grep -v "^ *#" | grep -v "^ *$" postmaster_address = domain@oamis.net protocol lda { mail_plugins = $mail_plugins sieve }
We create the master sieve file
cd /var/vmail/mkdir sievechown vmail:mail sieve/cd sieve/cat dovecot.sieve require ["fileinto"];
# rule:[Move Spam to Junk Folder] if header :is "X-Spam-Flag" "YES" { fileinto "Junk"; } # rule:[Openmarc fails to Junk Folder] if header :contains "Authentication-Results" "OpenDmarc; dmarc=fail" { fileinto "Junk"; }
chmod 500 dovecot.sievechown vmail:mail dovecot.sieve
SpamAssassin
spamassassin -V SpamAssassin version 3.4.2 running on Perl version 5.26.1
Download schema and create database
wget http://svn.apache.org/repos/asf/spamassassin/tags/spamassassin_release_3_4_2/sql/bayes_mysql.sqlmysql -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 3267 Server version: 5.7.27-0ubuntu0.18.04.1-log (Ubuntu) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> create database sa_bayes; Query OK, 1 row affected (0.01 sec) mysql> use sa_bayes; Database changed mysql> source bayes_mysql.sql Query OK, 0 rows affected (0.09 sec) Query OK, 0 rows affected (0.02 sec) Query OK, 1 row affected (0.02 sec) Query OK, 0 rows affected (0.02 sec) Query OK, 0 rows affected (0.03 sec) Query OK, 0 rows affected (0.03 sec) mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON sa_bayes.* TO sa_user@localhost IDENTIFIED BY 'xxxxxxxxxxxxxxxxx'; Query OK, 0 rows affected, 1 warning (0.07 sec) mysql> flush privileges; Query OK, 0 rows affected (0.02 sec) mysql> quit Bye
Modify setup
cd /etc/spamassassin/ cat /etc/spamassassin/local.cf | grep -v "^#" | grep -v "^ *$" ifplugin Mail::SpamAssassin::Plugin::Shortcircuit endif # Mail::SpamAssassin::Plugin::Shortcircuit required_score 5.0 rewrite_header subject 🚽⛔ report_safe 0 lock_method flock use_bayes 1 bayes_auto_learn 1 bayes_auto_expire 1 bayes_store_module Mail::SpamAssassin::BayesStore::MySQL bayes_sql_dsn DBI:mysql:sa_bayes:127.0.0.1:3306 bayes_sql_username sa_user bayes_sql_password xxxxxxxxxxxxxxxxx score DNS_FROM_AHBL_RHSBL 0 score URIBL_AB_SURBL 0 0.3306 0 0.3812 score URIBL_JP_SURBL 0 0.3360 0 0.4087 score URIBL_OB_SURBL 0 0.2617 0 0.3008 score URIBL_PH_SURBL 0 0.2240 0 0.2800 score URIBL_SBL 0 0.1094 0 0.1639 score URIBL_SC_SURBL 0 0.3600 0 0.4498 score URIBL_WS_SURBL 0 0.1533 0 0.2140 loadplugin Mail::SpamAssassin::Plugin::DKIM whitelist_from_dkim *@paypal.com whitelist_from_dkim *@linkedin.com whitelist_from_dkim *@twitter.com whitelist_from_dkim *@bounce.twitter.com ok_locales all score RP_MATCHES_RCVD 0
Amavis, ClamAV, and SpamAssassin
add users to group of each other
adduser amavis clamav Adding user `amavis' to group `clamav' ... Adding user amavis to group clamav Done.
We check
id clamav uid=115(clamav) gid=123(clamav) groups=123(clamav),127(amavis) id amavis uid=119(amavis) gid=127(amavis) groups=127(amavis),123(clamav)
Enable amavis
Enable antivirus and spam check
cat /etc/amavis/conf.d/15-content_filter_mode | grep -v "#" | grep -v "^$" use strict; @bypass_virus_checks_maps = ( \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); @bypass_spam_checks_maps = ( \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
Enable spamassasin
We change the option ENABLE from 0 to 1 and CRON from 0 to 1 in file /etc/default/spamassassin
cat /etc/default/spamassassin | grep -v "#" | grep -v "^$" ENABLED=1 OPTIONS="--create-prefs --max-children 5 --helper-home-dir" PIDFILE="/var/run/spamd.pid" CRON=1
Enable it.
systemctl enable spamassassin.service Synchronizing state of spamassassin.service with SysV init with /lib/systemd/systemd-sysv-install... Executing /lib/systemd/systemd-sysv-install enable spamassassin
Ensure mails through amavis are for local delivery
We let deliver spam mails
cat /etc/amavis/conf.d/50-user | grep -v "^#" | grep -v "^$" use strict; $final_virus_destiny = D_DISCARD; # (data not lost, see virus quarantine) $final_banned_destiny = D_BOUNCE; # D_REJECT when front-end MTA $final_spam_destiny = D_PASS; $final_bad_header_destiny = D_PASS; # False-positive prone (for spam) $max_servers = 3; $sa_tag_level_deflt = -9999; @lookup_sql_dsn = ( ['DBI:mysql:database=mail;host=127.0.0.1;port=3306', 'postfix', 'postfixpassowrd']); $sql_select_policy = 'SELECT domain from domain WHERE CONCAT("@",domain) IN (%k)'; 1; # ensure a defined return
Update clamav database
# freshclam Sun Aug 26 20:42:35 2018 -> ClamAV update process started at Sun Aug 26 20:42:35 2018 Sun Aug 26 20:42:38 2018 -> Downloading main.cvd [100%] Sun Aug 26 20:42:49 2018 -> main.cvd updated (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr) Sun Aug 26 20:42:51 2018 -> Downloading daily.cvd [100%] Sun Aug 26 20:42:57 2018 -> daily.cvd updated (version: 24875, sigs: 2064192, f-level: 63, builder: neo) Sun Aug 26 20:42:57 2018 -> Downloading bytecode.cvd [100%] Sun Aug 26 20:42:58 2018 -> bytecode.cvd updated (version: 327, sigs: 91, f-level: 63, builder: neo) Sun Aug 26 20:43:03 2018 -> Database updated (6630532 signatures) from db.local.clamav.net (IP: 2400:cb00:2048:1::6810:bd8a) Sun Aug 26 20:43:03 2018 -> ^Clamd was NOT notified: Can't connect to clamd through /var/run/clamav/clamd.ctl: No such file or directory
Restart services
clamav
systemctl restart clamav-daemonsystemctl status clamav-daemon ● clamav-daemon.service - Clam AntiVirus userspace daemon Loaded: loaded (/lib/systemd/system/clamav-daemon.service; enabled; vendor preset: enabled) Drop-In: /etc/systemd/system/clamav-daemon.service.d └─extend.conf Active: active (running) since Sun 2018-08-26 20:44:08 CEST; 6s ago Docs: man:clamd(8) man:clamd.conf(5) https://www.clamav.net/documents/ Process: 13261 ExecStartPre=/bin/chown clamav /run/clamav (code=exited, status=0/SUCCESS) Process: 13256 ExecStartPre=/bin/mkdir /run/clamav (code=exited, status=0/SUCCESS) Main PID: 13264 (clamd) CGroup: /system.slice/clamav-daemon.service └─13264 /usr/sbin/clamd --foreground=true
Aug 26 20:44:08 rigel systemd[1]: Starting Clam AntiVirus userspace daemon... Aug 26 20:44:08 rigel systemd[1]: Started Clam AntiVirus userspace daemon.
amavis
systemctl restart amavissystemctl status amavis ● amavis.service - LSB: Starts amavisd-new mailfilter Loaded: loaded (/etc/init.d/amavis; bad; vendor preset: enabled) Active: active (running) since Sun 2018-08-26 20:45:21 CEST; 9s ago Docs: man:systemd-sysv-generator(8) Process: 13272 ExecStop=/etc/init.d/amavis stop (code=exited, status=0/SUCCESS) Process: 13280 ExecStart=/etc/init.d/amavis start (code=exited, status=0/SUCCESS) CGroup: /system.slice/amavis.service ├─ 635 /usr/sbin/amavisd-new (master ├─13293 /usr/sbin/amavisd-new (master ├─13295 /usr/sbin/amavisd-new (virgin child ├─13296 /usr/sbin/amavisd-new (virgin child ├─13297 /usr/sbin/amavisd-new (virgin child ├─37445 /usr/sbin/amavisd-new (master ├─43440 /usr/sbin/amavisd-new (virgin child ├─43464 /usr/sbin/amavisd-new (virgin child ├─43577 /usr/sbin/amavisd-new (virgin child └─43578 /usr/sbin/amavisd-new (virgin child Aug 26 20:45:21 rigel amavis[13293]: Found decoder for .lha at /usr/bin/7z Aug 26 20:45:21 rigel amavis[13293]: Found decoder for .iso at /usr/bin/7z Aug 26 20:45:21 rigel amavis[13293]: Found decoder for .exe at /usr/bin/unrar-free; /usr/bin/arj Aug 26 20:45:21 rigel amavis[13293]: No decoder for .F Aug 26 20:45:21 rigel amavis[13293]: No decoder for .lrz Aug 26 20:45:21 rigel amavis[13293]: No decoder for .lz4 Aug 26 20:45:21 rigel amavis[13293]: Using primary internal av scanner code for ClamAV-clamd Aug 26 20:45:21 rigel amavis[13293]: Found secondary av scanner ClamAV-clamscan at /usr/bin/clamscan Aug 26 20:45:21 rigel amavis[13293]: Deleting db files snmp.db,__db.003,__db.001,nanny.db,__db.002 in /var/lib/amavis/db Aug 26 20:45:21 rigel amavis[13293]: Creating db in /var/lib/amavis/db/; BerkeleyDB 0.55, libdb 5.3
spamassassin
systemctl restart spamassassinsystemctl status spamassassin ● spamassassin.service - Perl-based spam filter using text analysis Loaded: loaded (/lib/systemd/system/spamassassin.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2018-08-26 20:47:02 CEST; 6s ago Process: 13304 ExecStart=/usr/sbin/spamd -d --pidfile=/var/run/spamassassin.pid $OPTIONS (code=exited, status=0/SUCCESS) Main PID: 13307 (/usr/sbin/spamd) CGroup: /system.slice/spamassassin.service ├─13307 /usr/sbin/spamd -d --pidfile=/var/run/spamassassin.pid --create-prefs --max-children 5 --helper-home-di ├─13309 spamd chil └─13310 spamd chil Aug 26 20:46:58 rigel systemd[1]: Starting Perl-based spam filter using text analysis... Aug 26 20:46:58 rigel spamd[13304]: logger: removing stderr method Aug 26 20:46:59 rigel spamd[13307]: zoom: able to use 353/353 'body_0' compiled rules (100%) Aug 26 20:47:02 rigel spamd[13307]: spamd: server started on IO::Socket::IP [::1]:783, IO::Socket::IP [127.0.0.1]:783 (running version 3.4.1) Aug 26 20:47:02 rigel spamd[13307]: spamd: server pid: 13307 Aug 26 20:47:02 rigel spamd[13307]: spamd: server successfully spawned child process, pid 13309 Aug 26 20:47:02 rigel systemd[1]: Started Perl-based spam filter using text analysis. Aug 26 20:47:02 rigel spamd[13307]: spamd: server successfully spawned child process, pid 13310 Aug 26 20:47:02 rigel spamd[13307]: prefork: child states: IS Aug 26 20:47:02 rigel spamd[13307]: prefork: child states: II
Automatic learning from spam or ham
Feed spamassassin with a spam message to initialize the database
cd /usr/share/doc/spamassassin/examples/sa-learn --spam --username=vmail sample-spam.txt Learned tokens from 1 message(s) (1 message(s) examined)
We check version to be sure dovecot is over 2.2.24
dovecot --version 2.2.33.2 (d6601f4ec)
We add the parameter mail_attribute_dict
cat /etc/dovecot/conf.d/10-mail.conf | grep mail_attribute_dict mail_attribute_dict = file:%h/dovecot-attributes
We add the plugin imap_sieve to imap protocol
cat /etc/dovecot/conf.d/20-imap.conf | grep -v "^ *#" | grep -v "^ *$" protocol imap { mail_plugins = imap_sieve }
Setup of plugin imapsieve
cat /etc/dovecot/conf.d/90-sieve-extprograms.conf | grep -v "^ *#" | grep -v "^ *$" plugin { sieve_plugins = sieve_imapsieve sieve_extprograms imapsieve_url = sieve://127.0.0.1:4190 imapsieve_mailbox1_name = Junk imapsieve_mailbox1_causes = COPY APPEND imapsieve_mailbox1_before = file:/var/vmail/sieve/report_spam.sieve imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Junk imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_before = file:/var/vmail/sieve/report_ham.sieve sieve_pipe_bin_dir = /etc/dovecot/sieve/pipe sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment }
We create needed folder
mkdir -p /etc/dovecot/sieve/pipemkdir -p /var/vmail/imapsieve_copychown vmail:mail /var/vmail/imapsieve_copychmod 0700 /var/vmail/imapsieve_copy
We create sieve rule for spam
cat /var/vmail/sieve/report_spam.sieve require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; if environment :matches "imap.user" "*" { set "username" "${1}"; } pipe :copy "imapsieve_copy" [ "${username}", "spam" ];
We create the sieve rules for ham
cat /var/vmail/sieve/report_ham.sieve require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; if environment :matches "imap.mailbox" "*" { set "mailbox" "${1}"; } if string "${mailbox}" "Trash" { stop; } if environment :matches "imap.user" "*" { set "username" "${1}"; } pipe :copy "imapsieve_copy" [ "${username}", "ham" ];
Script pipe run when move mails from/to spam
cat /etc/dovecot/sieve/pipe/imapsieve_copy #!/usr/bin/env bash # Author: Zhang Huangbin <zhb@iredmail.org> # Purpose: Read full email message from stdin, and save to a local file.
# Usage: bash imapsieve_copy <email> <spam|ham> <output_base_dir>
export USER="$1" export MSG_TYPE="$2"
export OUTPUT_BASE_DIR="/var/vmail/imapsieve_copy" export OUTPUT_DIR="${OUTPUT_BASE_DIR}/${MSG_TYPE}" export FILE="${OUTPUT_DIR}/${USER}-$(date +%Y%m%d%H%M%S)-${RANDOM}${RANDOM}.eml"
export OWNER="vmail" export GROUP="mail"
for dir in "${OUTPUT_BASE_DIR}" "${OUTPUT_DIR}"; do if [[ ! -d ${dir} ]]; then mkdir -p ${dir} chown ${OWNER}:${GROUP} ${dir} chmod 0700 ${dir} fi done
cat > ${FILE} < /dev/stdin
# Logging export LOG='logger -p local5.info -t imapsieve_copy' [[ $? == 0 ]]> && ${LOG} "Copied one ${MSG_TYPE} email reported by ${USER}: ${FILE}"
Fix file rights
chown vmail:mail /var/vmail/sieve/report_spam.sieve /var/vmail/sieve/report_ham.sieve /etc/dovecot/sieve/pipe/imapsieve_copychmod 700 /var/vmail/sieve/report_spam.sieve /var/vmail/sieve/report_ham.sieve /etc/dovecot/sieve/pipe/imapsieve_copy
Restart dovecot service
systemctl restart dovecot systemctl status dovecot ● dovecot.service - Dovecot IMAP/POP3 email server Loaded: loaded (/lib/systemd/system/dovecot.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2019-08-21 22:54:25 EDT; 4s ago Docs: man:dovecot(1) http://wiki2.dovecot.org/ Process: 61281 ExecStop=/usr/bin/doveadm stop (code=exited, status=0/SUCCESS) Main PID: 61284 (dovecot) Tasks: 4 (limit: 1114) CGroup: /system.slice/dovecot.service ├─61284 /usr/sbin/dovecot -F ├─61285 dovecot/anvil ├─61286 dovecot/log └─61288 dovecot/config Aug 21 22:54:25 rigel systemd[1]: Started Dovecot IMAP/POP3 email server. Aug 21 22:54:25 rigel dovecot[61284]: doveconf: Warning: SSLv2 not supported by OpenSSL. Please consider removing it from ssl_protocols. Aug 21 22:54:25 rigel dovecot[61284]: master: Dovecot v2.2.33.2 (d6601f4ec) starting up for imap (core dumps disabled) Aug 21 22:54:25 rigel dovecot[61286]: config: Warning: SSLv2 not supported by OpenSSL. Please consider removing it from ssl_protocols.
cat /etc/dovecot/sieve/scan_reported_mails.sh #!/usr/bin/env bash # Author: Zhang Huangbin <zhb@iredmail.org> # Purpose: Copy spam/ham to another directory and call sa-learn to learn.
# Paths to find program. export PATH="/bin:/usr/bin:/usr/local/bin:$PATH"
export OWNER="vmail" export GROUP="vmail"
# The Amavisd daemon user. # Note: on OpenBSD, it's "_vscan". On FreeBSD, it's "vscan". export AMAVISD_USER='amavis'
# Kernel name, in upper cases. export KERNEL_NAME="$(uname -s | tr '[a-z]' '[A-Z]')"
# A temporary lock file. should be removed after successfully examed messages. export LOCK_FILE='/tmp/scan_reported_mails.lock'
# Logging to syslog with 'logger' command. export LOG='logger -p local5.info -t scan_reported_mails'
# `sa-learn` command, with optional arguments. export SA_LEARN="sa-learn -u ${AMAVISD_USER}"
# Spool directory. # Must be owned by vmail:vmail. export SPOOL_DIR='/var/vmail/imapsieve_copy'
# Directories which store spam and ham emails. # These 2 should be created while setup Dovecot antispam plugin. export SPOOL_SPAM_DIR="${SPOOL_DIR}/spam" export SPOOL_HAM_DIR="${SPOOL_DIR}/ham"
# Directory used to store emails we're going to process. # We will copy new spam/ham messages to these directories, scan them, then # remove them. export SPOOL_LEARN_SPAM_DIR="${SPOOL_DIR}/processing/spam" export SPOOL_LEARN_HAM_DIR="${SPOOL_DIR}/processing/ham"
if [ -e ${LOCK_FILE} ]; then find $(dirname ${LOCK_FILE}) -maxdepth 1 -ctime 1 "$(basename ${LOCK_FILE})" >/dev/null 2>&1 if [ X"$?" == X'0' ]; then rm -f ${LOCK_FILE} >/dev/null 2>&1 else ${LOG} "Lock file exists (${LOCK_FILE}), abort." exit fi fi
for dir in "${SPOOL_DIR}" "${SPOOL_LEARN_SPAM_DIR}" "${SPOOL_LEARN_HAM_DIR}"; do if [[ ! -d ${dir} ]]; then mkdir -p ${dir} fi
chown ${OWNER}:${GROUP} ${dir} chmod 0700 ${dir} done
# If there're a lot files, direct `mv` command may fail with error like # `argument list too long`, so we need `find` in this case. if [[ X"${KERNEL_NAME}" == X'OPENBSD' ]]; then [[ -d ${SPOOL_SPAM_DIR} ]] && find ${SPOOL_SPAM_DIR} -name '*.eml' -exec mv {} ${SPOOL_LEARN_SPAM_DIR}/ \; [[ -d ${SPOOL_HAM_DIR} ]] && find ${SPOOL_HAM_DIR} -name '*.eml' -exec mv {} ${SPOOL_LEARN_HAM_DIR}/ \; else [[ -d ${SPOOL_SPAM_DIR} ]] && find ${SPOOL_SPAM_DIR} -name '*.eml' -exec mv -t ${SPOOL_LEARN_SPAM_DIR}/ {} + [[ -d ${SPOOL_HAM_DIR} ]] && find ${SPOOL_HAM_DIR} -name '*.eml' -exec mv -t ${SPOOL_LEARN_HAM_DIR}/ {} + fi
# Try to delete empty directory, if failed, that means we have some messages to # scan. rmdir ${SPOOL_LEARN_SPAM_DIR} &>/dev/null if [[ X"$?" != X'0' ]]; then output="$(${SA_LEARN} --spam ${SPOOL_LEARN_SPAM_DIR})" rm -rf ${SPOOL_LEARN_SPAM_DIR} &>/dev/null ${LOG} '[SPAM]' ${output} fi
rmdir ${SPOOL_LEARN_HAM_DIR} &>/dev/null if [[ X"$?" != X'0' ]]; then output="$(${SA_LEARN} --ham ${SPOOL_LEARN_HAM_DIR})" rm -rf ${SPOOL_LEARN_HAM_DIR} &>/dev/null ${LOG} '[CLEAN]' ${output} fi
rm -f ${LOCK_FILE} &>/dev/null
We add a crontab to process them each 10 minutes
crontab -l | grep sieve */10 * * * * /bin/bash /etc/dovecot/sieve/scan_reported_mails.sh
Sfp
We want SFP check the headers, but not reject the email.
cat /etc/postfix-policyd-spf-python/policyd-spf.conf | grep -v "^$" # For a fully commented sample config file see policyd-spf.conf.commented debugLevel = 1 defaultSeedOnly = 1 HELO_reject = False Mail_From_reject = False PermError_reject = False TempError_Defer = False skip_addresses = 127.0.0.0/8,::ffff:127.0.0.0/104,::1
Opendkim
/etc/opendkim.conf
cat opendkim.conf | grep -v "#" | grep -v "^$" Syslog yes LogWhy yes UMask 022 UserID opendkim:opendkim Canonicalization relaxed/simple Mode sv SubDomains yes OversignHeaders From KeyTable /etc/opendkim/KeyTable SigningTable /etc/opendkim/SigningTable ExternalIgnoreList /etc/opendkim/TrustedHosts InternalHosts /etc/opendkim/TrustedHosts Socket inet:8891@localhost
TrustedHosts file
mkdir /etc/opendkimcd /etc/opendkimcat TrustedHosts 127.0.0.1 localhost 93.90.207.52 2001:8d8:1800:8008::1 rigel.oamis.net
/etc/default/opendkim
cat /etc/default/opendkim | grep -v "^#" SOCKET="inet:8891@localhost"
create keys for a domain
mkdir -p /etc/opendkim/keyscd /etc/opendkim/keysmkdir oamis.netcd oamis.netopendkim-genkey -h rsa-sha256 -b 2048 -s dkim -d oamis.net chown opendkim:opendkim dkim.privateecho "dkim._domainkey.oamis.net oamis.net:dkim:/etc/opendkim/keys/oamis.net/dkim.private" >> /etc/opendkim/KeyTableecho "oamis.net dkim._domainkey.oamis.net" >> /etc/opendkim/SigningTableecho oamis.net >> /etc/opendkim/TrustedHosts
Add DNS record for a domain
cat /etc/opendkim/keys/oamis.net/dkim.txt >> oamis.net/etc/init.d/bind9 restart
restart service
/etc/init.d/bind9 restart
Opendmarc
Create database
cat /usr/share/doc/opendmarc/schema.mysql | mysql -p Enter password: mysql -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 418 Server version: 5.7.27-0ubuntu0.18.04.1-log (Ubuntu) Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> CREATE USER 'opendmarc'@'localhost' IDENTIFIED BY 'xxxxxxxxxxxx'; Query OK, 0 rows affected (0.01 sec) mysql> GRANT ALL ON opendmarc.* to 'opendmarc'@'localhost'; Query OK, 0 rows affected (0.00 sec) mysql> quit Bye
/etc/opendmarc.conf
cat /etc/opendmarc.conf | grep -v "^#" | grep -v "^$" AuthservID OpenDmarc PidFile /var/run/opendmarc/opendmarc.pid PublicSuffixList /usr/share/publicsuffix RejectFailures false Socket inet:8892@localhost Syslog true SyslogFacility mail UMask 0002 UserID opendmarc IgnoreAuthenticatedClients true HistoryFile /var/vmail/opendmarc/opendmarc.dat FailureReports true FailureReportsBcc servers@oamis.net FailureReportsSentBy noreply@oamis.net CopyFailuresTo servers@oamis.net
/etc/default/opendmarc
cat /etc/default/opendmarc | grep -v "^#" RUNDIR=/var/run/opendmarc SOCKET=inet:8892@localhost USER=opendmarc GROUP=opendmarc PIDFILE=$RUNDIR/$NAME.pid EXTRAAFTER=
Create opendmarc folder
mkdir -p /var/vmail/opendmarcchown opendmarc:opendmarc /var/vmail/opendmarcchmod 700 /var/vmail/opendmarc
Enable service
systemctl enable opendmarc Synchronizing state of opendmarc.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable opendmarc
Create script to transmit reports
Parameters file
rigel:~# cat /etc/luniel/etc/opendmarc-send-reports.conf DBHOST='localhost' DBUSER='opendmarc' DBPASS='xxxxxxxxxxxxxxxxx' DBNAME='opendmarc' HISTDIR='/var/vmail/opendmarc' HISTFILE='opendmarc'
Script file
rigel:~# cat /etc/luniel/opendmarc-send-reports.sh #!/bin/bash # Imports data from OpenDMARC's opendmarc.dat file into a local MySQL DB # and sends DMARC failure reports to domain owners. # Based on a script from Hamzah Khan (http://blog.hamzahkhan.com/) source /etc/luniel/etc/opendmarc-send-reports.conf UTCHOUR=`date -u +"%H"` #We check that it is 00:00 UTC time if [ ! "#${UTCHOUR}#" = "#00#" ] ; then exit 0 fi set -e DATESTAMP=`date +%Y%m%d%H%M%S` # Make sure history file exists touch ${HISTDIR}/${HISTFILE}.dat # Move history file temp dir for processing mv ${HISTDIR}/${HISTFILE}.dat ${HISTDIR}/${HISTFILE}.${DATESTAMP} # Import temp history file data and send reports /usr/sbin/opendmarc-import -dbhost=${DBHOST} -dbuser=${DBUSER} -dbpasswd=${DBPASS} -dbname=${DBNAME} -verbose < ${HISTDIR}/${HISTFILE}.${DATESTAMP} /usr/sbin/opendmarc-reports -dbhost=${DBHOST} -dbuser=${DBUSER} -dbpasswd=${DBPASS} -dbname=${DBNAME} --utc --keepfiles -verbose -interval=86400 -report-email 'noreply@oamis.net' -report-org 'oamis.net' #/usr/sbin/opendmarc-expire -dbhost=${DBHOST} -dbuser=${DBUSER} -dbpasswd=${DBPASS} -dbname=${DBNAME} -verbose # Delete temp history file # rm -rf *.$$
Add crontab line to run reports each hour but reports will be only sent at 0:00 UTC
rigel:~# crontab -l | grep opendmarc 0 * * * * /etc/luniel/opendmarc-send-reports.sh
Postfix
SQL maps files
/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
cat /etc/postfix/mysql_virtual_alias_domainaliases_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' AND alias.address=concat('%u', '@', alias_domain.target_domain) AND alias.active = 1
/etc/postfix/mysql_virtual_alias_maps.cf
cat /etc/postfix/mysql_virtual_alias_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail table = alias select_field = goto where_field = address additional_conditions = and active = '1'
/etc/postfix/mysql_virtual_domains_maps.cf
cat /etc/postfix/mysql_virtual_domains_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail table = domain select_field = domain where_field = domain additional_conditions = and backupmx = '0' and active = '1'
/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
cat /etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail query = SELECT maildir FROM mailbox, alias_domain WHERE alias_domain.alias_domain = '%d' AND mailbox.username=concat('%u', '@', alias_domain.target_domain ) AND mailbox.active = 1
/etc/postfix/mysql_virtual_mailbox_maps.cf
cat /etc/postfix/mysql_virtual_mailbox_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail table = mailbox select_field = CONCAT(domain, '/', local_part) where_field = username additional_conditions = and active = '1'
/etc/postfix/mysql_virtual_sender_login_maps.cf
cat /etc/postfix/mysql_virtual_sender_login_maps.cf user = postfix password = postfixpassword hosts = 127.0.0.1 dbname = mail query = SELECT goto FROM alias WHERE address='%s'
Headers check
/etc/postfix/header_checks
cat /etc/postfix/header_checks /^Received:/ IGNORE /^User-Agent:/ IGNORE /^X-Mailer:/ IGNORE /^X-Originating-IP:/ IGNORE /^x-cr-[a-z]*:/ IGNORE /^Thread-Index:/ IGNORE
Generating DH file
cd /etc/postfix/ssl/ openssl dhparam -out dh4096.pem 4096 Generating DH parameters, 4096 bit long safe prime, generator 2 This is going to take a long time
main.cf
cat main.cf | grep -v "#" | grep -v "^$" smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no append_dot_mydomain = no readme_directory = no smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes broken_sasl_auth_clients = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = smtpd_sasl_authenticated_header = yes smtpd_tls_cert_file = /etc/postfix/ssl/rigel.oamis.net.cer smtpd_tls_key_file = /etc/postfix/ssl/rigel.oamis.net.key smtpd_tls_CAfile = /etc/postfix/ssl/ca.cer smtpd_tls_mandatory_protocols = !SSLv2,!SSLv3 smtp_tls_note_starttls_offer = yes smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/urandom smtpd_tls_security_level = may smtp_tls_security_level = may smtpd_tls_exclude_ciphers = aNULL, eNULL, EXPORT, DES, RC4, MD5, PSK, aECDH, EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CDC3-SHA, KRB5-DE5, CBC3-SHA smtpd_tls_dh1024_param_file = /etc/postfix/ssl/dh4096.pem unknown_local_recipient_reject_code = 450 maximal_queue_lifetime = 7d minimal_backoff_time = 300s maximal_backoff_time = 8000s smtp_helo_timeout = 60s smtpd_recipient_limit = 16 smtpd_soft_error_limit = 3 smtpd_hard_error_limit = 12 smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit smtpd_sender_restrictions = permit_mynetworks, reject_authenticated_sender_login_mismatch, permit_sasl_authenticated, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/policy-spf, check_policy_service inet:127.0.0.1:10023, permit smtpd_data_restrictions = reject_unauth_pipelining smtpd_relay_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service unix:private/policy-spf, check_policy_service inet:127.0.0.1:10023, permit smtpd_helo_required = yes smtpd_delay_reject = yes disable_vrfy_command = yes myhostname = rigel.oamis.net mydestination = myorigin = /etc/mailname mydestination = $myhostname, rigel.oamis.net, rigel, localhost.localdomain, localhost relayhost = mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all inet_protocols = all mynetworks_style = host virtual_mailbox_base = /var/vmail virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, mysql:/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf virtual_uid_maps = static:150 virtual_gid_maps = static:8 virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf smtpd_sender_login_maps = mysql:/etc/postfix/mysql_virtual_sender_login_maps.cf virtual_transport = dovecot dovecot_destination_recipient_limit = 1 content_filter = amavis:[127.0.0.1]:10024 policy-spf_time_limit = 3600s header_checks = regexp:/etc/postfix/header_checks enable_original_recipient = no milter_default_action = accept milter_protocol = 6 smtpd_milters = inet:localhost:8891,inet:localhost:8892 non_smtpd_milters = inet:localhost:8891,inet:localhost:8892 alias_maps = hash:/etc/aliases # Increase message size limit to 200MB message_size_limit = 209715200
master.cf
cat master.cf | grep -v "#" | grep -v "^$" smtp inet n - y - - smtpd submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject -o smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit -o smtpd_sender_restrictions = permit_mynetworks, reject_authenticated_sender_login_mismatch, permit_sasl_authenticated, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING pickup unix n - y 60 1 pickup cleanup unix n - y - 0 cleanup qmgr unix n - n 300 1 qmgr tlsmgr unix - - y 1000? 1 tlsmgr rewrite unix - - y - - trivial-rewrite bounce unix - - y - 0 bounce defer unix - - y - 0 bounce trace unix - - y - 0 bounce verify unix - - y - 1 verify flush unix n - y 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - y - - smtp relay unix - - y - - smtp showq unix n - y - - showq error unix - - y - - error retry unix - - y - - error discard unix - - y - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - y - - lmtp anvil unix - - y - 1 anvil scache unix - - y - 1 scache maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} mailman unix - n n - - pipe flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user} amavis unix - - y - 3 smtp -o smtp_data_done_timeout=1200 -o smtp_send_xforward_command=yes -o disable_dns_lookups=yes -o max_use=20 127.0.0.1:10025 inet n - y - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= -o smtpd_restriction_classes= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters dovecot unix - n n - - pipe flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient) policy-spf unix - n n - - spawn user=nobody argv=/usr/bin/policyd-spf
Restart all services
service postfix restartservice opendkim restartservice opendmarc restartservice spamassassin restartservice clamav-daemon restartservice amavis restartservice dovecot restart
---