git subrepo commit (merge) mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "32243e56"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "e2b4b6f6"
git-subrepo: version: "0.4.3"
origin: "???"
commit: "???"
Change-Id: I51e2016ef5ab88a8b0bdc08551b18f48ceef0aa5
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/acme/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/acme/Dockerfile
index a19c434..82369a8 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/acme/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/acme/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13
+FROM alpine:3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/clamd/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/clamd/Dockerfile
index b251d96..e14858f 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/clamd/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/clamd/Dockerfile
@@ -2,8 +2,7 @@
LABEL maintainer "André Peters <andre.peters@servercow.de>"
-ARG CLAMAV=0.103.2
-
+ARG CLAMAV=0.103.4
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
zlib1g-dev \
@@ -24,7 +23,7 @@
dos2unix \
netcat \
&& rm -rf /var/lib/apt/lists/* \
- && wget -O - https://www.clamav.net/downloads/production/clamav-${CLAMAV}.tar.gz | tar xfvz - \
+ && wget -O - https://fossies.org/linux/misc/clamav-${CLAMAV}.tar.gz | tar xfvz - \
&& cd clamav-${CLAMAV} \
&& ./configure \
--prefix=/usr \
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/Dockerfile
index 645503a..b6eef46 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dockerapi/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13
+FROM alpine:3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/Dockerfile
index 1990097..1fc4000 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/Dockerfile
@@ -2,7 +2,7 @@
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
-ARG DOVECOT=2.3.14.1
+ARG DOVECOT=2.3.17
ENV LC_ALL C
ENV GOSU_VERSION 1.12
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/docker-entrypoint.sh b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/docker-entrypoint.sh
index 5ea1609..9ac2dc6 100755
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/docker-entrypoint.sh
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/docker-entrypoint.sh
@@ -155,34 +155,47 @@
local row = cur:fetch ({}, "a")
while row do
if req.password_verify(req, row.password, pass) == 1 then
- cur:close()
con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
VALUES ("%s", 0, "%s", "%s")]], con:escape(req.service), con:escape(req.user), con:escape(req.real_rip)))
+ cur:close()
+ con:close()
return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
end
row = cur:fetch (row, "a")
end
- -- check against app passwds
- local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, app_passwd.password FROM app_passwd
- INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox
- WHERE mailbox = '%s'
- AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.%s_access')), 1) = '1'
- AND IFNULL(JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.force_pw_update')), 0) != '1'
- AND app_passwd.active = '1'
- AND mailbox.active = '1'
- AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.user), con:escape(req.service), con:escape(req.domain)))
- local row = cur:fetch ({}, "a")
- while row do
- if req.password_verify(req, row.password, pass) == 1 then
- cur:close()
- con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
- VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
- return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
+ -- check against app passwds for imap and smtp
+ -- app passwords are only available for imap, smtp, sieve and pop3 when using sasl
+ if req.service == "smtp" or req.service == "imap" or req.service == "sieve" or req.service == "pop3" then
+ local cur,errorString = con:execute(string.format([[SELECT app_passwd.id, %s_access AS has_prot_access, app_passwd.password FROM app_passwd
+ INNER JOIN mailbox ON mailbox.username = app_passwd.mailbox
+ WHERE mailbox = '%s'
+ AND app_passwd.active = '1'
+ AND mailbox.active = '1'
+ AND app_passwd.domain IN (SELECT domain FROM domain WHERE domain='%s' AND active='1')]], con:escape(req.service), con:escape(req.user), con:escape(req.domain)))
+ local row = cur:fetch ({}, "a")
+ while row do
+ if req.password_verify(req, row.password, pass) == 1 then
+ -- if password is valid and protocol access is 1 OR real_rip matches SOGo, proceed
+ if tostring(req.real_rip) == "__IPV4_SOGO__" then
+ cur:close()
+ con:close()
+ return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
+ elseif row.has_prot_access == "1" then
+ con:execute(string.format([[REPLACE INTO sasl_log (service, app_password, username, real_rip)
+ VALUES ("%s", %d, "%s", "%s")]], con:escape(req.service), row.id, con:escape(req.user), con:escape(req.real_rip)))
+ cur:close()
+ con:close()
+ return dovecot.auth.PASSDB_RESULT_OK, "password=" .. pass
+ end
+ end
+ row = cur:fetch (row, "a")
end
- row = cur:fetch (row, "a")
end
+ cur:close()
+ con:close()
+
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, "Failed to authenticate"
-- PoC
@@ -230,6 +243,7 @@
sed -i "s/__DBUSER__/${DBUSER}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBPASS__/${DBPASS}/g" /etc/dovecot/lua/passwd-verify.lua
sed -i "s/__DBNAME__/${DBNAME}/g" /etc/dovecot/lua/passwd-verify.lua
+sed -i "s/__IPV4_SOGO__/${IPV4_NETWORK}.248/g" /etc/dovecot/lua/passwd-verify.lua
# Migrate old sieve_after file
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/imapsync_runner.pl b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/imapsync_runner.pl
index 0f01a97..5b297ab 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/imapsync_runner.pl
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/dovecot/imapsync_runner.pl
@@ -152,18 +152,28 @@
'--noreleasecheck'];
try {
- $is_running = $dbh->prepare("UPDATE imapsync SET is_running = 1 WHERE id = ?");
+ $is_running = $dbh->prepare("UPDATE imapsync SET is_running = 1, success = NULL, exit_status = NULL WHERE id = ?");
$is_running->bind_param( 1, ${id} );
$is_running->execute();
-
+
run [@$generated_cmds, @$custom_params_ref], '&>', \my $stdout;
-
- $update = $dbh->prepare("UPDATE imapsync SET returned_text = ? WHERE id = ?");
+
+ # check exit code and status
+ ($exit_code, $exit_status) = ($stdout =~ m/Exiting\swith\sreturn\svalue\s(\d+)\s\(([^:)]+)/);
+
+ $success = 0;
+ if (defined $exit_code && $exit_code == 0) {
+ $success = 1;
+ }
+
+ $update = $dbh->prepare("UPDATE imapsync SET returned_text = ?, success = ?, exit_status = ? WHERE id = ?");
$update->bind_param( 1, ${stdout} );
- $update->bind_param( 2, ${id} );
+ $update->bind_param( 2, ${success} );
+ $update->bind_param( 3, ${exit_status} );
+ $update->bind_param( 4, ${id} );
$update->execute();
} catch {
- $update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync' WHERE id = ?");
+ $update = $dbh->prepare("UPDATE imapsync SET returned_text = 'Could not start or finish imapsync', success = 0 WHERE id = ?");
$update->bind_param( 1, ${id} );
$update->execute();
} finally {
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/Dockerfile
index 007bd64..c63e99b 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13
+FROM alpine:3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ENV XTABLES_LIBDIR /usr/lib/xtables
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/server.py b/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/server.py
index 04f6c47..08c8727 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/server.py
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/netfilter/server.py
@@ -92,15 +92,16 @@
global exit_code
if not r.get('F2B_REGEX'):
f2bregex = {}
- f2bregex[1] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
- f2bregex[2] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
- f2bregex[3] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
- f2bregex[4] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
- f2bregex[5] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
- f2bregex[6] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
- f2bregex[7] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
- f2bregex[8] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
- f2bregex[9] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
+ f2bregex[1] = 'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
+ f2bregex[2] = 'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
+ f2bregex[3] = 'warning: .*\[([0-9a-f\.:]+)\]: SASL .+ authentication failed'
+ f2bregex[4] = 'warning: non-SMTP command from .*\[([0-9a-f\.:]+)]:.+'
+ f2bregex[5] = 'NOQUEUE: reject: RCPT from \[([0-9a-f\.:]+)].+Protocol error.+'
+ f2bregex[6] = '-login: Disconnected \(auth failed, .+\): user=.*, method=.+, rip=([0-9a-f\.:]+),'
+ f2bregex[7] = '-login: Aborted login \(auth failed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
+ f2bregex[8] = '-login: Aborted login \(tried to use disallowed .+\): user=.+, rip=([0-9a-f\.:]+), lip.+'
+ f2bregex[9] = 'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
+ f2bregex[10] = '([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
else:
try:
@@ -122,8 +123,10 @@
time.sleep(10)
with lock:
filter4_table = iptc.Table(iptc.Table.FILTER)
+ filter6_table = iptc.Table6(iptc.Table6.FILTER)
filter4_table.refresh()
- for f in [filter4_table]:
+ filter6_table.refresh()
+ for f in [filter4_table, filter6_table]:
forward_chain = iptc.Chain(f, 'FORWARD')
input_chain = iptc.Chain(f, 'INPUT')
for chain in [forward_chain, input_chain]:
@@ -195,7 +198,14 @@
if rule not in chain.rules:
chain.insert_rule(rule)
else:
- pass
+ with lock:
+ chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
+ rule = iptc.Rule6()
+ rule.src = net
+ target = iptc.Target(rule, "REJECT")
+ rule.target = target
+ if rule not in chain.rules:
+ chain.insert_rule(rule)
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME)
else:
logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
@@ -217,7 +227,14 @@
if rule in chain.rules:
chain.delete_rule(rule)
else:
- pass
+ with lock:
+ chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
+ rule = iptc.Rule6()
+ rule.src = net
+ target = iptc.Target(rule, "REJECT")
+ rule.target = target
+ if rule in chain.rules:
+ chain.delete_rule(rule)
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
if net in bans:
@@ -235,13 +252,26 @@
if rule not in chain.rules and not unban:
logCrit('Add host/network %s to blacklist' % net)
chain.insert_rule(rule)
- r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+ r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
elif rule in chain.rules and unban:
logCrit('Remove host/network %s from blacklist' % net)
chain.delete_rule(rule)
r.hdel('F2B_PERM_BANS', '%s' % net)
else:
- pass
+ with lock:
+ chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW')
+ rule = iptc.Rule6()
+ rule.src = net
+ target = iptc.Target(rule, "REJECT")
+ rule.target = target
+ if rule not in chain.rules and not unban:
+ logCrit('Add host/network %s to blacklist' % net)
+ chain.insert_rule(rule)
+ r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
+ elif rule in chain.rules and unban:
+ logCrit('Remove host/network %s from blacklist' % net)
+ chain.delete_rule(rule)
+ r.hdel('F2B_PERM_BANS', '%s' % net)
def quit(signum, frame):
global quit_now
@@ -254,7 +284,8 @@
unban(net)
with lock:
filter4_table = iptc.Table(iptc.Table.FILTER)
- for filter_table in [filter4_table]:
+ filter6_table = iptc.Table6(iptc.Table6.FILTER)
+ for filter_table in [filter4_table, filter6_table]:
filter_table.autocommit = False
forward_chain = iptc.Chain(filter_table, "FORWARD")
input_chain = iptc.Chain(filter_table, "INPUT")
@@ -337,7 +368,41 @@
table.commit()
table.autocommit = True
except:
- print('Error running SNAT4, retrying...')
+ print('Error running SNAT4, retrying...')
+
+def snat6(snat_target):
+ global lock
+ global quit_now
+
+ def get_snat6_rule():
+ rule = iptc.Rule6()
+ rule.src = os.getenv('IPV6_NETWORK', 'fd4d:6169:6c63:6f77::/64')
+ rule.dst = '!' + rule.src
+ target = rule.create_target("SNAT")
+ target.to_source = snat_target
+ return rule
+
+ while not quit_now:
+ time.sleep(10)
+ with lock:
+ try:
+ table = iptc.Table6('nat')
+ table.refresh()
+ chain = iptc.Chain(table, 'POSTROUTING')
+ table.autocommit = False
+ if get_snat6_rule() not in chain.rules:
+ logInfo('Added POSTROUTING rule for source network %s to SNAT target %s' % (get_snat6_rule().src, snat_target))
+ chain.insert_rule(get_snat6_rule())
+ table.commit()
+ else:
+ for position, item in enumerate(chain.rules):
+ if item == get_snat6_rule():
+ if position != 0:
+ chain.delete_rule(get_snat6_rule())
+ table.commit()
+ table.autocommit = True
+ except:
+ print('Error running SNAT6, retrying...')
def autopurge():
while not quit_now:
@@ -403,7 +468,7 @@
if Counter(new_whitelist) != Counter(WHITELIST):
WHITELIST = new_whitelist
logInfo('Whitelist was changed, it has %s entries' % len(WHITELIST))
- time.sleep(60.0 - ((time.time() - start_time) % 60.0))
+ time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def blacklistUpdate():
global quit_now
@@ -414,7 +479,7 @@
new_blacklist = []
if list:
new_blacklist = genNetworkList(list)
- if Counter(new_blacklist) != Counter(BLACKLIST):
+ if Counter(new_blacklist) != Counter(BLACKLIST):
addban = set(new_blacklist).difference(BLACKLIST)
delban = set(BLACKLIST).difference(new_blacklist)
BLACKLIST = new_blacklist
@@ -425,7 +490,7 @@
if delban:
for net in delban:
permBan(net=net, unban=True)
- time.sleep(60.0 - ((time.time() - start_time) % 60.0))
+ time.sleep(60.0 - ((time.time() - start_time) % 60.0))
def initChain():
# Is called before threads start, no locking
@@ -442,6 +507,18 @@
rule.target = target
if rule not in chain.rules:
chain.insert_rule(rule)
+ # IPv6
+ if not iptc.Chain(iptc.Table6(iptc.Table6.FILTER), "MAILCOW") in iptc.Table6(iptc.Table6.FILTER).chains:
+ iptc.Table6(iptc.Table6.FILTER).create_chain("MAILCOW")
+ for c in ['FORWARD', 'INPUT']:
+ chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), c)
+ rule = iptc.Rule6()
+ rule.src = '::/0'
+ rule.dst = '::/0'
+ target = iptc.Target(rule, "MAILCOW")
+ rule.target = target
+ if rule not in chain.rules:
+ chain.insert_rule(rule)
if __name__ == '__main__':
@@ -465,6 +542,17 @@
except ValueError:
print(os.getenv('SNAT_TO_SOURCE') + ' is not a valid IPv4 address')
+ if os.getenv('SNAT6_TO_SOURCE') and os.getenv('SNAT6_TO_SOURCE') != 'n':
+ try:
+ snat_ip = os.getenv('SNAT6_TO_SOURCE')
+ snat_ipo = ipaddress.ip_address(snat_ip)
+ if type(snat_ipo) is ipaddress.IPv6Address:
+ snat6_thread = Thread(target=snat6,args=(snat_ip,))
+ snat6_thread.daemon = True
+ snat6_thread.start()
+ except ValueError:
+ print(os.getenv('SNAT6_TO_SOURCE') + ' is not a valid IPv6 address')
+
autopurge_thread = Thread(target=autopurge)
autopurge_thread.daemon = True
autopurge_thread.start()
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/olefy/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/olefy/Dockerfile
index 3cacabb..6d9727c 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/olefy/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/olefy/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13
+FROM alpine:3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
WORKDIR /app
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/phpfpm/docker-entrypoint.sh b/mailcow/src/mailcow-dockerized/data/Dockerfiles/phpfpm/docker-entrypoint.sh
index 9a2b582..cefebcd 100755
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/phpfpm/docker-entrypoint.sh
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/phpfpm/docker-entrypoint.sh
@@ -181,8 +181,10 @@
# Fix permissions for global filters
chown -R 82:82 /global_sieve/*
-[[ ! -f /etc/nginx/conf.d/ZZZ-ejabberd.conf ]] && echo '# Autogenerated by mailcow' > /etc/nginx/conf.d/ZZZ-ejabberd.conf
-chown 82:82 /etc/nginx/conf.d/ZZZ-ejabberd.conf
+# Fix permissions on twig cache folder
+chown -R 82:82 /web/templates/cache
+# Clear cache
+find /web/templates/cache/* -not -name '.gitkeep' -delete
# Run hooks
for file in /hooks/*; do
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/postfix/postfix.sh b/mailcow/src/mailcow-dockerized/data/Dockerfiles/postfix/postfix.sh
index 35cd790..e734a9a 100755
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/postfix/postfix.sh
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/postfix/postfix.sh
@@ -181,11 +181,31 @@
dbname = ${DBNAME}
query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM relayhosts
WHERE id IN (
- SELECT relayhost FROM domain
- WHERE CONCAT('@', domain) = '%s'
- OR domain IN (
- SELECT target_domain FROM alias_domain WHERE CONCAT('@', alias_domain) = '%s'
+ SELECT COALESCE(
+ (SELECT id FROM relayhosts
+ LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
+ WHERE relayhosts.active = '1'
+ AND (domain.domain = '%d'
+ OR domain.domain IN (
+ SELECT target_domain FROM alias_domain
+ WHERE alias_domain = '%d'
+ )
+ )
+ ),
+ (SELECT id FROM relayhosts
+ LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
+ WHERE relayhosts.active = '1'
+ AND (
+ mailbox.username IN (
+ SELECT alias.goto from alias
+ JOIN mailbox ON mailbox.username = alias.goto
+ WHERE alias.active = '1'
+ AND alias.address = '%s'
+ AND alias.address NOT LIKE '@%%'
+ )
+ )
)
+ )
)
AND active = '1'
AND username != '';
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/rspamd/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/rspamd/Dockerfile
index 888bdcb..ee08f8d 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/rspamd/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/rspamd/Dockerfile
@@ -1,8 +1,8 @@
-FROM debian:buster-slim
-LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
+FROM debian:bullseye-slim
+LABEL maintainer "Andre Peters <andre.peters@tinc.gmbh>"
ARG DEBIAN_FRONTEND=noninteractive
-ARG CODENAME=buster
+ARG CODENAME=bullseye
ENV LC_ALL C
RUN apt-get update && apt-get install -y \
@@ -15,12 +15,13 @@
&& apt-key adv --fetch-keys https://rspamd.com/apt-stable/gpg.key \
&& echo "deb [arch=amd64] https://rspamd.com/apt-stable/ $CODENAME main" > /etc/apt/sources.list.d/rspamd.list \
&& apt-get update \
- && apt-get --no-install-recommends -y install rspamd redis-tools \
+ && apt-get --no-install-recommends -y install rspamd redis-tools procps nano \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get autoremove --purge \
&& apt-get clean \
&& mkdir -p /run/rspamd \
- && chown _rspamd:_rspamd /run/rspamd
+ && chown _rspamd:_rspamd /run/rspamd \
+ && echo 'alias ll="ls -la --color"' >> ~/.bashrc
COPY settings.conf /etc/rspamd/settings.conf
COPY metadata_exporter.lua /usr/share/rspamd/plugins/metadata_exporter.lua
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/sogo/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/sogo/Dockerfile
index 9cf5f62..72f7d81 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/sogo/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/sogo/Dockerfile
@@ -1,10 +1,10 @@
-FROM debian:buster-slim
+FROM debian:bullseye-slim
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive
ARG SOGO_DEBIAN_REPOSITORY=http://packages.inverse.ca/SOGo/nightly/5/debian/
ENV LC_ALL C
-ENV GOSU_VERSION 1.12
+ENV GOSU_VERSION 1.14
# Prerequisites
RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
@@ -31,7 +31,7 @@
&& mkdir /usr/share/doc/sogo \
&& touch /usr/share/doc/sogo/empty.sh \
&& apt-key adv --keyserver keyserver.ubuntu.com --recv-key 0x810273C4 \
- && echo "deb ${SOGO_DEBIAN_REPOSITORY} buster buster" > /etc/apt/sources.list.d/sogo.list \
+ && echo "deb ${SOGO_DEBIAN_REPOSITORY} bullseye bullseye" > /etc/apt/sources.list.d/sogo.list \
&& apt-get update && apt-get install -y --no-install-recommends \
sogo \
sogo-activesync \
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/unbound/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/unbound/Dockerfile
index cce2c00..a937e7e 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/unbound/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/unbound/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.13
+FROM alpine:3.14
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/Dockerfile b/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/Dockerfile
index e82bc5d..00cb8e9 100644
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/Dockerfile
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/Dockerfile
@@ -1,4 +1,4 @@
-FROM alpine:3.11
+FROM alpine:3.14
LABEL maintainer "André Peters <andre.peters@servercow.de>"
# Installation
@@ -36,4 +36,4 @@
COPY watchdog.sh /watchdog.sh
COPY check_mysql_slavestatus.sh /usr/lib/nagios/plugins/check_mysql_slavestatus.sh
-CMD /watchdog.sh 2> /dev/null
+CMD /watchdog.sh
diff --git a/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/watchdog.sh b/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/watchdog.sh
index 66ab12e..086e326 100755
--- a/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/watchdog.sh
+++ b/mailcow/src/mailcow-dockerized/data/Dockerfiles/watchdog/watchdog.sh
@@ -6,7 +6,10 @@
# Prepare
BACKGROUND_TASKS=()
echo "Waiting for containers to settle..."
-sleep 30
+for i in {30..1}; do
+ echo "${i}"
+ sleep 1
+done
if [[ "${USE_WATCHDOG}" =~ ^([nN][oO]|[nN])+$ ]]; then
echo -e "$(date) - USE_WATCHDOG=n, skipping watchdog..."
@@ -14,6 +17,14 @@
exec $(readlink -f "$0")
fi
+if [[ "${WATCHDOG_VERBOSE}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
+ SMTP_VERBOSE="--verbose"
+ set -xv
+else
+ SMTP_VERBOSE=""
+ exec 2>/dev/null
+fi
+
# Checks pipe their corresponding container name in this pipe
if [[ ! -p /tmp/com_pipe ]]; then
mkfifo /tmp/com_pipe
@@ -114,16 +125,16 @@
IFS=',' read -r -a MAIL_RCPTS <<< "${WATCHDOG_NOTIFY_EMAIL}"
for rcpt in "${MAIL_RCPTS[@]}"; do
RCPT_DOMAIN=
- #RCPT_MX=
+ RCPT_MX=
RCPT_DOMAIN=$(echo ${rcpt} | awk -F @ {'print $NF'})
- # Latest smtp-cli looks up mx via dns
- #RCPT_MX=$(dig +short ${RCPT_DOMAIN} mx | sort -n | awk '{print $2; exit}')
- #if [[ -z ${RCPT_MX} ]]; then
- # log_msg "Cannot determine MX for ${rcpt}, skipping email notification..."
- # return 1
- #fi
+ CHECK_FOR_VALID_MX=$(dig +short ${RCPT_DOMAIN} mx)
+ if [[ -z ${CHECK_FOR_VALID_MX} ]]; then
+ log_msg "Cannot determine MX for ${rcpt}, skipping email notification..."
+ return 1
+ fi
[ -f "/tmp/${1}" ] && BODY="/tmp/${1}"
timeout 10s ./smtp-cli --missing-modules-ok \
+ "${SMTP_VERBOSE}" \
--charset=UTF-8 \
--subject="${SUBJECT}" \
--body-plain="${BODY}" \
@@ -132,8 +143,15 @@
--from="watchdog@${MAILCOW_HOSTNAME}" \
--hello-host=${MAILCOW_HOSTNAME} \
--ipv4
- #--server="${RCPT_MX}"
- log_msg "Sent notification email to ${rcpt}"
+ if [[ $? -eq 1 ]]; then # exit code 1 is fine
+ log_msg "Sent notification email to ${rcpt}"
+ else
+ if [[ "${SMTP_VERBOSE}" == "" ]]; then
+ log_msg "Error while sending notification email to ${rcpt}. You can enable verbose logging by setting 'WATCHDOG_VERBOSE=y' in mailcow.conf."
+ else
+ log_msg "Error while sending notification email to ${rcpt}."
+ fi
+ fi
done
}
@@ -154,7 +172,7 @@
CONTAINER_ID=($(printf "%s\n" "${CONTAINER_ID[@]}" | shuf))
if [[ ! -z ${CONTAINER_ID} ]]; then
for matched_container in "${CONTAINER_ID[@]}"; do
- CONTAINER_IPS=($(curl --silent --insecure https://dockerapi/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress'))
+ CONTAINER_IPS=($(curl --silent --insecure https://dockerapi/containers/${matched_container}/json | jq -r '.NetworkSettings.Networks[].IPAddress'))
for ip_match in "${CONTAINER_IPS[@]}"; do
# grep will do nothing if one of these vars is empty
[[ -z ${ip_match} ]] && continue
@@ -358,7 +376,7 @@
touch /tmp/sogo-mailcow; echo "$(tail -50 /tmp/sogo-mailcow)" > /tmp/sogo-mailcow
host_ip=$(get_container_ip sogo-mailcow)
err_c_cur=${err_count}
- /usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /SOGo.index/ -p 20000 -R "SOGo\.MainUI" 2>> /tmp/sogo-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
+ /usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /SOGo.index/ -p 20000 2>> /tmp/sogo-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
progress "SOGo" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}