Skip to content

Commit

Permalink
HOSTNAME and DOMAINNAME setting improvements (docker-mailserver#2175)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
2 people authored and NorseGaud committed Sep 17, 2021
1 parent 72ff2f4 commit cda42ec
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 150 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/

# -----------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/content/config/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 1 addition & 6 deletions target/scripts/check-for-changes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
25 changes: 25 additions & 0 deletions target/scripts/helper-functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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.."
Expand Down
15 changes: 7 additions & 8 deletions target/scripts/postsrsd-wrapper.sh
Original file line number Diff line number Diff line change
@@ -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
Expand Down
4 changes: 2 additions & 2 deletions target/scripts/start-mailserver.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

# ------------------------------------------------------------
Expand Down
6 changes: 0 additions & 6 deletions target/scripts/startup/check-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"

Expand Down
202 changes: 202 additions & 0 deletions test/mail_hostname.bats
Original file line number Diff line number Diff line change
@@ -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'
}
Loading

0 comments on commit cda42ec

Please sign in to comment.