Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ RUN apt-get -q -y update \
&& apt-get -q -y install --no-install-recommends runit \
telnet \
net-tools \
iproute2 \
postfix \
libsasl2-modules \
rsyslog \
Expand Down
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,12 @@ __OFFICIAL ENVIRONMENT VARIABLES__
- POSTFIX_SMTPD_BANNER
- alter the SMTPD Banner of postfix e.g. _mailserver.example.local ESMTP_

- INET_PROTOCOLS
- which IP versions postfix listens on and uses: `all`, `ipv4` or `ipv6`
- _default: auto_ — `all` if the container has IPv6 (Docker network with `enable_ipv6`), otherwise `ipv4`
- AUTO_TRUST_NETWORKS
- add all networks this container is connected to and trust them to send mails
- includes IPv6 networks (as `[prefix]/len`) when the container has IPv6
- _set to any value to enable_
- ADDITIONAL_MYNETWORKS
- add this specific network to the automatically trusted onces
Expand Down Expand Up @@ -188,6 +192,27 @@ _some characters might brake your configuration!_

_for example: to set_ ___mynetworks_style = subnet___ _just add a environment variable_ ___POSTFIX_RAW_CONFIG_MYNETWORKS_STYLE=subnet___


## IPv6

Postfix listens on IPv6 whenever the container has it. With
plain Docker defaults a container is IPv4-only, and published ports reach it
over IPv6 through `docker-proxy`, which connects to the container over IPv4 —
so every IPv6 client shows up as the Docker network gateway (`172.x.0.1`).
To see real IPv6 client addresses, give the network IPv6 and let Docker NAT
IPv6 itself (`/etc/docker/daemon.json`: `"ip6tables": true`, plus
`"experimental": true` on Docker < 27):

```yaml
networks:
default:
enable_ipv6: true
ipam:
config:
- subnet: 172.19.0.0/16
- subnet: fd00:d0c:25::/64
```

## Volumes

- /etc/postfix/tls
Expand Down
18 changes: 18 additions & 0 deletions scripts/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,25 @@ EOF
# cleanup/remove amavis pidfile
rm -f /run/amavis/amavisd.pid 2> /dev/null > /dev/null

##
# POSTFIX IP PROTOCOLS
##

# Listen on IPv6 too whenever the container has it (Docker network with
# enable_ipv6). IPv4-only containers stay on ipv4 — Postfix would otherwise
# warn about missing IPv6 support on every start. INET_PROTOCOLS overrides.
if [ -z ${INET_PROTOCOLS+x} ]; then
if grep -q . /proc/net/if_inet6 2>/dev/null; then
INET_PROTOCOLS=all
else
INET_PROTOCOLS=ipv4
fi
fi
echo ">> postfix inet_protocols: $INET_PROTOCOLS"
postconf -e "inet_protocols=$INET_PROTOCOLS"

AVAILABLE_NETWORKS="127.0.0.0/8"
[ "$INET_PROTOCOLS" = "ipv4" ] || AVAILABLE_NETWORKS="$AVAILABLE_NETWORKS,[::1]/128"
if [ ! -z ${AUTO_TRUST_NETWORKS+x} ]; then
AVAILABLE_NETWORKS=$(list-available-networks.sh | tr '\n' ',' | sed 's/,$//g')
echo ">> trust all available networks: $AVAILABLE_NETWORKS"
Expand Down
54 changes: 16 additions & 38 deletions scripts/list-available-networks.sh
Original file line number Diff line number Diff line change
@@ -1,40 +1,18 @@
#!/bin/bash
#!/bin/sh
# Print every network this container is directly attached to, one per line,
# in Postfix mynetworks notation (IPv4 a.b.c.d/n, IPv6 [prefix]/n).
# Used by AUTO_TRUST_NETWORKS.
#
# Connected routes are exactly the attached networks, with the host bits
# already zeroed — no netmask arithmetic, and IPv6 works the same way.
# Link-local and multicast IPv6 prefixes are never trusted.

function getNetworkFromAddressAndNetmask {
IFS=. read -r i1 i2 i3 i4 <<< "$1"
IFS=. read -r m1 m2 m3 m4 <<< "$2"
printf "%d.%d.%d.%d\n" "$((i1 & m1))" "$((i2 & m2))" "$((i3 & m3))" "$((i4 & m4))"
}
echo "127.0.0.0/8"
ip -4 route show 2>/dev/null \
| awk '$1 ~ /\// && $1 != "default" && !/ via / { print $1 }'

function getCidrSuffixFromNetmask {
nbits=0
IFS=.
for dec in $1 ; do
case $dec in
255) let nbits+=8;;
254) let nbits+=7;;
252) let nbits+=6;;
248) let nbits+=5;;
240) let nbits+=4;;
224) let nbits+=3;;
192) let nbits+=2;;
128) let nbits+=1;;
0);;
*) echo "Error: $dec is not recognised"; exit 1
esac
done
echo "$nbits"
}


IFS=$'\n' # make newlines the only separator
for j in $(ifconfig | grep inet | tr ' ' '\n' | grep 'Mask\|add' | tr '\n' ' ' | sed 's/addr/\naddr/g' | grep . | sed 's/[^0-9. ]//g')
do
ADDR=$(echo "$j" | cut -d' ' -f1)
MASK=$(echo "$j" | cut -d' ' -f2)

NETWORK=$(getNetworkFromAddressAndNetmask "$ADDR" "$MASK")
CIDR=$(getCidrSuffixFromNetmask "$MASK")

echo "$NETWORK/$CIDR"
done
grep -q . /proc/net/if_inet6 2>/dev/null || exit 0
echo "[::1]/128"
ip -6 route show 2>/dev/null \
| awk '$1 ~ /\// && $1 != "default" && !/ via / && $1 !~ /^(fe80|ff[0-9a-f][0-9a-f]):/ {
split($1, p, "/"); print "[" p[1] "]/" p[2] }'
Loading