From de61d42e686b2a9b593ef2d13c67bb6e0efb2652 Mon Sep 17 00:00:00 2001 From: Casper Date: Tue, 19 Apr 2022 10:44:51 +0200 Subject: [PATCH] Add ban feature to fail2ban script (#2538) --- config-examples/fail2ban-jail.cf | 32 ++++++++++++++++------ docs/content/config/security/fail2ban.md | 4 +-- docs/content/config/setup.sh.md | 6 +++- docs/content/faq.md | 11 ++++++++ target/bin/fail2ban | 28 ++++++++++++++++--- target/bin/setup | 9 ++++-- target/fail2ban/jail.local | 7 +++++ target/scripts/startup/setup-stack.sh | 3 ++ test/mail_fail2ban.bats | 35 +++++++++++++++--------- 9 files changed, 105 insertions(+), 30 deletions(-) diff --git a/config-examples/fail2ban-jail.cf b/config-examples/fail2ban-jail.cf index 146c8282..9611e7e0 100644 --- a/config-examples/fail2ban-jail.cf +++ b/config-examples/fail2ban-jail.cf @@ -1,21 +1,37 @@ [DEFAULT] # "bantime" is the number of seconds that a host is banned. -#bantime = 10m +bantime = 3h # A host is banned if it has generated "maxretry" during the last "findtime" # seconds. -#findtime = 10m +findtime = 10m # "maxretry" is the number of failures before a host get banned. -#maxretry = 5 +maxretry = 3 # "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban # will not ban a host which matches an address in this list. Several addresses # can be defined using space (and/or comma) separator. -#ignoreip = 127.0.0.1/8 +ignoreip = 127.0.0.1/8 -# Default ban action -# nftables-multiport: block IP only on affected port -# nftables-allports: block IP on all ports -#banaction = nftables-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 + +[postfix] +enabled = true + +[postfix-sasl] +enabled = true + +# This jail is used for manual bans. +# To ban an IP address use: setup.sh fail2ban ban +[custom] +enabled = true +bantime = 180d +port = smtp,pop3,pop3s,imap,imaps,submission,submissions,sieve diff --git a/docs/content/config/security/fail2ban.md b/docs/content/config/security/fail2ban.md index 9adf63c8..2bebf77a 100644 --- a/docs/content/config/security/fail2ban.md +++ b/docs/content/config/security/fail2ban.md @@ -97,7 +97,7 @@ You can also manage and list the banned IPs with the [`setup.sh`][docs-setupsh] ### List bans ```sh -./setup.sh debug fail2ban +./setup.sh fail2ban ``` ### Un-ban @@ -105,7 +105,7 @@ You can also manage and list the banned IPs with the [`setup.sh`][docs-setupsh] Here `192.168.1.15` is our banned IP. ```sh -./setup.sh debug fail2ban unban 192.168.1.15 +./setup.sh fail2ban unban 192.168.1.15 ``` [docs-setupsh]: ../setup.sh.md diff --git a/docs/content/config/setup.sh.md b/docs/content/config/setup.sh.md index 11304284..e5261f7c 100644 --- a/docs/content/config/setup.sh.md +++ b/docs/content/config/setup.sh.md @@ -73,8 +73,12 @@ DESCRIPTION ./setup.sh relay add-domain [] ./setup.sh relay exclude-domain + COMMAND fail2ban = + ./setup.sh fail2ban + ./setup.sh fail2ban ban + ./setup.sh fail2ban unban + COMMAND debug := - ./setup.sh debug fail2ban [unban ] ./setup.sh debug fetchmail ./setup.sh debug login ./setup.sh debug show-mail-logs diff --git a/docs/content/faq.md b/docs/content/faq.md index 058865de..bcdb0fbb 100644 --- a/docs/content/faq.md +++ b/docs/content/faq.md @@ -427,6 +427,17 @@ sed -i 's/rimap -r/rimap/' /etc/supervisor/conf.d/saslauth.conf supervisorctl update ``` +### How to ban custom IP addresses with Fail2ban + +Use the following command: + +```bash +./setup.sh fail2ban ban +``` + +The default bantime is 180 days. This value can be [customized][fail2ban-customize]. + +[fail2ban-customize]: ./config/security/fail2ban.md [docs-maintenance]: ./config/advanced/maintenance/update-and-cleanup.md [docs-userpatches]: ./config/advanced/override-defaults/user-patches.md [github-issue-95]: https://github.com/docker-mailserver/docker-mailserver/issues/95 diff --git a/target/bin/fail2ban b/target/bin/fail2ban index f35f2f06..d5f61a16 100755 --- a/target/bin/fail2ban +++ b/target/bin/fail2ban @@ -3,7 +3,7 @@ # shellcheck source=../scripts/helpers/index.sh source /usr/local/bin/helpers/index.sh -function __usage { echo "Usage: ${0} [ ]" ; } +function __usage { echo "Usage: ./setup.sh fail2ban [ ]" ; } unset JAILS declare -a JAILS @@ -36,6 +36,26 @@ else case "${1}" in + ( 'help' ) __usage ; exit ;; + + ( 'ban' ) + shift + if [[ -n ${1} ]] + then + RESULT=$(fail2ban-client set custom banip "${@}") + if [[ ${RESULT} -gt 0 ]] + then + echo "Banned custom IP: ${RESULT}" + else + _log 'error' "Banning '${*}' failed. Already banned?" + fi + + else + _log 'warn' "You need to specify an IP address: Run './setup.sh fail2ban ban '" + exit 0 + fi + ;; + ( 'unban' ) shift if [[ -n ${1} ]] @@ -43,13 +63,13 @@ else for JAIL in "${JAILS[@]}" do - RESULT="$(fail2ban-client set "${JAIL}" unbanip "${@}" 2>&1)" + RESULT=$(fail2ban-client set "${JAIL}" unbanip "${@}" 2>&1) - [[ ${RESULT} != *"is not banned"* ]] && [[ ${RESULT} != *"NOK"* ]] && echo -e "Unbanned IP from ${JAIL}: ${RESULT}" + [[ ${RESULT} != *"is not banned"* ]] && [[ ${RESULT} != *"NOK"* ]] && echo "Unbanned IP from ${JAIL}: ${RESULT}" done else - _log 'warn' "You need to specify an IP address: Run './setup.sh debug fail2ban' to get a list of banned IP addresses" + _log 'warn' "You need to specify an IP address: Run './setup.sh fail2ban' to get a list of banned IP addresses" exit 0 fi ;; diff --git a/target/bin/setup b/target/bin/setup index 89dbf884..44d378cc 100755 --- a/target/bin/setup +++ b/target/bin/setup @@ -67,8 +67,12 @@ ${RED}[${ORANGE}SUB${RED}]${ORANGE}COMMANDS${RESET} ${0} relay ${CYAN}add-domain${RESET} [] ${0} relay ${CYAN}exclude-domain${RESET} + ${LBLUE}COMMAND${RESET} fail2ban ${RED}:=${RESET} + ${0} fail2ban ${RESET} + ${0} fail2ban ${CYAN}ban${RESET} + ${0} fail2ban ${CYAN}unban${RESET} + ${LBLUE}COMMAND${RESET} debug ${RED}:=${RESET} - ${0} debug ${CYAN}fail2ban${RESET} [unban ] ${0} debug ${CYAN}fetchmail${RESET} ${0} debug ${CYAN}login${RESET} ${0} debug ${CYAN}show-mail-logs${RESET} @@ -144,10 +148,11 @@ function _main esac ;; + ( fail2ban ) shift 1 ; fail2ban "${@}" ;; + ( debug ) case ${2:-} in ( fetchmail ) debug-fetchmail ;; - ( fail2ban ) shift 2 ; fail2ban "${@}" ;; ( show-mail-logs ) cat /var/log/mail/mail.log ;; ( login ) shift 2 diff --git a/target/fail2ban/jail.local b/target/fail2ban/jail.local index fcf351c5..9611e7e0 100644 --- a/target/fail2ban/jail.local +++ b/target/fail2ban/jail.local @@ -28,3 +28,10 @@ enabled = true [postfix-sasl] enabled = true + +# This jail is used for manual bans. +# To ban an IP address use: setup.sh fail2ban ban +[custom] +enabled = true +bantime = 180d +port = smtp,pop3,pop3s,imap,imaps,submission,submissions,sieve diff --git a/target/scripts/startup/setup-stack.sh b/target/scripts/startup/setup-stack.sh index d64548a9..a3ec3cf4 100644 --- a/target/scripts/startup/setup-stack.sh +++ b/target/scripts/startup/setup-stack.sh @@ -1149,10 +1149,13 @@ function _setup_user_patches function _setup_fail2ban { _log 'debug' 'Setting up Fail2Ban' + if [[ ${FAIL2BAN_BLOCKTYPE} != 'reject' ]] then echo -e '[Init]\nblocktype = drop' >/etc/fail2ban/action.d/nftables-common.local fi + + echo '[Definition]' >/etc/fail2ban/filter.d/custom.conf } function _setup_dnsbl_disable diff --git a/test/mail_fail2ban.bats b/test/mail_fail2ban.bats index a2393d3c..44768c68 100644 --- a/test/mail_fail2ban.bats +++ b/test/mail_fail2ban.bats @@ -116,32 +116,41 @@ function teardown_file() { refute_output "${FAIL_AUTH_MAILER_IP}" } -# -# debug -# +@test "checking fail2ban ban" { + run docker exec mail_fail2ban fail2ban ban 192.0.66.7 + assert_success + assert_output "Banned custom IP: 1" -@test "checking setup.sh: setup.sh debug fail2ban" { + run docker exec mail_fail2ban fail2ban + assert_success + assert_output --regexp "Banned in custom:.*192\.0\.66\.7" + + run docker exec mail_fail2ban fail2ban unban 192.0.66.7 + assert_success + assert_output --partial "Unbanned IP from custom: 1" +} + +@test "checking setup.sh: setup.sh fail2ban" { run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.4" run docker exec mail_fail2ban /bin/sh -c "fail2ban-client set dovecot banip 192.0.66.5" sleep 10 - run ./setup.sh -c mail_fail2ban debug fail2ban - 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 fail2ban + assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.4' + assert_output --regexp '^Banned in dovecot:.*192\.0\.66\.5' - run ./setup.sh -c mail_fail2ban debug fail2ban unban 192.0.66.4 + run ./setup.sh -c mail_fail2ban 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.*" + run ./setup.sh -c mail_fail2ban fail2ban + assert_output --regexp "^Banned in dovecot:.*192\.0\.66\.5" - run ./setup.sh -c mail_fail2ban debug fail2ban unban 192.0.66.5 + run ./setup.sh -c mail_fail2ban fail2ban unban 192.0.66.5 assert_output --partial "Unbanned IP from dovecot: 1" - run ./setup.sh -c mail_fail2ban debug fail2ban unban + run ./setup.sh -c mail_fail2ban fail2ban unban assert_output --partial "You need to specify an IP address: Run" }