fix for forwarding save option, added SRS
This commit is contained in:
parent
9186bc4a01
commit
6d1dd40484
12
etc/exim4/bounce_message_text
Normal file
12
etc/exim4/bounce_message_text
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
****
|
||||||
|
|
||||||
|
This message was created automatically by the mail delivery software on $primary_hostname:
|
||||||
|
|
||||||
|
A message ${if eq{$sender_address}{$bounce_recipient}{that you sent}{sent by\n}}
|
||||||
|
${if ! eq{$sender_address}{$bounce_recipient} {${if match {$sender_address} {\N(?i)^SRS[01][=+-]\N} {${sg {${sg {$sender_address} {\N(?i)^SRS[01][=+-][^ @]+?[=+-][a-zA-Z0-9]{2}[=+-]([^ @]+?)[=+-]([^ @]++)@.*$\N} {\N $2@$1\N}} } {\N^ prvs=[^=]+?=(.*)$\N} {\N $1\N} }\n} {${if match {$sender_address} {\N(?i)^prvs=\N} {${sg {$sender_address} {\N(?i)^prvs=[^ @]+?=(.*@.*)$\N} {\N $1\n\N}}} { $sender_address\n}}} }}}
|
||||||
|
could not be delivered to one or more of its recipients. The following
|
||||||
|
address(es) failed:
|
||||||
|
****
|
||||||
|
****
|
||||||
|
****
|
||||||
|
****
|
|
@ -7,6 +7,7 @@ disable_ipv6 = true
|
||||||
keep_environment =
|
keep_environment =
|
||||||
add_environment = PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
add_environment = PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
smtp_enforce_sync = false
|
smtp_enforce_sync = false
|
||||||
|
bounce_message_file = /etc/exim4/bounce_message_text
|
||||||
|
|
||||||
smtp_accept_max = 50
|
smtp_accept_max = 50
|
||||||
smtp_accept_max_per_host = 10
|
smtp_accept_max_per_host = 10
|
||||||
|
@ -202,7 +203,7 @@ rfc1413_query_timeout = 0s
|
||||||
|
|
||||||
ignore_bounce_errors_after = 0s
|
ignore_bounce_errors_after = 0s
|
||||||
|
|
||||||
# This option cancels (removes) frozen messages that are older than a week.
|
# This option cancels (removes) frozen messages that are older than a day.
|
||||||
|
|
||||||
timeout_frozen_after = 1d
|
timeout_frozen_after = 1d
|
||||||
|
|
||||||
|
@ -433,6 +434,32 @@ acl_rcpt_to:
|
||||||
# Recipent Address Checks
|
# Recipent Address Checks
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
# Ensure only valid SRS prefixed bounce message get accepted
|
||||||
|
deny
|
||||||
|
senders = :
|
||||||
|
domains = +local_domains
|
||||||
|
local_parts = ${if match {$local_part} {(?i)\N^SRS[01][=+-]\N} {$local_part}}
|
||||||
|
control = caseful_local_part
|
||||||
|
condition = ${if match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{\n}}}{^ERROR: .* Invalid hash at .*}}
|
||||||
|
message = Invalid reverse path (SRS check failed on $local_part@$domain).
|
||||||
|
|
||||||
|
warn
|
||||||
|
senders = :
|
||||||
|
domains = +local_domains
|
||||||
|
local_parts = ${if match {$local_part} {\N^srs[01][=+-]\N} {$local_part}}
|
||||||
|
control = caseful_local_part
|
||||||
|
condition = ${if match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{ }}}{^SRS: Case insensitive hash match detected. Someone smashed case in the local-part. .*}}
|
||||||
|
log_message = SRS hash smashed on the way for $local_part@$domain by case insensitive MTA.
|
||||||
|
|
||||||
|
# this is for debugging only. can be safely removed any time
|
||||||
|
warn
|
||||||
|
senders = :
|
||||||
|
domains = +local_domains
|
||||||
|
local_parts = ${if match {$local_part} {(?i)\N^SRS[01][=+-]\N} {$local_part}}
|
||||||
|
control = caseful_local_part
|
||||||
|
condition = ${if !match{${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part@$domain}{5s}{\n}}}{^ERROR: .* Invalid hash at .*}}
|
||||||
|
log_message = Incoming SRS bounce to $local_part@$domain
|
||||||
|
|
||||||
# Deny if the local part contains @ or % or / or | or !. These are
|
# Deny if the local part contains @ or % or / or | or !. These are
|
||||||
# rarely found in genuine local parts, but are often tried by people
|
# rarely found in genuine local parts, but are often tried by people
|
||||||
# looking to circumvent relaying restrictions.
|
# looking to circumvent relaying restrictions.
|
||||||
|
@ -697,6 +724,33 @@ autowhitelist_filter:
|
||||||
unseen
|
unseen
|
||||||
allow_filter = true
|
allow_filter = true
|
||||||
|
|
||||||
|
srs_bounce:
|
||||||
|
senders = :
|
||||||
|
driver = redirect
|
||||||
|
domains = +local_domains
|
||||||
|
allow_fail
|
||||||
|
allow_defer
|
||||||
|
local_part_prefix = srs0+ : srs0- : srs0= : srs1+ : srs1- : srs1=
|
||||||
|
caseful_local_part
|
||||||
|
address_data = ${readsocket{/run/srsd/srsd.sock}{REVERSE $local_part_prefix$local_part@$domain}{5s}{ }{:defer: SRS daemon failure}}
|
||||||
|
data = ${sg {$address_data} {^SRS: Case insensitive hash match detected. Someone smashed case in the local-part\. .* ([^ ]+)@([^ ]+)\$} {\N$1@$2\N} }
|
||||||
|
headers_add = X-SRS: Decoded valid SRS return address to ${quote_local_part:${local_part:$address_data}}@${domain:$address_data} by $primary_hostname
|
||||||
|
|
||||||
|
srs_forward:
|
||||||
|
driver = redirect
|
||||||
|
senders = ! : ! *@+local_domains
|
||||||
|
domains = ! +local_domains : ! +relay_to_domains
|
||||||
|
condition = ${lookup mysql{SELECT vm_domains.id FROM vm_domains WHERE vm_domains.domain='${original_domain}' AND vm_domains.status = '1'}}
|
||||||
|
address_data = ${readsocket{/run/srsd/srsd.sock}\
|
||||||
|
{FORWARD $sender_address_local_part@$sender_address_domain $original_domain\n}\
|
||||||
|
{5s}{\n}{:defer: SRS daemon failure}}
|
||||||
|
errors_to = ${quote_local_part:${local_part:$address_data}}@${domain:$address_data}
|
||||||
|
data = ${quote_local_part:$local_part}@$domain
|
||||||
|
headers_add = X-SRS-Forward: from $sender_address to $original_local_part@$original_domain forwarded to $local_part@$domain by $primary_hostname
|
||||||
|
repeat_use = false
|
||||||
|
allow_defer
|
||||||
|
no_verify
|
||||||
|
|
||||||
# This router routes addresses that are not in local domains by doing a DNS
|
# This router routes addresses that are not in local domains by doing a DNS
|
||||||
# lookup on the domain name. Any domain that resolves to 0.0.0.0 or to a
|
# lookup on the domain name. Any domain that resolves to 0.0.0.0 or to a
|
||||||
# loopback interface address (127.0.0.0/8) is treated as if it had no DNS
|
# loopback interface address (127.0.0.0/8) is treated as if it had no DNS
|
||||||
|
@ -735,24 +789,6 @@ junk_filter:
|
||||||
condition = ${lookup mysql{SELECT vm_mboxes.id FROM vm_domains, vm_mboxes WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_mboxes.filter > '0'}}
|
condition = ${lookup mysql{SELECT vm_mboxes.id FROM vm_domains, vm_mboxes WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_mboxes.filter > '0'}}
|
||||||
transport = junk_delivery
|
transport = junk_delivery
|
||||||
|
|
||||||
spamcheck_router:
|
|
||||||
driver = accept
|
|
||||||
domains = +local_domains
|
|
||||||
local_part_suffix = +*
|
|
||||||
local_part_suffix_optional = true
|
|
||||||
condition = ${if and { \
|
|
||||||
{ !eq {$received_protocol}{spam-scanned}} \
|
|
||||||
{ !eq {$sender_address_domain}{$domain}} \
|
|
||||||
{ < {$message_size}{512k}} \
|
|
||||||
{ !eq {$header_X-Junk-Flag:}{YES}} \
|
|
||||||
{ !eq {$header_X-Whitelist-Flag:}{YES}} \
|
|
||||||
{ eq {${lookup mysql{SELECT vm_mboxes.status FROM vm_domains, vm_mboxes WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_domains.status = '1'}{$value}fail}}{1} } \
|
|
||||||
} {yes} {no}}
|
|
||||||
# check domain & mbox 'status'?
|
|
||||||
# Check for other headers too? Blacklist, SPF, DKIM failers go directly to Spam folder without spam scan??? - actually they should go to spam folder before this router is hit?
|
|
||||||
headers_remove = X-Spam-Checker-Version:X-Spam-Flag:X-Spam-Level:X-Spam-Status:X-Spam-Score:X-Spam-Report
|
|
||||||
transport = spamcheck
|
|
||||||
|
|
||||||
spam_filter:
|
spam_filter:
|
||||||
driver = accept
|
driver = accept
|
||||||
domains = +local_domains
|
domains = +local_domains
|
||||||
|
@ -772,6 +808,7 @@ virtual_vacation:
|
||||||
# do not reply to errors or lists or spam-scanned messages, require vacation message in db
|
# do not reply to errors or lists or spam-scanned messages, require vacation message in db
|
||||||
condition = ${if and { \
|
condition = ${if and { \
|
||||||
{ !match {$h_precedence:} {(?i)junk|bulk|list}} \
|
{ !match {$h_precedence:} {(?i)junk|bulk|list}} \
|
||||||
|
{ !eq {$received_protocol}{spam-scanned}} \
|
||||||
{ !eq {$sender_address} {}} \
|
{ !eq {$sender_address} {}} \
|
||||||
{ eq {${lookup mysql{SELECT vm_autoresponders.mode FROM vm_domains, vm_mboxes, vm_autoresponders WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_autoresponders.mbox_id = vm_mboxes.id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_autoresponders.status = '1'}{$value}fail}}{Vacation}} \
|
{ eq {${lookup mysql{SELECT vm_autoresponders.mode FROM vm_domains, vm_mboxes, vm_autoresponders WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_autoresponders.mbox_id = vm_mboxes.id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_autoresponders.status = '1'}{$value}fail}}{Vacation}} \
|
||||||
} {yes} {no}}
|
} {yes} {no}}
|
||||||
|
@ -797,6 +834,7 @@ virtual_autoresponder:
|
||||||
# do not reply to errors or lists or spam-scanned messages, require autoresponder message in db
|
# do not reply to errors or lists or spam-scanned messages, require autoresponder message in db
|
||||||
condition = ${if and { \
|
condition = ${if and { \
|
||||||
{ !match {$h_precedence:} {(?i)junk|bulk|list}} \
|
{ !match {$h_precedence:} {(?i)junk|bulk|list}} \
|
||||||
|
{ !eq {$received_protocol}{spam-scanned}} \
|
||||||
{ !eq {$sender_address} {}} \
|
{ !eq {$sender_address} {}} \
|
||||||
{ eq {${lookup mysql{SELECT vm_autoresponders.mode FROM vm_domains, vm_mboxes, vm_autoresponders WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_autoresponders.mbox_id = vm_mboxes.id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_autoresponders.status = '1'}{$value}fail}}{Autoresponder} } \
|
{ eq {${lookup mysql{SELECT vm_autoresponders.mode FROM vm_domains, vm_mboxes, vm_autoresponders WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_autoresponders.mbox_id = vm_mboxes.id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_autoresponders.status = '1'}{$value}fail}}{Autoresponder} } \
|
||||||
} {yes} {no}}
|
} {yes} {no}}
|
||||||
|
@ -813,13 +851,38 @@ virtual_autoresponder:
|
||||||
unseen
|
unseen
|
||||||
no_verify
|
no_verify
|
||||||
|
|
||||||
virtual_forward:
|
virtual_forward_and_drop:
|
||||||
driver = redirect
|
driver = redirect
|
||||||
domains = +local_domains
|
domains = +local_domains
|
||||||
|
condition = ${if !eq {$received_protocol}{spam-scanned}}
|
||||||
|
local_part_suffix = +*
|
||||||
|
local_part_suffix_optional = true
|
||||||
|
data = ${lookup mysql{SELECT vm_forwards.forward_to FROM vm_domains, vm_mboxes, vm_forwards WHERE vm_domains.domain='${domain}' AND vm_domains.id = vm_mboxes.domain_id AND vm_mboxes.mbox='${local_part}' AND vm_mboxes.id=vm_forwards.mbox_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_forwards.save_local='0'}}
|
||||||
|
|
||||||
|
virtual_forward_and_keep:
|
||||||
|
driver = redirect
|
||||||
|
domains = +local_domains
|
||||||
|
condition = ${if !eq {$received_protocol}{spam-scanned}}
|
||||||
|
local_part_suffix = +*
|
||||||
|
local_part_suffix_optional = true
|
||||||
|
data = ${lookup mysql{SELECT CONCAT('${local_part}@${domain}\n', vm_forwards.forward_to) FROM vm_domains, vm_mboxes, vm_forwards WHERE vm_domains.domain='${domain}' AND vm_domains.id = vm_mboxes.domain_id AND vm_mboxes.mbox='${local_part}' AND vm_mboxes.id=vm_forwards.mbox_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_forwards.save_local='1'}}
|
||||||
|
|
||||||
|
spamcheck_router:
|
||||||
|
driver = accept
|
||||||
|
domains = +local_domains
|
||||||
local_part_suffix = +*
|
local_part_suffix = +*
|
||||||
local_part_suffix_optional = true
|
local_part_suffix_optional = true
|
||||||
data = ${lookup mysql{SELECT vm_forwards.forward_to FROM vm_domains, vm_mboxes, vm_forwards WHERE vm_domains.domain='${domain}' AND vm_domains.id = vm_mboxes.domain_id AND vm_mboxes.mbox='${local_part}' AND vm_mboxes.id=vm_forwards.mbox_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' }}
|
condition = ${if and { \
|
||||||
unseen = ${lookup mysql{SELECT vm_forwards.id FROM vm_domains, vm_mboxes, vm_forwards WHERE vm_domains.domain='${domain}' AND vm_domains.id = vm_mboxes.domain_id AND vm_mboxes.mbox='${local_part}' AND vm_mboxes.id=vm_forwards.mbox_id AND vm_domains.status = '1' AND vm_mboxes.status = '1' AND vm_forwards.save_local='1'}{true}{false}}
|
{ !eq {$received_protocol}{spam-scanned}} \
|
||||||
|
{ !eq {$sender_address_domain}{$domain}} \
|
||||||
|
{ < {$message_size}{512k}} \
|
||||||
|
{ !eq {$header_X-Junk-Flag:}{YES}} \
|
||||||
|
{ !eq {$header_X-Whitelist-Flag:}{YES}} \
|
||||||
|
{ eq {${lookup mysql{SELECT vm_mboxes.status FROM vm_domains, vm_mboxes WHERE vm_domains.domain='${domain}' AND vm_mboxes.mbox='${local_part}' AND vm_domains.id = vm_mboxes.domain_id AND vm_domains.status = '1' AND vm_mboxes.status = '1'}{$value}fail}}{1} } \
|
||||||
|
} {yes} {no}}
|
||||||
|
# Check for other headers too? Blacklist, SPF, DKIM failers go directly to Spam folder without spam scan??? - actually they should go to spam folder before this router is hit?
|
||||||
|
headers_remove = X-Spam-Checker-Version:X-Spam-Flag:X-Spam-Level:X-Spam-Status:X-Spam-Score:X-Spam-Report
|
||||||
|
transport = spamcheck
|
||||||
|
|
||||||
user_filter:
|
user_filter:
|
||||||
driver = redirect
|
driver = redirect
|
||||||
|
@ -1094,10 +1157,8 @@ address_reply:
|
||||||
begin retry
|
begin retry
|
||||||
|
|
||||||
# This single retry rule applies to all domains and all errors. It specifies
|
# This single retry rule applies to all domains and all errors. It specifies
|
||||||
# retries every 15 minutes for 2 hours, then increasing retry intervals,
|
# retries every 15 minutes for 2 hours, then every 2 hours until 1 full day
|
||||||
# starting at 1 hour and increasing each time by a factor of 1.5, up to 16
|
# has passed since the first delivery failed.
|
||||||
# hours, then retries every 6 hours until 4 days have passed since the first
|
|
||||||
# failed delivery.
|
|
||||||
|
|
||||||
# Domain Error Retries
|
# Domain Error Retries
|
||||||
# ------ ----- -------
|
# ------ ----- -------
|
||||||
|
@ -1114,7 +1175,6 @@ begin retry
|
||||||
begin rewrite
|
begin rewrite
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# AUTHENTICATION CONFIGURATION #
|
# AUTHENTICATION CONFIGURATION #
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
16
install.sh
16
install.sh
|
@ -59,7 +59,7 @@ mysql -e "GRANT ALL PRIVILEGES ON vmail.* TO 'vmail'@'localhost';"
|
||||||
mysqladmin flush-privileges
|
mysqladmin flush-privileges
|
||||||
|
|
||||||
# install mail server software
|
# install mail server software
|
||||||
apt -y install exim4-daemon-heavy spf-tools-perl spamassassin libclass-dbi-mysql-perl dovecot-core dovecot-imapd dovecot-mysql dovecot-pop3d dovecot-lmtpd
|
apt -y install exim4-daemon-heavy spf-tools-perl spamassassin srs libclass-dbi-mysql-perl dovecot-core dovecot-imapd dovecot-mysql dovecot-pop3d dovecot-lmtpd
|
||||||
|
|
||||||
# configure system users
|
# configure system users
|
||||||
apt -y install ssl-cert
|
apt -y install ssl-cert
|
||||||
|
@ -97,6 +97,16 @@ chmod 644 /etc/spamassassin/local.cf
|
||||||
chown debian-spamd:mail /etc/spamassassin/sql.cf
|
chown debian-spamd:mail /etc/spamassassin/sql.cf
|
||||||
chmod 640 /etc/spamassassin/sql.cf
|
chmod 640 /etc/spamassassin/sql.cf
|
||||||
|
|
||||||
|
# srsd
|
||||||
|
# bug fixes for libmail-srs-perl. still needed as of v0.31-6 on Ubuntu 20.04
|
||||||
|
sed -i 's|/tmp/srsd|/run/srsd/srsd.sock|' /usr/share/perl5/Mail/SRS/Daemon.pm
|
||||||
|
sed -i '/Until we decide that forward/,+3d' /usr/share/perl5/Mail/SRS/Daemon.pm
|
||||||
|
cp systemd/srsd.service /lib/systemd/system/srsd.service
|
||||||
|
chmod 644 /lib/systemd/system/srsd.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable srsd
|
||||||
|
systemctl start srsd
|
||||||
|
|
||||||
# exim config
|
# exim config
|
||||||
maildomain=`hostname -d`
|
maildomain=`hostname -d`
|
||||||
sed -i 's/size 10M/daily/g' /etc/logrotate.d/exim4-paniclog
|
sed -i 's/size 10M/daily/g' /etc/logrotate.d/exim4-paniclog
|
||||||
|
@ -112,6 +122,10 @@ chmod 640 /etc/exim4/skip_greylisting_hosts
|
||||||
sed -i "s|example.com|$maildomain|g" /etc/exim4/skip_greylisting_hosts
|
sed -i "s|example.com|$maildomain|g" /etc/exim4/skip_greylisting_hosts
|
||||||
sed -i "s|password|$VMAILPASS|g" /etc/exim4/exim_local.conf
|
sed -i "s|password|$VMAILPASS|g" /etc/exim4/exim_local.conf
|
||||||
sed -i "s|example.com|$maildomain|g" /etc/exim4/exim_local.conf
|
sed -i "s|example.com|$maildomain|g" /etc/exim4/exim_local.conf
|
||||||
|
touch /etc/exim4/srsd.secret
|
||||||
|
chmod 640 /etc/exim4/srsd.secret
|
||||||
|
chown Debian-exim:Debian-exim /etc/exim4/srsd.secret
|
||||||
|
pwgen -N 1 -cny 64 > /etc/exim4/srsd.secret
|
||||||
|
|
||||||
# dovecot config
|
# dovecot config
|
||||||
mkdir /etc/dovecot/sites.d
|
mkdir /etc/dovecot/sites.d
|
||||||
|
|
15
systemd/srsd.service
Normal file
15
systemd/srsd.service
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Sender Rewriting Scheme Daemon
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=exec
|
||||||
|
User=Debian-exim
|
||||||
|
Group=Debian-exim
|
||||||
|
ExecStart=/usr/bin/srsd --secretfile /etc/exim4/srsd.secret --hashlength 24
|
||||||
|
PIDFile=/run/srsd/srsd.pid
|
||||||
|
Restart=on-failure
|
||||||
|
RuntimeDirectory=srsd
|
||||||
|
RuntimeDirectoryMode=0750
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Reference in New Issue
Block a user