misc minor fixes
[distro-setup] / mail-setup
index 47f5990258ca184d2c5388f6411ce25507f26701..de9db482acad97f7c8cb4b23e4b856c7a8d87994 100755 (executable)
@@ -3,6 +3,25 @@
 # Copyright (C) 2019 Ian Kelling
 # SPDX-License-Identifier: AGPL-3.0-or-later
 
+
+# todo: setup an alert for bouncing test emails.
+
+# todo: bounces to my fsf mail can come from fsf@iankelling.org,
+# think about making bounces go from the original address.
+
+# todo: add a prometheus alert for dovecot.
+
+# todo: handle errors like this:
+# Mar 02 12:44:26 kw systemd[1]: exim4.service: Found left-over process 68210 (exim4) in control group while starting unit. Ignoring.
+# Mar 02 12:44:26 kw systemd[1]: This usually indicates unclean termination of a previous run, or service implementation deficiencies.
+#eg: on eggs, on may 1st, ps grep for exim, 2 daemons running. 1 leftover from a month ago
+#Debian-+  1954     1  0 36231 11560   4 Apr02 ?        00:40:25 /usr/sbin/exim4 -bd -q30m
+#Debian-+ 23058  1954  0 36821 10564   0 20:38 ?        00:00:00 /usr/sbin/exim4 -bd -q30m
+
+#  todo: harden dovecot. need to do some research. one way is for it to only listen on a wireguard vpn interface, so only clients that are on the vpn can access it.
+#  todo: consider hardening cups listening on 0.0.0.0
+#  todo: stop/disable local apache, and rpc.mountd, and kdeconnect when not in use.
+
 # todo:  hosts should only allow external mail that is authed and
 # destined for backup route. it is a minor issue since traffic is
 # limited to the wghole network.
 # todo: emailing info@amnimal.ninja produces a bounce, user doesn't exist
 # instead of a simple rejection like it should.
 
-# todo: auto restart of je on checkrestart
-
 # todo: run mailping test after running, or otherwise
 # clear out terminal alert
 
-# todo: reinstall bk with bigger filesystem
-
-# todo: on bk, dont send email if mailvpn is not up
-
-# todo: mailtest-check should check on bk too
-
 # todo: disable postgrey
 
 # todo: in testforward-check, we should also look
@@ -133,7 +144,7 @@ fi
 
 [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
 
-
+# note, this is hardcoded in /etc/exim4/conf.d/main/000_local
 u=$(id -nu 1000)
 
 
@@ -162,9 +173,10 @@ fi
 # background: dovecot does not yet have ocsp stapling support
 # reference: https://community.letsencrypt.org/t/simple-guide-using-lets-encrypt-ssl-certs-with-dovecot/2921
 #
-# for phone, k9mail, same thing but username alerts, pass in ivy-pass.
+# for phone, k9mail, fdroid, same thing but username alerts, pass in ivy-pass.
 # also, bk.b8.nz for secondary alerts, username is iank. same alerts pass.
-# fetching mail settings: folder poll frequency 10 minutes
+# fetching mail settings: folder poll frequency 10 minutes.
+# account settings, fetching mail, push folders: All. Then disable the persistent notification.
 #######
 
 
@@ -276,7 +288,11 @@ fi
 i() { # install file
   local tmp tmpdir dest="$1"
   local base="${dest##*/}"
-  mkdir -p ${dest%/*}
+  local dir="${dest%/*}"
+  if [[ $dir != "$base" ]]; then
+    # dest has a directory component
+    mkdir -p "$dir"
+  fi
   ir=false # i result
   tmpdir=$(mktemp -d)
   cat >$tmpdir/"$base"
@@ -300,22 +316,16 @@ soff () {
   for service; do
     # ignore services that dont exist
     if systemctl cat $service &>/dev/null; then
-      m systemctl stop $service;
-      m systemctl disable $service
+      m systemctl disable --now $service
     fi
   done
 }
-sre () {
+sre() {
   for service; do
     m systemctl restart $service
     m systemctl enable $service;
   done
 }
-sstart() {
-  for service; do
-    m systemctl enable --now $service;
-  done
-}
 mailhost() {
   [[ $HOSTNAME == "$MAIL_HOST" ]]
 }
@@ -337,7 +347,6 @@ stopifactive() {
 
 mxhost=mx.iankelling.org
 mxport=587
-forward=$u@$mxhost
 
 # old setup. left as comment for example
 # mxhost=mail.messagingengine.com
@@ -359,7 +368,7 @@ fi
 bhost_t=false
 case $HOSTNAME in
   $MAIL_HOST) : ;;
-  kd|frodo|x2|x3|kw|sy)
+  kd|frodo|x2|x3|kw|sy|bo)
     bhost_t=true
     ;;
 esac
@@ -367,6 +376,10 @@ esac
 
 # * Install universal packages
 
+
+# installs epanicclean iptables-exim ip6tables-exim
+/a/bin/ds/install-my-scripts
+
 if [[ $(debian-codename-compat) == bionic ]]; then
   cat >/etc/apt/preferences.d/spamassassin <<'EOF'
 Package: spamassassin sa-compile spamc
@@ -376,11 +389,17 @@ EOF
 fi
 
 # light version of exim does not have sasl auth support.
-pi-nostart exim4 exim4-daemon-heavy spamassassin openvpn unbound clamav-daemon wireguard
+# note: for bitfolk hosts, unbound has important config with conflink.
+pi-nostart exim4 exim4-daemon-heavy spamassassin unbound clamav-daemon wireguard
 
 # note: pyzor debian readme says you need to run some initialization command
 # but its outdated.
-pi spf-tools-perl p0f postgrey pyzor razor jq moreutils certbot
+pi spf-tools-perl p0f postgrey pyzor razor jq moreutils certbot fail2ban
+case $HOSTNAME in
+  je) : ;;
+  # not included due to using wireguard: openvpn
+  *) pi wget git unzip iptables ;;
+esac
 # bad packages that sometimes get automatically installed
 pu openresolv resolvconf
 
@@ -404,21 +423,6 @@ fi
 # our nostart pi fails to avoid enabling
 
 
-# * user forward file
-case $HOSTNAME in
-  $MAIL_HOST)
-    # afaik, these will get ignored on MAIL_HOST because they are routing to my own
-    # machine, but rm them is safer
-    rm -fv $uhome/.forward /root/.forward
-    ;;
-  *)
-    # this can\'t be a symlink and has permission restrictions
-    # it might work in /etc/aliases, but this seems more proper.
-    e setting $uhome/.forward to $forward
-    install -m 644 {-o,-g}$u <(e $forward) $uhome/.forward
-    ;;
-esac
-
 # * Mail clean cronjob
 
 i /etc/systemd/system/mailclean.timer <<'EOF'
@@ -462,30 +466,49 @@ EOF
 
 # * mail vpn config
 
-vpnser=mailvpn.service
+# old.
+#vpnser=mailvpn.service
+# todo: this hangs if it cant resolv the endpoint. we
+# want it to just retry in the background.
 vpnser=wg-quick@wgmail.service
 
 case $HOSTNAME in
   $MAIL_HOST)
+    rsync -aiSAX --chown=root:root --chmod=g-s /p/c/filesystem/etc/wireguard/ /etc/wireguard
     bindpaths="/etc/127.0.0.1-resolv:/run/systemd/resolve /etc/basic-nsswitch:/etc/resolved-nsswitch:norbind"
     ;;&
   bk)
     bindpaths="/etc/10.173.8.1-resolv:/etc/127.0.0.1-resolv"
     ;;&
+  *)
+    d=/p/c/machine_specific/$HOSTNAME/filesystem/etc/wireguard/
+    if [[ -d $d ]]; then
+      rsync -aiSAX --chown=root:root --chmod=g-s $d  /etc/wireguard
+    fi
+    ;;
 esac
 
-i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
+case $HOSTNAME in
+  li) : ;;
+  *)
+    i /etc/systemd/system/wg-quick@wgmail.service.d/override.conf <<EOF
 [Unit]
 Requires=mailnn.service
-After=network.target mailnn.service
 JoinsNamespaceOf=mailnn.service
 BindsTo=mailnn.service
+StartLimitIntervalSec=0
 
 [Service]
 PrivateNetwork=true
 # i dont think we need any of these, but it doesnt hurt to stay consistent
 BindPaths=$bindpaths
+
+Restart=on-failure
+RestartSec=20
 EOF
+    ;;
+esac
+
 
 # https://selivan.github.io/2017/12/30/systemd-serice-always-restart.html
 i /etc/systemd/system/mailvpn.service <<EOF
@@ -526,7 +549,7 @@ PrivateNetwork=true
 BindPaths=$bindpaths
 Restart=always
 # time to sleep before restarting a service
-RestartSec=1
+RestartSec=20
 
 [Install]
 WantedBy=multi-user.target
@@ -548,7 +571,7 @@ PrivateNetwork=true
 ExecStart=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns -n 10.173.8 start mail
 ExecStop=/usr/bin/flock -w 20 /tmp/newns.flock /a/bin/newns/newns stop mail
 Restart=always
-RestartSec=10
+RestartSec=20
 
 
 [Install]
@@ -571,6 +594,24 @@ ExecStart=/bin/sleep infinity
 WantedBy=multi-user.target
 EOF
 
+i /etc/systemd/system/mailbindwatchdog.service <<EOF
+[Unit]
+Description=Watchdog to restart services relying on systemd-resolved dir
+After=syslog.target network-online.target
+Wants=network-online.target
+BindsTo=mailnn.service
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/mailbindwatchdog $vpnser ${nn_progs[@]} unbound.service radicale.service
+Restart=always
+# time to sleep before restarting a service
+RestartSec=10
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
 
 
 # old service name
@@ -628,6 +669,7 @@ fi
 
 case $HOSTNAME in
   $MAIL_HOST)
+    # todo, should this be after vpn service
     i /etc/systemd/system/unbound.service.d/nn.conf <<EOF
 [Unit]
 After=mailnn.service
@@ -642,7 +684,7 @@ PrivateNetwork=true
 BindPaths=$bindpaths
 
 Restart=always
-RestartSec=1
+RestartSec=20
 EOF
 
     # sooo, there are a few ways to get traffic from the mail network
@@ -679,8 +721,12 @@ EOF
     for unit in ${nn_progs[@]}; do
       i /etc/systemd/system/$unit.service.d/nn.conf <<EOF
 [Unit]
-# commented for old openvpn
-Requires=$vpnser
+
+# Wants appears better than requires because with requires,
+# if the vpnser fails to start, this service won't get run at
+# all, even if the vpnser starts on an automatic restart.
+
+Wants=$vpnser
 After=network.target mailnn.service $vpnser
 JoinsNamespaceOf=mailnn.service
 BindsTo=mailnn.service
@@ -693,7 +739,7 @@ PrivateNetwork=true
 BindPaths=$bindpaths
 
 Restart=always
-RestartSec=1
+RestartSec=20
 EOF
     done
     ;;
@@ -755,14 +801,20 @@ if [[ -e /p/c/filesystem ]]; then
   # NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device.
   m /a/exe/vpn-mk-client-cert -b mailclient -n mail li.iankelling.org
 fi
-case $HOSTNAME in
-  bk)
-    if [[ ! -e /etc/openvpn/client/mail.conf ]]; then
-      echo "$0: error: first, on a system with /p/c/filesystem, run mail-setup, or the vpn-mk-client-cert line above this err" 2>&2
-      exit 1
-    fi
-    ;;
-esac
+
+# With openvpn, I didn't get around to persisting the openvpn
+# cert/configs into /p/c/machine_specific/bk, so I had this case to
+# manually get the cert. However, we aren't using openvpn anymore, so it
+# is commented out.
+#
+# case $HOSTNAME in
+#   bk)
+#     if [[ ! -e /etc/openvpn/client/mail.conf ]]; then
+#       echo "$0: error: first, on a system with /p/c/filesystem, run mail-setup, or the vpn-mk-client-cert line above this err" 2>&2
+#       exit 1
+#     fi
+#     ;;
+# esac
 
 m rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/mail-cert-cron /usr/local/bin
 
@@ -796,12 +848,139 @@ if $bhost_t && [[ ! -e /etc/exim4/certs/$wghost/privkey.pem ]]; then
           --deploy-hook /a/bin/ds/le-exim-deploy -d $wghost
 fi
 
+# * fail2ban
+
+# todo: test that these configs actually work, eg run
+# s iptables-exim -S
+# and see someone is banned.
+
+sed 's/^ *before *= *iptables-common.conf/before = iptables-common-exim.conf/' \
+    /etc/fail2ban/action.d/iptables-multiport.conf| i /etc/fail2ban/action.d/iptables-exim.conf
+i /etc/fail2ban/action.d/iptables-common-exim.conf <<'EOF'
+# iank: same as iptables-common, except iptables is iptables-exim, ip6tables is ip6tables-exim
+
+# Fail2Ban configuration file
+#
+# Author: Daniel Black
+#
+# This is a included configuration file and includes the definitions for the iptables
+# used in all iptables based actions by default.
+#
+# The user can override the defaults in iptables-common.local
+#
+# Modified: Alexander Koeppe <format_c@online.de>, Serg G. Brester <serg.brester@sebres.de>
+#       made config file IPv6 capable (see new section Init?family=inet6)
+
+[INCLUDES]
+
+after = iptables-blocktype.local
+        iptables-common.local
+# iptables-blocktype.local is obsolete
+
+[Definition]
+
+# Option:  actionflush
+# Notes.:  command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action)
+# Values:  CMD
+#
+actionflush = <iptables> -F f2b-<name>
+
+
+[Init]
+
+# Option:  chain
+# Notes    specifies the iptables chain to which the Fail2Ban rules should be
+#          added
+# Values:  STRING  Default: INPUT
+chain = INPUT
+
+# Default name of the chain
+#
+name = default
+
+# Option:  port
+# Notes.:  specifies port to monitor
+# Values:  [ NUM | STRING ]  Default:
+#
+port = ssh
+
+# Option:  protocol
+# Notes.:  internally used by config reader for interpolations.
+# Values:  [ tcp | udp | icmp | all ] Default: tcp
+#
+protocol = tcp
+
+# Option:  blocktype
+# Note:    This is what the action does with rules. This can be any jump target
+#          as per the iptables man page (section 8). Common values are DROP
+#          REJECT, REJECT --reject-with icmp-port-unreachable
+# Values:  STRING
+blocktype = REJECT --reject-with icmp-port-unreachable
+
+# Option:  returntype
+# Note:    This is the default rule on "actionstart". This should be RETURN
+#          in all (blocking) actions, except REJECT in allowing actions.
+# Values:  STRING
+returntype = RETURN
+
+# Option:  lockingopt
+# Notes.:  Option was introduced to iptables to prevent multiple instances from
+#          running concurrently and causing irratic behavior.  -w was introduced
+#          in iptables 1.4.20, so might be absent on older systems
+#          See https://github.com/fail2ban/fail2ban/issues/1122
+# Values:  STRING
+lockingopt = -w
+
+# Option:  iptables
+# Notes.:  Actual command to be executed, including common to all calls options
+# Values:  STRING
+iptables = /usr/local/bin/iptables-exim <lockingopt>
+
+
+[Init?family=inet6]
+
+# Option:  blocktype (ipv6)
+# Note:    This is what the action does with rules. This can be any jump target
+#          as per the iptables man page (section 8). Common values are DROP
+#          REJECT, REJECT --reject-with icmp6-port-unreachable
+# Values:  STRING
+blocktype = REJECT --reject-with icmp6-port-unreachable
+
+# Option:  iptables (ipv6)
+# Notes.:  Actual command to be executed, including common to all calls options
+# Values:  STRING
+iptables = /usr/local/bin/ip6tables-exim <lockingopt>
+EOF
+
+i /etc/fail2ban/jail.d/exim.local <<'EOF'
+[exim]
+enabled  = true
+port    = 25,587
+filter   = exim
+banaction = iptables-exim
+
+# 209.51.188.13 = mail.fsf.org
+# 2001:470:142::13 = mail.fsf.org
+# 209.51.188.92 = eggs.gnu.org
+# 2001:470:142:3::10 = eggs.gnu.org
+# 72.14.176.105 2600:3c00:e000:280::2 = mail.iankelling.org
+# 10.173.8.1 = non-nn net
+ignoreip = 209.51.188.13 2001:470:142::13 209.51.188.92 2001:470:142:3::10 72.14.176.105 2600:3c00:e000:280::2 10.173.8.1
+EOF
+if $ir; then
+  m systemctl restart fail2ban
+fi
+
 # * common exim4 config
 
 
+## old, not using forward files anymore
+rm -fv $uhome/.forward /root/.forward
+
+
 # Make all system users be aliases. preventative
-# measure for things like cron mail for user without alias
-awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ { print $1 }' /etc/passwd| while read -r user; do
+# prevents things like cron mail for user without alias
+awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ || $7 ~ /\/nologin$/  { print $1 }' /etc/passwd| while read -r user; do
   if [[ ! $user ]]; then
     continue
   fi
@@ -810,11 +989,23 @@ awk 'BEGIN { FS = ":" } ; $6 !~ /^\/home/ { print $1 }' /etc/passwd| while read
   fi
 done
 
-if ! grep -q "^ncsoft:" /etc/aliases; then
-  echo "ncsoft: graceq2323@gmail.com" |m tee -a /etc/aliases
-fi
+
+awk 'BEGIN { FS = ":" } ; $6 ~ /^\/home/ && $7 !~ /\/nologin$/ { print $1 }' /etc/passwd| while read -r user; do
+  case $HOSTNAME in
+    $MAIL_HOST)
+      sed -i "/^user:/d" /etc/aliases
+      ;;
+    *)
+      if ! grep -q "^$user:" /etc/aliases; then
+        echo "$user: root" |m tee -a /etc/aliases
+      fi
+      ;;
+  esac
+done
 
 
+. /a/bin/bash_unpublished/priv-mail-setup
+
 
 m gpasswd -a iank adm #needed for reading logs
 
@@ -846,16 +1037,24 @@ if (( ${#files[@]} )); then
     ${files[@]} /etc/exim4
 fi
 
-# by default, only 10 days of logs are kept. increase that.
-m sed -ri 's/^(\s*rotate\s).*/\11000/' /etc/logrotate.d/exim4-base
-
+# By default, only 10 days of logs are kept. increase that.
+# And dont compress, I look back at logs too often and
+# dont need the annoyance of decompressing them all the time.
+m sed -ri '/^\s*compress\s*$/d;s/^(\s*rotate\s).*/\11000/' /etc/logrotate.d/exim4-base
+files=(/var/log/exim4/*.gz)
+if (( ${#files[@]} )); then
+  gunzip ${files[@]}
+fi
 
-## https://blog.dhampir.no/content/make-exim4-on-debian-respect-forward-and-etcaliases-when-using-a-smarthost
-# i only need .forwards, so just doing that one.
-cd /etc/exim4/conf.d/router
-b=userforward_higher_priority
-# replace the router name so it is unique
-sed -r s/^\\S+:/$b:/ 600_exim4-config_userforward >175_$b
+## disabled. not using .forward files, but this is still interesting
+## for reference.
+# ## https://blog.dhampir.no/content/make-exim4-on-debian-respect-forward-and-etcaliases-when-using-a-smarthost
+# # i only need .forwards, so just doing that one.
+# cd /etc/exim4/conf.d/router
+# b=userforward_higher_priority
+# # replace the router name so it is unique
+# sed -r s/^\\S+:/$b:/ 600_exim4-config_userforward >175_$b
+rm -fv /etc/exim4/conf.d/router/175_userforward_higher_priority
 
 # todo, consider 'separate' in etc/exim4.conf, could it help on busy systems?
 
@@ -874,17 +1073,43 @@ rm -fv /etc/exim4/conf.d/retry/37_retry
 
 cat >/etc/exim4/conf.d/retry/17_retry <<'EOF'
 # Retry fast for my own domains
-iankelling.org * F,1d,10m;F,14d,1h
-amnimal.ninja * F,1d,10m;F,14d,1h
-expertpathologyreview.com * F,1d,10m;F,14d,1h
-je.b8.nz * F,1d,10m;F,14d,1h
-zroe.org * F,1d,10m;F,14d,1h
+iankelling.org * F,1d,4m;F,14d,1h
+amnimal.ninja * F,1d,4m;F,14d,1h
+expertpathologyreview.com * F,1d,4m;F,14d,1h
+je.b8.nz * F,1d,4m;F,14d,1h
+zroe.org * F,1d,4m;F,14d,1h
 eximbackup.b8.nz * F,1d,4m;F,14d,1h
+
+# The spec says the target domain will be used for temporary host errors,
+# but i've found that isn't correct, the hostname is required
+# at least sometimes.
+nn.b8.nz * F,1d,4m;F,14d,1h
+defaultnn.b8.nz * F,1d,4m;F,14d,1h
+mx.iankelling.org * F,1d,4m;F,14d,1h
+bk.b8.nz * F,1d,4m;F,14d,1h
+eggs.gnu.org * F,1d,4m;F,14d,1h
+fencepost.gnu.org * F,1d,4m;F,14d,1h
+
+# afaik our retry doesnt need this, but just using everything
+mx.amnimal.ninja * F,1d,4m;F,14d,1h
+mx.expertpathologyreview.com * F,1d,4m;F,14d,1h
+
+
+mail.fsf.org * F,1d,15m;F,14d,1h
 EOF
 
 
 rm -vf /etc/exim4/conf.d/main/000_localmacros # old filename
-cat >/etc/exim4/conf.d/main/000_local <<EOF
+
+# separate file so without quoted EOF for convenience
+cat >/etc/exim4/conf.d/main/000_local2 <<EOF
+# normally empty, I set this so I can set the envelope address
+# when doing mail redelivery to invoke filters. Also allows
+# me exiqgrep and stuff.
+MAIN_TRUSTED_GROUPS = $u
+EOF
+
+cat >/etc/exim4/conf.d/main/000_local <<'EOF'
 MAIN_TLS_ENABLE = true
 
 # require tls connections for all smarthosts
@@ -906,11 +1131,6 @@ MAIN_LOG_SELECTOR = +all
 # Based on spec, seems like a good idea to be nice.
 smtp_return_error_details = true
 
-# normally empty, I set this so I can set the envelope address
-# when doing mail redelivery to invoke filters. Also allows
-# me exiqgrep and stuff.
-MAIN_TRUSTED_GROUPS = $u
-
 # default is 10. when exim has been down for a bit, fsf mailserver
 # will do a big send in one connection, then exim decides to put
 # the messages in the queue instead of delivering them, to avoid
@@ -929,10 +1149,10 @@ DKIM_SELECTOR = li
 # There could be some circumstance when the
 # from: isnt our domain, but the envelope sender is
 # and so still want to sign, but I cant think of any case.
-DKIM_DOMAIN = \${lc:\${domain:\$rh_from:}}
+DKIM_DOMAIN = ${lc:${domain:$rh_from:}}
 # The file is based on the outgoing domain-name in the from-header.
 # sign if key exists
-DKIM_PRIVATE_KEY = \${if exists{/etc/exim4/\${dkim_domain}-private.pem} {/etc/exim4/\${dkim_domain}-private.pem}}
+DKIM_PRIVATE_KEY = ${if exists{/etc/exim4/${dkim_domain}-private.pem} {/etc/exim4/${dkim_domain}-private.pem}}
 
 # most of the ones that gmail seems to use.
 # Exim has horrible default of signing unincluded
@@ -943,19 +1163,43 @@ DKIM_SIGN_HEADERS = mime-version:in-reply-to:references:from:date:subject:to
 
 domainlist local_hostnames = ! je.b8.nz : ! bk.b8.nz : *.b8.nz : b8.nz
 
-hostlist iank_trusted = <; \\
+hostlist iank_trusted = <; \
 # veth0
-10.173.8.1 ; \\
+10.173.8.1 ; \
 # li li_ip6
-72.14.176.105 ; 2600:3c00::f03c:91ff:fe6d:baf8 ; \\
+72.14.176.105 ; 2600:3c00::f03c:91ff:fe6d:baf8 ; \
 # li_vpn_net li_vpn_net_ip6s
-10.8.0.0/24; 2600:3c00:e000:280::/64 ; 2600:3c00:e002:3800::/56 ;  \\
+10.8.0.0/24; 2600:3c00:e000:280::/64 ; 2600:3c00:e002:3800::/56 ;  \
 # bk bk_ip6
-85.119.83.50 ; 2001:ba8:1f1:f0c9::2 ; \\
+85.119.83.50 ; 2001:ba8:1f1:f0c9::2 ; \
 # je je_ipv6
-85.119.82.128 ; 2001:ba8:1f1:f09d::2 ; \\
+85.119.82.128 ; 2001:ba8:1f1:f09d::2 ; \
 # fsf_mit_net fsf_mit_net_ip6 fsf_net fsf_net_ip6 fsf_office_net
 18.4.89.0/24 ; 2603:3005:71a:2e00::/64 ; 209.51.188.0/24 ; 2001:470:142::/48 ; 74.94.156.208/28
+
+
+# this is the default delay_warning_condition, plus matching on local_domains.
+# If I have some problem with my local system that causes delayed delivery,
+# I dont want to send warnings out to non-local domains.
+delay_warning_condition = ${if or {\
+  { !eq{$h_list-id:$h_list-post:$h_list-subscribe:}{} }\
+  { match{$h_precedence:}{(?i)bulk|list|junk} }\
+  { match{$h_auto-submitted:}{(?i)auto-generated|auto-replied} }\
+  { match_domain{$domain}{+local_domains} }\
+  } {no}{yes}}
+
+
+# enable 587 in addition to the default 25, so that
+# i can send mail where port 25 is firewalled by isp
+daemon_smtp_ports = 25 : 587
+# default of 25, can get stuck when catching up on mail
+smtp_accept_max = 400
+smtp_accept_reserve = 100
+smtp_reserve_hosts = +iank_trusted
+
+# Rules that make receiving more liberal should be on backup hosts
+# so that we dont reject mail accepted by MAIL_HOST
+LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE = /etc/exim4/conf.d/local_deny_exceptions_acl
 EOF
 
 rm -fv /etc/exim4/rcpt_local_acl # old path
@@ -976,6 +1220,7 @@ accept
 EOF
 
 rm -fv /etc/exim4/data_local_acl # old path
+
 i /etc/exim4/conf.d/data_local_acl <<'EOF'
 # Except for the "condition =", this was
 # a comment in the check_data acl. The comment about this not
@@ -994,6 +1239,8 @@ warn
 
 warn
   !hosts = +iank_trusted
+  # Smarthosts connect with residential ips and thus get flagged as spam if we do a spam check.
+  !authenticated = plain_server:login_server
   condition = ${if < {$message_size}{5000K}}
   spam = Debian-exim:true
   add_header = X-Spam_score_int: $spam_score_int
@@ -1003,6 +1250,8 @@ warn
   add_header = X-Spam_action: $spam_action
 
 warn
+  !hosts = +iank_trusted
+  !authenticated = plain_server:login_server
   condition = ${if def:malware_name}
   remove_header = Subject:
   add_header = Subject: [Clamav warning: $malware_name] $h_subject
@@ -1015,14 +1264,14 @@ warn
 
 EOF
 
-i /etc/exim4/conf.d/router/900_exim4-config_local_user <<EOF
+i /etc/exim4/conf.d/router/900_exim4-config_local_user <<'EOF'
 ### router/900_exim4-config_local_user
 #################################
 
 # This router matches local user mailboxes. If the router fails, the error
 # message is "Unknown user".
 local_user:
-  debug_print = "R: local_user for \$local_part@\$domain"
+  debug_print = "R: local_user for $local_part@$domain"
   driver = accept
   domains = +local_domains
 # ian: default file except where mentioned.
@@ -1211,13 +1460,10 @@ if mailhost; then
 
   i /etc/systemd/system/radicale.service.d/override.conf <<EOF
 [Unit]
-# this unit is configured to start and stop whenever
-# $vpnser does
 
 After=network.target network-online.target mailnn.service $vpnser
-BindsTo=$vpnser
 
-Wants=network-online.target
+Wants=$vpnser
 JoinsNamespaceOf=mailnn.service
 StartLimitIntervalSec=0
 
@@ -1226,7 +1472,7 @@ PrivateNetwork=true
 BindPaths=$bindpaths
 Restart=always
 # time to sleep before restarting a service
-RestartSec=1000
+RestartSec=20
 
 [Install]
 # for openvpn
@@ -1331,7 +1577,7 @@ case $HOSTNAME in
     # sieve has the benefit of being supported in postfix and
     # proprietary/weird environments, so there is more examples on the
     # internet.
-    pi dovecot-core dovecot-imapd dovecot-sieve dovecot-lmtpd dovecot-sqlite sqlite3
+    pi-nostart dovecot-core dovecot-imapd dovecot-sieve dovecot-lmtpd dovecot-sqlite sqlite3
 
     for f in /p/c{/machine_specific/$HOSTNAME,}/filesystem/etc/dovecot/users; do
       if [[ -e $f ]]; then
@@ -1339,8 +1585,8 @@ case $HOSTNAME in
         break
       fi
     done
-    for f in /p/c/subdir_files/sieve/*sieve /a/c/subdir_files/sieve/*sieve; do
-      m sudo -u $u /a/exe/lnf -T $f $uhome/sieve/${f##*/}
+    for f in /p/c/subdir_files/sieve/*sieve /a/bin/ds/subdir_files/sieve/*sieve; do
+      m sudo -u $u /a/exe/lnf -v -T $f $uhome/sieve/${f##*/}
     done
 
     # https://wiki.dovecot.org/SSL/DovecotConfiguration
@@ -1355,33 +1601,38 @@ xioE3sYKdjOt+p6mlg3l8+OLtODEFPHDqwIBAg==
 -----END DH PARAMETERS-----
 EOF
     {
+
       if [[ $HOSTNAME == "$MAIL_HOST" ]]; then
         cat <<'EOF'
 ssl_cert = </etc/exim4/fullchain.pem
 ssl_key = </etc/exim4/privkey.pem
 EOF
       else
+        # We have a lets encrypt hooks that puts things here.
+        # This is just for bk, which uses the vpn cert in exim
+        # for sending mail, but the local hostname cert for
+        # dovecot.
         cat <<'EOF'
 ssl_cert = </etc/exim4/exim.crt
 ssl_key = </etc/exim4/exim.key
 EOF
       fi
-      cat <<EOF
+
+      cat <<'EOF'
 # https://ssl-config.mozilla.org
 ssl = required
-# this is the same as the certbot list, in my cert cronjob, I check if that has changed upstream.
+# this is the same as the certbot list, i check changes in /a/bin/ds/filesystem/usr/local/bin/check-lets-encrypt-ssl-settings
 ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
 ssl_protocols = TLSv1.2
 ssl_prefer_server_ciphers = no
-ssl_dh_parameters_length = 2048
 
 protocol lmtp {
 #per https://wiki2.dovecot.org/Pigeonhole/Sieve/Configuration
-# default is just \$mail_plugins
-  mail_plugins = \$mail_plugins sieve
+# default is just $mail_plugins
+  mail_plugins = $mail_plugins sieve
 }
 EOF
-      if dpkg --compare-versions $(dpkg-query -f='${Version}\n' --show dovecot-core) ge 1:2.3; then
+      if dpkg --compare-versions "$(dpkg-query -f='${Version}\n' --show dovecot-core)" ge 1:2.3; then
         cat <<EOF
 ssl_dh = </etc/dovecot/dhparam
 EOF
@@ -1550,6 +1801,7 @@ EOF
     i /etc/dovecot/dovecot-sql.conf.ext <<'EOF'
 # from mailinabox
 driver = sqlite
+# for je and bk, populated the testignore users for the relevant domains
 connect = /m/rc/users.sqlite
 default_pass_scheme = SHA512-CRYPT
 password_query = SELECT email as user, password FROM users WHERE email='%u';
@@ -1571,6 +1823,8 @@ extra,
 privileges TEXT NOT NULL DEFAULT '');
 EOF
     fi
+    # users.sqlite is saved into /p/c/machine_specific, so update it there!.
+    #
     # example of adding a user:
     # hash: doveadm pw -s SHA512-CRYPT -p passhere
     # sqlite3 /m/rc/users.sqlite <<'EOF'
@@ -1677,6 +1931,7 @@ if [[ $HOSTNAME == bk ]]; then
   ### end composer install
 
   rcdirs=(/usr/local/lib/rcexpertpath /usr/local/lib/rcninja)
+  ncdirs=(/var/www/ncninja)
   ncdirs=(/var/www/ncexpertpath /var/www/ncninja)
   # point debian cronjob to our local install, preventing daily cron error
 
@@ -1685,8 +1940,8 @@ if [[ $HOSTNAME == bk ]]; then
 
   #### begin dl roundcube
   # note, im r2e subbed to https://github.com/roundcube/roundcubemail/releases.atom
-  v=1.4.11; f=roundcubemail-$v-complete.tar.gz
-  cd /a/opt
+  v=1.4.13; f=roundcubemail-$v-complete.tar.gz
+  cd /root
   if [[ -e $f ]]; then
     timestamp=$(stat -c %Y $f)
   else
@@ -1817,7 +2072,6 @@ EOF
     m chown -R www-data.www-data $rctmpdir /m/rc
     m chmod 750 $rctmpdir
     # Ensure the log file monitored by fail2ban exists, or else fail2ban can't start.
-    # todo: setup fail2ban
     # todo: check for other mailinabox things
     m sudo -u www-data touch $rclogdir/errors.log
 
@@ -1924,7 +2178,7 @@ EOF
   m phpenmod -v php mcrypt imap
   # dpkg says this is required
   m a2enmod proxy_fcgi setenvif
-  fpm=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* (php[^ ]*-fpm)( .*|$)/\1/p') # eg: php7.3-fpm
+  fpm=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* (php[^ ]*-fpm)( .*|$)/\1/p') # eg: php7.4-fpm
   phpver=$(dpkg-query -s php-fpm | sed -nr 's/^Depends:.* php([^ ]*)-fpm( .*|$)/\1/p')
   m a2enconf $fpm
   # 3 useless guides on php fpm fcgi debian 10 later, i figure out from reading
@@ -2010,7 +2264,7 @@ EOF
 
 # https://github.com/nextcloud/user_external#readme
 # plus mailinabox example
-\$CONFIG['user_backends'] = array(array('class' => 'OC_User_IMAP','arguments' => array('127.0.0.1', 143, null),),);
+#\$CONFIG['user_backends'] = array(array('class' => 'OC_User_IMAP','arguments' => array('127.0.0.1', 143, null),),);
 
 
 # based on installer check
@@ -2028,7 +2282,7 @@ var_export(\$CONFIG);
 fwrite(STDOUT, ";\n");
 EOF
     m php tmp.php >config.php
-    m rm tmp.php
+    m rm -f tmp.php
     m sudo -u www-data php $ncdir/occ maintenance:update:htaccess
     list=$(sudo -u www-data php $ncdir/occ --output=json_pretty app:list)
     # user_external not compaible with nc 23
@@ -2079,11 +2333,12 @@ For logs, run: jr -u $ncbase
 EOF
 fi
 EOFOUTER
+    chmod +x /usr/local/bin/ncup
 
     mkdir -p /var/www/cron-errors
     chown www-data.www-data /var/www/cron-errors
     i /etc/cron.d/$ncbase <<EOF
-PATH=/sbin:/usr/sbin:/usr/bin:/bin:/usr/local/bin
+PATH=/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin
 SHELL=/bin/bash
 # https://docs.nextcloud.com/server/20/admin_manual/configuration_server/background_jobs_configuration.html
 */5  *  *  *  * www-data php -f $ncdir/cron.php --define apc.enable_cli=1 |& log-once nccron
@@ -2118,7 +2373,7 @@ if (( ${#files[@]} )); then
 fi
 
 
-# ** auth
+# ** exim: auth
 
 case $HOSTNAME in
   bk|je)
@@ -2154,7 +2409,7 @@ server_advertise_condition = ${if eq{$tls_in_cipher}{}{}{*}}
 EOF
 fi
 
-# ** main daemon use non-default config file
+# ** exim: main daemon use non-default config file
 case $HOSTNAME in
   bk|$MAIL_HOST)
     # to see the default comments in /etc/default/exim4:
@@ -2165,8 +2420,12 @@ QUEUERUNNER='combined'
 QUEUEINTERVAL='30m'
 COMMONOPTIONS='-C /etc/exim4/my.conf'
 UPEX4OPTS='-o /etc/exim4/my.conf'
-#E4BCD_PANICLOG_NOISE='malware acl condition: clamd /var/run/clamav/clamd\.ctl : unable to connect to UNIX socket'
+# i use epanic-clean for alerting if there are bad paniclog entries
+E4BCD_WATCH_PANICLOG='no'
 EOF
+    chown Debian-exim:Debian-exim /usr/sbin/exim4
+    # needs guid set in order to become Debian-exim
+    chmod g+s,u+s /usr/sbin/exim4
     i /etc/exim4/trusted_configs <<'EOF'
 /etc/exim4/my.conf
 EOF
@@ -2180,7 +2439,57 @@ EOF
     ;;
 esac
 
+# ** exim non-root
+
 case $HOSTNAME in
+  bk|je|li)
+    # no reason to expect it to ever be there.
+    rm -fv /etc/systemd/system/exim4.service.d/nonroot.conf
+    ;;
+  *)
+    dirs=()
+    for d in /a /d /m /media /mnt /nocow /o /p /q; do
+      if [[ -d $d ]]; then
+        dirs+=($d)
+      fi
+    done
+    i /etc/systemd/system/exim4.service.d/nonroot.conf <<EOF
+[Service]
+# see 56.2 Root privilege in exim spec
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+# https://www.redhat.com/sysadmin/mastering-systemd
+# things that seem good and reasonabl.e
+PrivateTmp=yes
+ProtectHome=yes
+# note, in t10 systemd, if one of these is an sshfs mountpoint,
+# this whole setting doesnt work. tried it with a newer systemd 250 though
+# an nspawn, and it worked there.
+InaccessiblePaths=${dirs[@]}
+NoNewPrivileges=yes
+ProtectSystem=yes
+
+# when we get newer systemd
+#ProtectDevices=yes
+EOF
+    i /etc/exim4/conf.d/main/000_local-noroot <<'EOF'
+# see 56.2 Root privilege in exim spec
+deliver_drop_privilege = true
+EOF
+    files=(
+      300_exim4-config_real_local
+      600_exim4-config_userforward
+      700_exim4-config_procmail
+      800_exim4-config_maildrop
+      mmm_mail4root
+    )
+    for f in ${files[@]}; do
+      echo "# iank: removed due to running nonroot"|i /etc/exim4/conf.d/router/$f
+    done
+    ;;
+esac
+
+case $HOSTNAME in
+
   # ** $MAIL_HOST|bk|je)
   $MAIL_HOST|bk|je)
 
@@ -2197,25 +2506,17 @@ EOF
 CHECK_RCPT_VERIFY_SENDER = true
 # default config comment says: If you enable this, you might reject legitimate mail,
 # but eggs has had this a long time, so that seems unlikely.
-CHECK_DATA_VERIFY_HEADER_SYNTAX = true
 CHECK_RCPT_SPF = true
 CHECK_RCPT_REVERSE_DNS = true
 CHECK_MAIL_HELO_ISSUED = true
 
-# enable 587 in addition to the default 25, so that
-# i can send mail where port 25 is firewalled by isp
-daemon_smtp_ports = 25 : 587
-# default of 25, can get stuck when catching up on mail
-smtp_accept_max = 400
-smtp_accept_reserve = 100
-smtp_reserve_hosts = +iank_trusted
 
-# options exim has to avoid having to alter the default config files
-CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/conf.d/rcpt_local_acl
 CHECK_DATA_LOCAL_ACL_FILE = /etc/exim4/conf.d/data_local_acl
-LOCAL_DENY_EXCEPTIONS_LOCAL_ACL_FILE = /etc/exim4/conf.d/local_deny_exceptions_acl
+CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/conf.d/rcpt_local_acl
+
 # testing dmarc
 #dmarc_tld_file = /etc/public_suffix_list.dat
+
 EOF
     ;;&
 
@@ -2327,6 +2628,7 @@ ignore_target_hosts = ${HOSTNAME}wg.b8.nz
 # note changes here also require change in passwd.client
 route_list = * eximbackup.b8.nz
 same_domain_copy_routing = yes
+errors_to = alerts@iankelling.org
 no_more
 EOF
 
@@ -2340,9 +2642,8 @@ backup_remote:
 .endif
   hosts_require_auth = *
   hosts_try_auth = *
-  return_path = alerts@iankelling.org
   envelope_to_add
-  # manual return path because we dont want it to be the envelope sender
+  # manual return path because we want it to be the envelope sender
   # we got not the one we are using in this smtp transport
   headers_add = "Return-path: $sender_address"
 .ifdef REMOTE_SMTP_SMARTHOST_HOSTS_AVOID_TLS
@@ -2380,10 +2681,10 @@ EOF
 
     # this avoids some error. i cant remember what. todo:
     # test it out and document why/if its needed.
-    i /etc/exim4/host_local_deny_exceptions <<'EOF'
-mail.fsf.org
-*.posteo.de
-EOF
+    #     i /etc/exim4/host_local_deny_exceptions <<'EOF'
+    # mail.fsf.org
+    # *.posteo.de
+    # EOF
 
     # cron email from smarthost hosts will automatically be to
     # USER@FQDN. I redirect that to alerts@, on the smarthosts, but in
@@ -2398,11 +2699,28 @@ deny
 EOF
     echo|i /etc/exim4/conf.d/router/880_universal_forward
 
+
+    cat >>/etc/exim4/conf.d/main/000_local <<EOF
+MAILDIR_HOME_MAILDIR_LOCATION = /m/md/Sent
+EOF
+
     # for iank@fsf.org, i have mail.fsf.org forward it to fsf@iankelling.org.
     # and also have mail.iankelling.org whitelisted as a relay domain.
     # I could avoid that if I changed this to submit to 587 with a
     # password like a standard mua.
     i /etc/exim4/conf.d/router/188_exim4-config_smarthost <<'EOF'
+# ian: save a copy of sent mail. i thought of other ways to
+# do this, for example, to only save sent mail that is not sent
+# from my mail client which saves a copy by default, but in the
+# end, it seems simplest to turn that off. We want to save
+# external mail sent by smarthosts.
+sentarchive:
+  driver = redirect
+  domains = ! +local_domains
+  condition = ${if !bool{${lookup{$local_part@$domain}lsearch{/etc/exim4/ignore-sent}{true}}}}
+  data    = vojdedIdNejyebni@b8.nz
+  unseen
+
 # ian: copied from /etc/exim4/conf.d/router/200_exim4-config_primary, and added senders = and
 # replaced DCsmarthost with hostname
 fsfsmarthost:
@@ -2426,7 +2744,6 @@ posteosmarthost:
   host_find_failed = ignore
   same_domain_copy_routing = yes
   no_more
-
 EOF
 
     # Greping /etc/exim4, unqualified mails this would end up as
@@ -2448,13 +2765,13 @@ EOF
 
     /a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]]
 # note: i put nn.b8.nz into bind for good measure
-10.173.8.2 nn.b8.nz mail.iankelling.org
+10.173.8.2 nn.b8.nz mx.iankelling.org
 EOF
 
     # note: systemd-resolved will consult /etc/hosts, dnsmasq wont. this assumes
     # weve configured this file in dnsmasq if we are using it.
     /a/exe/cedit mail /etc/dnsmasq-servers.conf <<'EOF' || [[ $? == 1 ]]
-server=/mail.iankelling.org/127.0.1.1
+server=/mx.iankelling.org/127.0.1.1
 EOF
     # I used to use debconf-set-selections + dpkg-reconfigure,
     # which then updates this file
@@ -2466,10 +2783,12 @@ EOF
     # The debconf questions output is additional documentation that is not
     # easily accessible, but super long, along with the initial default comment in this
     # file, so I've saved that into ./mail-notes.conf.
+    #
+    # # TODO: remove mx.iankelling.org once systems get updated mail-setup from jan 2022
     cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # man page: is used to build the local_domains list, together with "localhost"
 # this is duplicated in a later router.
-dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
+dc_other_hostnames='iankelling.org;zroe.org;r2e.iankelling.org;mx.iankelling.org;!je.b8.nz;!bk.b8.nz;*.b8.nz;b8.nz'
 EOF
 
 
@@ -2490,8 +2809,6 @@ EOF
     echo|i /etc/exim4/conf.d/rcpt_local_acl
     echo|i /etc/exim4/conf.d/router/880_universal_forward
 
-    echo amnimal.ninja > /etc/mailname
-
     /a/exe/cedit nn /etc/hosts <<'EOF' || [[ $? == 1 ]]
 10.173.8.2 nn.b8.nz
 EOF
@@ -2511,7 +2828,7 @@ StartLimitIntervalSec=0
 [Service]
 Restart=always
 # time to sleep before restarting a service
-RestartSec=1
+RestartSec=20
 EOF
 
     i /etc/default/exim4in <<'EOF'
@@ -2521,9 +2838,10 @@ COMMONOPTIONS='-oP /run/exim4/eximin.pid'
 UPEX4OPTS='-d /etc/myexim4'
 EOF
 
+    echo bk.b8.nz > /etc/mailname
     cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # man page: is used to build the local_domains list, together with "localhost"
-dc_other_hostnames='amnimal.ninja;expertpathologyreview.com'
+dc_other_hostnames='amnimal.ninja;expertpathologyreview.com;bk.b8.nz'
 EOF
 
     ;;
@@ -2548,6 +2866,7 @@ EOF
     echo|i /etc/exim4/conf.d/router/190_exim4-config_fsfsmarthost
     echo|i /etc/exim4/conf.d/rcpt_local_acl
     echo|i /etc/exim4/conf.d/router/890_backup_copy
+    echo|i /etc/exim4/conf.d/main/000_local-nn
 
 
     if $bhost_t; then
@@ -2582,7 +2901,13 @@ EOF
     echo | /a/exe/cedit nn /etc/hosts || [[ $? == 1 ]]
     echo | /a/exe/cedit mail /etc/dnsmasq-servers.conf || [[ $? == 1 ]]
 
+
     if $bhost_t; then
+      install -d /bu
+      install -d -g Debian-exim -o Debian-exim -m 771 /bu/md
+      if [[ -e /bu/md/cur && $(stat -c %u /bu/md/cur) == 1000 ]]; then
+        chown -R Debian-exim:Debian-exim /bu/md
+      fi
       i /etc/exim4/conf.d/transport/30_backup_maildir <<EOF
 # modified debian maildir transport
 backup_maildir:
@@ -2594,26 +2919,36 @@ backup_maildir:
   directory_mode = 0700
   mode = 0644
   mode_fail_narrower = false
-  user = $u
 EOF
 
-      i /etc/exim4/conf.d/router/870_backup_local <<EOF
+      i /etc/exim4/conf.d/router/870_backup_local <<'EOF'
 ### router/900_exim4-config_local_user
 #################################
 
 backup_local:
-  debug_print = "R: local_user for \$local_part@\$domain"
+  debug_print = "R: local_user for $local_part@$domain"
   driver = accept
   domains = eximbackup.b8.nz
   transport = backup_maildir
 EOF
 
-
+      # Bind to wghole to receive mailbackup.
       wgholeip=$(sed -rn 's/^ *Address *= *([^/]+).*/\1/p' /etc/wireguard/wghole.conf)
       cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 dc_other_hostnames='eximbackup.b8.nz'
 dc_local_interfaces='127.0.0.1;::1;$wgholeip'
 EOF
+
+      # wghole & thus exim will fail to start without internet connectivity.
+      i /etc/systemd/system/exim4.service.d/backup.conf <<'EOF'
+[Unit]
+StartLimitIntervalSec=0
+
+[Service]
+Restart=always
+RestartSec=20
+EOF
+
     else
       cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 # Note: If theres like a temporary problem where mail gets sent to
@@ -2621,6 +2956,7 @@ EOF
 # instead of a permanent 5xx.
 dc_local_interfaces='127.0.0.1;::1'
 EOF
+      rm -fv /etc/systemd/system/exim4.service.d/backup.conf
     fi
     cat >>/etc/exim4/update-exim4.conf.conf <<EOF
 dc_eximconfig_configtype='smarthost'
@@ -2646,6 +2982,36 @@ case $HOSTNAME in
   $MAIL_HOST|bk)
     # config for the non-nn exim
     m rsync -ra --delete /etc/exim4/ /etc/myexim4
+    cat >>/etc/myexim4/conf.d/main/000_local-nn <<'EOF'
+# this makes it easier to see which exim is doing what
+log_file_path = /var/log/exim4/my%s
+EOF
+
+    cat >/etc/logrotate.d/myexim <<'EOF'
+/var/log/exim4/mymain /var/log/exim4/myreject {
+       daily
+       missingok
+       rotate 1000
+       delaycompress
+       notifempty
+       nocreate
+}
+/var/log/exim4/mypanic {
+       size 10M
+       missingok
+       rotate 10
+       compress
+       delaycompress
+       notifempty
+       nocreate
+}
+EOF
+
+    # If we ever wanted to have a separate spool,
+    # we could do it like this.
+    #     cat >>/etc/exim4/conf.d/main/000_local-nn <<'EOF'
+    # spool_directory = /var/spool/myexim4
+    # EOF
     cat >>/etc/myexim4/update-exim4.conf.conf <<'EOF'
 dc_eximconfig_configtype='smarthost'
 dc_smarthost='nn.b8.nz'
@@ -2687,6 +3053,9 @@ if [[ -e /nocow ]]; then
 # without local-fs on exim, we get these kind of errors in paniclog on shutdown:
 # Failed to create spool file /var/spool/exim4//input//1jCLxz-0008V4-V9-D: Permission denied
 After=local-fs.target
+
+[Service]
+ExecStartPre=/usr/local/bin/exim-nn-iptables
 EOF
   if ! mountpoint -q $sdir; then
     stopifactive exim4 exim4in
@@ -2721,8 +3090,8 @@ elif [[ $uid != 608 ]]; then
   m usermod -u 608 Debian-exim
   m groupmod -g 608 Debian-exim
   m usermod -g 608 Debian-exim
-  m find / /nocow -path ./var/tmp -prune -o -xdev -uid $uid -execdir chown -h 608 {} +
-  m find / /nocow -path ./var/tmp -prune -o -xdev -gid $gid -execdir chgrp -h 608 {} +
+  m find / /nocow -xdev -path ./var/tmp -prune -o -uid $uid -execdir chown -h 608 {} +
+  m find / /nocow -xdev -path ./var/tmp -prune -o -gid $gid -execdir chgrp -h 608 {} +
 fi
 
 # * start / stop services
@@ -2733,6 +3102,9 @@ if $reload; then
   m systemctl daemon-reload
 fi
 
+sysd-prom-fail-install epanicclean
+m systemctl --now enable epanicclean
+
 case $HOSTNAME in
   je)
     /a/exe/web-conf apache2 je.b8.nz
@@ -2746,31 +3118,32 @@ m /a/bin/ds/mail-cert-cron -1
 sre mailcert.timer
 
 case $HOSTNAME in
-  bk)
-    # todo, this should be done in distro-begin
-    soff systemd-resolved
-    ln -sf 127.0.0.1-resolv/stub-resolv.conf /etc/resolv.conf
-    ;;&
   $MAIL_HOST|bk)
-    sstart mailnn mailnnroute
-    # If these have changes, id rather manually restart it, id rather
-    # not restart and cause temporary errors
-    if $reload; then
-      sre $vpnser
-    else
-      sstart $vpnser
-    fi
+    m systemctl --now enable mailnn mailnnroute
     ;;&
   $MAIL_HOST)
+    # we use dns to start wg
     if $reload; then
       sre unbound
     else
-      sstart unbound
+      m systemctl --now enable unbound
     fi
     ;;&
   $MAIL_HOST|bk)
+    # If these have changes, id rather manually restart it, id rather
+    # not restart and cause temporary errors
+    if $reload; then
+      sre $vpnser
+    else
+      m systemctl --now enable $vpnser
+    fi
     if ! systemctl is-active clamav-daemon >/dev/null; then
-      sstart clamav-daemon
+      m systemctl --now enable clamav-daemon
+      out=$(rsync -aiSAX --chown=root:root --chmod=g-s /a/bin/ds/filesystem/etc/systemd/system/epanicclean.service /etc/systemd/system)
+      if [[ $out ]]; then
+        reload=true
+      fi
+
       # note, this will cause paniclog entries because it takes like 45
       # seconds for clamav to start, i use ./epanic-clean to remove
       # them.
@@ -2782,13 +3155,13 @@ case $HOSTNAME in
     # need to wait a bit before restarting exim, else I
     # get a paniclog entry like: spam acl condition: all spamd servers failed
     sleep 3
-    sstart mailclean.timer
+    m systemctl --now enable mailclean.timer
     ;;&
   $MAIL_HOST)
     # < 2.1 (eg: in t9), uses a different data format which required manual
     # migration. dont start if we are running an old version.
-    if dpkg --compare-versions $(dpkg -s radicale | awk '$1 == "Version:" { print $2 }') ge 2.1; then
-      sstart radicale
+    if dpkg --compare-versions "$(dpkg -s radicale | awk '$1 == "Version:" { print $2 }')" ge 2.1; then
+      m systemctl --now enable radicale
     fi
     ;;&
 esac
@@ -2798,7 +3171,10 @@ rm -f /var/local/mail-setup-reload
 
 
 case $HOSTNAME in
-  $MAIL_HOST|bk|je) : ;;
+  $MAIL_HOST|bk|je|li)
+    # on li, these are never started, except $vpnser
+    :
+    ;;
   *)
     soff radicale mailclean.timer dovecot spamassassin $vpnser mailnn clamav-daemon
     ;;
@@ -2806,6 +3182,16 @@ esac
 
 sre exim4
 
+case $HOSTNAME in
+  $MAIL_HOST)
+    m systemctl --now enable mailbindwatchdog
+    ;;
+  *)
+    soff mailbindwatchdog
+    ;;
+esac
+
+
 case $HOSTNAME in
   bk) sre exim4in ;;
 esac
@@ -2820,48 +3206,98 @@ case $HOSTNAME in
     # note: cronjob "ian" also does some important monitoring
     # todo: this will sometimes cause an alert because mailtest-check will run
     # before we have setup network namespace and spamassassin
-    cat >/etc/cron.d/mailtest <<EOF
+    /etc/cron.d/mailtest <<EOF
 SHELL=/bin/bash
 PATH=/usr/bin:/bin:/usr/local/bin
-MAILTO=alerts@iankelling.org
-*/5 * * * *   $u send-test-forward |& log-once send-test-forward
+MAILTO=daylert@iankelling.org
+*/5  * * * *   $u send-test-forward |& log-once send-test-forward
 */10 * * * *   root chmod -R g+rw /m/md/bounces |& log-once -1 bounces-chmod
-# im seeing some intermittent failures on the slow check, do it all the time
-# for now. It looks like a dns failure.
-#5-59/5 * * * *   root mailtest-check |& log-once -1 mailtest-check
-#0 * * * *   root mailtest-check slow |& log-once -1 mailtest-slow
-*/5 * * * *   root timeout 290 mailtest-check slow |& log-once -12 mailtest-check
+# if a bounce happened yesterday, dont let it slip through the cracks
+8   1 * * *   root export MAILTO=alerts@iankelling.org; [[ -s /var/log/exim4/mainlog.1 ]] && awk '\$5 == "**"' /var/log/exim4/mainlog.1
 EOF
+
+
     m sudo rsync -ahhi --chown=root:root --chmod=0755 \
       /b/ds/mailtest-check /b/ds/check-remote-mailqs /usr/local/bin/
+    i /etc/systemd/system/mailtest-check.service <<'EOF'
+[Unit]
+Description=mailtest-check
+After=local-fs.target
+StartLimitIntervalSec=0
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/mailtest-check slow
+Restart=always
+RestartSec=60
+
+[Install]
+WantedBy=graphical.target
+EOF
+    sysd-prom-fail-install mailtest-check
+    sre mailtest-check
     ;;&
   $MAIL_HOST)
     test_froms=(ian@iankelling.org z@zroe.org iank@gnu.org)
-    test_to="testignore@expertpathologyreview.com, testignore@je.b8.nz, testignore@amnimal.ninja, jtuttle@gnu.org"
+    test_tos=(testignore@expertpathologyreview.com testignore@je.b8.nz testignore@amnimal.ninja jtuttle@gnu.org)
 
     cat >>/etc/cron.d/mailtest <<EOF
-2   * * * *   $u check-remote-mailqs |& log-once check-remote-mailqs
+0   13 * * *  root echo "1pm alert. You are not in the matrix."
+2   * * * *   root check-remote-mailqs |& log-once check-remote-mailqs
 EOF
     ;;&
   bk)
-    test_froms=(testignore@expertpathologyreview.com testignore@amnimal.ninja)
-    test_to="testignore@iankelling.org, testignore@zroe.org, testignore@je.b8.nz"
+    test_froms=(testignore@amnimal.ninja testignore@expertpathologyreview.com)
+    test_tos=(testignore@iankelling.org testignore@je.b8.nz)
+    # We dont need to send from different addresses to the same
+    # address. this breaks down our nice elegant logic of building up
+    # froms and tos , so I just handle expertpath in a special case
+    # below and set the to: to be testignore@zroe.org.  If we did sent
+    # that way, it would also mess up our mailtest-check logic that
+    # finds which messages to check.
+    # for example: from testignore@amnimal.ninja to: testignore@iankelling.org testignore@zroe.org
+    # that would become 2 messages and we'd only check 1.
     ;;&
   je)
     test_froms=(testignore@je.b8.nz)
-    test_to="testignore@iankelling.org, testignore@zroe.org, testignore@expertpathologyreview.com, testignore@amnimal.ninja"
+    test_tos=(testignore@iankelling.org testignore@zroe.org testignore@expertpathologyreview.com testignore@amnimal.ninja)
     ;;&
   $MAIL_HOST|bk|je)
+
+    # Dont put these test messages into the sent folder or else it will
+    # overwhelm it, plus i dont want to save a copy at all.
+    rm -f /etc/exim4/ignore-sent
+    for t in ${test_tos[@]}; do
+      echo $t >> /etc/exim4/ignore-sent
+    done
+
     cat >/usr/local/bin/send-test-forward <<'EOF'
 #!/bin/bash
-exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$' | xargs /sbin/exim -Mrm >/dev/null
+# we remove from the queue older than 4.3 minutes since we send every 5 minutes.
+olds=(
+$(/usr/sbin/exiqgrep -o 260 -i -r '^(testignore@(iankelling\.org|zroe\.org|expertpathologyreview\.com|amnimal\.ninja|je\.b8\.nz)|jtuttle@gnu\.org)$')
+)
+if (( ${#olds[@]} )); then
+  /usr/sbin/exim -Mrm "${olds[@]}" >/dev/null
+fi
 EOF
     for test_from in ${test_froms[@]}; do
+
+      test_to=${test_tos[0]}
+      for t in ${test_tos[@]:1}; do
+        test_to+=", $t"
+      done
+      case $test_from in
+        testignore@expertpathologyreview.com)
+          test_to=testignore@zroe.org
+          ;;
+      esac
+
       cat >>/usr/local/bin/send-test-forward <<EOFOUTER
 /usr/sbin/exim -f $test_from -t <<EOF
 From: $test_from
 To: $test_to
-Subject: test \$(date +%Y-%m-%dT%H:%M:%S%z) \$(date +%s)
+Subject: test \$(date +%Y-%m-%dT%H:%M:%S%z) \$EPOCHSECONDS
 
 /usr/local/bin/send-test-forward
 EOF
@@ -2870,7 +3306,10 @@ EOFOUTER
     m chmod +x /usr/local/bin/send-test-forward
     ;;
   *)
-    rm -fv /etc/cron.d/mailtest
+    soff mailtest-check.service
+    rm -fv /etc/cron.d/mailtest \
+       /var/lib/prometheus/node-exporter/mailtest-check.prom* \
+       /var/local/cron-errors/check-remote-mailqs*
     ;;
 esac
 
@@ -2911,44 +3350,6 @@ done
 # Multiple user names need to be separated by spaces.
 # Root and postmaster mail recipient:
 
-# duplicated in brc2
-bum() {
-  local cur host
-  host=$1
-  (( $# == 1 )) || return 1
-  cur="$(awk '$2 == "/bu/mnt" {print $1}' /proc/mounts)"
-  if [[ $cur ]]; then
-    if [[ $cur == "$host:/bu/md" ]]; then
-      return 0
-    else
-      fusermount -u /bu/mnt
-    fi
-  fi
-  m sshfs bu@$host:/bu/home/md /bu/mnt -o reconnect,ServerAliveInterval=20,ServerAliveCountMax=30 -o allow_other
-}
-bu() {
-  if mountpoint -q /bu/mnt; then
-    if ! timeout -s 9 10 fusermount -u /bu/mnt; then
-      fusermount -zu /bu/mnt
-    fi
-  fi
-}
-
-case $HOSTNAME in
-  $MAIL_HOST)
-    case $HOSTNAME in
-      kw) bum x3 ;;
-      x3) bum kw ;;
-      kd|sy) bum x2 ;;
-      x2) bum kd ;;
-    esac
-    ;;
-  *)
-    bu
-    ;;
-esac
-
-
 m exit 0
 :