HOSTNAME and DOMAINNAME setting improvements (#2175)

Centralize the collection of the HOSTNAME and DOMAINAME so that it's predictable and uniform across the various scripts (using the helper). Ensure it supports the various configurations users can have (both subdomain and without subdomain, override and no override).

---

* using _obtain_hostname_and_domainname helper + covers when not a subdomain
doc: OVERRIDE_HOSTNAME takes priority

* added tests for non-subdomain hostname + further improvements

* moved SRS DOMAINANME tests into hostname test file + Allowing DOMAINNAME ENV to override what would be automatically set

---

Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
This commit is contained in:
Nathan Pierce 2021-09-11 10:20:16 -04:00 committed by GitHub
parent 8e91251d8c
commit c267d8a990
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 239 additions and 150 deletions

View file

@ -25,7 +25,7 @@ clean:
# remove running and stopped test containers # remove running and stopped test containers
-@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak config ; } || : -@ [[ -d config.bak ]] && { rm -rf config ; mv config.bak config ; } || :
-@ [[ -d testconfig.bak ]] && { sudo rm -rf test/config ; mv testconfig.bak test/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/ -@ 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/
# ----------------------------------------------- # -----------------------------------------------

View file

@ -11,7 +11,7 @@ title: Environment Variables
##### OVERRIDE_HOSTNAME ##### OVERRIDE_HOSTNAME
- empty => uses the `hostname` command to get the mail server's canonical 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 ##### DMS_DEBUG

View file

@ -30,12 +30,7 @@ fi
# determine postmaster address, duplicated from start-mailserver.sh # determine postmaster address, duplicated from start-mailserver.sh
# this script previously didn't work when POSTMASTER_ADDRESS was empty # this script previously didn't work when POSTMASTER_ADDRESS was empty
if [[ -n ${OVERRIDE_HOSTNAME} ]] _obtain_hostname_and_domainname
then
DOMAINNAME="${OVERRIDE_HOSTNAME#*.}"
else
DOMAINNAME="$(hostname -d)"
fi
PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}" PM_ADDRESS="${POSTMASTER_ADDRESS:=postmaster@${DOMAINNAME}}"
_notify 'inf' "${LOG_DATE} Using postmaster address ${PM_ADDRESS}" _notify 'inf' "${LOG_DATE} Using postmaster address ${PM_ADDRESS}"

View file

@ -209,6 +209,31 @@ function _monitored_files_checksums
} }
export -f _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 function _shutdown
{ {
_notify 'err' "Shutting down.." _notify 'err' "Shutting down.."

View file

@ -1,18 +1,17 @@
#! /bin/bash #! /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}" ; ) ; } 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 then
NEW_DOMAIN_NAME="${SRS_DOMAINNAME}" NEW_DOMAIN_NAME="${SRS_DOMAINNAME}"
elif [[ -n ${OVERRIDE_HOSTNAME} ]]
then
NEW_DOMAIN_NAME="${OVERRIDE_HOSTNAME#*.}"
elif [[ -n ${DOMAINNAME} ]]
then
NEW_DOMAIN_NAME="${DOMAINNAME}"
else else
NEW_DOMAIN_NAME=$(hostname -d) NEW_DOMAIN_NAME="${DOMAINNAME}"
fi fi
sed -i -e "s/localdomain/${NEW_DOMAIN_NAME}/g" /etc/default/postsrsd sed -i -e "s/localdomain/${NEW_DOMAIN_NAME}/g" /etc/default/postsrsd

View file

@ -67,8 +67,8 @@ VARS[VIRUSMAILS_DELETE_DELAY]="${VIRUSMAILS_DELETE_DELAY:=7}"
export HOSTNAME DOMAINNAME CHKSUM_FILE export HOSTNAME DOMAINNAME CHKSUM_FILE
HOSTNAME="$(hostname -f)" _obtain_hostname_and_domainname
DOMAINNAME="$(hostname -d)"
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
# ------------------------------------------------------------ # ------------------------------------------------------------

View file

@ -13,12 +13,6 @@ function _check_hostname
{ {
_notify 'task' 'Checking that hostname/domainname is provided or overridden' _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' "Domain has been set to ${DOMAINNAME}"
_notify 'inf' "Hostname has been set to ${HOSTNAME}" _notify 'inf' "Hostname has been set to ${HOSTNAME}"

202
test/mail_hostname.bats Normal file
View file

@ -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'
}

View file

@ -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'
}

View file

@ -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
}