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
9 changes: 2 additions & 7 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ RUN \
dovecot-ldap dovecot-lmtpd dovecot-managesieved dovecot-pop3d \
dovecot-sieve dovecot-solr dumb-init \
# E - O
ed fetchmail file gamin gnupg gzip iproute2 iptables \
ed fetchmail file gamin gnupg gzip iproute2 \
locales logwatch lhasa libdate-manip-perl libldap-common liblz4-tool \
libmail-spf-perl libnet-dns-perl libsasl2-modules lrzip lzop \
netcat-openbsd nomarch opendkim opendkim-tools opendmarc \
netcat-openbsd nftables nomarch opendkim opendkim-tools opendmarc \
# P - Z
pax pflogsumm postgrey p7zip-full postfix-ldap postfix-pcre \
postfix-policyd-spf-python postsrsd pyzor \
Expand Down Expand Up @@ -194,11 +194,6 @@ COPY target/opendmarc/opendmarc.conf /etc/opendmarc.conf
COPY target/opendmarc/default-opendmarc /etc/default/opendmarc
COPY target/opendmarc/ignore.hosts /etc/opendmarc/ignore.hosts

RUN \
# switch iptables and ip6tables to legacy for Fail2Ban
update-alternatives --set iptables /usr/sbin/iptables-legacy && \
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

# -----------------------------------------------
# --- Fetchmail, Postfix & Let'sEncrypt ---------
# -----------------------------------------------
Expand Down
6 changes: 3 additions & 3 deletions config-examples/fail2ban-jail.cf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
#ignoreip = 127.0.0.1/8

# Default ban action
# iptables-multiport: block IP only on affected port
# iptables-allports: block IP on all ports
#banaction = iptables-allports
# nftables-multiport: block IP only on affected port
# nftables-allports: block IP on all ports
#banaction = nftables-allports
2 changes: 1 addition & 1 deletion docs/content/config/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ cap_add:
- NET_ADMIN
```

Otherwise, `iptables` won't be able to ban IPs.
Otherwise, `nftables` won't be able to ban IPs.

##### FAIL2BAN_BLOCKTYPE

Expand Down
12 changes: 1 addition & 11 deletions docs/content/config/security/fail2ban.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Example configuration volume bind:
```

!!! attention
`docker-mailserver` must be launched with the `NET_ADMIN` capability in order to be able to install the iptable rules that actually ban IP addresses.
`docker-mailserver` must be launched with the `NET_ADMIN` capability in order to be able to install the nftables rules that actually ban IP addresses.

Thus either include `--cap-add=NET_ADMIN` in the `docker run` command, or the equivalent in `docker-compose.yml`:

Expand All @@ -38,16 +38,6 @@ Example configuration volume bind:
- NET_ADMIN
```

If you don't you will see errors the form of:

```log
iptables -w -X f2b-postfix -- stderr: "getsockopt failed strangely: Operation not permitted\niptables v1.4.21: can't initialize iptabl
es table `filter': Permission denied (you must be root)\nPerhaps iptables or your kernel needs to be upgraded.\niptables v1.4.21: can'
t initialize iptables table `filter': Permission denied (you must be root)\nPerhaps iptables or your kernel needs to be upgraded.\n"
2016-06-01 00:53:51,284 fail2ban.action [678]: ERROR iptables -w -D INPUT -p tcp -m multiport --dports smtp,465,submission -
j f2b-postfix
```

## Running fail2ban in a rootless container

[`RootlessKit`][rootless::rootless-kit] is the _fakeroot_ implementation for supporting _rootless mode_ in Docker and Podman. By default RootlessKit uses the [`builtin` port forwarding driver][rootless::port-drivers], which does not propagate source IP addresses.
Expand Down
2 changes: 1 addition & 1 deletion mailserver.env
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ ENABLE_DNSBL=0
# If you enable Fail2Ban, don't forget to add the following lines to your `docker-compose.yml`:
# cap_add:
# - NET_ADMIN
# Otherwise, `iptables` won't be able to ban IPs.
# Otherwise, `nftables` won't be able to ban IPs.
ENABLE_FAIL2BAN=0

# Fail2Ban blocktype
Expand Down
37 changes: 10 additions & 27 deletions target/bin/fail2ban
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,35 @@
# shellcheck source=../scripts/helpers/index.sh
source /usr/local/bin/helpers/index.sh

if ! IPTABLES_OUTPUT=$(iptables -L -n 2>&1)
then
_exit_with_error "IPTables is not functioning correctly

The output of \`iptables -L\` was:

${IPTABLES_OUTPUT}

Possible causes for this error are

1. Missing capabilities (you need CAP_NET_RAW & CAP_NET_ADMIN, see \`capsh --print\`)
2. Modifications caused by user-patches.sh
3. Host is configured incorrectly
"
fi

function __usage { echo "Usage: ${0} [<unban> <ip-address>]" ; }

unset JAILS
declare -a JAILS
IP_REGEXP='((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'

for LIST in $(fail2ban-client status | grep "Jail list" | cut -f2- | sed 's/,/ /g')
do
JAILS+=("${LIST}")
done

if [[ -z ${1} ]]
then

IP_COUNT=0
IPS_BANNED=0

for JAIL in "${JAILS[@]}"
do
BANNED_IP="$(iptables -L "f2b-${JAIL}" -n 2>/dev/null | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -v '0.0.0.0')"
BANNED_IPS=$(fail2ban-client status "${JAIL}" \
| grep 'Banned IP list' \
| grep -oE "${IP_REGEXP}")

if [[ -n ${BANNED_IP} ]]
if [[ -n ${BANNED_IPS} ]]
then
echo "Banned in ${JAIL}: ${BANNED_IP//$'\n'/, }"
IP_COUNT=$(( IP_COUNT + 1 ))
echo "Banned in ${JAIL}: ${BANNED_IPS//$'\n'/, }"
IPS_BANNED=1
fi
done

if [[ ${IP_COUNT} -eq 0 ]]
then
_log 'info' 'No IPs have been banned'
fi

[[ ${IPS_BANNED} -eq 0 ]] && _log 'info' "No IPs have been banned"
else

case "${1}" in
Expand Down
8 changes: 4 additions & 4 deletions target/fail2ban/jail.local
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ maxretry = 3
# can be defined using space (and/or comma) separator.
ignoreip = 127.0.0.1/8

# Default ban action
# iptables-multiport: block IP only on affected port
# iptables-allports: block IP on all ports
banaction = iptables-allports
# default ban action
# nftables-multiport: block IP only on affected port
# nftables-allports: block IP on all ports
banaction = nftables-allports

[dovecot]
enabled = true
Expand Down
2 changes: 1 addition & 1 deletion target/scripts/startup/setup-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ function _setup_fail2ban
_log 'debug' 'Setting up Fail2Ban'
if [[ ${FAIL2BAN_BLOCKTYPE} != 'reject' ]]
then
echo -e '[Init]\nblocktype = DROP' >/etc/fail2ban/action.d/iptables-common.local
echo -e '[Init]\nblocktype = drop' >/etc/fail2ban/action.d/nftables-common.local
fi
}

Expand Down
6 changes: 3 additions & 3 deletions test/config/fail2ban-jail.cf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ findtime = 321
maxretry = 2

# Default ban action
# iptables-multiport: block IP only on affected port
# iptables-allports: block IP on all ports
banaction = iptables-multiport
# nftables-multiport: block IP only on affected port
# nftables-allports: block IP on all ports
banaction = nftables-multiport
30 changes: 16 additions & 14 deletions test/mail_fail2ban.bats
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ function teardown_file() {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client get ${FILTER} maxretry"
assert_output 2

run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'dovecot', 'addaction', 'iptables-multiport']\""
assert_output "['set', 'dovecot', 'addaction', 'iptables-multiport']"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'dovecot', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'dovecot', 'addaction', 'nftables-multiport']"

run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix', 'addaction', 'iptables-multiport']\""
assert_output "['set', 'postfix', 'addaction', 'iptables-multiport']"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'postfix', 'addaction', 'nftables-multiport']"

run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix-sasl', 'addaction', 'iptables-multiport']\""
assert_output "['set', 'postfix-sasl', 'addaction', 'iptables-multiport']"
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client -d | grep -F \"['set', 'postfix-sasl', 'addaction', 'nftables-multiport']\""
assert_output "['set', 'postfix-sasl', 'addaction', 'nftables-multiport']"
done
}

Expand All @@ -96,9 +96,9 @@ function teardown_file() {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep '${FAIL_AUTH_MAILER_IP}'"
assert_success

# Checking that FAIL_AUTH_MAILER_IP is banned by iptables and blocktype set to DROP
run docker exec mail_fail2ban /bin/sh -c "iptables -n -L f2b-postfix-sasl"
assert_output --regexp "DROP.+all.+${FAIL_AUTH_MAILER_IP}"
# Checking that FAIL_AUTH_MAILER_IP is banned by nftables and blocktype set to DROP
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl 2>/dev/null"
assert_output --regexp "${FAIL_AUTH_MAILER_IP}"
}

@test "checking fail2ban: unban ip works" {
Expand All @@ -111,9 +111,9 @@ function teardown_file() {
run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status postfix-sasl | grep 'IP list:.*${FAIL_AUTH_MAILER_IP}'"
assert_failure

# Checking that FAIL_AUTH_MAILER_IP is unbanned by iptables
run docker exec mail_fail2ban /bin/sh -c "iptables -L f2b-postfix-sasl -n | grep REJECT | grep '${FAIL_AUTH_MAILER_IP}'"
assert_failure
# Checking that FAIL_AUTH_MAILER_IP is unbanned by nftables
run docker exec mail_fail2ban /bin/sh -c "nft list set inet f2b-table addr-set-postfix-sasl 2>/dev/null"
refute_output "${FAIL_AUTH_MAILER_IP}"
}

#
Expand All @@ -128,13 +128,15 @@ function teardown_file() {
sleep 10

run ./setup.sh -c mail_fail2ban debug fail2ban
assert_output --regexp "^Banned in dovecot: 192.0.66.5, 192.0.66.4.*"
assert_output --partial 'Banned in dovecot:'
assert_output --partial '192.0.66.5'
assert_output --partial '192.0.66.4'

run ./setup.sh -c mail_fail2ban debug fail2ban unban 192.0.66.4
assert_output --partial "Unbanned IP from dovecot: 1"

run ./setup.sh -c mail_fail2ban debug fail2ban
assert_output --regexp "^Banned in dovecot: 192.0.66.5.*"
assert_output --regexp "^Banned in dovecot:.*192.0.66.5.*"

run ./setup.sh -c mail_fail2ban debug fail2ban unban 192.0.66.5
assert_output --partial "Unbanned IP from dovecot: 1"
Expand Down