diff --git a/Makefile b/Makefile index f717e39e..c38731d4 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ clean: # remove running and stopped test containers -@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak config ; } || : -@ [[ -d testconfig.bak ]] && { sudo rm -rf test/config ; mv testconfig.bak test/config ; } || : - -@ for container in $$(docker ps -a --filter name='^/mail$$|^ldap_for_mail$$|^mail_override_hostname$$|^open-dkim$$|^hadolint$$|^eclint$$|^shellcheck$$' | sed 1d | cut -f 1-1 -d ' '); do docker rm -f $$container; done + -@ for container in $$(docker ps -a --filter name='^/mail$$|^ldap_for_mail$$|^mail_override_hostname$$|^mail_non_subdomain_hostname$$|^open-dkim$$|^hadolint$$|^eclint$$|^shellcheck$$' | sed 1d | cut -f 1-1 -d ' '); do docker rm -f $$container; done -@ sudo rm -rf test/onedir test/alias test/quota test/relay test/config/dovecot-lmtp/userdb test/config/key* test/config/opendkim/keys/domain.tld/ test/config/opendkim/keys/example.com/ test/config/opendkim/keys/localdomain2.com/ test/config/postfix-aliases.cf test/config/postfix-receive-access.cf test/config/postfix-receive-access.cfe test/config/dovecot-quotas.cf test/config/postfix-send-access.cf test/config/postfix-send-access.cfe test/config/relay-hosts/chksum test/config/relay-hosts/postfix-aliases.cf test/config/dhparams.pem test/config/dovecot-lmtp/dh.pem test/config/relay-hosts/dovecot-quotas.cf test/config/user-patches.sh test/alias/config/postfix-virtual.cf test/quota/config/dovecot-quotas.cf test/quota/config/postfix-accounts.cf test/relay/config/postfix-relaymap.cf test/relay/config/postfix-sasl-password.cf test/duplicate_configs/ # ----------------------------------------------- diff --git a/docs/content/config/environment.md b/docs/content/config/environment.md index e134648b..923d3dd2 100644 --- a/docs/content/config/environment.md +++ b/docs/content/config/environment.md @@ -11,7 +11,7 @@ title: Environment Variables ##### OVERRIDE_HOSTNAME - empty => uses the `hostname` command to get the mail server's canonical hostname. -- => Specify a fully-qualified domainname to serve mail for. This is used for many of the config features so if you can't set your hostname (e.g. you're in a container platform that doesn't let you) specify it in this environment variable. +- => Specify a fully-qualified domainname to serve mail for. This is used for many of the config features so if you can't set your hostname (e.g. you're in a container platform that doesn't let you) specify it in this environment variable. It will take priority over your docker-compose.yml's `hostname:` and `domainname:` values. ##### DMS_DEBUG diff --git a/target/scripts/check-for-changes.sh b/target/scripts/check-for-changes.sh index f089a5cc..7223d729 100755 --- a/target/scripts/check-for-changes.sh +++ b/target/scripts/check-for-changes.sh @@ -30,12 +30,7 @@ fi # determine postmaster address, duplicated from start-mailserver.sh # this script previously didn't work when POSTMASTER_ADDRESS was empty -if [[ -n ${OVERRIDE_HOSTNAME} ]] -then - DOMAINNAME="${OVERRIDE_HOSTNAME#*.}" -else - DOMAINNAME="$(hostname -d)" -fi +_obtain_hostname_and_domainname PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}" _notify 'inf' "${LOG_DATE} Using postmaster address ${PM_ADDRESS}" diff --git a/target/scripts/helper-functions.sh b/target/scripts/helper-functions.sh index d94091ff..5967e82a 100755 --- a/target/scripts/helper-functions.sh +++ b/target/scripts/helper-functions.sh @@ -209,6 +209,31 @@ function _monitored_files_checksums } export -f _monitored_files_checksums +# ? --------------------------------------------- General + +function _obtain_hostname_and_domainname +{ + if [[ -n "${OVERRIDE_HOSTNAME}" ]] + then + export HOSTNAME="${OVERRIDE_HOSTNAME}" + export DOMAINNAME="${DOMAINNAME:-${HOSTNAME#*.}}" + # Handle situations where the hostname is name.tld and hostname -d ends up just showing "tld" + if [[ ! "${DOMAINNAME}" =~ .*\..* ]] + then + DOMAINNAME="${HOSTNAME}" + fi + else + # These hostname commands will fail with "hostname: Name or service not known" + # if the hostname is not valid (important for tests) + HOSTNAME="$(hostname -f)" + DOMAINNAME="${DOMAINNAME:-$(hostname -d)}" + if [[ ! "${DOMAINNAME}" =~ .*\..* ]] + then + DOMAINNAME="${HOSTNAME}" + fi + fi +} + function _shutdown { _notify 'err' "Shutting down.." diff --git a/target/scripts/postsrsd-wrapper.sh b/target/scripts/postsrsd-wrapper.sh index 0ba1ba8f..1ad3db23 100755 --- a/target/scripts/postsrsd-wrapper.sh +++ b/target/scripts/postsrsd-wrapper.sh @@ -1,18 +1,17 @@ #! /bin/bash +# shellcheck source=./helper-functions.sh +. /usr/local/bin/helper-functions.sh + function _generate_secret { ( umask 0077 ; dd if=/dev/urandom bs=24 count=1 2>/dev/null | base64 -w0 > "${1}" ; ) ; } -if [[ -n ${SRS_DOMAINNAME} ]] +_obtain_hostname_and_domainname + +if [[ -n "${SRS_DOMAINNAME}" ]] then NEW_DOMAIN_NAME="${SRS_DOMAINNAME}" -elif [[ -n ${OVERRIDE_HOSTNAME} ]] -then - NEW_DOMAIN_NAME="${OVERRIDE_HOSTNAME#*.}" -elif [[ -n ${DOMAINNAME} ]] -then - NEW_DOMAIN_NAME="${DOMAINNAME}" else - NEW_DOMAIN_NAME=$(hostname -d) + NEW_DOMAIN_NAME="${DOMAINNAME}" fi sed -i -e "s/localdomain/${NEW_DOMAIN_NAME}/g" /etc/default/postsrsd diff --git a/target/scripts/start-mailserver.sh b/target/scripts/start-mailserver.sh index 160403ba..7b1e1c5c 100755 --- a/target/scripts/start-mailserver.sh +++ b/target/scripts/start-mailserver.sh @@ -67,8 +67,8 @@ VARS[VIRUSMAILS_DELETE_DELAY]="${VIRUSMAILS_DELETE_DELAY:=7}" export HOSTNAME DOMAINNAME CHKSUM_FILE -HOSTNAME="$(hostname -f)" -DOMAINNAME="$(hostname -d)" +_obtain_hostname_and_domainname + CHKSUM_FILE=/tmp/docker-mailserver-config-chksum # ------------------------------------------------------------ diff --git a/target/scripts/startup/check-stack.sh b/target/scripts/startup/check-stack.sh index 0f3203e9..f7061d35 100644 --- a/target/scripts/startup/check-stack.sh +++ b/target/scripts/startup/check-stack.sh @@ -13,12 +13,6 @@ function _check_hostname { _notify 'task' 'Checking that hostname/domainname is provided or overridden' - if [[ -n ${OVERRIDE_HOSTNAME} ]] - then - export HOSTNAME=${OVERRIDE_HOSTNAME} - export DOMAINNAME="${HOSTNAME#*.}" - fi - _notify 'inf' "Domain has been set to ${DOMAINNAME}" _notify 'inf' "Hostname has been set to ${HOSTNAME}" diff --git a/test/mail_hostname.bats b/test/mail_hostname.bats new file mode 100644 index 00000000..3d13618e --- /dev/null +++ b/test/mail_hostname.bats @@ -0,0 +1,202 @@ +load 'test_helper/common' + +function setup() { + run_setup_file_if_necessary +} + +function setup_file() { + local PRIVATE_CONFIG + PRIVATE_CONFIG="$(duplicate_config_for_container . mail_override_hostname)" + docker run --rm -d --name mail_override_hostname \ + -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ + -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ + -e PERMIT_DOCKER=network \ + -e DMS_DEBUG=0 \ + -e ENABLE_SRS=1 \ + -e OVERRIDE_HOSTNAME=mail.my-domain.com \ + -h unknown.domain.tld \ + -t "${NAME}" + + PRIVATE_CONFIG_TWO="$(duplicate_config_for_container . mail_non_subdomain_hostname)" + docker run --rm -d --name mail_non_subdomain_hostname \ + -v "${PRIVATE_CONFIG_TWO}":/tmp/docker-mailserver \ + -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ + -e PERMIT_DOCKER=network \ + -e ENABLE_SRS=1 \ + -e DMS_DEBUG=0 \ + --hostname domain.com \ + --domainname domain.com \ + -t "${NAME}" + + PRIVATE_CONFIG_THREE="$(duplicate_config_for_container . mail_srs_domainname)" + docker run --rm -d --name mail_srs_domainname \ + -v "${PRIVATE_CONFIG_THREE}":/tmp/docker-mailserver \ + -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ + -e PERMIT_DOCKER=network \ + -e DMS_DEBUG=0 \ + -e ENABLE_SRS=1 \ + -e SRS_DOMAINNAME=srs.my-domain.com \ + -e DOMAINNAME=my-domain.com \ + -h unknown.domain.tld \ + -t "${NAME}" + + PRIVATE_CONFIG_FOUR="$(duplicate_config_for_container . mail_domainname)" + docker run --rm -d --name mail_domainname \ + -v "${PRIVATE_CONFIG_FOUR}":/tmp/docker-mailserver \ + -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ + -e PERMIT_DOCKER=network \ + -e DMS_DEBUG=0 \ + -e ENABLE_SRS=1 \ + -e DOMAINNAME=my-domain.com \ + -h unknown.domain.tld \ + -t "${NAME}" + + wait_for_smtp_port_in_container mail_override_hostname + + wait_for_smtp_port_in_container mail_non_subdomain_hostname + + wait_for_smtp_port_in_container mail_srs_domainname + + wait_for_smtp_port_in_container mail_domainname + + # postfix virtual transport lmtp + docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" + docker exec mail_non_subdomain_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" +} + +@test "first" { + skip 'only used to call setup_file from setup' +} + +@test "checking SRS: SRS_DOMAINNAME is used correctly" { + repeat_until_success_or_timeout 15 docker exec mail_srs_domainname grep "SRS_DOMAIN=srs.my-domain.com" /etc/default/postsrsd +} + +@test "checking SRS: DOMAINNAME is handled correctly" { + repeat_until_success_or_timeout 15 docker exec mail_domainname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd +} + +@test "checking configuration: hostname/domainname override: check container hostname is applied correctly" { + run docker exec mail_override_hostname /bin/bash -c "hostname | grep unknown.domain.tld" + assert_success +} + +@test "checking configuration: hostname/domainname override: check overriden hostname is applied to all configs" { + run docker exec mail_override_hostname /bin/bash -c "cat /etc/mailname | grep my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com" + assert_success + run docker exec mail_override_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep mail.my-domain.com" + assert_success +} + +@test "checking configuration: hostname/domainname override: check hostname in postfix HELO message" { + run docker exec mail_override_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep mail.my-domain.com" + assert_success +} + +@test "checking configuration: hostname/domainname override: check headers of received mail" { + run docker exec mail_override_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1" + assert_success + run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com" + assert_success + + # test whether the container hostname is not found in received mail + run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep unknown.domain.tld" + assert_failure +} + +@test "checking SRS: OVERRIDE_HOSTNAME is handled correctly" { + run docker exec mail_override_hostname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd + assert_success +} + +@test "checking dovecot: postmaster address" { + run docker exec mail_override_hostname /bin/sh -c "grep 'postmaster_address = postmaster@my-domain.com' /etc/dovecot/conf.d/15-lda.conf" + assert_success +} + +# +# non-subdomain tests +# + +@test "checking configuration: non-subdomain: check container hostname is applied correctly" { + run docker exec mail_non_subdomain_hostname /bin/bash -c "hostname | grep domain.com" + assert_success +} + +@test "checking configuration: non-subdomain: check overriden hostname is applied to all configs" { + run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/mailname | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep mydomain | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "postconf -n | grep myhostname | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "doveconf | grep hostname | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep domain.com" + assert_success + run docker exec mail_non_subdomain_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep domain.com" + assert_success +} + +@test "checking configuration: non-subdomain: check hostname in postfix HELO message" { + run docker exec mail_non_subdomain_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep domain.com" + assert_success +} + +@test "checking configuration: non-subdomain: check headers of received mail" { + run docker exec mail_non_subdomain_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1" + assert_success + run docker exec mail_non_subdomain_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep domain.com" + assert_success +} + +@test "checking SRS: non-subdomain is handled correctly" { + docker exec mail_non_subdomain_hostname cat /etc/default/postsrsd + run docker exec mail_non_subdomain_hostname grep "SRS_DOMAIN=domain.com" /etc/default/postsrsd + assert_success +} + +@test "checking dovecot: non-subdomain postmaster address" { + run docker exec mail_non_subdomain_hostname /bin/sh -c "grep 'postmaster_address = postmaster@domain.com' /etc/dovecot/conf.d/15-lda.conf" + assert_success +} + +# +# clean exit +# + +@test "checking that the container stops cleanly: mail_override_hostname" { + run docker stop -t 60 mail_override_hostname + assert_success +} + +@test "checking that the container stops cleanly: mail_non_subdomain_hostname" { + run docker stop -t 60 mail_non_subdomain_hostname + assert_success +} + +@test "checking that the container stops cleanly: mail_srs_domainname" { + run docker stop -t 60 mail_srs_domainname + assert_success +} + +@test "checking that the container stops cleanly: mail_domainname" { + run docker stop -t 60 mail_domainname + assert_success +} + +@test "last" { + skip 'only used to call teardown_file from teardown' +} diff --git a/test/mail_override_hostname.bats b/test/mail_override_hostname.bats deleted file mode 100644 index 3eb2406b..00000000 --- a/test/mail_override_hostname.bats +++ /dev/null @@ -1,88 +0,0 @@ -load 'test_helper/common' - -function setup() { - run_setup_file_if_necessary -} - -function setup_file() { - local PRIVATE_CONFIG - PRIVATE_CONFIG="$(duplicate_config_for_container .)" - docker run --rm -d --name mail_override_hostname \ - -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e DMS_DEBUG=0 \ - -e ENABLE_SRS=1 \ - -e OVERRIDE_HOSTNAME=mail.my-domain.com \ - -h unknown.domain.tld \ - -t "${NAME}" - - wait_for_smtp_port_in_container mail_override_hostname - # postfix virtual transport lmtp - docker exec mail_override_hostname /bin/sh -c "nc 0.0.0.0 25 < /tmp/docker-mailserver-test/email-templates/existing-user1.txt" -} - -@test "first" { - skip 'only used to call setup_file from setup' -} - -@test "checking configuration: hostname/domainname override: check container hostname is applied correctly" { - run docker exec mail_override_hostname /bin/bash -c "hostname | grep unknown.domain.tld" - assert_success -} - -@test "checking configuration: hostname/domainname override: check overriden hostname is applied to all configs" { - run docker exec mail_override_hostname /bin/bash -c "cat /etc/mailname | grep my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep mydomain | grep my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "postconf -n | grep myhostname | grep mail.my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "doveconf | grep hostname | grep mail.my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep AuthservID | grep mail.my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "cat /etc/opendmarc.conf | grep TrustedAuthservIDs | grep mail.my-domain.com" - assert_success - run docker exec mail_override_hostname /bin/bash -c "cat /etc/amavis/conf.d/05-node_id | grep myhostname | grep mail.my-domain.com" - assert_success -} - -@test "checking configuration: hostname/domainname override: check hostname in postfix HELO message" { - run docker exec mail_override_hostname /bin/bash -c "nc -w 1 0.0.0.0 25 | grep mail.my-domain.com" - assert_success -} - -@test "checking configuration: hostname/domainname override: check headers of received mail" { - run docker exec mail_override_hostname /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l | grep 1" - assert_success - run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep mail.my-domain.com" - assert_success - - # test whether the container hostname is not found in received mail - run docker exec mail_override_hostname /bin/sh -c "cat /var/mail/localhost.localdomain/user1/new/* | grep unknown.domain.tld" - assert_failure -} - -@test "checking SRS: OVERRIDE_HOSTNAME is handled correctly" { - run docker exec mail_override_hostname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd - assert_success -} - -@test "checking dovecot: postmaster address" { - run docker exec mail_override_hostname /bin/sh -c "grep 'postmaster_address = postmaster@my-domain.com' /etc/dovecot/conf.d/15-lda.conf" - assert_success -} - -# -# clean exit -# - -@test "checking that the container stops cleanly" { - run docker stop -t 60 mail_override_hostname - assert_success -} - -@test "last" { - skip 'only used to call teardown_file from teardown' -} diff --git a/test/mail_srs_domainname.bats b/test/mail_srs_domainname.bats deleted file mode 100644 index aa730476..00000000 --- a/test/mail_srs_domainname.bats +++ /dev/null @@ -1,38 +0,0 @@ -load 'test_helper/common' - -@test "checking SRS: SRS_DOMAINNAME is used correctly" { - local PRIVATE_CONFIG - PRIVATE_CONFIG="$(duplicate_config_for_container . mail_srs_domainname)" - docker run --rm -d --name mail_srs_domainname \ - -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e DMS_DEBUG=0 \ - -e ENABLE_SRS=1 \ - -e SRS_DOMAINNAME=srs.my-domain.com \ - -e DOMAINNAME=my-domain.com \ - -h unknown.domain.tld \ - -t "${NAME}" - - teardown() { docker rm -f mail_srs_domainname; } - - repeat_until_success_or_timeout 15 docker exec mail_srs_domainname grep "SRS_DOMAIN=srs.my-domain.com" /etc/default/postsrsd -} - -@test "checking SRS: DOMAINNAME is handled correctly" { - local PRIVATE_CONFIG - PRIVATE_CONFIG="$(duplicate_config_for_container . mail_domainname)" - docker run --rm -d --name mail_domainname \ - -v "${PRIVATE_CONFIG}":/tmp/docker-mailserver \ - -v "$(pwd)/test/test-files":/tmp/docker-mailserver-test:ro \ - -e PERMIT_DOCKER=network \ - -e DMS_DEBUG=0 \ - -e ENABLE_SRS=1 \ - -e DOMAINNAME=my-domain.com \ - -h unknown.domain.tld \ - -t "${NAME}" - - teardown() { docker rm -f mail_domainname; } - - repeat_until_success_or_timeout 15 docker exec mail_domainname grep "SRS_DOMAIN=my-domain.com" /etc/default/postsrsd -}