Compare commits

..

No commits in common. "master" and "1.0.1" have entirely different histories.

203 changed files with 2018 additions and 5218 deletions

View file

@ -1,12 +0,0 @@
[codespell]
# THANKS - names
skip = .git,*.pdf,*.svg,venv,.codespellrc,.typos.toml,THANKS,*test*.log,logs
check-hidden = true
# Ignore all acronyms etc as plenty e.g. in fail2ban/server/strptime.py
# Try to identify incomplete words which are part of a regex, hence having [] at the beginning
# Ignore all urls as something with :// in it
# Ignore all lines with codespell-ignore in them for pragma annotation
ignore-regex = (\b([A-Z][A-Z][A-Z]+|gir\.st)\b)|\[[a-zA-Z]+\][a-z]+\b|[a-z]+://\S+|.*codespell-ignore.*
# some oddly named variables, some names, etc
# wee -- comes in regex etc for weeks
ignore-words-list = assertIn,theis,timere,alls,wee,wight,ans,re-use,pre-emptive

3
.github/FUNDING.yml vendored
View file

@ -1,5 +1,4 @@
# These are supported funding model platforms
github: [sebres]
custom: [https://paypal.me/sebres]
liberapay: sebres
custom: [paypal.me/sebres]

View file

@ -1,10 +1,12 @@
Before submitting your PR, please review the following checklist:
- [ ] **CHOOSE CORRECT BRANCH**: if filing a bugfix/enhancement
against certain release version, choose `0.9`, `0.10` or `0.11` branch,
for dev-edition use `master` branch
- [ ] **CONSIDER adding a unit test** if your PR resolves an issue
- [ ] **LIST ISSUES** this PR resolves or describe the approach in detail
- [ ] **LIST ISSUES** this PR resolves
- [ ] **MAKE SURE** this PR doesn't break existing tests
- [ ] **KEEP PR small** so it could be easily reviewed
- [ ] **KEEP PR small** so it could be easily reviewed.
- [ ] **AVOID** making unnecessary stylistic changes in unrelated code
- [ ] **ACCOMPANY** each new `failregex` for filter `X` with sample log lines
(and `# failJSON`) within `fail2ban/tests/files/logs/X` file
- [ ] **PROVIDE ChangeLog** entry describing the pull request
within `fail2ban/tests/files/logs/X` file

View file

@ -1,22 +0,0 @@
---
name: Codespell
on:
push:
branches: [master]
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Codespell
uses: codespell-project/actions-codespell@v2

View file

@ -19,18 +19,18 @@ jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: [3.8, 3.9, '3.10', '3.11', '3.12', '3.13', '3.14', '3.15.0-alpha.5', pypy3.11]
python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9, '3.10', '3.11.0-beta.3', pypy2, pypy3]
fail-fast: false
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v5
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
@ -51,35 +51,27 @@ jobs:
- name: Install dependencies
run: |
#if [[ "$F2B_PY" = 3 ]]; then python -m pip install --upgrade pip || echo "can't upgrade pip"; fi
if [[ "$F2B_PY" = 3 ]]; then python -m pip install --upgrade pip || echo "can't upgrade pip"; fi
if [[ "$F2B_PY" = 3 ]] && ! command -v 2to3x -v 2to3 > /dev/null; then
#pip install 2to3
sudo apt-get -y install 2to3
fi
#sudo apt-get -y install python${F2B_PY/2/}-pyinotify || echo 'inotify not available'
python -m pip install pyinotify || echo 'inotify not available'
sudo apt-get -y install sqlite3 || echo 'sqlite3 not available'
#sudo apt-get -y install python${F2B_PY/2/}-systemd || echo 'systemd not available'
sudo apt-get -y install libsystemd-dev || echo 'systemd dependencies seems to be unavailable'
python -m pip install systemd-python || echo 'systemd not available'
# readline if available as module:
#readline if available as module:
python -c 'import readline' 2> /dev/null || python -m pip install readline || echo 'readline not available'
# asyncore/asynchat:
if dpkg --compare-versions "$F2B_PYV" ge 3.12; then
#sudo apt-get -y install python${F2B_PY/2/}-setuptools || echo 'setuptools not unavailable'
python -m pip install setuptools || echo "can't install setuptools"
# don't install async* modules, we need to cover bundled-in libraries:
#python -m pip install pyasynchat || echo "can't install pyasynchat";
#python -m pip install pyasyncore || echo "can't install pyasyncore";
fi
# aiosmtpd in test_smtp (for 3.10+, no need to test it everywhere):
if dpkg --compare-versions "$F2B_PYV" ge 3.10; then
#sudo apt-get -y install python${F2B_PY/2/}-aiosmtpd || echo 'aiosmtpd not available'
python -m pip install aiosmtpd || echo 'aiosmtpd not available'
fi
- name: Before scripts
run: |
cd "$GITHUB_WORKSPACE"
# Manually execute 2to3 for now
if [[ "$F2B_PY" = 3 ]]; then echo "2to3 ..." && ./fail2ban-2to3; fi
_debug() { echo -n "$1 "; err=$("${@:2}" 2>&1) && echo 'OK' || echo -e "FAIL\n$err"; }
# (debug) output current preferred encoding:
echo 'Encodings:' $(python -c 'import locale, sys; from fail2ban.helpers import PREFER_ENC; print(PREFER_ENC, locale.getpreferredencoding(), (sys.stdout and sys.stdout.encoding))')
_debug 'Encodings:' python -c 'import locale, sys; from fail2ban.helpers import PREFER_ENC; print(PREFER_ENC, locale.getpreferredencoding(), (sys.stdout and sys.stdout.encoding))'
# (debug) backend availabilities:
echo 'Backends:'
_debug '- systemd:' python -c 'from fail2ban.server.filtersystemd import FilterSystemd'
@ -88,8 +80,14 @@ jobs:
- name: Test suite
run: |
#python setup.py test
python bin/fail2ban-testcases --verbosity=2
if [[ "$F2B_PY" = 2 ]]; then
python setup.py test
elif dpkg --compare-versions "$F2B_PYV" lt 3.10; then
python bin/fail2ban-testcases --verbosity=2
else
echo "Skip systemd backend since systemd-python module must be fixed for python >= v.3.10 in GHA ..."
python bin/fail2ban-testcases --verbosity=2 -i "[sS]ystemd|[jJ]ournal"
fi
#- name: Test suite (debug some systemd tests only)
#run: python bin/fail2ban-testcases --verbosity=2 "[sS]ystemd|[jJ]ournal"

View file

@ -1,32 +0,0 @@
name: Upload Package to PyPI
on:
workflow_dispatch:
release:
types: [created]
jobs:
pypi-publish:
name: Publish release to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/fail2ban
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip || echo "can't upgrade pip"
pip install setuptools wheel || echo "can't install/update setuptools or wheel"
- name: Build package
run: |
# python -m build ...
python setup.py sdist bdist_wheel
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

1
.gitignore vendored
View file

@ -10,4 +10,3 @@ htmlcov
__pycache__
.vagrant/
.idea/
.venv/

17
.project Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>fail2ban-unstable</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

82
.travis.yml Normal file
View file

@ -0,0 +1,82 @@
# vim ft=yaml
# travis-ci.org definition for Fail2Ban build
# https://travis-ci.org/fail2ban/fail2ban/
#os: linux
language: python
dist: xenial
matrix:
fast_finish: true
include:
- python: 2.7
#- python: pypy
- python: 3.4
- python: 3.5
- python: 3.6
- python: 3.7
- python: 3.8
- python: 3.9-dev
- python: pypy3.5
before_install:
- echo "running under $TRAVIS_PYTHON_VERSION"
- if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == pypy* && $TRAVIS_PYTHON_VERSION != pypy3* ]]; then export F2B_PY=2; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == pypy3* ]]; then export F2B_PY=3; fi
- echo "Set F2B_PY=$F2B_PY"
- travis_retry sudo apt-get update -qq
# Set this so sudo executes the correct python binary
# Anything not using sudo will already have the correct environment
- export VENV_BIN="$VIRTUAL_ENV/bin" && echo "VENV_BIN set to $VENV_BIN"
install:
# Install Python packages / dependencies
# coverage
- travis_retry pip install coverage
# coveralls (note coveralls doesn't support 2.6 now):
#- if [[ $TRAVIS_PYTHON_VERSION != 2.6* ]]; then F2B_COV=1; else F2B_COV=0; fi
- F2B_COV=1
- if [[ "$F2B_COV" = 1 ]]; then travis_retry pip install coveralls; fi
# codecov:
- travis_retry pip install codecov
# dnspython or dnspython3
- if [[ "$F2B_PY" = 2 ]]; then travis_retry pip install dnspython || echo 'not installed'; fi
- if [[ "$F2B_PY" = 3 ]]; then travis_retry pip install dnspython3 || echo 'not installed'; fi
# python systemd bindings:
- if [[ "$F2B_PY" = 2 ]]; then travis_retry sudo apt-get install -qq python-systemd || echo 'not installed'; fi
- if [[ "$F2B_PY" = 3 ]]; then travis_retry sudo apt-get install -qq python3-systemd || echo 'not installed'; fi
# gamin - install manually (not in PyPI) - travis-ci system Python is 2.7
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then (travis_retry sudo apt-get install -qq python-gamin && cp /usr/share/pyshared/gamin.py /usr/lib/pyshared/python2.7/_gamin.so $VIRTUAL_ENV/lib/python2.7/site-packages/) || echo 'not installed'; fi
# pyinotify
- travis_retry pip install pyinotify || echo 'not installed'
# Install helper tools
- sudo apt-get install shellcheck
before_script:
# Manually execute 2to3 for now
- if [[ "$F2B_PY" = 3 ]]; then ./fail2ban-2to3; fi
# (debug) output current preferred encoding:
- python -c 'import locale, sys; from fail2ban.helpers import PREFER_ENC; print(PREFER_ENC, locale.getpreferredencoding(), (sys.stdout and sys.stdout.encoding))'
script:
# Keep the legacy setup.py test approach of checking coverage for python2
- if [[ "$F2B_PY" = 2 ]]; then coverage run setup.py test; fi
# Coverage doesn't pick up setup.py test with python3, so run it directly (with same verbosity as from setup)
- if [[ "$F2B_PY" = 3 ]]; then coverage run bin/fail2ban-testcases --verbosity=2; fi
# Use $VENV_BIN (not python) or else sudo will always run the system's python (2.7)
- sudo $VENV_BIN/pip install .
# Doc files should get installed on Travis under Linux (some builds/python's seem to use another path segment)
- test -e /usr/share/doc/fail2ban/FILTERS && echo 'found' || echo 'not found'
# Test initd script
- shellcheck -s bash -e SC1090,SC1091 files/debian-initd
after_success:
- if [[ "$F2B_COV" = 1 ]]; then coveralls; fi
- codecov
# Might be worth looking into
#notifications:
# email: true
# irc:
# channels: "irc.freenode.org#fail2ban"
# template:
# - "%{repository}@%{branch}: %{message} (%{build_url})"
# on_success: change
# on_failure: change
# skip_join: true

View file

@ -1,35 +0,0 @@
[files]
extend-exclude = [
".git/",
".codespellrc",
"fail2ban/tests/files/logs/",
]
ignore-hidden = false
[default]
extend-ignore-re = [
"Christoph Theis",
"\\[[0-9a-f]{7,8}\\]",
"hash_[0-9a-f]{38}",
"\t[0-9.-]+[ A-Z]+",
"Erreur d'authentification",
"WebEMailExtrac",
"ssh2: RSA 14:ba:xx",
"\\[Cc\\]lient",
"\\[Gg\\]ot",
"\\[nN\\]ot",
"\\[Uu\\]nknown",
"\\[uU\\]ser",
"\\[Uu\\]\\(\\?:ser",
]
[default.extend-words]
"alls" = "alls"
"helo" = "helo"
[default.extend-identifiers]
"failManager2nd" = "failManager2nd"
"log2nd" = "log2nd"
"routeros" = "routeros"
"REFERERS" = "REFERERS"
"tre_search" = "tre_search"

228
ChangeLog
View file

@ -7,208 +7,6 @@
Fail2Ban: Changelog
===================
ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition
-----------
### Compatibility
* `action.d/iptables.conf` rewritten due to support of multiple chains (gh-3909), therefore user-level derivations
(action including iptables-based action) may become incompatible, e. g. some tags if used need to be replaced,
e. g. `<chain>` with `$chain` or `<_ipt_for_proto-iter>` with `<_ipt-iter>`;
* `filter.d/exim.conf` - several rules of mode `normal` moved to new mode `more`, because of too risky handling (see [gh-3940](https://github.com/fail2ban/fail2ban/pull/3940)),
to use it as before set `mode = more` for exim jail, but be aware of the consequences.
### Fixes
* fixes `systemd` bug with missing journal descriptor after rotation by reopening of journal if it is recognized as not alive (gh-3929)
* improve threaded clean-up of all filters, new thread functions `afterStop` (to force clean-up after stop) and `done`, invoking `afterStop` once
* ensure journal-reader is always closed (additional prevention against leaks and "too many open files"), thereby avoid sporadic segfault
in systemd module (see https://github.com/systemd/python-systemd/issues/143)
* fixes `systemd` causing "too many open files" error for a lot of journal files and large amount of systemd jails
(see new parameter `rotated` below, gh-3391);
* passing of arguments from jails to action or filter will affect conditional section too (gh-4069),
e. g. setting `blocktype="DROP"` via jail for action would now apply for IPv4 and IPv6 chains,
to submit different `blocktype` for IPv4 and IPv6 from jail, one can pass them like in this example:
`banaction = iptables-ipset[blocktype="...", blocktype?family=inet6="..."]`
* `jail.conf`:
- default banactions need to be specified in `paths-*.conf` (maintainer level) now
- since stock fail2ban includes `paths-debian.conf` by default, banactions are `nftables`
(can be overwritten in `jail.local` by user)
* `paths-common.conf`:
- changed default `mysql_log` path (default `logpath` of `mysqld-auth` jail without maintainer overrides, gh-3932)
* `paths-debian.conf`:
- default banactions are `nftables`
- sshd backend switched to `systemd` (gh-3292)
- postfix backend switched to `systemd` (gh-3527)
* `action.d/firewallcmd-ipset.conf`:
- rename `ipsettype` to `ipsetbackend` (gh-2620), parameter `ipsettype` will be used now to the real set type (gh-3760)
* `action.d/nftables.conf`:
- action fixed for SELinux without execmem permission, rewrite capturing with `grep -P` using `grep -E` or `sed`
(PCRE-JIT by `grep -P` may cause SELinux denial for execmem, see gh-4137)
* `action.d/xarf-login-attack.conf` - ignore errors or warnings in output of `dig` provided as comment (gh-4068)
* `filter.d/apache-badbots.conf`, `filter.d/apache-fakegooglebot.conf`:
- regexs rewritten more strict (removed catch-alls, etc);
- regexs fixed to match lines with vhost in accesslog (gh-1594)
* `filter.d/apache-noscript.conf` - consider new log-format with "AH02811: stderr from /..." (gh-3900)
* `filter.d/apache-overflows.conf` - consider AH10244: invalid URI path (gh-3778, gh-3900)
* `filter.d/asterisk.conf` - fixed RE for "no matching endpoint" with retry info (like `after X tries in Y ms`) at end,
loosening of end anchor (ignore any simple text tokens at end if no single quote found), gh-4037
* `filter.d/exim.conf`:
- several rules of mode `normal` moved to new mode `more`, because of too risky handling (gh-3940),
thereby mode `aggressive` is not affected, because it fully includes mode `more` now;
- mode `aggressive` extended to catch dropped by ACL failures, e.g. "ACL: Country is banned"
* `filter.d/freeswitch.conf` - bypass some new info in prefix before [WARNING] (changed default `_pref_line`),
FreeSWITCH log line prefix has changed in newer versions (gh-3143)
* `filter.d/lighttpd-auth.conf` - fixed regex (if failures generated by systemd-journal), bypass several prefixes now (gh-3955)
* `filter.d/postfix.conf`:
- consider CONNECT and other rejected commands as a valid `_pref` (gh-3800)
- default `_daemon` in prefix-line is loosened - can match everything starting with word postfix, like `postfix-example.com/smtpd` (gh-3297)
- add optional `NOQUEUE:` prefix to ddos regex (gh-4072)
- internal parameter `_pref` is renamed to `_cmd`, `_pref` matches now optional prefix like `NOQUEUE: ` etc
- modes `ddos` and `aggressive` extended to match `rate limit exceeded` for connection or message delivery request rates (gh-3265, gh-4073)
* `filter.d/dropbear.conf`:
- recognizes extra pid/timestamp if logged into stdout/journal, added `journalmatch` (gh-3597)
- failregex extended to match different format of "Exit before auth" message (gh-3791)
* `filter.d/recidive.conf` - restore possibility to set jail name in the filter, _jailname is positive now (gh-3769)
* `filter.d/roundcube-auth.conf` - improved RE better matching log format of roundcube version 1.4+ (gh-3816)
* `filter.d/sendmail-reject.conf`: (gh-4020)
- support `<F-MLFID>` for BSD-style logfiles
- add match for `User unknown` to default
- the relay field may not always have a hostname before the ip address
- mode `aggressive` enables match for `lost input channel` and `Cannot resolve PTR record`
* `filter.d/sshd.conf`:
- adapted to conform possible new daemon name sshd-session, since OpenSSH 9.8
several log messages will be tagged with as originating from a process named "sshd-session" rather than "sshd" (gh-3782)
- `ddos` and `aggressive` modes: regex extended for timeout before authentication (optional connection from part, gh-3907)
* `filter.d/vsftpd.conf` - fixed regex (if failures generated by systemd-journal, gh-3954)
* `filter.d/froxlor-auth.conf` - updated the regex to the new logging situation for froxlor and changed logpath in jail.conf (gh-4075).
### New Features and Enhancements
* backend `systemd` extended with new parameter `rotated` (default `false`, as prevention against "too many open files"),
that allows to monitor only actual journals and ignore now a lot of rotated files by default; so can drastically reduce
amount of used file descriptors, normally to 1 or 2 descriptors per jail (gh-3391)
* new jail option `skip_if_nologs` to ignore jail if no `logpath` matches found, fail2ban continue to start with warnings/errors,
thus other jails become running (gh-2756)
* implements automatic switch `backend = auto` to backend `systemd`, when the following is true (RFE gh-3768):
- no files matching `logpath` found for this jail;
- no `systemd_if_nologs = false` is specified for the jail (`true` by default);
- option `journalmatch` is set for the jail or its filter (otherwise it'd be too heavy to allow all auto-jails,
even if they have never been foreseen for journal monitoring);
(option `skip_if_nologs` will be ignored if we could switch backend to `systemd`)
* configuration `ignoreip` and fail2ban-client commands `addignoreip`/`delignoreip` extended with `file:...` syntax
to ignore IPs from file-ip-set (containing IP, subnet, dns/fqdn or raw strings); the file would be read lazy on demand,
by first ban (and automatically reloaded by update after small latency to avoid expensive stats check on every compare);
the entries inside the file can be separated by comma, space or new line with optional comments (text following chars
`#` or `;` after space or newline would be ignored up to next newline)
* `action.d/apprise.conf` - updated to support tagging and other command line args (gh-4141)
* `action.d/*-ipset.conf`:
- parameter `ipsettype` to set type of ipset, e. g. hash:ip, hash:net, etc (gh-3760)
* `action.d/iptables.conf` - action and few derivatives of it extended to handle multiple chains,
e. g. would also accept `chain = INPUT,FORWARD` (gh-3909)
* `action.d/nftables.conf` (gh-3291):
- new parameter `addr_options` for addr-set (default `flags interval\;`, allows to store CIDR or address ranges);
can be set to empty value to create simple addresses set (restore previous behavior).
* `action.d/firewallcmd-rich-*.conf` - fixed incorrect quoting, disabling port variable expansion
by substitution of rich rule (gh-3815)
* `filter.d/dovecot.conf`:
- add support for latest Dovecot 2.4 release (gh-4016)
- mode `aggressive` covered new variant for `no auth attempts in X secs` with `Login aborted` and `(no_auth_attempts)`
- mode `aggressive` extended to match `disconnected during TLS handshake` with `no application protocol` and `no shared cipher`
* `filter.d/nginx-http-auth.conf`:
- extended with `prefregex` to capture content of error only (bypass common prefix and suffix, like server, request, host, referrer);
- extended to match PAM authentication failures (gh-4071)
- modes `fallback` and `aggressive` extended to match more SSL failures by SSL_do_handshake or SSL_read (gh-4142, gh-2881)
* `filter.d/nginx-limit-req.conf` - extended to ban hosts failed by limit connection in ngx_http_limit_conn_module (gh-3674, gh-4047)
* `filter.d/proxmox.conf` - add support to Proxmox Web GUI (gh-2966)
* `filter.d/openvpn.conf` - new filter and jail for openvpn recognizing failed TLS handshakes (gh-2702)
* `filter.d/sendmail-reject.conf` - also recognize "Domain of sender address ... does not resolve" (gh-4035)
* `filter.d/vaultwarden.conf` - new filter and jail for Vaultwarden (gh-3979)
* `filter.d/xrdp.conf` - new filter for XRDP, an open source RDP server (gh-3254)
* `fail2ban-regex` extended with new option `-i` or `--invert` to output not-matched lines by `-o` or `--out` (gh-4001)
ver. 1.1.0 (2024/04/25) - object-found--norad-59479-cospar-2024-069a--altitude-36267km
-----------
### Compatibility
* the minimum supported python version is now 3.5, if you have previous python version
you can use the 0.11 or 1.0 version of fail2ban or upgrade python (or even build it from source).
### Fixes
* circumvent SEGFAULT in a python's socket module by getaddrinfo with disabled IPv6 (gh-3438)
* avoid sporadic error in pyinotify backend if pending file deleted in other thread, e. g. by flushing logs (gh-3635)
* `action.d/cloudflare-token.conf` - fixes gh-3479, url-encode args by unban
* `action.d/*ipset*`: make `maxelem` ipset option configurable through banaction arguments (gh-3564)
* `filter.d/apache-common.conf` - accepts remote besides client (gh-3622)
* `filter.d/mysqld-auth.conf` - matches also if no suffix in message (mariadb 10.3 log format, gh-3603)
* `filter.d/nginx-*.conf` - nginx error-log filters extended with support of journal format (gh-3646)
* `filter.d/postfix.conf`:
- "rejected" rule extended to match "Access denied" too (gh-3474)
- avoid double counting ('lost connection after AUTH' together with message 'disconnect ...', gh-3505)
- add Sender address rejected: Malformed DNS server reply (gh-3590)
- add to postfix syslog daemon format (gh-3690)
- change journalmatch postfix, allow sub-units with postfix@-.service (gh-3692)
* `filter.d/recidive.conf`: support for systemd-journal, conditional RE depending on logtype (for file or journal, gh-3693)
* `filter.d/slapd.conf` - filter rewritten for single-line processing, matches errored result without `text=...` (gh-3604)
### New Features and Enhancements
* supports python 3.12 and 3.13 (gh-3487)
* bundling async modules removed in python 3.12+ (fallback to local libraries pyasyncore/pyasynchat if import would miss them, gh-3487)
* `fail2ban-client` extended (gh-2975):
- `fail2ban-client status --all [flavor]` - returns status of fail2ban and all jails in usual form
- `fail2ban-client stats` - returns statistic in form of table (jail, backend, found and banned counts)
- `fail2ban-client statistic` or `fail2ban-client statistics` - same as `fail2ban-client stats` (aliases for stats)
- `fail2ban-client status --all stats` - (undocumented, flavor "stats") returns statistic of all jails in form of python dict
* `fail2ban-regex` extended to load settings from jail (by simple name it'd prefer jail to the filter now, gh-2655);
to load the settings from filter one could use:
```diff
- fail2ban-regex ... sshd ; # jail
+ fail2ban-regex ... sshd.conf ; # filter
# or:
+ fail2ban-regex ... filter.d/sshd ; # filter
```
* better auto-detection for IPv6 support (`allowipv6 = auto` by default), trying to check sysctl net.ipv6.conf.all.disable_ipv6
(value read from `/proc/sys/net/ipv6/conf/all/disable_ipv6`) if available, otherwise seeks over local IPv6 from network interfaces
if available for platform and uses DNS to find local IPv6 as a fallback only
* improve `ignoreself` by considering all local addresses from network interfaces additionally to IPs from hostnames (gh-3132)
* `action.d/mikrotik.conf` - new action for mikrotik routerOS, adds and removes entries from address lists on the router (gh-2860)
* `action.d/pf.conf` - pf action extended with support of `protocol=all` (gh-3503)
* `action.d/smtp.py` - added optional support for TLS connections via the `ssl` arg.
* `filter.d/dante.conf` - new filter for Dante SOCKS server (gh-2112)
* `filter.d/exim.conf`, `filter.d/exim-spam.conf`:
- messages are prefiltered by `prefregex` now
- filter can bypass additional timestamp or pid that may be logged via systemd-journal or syslog-ng (gh-3060)
- rewrite host line regex for all varied exim's log_selector states (gh-3263, gh-3701, gh-3702)
- fixed "dropped: too many ..." regex, also matching unrecognized commands now (gh-3502)
* `filter.d/named-refused.conf` - denied allows any reason in parenthesis as suffix (gh-3697)
* `filter.d/nginx-forbidden.conf` - new filter to ban forbidden locations, e. g. using `deny` directive (gh-2226)
* `filter.d/routeros-auth.conf` - new filter detecting failed login attempts in the log produced by MikroTik RouterOS
* `filter.d/sshd.conf`:
- avoid double counting for "maximum authentication attempts exceeded" (gh-3502)
- message "Disconnecting ... Too many authentication failures" is not a failure anymore
- mode `ddos`/`aggressive` extended to match new messages caused by port scanner, wrong payload on ssh port (gh-3486):
* message authentication code incorrect [preauth]
* connection corrupted [preauth]
* timeout before authentication
ver. 1.0.2 (2022/11/09) - finally-war-game-test-tape-not-a-nuclear-alarm
-----------
### Fixes
* backend `systemd`: code review and several fixes:
- wait only if it is necessary, e. g. in operational mode and if no more entries retrieved (end of journal);
- ensure we give enough time after possible rotation, vacuuming or adding/removing journal files,
and move cursor back and forth to avoid entering dead space
* `filter.d/named-refused.conf`:
- support BIND named log categories, gh-3388
- allow `info:` as possible error prefix too ("query (cache) denied" may occur as info)
* `filter.d/dovecot.conf`:
- fixes regression introduced in gh-3210: resolve extremely long search by repeated apply of non-greedy RE-part
with following branches (it may be extremely slow up to infinite search depending on message), gh-3370
- fixes regression and matches new format in aggressive mode too (amend to gh-3210)
### New Features and Enhancements
ver. 1.0.1 (2022/09/27) - energy-equals-mass-times-the-speed-of-light-squared
-----------
@ -236,7 +34,7 @@ ver. 1.0.1 (2022/09/27) - energy-equals-mass-times-the-speed-of-light-squared
* [stability] solves race condition with uncontrolled growth of failure list (jail with too many matches,
that did not cause ban), behavior changed to ban ASAP, gh-2945
* fixes search for the best datepattern - e. g. if line is too short, boundaries check for previously known
imprecise pattern may fail on incomplete lines (logging break-off, no flush, etc), gh-3020
unprecise pattern may fail on incomplete lines (logging break-off, no flush, etc), gh-3020
* [stability, performance] backend `systemd`:
- fixes error "local variable 'line' referenced before assignment", introduced in 55d7d9e2, gh-3097
- don't update database too often (every 10 ticks or ~ 10 seconds in production)
@ -574,7 +372,7 @@ filter = flt[logtype=short]
* `filter.d/znc-adminlog.conf`: new filter for ZNC (IRC bouncer); requires the adminlog module to be loaded
### Enhancements
* introduced new options: `dbmaxmatches` (fail2ban.conf) and `maxmatches` (jail.conf) to control
* introduced new options: `dbmaxmatches` (fail2ban.conf) and `maxmatches` (jail.conf) to contol
how many matches per ticket fail2ban can hold in memory and store in database (gh-2402, gh-2118);
* fail2ban.conf: introduced new section `[Thread]` and option `stacksize` to configure default size
of the stack for threads running in fail2ban (gh-2356), it could be set in `fail2ban.local` to
@ -684,7 +482,7 @@ ver. 0.10.3 (2018/04/04) - the-time-is-always-right-to-do-what-is-right
- fixed root login refused regex (optional port before preauth, gh-2080);
- avoid banning of legitimate users when pam_unix used in combination with other password method, so
bypass pam_unix failures if accepted available for this user gh-2070;
- amend to gh-1263 with better handling of multiple attempts (failures for different user-names recognized immediately);
- amend to gh-1263 with better handling of multiple attempts (failures for different user-names recognized immediatelly);
- mode `ddos` (and `aggressive`) extended to catch `Connection closed by ... [preauth]`, so in DDOS mode
it counts failure on closing connection within preauth-stage (gh-2085);
* `action.d/abuseipdb.conf`: fixed curl cypher errors and comment quote-issue (gh-2044, gh-2101);
@ -1014,7 +812,7 @@ ver. 0.10.0-alpha-1 (2016/07/14) - ipv6-support-etc
sane environment in error case of `actioncheck`.
* Reporting via abuseipdb.com:
- Bans can now be reported to abuseipdb
- Categories must be set in the config
- Catagories must be set in the config
- Relevant log lines included in report
### Enhancements
@ -1151,7 +949,7 @@ releases.
- Rewritten without end-anchor ($), because of potential vulnerability on very long URLs.
* filter.d/apache-badbots.conf - extended to recognize Jorgee Vulnerability Scanner (gh-1882)
* filter.d/asterisk.conf
- fixed failregex AMI Asterisk authentication failed (see gh-1302)
- fixed failregex AMI Asterisk authentification failed (see gh-1302)
- removed invalid (vulnerable) regex blocking IPs using forign data (from header "from")
thus not the IP-address that really originates the request (see gh-1927)
- fixed failregex for the SQL-injection attempts with single-quotes in connect-string (see gh-2011)
@ -1451,7 +1249,7 @@ ver. 0.9.3 (2015/08/01) - lets-all-stay-friends
* `filter.d/roundcube-auth.conf`
- Updated regex to work with 'errors' log (1.0.5 and 1.1.1)
- Added regex to work with 'userlogins' log
* `action.d/sendmail*.conf` - use LC_ALL (superseding LC_TIME) to override
* `action.d/sendmail*.conf` - use LC_ALL (superseeding LC_TIME) to override
locale on systems with customized LC_ALL
* performance fix: minimizes connection overhead, close socket only at
communication end (gh-1099)
@ -1621,7 +1419,7 @@ ver. 0.9.1 (2014/10/29) - better, faster, stronger
* Ignored IPs are no longer banned when being restored from persistent
database
* Manually unbanned IPs are now removed from persistent database, such they
won't be banned again when Fail2Ban is restarted
wont be banned again when Fail2Ban is restarted
* Pass "bantime" parameter to the actions in default jail's action
definition(s)
* `filters.d/sieve.conf` - fixed typo in _daemon. Thanks Jisoo Park
@ -1912,7 +1710,7 @@ those filters were used.
all platforms to ensure permissions are the same before and after a ban.
Closes gh-266. hostsdeny supports daemon_list now too.
* `action.d/bsd-ipfw` - action option unused. Change blocktype to port unreach
instead of deny for consistency.
instead of deny for consistancy.
* `filter.d/dovecot` - added to support different dovecot failure
"..disallowed plaintext auth". Closes Debian bug #709324
* `filter.d/roundcube-auth` - timezone offset can be positive or negative
@ -2102,7 +1900,7 @@ fail2ban-users mailing list and IRC.
### New Features
- Yaroslav Halchenko
* [9ba27353] Add support for `jail.d/{confilefile}` and `fail2ban.d/{configfile}`
to provide additional flexibility to system administrators. Thanks to
to provide additional flexibility to system adminstrators. Thanks to
beilber for the idea. Closes gh-114.
* [3ce53e87] Add exim filter.
- Erwan Ben Souiden
@ -2253,7 +2051,7 @@ ver. 0.8.7 (2012/07/31) - stable
* [47c03a2] files/nagios - spelling/grammar fixes
* [b083038] updated Free Software Foundation's address
* [9092a63] changed TLDs to invalid domains, in accordance with RFC 2606
* [642d9af,3282f86] reformatted printing of jail's name to be consistent
* [642d9af,3282f86] reformated printing of jail's name to be consistent
with init's info messages
* [3282f86] uniform use of capitalized Jail in the messages
- Leonardo Chiquitto
@ -2598,7 +2396,7 @@ ver. 0.6.1 (2006/03/16) - stable
- Fixed crash when time format does not match data
- Propagated patch from Debian to fix fail2ban search path addition to the path
search list: now it is added first. Thanks to Nick Craig-Wood
- Added SMTP authentication for mail notification. Thanks to Markus Hoffmann
- Added SMTP authentification for mail notification. Thanks to Markus Hoffmann
- Removed debug mode as it is confusing for people
- Added parsing of timestamp in TAI64N format (#1275325). Thanks to Mark
Edgington
@ -2631,7 +2429,7 @@ ver. 0.5.5 (2005/10/26) - beta
further adjusted by upstream author).
* Added -f command line parameter for [findtime].
* Added a cleanup of firewall rules on emergency shutdown when unknown
exception is caught.
exception is catched.
* Fail2ban should not crash now if a wrong file name is specified in config.
* reordered code a bit so that log targets are setup right after background
and then only loglevel (verbose, debug) is processed, so the warning could
@ -2720,7 +2518,7 @@ ver. 0.3.1 (2005/03/31) - beta
ver. 0.3.0 (2005/02/24) - beta
----------
- Re-writing of parts of the code in order to handle several log files with
- Re-writting of parts of the code in order to handle several log files with
different rules
- Removed `sshd.py` because it is no more needed
- Fixed a bug when exiting with IP in the ban list

30
FILTERS
View file

@ -129,7 +129,7 @@ Date/Time
---------
At the moment, Fail2Ban depends on log lines to have time stamps. That is why
before starting to develop failregex, check if your log line format is known to
before starting to develop failregex, check if your log line format known to
Fail2Ban. Copy the time component from the log line and append an IP address to
test with following command::
@ -232,24 +232,16 @@ the <> at the start so regex should be similar to '^<> error <HOST> is evil$' us
The following general rules apply to regular expressions:
* ensure regexes are anchored (e. g. start with a ^) and are as restrictive
as possible. E.g. do not use catch-alls .+ or .* if \d+ or [^"]* is sufficient.
Basically avoid the catch-alls where it is possible, especially non-greedy
catch-alls on RE with many branches or ambiguous matches;
* ensure regexes start with a ^ and are as restrictive as possible. E.g. do not
use .* if \d+ is sufficient;
* use functionality of Python regexes defined in the standard Python re library
https://docs.python.org/library/re.html;
* try to write regular expressions as efficient as possible. E.g. do not write
several REs for almost the same messages, just with A or B or C, if they can
be matched by single RE using | operator like ...(?:A|B|C)... and order them
by their frequency, so A before B and C, if A is more frequent or will match
faster;
* make regular expressions readable (as much as possible), but only if it is
justified. E.g. (?:...) represents a non-capturing regex and (...) is more
readable, but capturing groups make the RE a bit slower, thus (?:...) may be
more preferable.
http://docs.python.org/2/library/re.html;
* make regular expressions readable (as much as possible). E.g.
(?:...) represents a non-capturing regex but (...) is more readable, thus
preferred.
If you have only a basic knowledge of regular repressions we advise to read
https://docs.python.org/library/re.html first. It doesn't take long and would
http://docs.python.org/2/library/re.html first. It doesn't take long and would
remind you e.g. which characters you need to escape and which you don't.
Developing/testing a regex
@ -273,6 +265,10 @@ Take note of -l heavydebug / -l debug and -v as they might be very useful.
parts are constrained and different formats depending on configuration or
less common usages.
.. TIP::
For looking through source code - http://sourcecodebrowser.com/ . It has
call graphs and can browse different versions.
.. TIP::
Some applications log spaces at the end. If you are not sure add \s*$ as
the end part of the regex.
@ -313,8 +309,6 @@ So more specifically in the [filter] section in jail.conf:
Submit github pull request (See "Pull Requests" above) for
github.com/fail2ban/fail2ban containing your great work.
You may also consider https://github.com/fail2ban/fail2ban/wiki/Best-practice
Filter Security
===============

View file

@ -40,7 +40,6 @@ config/action.d/mail.conf
config/action.d/mail-whois-common.conf
config/action.d/mail-whois.conf
config/action.d/mail-whois-lines.conf
config/action.d/mikrotik.conf
config/action.d/mynetwatchman.conf
config/action.d/netscaler.conf
config/action.d/nftables-allports.conf
@ -91,7 +90,6 @@ config/filter.d/counter-strike.conf
config/filter.d/courier-auth.conf
config/filter.d/courier-smtp.conf
config/filter.d/cyrus-imap.conf
config/filter.d/dante.conf
config/filter.d/directadmin.conf
config/filter.d/domino-smtp.conf
config/filter.d/dovecot.conf
@ -123,8 +121,6 @@ config/filter.d/nagios.conf
config/filter.d/named-refused.conf
config/filter.d/nginx-bad-request.conf
config/filter.d/nginx-botsearch.conf
config/filter.d/nginx-error-common.conf
config/filter.d/nginx-forbidden.conf
config/filter.d/nginx-http-auth.conf
config/filter.d/nginx-limit-req.conf
config/filter.d/nsd.conf
@ -142,7 +138,6 @@ config/filter.d/pure-ftpd.conf
config/filter.d/qmail.conf
config/filter.d/recidive.conf
config/filter.d/roundcube-auth.conf
config/filter.d/routeros-auth.conf
config/filter.d/scanlogd.conf
config/filter.d/screensharingd.conf
config/filter.d/selinux-common.conf
@ -180,6 +175,7 @@ CONTRIBUTING.md
COPYING
.coveragerc
DEVELOP
fail2ban-2to3
fail2ban/client/actionreader.py
fail2ban/client/beautifier.py
fail2ban/client/configparserinc.py
@ -195,8 +191,6 @@ fail2ban/client/filterreader.py
fail2ban/client/__init__.py
fail2ban/client/jailreader.py
fail2ban/client/jailsreader.py
fail2ban/compat/asynchat.py
fail2ban/compat/asyncore.py
fail2ban/exceptions.py
fail2ban/helpers.py
fail2ban/__init__.py
@ -210,6 +204,7 @@ fail2ban/server/datedetector.py
fail2ban/server/datetemplate.py
fail2ban/server/failmanager.py
fail2ban/server/failregex.py
fail2ban/server/filtergamin.py
fail2ban/server/filterpoll.py
fail2ban/server/filter.py
fail2ban/server/filterpyinotify.py
@ -277,7 +272,7 @@ fail2ban/tests/files/config/apache-auth/noentry/.htaccess
fail2ban/tests/files/config/apache-auth/README
fail2ban/tests/files/database_v1.db
fail2ban/tests/files/database_v2.db
fail2ban/tests/files/filter.d/substitution.conf
fail2ban/tests/files/filter.d/substition.conf
fail2ban/tests/files/filter.d/testcase01.conf
fail2ban/tests/files/filter.d/testcase02.conf
fail2ban/tests/files/filter.d/testcase02.local
@ -305,7 +300,6 @@ fail2ban/tests/files/logs/counter-strike
fail2ban/tests/files/logs/courier-auth
fail2ban/tests/files/logs/courier-smtp
fail2ban/tests/files/logs/cyrus-imap
fail2ban/tests/files/logs/dante
fail2ban/tests/files/logs/directadmin
fail2ban/tests/files/logs/domino-smtp
fail2ban/tests/files/logs/dovecot
@ -335,7 +329,6 @@ fail2ban/tests/files/logs/nagios
fail2ban/tests/files/logs/named-refused
fail2ban/tests/files/logs/nginx-bad-request
fail2ban/tests/files/logs/nginx-botsearch
fail2ban/tests/files/logs/nginx-forbidden
fail2ban/tests/files/logs/nginx-http-auth
fail2ban/tests/files/logs/nginx-limit-req
fail2ban/tests/files/logs/nsd
@ -353,7 +346,6 @@ fail2ban/tests/files/logs/pure-ftpd
fail2ban/tests/files/logs/qmail
fail2ban/tests/files/logs/recidive
fail2ban/tests/files/logs/roundcube-auth
fail2ban/tests/files/logs/routeros-auth
fail2ban/tests/files/logs/scanlogd
fail2ban/tests/files/logs/screensharingd
fail2ban/tests/files/logs/selinux-ssh

View file

@ -2,7 +2,7 @@
/ _|__ _(_) |_ ) |__ __ _ _ _
| _/ _` | | |/ /| '_ \/ _` | ' \
|_| \__,_|_|_/___|_.__/\__,_|_||_|
v1.1.0.dev1 20??/??/??
v1.0.1.dev1 20??/??/??
## Fail2Ban: ban hosts that cause multiple authentication errors
@ -18,7 +18,7 @@ attempts, it cannot eliminate the risk presented by weak authentication.
Set up services to use only two factor, or public/private authentication
mechanisms if you really want to protect services.
<img src="http://www.worldipv6launch.org/wp-content/themes/ipv6/downloads/World_IPv6_launch_logo.svg" style="height:52pt;"/> | Since v0.10 fail2ban supports the matching of IPv6 addresses.
<img src="http://www.worldipv6launch.org/wp-content/themes/ipv6/downloads/World_IPv6_launch_logo.svg" height="52pt"/> | Since v0.10 fail2ban supports the matching of IPv6 addresses.
------|------
This README is a quick introduction to Fail2Ban. More documentation, FAQ, and HOWTOs
@ -29,30 +29,29 @@ and the website: https://www.fail2ban.org
Installation:
-------------
Fail2Ban is likely already packaged for your Linux distribution and [can be installed with a simple command](https://github.com/fail2ban/fail2ban/wiki/How-to-install-fail2ban-packages).
If your distribution is not listed, you can install from GitHub:
**It is possible that Fail2Ban is already packaged for your distribution. In
this case, you should use that instead.**
Required:
- [Python >= 3.5](https://www.python.org) or [PyPy3](https://pypy.org)
- python-setuptools (or python3-setuptools) for installation from source
- [Python2 >= 2.7 or Python >= 3.2](https://www.python.org) or [PyPy](https://pypy.org)
- python-setuptools, python-distutils or python3-setuptools for installation from source
Optional:
- [pyinotify >= 0.8.3](https://github.com/seb-m/pyinotify), may require:
* Linux >= 2.6.13
- [gamin >= 0.0.21](http://www.gnome.org/~veillard/gamin)
- [systemd >= 204](http://www.freedesktop.org/wiki/Software/systemd) and python bindings:
* [python-systemd package](https://www.freedesktop.org/software/systemd/python-systemd/index.html)
- [dnspython](http://www.dnspython.org/)
- [pyasyncore](https://pypi.org/project/pyasyncore/) and [pyasynchat](https://pypi.org/project/pyasynchat/) (normally bundled-in within fail2ban, for python 3.12+ only)
To install:
tar xvfj fail2ban-master.tar.bz2
cd fail2ban-master
tar xvfj fail2ban-1.0.1.tar.bz2
cd fail2ban-1.0.1
sudo python setup.py install
Alternatively, you can clone the source from GitHub to a directory of your choice, and do the install from there. Pick the correct branch, for example, master or 0.11
Alternatively, you can clone the source from GitHub to a directory of Your choice, and do the install from there. Pick the correct branch, for example, master or 0.11
git clone https://github.com/fail2ban/fail2ban.git
cd fail2ban
@ -91,7 +90,11 @@ fail2ban(1) and jail.conf(5) manpages for further references.
Code status:
------------
* [![CI](https://github.com/fail2ban/fail2ban/actions/workflows/main.yml/badge.svg)](https://github.com/fail2ban/fail2ban/actions/workflows/main.yml)
* travis-ci.org: [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.svg?branch=master)](https://travis-ci.org/fail2ban/fail2ban?branch=master) / [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.svg?branch=0.11)](https://travis-ci.org/fail2ban/fail2ban?branch=0.11) (0.11 branch) / [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.svg?branch=0.10)](https://travis-ci.org/fail2ban/fail2ban?branch=0.10) (0.10 branch)
* coveralls.io: [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.svg?branch=master)](https://coveralls.io/github/fail2ban/fail2ban?branch=master) / [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.svg?branch=0.11)](https://coveralls.io/github/fail2ban/fail2ban?branch=0.11) (0.11 branch) / [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.svg?branch=0.10)](https://coveralls.io/github/fail2ban/fail2ban?branch=0.10) / (0.10 branch)
* codecov.io: [![codecov.io](https://codecov.io/gh/fail2ban/fail2ban/coverage.svg?branch=master)](https://codecov.io/gh/fail2ban/fail2ban/branch/master) / [![codecov.io](https://codecov.io/gh/fail2ban/fail2ban/coverage.svg?branch=0.11)](https://codecov.io/gh/fail2ban/fail2ban/branch/0.11) (0.11 branch) / [![codecov.io](https://codecov.io/gh/fail2ban/fail2ban/coverage.svg?branch=0.10)](https://codecov.io/gh/fail2ban/fail2ban/branch/0.10) (0.10 branch)
Contact:
--------

View file

@ -13,7 +13,7 @@ Preparation
* Check distribution patches and see if they can be included
* https://apps.fedoraproject.org/packages/fail2ban/sources
* https://gitweb.gentoo.org/repo/gentoo.git/tree/net-analyzer/fail2ban
* http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-analyzer/fail2ban/
* http://svnweb.freebsd.org/ports/head/security/py-fail2ban/
* https://build.opensuse.org/package/show?package=fail2ban&project=openSUSE%3AFactory
* http://sophie.zarb.org/sources/fail2ban (Mageia)
@ -49,7 +49,7 @@ Preparation
ad-hoc bash script to run in a clean clone:
find -type f | grep -v -e '\.git' -e '/doc/' -e MANIFEST | sed -e 's,^\./,,g' | while read f; do grep -ne "^$f\$" MANIFEST >/dev/null || echo "$f" ; done
find -type f | grep -v -e '\.git' -e '/doc/' -e '\.travis' -e MANIFEST | sed -e 's,^\./,,g' | while read f; do grep -ne "^$f\$" MANIFEST >/dev/null || echo "$f" ; done
or an alternative for comparison with previous release
@ -115,7 +115,7 @@ Pre Release
* Arch Linux:
* https://www.archlinux.org/packages/extra/any/fail2ban/
* https://www.archlinux.org/packages/community/any/fail2ban/
* Debian: Yaroslav Halchenko <debian@onerussian.com>
@ -134,7 +134,7 @@ Pre Release
* Gentoo: netmon@gentoo.org
* https://gitweb.gentoo.org/repo/gentoo.git/tree/net-analyzer/fail2ban/metadata.xml
* http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-analyzer/fail2ban/metadata.xml?view=markup
* https://bugs.gentoo.org/buglist.cgi?quicksearch=fail2ban
* openSUSE: Stephan Kulow <coolo@suse.com>

1
THANKS
View file

@ -22,7 +22,6 @@ Andrey G. Grozin
Andy Fragen
Arturo 'Buanzo' Busleiman
Axel Thimm
Balazs Mateffy
Bas van den Dikkenberg
Beau Raines
Bill Heaton

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
#

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: t -*-
# vi: set ft=python sts=4 ts=4 sw=4 noet :
"""Script to run Fail2Ban tests battery

View file

@ -80,7 +80,7 @@ actioncheck =
# use my (Shaun's) helper PHP script by commenting out the first #actionban
# line below, uncommenting the second one, and pointing the URL at
# wherever you install the helper script. For the PHP helper script, see
# <https://github.com/parseword/fail2ban-abuseipdb/>
# <https://wiki.shaunc.com/wikka.php?wakka=ReportingToAbuseIPDBWithFail2Ban>
#
# Tags: See jail.conf(5) man page
# Values: CMD

View file

@ -2,61 +2,7 @@
#
# Author: Chris Caron <lead2gold@gmail.com>
#
# ban & send a notification to one or more of the 120+ services supported by
# Apprise.
# - See https://appriseit.com/services/ for details on what is supported.
# - See https://appriseit.com/getting-started/configuration/ for information
# on how to prepare an Apprise configuration file.
#
# This plugin requires that Apprise is installed on your system:
#
# pip install apprise
#
# Breakdown:
# config provide a path to an Apprise Config file
# The default is /etc/fail2ban/apprise.conf if not provided.
# Both YAML and TEXT formats are supported.
# You can even point your configuration to an Apprise API
# endpoint.
#
# args Provide additional arguments to support the Apprise CLI.
# See https://appriseit.com/cli/usage/ for additional options.
# the --tag (-g) is incredibly useful for integrating with
# fail2ban as you can exclusively have it target specific
# notifications this way.
#
# Config Example #1: Simple
# 1. Create a /etc/fail2ban/apprise.conf
# ```
# # /etc/fail2ban/apprise.conf
# fail2ban=mailto://user:pass@example.com
# ```
# 2 In jail:
# ```
# action = %(action_)s
# apprise[args='--tag fail2ban']
# ```
#
# Config Example #2: YAML an Custom path
# 1. Create a /etc/fail2ban/apprise.conf
# ```
# # /etc/fail2ban/apprise.yaml
# urls:
# - mailto://user:pass@example.com:
# tags: f2b
# ```
# 2. In jail:
# ```
# action = %(action_)s
# apprise[config='/etc/fail2ban/apprise.yaml',args='--tag f2b']
# ```
#
# Config Example #3: Apprise API
# 1. In jail:
# ```
# action = %(action_)s
# apprise[config='http://apprise.example.ca/get/mykey',args='-g f2b']
# ```
[Definition]
@ -64,7 +10,7 @@
# Notes.: command executed once at the start of Fail2Ban.
# Values: CMD
#
actionstart = printf %%b "The jail <name> has been started successfully." | <apprise> -t "[Fail2Ban] <name>: started on `uname -n`"
actionstart = printf %%b "The jail <name> as been started successfully." | <apprise> -t "[Fail2Ban] <name>: started on `uname -n`"
# Option: actionstop
# Notes.: command executed once at the end of Fail2Ban
@ -99,9 +45,5 @@ actionunban =
# Define location of the default apprise configuration file to use
#
config = /etc/fail2ban/apprise.conf
# Support passing in arguments for example: "-g fail2ban"
#
args =
#
apprise = apprise -c "<config>" <args>
apprise = apprise -c "<config>"

View file

@ -30,9 +30,6 @@
[Definition]
# bypass reporting of restored (already reported) tickets:
norestored = 1
# Option: actionstart
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
# Values: CMD

View file

@ -80,7 +80,7 @@ block = ip
# Option: blocktype
# Notes.: How to block the traffic. Use a action from man 5 ipfw
# Common values: deny, unreach port, reset
# ACTION definition at the top of man ipfw for allowed values.
# ACTION defination at the top of man ipfw for allowed values.
# Values: STRING
#
blocktype = unreach port

View file

@ -50,12 +50,11 @@ actionban = curl -s -X POST "<_cf_api_url>" \
# <time> unix timestamp of the ban time
# Values: CMD
#
actionunban = id=$(curl -s -G -X GET "<_cf_api_url>" \
--data-urlencode "mode=<cfmode>" --data-urlencode "notes=<notes>" --data-urlencode "configuration.target=<cftarget>" --data-urlencode "configuration.value=<ip>" \
<_cf_api_prms> \
| awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'id'\042/){print $(i+1)}}}' \
| tr -d ' "' \
| head -n 1)
actionunban = id=$(curl -s -X GET "<_cf_api_url>?mode=<cfmode>&notes=<notes>&configuration.target=<cftarget>&configuration.value=<ip>" \
<_cf_api_prms> \
| awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'id'\042/){print $(i+1)}}}' \
| tr -d ' "' \
| head -n 1)
if [ -z "$id" ]; then echo "<name>: id for <ip> cannot be found using target <cftarget>"; exit 0; fi; \
curl -s -X DELETE "<_cf_api_url>/$id" \
<_cf_api_prms> \
@ -68,7 +67,7 @@ _cf_api_prms = -H "Authorization: Bearer <cftoken>" -H "Content-Type: applicatio
# Declare your Cloudflare Authorization Bearer Token in the [DEFAULT] section of your jail.local file.
# The Cloudflare <ZONE_ID> of the domain you want to manage.
# The Cloudflare <ZONE_ID> of hte domain you want to manage.
#
# cfzone =

View file

@ -16,7 +16,7 @@
#
# Please do not use this action unless you are certain that fail2ban
# does not result in "false positives" for your deployment. False
# positive reports could serve a misfavor to the original cause by
# positive reports could serve a mis-favor to the original cause by
# flooding corresponding contact addresses, and complicating the work
# of administration personnel responsible for handling (verified) legit
# complains.

View file

@ -1,26 +0,0 @@
# Fail2Ban configuration file
# http://configserver.com/cp/csf.html
#
# Note: CSF doesn't play nicely with other actions. It has been observed to
# remove bans created by other iptables based actions. If you are going to use
# this action, use it for all of your jails.
#
# DON'T MIX CSF and other IPTABLES based actions
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = csf --deny <ip> "banned by Fail2Ban <name>"
actionunban = csf --denyrm <ip>
[Init]
# Name used in CSF configuration
#
name = default
# DEV NOTES:
#
# based on apf.conf by Mark McKinstry

View file

@ -18,36 +18,36 @@ before = firewallcmd-common.conf
[Definition]
actionstart = <ipsbackend_<ipsetbackend>/actionstart>
actionstart = <ipstype_<ipsettype>/actionstart>
firewall-cmd --direct --add-rule <family> filter <chain> 0 <actiontype> -m set --match-set <ipmset> src -j <blocktype>
actionflush = <ipsbackend_<ipsetbackend>/actionflush>
actionflush = <ipstype_<ipsettype>/actionflush>
actionstop = firewall-cmd --direct --remove-rule <family> filter <chain> 0 <actiontype> -m set --match-set <ipmset> src -j <blocktype>
<actionflush>
<ipsbackend_<ipsetbackend>/actionstop>
<ipstype_<ipsettype>/actionstop>
actionban = <ipsbackend_<ipsetbackend>/actionban>
actionban = <ipstype_<ipsettype>/actionban>
# actionprolong = %(actionban)s
actionunban = <ipsbackend_<ipsetbackend>/actionunban>
actionunban = <ipstype_<ipsettype>/actionunban>
[ipsbackend_ipset]
[ipstype_ipset]
actionstart = ipset -exist create <ipmset> <ipsettype> timeout <default-ipsettime> maxelem <maxelem> <familyopt>
actionstart = ipset -exist create <ipmset> hash:ip timeout <default-ipsettime> <familyopt>
actionflush = ipset flush <ipmset>
actionstop = ipset destroy <ipmset> 2>/dev/null || { sleep 1; ipset destroy <ipmset>; }
actionstop = ipset destroy <ipmset>
actionban = ipset -exist add <ipmset> <ip> timeout <ipsettime>
actionunban = ipset -exist del <ipmset> <ip>
[ipsbackend_firewalld]
[ipstype_firewalld]
actionstart = firewall-cmd --direct --new-ipset=<ipmset> --type=<ipsettype> --option=timeout=<default-ipsettime> --option=maxelem=<maxelem> <firewalld_familyopt>
actionstart = firewall-cmd --direct --new-ipset=<ipmset> --type=hash:ip --option=timeout=<default-ipsettime> <firewalld_familyopt>
# TODO: there doesn't seem to be an explicit way to invoke the ipset flush function using firewall-cmd
actionflush =
@ -60,11 +60,6 @@ actionunban = firewall-cmd --ipset=<ipmset> --remove-entry=<ip>
[Init]
# Option: ipsettype
# Notes: specifies type of set, see `man --pager='less -p "^SET TYPES"' ipset` for details
# Values: hash:ip, hash:net, etc... Default: hash:ip
ipsettype = hash:ip
# Option: chain
# Notes specifies the iptables chain to which the fail2ban rules should be
# added
@ -82,21 +77,15 @@ default-ipsettime = 0
# Values: [ NUM ] Default: 0 (managed by fail2ban by unban)
ipsettime = 0
# Option: maxelem
# Notes: maximal number of elements which can be stored in the ipset
# You may want to increase this for long-duration/high-volume jails
# Values: [ NUM ] Default: 65536
maxelem = 65536
# expression to calculate timeout from bantime, example:
# expresion to caclulate timeout from bantime, example:
# banaction = %(known/banaction)s[ipsettime='<timeout-bantime>']
timeout-bantime = $([ "<bantime>" -le 2147483 ] && echo "<bantime>" || echo 0)
# Option: ipsetbackend
# Notes.: defines the backend of ipset used for match-set (firewalld or ipset)
# Option: ipsettype
# Notes.: defines type of ipset used for match-set (firewalld or ipset)
# Values: firewalld or ipset
# Default: ipset
ipsetbackend = ipset
ipsettype = ipset
# Option: actiontype
# Notes.: defines additions to the blocking rule
@ -129,4 +118,4 @@ firewalld_familyopt = --option=family=inet6
# DEV NOTES:
#
# Author: Edgar Hoch, Daniel Black, Sergey Brester and Mihail Politaev
# firewallcmd-new / iptables-ipset-proto6 combined for maximum goodness
# firewallcmd-new / iptables-ipset-proto6 combined for maximium goodness

View file

@ -35,7 +35,7 @@ actioncheck =
#
# Because rich rules can only handle single or a range of ports we must split ports and execute the command for each port. Ports can be single and ranges separated by a comma or space for an example: http, https, 22-60, 18 smtp
fwcmd_rich_rule = rule family=\"<family>\" source address=\"<ip>\" port port=\"$p\" protocol=\"<protocol>\" %(rich-suffix)s
fwcmd_rich_rule = rule family='<family>' source address='<ip>' port port='$p' protocol='<protocol>' %(rich-suffix)s
actionban = ports="<port>"; for p in $(echo $ports | tr ", " " "); do firewall-cmd --add-rich-rule="%(fwcmd_rich_rule)s"; done

View file

@ -27,7 +27,7 @@ before = iptables.conf
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
# Values: CMD
#
actionstart = ipset --create f2b-<name> maxelem <maxelem> iphash
actionstart = ipset --create f2b-<name> iphash
<_ipt_add_rules>
@ -61,14 +61,6 @@ actionban = ipset --test f2b-<name> <ip> || ipset --add f2b-<name> <ip>
#
actionunban = ipset --test f2b-<name> <ip> && ipset --del f2b-<name> <ip>
# Several capabilities used internally:
# Several capabilities used internaly:
rule-jump = -m set --match-set f2b-<name> src -j <blocktype>
[Init]
# Option: maxelem
# Notes: maximal number of elements which can be stored in the ipset
# You may want to increase this for long-duration/high-volume jails
# Values: [ NUM ] Default: 65536
maxelem = 65536

View file

@ -24,7 +24,7 @@ before = iptables.conf
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
# Values: CMD
#
actionstart = ipset -exist create <ipmset> <ipsettype> timeout <default-ipsettime> maxelem <maxelem> <familyopt>
actionstart = ipset -exist create <ipmset> hash:ip timeout <default-ipsettime> <familyopt>
<_ipt_add_rules>
# Option: actionflush
@ -39,7 +39,7 @@ actionflush = ipset flush <ipmset>
#
actionstop = <_ipt_del_rules>
<actionflush>
ipset destroy <ipmset> 2>/dev/null || { sleep 1; ipset destroy <ipmset>; }
ipset destroy <ipmset>
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the
@ -59,18 +59,13 @@ actionban = ipset -exist add <ipmset> <ip> timeout <ipsettime>
#
actionunban = ipset -exist del <ipmset> <ip>
# Several capabilities used internally:
# Several capabilities used internaly:
rule-jump = -m set --match-set <ipmset> src -j <blocktype>
[Init]
# Option: ipsettype
# Notes: specifies type of set, see `man --pager='less -p "^SET TYPES"' ipset` for details
# Values: hash:ip, hash:net, etc... Default: hash:ip
ipsettype = hash:ip
# Option: default-ipsettime
# Notes: specifies default timeout in seconds (handled default ipset timeout only)
# Values: [ NUM ] Default: 0 (no timeout, managed by fail2ban by unban)
@ -81,13 +76,7 @@ default-ipsettime = 0
# Values: [ NUM ] Default: 0 (managed by fail2ban by unban)
ipsettime = 0
# Option: maxelem
# Notes: maximal number of elements which can be stored in the ipset
# You may want to increase this for long-duration/high-volume jails
# Values: [ NUM ] Default: 65536
maxelem = 65536
# expression to calculate timeout from bantime, example:
# expresion to caclulate timeout from bantime, example:
# banaction = %(known/banaction)s[ipsettime='<timeout-bantime>']
timeout-bantime = $([ "<bantime>" -le 2147483 ] && echo "<bantime>" || echo 0)

View file

@ -12,9 +12,8 @@ before = iptables.conf
[Definition]
_ipt_chain_rule = -m recent --update --seconds 3600 --name <iptname> -j <blocktype>
_ipt_check_rule = <iptables> -C <chain> %(_ipt_chain_rule)s
_ipt-iter =
_ipt-done =
_ipt_for_proto-iter =
_ipt_for_proto-done =
# Option: actionstart
# Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
@ -61,7 +60,7 @@ actionstop = echo / > /proc/net/xt_recent/<iptname>
# Notes.: command executed as invariant check (error by ban)
# Values: CMD
#
actioncheck = { %(_ipt_check_rule)s >/dev/null 2>&1; } && test -e /proc/net/xt_recent/<iptname>
actioncheck = { <iptables> -C <chain> %(_ipt_chain_rule)s; } && test -e /proc/net/xt_recent/<iptname>
# Option: actionban
# Notes.: command executed when banning an IP. Take care that the

View file

@ -62,25 +62,25 @@ pre-rule =
rule-jump = -j <_ipt_rule_target>
# Several capabilities used internally:
# Several capabilities used internaly:
_ipt-iter = for chain in $(echo '<chain>' | sed 's/,/ /g'); do for proto in $(echo '<protocol>' | sed 's/,/ /g'); do
_ipt-done = done; done
_ipt_for_proto-iter = for proto in $(echo '<protocol>' | sed 's/,/ /g'); do
_ipt_for_proto-done = done
_ipt_add_rules = <_ipt-iter>
{ %(_ipt_check_rule)s >/dev/null 2>&1; } || { <iptables> -I $chain %(_ipt_chain_rule)s; }
<_ipt-done>
_ipt_add_rules = <_ipt_for_proto-iter>
{ %(_ipt_check_rule)s >/dev/null 2>&1; } || { <iptables> -I <chain> %(_ipt_chain_rule)s; }
<_ipt_for_proto-done>
_ipt_del_rules = <_ipt-iter>
<iptables> -D $chain %(_ipt_chain_rule)s
<_ipt-done>
_ipt_del_rules = <_ipt_for_proto-iter>
<iptables> -D <chain> %(_ipt_chain_rule)s
<_ipt_for_proto-done>
_ipt_check_rules = <_ipt-iter>
_ipt_check_rules = <_ipt_for_proto-iter>
%(_ipt_check_rule)s
<_ipt-done>
<_ipt_for_proto-done>
_ipt_chain_rule = <pre-rule><ipt_<type>/_chain_rule>
_ipt_check_rule = <iptables> -C $chain %(_ipt_chain_rule)s
_ipt_check_rule = <iptables> -C <chain> %(_ipt_chain_rule)s
_ipt_rule_target = f2b-<name>
[ipt_oneport]
@ -99,9 +99,8 @@ _chain_rule = -p $proto <rule-jump>
[Init]
# Option: chain
# Notes specifies the iptables chains to which the Fail2Ban rules should be
# added. May be a single chain (e.g. INPUT) or a comma separated list
# (e.g. INPUT, FORWARD)
# Notes specifies the iptables chain to which the Fail2Ban rules should be
# added
# Values: STRING Default: INPUT
chain = INPUT
@ -136,7 +135,7 @@ returntype = RETURN
# Option: lockingopt
# Notes.: Option was introduced to iptables to prevent multiple instances from
# running concurrently and causing erratic behavior. -w was introduced
# running concurrently and causing irratic behavior. -w was introduced
# in iptables 1.4.20, so might be absent on older systems
# See https://github.com/fail2ban/fail2ban/issues/1122
# Values: STRING

View file

@ -15,7 +15,7 @@
# Reporting an IP is a serious action. Make sure that it is legit.
# Consider using this action only for:
# * IP that has been banned more than once
# * High max retry to avoid user mistyping password
# * High max retry to avoid user mis-typing password
# * Filters that are unlikely to be human error
#
# Example:
@ -47,7 +47,7 @@
# BadBot 256 Bad bot that is not honoring robots.txt or just flooding with too many requests, etc
# Compromised 512 The ip has been taken over by malware or botnet
# Phishing 1024 The ip is involved in phishing or spoofing
# Iot 2048 The ip has targeted an iot (Internet of Things) device
# Iot 2048 The ip has targetted an iot (Internet of Things) device
# PortScan 4096 Port scan
# See https://ipthreat.net/bulkreportformat for more information
# ```

View file

@ -1,84 +0,0 @@
# Fail2Ban configuration file
#
# Mikrotik routerOS action to add/remove address-list entries
#
# Author: Duncan Bellamy <dunk@denkimushi.com>
# based on forum.mikrotik.com post by pakjebakmeel
#
# in the instructions:
# (10.0.0.1 is ip of mikrotik router)
# (10.0.0.2 is ip of fail2ban machine)
#
# on fail2ban machine:
# sudo mkdir /var/lib/fail2ban/ssh
# sudo chmod 700 /var/lib/fail2ban/ssh
# sudo ssh-keygen -N "" -f /var/lib/fail2ban/ssh/fail2ban_id_rsa
# sudo scp /var/lib/fail2ban/ssh/fail2ban_id_rsa.pub admin@10.0.0.1:/
# ssh admin@10.0.0.1
#
# on mikrotik router:
# /user add name=miki-f2b group=write address=10.0.0.2 password=""
# /user ssh-keys import public-key-file=fail2ban_id_rsa.pub user=miki-f2b
# /quit
#
# on fail2ban machine:
# (check password login fails)
# ssh miki-f2b@10.0.0.1
# (check private key works)
# sudo ssh -i /var/lib/fail2ban/ssh/fail2ban_id_rsa miki-f2b@10.0.0.1
#
# Then create rules on mikrorik router that use address
# list(s) maintained by fail2ban eg in the forward chain
# drop from address list, or in the forward chain drop
# from address list to server
#
# example extract from jail.local overriding some defaults
# action = mikrotik[keyfile="%(mkeyfile)s", user="%(muser)s", host="%(mhost)s", list="%(mlist)s"]
#
# ignoreip = 127.0.0.1/8 192.168.0.0/24
# mkeyfile = /etc/fail2ban/ssh/mykey_id_rsa
# muser = myuser
# mhost = 192.168.0.1
# mlist = BAD LIST
[Definition]
actionstart =
actionstop = %(actionflush)s
actionflush = %(command)s "/ip firewall address-list remove [find list=\"%(list)s\" comment~\"%(startcomment)s-*\"]"
actioncheck =
actionban = %(command)s "/ip firewall address-list add list=\"%(list)s\" address=<ip> comment=%(comment)s"
actionunban = %(command)s "/ip firewall address-list remove [find list=\"%(list)s\" comment=%(comment)s]"
command = ssh -l %(user)s -p%(port)s -i %(keyfile)s %(host)s
# Option: user
# Notes.: username to use when connecting to routerOS
user =
# Option: port
# Notes.: port to use when connecting to routerOS
port = 22
# Option: keyfile
# Notes.: ssh private key to use for connecting to routerOS
keyfile =
# Option: host
# Notes.: hostname or ip of router
host =
# Option: list
# Notes.: name of "address-list" to use on router
list = Fail2Ban
# Option: startcomment
# Notes.: used as a prefix to all comments, and used to match for flushing rules
startcomment = f2b-<name>
# Option: comment
# Notes.: comment to use on routerOS (must be unique as used for ip address removal)
comment = %(startcomment)s-<ip>
[Init]
name="%(__name__)s"

View file

@ -5,7 +5,7 @@
# The script will add offender IPs to a dataset on netscaler, the dataset can then be used to block the IPs at a cs/vserver or global level
# This dataset is then used to block IPs using responder policies on the netscaler.
#
# The script assumes using HTTPS with insecure certificate to access the netscaler,
# The script assumes using HTTPS with unsecure certificate to access the netscaler,
# if you have a valid certificate installed remove the -k from the curl lines, or if you want http change it accordingly (and remove the -k)
#
# This action depends on curl

View file

@ -44,7 +44,7 @@ match = <rule_match-<type>>
#
rule_stat = %(match)s <addr_family> saddr @<addr_set> <blocktype>
# optional iterator over protocol's:
# optional interator over protocol's:
_nft_for_proto-custom-iter =
_nft_for_proto-custom-done =
_nft_for_proto-allports-iter =
@ -53,9 +53,9 @@ _nft_for_proto-multiport-iter = for proto in $(echo '<protocol>' | sed 's/,/ /g'
_nft_for_proto-multiport-done = done
_nft_list = <nftables> -a list chain <table_family> <table> <chain>
_nft_get_handle_id = sed -nE 's/.*@<addr_set>\s+.*\s+\#\s*(handle\s+[0-9]+)$/\1/p'
_nft_get_handle_id = grep -oP '@<addr_set>\s+.*\s+\Khandle\s+(\d+)$'
_nft_add_set = <nftables> add set <table_family> <table> <addr_set> \{ type <addr_type>\;<addr_options> \}
_nft_add_set = <nftables> add set <table_family> <table> <addr_set> \{ type <addr_type>\; \}
<_nft_for_proto-<type>-iter>
<nftables> add rule <table_family> <table> <chain> %(rule_stat)s
<_nft_for_proto-<type>-done>
@ -67,7 +67,7 @@ _nft_del_set = { %(_nft_list)s | %(_nft_get_handle_id)s; } | while read -r hdl;
# Notes.: command executed after the stop in order to delete table (it checks that no sets are available):
# Values: CMD
#
_nft_shutdown_table = { <nftables> list table <table_family> <table> | grep -qE '^\s+set\s+'; } || {
_nft_shutdown_table = { <nftables> list table <table_family> <table> | grep -qP '^\s+set\s+'; } || {
<nftables> delete table <table_family> <table>
}
@ -97,7 +97,7 @@ actionstop = %(_nft_del_set)s
<_nft_shutdown_table>
# Option: actioncheck
# Notes.: command executed once in error case by other command (during the check/restore sane environment process)
# Notes.: command executed once before each actionban command
# Values: CMD
#
actioncheck = <nftables> list chain <table_family> <table> <chain> | grep -q '@<addr_set>[ \t]'
@ -197,11 +197,6 @@ addr_set = addr-set-<name>
# Values: [ ip | ip6 ]
addr_family = ip
# Option: addr_options
# Notes: Additional options for the addr-set, by default allows to store CIDR or address ranges.
# Can be set to empty value to create simple addresses set.
addr_options = <sp>flags interval\;
[Init?family=inet6]
addr_family = ip6
addr_type = ipv6_addr

View file

@ -4,7 +4,6 @@
#
# Author: Nick Hilliard <nick@foobar.org>
# Modified by: Alexander Koeppe making PF work seamless and with IPv4 and IPv6
# Modified by: Balazs Mateffy adding allproto option so all traffic gets blocked from the malicious source
#
#
@ -27,11 +26,9 @@
# }
# to your main pf ruleset, where "namei" are the names of the jails
# which invoke this action
# to block all protocols use the pf[protocol=all] option
actionstart = echo "table <<tablename>-<name>> persist counters" | <pfctl> -f-
port="<port>"; if [ "$port" != "" ] && case "$port" in \{*) false;; esac; then port="{$port}"; fi
protocol="<protocol>"; if [ "$protocol" != "all" ]; then protocol="proto $protocol"; else protocol=all; fi
echo "<block> $protocol from <<tablename>-<name>> to <actiontype>" | <pfctl> -f-
echo "<block> proto <protocol> from <<tablename>-<name>> to <actiontype>" | <pfctl> -f-
# Option: start_on_demand - to start action on demand
# Example: `action=pf[actionstart_on_demand=true]`
@ -101,7 +98,6 @@ tablename = f2b
#
# The action you want pf to take.
# Probably, you want "block quick", but adjust as needed.
# If you want to log all blocked use "blog log quick"
block = block quick
# Option: protocol

View file

@ -51,7 +51,7 @@
# Values: CMD
#
actionstart = if ! ipset -quiet -name list f2b-<name> >/dev/null;
then ipset -quiet -exist create f2b-<name> <ipsettype> timeout <default-ipsettime> maxelem <maxelem>;
then ipset -quiet -exist create f2b-<name> hash:ip timeout <default-ipsettime>;
fi
# Option: actionstop
@ -88,19 +88,6 @@ default-ipsettime = 0
# Values: [ NUM ] Default: 0 (managed by fail2ban by unban)
ipsettime = 0
# expression to calculate timeout from bantime, example:
# expresion to caclulate timeout from bantime, example:
# banaction = %(known/banaction)s[ipsettime='<timeout-bantime>']
timeout-bantime = $([ "<bantime>" -le 2147483 ] && echo "<bantime>" || echo 0)
[Init]
# Option: ipsettype
# Notes: specifies type of set, see `man --pager='less -p "^SET TYPES"' ipset` for details
# Values: hash:ip, hash:net, etc... Default: hash:ip
ipsettype = hash:ip
# Option: maxelem
# Notes: maximal number of elements which can be stored in the ipset
# You may want to increase this for long-duration/high-volume jails
# Values: [ NUM ] Default: 65536
maxelem = 65536

View file

@ -19,8 +19,7 @@
import socket
import smtplib
import email.policy
from email.message import EmailMessage
from email.mime.text import MIMEText
from email.utils import formatdate, formataddr
from fail2ban.server.actions import ActionBase, CallingMap
@ -76,7 +75,7 @@ class SMTPAction(ActionBase):
"""
def __init__(
self, jail, name, host="localhost", ssl=False, user=None, password=None,
self, jail, name, host="localhost", user=None, password=None,
sendername="Fail2Ban", sender="fail2ban", dest="root", matches=None):
"""Initialise action.
@ -89,8 +88,6 @@ class SMTPAction(ActionBase):
host : str, optional
SMTP host, of host:port format. Default host "localhost" and
port "25"
ssl : bool, optional
Whether to use TLS for the SMTP connection or not. Default False.
user : str, optional
Username used for authentication with SMTP server.
password : str, optional
@ -112,7 +109,7 @@ class SMTPAction(ActionBase):
super(SMTPAction, self).__init__(jail, name)
self.host = host
self.ssl = ssl
#TODO: self.ssl = ssl
self.user = user
self.password =password
@ -152,25 +149,16 @@ class SMTPAction(ActionBase):
See Python `smtplib` for full list of other possible
exceptions.
"""
msg = EmailMessage(policy=email.policy.SMTP)
msg.set_content(text)
msg = MIMEText(text)
msg['Subject'] = subject
msg['From'] = formataddr((self.fromname, self.fromaddr))
msg['To'] = self.toaddr
msg['Date'] = formatdate()
smtp_host, smtp_port = self.host.split(':')
smtp = smtplib.SMTP(host=smtp_host, port=smtp_port)
smtp = smtplib.SMTP()
try:
r = smtp.connect(host=smtp_host, port=smtp_port)
self._logSys.debug("Connected to SMTP '%s', response: %i: %s",
self.host, *r)
if self.ssl: # pragma: no cover
r = smtp.starttls()[0];
if r != 220: # pragma: no cover
raise Exception("Failed to starttls() on '%s': %s" % (self.host, r))
self.host, *smtp.connect(self.host))
if self.user and self.password: # pragma: no cover (ATM no tests covering that)
smtp.login(self.user, self.password)
failed_recipients = smtp.sendmail(

View file

@ -44,7 +44,7 @@ _kill_conntrack = conntrack -D -s "<ip>"
# Option: kill
# Notes.: can be used to specify custom killing feature, by default depending on option kill-mode
# Examples: banaction = ufw[kill='ss -K "dst = [<ip>] && ( sport = :http || sport = :https )"']
# Examples: banaction = ufw[kill='ss -K "( sport = :http || sport = :https )" dst "[<ip>]"']
# banaction = ufw[kill='cutter "<ip>"']
kill = <_kill_<kill-mode>>

View file

@ -44,13 +44,7 @@ actioncheck =
actionban = oifs=${IFS};
RESOLVER_ADDR="%(addr_resolver)s"
if [ "<debug>" -gt 0 ]; then echo "try to resolve $RESOLVER_ADDR"; fi
ADDRESSES=$(dig +short -t txt -q $RESOLVER_ADDR | grep -v ';;' | tr -d '"')
if [ "<debug>" -gt 0 ]; then echo "returned address $ADDRESSES"; fi
if [ -z "$ADDRESSES" ]; then
echo "address for $RESOLVER_ADDR cannot be found or timeout from dig";
if [ "<debug>" -gt 0 ]; then exit 1; fi
exit 0
fi
ADDRESSES=$(dig +short -t txt -q $RESOLVER_ADDR | tr -d '"')
IFS=,; ADDRESSES=$(echo $ADDRESSES)
IFS=${oifs}
IP=<ip>
@ -61,11 +55,13 @@ actionban = oifs=${IFS};
TLP=<tlp>
PORT=<port>
DATE=`LC_ALL=C date --date=@<time> +"%%a, %%d %%h %%Y %%T %%z"`
oifs=${IFS}; IFS=,; ADDRESSES=$(echo $ADDRESSES)
IFS=${oifs}
(printf -- %%b "<header>\n<message>\n<report>\n\n";
date '+Note: Local timezone is %%z (%%Z)';
printf -- %%b "\n<ipmatches>\n\n<footer>") | <mailcmd> <mailargs> $ADDRESSES
if [ ! -z "$ADDRESSES" ]; then
oifs=${IFS}; IFS=,; ADDRESSES=$(echo $ADDRESSES)
IFS=${oifs}
(printf -- %%b "<header>\n<message>\n<report>\n\n";
date '+Note: Local timezone is %%z (%%Z)';
printf -- %%b "\n<ipmatches>\n\n<footer>") | <mailcmd> <mailargs> $ADDRESSES
fi
actionunban =

View file

@ -64,7 +64,7 @@ ignoreregex =
# ^user .*: one-time-nonce mismatch - sending new nonce\s*$
# ^realm mismatch - got `(?:[^']*|.*?)' but no realm specified\s*$
#
# Because url/referer are foreign input, short form of regex used if long enough to identify failure.
# Because url/referer are foreign input, short form of regex used if long enough to idetify failure.
#
# Author: Cyril Jaquier
# Major edits by Daniel Black and Ben Rubson.

View file

@ -10,8 +10,7 @@
badbotscustom = EmailCollector|WebEMailExtrac|TrackBack/1\.02|sogou music spider|(?:Mozilla/\d+\.\d+ )?Jorgee
badbots = Atomic_Email_Hunter/4\.0|atSpider/1\.0|autoemailspider|bwh3_user_agent|China Local Browse 2\.6|ContactBot/0\.2|ContentSmartz|DataCha0s/2\.0|DBrowse 1\.4b|DBrowse 1\.4d|Demo Bot DOT 16b|Demo Bot Z 16b|DSurf15a 01|DSurf15a 71|DSurf15a 81|DSurf15a VA|EBrowse 1\.4b|Educate Search VxB|EmailSiphon|EmailSpider|EmailWolf 1\.00|ESurf15a 15|ExtractorPro|Franklin Locator 1\.8|FSurf15a 01|Full Web Bot 0416B|Full Web Bot 0516B|Full Web Bot 2816B|Guestbook Auto Submitter|Industry Program 1\.0\.x|ISC Systems iRc Search 2\.1|IUPUI Research Bot v 1\.9a|LARBIN-EXPERIMENTAL \(efp@gmx\.net\)|LetsCrawl\.com/1\.0 \+http\://letscrawl\.com/|Lincoln State Web Browser|LMQueueBot/0\.2|LWP\:\:Simple/5\.803|Mac Finder 1\.0\.xx|MFC Foundation Class Library 4\.0|Microsoft URL Control - 6\.00\.8xxx|Missauga Locate 1\.0\.0|Missigua Locator 1\.9|Missouri College Browse|Mizzu Labs 2\.2|Mo College 1\.9|MVAClient|Mozilla/2\.0 \(compatible; NEWT ActiveX; Win32\)|Mozilla/3\.0 \(compatible; Indy Library\)|Mozilla/3\.0 \(compatible; scan4mail \(advanced version\) http\://www\.peterspages\.net/?scan4mail\)|Mozilla/4\.0 \(compatible; Advanced Email Extractor v2\.xx\)|Mozilla/4\.0 \(compatible; Iplexx Spider/1\.0 http\://www\.iplexx\.at\)|Mozilla/4\.0 \(compatible; MSIE 5\.0; Windows NT; DigExt; DTS Agent|Mozilla/4\.0 efp@gmx\.net|Mozilla/5\.0 \(Version\: xxxx Type\:xx\)|NameOfAgent \(CMS Spider\)|NASA Search 1\.0|Nsauditor/1\.x|PBrowse 1\.4b|PEval 1\.4b|Poirot|Port Huron Labs|Production Bot 0116B|Production Bot 2016B|Production Bot DOT 3016B|Program Shareware 1\.0\.2|PSurf15a 11|PSurf15a 51|PSurf15a VA|psycheclone|RSurf15a 41|RSurf15a 51|RSurf15a 81|searchbot admin@google\.com|ShablastBot 1\.0|snap\.com beta crawler v0|Snapbot/1\.0|Snapbot/1\.0 \(Snap Shots&#44; \+http\://www\.snap\.com\)|sogou develop spider|Sogou Orion spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sogou spider|Sogou web spider/3\.0\(\+http\://www\.sogou\.com/docs/help/webmasters\.htm#07\)|sohu agent|SSurf15a 11 |TSurf15a 11|Under the Rainbow 2\.2|User-Agent\: Mozilla/4\.0 \(compatible; MSIE 6\.0; Windows NT 5\.1\)|VadixBot|WebVulnCrawl\.unknown/1\.0 libwww-perl/5\.803|Wells Search II|WEP Search 00
vhostpref = (?:[\w]+[\w\-\.]*\s+)?
failregex = ^\s*%(vhostpref)s<ADDR> [^"]*"[A-Z]{3,10} [^"]+" \d+ \d+ "[^"]+" "[^"]*(?:%(badbots)s|%(badbotscustom)s)"$
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*"(?:%(badbots)s|%(badbotscustom)s)"$
ignoreregex =

View file

@ -29,7 +29,7 @@ apache-prefix = <apache-prefix-<logging>>
apache-pref-ignore =
_apache_error_client = <apache-prefix>\[(:?error|<apache-pref-ignore>\S+:\S+)\]( \[pid \d+(:\S+ \d+)?\])? \[(?:client|remote) <HOST>(:\d{1,5})?\]
_apache_error_client = <apache-prefix>\[(:?error|<apache-pref-ignore>\S+:\S+)\]( \[pid \d+(:\S+ \d+)?\])? \[client <HOST>(:\d{1,5})?\]
datepattern = {^LN-BEG}

View file

@ -2,8 +2,7 @@
[Definition]
vhostpref = (?:[\w]+[\w\-\.]*\s+)?
failregex = ^\s*%(vhostpref)s<ADDR> [^"]*"[A-Z]{3,10} /\S* [^"]*" \d+ \d+ "[^"]*" "[^"]*\bGooglebot/[^"]*"
failregex = ^\s*<HOST> \S+ \S+(?: \S+)?\s+\S+ "[A-Z]+ /\S* [^"]*" \d+ \d+ \"[^"]*\" "[^"]*\bGooglebot/[^"]*"
ignoreregex =

View file

@ -19,10 +19,11 @@ before = apache-common.conf
script = /\S*(?:php(?:[45]|[.-]cgi)?|\.asp|\.exe|\.pl|\bcgi-bin/)
prefregex = ^%(_apache_error_client)s (?:AH0(?:01(?:28|30)|1(?:264|071)|2811): )?(?=(?:[Ff]ile|[Ss]cript|[Gg]ot error|stderr from) )<F-CONTENT>.+</F-CONTENT>$
prefregex = ^%(_apache_error_client)s (?:AH0(?:01(?:28|30)|1(?:264|071)|2811): )?(?:(?:[Ff]ile|script|[Gg]ot) )<F-CONTENT>.+</F-CONTENT>$
failregex = ^(?:(?:[Ff]ile does not exist|[Ss]cript not found or unable to stat): <script>\b|[Gg]ot error '[Pp]rimary script unknown\b)
^(?:stderr from |script (?P<_q>'))<script>\S*(?(_q)'|) (?:script )?(?:does not exist|not found or unable to stat)
failregex = ^(?:does not exist|not found or unable to stat): <script>\b
^'<script>\S*' not found or unable to stat
^error '[Pp]rimary script unknown(?:\\n)?'
ignoreregex =

View file

@ -8,7 +8,7 @@ before = apache-common.conf
[Definition]
failregex = ^%(_apache_error_client)s (?:(?:AH(?:001[23][456]|10244): )?[Ii]nvalid (method|URI)\b|(?:AH00565: )?request failed: URI too long \(longer than \d+\)|request failed: erroneous characters after protocol string:|(?:AH00566: )?request failed: invalid characters in URI\b)
failregex = ^%(_apache_error_client)s (?:(?:AH001[23][456]: )?Invalid (method|URI) in request\b|(?:AH00565: )?request failed: URI too long \(longer than \d+\)|request failed: erroneous characters after protocol string:|(?:AH00566: )?request failed: invalid characters in URI\b)
ignoreregex =

View file

@ -21,13 +21,13 @@ log_prefix= (?:NOTICE|SECURITY|WARNING)%(__pid_re)s:?(?:\[C-[\da-f]*\])?:? [^:]+
prefregex = ^%(__prefix_line)s%(log_prefix)s <F-CONTENT>.+</F-CONTENT>$
failregex = ^Registration from '[^']*' failed for '<HOST>(:\d+)?' - (?:Wrong password|Username/auth name mismatch|No matching peer found|Not a local domain|Device does not match ACL|Peer is not supposed to register|ACL error \(permit/deny\)|Not a local domain)$
^Call (?:from '[^']*' )?\((?:(?:TCP|UDP):)?<HOST>:\d+\) to extension '[^']*' rejected because extension not found in context
^Call from '[^']*' \((?:(?:TCP|UDP):)?<HOST>:\d+\) to extension '[^']*' rejected because extension not found in context
^(?:Host )?<HOST> (?:failed (?:to authenticate\b|MD5 authentication\b)|tried to authenticate with nonexistent user\b)
^No registration for peer '[^']*' \(from <HOST>\)$
^hacking attempt detected '<HOST>'$
^SecurityEvent="(?:FailedACL|InvalidAccountID|ChallengeResponseFailed|InvalidPassword)"(?:(?:,(?!RemoteAddress=)\w+="[^"]*")*|.*?),RemoteAddress="IPV[46]/[^/"]+/<HOST>/\d+"(?:,(?!RemoteAddress=)\w+="[^"]*")*$
^"Rejecting unknown SIP connection from <HOST>(?::\d+)?"$
^Request (?:'[^']*' )?from '(?:[^']*|.*?)' failed for '<HOST>(?::\d+)?'\s\(callid: [^\)]*\) - (?:No matching endpoint found|Not match Endpoint(?: Contact)? ACL|(?:Failed|Error) to authenticate)\b[^']*$
^Request (?:'[^']*' )?from '(?:[^']*|.*?)' failed for '<HOST>(?::\d+)?'\s\(callid: [^\)]*\) - (?:No matching endpoint found|Not match Endpoint(?: Contact)? ACL|(?:Failed|Error) to authenticate)\s*$
# FreePBX (todo: make optional in v.0.10):
# ^(%(__prefix_line)s|\[\]\s*WARNING%(__pid_re)s:?(?:\[C-[\da-f]*\])? )[^:]+: Friendly Scanner from <HOST>$

View file

@ -1,16 +0,0 @@
# Fail2Ban filter for dante
#
# Make sure you have "log: error" set in your "client pass" directive
#
[INCLUDES]
before = common.conf
[Definition]
_daemon = danted
failregex = ^%(__prefix_line)sinfo: block\(\d\): tcp/accept \]: <ADDR>\.\d+ \S+: error after reading \d+ bytes? in \d+ seconds?: (?:could not access|system password authentication failed for|pam_authenticate\(\) for) user "<F-USER>[^"]+</F-USER>"
[Init]
journalmatch = _SYSTEMD_UNIT=danted.service

View file

@ -7,21 +7,19 @@ before = common.conf
[Definition]
_daemon = (?:dovecot(?:-auth)?|auth)
_auth_worker = (?:dovecot: )?auth(?:-worker)?
_auth_worker_info = (?:conn \w+:auth(?:-worker)? \([^\)]+\): auth(?:-worker)?<\d+>: )?
_bypass_reject_reason = (?:: (?:\w+\([^\):]*\) \w+|[^\(]+))*
_daemon = (?:dovecot(?:-auth)?|auth)
prefregex = ^%(__prefix_line)s(?:%(_auth_worker)s(?:\([^\)]+\))?: )?(?:%(__pam_auth)s(?:\(dovecot:auth\))?: |(?:pop3|imap|managesieve|submission)-login: )?(?:Info: )?%(_auth_worker_info)s<F-CONTENT>.+</F-CONTENT>$
failregex = ^authentication failure; logname=<F-ALT_USER1>\S*</F-ALT_USER1> uid=\S* euid=\S* tty=dovecot ruser=<F-USER>\S*</F-USER> rhost=<HOST>(?:\s+user=<F-ALT_USER>\S*</F-ALT_USER>)?\s*$
^(?:Login aborted|Aborted login|Disconnected|Remote closed connection|Client has quit the connection)%(_bypass_reject_reason)s \((?:auth failed, \d+ attempts(?: in \d+ secs)?|tried to use (?:disabled|disallowed) \S+ auth|proxy dest auth failed)\)[^:]*:(?: user=<<F-USER>[^>]*</F-USER>>,)?(?: method=\S+,)? rip=<HOST>(?:[^>]*(?:, session=<\S+>)?)\s*$
^(?:Aborted login|Disconnected|Remote closed connection|Client has quit the connection)(?:: (?:[^\(]+|\w+\([^\)]*\))+)? \((?:auth failed, \d+ attempts(?: in \d+ secs)?|tried to use (?:disabled|disallowed) \S+ auth|proxy dest auth failed)\):(?: user=<<F-USER>[^>]*</F-USER>>,)?(?: method=\S+,)? rip=<HOST>(?:[^>]*(?:, session=<\S+>)?)\s*$
^pam\(\S+,<HOST>(?:,\S*)?\): pam_authenticate\(\) failed: (?:User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \([Pp]assword mismatch\?\)|Permission denied)\s*$
^[a-z\-]{3,15}\(\S*,<HOST>(?:,\S*)?\): (?:[Uu]nknown user|[Ii]nvalid credentials|[Pp]assword mismatch)
<mdre-<mode>>
mdre-aggressive = ^(?:Login aborted|Aborted login|Disconnected|Remote closed connection|Client has quit the connection)%(_bypass_reject_reason)s \((?:no auth attempts|disconnected before auth was ready,|client didn't finish \S+ auth,|disconnected during TLS handshake)(?: (?:in|waited) \d+ secs)?\)[^:]*:(?: user=<[^>]*>,)?(?: method=\S+,)? rip=<HOST>(?:[^>]*(?:, session=<\S+>)?)\s*$
mdre-aggressive = ^(?:Aborted login|Disconnected|Remote closed connection|Client has quit the connection)(?::(?: [^ \(]+)+)? \((?:no auth attempts|disconnected before auth was ready,|client didn't finish \S+ auth,)(?: (?:in|waited) \d+ secs)?\):(?: user=<[^>]*>,)?(?: method=\S+,)? rip=<HOST>(?:[^>]*(?:, session=<\S+>)?)\s*$
mdre-normal =
@ -43,7 +41,6 @@ datepattern = {^LN-BEG}TAI64N
# DEV Notes:
# * the first regex is essentially a copy of pam-generic.conf
# * Probably doesn't do dovecot sql/ldap backends properly (resolved in edit 21/03/2016)
# * Dovecot version 2.4 changed event log structure, line prior needed to maintain 2.3 support
#
# Author: Martin Waschbuesch
# Daniel Black (rewrote with begin and end anchors)

View file

@ -23,17 +23,14 @@ before = common.conf
_daemon = dropbear
prefregex = ^%(__prefix_line)s(?:\[\d+\] \w{2,3} [\d:\s]+)?<F-CONTENT>(?:[Ll]ogin|[Bb]ad|[Ee]xit).+</F-CONTENT>$
prefregex = ^%(__prefix_line)s<F-CONTENT>(?:[Ll]ogin|[Bb]ad|[Ee]xit).+</F-CONTENT>$
failregex = ^[Ll]ogin attempt for nonexistent user (?:'<F-USER>.*</F-USER>' )?from <HOST>:\d+$
^[Bb]ad (?:PAM )?password attempt for '<F-USER>.+</F-USER>' from <HOST>(?::\d+)?$
^[Ee]xit before auth from \<?<ADDR>:\d+\>?: (?:\([^\)]*\): )?Max auth tries reached - user '<F-USER>.+</F-USER>'\s*$
^[Ee]xit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '<F-USER>.+</F-USER>' from <HOST>:\d+\s*$
failregex = ^[Ll]ogin attempt for nonexistent user ('.*' )?from <HOST>:\d+$
^[Bb]ad (PAM )?password attempt for .+ from <HOST>(:\d+)?$
^[Ee]xit before auth \(user '.+', \d+ fails\): Max auth tries reached - user '.+' from <HOST>:\d+\s*$
ignoreregex =
journalmatch = _SYSTEMD_UNIT=dropbear.service + _COMM=dropbear
# DEV Notes:
#
# The first two regexs here match the unmodified dropbear messages. It isn't

View file

@ -9,43 +9,12 @@ after = exim-common.local
[Definition]
_fields_grp = (?: (?!H=)[A-Za-z]{1,4}(?:=\S+)?)*
host_info = %(_fields_grp)s (?:H=)?(?:[\w.-]+)? ?(?:\(\S+\))? ?\[<ADDR>\](?::\d+)?%(_fields_grp)s
pid = (?:\s?\[\d+\]|\s?[\w\.-]+ exim\[\d+\]:){0,2}
host_info_pre = (?:H=([\w.-]+ )?(?:\(\S+\) )?)?
host_info_suf = (?::\d+)?(?: I=\[\S+\](:\d+)?)?(?: U=\S+)?(?: P=e?smtp)?(?: F=(?:<>|[^@]+@\S+))?\s
host_info = %(host_info_pre)s\[<HOST>\]%(host_info_suf)s
pid = (?: \[\d+\]| \w+ exim\[\d+\]:)?
logtype = file
_add_pref = <lt_<logtype>/_add_pref>
__prefix_line = %(pid)s%(_add_pref)s
[lt_journal]
_add_pref = (?: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})?
[lt_file]
_add_pref =
# DEV Notes
# ------------
# Host string happens:
# H=[ip address]
# H=(helo_name) [ip address]
# H=host_name [ip address]
# H=host_name (helo_name) [ip address]
# flags H=host_name (helo_name) [ip address] flags
# where only [ip address] always visible, ignore ident
# From exim source code:
# src/src/host.c:host_and_ident()
# src/receive.c:add_host_info_for_log()
# Substitution of `_fields_grp` bypasses all flags but H
# Summary of Fields in Log Lines depending on log_selector
# https://www.exim.org/exim-html-current/doc/html/spec_html/ch-log_files.html
# at version exim-4.97.1
# ---
# Authors:
# Cyril Jaquier
# Daniel Black (rewrote with strong regexs)
# Sergey G. Brester aka sebres (optimization, rewrite to prefregex, reviews)
# Martin O'Neal (added additional regexs to detect authentication failures, protocol errors, and drops)
# Vladimir Varlamov (host line definition)
# DEV Notes:
# From exim source code: ./src/receive.c:add_host_info_for_log
#
# Author: Daniel Black

View file

@ -26,13 +26,11 @@ before = exim-common.conf
[Definition]
prefregex = ^%(__prefix_line)s<F-CONTENT>.+</F-CONTENT>$
failregex = ^\s?\S+%(host_info)s rejected by local_scan\(\): .{0,256}$
^%(host_info)s rejected RCPT [^@]+@\S+: .*dnsbl.*\s*$
^\s?\S+%(host_info)s rejected after DATA: This message contains a virus \(\S+\)\.\s*$
^\s?\S+ SA: Action: flagged as Spam but accepted: score=\d+\.\d+ required=\d+\.\d+ \(scanned in \d+/\d+ secs \| Message-Id: \S+\)\. From \S+ \(host=\S+ \[<HOST>\]\) for <honeypot>$
^\s?\S+ SA: Action: silently tossed message: score=\d+\.\d+ required=\d+\.\d+ trigger=\d+\.\d+ \(scanned in \d+/\d+ secs \| Message-Id: \S+\)\. From \S+ \(host=(\S+ )?\[<HOST>\]\) for \S+$
failregex = ^%(pid)s \S+ F=(<>|\S+@\S+) %(host_info)srejected by local_scan\(\): .{0,256}$
^%(pid)s %(host_info)sF=(<>|[^@]+@\S+) rejected RCPT [^@]+@\S+: .*dnsbl.*\s*$
^%(pid)s \S+ %(host_info)sF=(<>|[^@]+@\S+) rejected after DATA: This message contains a virus \(\S+\)\.\s*$
^%(pid)s \S+ SA: Action: flagged as Spam but accepted: score=\d+\.\d+ required=\d+\.\d+ \(scanned in \d+/\d+ secs \| Message-Id: \S+\)\. From \S+ \(host=\S+ \[<HOST>\]\) for <honeypot>$
^%(pid)s \S+ SA: Action: silently tossed message: score=\d+\.\d+ required=\d+\.\d+ trigger=\d+\.\d+ \(scanned in \d+/\d+ secs \| Message-Id: \S+\)\. From \S+ \(host=(\S+ )?\[<HOST>\]\) for \S+$
ignoreregex =
@ -45,6 +43,8 @@ ignoreregex =
honeypot = trap@example.com
# DEV Notes
# -----------
# The %(host_info) definition contains a <ADDR> match. No space before. See exim-common.conf
# DEV Notes:
# The %(host_info) defination contains a <HOST> match
#
# Author: Cyril Jaquier
# Daniel Black (rewrote with strong regexs)

View file

@ -13,23 +13,21 @@ before = exim-common.conf
[Definition]
prefregex = ^%(__prefix_line)s<F-CONTENT>.+</F-CONTENT>$
# Fre-filter via "prefregex" is currently inactive because of too different failure syntax in exim-log (testing needed):
#prefregex = ^%(pid)s <F-CONTENT>\b(?:\w+ authenticator failed|([\w\-]+ )?SMTP (?:(?:call|connection) from|protocol(?: synchronization)? error)|no MAIL in|(?:%(host_info_pre)s\[[^\]]+\]%(host_info_suf)s(?:sender verify fail|rejected RCPT|dropped|AUTH command))).+</F-CONTENT>$
failregex = ^\s?\w+ authenticator failed for%(host_info)s: 535 Incorrect authentication data(?: \(set_id=.*\)|: \d+ Time\(s\))?\s*$
failregex = ^%(pid)s %(host_info)ssender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$
^%(pid)s \w+ authenticator failed for (?:[^\[\( ]* )?(?:\(\S*\) )?\[<HOST>\](?::\d+)?(?: I=\[\S+\](:\d+)?)?: 535 Incorrect authentication data( \(set_id=.*\)|: \d+ Time\(s\))?\s*$
^%(pid)s %(host_info)srejected RCPT [^@]+@\S+: (?:relay not permitted|Sender verify failed|Unknown user|Unrouteable address)\s*$
^%(pid)s SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+") %(host_info)s(?:next )?input=".*"\s*$
^%(pid)s SMTP call from (?:[^\[\( ]* )?%(host_info)sdropped: too many (?:nonmail commands|syntax or protocol errors) \(last (?:command )?was "[^"]*"\)\s*$
^%(pid)s SMTP protocol error in "[^"]+(?:"+[^"]*(?="))*?" %(host_info)sAUTH command used when not advertised\s*$
^%(pid)s no MAIL in SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sD=\d\S*s(?: C=\S*)?\s*$
^%(pid)s (?:[\w\-]+ )?SMTP connection from (?:[^\[\( ]* )?(?:\(\S*\) )?%(host_info)sclosed by DROP in ACL\s*$
<mdre-<mode>>
mdre-more = ^%(host_info)s sender verify fail for <\S+>: (?:Unknown user|Unrouteable address|all relevant MX records point to non-existent hosts)\s*$
^%(host_info)s rejected RCPT (?:<F-RCPT>[^@]+@\S+</F-RCPT>:)?
^\s?SMTP protocol synchronization error \([^)]*\): rejected (?:connection from|"\S+")%(host_info)s (?:next )?input=".*"\s*$
^\s?SMTP call from%(host_info)s dropped: too many (?:(?:nonmail|unrecognized) commands|syntax or protocol errors)
^\s?SMTP protocol error in "[^"]+(?:"+[^"]*(?="))*?"%(host_info)s [A-Z]+ (?:command used when not advertised|authentication mechanism not supported)\s*$
^\s?no MAIL in SMTP connection from%(host_info)s
^\s?(?:[\w\-]+ )?SMTP connection from%(host_info)s closed by DROP in ACL\s*$
mdre-aggressive = %(mdre-more)s
^\s?no host name found for IP address <ADDR>$
^\s?no IP address found for host \S+ \(during SMTP connection from%(host_info)s\)$
^%(host_info)s dropped by '[^']+' ACL:
mdre-aggressive = ^%(pid)s no host name found for IP address <HOST>$
^%(pid)s no IP address found for host \S+ \(during SMTP connection from \[<HOST>\]\)$
mdre-normal =
@ -44,10 +42,13 @@ mode = normal
ignoreregex =
# DEV Notes
# -----------
# The %(host_info) definition contains a <ADDR> match. No space before. See exim-common.conf
# DEV Notes:
# The %(host_info) defination contains a <HOST> match
#
# SMTP protocol synchronization error \([^)]*\) <- This needs to be non-greedy
# to void capture beyond ")" to avoid a DoS Injection vulnerability as input= is
# to void capture beyond ")" to avoid a DoS Injection vulnerabilty as input= is
# user injectable data.
#
# Author: Cyril Jaquier
# Daniel Black (rewrote with strong regexs)
# Martin O'Neal (added additional regexs to detect authentication failures, protocol errors, and drops)

View file

@ -29,9 +29,9 @@ _daemon = freeswitch
mode = extra
# Prefix contains common prefix line (server, daemon, etc.) and 2 datetimes if used systemd backend
_pref_line = ^%(__prefix_line)s[^\[]*
_pref_line = ^%(__prefix_line)s(?:(?:\d+-)?\d+-\d+ \d+:\d+:\d+\.\d+)?
prefregex = ^%(_pref_line)s\s*\[WARN(?:ING)?\](?: \[SOFIA\])? \[?sofia_reg\.c:\d+\]? <F-CONTENT>.+</F-CONTENT>$
prefregex = ^%(_pref_line)s \[WARN(?:ING)?\](?: \[SOFIA\])? \[?sofia_reg\.c:\d+\]? <F-CONTENT>.+</F-CONTENT>$
cmnfailre = ^Can't find user \[[^@]+@[^\]]+\] from <HOST>$

View file

@ -1,15 +1,11 @@
# Fail2Ban configuration file to block repeated failed login attempts to Frolor installation(s)
#
# Froxlor needs to log to Syslog User (e.g. /var/log/user.log) with one of the following messages
# - for type=2
# <syslog prefix> froxlor[1-6]: froxlor.WARNING: Unknown user tried to login. {"source":"login","action":"50","user":"<ADDR>"} []
# <syslog prefix> froxlor[1-6]: froxlor.WARNING: User tried to login with wrong password. {"source":"login","action":"50","user":"<ADDR>"} []
# - for type=1:
# <syslog prefix> Froxlor: [Login Action <ADDR>] Unknown user '<USER>' tried to login.
# <syslog prefix> Froxlor: [Login Action <ADDR>] User '<USER>' tried to login with wrong password.
# <syslog prefix> Froxlor: [Login Action <HOST>] Unknown user '<USER>' tried to login.
# <syslog prefix> Froxlor: [Login Action <HOST>] User '<USER>' tried to login with wrong password.
#
# Author: Joern Muehlencord
# Modified: Para-do-x™ - Andreas Duennwald
#
[INCLUDES]
@ -17,18 +13,28 @@
# common.local
before = common.conf
[DEFAULT]
_daemon = [Ff]roxlor
_re = (?:Unknown )?[uU]ser(?: '<F-USER>(?:\S*|[^']*)</F-USER>')? tried to login(?: with wrong password)?\.
[type1]
failregex = ^%(__prefix_line)s\[Login Action <ADDR>\] %(_re)s$
[type2]
failregex = ^%(__prefix_line)sfroxlor\.WARNING: %(_re)s \{(?:"[^"]+":"[^"]*",\s*){,5}"user":"<ADDR>"\} \[\]$
[Definition]
type = 2
failregex = <type<type>/failregex>
_daemon = Froxlor
# Option: failregex
# Notes.: regex to match the password failures messages in the logfile. The
# host must be matched by a group named "host". The tag "<HOST>" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P<host>[\w\-.^_]+)
# Values: TEXT
#
prefregex = ^%(__prefix_line)s\[Login Action <HOST>\] <F-CONTENT>.+</F-CONTENT>$
failregex = ^Unknown user \S* tried to login.$
^User \S* tried to login with wrong password.$
# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

View file

@ -3,8 +3,8 @@
[Definition]
failregex = ^[^\)]*\(?(?:http|mod)_auth\.c\.\d+\) (?:password doesn\'t match for (?:\S+|.*?) username:\s+<F-USER>(?:\S+|.*?)</F-USER>\s*|digest: auth failed(?: for\s+<F-ALT_USER>(?:\S+|.*?)</F-ALT_USER>\s*)?: (?:wrong password|uri mismatch \([^\)]*\))|get_password failed),? IP: <HOST>\s*$
failregex = ^\s*(?:: )?\(?(?:http|mod)_auth\.c\.\d+\) (?:password doesn\'t match for (?:\S+|.*?) username:\s+<F-USER>(?:\S+|.*?)</F-USER>\s*|digest: auth failed(?: for\s+<F-ALT_USER>(?:\S+|.*?)</F-ALT_USER>\s*)?: (?:wrong password|uri mismatch \([^\)]*\))|get_password failed),? IP: <HOST>\s*$
ignoreregex =
ignoreregex =
# Authors: Francois Boulogne <fboulogne@april.org>, Lucian Maly <lmaly@redhat.com>
# Author: Francois Boulogne <fboulogne@april.org>

View file

@ -1,4 +1,4 @@
# Fail2Ban filter for unsuccessful MongoDB authentication attempts
# Fail2Ban filter for unsuccesfull MongoDB authentication attempts
#
# Logfile /var/log/mongodb/mongodb.log
#
@ -23,7 +23,7 @@ maxlines = 10
#
# Regarding the multiline regex:
#
# There can be a number of non-related lines between the first and second part
# There can be a nunber of non-related lines between the first and second part
# of this regex maxlines of 10 is quite generious.
#
# Note the capture __connid, includes the connection ID, used in second part of regex.

View file

@ -1,10 +1,9 @@
# Fail2Ban filter for unsuccessful MySQL authentication attempts
# Fail2Ban filter for unsuccesful MySQL authentication attempts
#
#
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld],
# `log_error_verbosity` system variable set to 3 (`log-warnings = 2` for older versions),
# and check whether `log_error` (or `log-error`) system variable would match the `logpath` of fail2ban
# (see https://dev.mysql.com/doc/refman/en/communication-errors.html)
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld]:
# log-error=/var/log/mysqld.log
# log-warnings = 2
#
# If using mysql syslog [mysql_safe] has syslog in /etc/my.cnf
@ -18,7 +17,7 @@ before = common.conf
_daemon = mysqld
failregex = ^%(__prefix_line)s(?:(?:\d{6}|\d{4}-\d{2}-\d{2})[ T]\s?\d{1,2}:\d{2}:\d{2} )?(?:\d+ )?\[\w+\] (?:\[[^\]]+\] )*Access denied for user '<F-USER>[^']+</F-USER>'@'<HOST>'(?:\s+(?:to database '[^']*'|\(using password: (?:YES|NO)\)){1,2})?\s*$
failregex = ^%(__prefix_line)s(?:(?:\d{6}|\d{4}-\d{2}-\d{2})[ T]\s?\d{1,2}:\d{2}:\d{2} )?(?:\d+ )?\[\w+\] (?:\[[^\]]+\] )*Access denied for user '<F-USER>[^']+</F-USER>'@'<HOST>' (to database '[^']*'|\(using password: (YES|NO)\))*\s*$
ignoreregex =

View file

@ -30,14 +30,11 @@ __pid_re=(?:\[\d+\])
__daemon_re=\(?%(_daemon)s(?:\(\S+\))?\)?:?
__daemon_combs_re=(?:%(__pid_re)s?:\s+%(__daemon_re)s|%(__daemon_re)s%(__pid_re)s?:)
_category = (?!error|info)[\w-]+
_category_re = (?:%(_category)s: )?
# hostname daemon_id spaces
# this can be optional (for instance if we match named native log files)
__line_prefix=\s*(?:\S+ %(__daemon_combs_re)s\s+)?%(_category_re)s
__line_prefix=(?:\s*\S+ %(__daemon_combs_re)s\s+)?
prefregex = ^%(__line_prefix)s(?:(?:error|info):\s*)?client(?: @\S*)? <HOST>#\S+(?: \([\S.]+\))?: <F-CONTENT>.+</F-CONTENT>\s(?:denied(?: \([^\)]*\))?|\(NOTAUTH\))\s*$
prefregex = ^%(__line_prefix)s(?: error:)?\s*client(?: @\S*)? <HOST>#\S+(?: \([\S.]+\))?: <F-CONTENT>.+</F-CONTENT>\s(?:denied|\(NOTAUTH\))\s*$
failregex = ^(?:view (?:internal|external): )?query(?: \(cache\))?
^zone transfer

View file

@ -1,32 +0,0 @@
# Generic nginx error_log configuration items (to be used as interpolations) in other
# filters monitoring nginx error-logs
#
[DEFAULT]
# Type of log-file resp. log-format (file, short, journal):
logtype = file
# Daemon definition is to be specialized (if needed) in .conf file
_daemon = nginx
# Common line prefixes (beginnings) which could be used in filters
#
# [bsdverbose]? [hostname] [vserver tag] daemon_id spaces
#
# This can be optional (for instance if we match named native log files)
__prefix = <lt_<logtype>/__prefix>
__err_type = error
__prefix_line = %(__prefix)s\[%(__err_type)s\] \d+#\d+: \*\d+\s+
[lt_file]
__prefix = \s*
[lt_short]
__prefix = \s*(?:(?!\[)\S+ %(_daemon)s\[\d+\]: [^\[]*)?
[lt_journal]
__prefix = %(lt_short/__prefix)s

View file

@ -1,29 +0,0 @@
# fail2ban filter configuration for nginx forbidden accesses
#
# If you have configured nginx to forbid some paths in your webserver, e.g.:
#
# location ~ /\. {
# deny all;
# }
#
# if a client tries to access https://yoursite/.user.ini then you will see
# in nginx error log:
#
# 2018/09/14 19:03:05 [error] 2035#2035: *9134 access forbidden by rule, client: 10.20.30.40, server: www.example.net, request: "GET /.user.ini HTTP/1.1", host: "www.example.net", referrer: "https://www.example.net"
#
# By carefully setting this filter we ban every IP that tries too many times to
# access forbidden resources.
#
# Author: Michele Bologna https://www.michelebologna.net/
[INCLUDES]
before = nginx-error-common.conf
[Definition]
failregex = ^%(__prefix_line)saccess forbidden by rule, client: <HOST>
ignoreregex =
datepattern = {^LN-BEG}
journalmatch = _SYSTEMD_UNIT=nginx.service + _COMM=nginx

View file

@ -1,25 +1,14 @@
# fail2ban filter configuration for nginx
[INCLUDES]
before = nginx-error-common.conf
[Definition]
mode = normal
__err_type = (?:error|crit)
__suffix_line = , client: <ADDR>(?:, (?:server|request|host|referrer): (?:"[^"]*"|\S*)){0,4}
prefregex = ^%(__prefix_line)s<F-CONTENT>.*</F-CONTENT>%(__suffix_line)s\s*$
mdre-auth = ^user "<F-USER>(?:[^"]+|.*?)</F-USER>":? (?:password mismatch|was not found in "[^\"]*")$
^(?:PAM: )?user '<F-USER>(?:[^']+|.*?)</F-USER>' - not authenticated: Authentication failure$
mdre-fallback = ^SSL_(?:do_handshake|read)\(\) failed \(SSL: error:\S+(?: \S+){1,3}[^\)]*\)[^,]*
mdre-auth = ^\s*\[error\] \d+#\d+: \*\d+ user "(?:[^"]+|.*?)":? (?:password mismatch|was not found in "[^\"]*"), client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(?:, referrer: "\S+")?\s*$
mdre-fallback = ^\s*\[crit\] \d+#\d+: \*\d+ SSL_do_handshake\(\) failed \(SSL: error:\S+(?: \S+){1,3} too (?:long|short)\)[^,]*, client: <HOST>
mdre-normal = %(mdre-auth)s
mdre-aggressive = %(mdre-auth)s
%(mdre-fallback)s

View file

@ -23,10 +23,6 @@
# ...
#
[INCLUDES]
before = nginx-error-common.conf
[Definition]
# Specify following expression to define exact zones, if you want to ban IPs limited
@ -37,16 +33,13 @@ before = nginx-error-common.conf
#
ngx_limit_req_zones = [^"]+
# Depending on limit_req_log_level directive (may be: info | notice | warn | error):
__err_type = [a-z]+
# Use following full expression if you should range limit request to specified
# servers, requests, referrers etc. only :
#
# failregex = ^%(__prefix_line)slimiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(, referrer: "\S+")?\s*$
# failregex = ^\s*\[[a-z]+\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>, server: \S*, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"(, referrer: "\S+")?\s*$
# Shortly, much faster and stable version of regexp:
failregex = ^%(__prefix_line)s(?:limiting|delaying) (?:request|connection)s?(?:, excess: [\d\.]+,?)? by zone "(?:%(ngx_limit_req_zones)s)", client: <ADDR>,
failregex = ^\s*\[[a-z]+\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>,
ignoreregex =

View file

@ -1,13 +0,0 @@
# Fail2Ban filter for openvpn server
# Detecting wrong TLS handshakes
# typically logged in /var/log/syslog
# Author: Philipp Burndorfer
[INCLUDES]
before = common.conf
[Definition]
_daemon = ovpn-server\d*
failregex = ^%(__prefix_line)s<HOST>:\d{4,5} (?:TLS Auth Error:|VERIFY ERROR:|TLS Error: TLS handshake failed\b|SIGUSR1\[soft,connection-reset\] received\b)
^%(__prefix_line)sTLS Error: cannot locate HMAC in incoming packet from \[AF_INET\]\s*<HOST>:\d{4,5}

View file

@ -10,63 +10,50 @@ before = common.conf
[Definition]
_daemon = postfix\b([^\[\s]+)?
# optional port:
_daemon = postfix(-\w+)?/\w+(?:/smtp[ds])?
_port = (?::\d+)?
# optional prefix like `NOQUEUE: ` or `00ADB3C0899: ` etc...
_pref = (?:\w+: )?
# SMTP commands like RCPT etc
_cmd = [A-Z]{4,}
_pref = [A-Z]{4}
prefregex = ^%(__prefix_line)s%(_pref)s<mdpr-<mode>> <F-CONTENT>.+</F-CONTENT>$
prefregex = ^%(__prefix_line)s<mdpr-<mode>> <F-CONTENT>.+</F-CONTENT>$
# Extended RE for normal mode to match reject by unknown users or undeliverable address, can be set to empty to avoid this:
exre-user = |[Uu](?:ser unknown|ndeliverable address) ; pragma: codespell-ignore
exre-user = |[Uu](?:ser unknown|ndeliverable address)
mdpr-normal = (?:(?:milter-)?reject:|(?:improper command pipelining|too many errors) after \S+)
mdre-normal=^%(_cmd)s from [^[]*\[<HOST>\]%(_port)s: [45][50][04] [45]\.\d\.\d+ (?:(?:<[^>]*>)?: )?(?:(?:Helo command|(?:Sender|Recipient) address) rejected: )?(?:Service unavailable|Access denied|(?:Client host|Command|Data command) rejected|Relay access denied|Malformed DNS server reply|(?:Host|Domain) not found|need fully-qualified hostname|match%(exre-user)s)\b
mdpr-normal = (?:\w+: (?:milter-)?reject:|(?:improper command pipelining|too many errors) after \S+)
mdre-normal=^%(_pref)s from [^[]*\[<HOST>\]%(_port)s: [45][50][04] [45]\.\d\.\d+ (?:(?:<[^>]*>)?: )?(?:(?:Helo command|(?:Sender|Recipient) address) rejected: )?(?:Service unavailable|(?:Client host|Command|Data command) rejected|Relay access denied|(?:Host|Domain) not found|need fully-qualified hostname|match%(exre-user)s)\b
^from [^[]*\[<HOST>\]%(_port)s:?
mdad-normal =
mdpr-auth = warning:
mdre-auth = ^[^[]*\[<HOST>\]%(_port)s: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:(?! Connection lost to authentication server| Invalid authentication mechanism)
mdre-auth2= ^[^[]*\[<HOST>\]%(_port)s: SASL ((?i)LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed:(?! Connection lost to authentication server)
# todo: check/remove "Invalid authentication mechanism" from ignore list, if gh-1243 will get finished (see gh-1297).
mdad-auth =
mdad-auth2 =
# Mode "rbl" currently included in mode "normal", but if needed for jail "postfix-rbl" only:
mdpr-rbl = %(mdpr-normal)s
mdre-rbl = ^%(_cmd)s from [^[]*\[<HOST>\]%(_port)s: [45]54 [45]\.7\.1 Service unavailable; Client host \[\S+\] blocked\b
mdad-rbl =
mdre-rbl = ^%(_pref)s from [^[]*\[<HOST>\]%(_port)s: [45]54 [45]\.7\.1 Service unavailable; Client host \[\S+\] blocked\b
# Mode "rbl" currently included in mode "normal" (within 1st rule)
mdpr-more = %(mdpr-normal)s
mdre-more = %(mdre-normal)s
mdad-more =
# Includes some of the log messages described in
# <http://www.postfix.org/POSTSCREEN_README.html>.
mdpr-ddos = (?:lost connection after (?!(?:DATA|AUTH)\b)[A-Z]+|disconnect(?= from \S+(?: \S+=\d+)* auth=0/(?:[1-9]|\d\d+))|(?:PREGREET \d+|HANGUP) after \S+|COMMAND (?:TIME|COUNT|LENGTH) LIMIT|warning:)
mdpr-ddos = (?:lost connection after(?! DATA) [A-Z]+|disconnect(?= from \S+(?: \S+=\d+)* auth=0/(?:[1-9]|\d\d+))|(?:PREGREET \d+|HANGUP) after \S+|COMMAND (?:TIME|COUNT|LENGTH) LIMIT)
mdre-ddos = ^from [^[]*\[<HOST>\]%(_port)s:?
mdad-ddos = ^(?:Message delivery request|Connection) rate limit exceeded: \d+ from [^[]*\[<ADDR>\]
mdpr-extra = (?:%(mdpr-auth)s|%(mdpr-normal)s)
mdre-extra = %(mdre-auth)s
%(mdre-normal)s
mdad-extra =
mdpr-aggressive = (?:%(mdpr-auth)s|%(mdpr-normal)s|%(mdpr-ddos)s)
mdre-aggressive = %(mdre-auth2)s
%(mdre-normal)s
mdad-aggressive = %(mdad-ddos)s
mdpr-errors = too many errors after \S+
mdre-errors = ^from [^[]*\[<HOST>\]%(_port)s$
mdad-errors =
failregex = <mdre-<mode>>
<mdad-<mode>>
# Parameter "mode": more (default combines normal and rbl), auth, normal, rbl, ddos, extra or aggressive (combines all)
# Usage example (for jail.local):
@ -89,6 +76,6 @@ ignoreregex =
[Init]
journalmatch = _SYSTEMD_UNIT=postfix.service _SYSTEMD_UNIT=postfix@-.service
journalmatch = _SYSTEMD_UNIT=postfix.service
# Author: Cyril Jaquier

View file

@ -1,20 +0,0 @@
# Fail2Ban filter for Proxmox Web GUI
#
# Jail example:
# [proxmox]
# enabled = true
# port = https,http,8006
# filter = proxmox
# logpath = /var/log/daemon.log
# maxretry = 3
# # 1 hour
# bantime = 3600
[Definition]
_daemon = pvedaemon
failregex = ^\s*\S+ %(_daemon)s\[\d+\]: authentication failure; rhost=<ADDR> user=<F-USER>\S+</F-USER>
ignoreregex =

View file

@ -19,34 +19,20 @@
# common.local
before = common.conf
[DEFAULT]
[Definition]
_daemon = (?:fail2ban(?:-server|\.actions)\s*)
# The name of the jail that this filter is used for. In jail.conf, name the jail using
# this filter 'recidive', or supply another name with `filter = recidive[_jailname="jail"]`,
# default all jails excepting recidive
_jailname = (?!recidive\])[^\]]*
# this filter 'recidive', or supply another name with `filter = recidive[_jailname="jail"]`
_jailname = recidive
failregex = ^%(__prefix_line)s(?:\s*fail2ban\.actions\s*%(__pid_re)s?:\s+)?NOTICE\s+\[<_jailname>\]\s+Ban\s+<HOST>
[lt_short]
_daemon = (?:fail2ban(?:-server|\.actions)?\s*)
failregex = ^%(__prefix_line)s(?:\s*fail2ban(?:\.actions)?\s*%(__pid_re)s?:\s+)?(?:NOTICE\s+)?\[<_jailname>\]\s+Ban\s+<HOST>
[lt_journal]
_daemon = <lt_short/_daemon>
failregex = <lt_short/failregex>
[Definition]
_daemon = <lt_<logtype>/_daemon>
failregex = <lt_<logtype>/failregex>
failregex = ^%(__prefix_line)s(?:\s*fail2ban\.actions\s*%(__pid_re)s?:\s+)?NOTICE\s+\[(?!%(_jailname)s\])(?:.*)\]\s+Ban\s+<HOST>\s*$
datepattern = ^{DATE}
ignoreregex =
journalmatch = _SYSTEMD_UNIT=fail2ban.service
journalmatch = _SYSTEMD_UNIT=fail2ban.service PRIORITY=5
# Author: Tom Hendrikx, modifications by Amir Caspi

View file

@ -13,9 +13,10 @@ before = common.conf
[Definition]
prefregex = ^\s*(\[\])?(%(__hostname)s\s*(?:roundcube(?:\[(\d*)\])?:)?\s*(<[\w]+>)? IMAP Error)?: (?:<[\w]+> )?<F-CONTENT>.+</F-CONTENT>$
prefregex = ^\s*(\[\])?(%(__hostname)s\s*(?:roundcube(?:\[(\d*)\])?:)?\s*(<[\w]+>)? IMAP Error)?: <F-CONTENT>.+</F-CONTENT>$
failregex = ^(?:Login failed|(?i:Failed) login) for <F-USER>(?:(?P<simple>\S+)|.*)</F-USER> (?:against \S+ )?from <ADDR>(?:(?:\([^\)]*\))?\.(?! from ) (?(simple)(?:\S+(?! from ) )*|(?:(?! from ).)*(?: user=(?P=user))? )in \S+\.php on line \d+| in session \w+)?(?: \([^\)]*\))?$
failregex = ^(?:FAILED login|Login failed) for <F-USER>.*</F-USER> from <HOST>(?:(?:\([^\)]*\))?\. (?:(?! from ).)*(?: user=(?P=user))? in \S+\.php on line \d+ \(\S+ \S+\))?$
^(?:<[\w]+> )?Failed login for <F-USER>.*</F-USER> from <HOST> in session \w+( \(error: \d\))?$
ignoreregex =

View file

@ -1,10 +0,0 @@
# Fail2Ban filter for failure attempts in MikroTik RouterOS
#
#
[Definition]
failregex = ^\s*\S+ system,error,critical login failure for user <F-USER>.*?</F-USER> from <ADDR> via \S+$
# Author: Vit Kabele <vit@kabele.me>

View file

@ -14,7 +14,7 @@
[Definition]
failregex = ^type=%(_type)s msg=audit\(:\d+\): (?:user )?pid=\d+ uid=%(_uid)s auid=%(_auid)s ses=\d+ subj=%(_subj)s msg='%(_msg)s'(?:\x1D|$)
failregex = ^type=%(_type)s msg=audit\(:\d+\): (user )?pid=\d+ uid=%(_uid)s auid=%(_auid)s ses=\d+ subj=%(_subj)s msg='%(_msg)s'$
ignoreregex =

View file

@ -15,13 +15,11 @@ _subj = (?:unconfined_u|system_u):system_r:sshd_t:s0-s0:c0\.c1023
_exe =/usr/sbin/sshd
_terminal = ssh
_anygrp = (?!acct=|exe=|addr=|terminal=|res=)\w+=(?:"[^"]+"|\S*)
_msg = (?:%(_anygrp)s )*acct=(?:"<F-USER>[^"]+</F-USER>"|<F-ALT_USER>\S+</F-ALT_USER>) exe="%(_exe)s" (?:%(_anygrp)s )*addr=<ADDR> terminal=%(_terminal)s res=failed
_msg = op=\S+ acct=(?P<_quote_acct>"?)\S+(?P=_quote_acct) exe="%(_exe)s" hostname=(\?|(\d+\.){3}\d+) addr=<HOST> terminal=%(_terminal)s res=failed
# DEV Notes:
#
# Note: USER_LOGIN is ignored as this is the duplicate message
# Note: USER_LOGIN is ignored as this is the duplicate messsage
# ssh logs after 3 USER_AUTH failures.
#
# Author: Daniel Black

View file

@ -22,28 +22,21 @@ before = common.conf
_daemon = (?:(sm-(mta|acceptingconnections)|sendmail))
__prefix_line = %(known/__prefix_line)s(?:\w{14,20}: )?
addr = (?:(?:IPv6:)?<IP6>|<IP4>)
# mta_dname -- matches name of MTA daemon (typically specified in DAEMON_OPTIONS),
# normally something without spaces like MTA-v4 or Deamon0, etc. If it'd contain spaces, one can
# rewrite it in jail using `filter = %(known/filter)s[mta_dname="[^,]+"]` or in .local overwrite
# of the filter. (we would not use catch-alls here to satisfy obscure artificial case).
mta_dname = \S+
prefregex = ^\s*(?:<mail\.[^\>]+> )?<F-MLFID>%(__prefix_line)s</F-MLFID><F-CONTENT>.+</F-CONTENT>$
prefregex = ^<F-MLFID>%(__prefix_line)s</F-MLFID><F-CONTENT>.+</F-CONTENT>$
cmnfailre = ^ruleset=check_rcpt, arg1=(?P<email><\S+@\S+>), relay=(\S+ )?\[%(addr)s\](?: \(may be forged\))?, reject=(?:550 5\.7\.1(?: (?P=email)\.\.\.)?(?: Relaying denied\.)? (?:IP name possibly forged \[(\d+\.){3}\d+\]|Proper authentication required\.|IP name lookup failed \[(\d+\.){3}\d+\]|Fix reverse DNS for \S+)|[45]5[13] [45]\.1\.8(?: (?P=email)\.\.\.)? Domain of sender address \S+ does not (?:exist|resolve)|550 5\.[71]\.1 (?P=email)\.\.\. (Rejected: .*|User unknown))$
cmnfailre = ^ruleset=check_rcpt, arg1=(?P<email><\S+@\S+>), relay=(\S+ )?\[%(addr)s\](?: \(may be forged\))?, reject=(?:550 5\.7\.1(?: (?P=email)\.\.\.)?(?: Relaying denied\.)? (?:IP name possibly forged \[(\d+\.){3}\d+\]|Proper authentication required\.|IP name lookup failed \[(\d+\.){3}\d+\]|Fix reverse DNS for \S+)|553 5\.1\.8(?: (?P=email)\.\.\.)? Domain of sender address \S+ does not exist|550 5\.[71]\.1 (?P=email)\.\.\. (Rejected: .*|User unknown))$
^ruleset=check_relay(?:, arg\d+=\S*)*, relay=(\S+ )?\[%(addr)s\](?: \(may be forged\))?, reject=421 4\.3\.2 (Connection rate limit exceeded\.|Too many open connections\.)$
^rejecting commands from (\S* )?\[%(addr)s\] due to pre-greeting traffic after \d+ seconds$
^(?:\S+ )?\[%(addr)s\]: (?:(?i)expn|vrfy) \S+ \[rejected\]$
^<[^@]+@[^>]+>\.\.\. (?:No such user here|User unknown)$
^<F-NOFAIL>from=<[^@]+@[^>]+></F-NOFAIL>, size=\d+, class=\d+, nrcpts=\d+,(?: bodytype=\w+,)? proto=E?SMTP, daemon=%(mta_dname)s, relay=(?:\S+ )?\[%(addr)s\]$
^<[^@]+@[^>]+>\.\.\. No such user here$
^<F-NOFAIL>from=<[^@]+@[^>]+></F-NOFAIL>, size=\d+, class=\d+, nrcpts=\d+, bodytype=\w+, proto=E?SMTP, daemon=MTA, relay=\S+ \[%(addr)s\]$
mdre-normal =
mdre-extra = ^(?:\S+ )?\[%(addr)s\](?: \(may be forged\))? did not issue \S+ during connection
mdre-aggressive = %(mdre-extra)s
^lost input channel from (?:\S+ )?\[%(addr)s\] to %(mta_dname)s after rcpt$
^ruleset=check_rcpt, arg1=(?P<email><\S+@\S+>), relay=(?:\S+ )?\[%(addr)s\](?: \(may be forged\))?, reject=(?:450 4\.4\.0(?: (?P=email)\.\.\.)?(?: Relaying temporarily denied\.)?(?: Cannot resolve PTR record for (\d+\.){3}\d+))$
failregex = %(cmnfailre)s
<mdre-<mode>>
@ -70,8 +63,6 @@ journalmatch = SYSLOG_IDENTIFIER=sm-mta + _SYSTEMD_UNIT=sendmail.service
# Note the capture <F-MLFID>, includes both the __prefix_lines (which includes
# the sendmail PID), but also the `\w{14}` which the the sendmail assigned
# mail ID (todo: check this is necessary, possible obsolete).
# Avoid moving <F-MLFID> into the entire prefregex because the grouped messages we
# need have different syslog levels (info vs notice) that break the group if BSD verbose format is set
#
# Author: Daniel Black, Fabian Wenk and Sergey Brester aka sebres.
# Rewritten using prefregex by Serg G. Brester.

View file

@ -13,11 +13,13 @@ before = common.conf
_daemon = slapd
prefregex = ^%(__prefix_line)sconn=<F-MLFID>\d+</F-MLFID>(?: (?:fd|op)=\d+){0,2} (?=ACCEPT|RESULT)<F-CONTENT>.+</F-CONTENT>$
failregex = ^<F-NOFAIL>ACCEPT</F-NOFAIL> from IP=<ADDR>:\d{1,5}\s+
^RESULT(?:\s(?!err)\S+=\S*)* err=49\b
failregex = ^(?P<__prefix>%(__prefix_line)s)conn=(?P<_conn_>\d+) fd=\d+ ACCEPT from IP=<HOST>:\d{1,5} \(IP=\S+\)\s*<SKIPLINES>(?P=__prefix)conn=(?P=_conn_) op=\d+ RESULT(?:\s(?!err)\S+=\S*)* err=49 text=[\w\s]*$
ignoreregex =
# Author: Andrii Melnyk, Sergey G. Brester
[Init]
# "maxlines" is number of log lines to buffer for multi-line regex searches
maxlines = 20
# Author: Andrii Melnyk

View file

@ -1,4 +1,4 @@
# Fail2ban filter for SOGo authentication
# Fail2ban filter for SOGo authentcation
#
# Log file usually in /var/log/sogo/sogo.log

View file

@ -16,7 +16,7 @@ before = common.conf
[DEFAULT]
_daemon = sshd(?:-session)?
_daemon = sshd
# optional prefix (logged from several ssh versions) like "error: ", "error: PAM: " or "fatal: "
__pref = (?:(?:error|fatal): (?:PAM: )?)?
@ -24,8 +24,8 @@ __pref = (?:(?:error|fatal): (?:PAM: )?)?
#__suff = (?: port \d+)?(?: \[preauth\])?\s*
__suff = (?: (?:port \d+|on \S+|\[preauth\])){0,3}\s*
__on_port_opt = (?: (?:port \d+|on \S+)){0,2}
# close by authenticating user (don't use <HOST> after %(__authng_user)s because of catch-all `.*?`):
__authng_user = (?: (?:by|from))?(?: (?:invalid|authenticating) user <F-USER>\S+|.*?</F-USER>)?(?: from)?
# close by authenticating user:
__authng_user = (?: (?:invalid|authenticating) user <F-USER>\S+|.*?</F-USER>)?
# for all possible (also future) forms of "no matching (cipher|mac|MAC|compression method|key exchange method|host key type) found",
# see ssherr.c for all possible SSH_ERR_..._ALG_MATCH errors.
@ -38,21 +38,21 @@ __pam_auth = pam_[a-z]+
prefregex = ^<F-MLFID>%(__prefix_line)s</F-MLFID>%(__pref)s<F-CONTENT>.+</F-CONTENT>$
cmnfailre = ^[aA]uthentication (?:failure|error|failed) for <F-USER>.*?</F-USER> (?:from )?<HOST>( via \S+)?%(__suff)s$
^User not known to the underlying authentication module for <F-USER>.*?</F-USER> (?:from )?<HOST>%(__suff)s$
cmnfailre = ^[aA]uthentication (?:failure|error|failed) for <F-USER>.*</F-USER> from <HOST>( via \S+)?%(__suff)s$
^User not known to the underlying authentication module for <F-USER>.*</F-USER> from <HOST>%(__suff)s$
<cmnfailre-failed-pub-<publickey>>
^Failed <cmnfailed> for (?P<cond_inv>invalid user )?<F-USER>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
^<F-USER>ROOT</F-USER> LOGIN REFUSED FROM <HOST>
^[iI](?:llegal|nvalid) user <F-USER>.*?</F-USER> (?:from )?<HOST>%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> (?:from )?<HOST> not allowed because not listed in AllowUsers%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> (?:from )?<HOST> not allowed because listed in DenyUsers%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> (?:from )?<HOST> not allowed because not in any group%(__suff)s$
^[iI](?:llegal|nvalid) user <F-USER>.*?</F-USER> from <HOST>%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> from <HOST> not allowed because not listed in AllowUsers%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> from <HOST> not allowed because listed in DenyUsers%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> from <HOST> not allowed because not in any group%(__suff)s$
^refused connect from \S+ \(<HOST>\)
^Received <F-MLFFORGET>disconnect</F-MLFFORGET> from <HOST>%(__on_port_opt)s:\s*3: .*: Auth fail%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> (?:from )?<HOST> not allowed because a group is listed in DenyGroups%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> (?:from )?<HOST> not allowed because none of user's groups are listed in AllowGroups%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> from <HOST> not allowed because a group is listed in DenyGroups%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> from <HOST> not allowed because none of user's groups are listed in AllowGroups%(__suff)s$
^<F-NOFAIL>%(__pam_auth)s\(sshd:auth\):\s+authentication failure;</F-NOFAIL>(?:\s+(?:(?:logname|e?uid|tty)=\S*)){0,4}\s+ruser=<F-ALT_USER>\S*</F-ALT_USER>\s+rhost=<HOST>(?:\s+user=<F-USER>\S*</F-USER>)?%(__suff)s$
^maximum authentication attempts exceeded for (?:invalid user )?<F-USER>.*?</F-USER> (?:from )?<HOST>%(__on_port_opt)s(?: ssh\d*)?%(__suff)s$
^maximum authentication attempts exceeded for <F-USER>.*</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?%(__suff)s$
^User <F-USER>\S+|.*?</F-USER> not allowed because account is locked%(__suff)s
^<F-MLFFORGET>Disconnecting</F-MLFFORGET>(?: from)?(?: (?:invalid|authenticating)) user <F-USER>\S+</F-USER> <HOST>%(__on_port_opt)s:\s*Change of username or service not allowed:\s*.*\[preauth\]\s*$
^Disconnecting: Too many authentication failures(?: for <F-USER>\S+|.*?</F-USER>)?%(__suff)s$
@ -68,25 +68,24 @@ cmnfailed = <cmnfailed-<publickey>>
mdre-normal =
# used to differentiate "connection closed" with and without `[preauth]` (fail/nofail cases in ddos mode)
mdre-normal-other = ^<F-NOFAIL><F-MLFFORGET>(?:Connection (?:closed|reset)|Disconnect(?:ed|ing))</F-MLFFORGET></F-NOFAIL>%(__authng_user)s <ADDR>%(__on_port_opt)s(?:: (?!Too many authentication failures)[^\[]+)?(?: \[preauth\])?\s*$
mdre-normal-other = ^<F-NOFAIL><F-MLFFORGET>(Connection (?:closed|reset)|Disconnected)</F-MLFFORGET></F-NOFAIL> (?:by|from)%(__authng_user)s <HOST>(?:%(__suff)s|\s*)$
mdre-ddos = ^(?:Did not receive identification string from|Timeout before authentication for(?: connection from)?) <HOST>
mdre-ddos = ^Did not receive identification string from <HOST>
^kex_exchange_identification: (?:read: )?(?:[Cc]lient sent invalid protocol identifier|[Cc]onnection (?:closed by remote host|reset by peer))
^Bad protocol version identification '(?:[^']|.*?)' (?:from )?<HOST>%(__suff)s$
^Bad protocol version identification '.*' from <HOST>
^<F-NOFAIL>SSH: Server;Ltype:</F-NOFAIL> (?:Authname|Version|Kex);Remote: <HOST>-\d+;[A-Z]\w+:
^Read from socket failed: Connection <F-MLFFORGET>reset</F-MLFFORGET> by peer
^(?:banner exchange|ssh_dispatch_run_fatal): Connection from <HOST><__on_port_opt>: (?:invalid format|(?:message authentication code incorrect|[Cc]onnection corrupted) \[preauth\])
^banner exchange: Connection from <HOST><__on_port_opt>: invalid format
# same as mdre-normal-other, but as failure (without <F-NOFAIL> with [preauth] and with <F-NOFAIL> on no preauth phase as helper to identify address):
mdre-ddos-other = ^<F-MLFFORGET>(?:Connection (?:closed|reset)|Disconnect(?:ed|ing))</F-MLFFORGET>%(__authng_user)s <ADDR>%(__on_port_opt)s(?:: (?!Too many authentication failures)[^\[]+)?\s+\[preauth\]\s*$
^<F-NOFAIL><F-MLFFORGET>(?:Connection (?:closed|reset)|Disconnect(?:ed|ing))</F-MLFFORGET></F-NOFAIL>%(__authng_user)s <ADDR>(?:%(__on_port_opt)s(?:: (?!Too many authentication failures)[^\[]+)?|\s*)$
mdre-ddos-other = ^<F-MLFFORGET>(Connection (?:closed|reset)|Disconnected)</F-MLFFORGET> (?:by|from)%(__authng_user)s <HOST>%(__on_port_opt)s\s+\[preauth\]\s*$
^<F-NOFAIL><F-MLFFORGET>(Connection (?:closed|reset)|Disconnected)</F-MLFFORGET></F-NOFAIL> (?:by|from)%(__authng_user)s <HOST>(?:%(__on_port_opt)s|\s*)$
mdre-extra = ^Received <F-MLFFORGET>disconnect</F-MLFFORGET> from <HOST>%(__on_port_opt)s:\s*14: No(?: supported)? authentication methods available
^Unable to negotiate with <HOST>%(__on_port_opt)s: no matching <__alg_match> found.
^Unable to negotiate a <__alg_match>
^no matching <__alg_match> found:
# part of mdre-ddos-other, but user name is supplied (invalid/authenticating) on [preauth] phase only:
mdre-extra-other = ^<F-MLFFORGET>Disconnected</F-MLFFORGET>(?: from)?(?: (?:invalid|authenticating)) user <F-USER>\S+|.*?</F-USER> (?:from )?<HOST>%(__on_port_opt)s \[preauth\]\s*$
mdre-extra-other = ^<F-MLFFORGET>Disconnected</F-MLFFORGET>(?: from)?(?: (?:invalid|authenticating)) user <F-USER>\S+|.*?</F-USER> <HOST>%(__on_port_opt)s \[preauth\]\s*$
mdre-aggressive = %(mdre-ddos)s
%(mdre-extra)s
@ -126,7 +125,7 @@ ignoreregex =
maxlines = 1
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd + _COMM=sshd-session
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd
# DEV Notes:
#

View file

@ -5,7 +5,7 @@
#
# To use 'traefik-auth' filter you have to configure your Traefik instance to write
# the access logs as describe in https://docs.traefik.io/configuration/logs/#access-logs
# into a log file on host and specify users for Basic Authentication
# into a log file on host and specifiy users for Basic Authentication
# https://docs.traefik.io/configuration/entrypoints/#basic-authentication
#
# Example:
@ -51,7 +51,7 @@
[Definition]
# Parameter "method" can be used to specify request method
# Parameter "method" can be used to specifiy request method
req-method = \S+
# Usage example (for jail.local):
# filter = traefik-auth[req-method="GET|POST|HEAD"]

View file

@ -1,8 +0,0 @@
# Fail2Ban filter for unsuccessful Vaultwarden authentication attempts
# Logged in /var/log/vaultwarden.log
# Author: LearningSpot
[Definition]
failregex = ^\s*(?:\[\]\s*)?\[vaultwarden::api::(?:identity|admin|core::two_factor::authenticator)?\]\[ERROR\] (?:Invalid admin token|Invalid TOTP code|Username or password is incorrect)[\.!](?:\s+(?!IP:)\S+)* IP: <ADDR>(?:\. Username: <F-USER>\S+</F-USER>)?
ignoreregex =

View file

@ -10,13 +10,13 @@ before = common.conf
[Definition]
__pam_re=(?:\(?%(__pam_auth)s(?:\(\S+\))?\)?:?\s+)?
__pam_re=\(?%(__pam_auth)s(?:\(\S+\))?\)?:?
_daemon = vsftpd
failregex = ^%(__prefix_line)s%(__pam_re)sauthentication failure; logname=<F-ALT_USER1>\S*</F-ALT_USER1> uid=\S* euid=\S* tty=(?:ftp)? ruser=<F-USER>\S*</F-USER> rhost=<HOST>(?:\s+user=<F-ALT_USER>\S*</F-ALT_USER>)?\s*$
^(?:\s*\[pid \d+\] |%(__prefix_line)s)\[<F-USER>[^\]]+</F-USER>\] FAIL LOGIN: Client "<HOST>"(?:\s*$|,)
failregex = ^%(__prefix_line)s%(__pam_re)s\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=(ftp)? ruser=\S* rhost=<HOST>(?:\s+user=.*)?\s*$
^ \[pid \d+\] \[[^\]]+\] FAIL LOGIN: Client "<HOST>"(?:\s*$|,)
ignoreregex =
ignoreregex =
# Authors: Cyril Jaquier, Lucian Maly <lmaly@redhat.com>
# Author: Cyril Jaquier
# Documentation from fail2ban wiki

View file

@ -1,35 +0,0 @@
#
# Fail2Ban filter for XRDP
#
# Detects login attempts with invalid credentials
#
# Requirements:
# - xrdp >= 0.9.19
# - The log level in sesman.ini should be set to `INFO` or higher
# to emit the log messages needed for this filter.
#
# Author: Evan Linde
#
[INCLUDES]
# Read common prefixes. If any customizations available -- read them from
# common.local
before = common.conf
[DEFAULT]
_daemon = xrdp-sesman
[Definition]
authfail_re = \[INFO \] AUTHFAIL: user=<F-USER>(?:\S+|.+)</F-USER> ip=<ADDR> time=\d+
failregex = ^%(__prefix_line)s%(authfail_re)s$
ignoreregex =
datepattern = ^\[?%%ExY%%Exm%%Exd-%%ExH:%%ExM:%%ExS\]?
^{DATE}

View file

@ -97,9 +97,7 @@ before = paths-debian.conf
# ignorecommand = /path/to/command <ip>
ignorecommand =
# "bantime" is the amount of time that a host is banned, integer in seconds or
# time abbreviation format (m - minutes, h - hours, d - days, w - weeks, mo - months, y - years).
# This is to consider as an initial time if bantime.increment gets enabled.
# "bantime" is the number of seconds that a host is banned.
bantime = 10m
# A host is banned if it has generated "maxretry" during the last "findtime"
@ -113,17 +111,19 @@ maxretry = 5
maxmatches = %(maxretry)s
# "backend" specifies the backend used to get files modification.
# Available options are "pyinotify", "polling", "systemd" and "auto".
# Available options are "pyinotify", "gamin", "polling", "systemd" and "auto".
# This option can be overridden in each jail as well.
#
# pyinotify: requires pyinotify (a file alteration monitor) to be installed.
# If pyinotify is not installed, Fail2ban will use auto.
# gamin: requires Gamin (a file alteration monitor) to be installed.
# If Gamin is not installed, Fail2ban will use auto.
# polling: uses a polling algorithm which does not require external libraries.
# systemd: uses systemd python library to access the systemd journal.
# Specifying "logpath" is not valid for this backend.
# See "journalmatch" in the jails associated filter config
# auto: will try to use the following backends, in order:
# pyinotify, polling.
# pyinotify, gamin, polling.
#
# Note: if systemd backend is chosen as the default but you enable a jail
# for which logs are present only in its own log files, specify some other
@ -205,8 +205,8 @@ fail2ban_agent = Fail2Ban/%(fail2ban_version)s
# iptables-multiport, shorewall, etc) It is used to define
# action_* variables. Can be overridden globally or per
# section within jail.local file
#banaction = iptables-multiport
#banaction_allports = iptables-allports
banaction = iptables-multiport
banaction_allports = iptables-allports
# The simplest action to take: ban only
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
@ -227,11 +227,14 @@ action_mwl = %(action_)s
action_xarf = %(action_)s
xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath="%(logpath)s", port="%(port)s"]
# ban & send a notification to one or more of the 120+ services supported by Apprise.
# ban & send a notification to one or more of the 50+ services supported by Apprise.
# See https://github.com/caronc/apprise/wiki for details on what is supported.
#
# You may optionally over-ride the default configuration line (containing the Apprise URLs)
# by using 'apprise[config="/alternate/path/to/apprise.cfg"]' otherwise
# /etc/fail2ban/apprise.conf is sourced for your supported notification configuration.
# action = %(action_)s
# apprise[config="/alternate/path/to/apprise.yaml", args='--tag fail2ban']
# See https://appriseit.com/services/ for details on what is supported.
# Or action.d/apprise.conf for more details how to configure or customize it.
# apprise
# ban IP on CloudFlare & send an e-mail with whois report and relevant log lines
# to the destemail.
@ -392,10 +395,6 @@ logpath = %(nginx_error_log)s
port = http,https
logpath = %(nginx_access_log)s
[nginx-forbidden]
port = http,https
logpath = %(nginx_error_log)s
# Ban attackers that try to use PHP's URL-fopen() functionality
# through GET/POST variables. - Experimental, with more than a year
# of usage in production environments.
@ -498,7 +497,7 @@ backend = %(syslog_backend)s
[froxlor-auth]
port = http,https
logpath = %(syslog_user)s
logpath = %(syslog_authpriv)s
backend = %(syslog_backend)s
@ -782,11 +781,17 @@ logpath = /var/lib/znc/moddata/adminlog/znc.log
# To log wrong MySQL access attempts add to /etc/my.cnf in [mysqld] or
# equivalent section:
# log_error_verbosity = 3
# for older versions:
# log-warnings = 2
# Also check whether `log_error` (or `log-error`) system variable match the `logpath`.
# log-warnings = 2
#
# for syslog (daemon facility)
# [mysqld_safe]
# syslog
#
# for own logfile
# [mysqld]
# log-error=/var/log/mysqld.log
[mysqld-auth]
port = 3306
logpath = %(mysql_log)s
backend = %(mysql_backend)s
@ -953,9 +958,6 @@ port = http,https
logpath = %(syslog_authpriv)s
backend = %(syslog_backend)s
[routeros-auth]
port = ssh,http,https
logpath = /var/log/MikroTik/router.log
[zoneminder]
# Zoneminder HTTP/HTTPS web interface auth
@ -969,10 +971,6 @@ logpath = %(apache_error_log)s
port = http,https
logpath = /var/log/traefik/access.log
[openvpn]
port = 443
logpath = /var/log/syslog
[scanlogd]
logpath = %(syslog_local0)s
banaction = %(banaction_allports)s
@ -980,19 +978,3 @@ banaction = %(banaction_allports)s
[monitorix]
port = 8080
logpath = /var/log/monitorix-httpd
[dante]
port = 1080
logpath = %(syslog_daemon)s
[proxmox]
port = https,http,8006
logpath = /var/log/daemon.log
[vaultwarden]
port = http,https
logpath = /var/log/vaultwarden.log
[xrdp]
port = 3389
logpath = /var/log/xrdp-sesman.log

View file

@ -67,7 +67,7 @@ proftpd_backend = %(default_backend)s
pureftpd_log = %(syslog_ftp)s
pureftpd_backend = %(default_backend)s
# ftp, daemon and then local7 are tried at configure time however it is overwritable at configure time
# ftp, daemon and then local7 are tried at configure time however it is overwriteable at configure time
#
wuftpd_log = %(syslog_ftp)s
wuftpd_backend = %(default_backend)s
@ -87,12 +87,7 @@ dovecot_backend = %(default_backend)s
# Seems to be set at compile time only to LOG_LOCAL0 (src/const.h) at Notice level
solidpop3d_log = %(syslog_local0)s
mysql_log = /var/log/mariadb/mariadb.log
/var/log/mariadb/error.log
/var/log/mysql/mysqld.log
/var/log/mysql/error.log
/var/log/mysqld.log
mysql_log = %(syslog_daemon)s
mysql_backend = %(default_backend)s
roundcube_errors_log = /var/log/roundcube/errors

View file

@ -9,12 +9,6 @@ after = paths-overrides.local
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
sshd_backend = systemd
postfix_backend = systemd
syslog_mail = /var/log/mail.log
# control the `mail.warn` setting, see `/etc/rsyslog.d/50-default.conf` (if commented `mail.*` wins).

View file

@ -47,9 +47,12 @@ copyright = u'2014'
#
from fail2ban.version import version as fail2ban_version
from distutils.version import LooseVersion
fail2ban_loose_version = LooseVersion(fail2ban_version)
# The short X.Y version.
version = ".".join(str(_) for _ in fail2ban_version.split(".")[:2])
version = ".".join(str(_) for _ in fail2ban_loose_version.version[:2])
# The full version, including alpha/beta/rc tags.
release = fail2ban_version

View file

@ -0,0 +1,7 @@
fail2ban.server.filtergamin module
==================================
.. automodule:: fail2ban.server.filtergamin
:members:
:undoc-members:
:show-inheritance:

View file

@ -13,6 +13,7 @@ fail2ban.server package
fail2ban.server.failmanager
fail2ban.server.failregex
fail2ban.server.filter
fail2ban.server.filtergamin
fail2ban.server.filterpoll
fail2ban.server.filterpyinotify
fail2ban.server.filtersystemd

14
fail2ban-2to3 Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
# This script carries out conversion of fail2ban to python3
# A backup of any converted files are created with ".bak"
# extension
set -eu
if 2to3 -w --no-diffs bin/* fail2ban;then
echo "Success!" >&2
exit 0
else
echo "Fail!" >&2
exit 1
fi

View file

@ -89,11 +89,11 @@ class ActionReader(DefinitionInitConfigReader):
stream = list()
stream.append(head + ["addaction", self._name])
multi = []
for opt, optval in opts.items():
for opt, optval in opts.iteritems():
if opt in self._configOpts and not opt.startswith('known/'):
multi.append([opt, optval])
if self._initOpts:
for opt, optval in self._initOpts.items():
for opt, optval in self._initOpts.iteritems():
if opt not in self._configOpts and not opt.startswith('known/'):
multi.append([opt, optval])
if len(multi) > 1:

View file

@ -21,10 +21,8 @@ __author__ = "Cyril Jaquier, Yaroslav Halchenko"
__copyright__ = "Copyright (c) 2004 Cyril Jaquier, 2013- Yaroslav Halchenko"
__license__ = "GPL"
import sys
from ..exceptions import UnknownJailException, DuplicateJailException
from ..helpers import getLogger, logging, PREFER_ENC
from ..helpers import getLogger, logging
# Gets the instance of the logger.
logSys = getLogger(__name__)
@ -38,11 +36,6 @@ logSys = getLogger(__name__)
class Beautifier:
stdoutEnc = PREFER_ENC
if sys.stdout and sys.stdout.encoding is not None:
stdoutEnc = sys.stdout.encoding
encUtf = 1 if stdoutEnc.lower() == 'utf-8' else 0
def __init__(self, cmd = None):
self.__inputCmd = cmd
@ -78,84 +71,24 @@ class Beautifier:
elif inC[0] == "echo":
msg = ' '.join(msg)
elif inC[0:1] == ['status']:
def jail_stat(response, pref=""):
# Display jail information
if len(inC) > 1:
# Display information
msg = ["Status for the jail: %s" % inC[1]]
for n, res1 in enumerate(response):
prefix1 = pref + ("`-" if n == len(response) - 1 else "|-")
prefix1 = "`-" if n == len(response) - 1 else "|-"
msg.append("%s %s" % (prefix1, res1[0]))
prefix1 = pref + (" " if n == len(response) - 1 else "| ")
prefix1 = " " if n == len(response) - 1 else "| "
for m, res2 in enumerate(res1[1]):
prefix2 = prefix1 + ("`-" if m == len(res1[1]) - 1 else "|-")
val = " ".join(map(str, res2[1])) if isinstance(res2[1], list) else res2[1]
msg.append("%s %s:\t%s" % (prefix2, res2[0], val))
if len(inC) > 1 and inC[1] != "--all":
msg = ["Status for the jail: %s" % inC[1]]
jail_stat(response)
else:
jstat = None
if len(inC) > 1: # --all
jstat = response[-1]
response = response[:-1]
msg = ["Status"]
for n, res1 in enumerate(response):
prefix1 = "`-" if not jstat and n == len(response) - 1 else "|-"
prefix1 = "`-" if n == len(response) - 1 else "|-"
val = " ".join(map(str, res1[1])) if isinstance(res1[1], list) else res1[1]
msg.append("%s %s:\t%s" % (prefix1, res1[0], val))
if jstat:
msg.append("`- Status for the jails:")
i = 0
for n, j in jstat.items():
i += 1
prefix1 = "`-" if i == len(jstat) else "|-"
msg.append(" %s Jail: %s" % (prefix1, n))
jail_stat(j, " " if i == len(jstat) else " | ")
msg = "\n".join(msg)
elif inC[0:1] == ['stats'] or inC[0:1] == ['statistics']:
chrTable = [
['|', '-', '|', 'x', 'x', '-', '|', '-'], ## ascii
["\u2551", "\u2550", "\u255F", "\u256B", "\u256C", "\u2569", "\u2502", "\u2500"] ## utf-8
];
def _statstable(response, ct):
tophead = ["Jail", "Backend", "Filter", "Actions"]
headers = ["", "", "cur", "tot", "cur", "tot"]
minlens = [8, 8, 3, 3, 3, 3]
ralign = [0, 0, 1, 1, 1, 1]
rows = [[n, r[0], *r[1], *r[2]] for n, r in response.items()]
lens = []
for i in range(len(rows[0])):
col = (len(str(s[i])) for s in rows)
lens.append(max(minlens[i], max(col)))
rfmt = []
hfmt = []
for i in range(len(rows[0])):
f = "%%%ds" if ralign[i] else "%%-%ds"
rfmt.append(f % lens[i])
hfmt.append(f % lens[i])
rfmt = [rfmt[0], rfmt[1], "%s %s %s" % (rfmt[2], ct[6], rfmt[3]), "%s %s %s" % (rfmt[4], ct[6], rfmt[5])]
hfmt = [hfmt[0], hfmt[1], "%s %s %s" % (hfmt[2], ct[6], hfmt[3]), "%s %s %s" % (hfmt[4], ct[6], hfmt[5])]
tlens = [lens[0], lens[1], 3 + lens[2] + lens[3], 3 + lens[4] + lens[5]]
tfmt = [hfmt[0], hfmt[1], "%%-%ds" % (tlens[2],), "%%-%ds" % (tlens[3],)]
tsep = tfmt[0:2]
rfmt = (" "+ct[0]+" ").join(rfmt)
hfmt = (" "+ct[0]+" ").join(hfmt)
tfmt = (" "+ct[0]+" ").join(tfmt)
tsep = (" "+ct[0]+" ").join(tsep)
separator = ((tsep % tuple(tophead[0:2])) + " "+ct[2]+ct[7] +
((ct[7]+ct[3]+ct[7]).join([ct[7] * n for n in tlens[2:]])) + ct[7])
ret = []
ret.append(" "+tfmt % tuple(["", ""]+tophead[2:]))
ret.append(" "+separator)
ret.append(" "+hfmt % tuple(headers))
separator = (ct[1]+ct[4]+ct[1]).join([ct[1] * n for n in tlens]) + ct[1]
ret.append(ct[1]+separator)
for row in rows:
ret.append(" "+rfmt % tuple(row))
separator = (ct[1]+ct[5]+ct[1]).join([ct[1] * n for n in tlens]) + ct[1]
ret.append(ct[1]+separator)
return ret
if not response:
return "No jails found."
msg = "\n".join(_statstable(response, chrTable[self.encUtf]))
elif len(inC) < 2:
pass # to few cmd args for below
elif inC[1] == "syslogsocket":
@ -212,8 +145,8 @@ class Beautifier:
else:
msg = "These IP addresses/networks are ignored:\n"
for ip in response[:-1]:
msg += "|- " + str(ip) + "\n"
msg += "`- " + str(response[-1])
msg += "|- " + ip + "\n"
msg += "`- " + response[-1]
elif inC[2] in ("failregex", "addfailregex", "delfailregex",
"ignoreregex", "addignoreregex", "delignoreregex"):
if len(response) == 0:

View file

@ -29,36 +29,49 @@ import re
import sys
from ..helpers import getLogger
# SafeConfigParser deprecated from Python 3.2 (renamed to ConfigParser)
from configparser import ConfigParser as SafeConfigParser, BasicInterpolation, \
InterpolationMissingOptionError, NoOptionError, NoSectionError
if sys.version_info >= (3,): # pragma: 2.x no cover
# And interpolation of __name__ was simply removed, thus we need to
# decorate default interpolator to handle it
class BasicInterpolationWithName(BasicInterpolation):
"""Decorator to bring __name__ interpolation back.
# SafeConfigParser deprecated from Python 3.2 (renamed to ConfigParser)
from configparser import ConfigParser as SafeConfigParser, BasicInterpolation, \
InterpolationMissingOptionError, NoOptionError, NoSectionError
Original handling of __name__ was removed because of
functional deficiencies: http://bugs.python.org/issue10489
# And interpolation of __name__ was simply removed, thus we need to
# decorate default interpolator to handle it
class BasicInterpolationWithName(BasicInterpolation):
"""Decorator to bring __name__ interpolation back.
commit v3.2a4-105-g61f2761
Author: Lukasz Langa <lukasz@langa.pl>
Date: Sun Nov 21 13:41:35 2010 +0000
Original handling of __name__ was removed because of
functional deficiencies: http://bugs.python.org/issue10489
Issue #10489: removed broken `__name__` support from configparser
commit v3.2a4-105-g61f2761
Author: Lukasz Langa <lukasz@langa.pl>
Date: Sun Nov 21 13:41:35 2010 +0000
But should be fine to reincarnate for our use case
"""
def _interpolate_some(self, parser, option, accum, rest, section, map,
*args, **kwargs):
if section and not (__name__ in map):
map = map.copy() # just to be safe
map['__name__'] = section
# try to wrap section options like %(section/option)s:
parser._map_section_options(section, option, rest, map)
return super(BasicInterpolationWithName, self)._interpolate_some(
parser, option, accum, rest, section, map, *args, **kwargs)
Issue #10489: removed broken `__name__` support from configparser
But should be fine to reincarnate for our use case
"""
def _interpolate_some(self, parser, option, accum, rest, section, map,
*args, **kwargs):
if section and not (__name__ in map):
map = map.copy() # just to be safe
map['__name__'] = section
# try to wrap section options like %(section/option)s:
parser._map_section_options(section, option, rest, map)
return super(BasicInterpolationWithName, self)._interpolate_some(
parser, option, accum, rest, section, map, *args, **kwargs)
else: # pragma: 3.x no cover
from ConfigParser import SafeConfigParser, \
InterpolationMissingOptionError, NoOptionError, NoSectionError
# Interpolate missing known/option as option from default section
SafeConfigParser._cp_interpolate_some = SafeConfigParser._interpolate_some
def _interpolate_some(self, option, accum, rest, section, map, *args, **kwargs):
# try to wrap section options like %(section/option)s:
self._map_section_options(section, option, rest, map)
return self._cp_interpolate_some(option, accum, rest, section, map, *args, **kwargs)
SafeConfigParser._interpolate_some = _interpolate_some
def _expandConfFilesWithLocal(filenames):
"""Expands config files with local extension.
@ -116,14 +129,20 @@ after = 1.conf
CONDITIONAL_RE = re.compile(r"^(\w+)(\?.+)$")
# overload constructor only for fancy new Python3's
def __init__(self, share_config=None, *args, **kwargs):
kwargs = kwargs.copy()
kwargs['interpolation'] = BasicInterpolationWithName()
kwargs['inline_comment_prefixes'] = ";"
super(SafeConfigParserWithIncludes, self).__init__(
*args, **kwargs)
self._cfg_share = share_config
if sys.version_info >= (3,2):
# overload constructor only for fancy new Python3's
def __init__(self, share_config=None, *args, **kwargs):
kwargs = kwargs.copy()
kwargs['interpolation'] = BasicInterpolationWithName()
kwargs['inline_comment_prefixes'] = ";"
super(SafeConfigParserWithIncludes, self).__init__(
*args, **kwargs)
self._cfg_share = share_config
else:
def __init__(self, share_config=None, *args, **kwargs):
SafeConfigParser.__init__(self, *args, **kwargs)
self._cfg_share = share_config
def get_ex(self, section, option, raw=False, vars={}):
"""Get an option value for a given section.
@ -308,7 +327,7 @@ after = 1.conf
# mix it with defaults:
return set(opts.keys()) | set(self._defaults)
# only own option names:
return list(opts.keys())
return opts.keys()
def read(self, filenames, get_includes=True):
if not isinstance(filenames, list):
@ -337,7 +356,7 @@ after = 1.conf
ret += i
# merge defaults and all sections to self:
alld.update(cfg.get_defaults())
for n, s in cfg.get_sections().items():
for n, s in cfg.get_sections().iteritems():
# conditional sections
cond = SafeConfigParserWithIncludes.CONDITIONAL_RE.match(n)
if cond:
@ -347,14 +366,14 @@ after = 1.conf
del(s['__name__'])
except KeyError:
pass
for k in list(s.keys()):
for k in s.keys():
v = s.pop(k)
s[k + cond] = v
s2 = alls.get(n)
if isinstance(s2, dict):
# save previous known values, for possible using in local interpolations later:
self.merge_section('KNOWN/'+n,
dict([i for i in iter(s2.items()) if i[0] in s]), '')
dict(filter(lambda i: i[0] in s, s2.iteritems())), '')
# merge section
s2.update(s)
else:
@ -366,7 +385,10 @@ after = 1.conf
if logSys.getEffectiveLevel() <= logLevel:
logSys.log(logLevel, " Reading file: %s", fileNamesFull[0])
# read file(s) :
return SafeConfigParser.read(self, fileNamesFull, encoding='utf-8')
if sys.version_info >= (3,2): # pragma: no cover
return SafeConfigParser.read(self, fileNamesFull, encoding='utf-8')
else:
return SafeConfigParser.read(self, fileNamesFull)
def merge_section(self, section, options, pref=None):
alls = self.get_sections()
@ -378,7 +400,7 @@ after = 1.conf
sec.update(options)
return
sk = {}
for k, v in options.items():
for k, v in options.iteritems():
if not k.startswith(pref) and k != '__name__':
sk[pref+k] = v
sec.update(sk)

View file

@ -26,7 +26,7 @@ __license__ = "GPL"
import glob
import os
from configparser import NoOptionError, NoSectionError
from ConfigParser import NoOptionError, NoSectionError
from .configparserinc import sys, SafeConfigParserWithIncludes, logLevel
from ..helpers import getLogger, _as_bool, _merge_dicts, substituteRecursiveTags
@ -98,7 +98,7 @@ class ConfigReader():
def read(self, name, once=True):
""" Overloads a default (not shared) read of config reader.
To prevent multiple reads of config files with it includes, reads into
To prevent mutiple reads of config files with it includes, reads into
the config reader, if it was not yet cached/shared by 'name'.
"""
# already shared ?
@ -183,7 +183,7 @@ class ConfigReader():
class ConfigReaderUnshared(SafeConfigParserWithIncludes):
"""Unshared config reader (previously ConfigReader).
Do not use this class (internal not shared/cached representation).
Do not use this class (internal not shared/cached represenation).
Use ConfigReader instead.
"""
@ -221,7 +221,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
config_files += sorted(glob.glob('%s/*.local' % config_dir))
# choose only existing ones
config_files = list(filter(os.path.exists, config_files))
config_files = filter(os.path.exists, config_files)
if len(config_files):
# at least one config exists and accessible
@ -230,7 +230,6 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
missed = [ cf for cf in config_files if cf not in config_files_read ]
if missed:
logSys.error("Could not read config files: %s", ', '.join(missed))
return False
if config_files_read:
return True
logSys.error("Found no accessible config files for %r under %s",
@ -278,7 +277,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
# TODO: validate error handling here.
except NoOptionError:
if not optvalue is None:
logSys.debug("'%s' not defined in '%s'. Using default one: %r"
logSys.warning("'%s' not defined in '%s'. Using default one: %r"
% (optname, sec, optvalue))
values[optname] = optvalue
# elif logSys.getEffectiveLevel() <= logLevel:
@ -354,11 +353,6 @@ class DefinitionInitConfigReader(ConfigReader):
if v is None: v = getopt(opt)
self._initOpts['known/'+opt] = v
if opt not in self._initOpts:
# overwrite also conditional init options (from init?... section):
cond = SafeConfigParserWithIncludes.CONDITIONAL_RE.match(opt)
if cond:
optc, cond = cond.groups()
v = pOpts.get(optc, v)
if v is None: v = getopt(opt)
self._initOpts[opt] = v
if all and self.has_section("Definition"):
@ -412,7 +406,7 @@ class DefinitionInitConfigReader(ConfigReader):
if cond:
n, cond = cond.groups()
ignore.add(n)
# substitute options already specified direct:
# substiture options already specified direct:
opts = substituteRecursiveTags(combinedopts,
ignore=ignore, addrepl=self.getCombOption)
if not opts:

View file

@ -63,13 +63,11 @@ class Configurator:
return fail2ban_basedir
def readEarly(self):
if not self.__fail2ban.read():
raise LookupError("Read fail2ban configuration failed.")
self.__fail2ban.read()
def readAll(self):
self.readEarly()
if not self.__jails.read():
raise LookupError("Read jails configuration failed.")
self.__jails.read()
def getEarlyOptions(self):
return self.__fail2ban.getEarlyOptions()

View file

@ -47,7 +47,7 @@ class CSocket:
def send(self, msg, nonblocking=False, timeout=None):
# Convert every list member to string
obj = dumps(list(map(CSocket.convert, msg)), HIGHEST_PROTOCOL)
obj = dumps(map(CSocket.convert, msg), HIGHEST_PROTOCOL)
self.__csock.send(obj)
self.__csock.send(CSPROTO.END)
return self.receive(self.__csock, nonblocking, timeout)
@ -72,7 +72,7 @@ class CSocket:
@staticmethod
def convert(m):
"""Convert every "unexpected" member of message to string"""
if isinstance(m, (str, bool, int, float, list, dict, set)):
if isinstance(m, (basestring, bool, int, float, list, dict, set)):
return m
else: # pragma: no cover
return str(m)

View file

@ -45,7 +45,7 @@ def _thread_name():
return threading.current_thread().__class__.__name__
def input_command(): # pragma: no cover
return input(PROMPT)
return raw_input(PROMPT)
##
#
@ -406,8 +406,6 @@ class Fail2banClient(Fail2banCmdLine, Thread):
if ret is not None:
if ret:
return True
if self._conf.get("test", False) and not self._args: # test only
return False
raise ServerExecutionException("Init of command line failed")
# Commands
@ -458,7 +456,7 @@ class Fail2banClient(Fail2banCmdLine, Thread):
return False
finally:
self._alive = False
for s, sh in _prev_signals.items():
for s, sh in _prev_signals.iteritems():
signal.signal(s, sh)

View file

@ -27,7 +27,7 @@ import sys
from ..version import version, normVersion
from ..protocol import printFormatted
from ..helpers import getLogger, str2LogLevel, getVerbosityFormat
from ..helpers import getLogger, str2LogLevel, getVerbosityFormat, BrokenPipeError
# Gets the instance of the logger.
logSys = getLogger("fail2ban")
@ -260,15 +260,12 @@ class Fail2banCmdLine():
if readcfg:
readcfg = False
ret, stream = self.readConfig()
# exit after test if no commands specified (test only):
if not len(self._args):
if ret:
output("OK: configuration test is successful")
else:
output("ERROR: test configuration failed")
return ret
if not ret:
raise ServerExecutionException("ERROR: test configuration failed")
# exit after test if no commands specified (test only):
if not len(self._args):
output("OK: configuration test is successful")
return ret
# Nothing to do here, process in client/server
return None

View file

@ -37,7 +37,7 @@ class Fail2banReader(ConfigReader):
ConfigReader.__init__(self, **kwargs)
def read(self):
return ConfigReader.read(self, "fail2ban")
ConfigReader.read(self, "fail2ban")
def getEarlyOptions(self):
opts = [

View file

@ -40,10 +40,10 @@ import os
import shlex
import sys
import time
import urllib.request, urllib.parse, urllib.error
import urllib
from optparse import OptionParser, Option
from configparser import NoOptionError, NoSectionError, MissingSectionHeaderError
from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError
try: # pragma: no cover
from ..server.filtersystemd import FilterSystemd
@ -51,7 +51,7 @@ except ImportError:
FilterSystemd = None
from ..version import version, normVersion
from .jailreader import FilterReader, JailReader, NoJailError
from .filterreader import FilterReader
from ..server.filter import Filter, FileContainer, MyTime
from ..server.failregex import Regex, RegexException
@ -67,9 +67,9 @@ def debuggexURL(sample, regex, multiline=False, useDns="yes"):
'flavor': 'python'
}
if multiline: args['flags'] = 'm'
return 'https://www.debuggex.com/?' + urllib.parse.urlencode(args)
return 'https://www.debuggex.com/?' + urllib.urlencode(args)
def output(args): # pragma: no cover (overridden in test-cases)
def output(args): # pragma: no cover (overriden in test-cases)
print(args)
def shortstr(s, l=53):
@ -106,7 +106,7 @@ usage = lambda: "%s [OPTIONS] <LOG> <REGEX> [IGNOREREGEX]" % sys.argv[0]
class _f2bOptParser(OptionParser):
def format_help(self, *args, **kwargs):
""" Overwritten format helper with full usage."""
""" Overwritten format helper with full ussage."""
self.usage = ''
return "Usage: " + usage() + "\n" + __doc__ + """
LOG:
@ -118,11 +118,12 @@ LOG:
REGEX:
string a string representing a 'failregex'
filter name of jail or filter, optionally with options (sshd[mode=aggressive])
filter name of filter, optionally with options (sshd[mode=aggressive])
filename path to a filter file (filter.d/sshd.conf)
IGNOREREGEX:
string a string representing an 'ignoreregex'
filename path to a filter file (filter.d/sshd.conf)
\n""" + OptionParser.format_help(self, *args, **kwargs) + """\n
Report bugs to https://github.com/fail2ban/fail2ban/issues\n
""" + __copyright__ + "\n"
@ -172,8 +173,6 @@ def get_opt_parser():
help="Disable check for all regex's"),
Option("-o", "--out", action="store", dest="out", default=None,
help="Set token to print failure information only (row, id, ip, msg, host, ip4, ip6, dns, matches, ...)"),
Option("-i", "--invert", action="store_true", dest="invert",
help="Invert the sense of matching, to output non-matching lines."),
Option("--print-no-missed", action='store_true',
help="Do not print any missed lines"),
Option("--print-no-ignored", action='store_true',
@ -247,7 +246,7 @@ class Fail2banRegex(object):
def __init__(self, opts):
# set local protected members from given options:
self.__dict__.update(dict(('_'+o,v) for o,v in opts.__dict__.items()))
self.__dict__.update(dict(('_'+o,v) for o,v in opts.__dict__.iteritems()))
self._opts = opts
self._maxlines_set = False # so we allow to override maxlines in cmdline
self._datepattern_set = False
@ -281,7 +280,7 @@ class Fail2banRegex(object):
self._filter.setUseDns(opts.usedns)
self._filter.returnRawHost = opts.raw
self._filter.checkAllRegex = opts.checkAllRegex and not opts.out
# ignore pending (without ID/IP), added to matches if it hits later (if ID/IP can be retrieved)
# ignore pending (without ID/IP), added to matches if it hits later (if ID/IP can be retreved)
self._filter.ignorePending = bool(opts.out)
# callback to increment ignored RE's by index (during process):
self._filter.onIgnoreRegex = self._onIgnoreRegex
@ -313,18 +312,12 @@ class Fail2banRegex(object):
def _dumpRealOptions(self, reader, fltOpt):
realopts = {}
combopts = reader.getCombined()
if isinstance(reader, FilterReader):
_get_opt = lambda k: reader.get('Definition', k)
elif reader.filter: # JailReader for jail with filter:
_get_opt = lambda k: reader.filter.get('Definition', k)
else: # JailReader for jail without filter:
_get_opt = lambda k: None
# output all options that are specified in filter-argument as well as some special (mostly interested):
for k in ['logtype', 'datepattern'] + list(fltOpt.keys()):
for k in ['logtype', 'datepattern'] + fltOpt.keys():
# combined options win, but they contain only a sub-set in filter expected keys,
# so get the rest from definition section:
try:
realopts[k] = combopts[k] if k in combopts else _get_opt(k)
realopts[k] = combopts[k] if k in combopts else reader.get('Definition', k)
except NoOptionError: # pragma: no cover
pass
self.output("Real filter options : %r" % realopts)
@ -337,26 +330,16 @@ class Fail2banRegex(object):
fltName = value
fltFile = None
fltOpt = {}
jail = None
if regextype == 'fail':
if re.search(r'(?ms)^/{0,3}[\w/_\-.]+(?:\[.*\])?$', value):
try:
fltName, fltOpt = extractOptions(value)
if not re.search(r'(?ms)(?:/|\.(?:conf|local)$)', fltName): # name of jail?
try:
jail = JailReader(fltName, force_enable=True,
share_config=self.share_config, basedir=basedir)
jail.read()
except NoJailError:
jail = None
if "." in fltName[~5:]:
tryNames = (fltName,)
else:
tryNames = (fltName, fltName + '.conf', fltName + '.local')
for fltFile in tryNames:
if os.path.dirname(fltFile) == 'filter.d':
fltFile = os.path.join(basedir, fltFile)
elif not "/" in fltFile:
if not "/" in fltFile:
if os.path.basename(basedir) == 'filter.d':
fltFile = os.path.join(basedir, fltFile)
else:
@ -371,28 +354,8 @@ class Fail2banRegex(object):
output(" while parsing: %s" % (value,))
if self._verbose: raise(e)
return False
elif self._ignoreregex:
# clear ignoreregex that could be previously loaded from filter:
self._filter.delIgnoreRegex()
readercommands = None
# if it is jail:
if jail:
self.output( "Use %11s jail : %s" % ('', fltName) )
if fltOpt:
self.output( "Use jail/flt options : %r" % fltOpt )
if not fltOpt: fltOpt = {}
fltOpt['backend'] = self._backend
ret = jail.getOptions(addOpts=fltOpt)
if not ret:
output('ERROR: Failed to get jail for %r' % (value,))
return False
# show real options if expected:
if self._verbose > 1 or logSys.getEffectiveLevel()<=logging.DEBUG:
self._dumpRealOptions(jail, fltOpt)
readercommands = jail.convert(allow_no_files=True)
# if it is filter file:
elif fltFile is not None:
if fltFile is not None:
if (basedir == self._opts.config
or os.path.basename(basedir) == 'filter.d'
or ("." not in fltName[~5:] and "/" not in fltName)
@ -401,17 +364,16 @@ class Fail2banRegex(object):
if os.path.basename(basedir) == 'filter.d':
basedir = os.path.dirname(basedir)
fltName = os.path.splitext(os.path.basename(fltName))[0]
self.output( "Use %11s file : %s, basedir: %s" % ('filter', fltName, basedir) )
self.output( "Use %11s filter file : %s, basedir: %s" % (regex, fltName, basedir) )
else:
## foreign file - readexplicit this file and includes if possible:
self.output( "Use %11s file : %s" % ('filter', fltName) )
self.output( "Use %11s file : %s" % (regex, fltName) )
basedir = None
if not os.path.isabs(fltName): # avoid join with "filter.d" inside FilterReader
fltName = os.path.abspath(fltName)
if fltOpt:
self.output( "Use filter options : %r" % fltOpt )
reader = FilterReader(fltName, 'fail2ban-regex-jail', fltOpt,
share_config=self.share_config, basedir=basedir)
reader = FilterReader(fltName, 'fail2ban-regex-jail', fltOpt, share_config=self.share_config, basedir=basedir)
ret = None
try:
if basedir is not None:
@ -436,8 +398,7 @@ class Fail2banRegex(object):
# to stream:
readercommands = reader.convert()
regex_values = {}
if readercommands:
regex_values = {}
for opt in readercommands:
if opt[0] == 'multi-set':
optval = opt[3]
@ -477,9 +438,9 @@ class Fail2banRegex(object):
else:
self.output( "Use %11s line : %s" % (regex, shortstr(value)) )
regex_values[regextype] = [RegexStat(value)]
regex_values = {regextype: [RegexStat(value)]}
for regextype, regex_values in regex_values.items():
for regextype, regex_values in regex_values.iteritems():
regex = regextype + 'regex'
setattr(self, "_" + regex, regex_values)
for regex in regex_values:
@ -515,7 +476,7 @@ class Fail2banRegex(object):
ret.append(match)
else:
is_ignored = True
if self._opts.out: # (formatted) output - don't need stats:
if self._opts.out: # (formated) output - don't need stats:
return None, ret, None
# prefregex stats:
if self._filter.prefRegex:
@ -531,7 +492,7 @@ class Fail2banRegex(object):
except RegexException as e: # pragma: no cover
output( 'ERROR: %s' % e )
return None, 0, None
if self._filter.getMaxLines() > 1 and not self._opts.out:
if self._filter.getMaxLines() > 1:
for bufLine in orgLineBuffer[int(fullBuffer):]:
if bufLine not in self._filter._Filter__lineBuffer:
try:
@ -571,13 +532,13 @@ class Fail2banRegex(object):
def _out(ret):
for r in ret:
for r in r[3].get('matches'):
if not isinstance(r, str):
if not isinstance(r, basestring):
r = ''.join(r for r in r)
output(r)
elif ofmt == 'row':
def _out(ret):
for r in ret:
output('[%r,\t%r,\t%r],' % (r[1],r[2],dict((k,v) for k, v in r[3].items() if k != 'matches')))
output('[%r,\t%r,\t%r],' % (r[1],r[2],dict((k,v) for k, v in r[3].iteritems() if k != 'matches')))
elif '<' not in ofmt:
def _out(ret):
for r in ret:
@ -612,7 +573,7 @@ class Fail2banRegex(object):
# wrap multiline tag (msg) interpolations to single line:
for r, v in rows:
for r in r[3].get('matches'):
if not isinstance(r, str):
if not isinstance(r, basestring):
r = ''.join(r for r in r)
r = v.replace("\x00msg\x00", r)
output(r)
@ -621,10 +582,8 @@ class Fail2banRegex(object):
def process(self, test_lines):
t0 = time.time()
out = None
if self._opts.out: # get out function
out = self._prepaireOutput()
outinv = self._opts.invert
for line in test_lines:
if isinstance(line, tuple):
line_datetimestripped, ret, is_ignored = self.testRegex(line[0], line[1])
@ -636,13 +595,8 @@ class Fail2banRegex(object):
continue
line_datetimestripped, ret, is_ignored = self.testRegex(line)
if out: # (formatted) output:
if len(ret) > 0 and not is_ignored:
if not outinv: out(ret)
elif outinv: # inverted output (currently only time and message as matches):
if not len(ret): # [failRegexIndex, fid, date, fail]
ret = [[-1, "", self._filter._Filter__lastDate, {"fid":"", "matches":[line]}]]
out(ret)
if self._opts.out: # (formated) output:
if len(ret) > 0 and not is_ignored: out(ret)
continue
if is_ignored:
@ -685,9 +639,9 @@ class Fail2banRegex(object):
ans = [[]]
for arg in [l, regexlist]:
ans = [ x + [y] for x in ans for y in arg ]
b = [a[0] + ' | ' + a[1].getFailRegex() + ' | ' +
b = map(lambda a: a[0] + ' | ' + a[1].getFailRegex() + ' | ' +
debuggexURL(self.encode_line(a[0]), a[1].getFailRegex(),
multiline, self._opts.usedns) for a in ans]
multiline, self._opts.usedns), ans)
pprint_list([x.rstrip() for x in b], header)
else:
output( "%s too many to print. Use --print-all-%s " \
@ -835,15 +789,7 @@ class Fail2banRegex(object):
return True
def _loc_except_hook(exctype, value, traceback):
if (exctype != BrokenPipeError and exctype != IOError or value.errno != 32):
return sys.__excepthook__(exctype, value, traceback)
# pipe seems to be closed (head / tail / etc), thus simply exit:
sys.exit(0)
def exec_command_line(*args):
sys.excepthook = _loc_except_hook; # stop on closed/broken pipe
logging.exitOnIOError = True
parser = get_opt_parser()
(opts, args) = parser.parse_args(*args)

View file

@ -45,7 +45,7 @@ class Fail2banServer(Fail2banCmdLine):
@staticmethod
def startServerDirect(conf, daemon=True, setServer=None):
logSys.debug(" direct starting of server in %s, daemon: %s", os.getpid(), daemon)
logSys.debug(" direct starting of server in %s, deamon: %s", os.getpid(), daemon)
from ..server.server import Server
server = None
try:
@ -120,7 +120,7 @@ class Fail2banServer(Fail2banCmdLine):
if frk: # pragma: no cover
os.execv(exe, args)
else:
# use P_WAIT instead of P_NOWAIT (to prevent defunct-zomby process), it started as daemon, so parent exit fast after fork):
# use P_WAIT instead of P_NOWAIT (to prevent defunct-zomby process), it startet as daemon, so parent exit fast after fork):
ret = os.spawnv(os.P_WAIT, exe, args)
if ret != 0: # pragma: no cover
raise OSError(ret, "Unknown error by executing server %r with %r" % (args[1], exe))

View file

@ -71,7 +71,7 @@ class FilterReader(DefinitionInitConfigReader):
@staticmethod
def _fillStream(stream, opts, jailName):
prio0idx = 0
for opt, value in opts.items():
for opt, value in opts.iteritems():
# Do not send a command if the value is not set (empty).
if value is None: continue
if opt in ("failregex", "ignoreregex"):
@ -89,7 +89,7 @@ class FilterReader(DefinitionInitConfigReader):
stream.insert(0 if opt == 'usedns' else prio0idx,
["set", jailName, opt, value])
prio0idx += 1
elif opt == 'datepattern':
elif opt in ('datepattern'):
stream.append(["set", jailName, opt, value])
elif opt == 'journalmatch':
for match in value.split("\n"):

Some files were not shown because too many files have changed in this diff Show more