diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a9fff350..3a17ccc2 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,11 @@ Before submitting your PR, please review the following checklist: +- [ ] **CHOOSE CORRECT BRANCH**: if filing a bugfix/enhancement + against 0.9.x series, choose `master` branch - [ ] **CONSIDER adding a unit test** if your PR resolves an issue - [ ] **LIST ISSUES** this PR resolves -- [ ] **MAKE SURE** this PR doesn't break existing tests +- [ ] **MAKE SURE** this PR doesn't break existing tests - [ ] **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 - within `fail2ban/tests/files/logs/X` file \ No newline at end of file +- [ ] **ACCOMPANY** each new `failregex` for filter `X` with sample log lines + within `fail2ban/tests/files/logs/X` file diff --git a/.travis.yml b/.travis.yml index 40376075..0c611a95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,12 +10,16 @@ python: # - 3.2 - 3.3 - 3.4 + - 3.5 + - 3.6 + - 3.7-dev # disabled since setuptools dropped support for Python 3.0 - 3.2 # - pypy3 - - pypy3.3-5.2-alpha1 + - pypy3.3-5.5-alpha before_install: - - if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then export F2B_PY_2=true && echo "Set F2B_PY_2"; fi - - if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then export F2B_PY_3=true && echo "Set F2B_PY_3"; fi + - echo "running under $TRAVIS_PYTHON_VERSION" + - if [[ $TRAVIS_PYTHON_VERSION == 2* || $TRAVIS_PYTHON_VERSION == pypy* && $TRAVIS_PYTHON_VERSION != pypy3* ]]; then export F2B_PY_2=true && echo "Set F2B_PY_2"; fi + - if [[ $TRAVIS_PYTHON_VERSION == 3* || $TRAVIS_PYTHON_VERSION == pypy3* ]]; then export F2B_PY_3=true && echo "Set F2B_PY_3"; fi - 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 @@ -39,8 +43,8 @@ before_script: 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 - - if [[ "$F2B_PY_3" ]]; then coverage run bin/fail2ban-testcases; 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 diff --git a/ChangeLog b/ChangeLog index ec855ab0..29b07973 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,14 +6,490 @@ Fail2Ban: Changelog =================== +Incompatibility list (compared to v.0.9): +----------- -ver. 0.9.7 (2017/05/11) - awaiting-victory +* Filter (or `failregex`) internal capture-groups: + + - If you've your own `failregex` or custom filters using conditional match `(?P=host)`, you should + rewrite the regex like in example below resp. using `(?:(?P=ip4)|(?P=ip6)` instead of `(?P=host)` + (or `(?:(?P=ip4)|(?P=ip6)|(?P=dns))` corresponding your `usedns` and `raw` settings). + + Of course you can always define your own capture-group (like below `_cond_ip_`) to do this. + ``` + testln="1500000000 failure from 192.0.2.1: bad host 192.0.2.1" + fail2ban-regex "$testln" "^\s*failure from (?P<_cond_ip_>): bad host (?P=_cond_ip_)$" + ``` + - New internal groups (currently reserved for internal usage): + `ip4`, `ip6`, `dns`, `fid`, `fport`, additionally `user` and another captures in lower case if + mapping from tag `` used in failregex (e. g. `user` by ``). + +* v.0.10 uses more precise date template handling, that can be theoretically incompatible to some + user configurations resp. `datepattern`. + +* Since v0.10 fail2ban supports the matching of the IPv6 addresses, but not all ban actions are + IPv6-capable now. + + +ver. 0.10.2 (2018/01/18) - nothing-burns-like-the-cold +----------- + +### Incompatibility list: +* The configuration for jails using banaction `pf` can be incompatible after upgrade, because pf-action uses + anchors now (see `action.d/pf.conf` for more information). If you want use obsolete handling without anchors, + just rewrite it in the `jail.local` by overwrite of `pfctl` parameter, e. g. like `banaction = pf[pfctl="pfctl"]`. + +### Fixes +* Fixed logging to systemd-journal: new logtarget value SYSOUT can be used instead of STDOUT, to avoid + write of the time-stamp, if logging to systemd-journal from foreground mode (gh-1876) +* Fixed recognition of the new date-format on mysqld-auth filter (gh-1639) +* jail.conf: port `imap3` replaced with `imap` everywhere, since imap3 is not a standard port and old rarely + (if ever) used and can missing on some systems (e. g. debian stretch), see gh-1942. +* config/paths-common.conf: added missing initial values (and small normalization in config/paths-*.conf) + in order to avoid errors while interpolating (e. g. starting with systemd-backend), see gh-1955. +* `action.d/pf.conf`: + - fixed syntax error in achnor definition (documentation, see gh-1919); + - enclose ports in braces for multiport jails (see gh-1925); +* `action.d/firewallcmd-ipset.conf`: fixed create of set for ipv6 (missing `family inet6`, gh-1990) +* `filter.d/sshd.conf`: + - extended failregex for modes "extra"/"aggressive": now finds 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 (gh-1943, gh-1944); + - fixed failregex in order to avoid banning of legitimate users with multiple public keys (gh-2014, gh-1263); + +### New Features +* datedetector: extended default date-patterns (allows extra space between the date and time stamps); + introduces 2 new format directives (with corresponding %Ex prefix for more precise parsing): + - %k - one- or two-digit number giving the hour of the day (0-23) on a 24-hour clock, + (corresponds %H, but allows space if not zero-padded). + - %l - one- or two-digit number giving the hour of the day (12-11) on a 12-hour clock, + (corresponds %I, but allows space if not zero-padded). +* `filter.d/exim.conf`: added mode `aggressive` to ban flood resp. DDOS-similar failures (gh-1983); +* New Actions: + - `action.d/nginx-block-map.conf` - in order to ban not IP-related tickets via nginx (session blacklisting in + nginx-location with map-file); + +### Enhancements +* jail.conf: extended with new parameter `mode` for the filters supporting it (gh-1988); +* action.d/pf.conf: extended with bulk-unban, command `actionflush` in order to flush all bans at once. +* Introduced new parameters for logging within fail2ban-server (gh-1980). + Usage `logtarget = target[facility=..., datetime=on|off, format="..."]`: + - `facility` - specify syslog facility (default `daemon`, see https://docs.python.org/2/library/logging.handlers.html#sysloghandler + for the list of facilities); + - `datetime` - add date-time to the message (default on, ignored if `format` specified); + - `format` - specify own format how it will be logged, for example for short-log into STDOUT: + `fail2ban-server -f --logtarget 'stdout[format="%(relativeCreated)5d | %(message)s"]' start`; +* Automatically recover or recreate corrupt persistent database (e. g. if failed to open with + 'database disk image is malformed'). Fail2ban will create a backup, try to repair the database, + if repair fails - recreate new database (gh-1465, gh-2004). + + +ver. 0.10.1 (2017/10/12) - succeeded-before-friday-the-13th +----------- + +### Fixes +* fix Gentoo init script's shebang to use openrc-run instead of runscript (gh-1891) +* jail "pass2allow-ftp" supply blocktype and returntype parameters to the action (gh-1884) +* avoid using "ANSI_X3.4-1968" as preferred encoding (if missing environment variables + 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', and 'LANG', see gh-1587). +* action.d/pf.conf: several fixes for pf-action like anchoring, etc. (see gh-1866, gh-1867); +* fixed ignorself issue "Retrieving own IPs of localhost failed: inet_pton() argument 2 must be string, not int" (see gh-1865); +* fixed tags `` and ``, could be used without ticket (a. g. in `actionstart` etc., gh-1859). + +* setup.py: fixed several setup facilities (gh-1874): + - don't check return code by dry-run: returns 256 on some python/setuptool versions; + - `files/fail2ban.service` renamed as template to `files/fail2ban.service.in`; + - setup process generates `build/fail2ban.service` from `files/fail2ban.service.in` using distribution related bin-path; + - bug-fixing by running setup with option `--dry-run`; + +### New Features +* introduced new command-line options `--dp`, `--dump-pretty` to dump the configuration using more + human readable representation (opposite to `-d`); + +### Enhancements +* nftables actions are IPv6-capable now (gh-1893) +* filter.d/dovecot.conf: introduced mode `aggressive` for cases like "disconnected before auth was ready" (gh-1880) + + +ver. 0.10.0 (2017/08/09) - long-awaited 0.10th version +----------- + +TODO: implementing of options resp. other tasks from PR #1346 + documentation should be extended (new options, etc) + +### Fixes +* `filter.d/apache-auth.conf`: + - better failure recognition using short form of regex (url/referer are foreign inputs, see gh-1645) +* `filter.d/apache-common.conf` (`filter.d/apache-*.conf`): + - support of apache log-format if logging into syslog/systemd (gh-1695), using parameter `logging`, + parameter usage for jail: + filter = apache-auth[logging=syslog] + parameter usage for `apache-common.local`: + logging = syslog +* `filter.d/pam-generic.conf`: + - [grave] injection on user name to host fixed +* `filter.d/sshd.conf`: + - rewritten using `prefregex` and used MLFID-related multi-line parsing + (by using tag `` instead of buffering with `maxlines`); + - optional parameter `mode` rewritten: normal (default), ddos, extra or aggressive (combines all), + see sshd for regex details) +* `filter.d/sendmail-reject.conf`: + - rewritten using `prefregex` and used MLFID-related multi-line parsing; + - optional parameter `mode` introduced: normal (default), extra or aggressive +* `filter.d/haproxy-http-auth`: do not mistake client port for part of an IPv6 address (gh-1745) +* `filter.d/postfix.conf`: + - updated to latest postfix formats + - joined several postfix filter together (normalized and optimized version, gh-1825) + - introduced new parameter `mode` (see gh-1825): more (default, combines normal and rbl), auth, normal, + rbl, ddos, extra or aggressive (combines all) + - postfix postscreen (resp. other RBL's compatibility fix, gh-1764, gh-1825) +* `filter.d/postfix-rbl.conf`: removed (replaced with `postfix[mode=rbl]`) +* `filter.d/postfix-sasl.conf`: removed (replaced with `postfix[mode=auth]`) +* `filter.d/roundcube-auth.conf`: + - fixed regex when `X-Real-IP` or/and `X-Forwarded-For` are present after host (gh-1303); + - fixed regex when logging authentication errors to journal instead to a local file (gh-1159); + - additionally fixed more complex injections on username (e. g. using dot after fake host). +* `filter.d/ejabberd-auth.conf`: fixed failregex - accept new log-format (gh-993) +* `action.d/complain.conf` + - fixed using new tag `` (sh/dash compliant now) +* `action.d/sendmail-geoip-lines.conf` + - fixed using new tag `` (without external command execution) +* fail2ban-regex: fixed matched output by multi-line (buffered) parsing +* fail2ban-regex: support for multi-line debuggex URL implemented (gh-422) +* fixed ipv6-action errors on systems not supporting ipv6 and vice versa (gh-1741) +* fixed directory-based log-rotate for pyinotify-backend (gh-1778) + +### New Features +* New Actions: + +* New Filters: + +### Enhancements +* Introduced new filter option `prefregex` for pre-filtering using single regular expression (gh-1698); +* Many times faster and fewer CPU-hungry because of parsing with `maxlines=1`, so without + line buffering (scrolling of the buffer-window). + Combination of tags `` and `` can be used now to process multi-line logs + using single-line expressions: + - tag ``: used to identify resp. store failure info for groups of log-lines with the same + identifier (e. g. combined failure-info for the same conn-id by `(?:conn-id)`, + see sshd.conf for example); + - tag ``: can be used as mark to forget current multi-line MLFID (e. g. by connection + closed, reset or disconnect etc); + - tag ``: used as mark for no-failure (helper to accumulate common failure-info, + e. g. from lines that contain IP-address); + Opposite to obsolete multi-line parsing (using buffering with `maxlines`) it is more precise and + can recognize multiple failure attempts within the same connection (MLFID). +* Several filters optimized with pre-filtering using new option `prefregex`, and multiline filter + using `` + `` combination; +* Exposes filter group captures in actions (non-recursive interpolation of tags ``, + see gh-1698, gh-1110) +* Some filters extended with user name (can be used in gh-1243 to distinguish IP and user, + resp. to remove after success login the user-related failures only); +* Safer, more stable and faster replaceTag interpolation (switched from cycle over all tags + to re.sub with callable) +* substituteRecursiveTags optimization + moved in helpers facilities (because currently used + commonly in server and in client) +* New tags (usable in actions): + - `` - failure identifier (if raw resp. failures without IP address) + - `` - PTR reversed representation of IP address + - `` - host name of the IP address + - `` - interpolates to the corresponding filter group capture `...` + - `` - fully-qualified name of host (the same as `$(hostname -f)`) + - `` - short hostname (the same as `$(uname -n)`) +* Allow to use filter options by `fail2ban-regex`, example: + fail2ban-regex text.log "sshd[mode=aggressive]" +* Samples test case factory extended with filter options - dict in JSON to control + filter options (e. g. mode, etc.): + # filterOptions: {"mode": "aggressive"} +* Introduced new jail option "ignoreself", specifies whether the local resp. own IP addresses + should be ignored (default is true). Fail2ban will not ban a host which matches such addresses. + Option "ignoreip" affects additionally to "ignoreself" and don't need to include the DNS + resp. IPs of the host self. +* Regex will be compiled as MULTILINE only if needed (buffering with `maxlines` > 1), that enables: + - to improve performance by the single line parsing (see gh-1733); + - make regex more precise (because distinguish between anchors `^`/`$` for the begin/end of string + and the new-line character '\n', e. g. if coming from filters (like systemd journal) that allow + the parsing of log-entries contain new-line chars (as single entry); + - if multiline regex however expected (by single-line parsing without buffering) - prefix `(?m)` + could be used in regex to enable it; +* Implemented execution of `actionstart` on demand (conditional), if action depends on `family` (gh-1742): + - new action parameter `actionstart_on_demand` (bool) can be set to prevent/allow starting action + on demand (default retrieved automatically, if some conditional parameter `param?family=...` + presents in action properties), see `action.d/pf.conf` for example; + - additionally `actionstop` will be executed only for families previously executing `actionstart` + (starting on demand only) +* Introduced new command `actionflush`: executed in order to flush all bans at once + e. g. by unban all, reload with removing action, stop, shutdown the system (gh-1743), + the actions having `actionflush` do not execute `actionunban` for each single ticket +* Add new command `actionflush` default for several iptables/iptables-ipset actions (and common include); +* Add new jail option `logtimezone` to force the timezone on log lines that don't have an explicit one (gh-1773) +* Implemented zone abbreviations (like CET, CEST, etc.) and abbr+-offset functionality (accept zones + like 'CET+0100'), for the list of abbreviations see strptime.TZ_STR; +* Introduced new option `--timezone` (resp. `--TZ`) for `fail2ban-regex`. +* Tokens `%z` and `%Z` are changed (more precise now); +* Introduced new tokens `%Exz` and `%ExZ` that fully support zone abbreviations and/or offset-based + zones (implemented as enhancement using custom `datepattern`, because may be too dangerous for default + patterns and tokens like `%z`); + Note: the extended tokens supported zone abbreviations, but it can parse 1 or 3-5 char(s) in lowercase. + Don't use them in default date-patterns (if not anchored, few precise resp. optional). + Because python currently does not support mixing of case-sensitive with case-insensitive matching, + the TZ (in uppercase) cannot be combined with `%a`/`%b` etc (that are currently case-insensitive), + to avoid invalid date-time recognition in strings like '11-Aug-2013 03:36:11.372 error ...' with + wrong TZ "error". + Hence `%z` currently match literal Z|UTC|GMT only (and offset-based), and `%Exz` - all zone + abbreviations. +* `filter.d/courier-auth.conf`: support failed logins with method only +* Config reader's: introduced new syntax `%(section/option)s`, in opposite to extended interpolation of + python 3 `${section:option}` work with all supported python version in fail2ban and this syntax is + like our another features like `%(known/option)s`, etc. (gh-1750) +* Variable `default_backend` switched to `%(default/backend)s`, so totally backwards compatible now, + but now the setting of parameter `backend` in default section of `jail.local` can overwrite default + backend also (see gh-1750). In the future versions parameter `default_backend` can be removed (incompatibility, + possibly some distributions affected). + + +ver. 0.10.0-alpha-1 (2016/07/14) - ipv6-support-etc +----------- + +### Fixes +* [Grave] memory leak's fixed (gh-1277, gh-1234) +* [Grave] Misleading date patterns defined more precisely (using extended syntax + `%Ex[mdHMS]` for exact two-digit match or e. g. `%ExY` as more precise year + pattern, within same century of last year and the next 3 years) +* [Grave] extends date detector template with distance (position of match in + log-line), to prevent grave collision using (re)ordered template list (e.g. + find-spot of wrong date-match inside foreign input, misleading date patterns + by ambiguous formats, etc.) +* Distance collision check always prefers template with shortest distance + (left for right) if date pattern is not anchored +* Tricky bug fix: last position of log file will be never retrieved (gh-795), + because of CASCADE all log entries will be deleted from logs table together with jail, + if used "INSERT OR REPLACE" statement +* Asyncserver (asyncore) code fixed and test cases repaired (again gh-161) +* testSocket: sporadical bug repaired - wait for server thread starts a socket (listener) +* testExecuteTimeoutWithNastyChildren: sporadical bug repaired - wait for pid file inside bash, + kill tree in any case (gh-1155) +* Fixed high-load of pyinotify-backend, + see https://github.com/fail2ban/fail2ban/issues/885#issuecomment-248964591 +* Database: stability fix - repack cursor iterator as long as locked +* File filter backends: stability fix for sporadically errors - always close file + handle, otherwise may be locked (prevent log-rotate, etc.) +* Pyinotify-backend: stability fix for sporadically errors in multi-threaded + environment (without lock) +* Fixed sporadically error in testCymruInfoNxdomain, because of unsorted values +* Misleading errors logged from ignorecommand in success case on retcode 1 (gh-1194) +* fail2ban.service - systemd service updated (gh-1618): + - starting service in normal mode (without forking) + - does not restart if service exited normally (exit-code 0, e.g. stopped via fail2ban-client) + - does not restart if service can not start (exit-code 255, e.g. wrong configuration, etc.) + - service can be additionally started/stopped with commands (fail2ban-client, fail2ban-server) + - automatically creates `/var/run/fail2ban` directory before start fail2ban + (systems with virtual resp. memory-based FS for `/var/run`), see gh-1531 + - if fail2ban running as systemd-service, for logging to the systemd-journal, + the `logtarget` could be set to STDOUT + - value `logtarget` for system targets allowed also in lowercase (stdout, stderr, syslog, etc.) +* Fixed UTC/GMT named time zone, using `%Z` and `%z` patterns + (special case with 0 zone offset, see gh-1575) +* `filter.d/freeswitch.conf` + - Optional prefixes (server, daemon, dual time) if systemd daemon logs used (gh-1548) + - User part rewritten to accept IPv6 resp. domain after "@" (gh-1548) + +### New Features +* IPv6 support: + - IP addresses are now handled as objects rather than strings capable for + handling both address types IPv4 and IPv6 + - iptables related actions have been amended to support IPv6 specific actions + additionally + - hostsdeny and route actions have been tested to be aware of v4 and v6 already + - pf action for *BSD systems has been improved and supports now also v4 and v6 + - name resolution is now working for either address type + - new conditional section functionality used in config resp. includes: + - [Init?family=inet4] - IPv4 qualified hosts only + - [Init?family=inet6] - IPv6 qualified hosts only +* New reload functionality (now totally without restart, unbanning/rebanning, etc.), + see gh-1557 +* Several commands extended and new commands introduced: + - `restart [--unban] [--if-exists] ` - restarts the jail \ + (alias for `reload --restart ... `) + - `reload [--restart] [--unban] [--all]` - reloads the configuration without restarting + of the server, the option `--restart` activates completely restarting of affected jails, + thereby can unban IP addresses (if option `--unban` specified) + - `reload [--restart] [--unban] [--if-exists] ` - reloads the jail \, + or restarts it (if option `--restart` specified), at the same time unbans all IP addresses + banned in this jail, if option `--unban` specified + - `unban --all` - unbans all IP addresses (in all jails and database) + - `unban ... ` - unbans \ (in all jails and database) (see gh-1388) + - introduced new option `-t` or `--test` to test configuration resp. start server only + if configuration is clean (fails by wrong configured jails if option `-t` specified) +* New command action parameter `actionrepair` - command executed in order to restore + sane environment in error case of `actioncheck`. +* Reporting via abuseipdb.com: + - Bans can now be reported to abuseipdb + - Catagories must be set in the config + - Relevant log lines included in report + +### Enhancements +* Huge increasing of fail2ban performance and especially test-cases performance (see gh-1109) +* Datedetector: in-place reordering using hits and last used time: + matchTime, template list etc. rewritten because of performance degradation +* Prevent out of memory situation if many IP's makes extremely many failures (maxEntries) +* Introduced string to seconds (str2seconds) for configuration entries with time, + use `1h` instead of `3600`, `1d` instead of `86400`, etc +* seekToTime - prevent completely read of big files first time (after start of service), + initial seek to start time using half-interval search algorithm (see issue gh-795) +* Ticket and some other modules prepared to easy merge with newest version of 'ban-time-incr' +* Cache dnsToIp, ipToName to prevent long wait during retrieving of ip/name, + especially for wrong dns or lazy dns-system +* FailManager memory-optimization: increases performance, + prevents memory leakage, because don't copy failures list on some operations +* fail2ban-testcases - new options introduced: + - `-f`, `--fast` to decrease wait intervals, avoid passive waiting, and skip + few very slow test cases (implied memory database, see `-m` and no gamin tests `-g`) + - `-g`, `--no-gamin` to prevent running of tests that require the gamin (slow) + - `-m`, `--memory-db` - run database tests using memory instead of file + - `-i`, `--ignore` - negate [regexps] filter to ignore tests matched specified regexps +* Background servicing: prevents memory leak on some platforms/python versions, using forced GC + in periodic intervals (latency and threshold) +* executeCmd partially moved from action to new module utils +* Several functionality of class `DNSUtils` moved to new class `IPAddr`, + both classes moved to new module `ipdns` +* Pseudo-conditional section introduced, for conditional substitution resp. + evaluation of parameters for different family qualified hosts, + syntax `[Section?family=inet6]` (currently use for IPv6-support only). +* All the backends were rewritten to get reload-possibility, performance increased, + so fewer greedy regarding cpu- resp. system-load now +* Numeric log-level allowed now in server (resp. fail2ban.conf); +* Implemented better error handling in some multi-threaded routines; shutdown of jails + rewritten (faster and safer, does not breaks shutdown process if some error occurred) +* Possibility for overwriting some configuration options (read with config-readers) + with command line option, e. g.: +```bash +## start server with DEBUG log-level (ignore level read from fail2ban.conf): +fail2ban-client --loglevel DEBUG start +## or +fail2ban-server -c /cfg/path --loglevel DEBUG start +## keep server log-level by reload (without restart it) +fail2ban-client --loglevel DEBUG reload +## switch log-level back to INFO: +fail2ban-client set loglevel INFO +``` +* Optimized BanManager: increase performance, fewer system load, try to prevent + memory leakage: + - better ban/unban handling within actions (e.g. used dict instead of list) + - don't copy bans resp. its list on some operations; + - added new unbantime handling to relieve unBanList (prevent permanent + searching for tickets to unban) + - prefer failure-ID as identifier of the ticket to its IP (most of the time + the same, but it can be something else e.g. user name in some complex jails, + as introduced in 0.10) +* Regexp enhancements: + - build replacement of `` substitution corresponding parameter + `usedns` - dns-part will be added only if `usedns` is not `no`, + also using fail2ban-regex + - new replacement for `` in opposition to ``, for separate + usage of 2 address groups only (regardless of `usedns`), `ip4` and `ip6` + together, without host (dns) +* Misconfigured jails don't prevent fail2ban from starting, server starts + nevertheless, as long as one jail was successful configured (gh-1619) + Message about wrong jail configuration logged in client log (stdout, systemd + journal etc.) and in server log with error level +* More precise date template handling (WARNING: theoretically possible incompatibilities): + - datedetector rewritten more strict as earlier; + - default templates can be specified exacter using prefix/suffix syntax (via `datepattern`); + - more as one date pattern can be specified using option `datepattern` now + (new-line separated); + - some default options like `datepattern` can be specified directly in + section `[Definition]`, that avoids contrary usage of unnecessarily `[Init]` + section, because of performance (each extra section costs time); + - option `datepattern` can be specified in jail also (e. g. jails without filters + or custom log-format, new-line separated for multiple patterns); + - if first unnamed group specified in pattern, only this will be cut out from + search log-line (e. g.: `^date:[({DATE})]` will cut out only datetime match + pattern, and leaves `date:[] ...` for searching in filter); + - faster match and fewer searching of appropriate templates + (DateDetector.matchTime calls rarer DateTemplate.matchDate now); + - several standard filters extended with exact prefixed or anchored date templates; +* Added possibility to recognize restored state of the tickets (see gh-1669). + New option `norestored` introduced, to ignore restored tickets (after restart). + To avoid execution of ban/unban for the restored tickets, `norestored = true` + could be added in definition section of action. + For conditional usage in the shell-based actions an interpolation `` + could be used also. E. g. it is enough to add following script-piece at begin + of `actionban` (or `actionunban`) to prevent execution: + `if [ '' = '1' ]; then exit 0; fi;` + Several actions extended now using `norestored` option: + - complain.conf + - dshield.conf + - mail-buffered.conf + - mail-whois-lines.conf + - mail-whois.conf + - mail.conf + - sendmail-buffered.conf + - sendmail-geoip-lines.conf + - sendmail-whois-ipjailmatches.conf + - sendmail-whois-ipmatches.conf + - sendmail-whois-lines.conf + - sendmail-whois-matches.conf + - sendmail-whois.conf + - sendmail.conf + - smtp.py + - xarf-login-attack.conf +* fail2ban-testcases: + - `assertLogged` extended with parameter wait (to wait up to specified timeout, + before we throw assert exception) + test cases rewritten using that + - added `assertDictEqual` for compatibility to early python versions (< 2.7); + - new `with_foreground_server_thread` decorator to test several client/server commands + + +ver. 0.9.8 (2016/XX/XXX) - wanna-be-released ----------- 0.9.x line is no longer heavily developed. If you are interested in new features (e.g. IPv6 support), please consider 0.10 branch and its releases. + +### Fixes +* Fix for systemd-backend: fail2ban hits the ulimit (out of file descriptors), see gh-991. + Partially back-ported from v.0.10. +* action.d/bsd-ipfw.conf + - Make the rule number, the action starts looking for a free slot to insert + the new rule, configurable (gh-1689) + - Replace not posix-compliant grep option: fgrep with `-q` option can cause + 141 exit code in some cases (gh-1389) +* filter.d/apache-overflows.conf: + - Fixes resources greedy expression (see gh-1790); + - 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 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) +* filter.d/dovecot.conf: + - fixed failregex, see gh-1879 (partially cherry-picked from gh-1880) + - extended to match pam_authenticate failures with "Permission denied" (gh-1897) +* filter.d/exim.conf + - fixed failregex for case of flood attempts with `D=0s` (gh-1887) + - fixed failregex of "AUTH command used when not advertised" to better handle the foreign + input SMTP command (lower/mixed case auth command, prevent injection) (gh-1979) +* filter.d/postfix-*.conf - added optional port regex (gh-1902) +* filter.d/sendmail-auth.conf - extended daemon for Fedora 24/RHEL - the daemon name is "sendmail" (gh-1632) +* filter.d/nginx-http-auth.conf - match usernames with spaces (gh-2015) + +### New Features + +### Enhancements +* action.d/cloudflare.conf - Cloudflare API v4 implementation (gh-1651) +* action.d/firewallcmd-ipset.conf - new parameter `actiontype`, provides `allports` capability (gh-1167) +* filter.d/kerio.conf - filter extended with new rules (see gh-1455) +* filter.d/phpmyadmin-syslog.conf - new filter for phpMyAdmin using syslog for auth logging +* filter.d/zoneminder.conf - new filter for ZoneMinder (gh-1376) + + +ver. 0.9.7 (2017/05/11) - awaiting-victory +----------- + ### Fixes * Fixed a systemd-journal handling in fail2ban-regex (gh-1657) * filter.d/sshd.conf diff --git a/MANIFEST b/MANIFEST index e91ccff0..bfdd77c0 100644 --- a/MANIFEST +++ b/MANIFEST @@ -3,6 +3,7 @@ bin/fail2ban-regex bin/fail2ban-server bin/fail2ban-testcases ChangeLog +config/action.d/abuseipdb.conf config/action.d/apf.conf config/action.d/badips.conf config/action.d/badips.py @@ -13,11 +14,13 @@ config/action.d/complain.conf config/action.d/dshield.conf config/action.d/dummy.conf config/action.d/firewallcmd-allports.conf +config/action.d/firewallcmd-common.conf config/action.d/firewallcmd-ipset.conf config/action.d/firewallcmd-multiport.conf config/action.d/firewallcmd-new.conf config/action.d/firewallcmd-rich-logging.conf config/action.d/firewallcmd-rich-rules.conf +config/action.d/helpers-common.conf config/action.d/hostsdeny.conf config/action.d/ipfilter.conf config/action.d/ipfw.conf @@ -41,6 +44,7 @@ config/action.d/netscaler.conf config/action.d/nftables-allports.conf config/action.d/nftables-common.conf config/action.d/nftables-multiport.conf +config/action.d/nginx-block-map.conf config/action.d/npf.conf config/action.d/nsupdate.conf config/action.d/osx-afctl.conf @@ -99,7 +103,6 @@ config/filter.d/gssftpd.conf config/filter.d/guacamole.conf config/filter.d/haproxy-http-auth.conf config/filter.d/horde.conf -config/filter.d/ignorecommands config/filter.d/ignorecommands/apache-fakegooglebot config/filter.d/kerio.conf config/filter.d/lighttpd-auth.conf @@ -118,11 +121,10 @@ config/filter.d/openwebmail.conf config/filter.d/oracleims.conf config/filter.d/pam-generic.conf config/filter.d/perdition.conf +config/filter.d/phpmyadmin-syslog.conf config/filter.d/php-url-fopen.conf config/filter.d/portsentry.conf config/filter.d/postfix.conf -config/filter.d/postfix-rbl.conf -config/filter.d/postfix-sasl.conf config/filter.d/proftpd.conf config/filter.d/pure-ftpd.conf config/filter.d/qmail.conf @@ -133,16 +135,13 @@ config/filter.d/selinux-common.conf config/filter.d/selinux-ssh.conf config/filter.d/sendmail-auth.conf config/filter.d/sendmail-reject.conf -config/filter.d/sendmail-spam.conf config/filter.d/sieve.conf config/filter.d/slapd.conf config/filter.d/sogo-auth.conf config/filter.d/solid-pop3d.conf config/filter.d/squid.conf config/filter.d/squirrelmail.conf -config/filter.d/sshd-aggressive.conf config/filter.d/sshd.conf -config/filter.d/sshd-ddos.conf config/filter.d/stunnel.conf config/filter.d/suhosin.conf config/filter.d/tine20.conf @@ -151,7 +150,9 @@ config/filter.d/vsftpd.conf config/filter.d/webmin-auth.conf config/filter.d/wuftpd.conf config/filter.d/xinetd-fail.conf +config/filter.d/zoneminder.conf config/jail.conf +config/paths-arch.conf config/paths-common.conf config/paths-debian.conf config/paths-fedora.conf @@ -162,7 +163,6 @@ CONTRIBUTING.md COPYING .coveragerc DEVELOP -doc/run-rootless.txt fail2ban-2to3 fail2ban/client/actionreader.py fail2ban/client/beautifier.py @@ -170,8 +170,11 @@ fail2ban/client/configparserinc.py fail2ban/client/configreader.py fail2ban/client/configurator.py fail2ban/client/csocket.py +fail2ban/client/fail2banclient.py +fail2ban/client/fail2bancmdline.py fail2ban/client/fail2banreader.py fail2ban/client/fail2banregex.py +fail2ban/client/fail2banserver.py fail2ban/client/filterreader.py fail2ban/client/__init__.py fail2ban/client/jailreader.py @@ -187,7 +190,6 @@ fail2ban/server/banmanager.py fail2ban/server/database.py fail2ban/server/datedetector.py fail2ban/server/datetemplate.py -fail2ban/server/faildata.py fail2ban/server/failmanager.py fail2ban/server/failregex.py fail2ban/server/filtergamin.py @@ -196,7 +198,7 @@ fail2ban/server/filter.py fail2ban/server/filterpyinotify.py fail2ban/server/filtersystemd.py fail2ban/server/__init__.py -fail2ban/server/iso8601.py +fail2ban/server/ipdns.py fail2ban/server/jail.py fail2ban/server/jails.py fail2ban/server/jailthread.py @@ -205,6 +207,7 @@ fail2ban/server/server.py fail2ban/server/strptime.py fail2ban/server/ticket.py fail2ban/server/transmitter.py +fail2ban/server/utils.py fail2ban/setup.py fail2ban-testcases-all fail2ban-testcases-all-python3 @@ -214,22 +217,20 @@ fail2ban/tests/action_d/test_smtp.py fail2ban/tests/actionstestcase.py fail2ban/tests/actiontestcase.py fail2ban/tests/banmanagertestcase.py +fail2ban/tests/clientbeautifiertestcase.py fail2ban/tests/clientreadertestcase.py fail2ban/tests/config/action.d/brokenaction.conf fail2ban/tests/config/fail2ban.conf -fail2ban/tests/config/filter.d/common.conf fail2ban/tests/config/filter.d/simple.conf fail2ban/tests/config/filter.d/test.conf fail2ban/tests/config/filter.d/test.local fail2ban/tests/config/filter.d/zzz-generic-example.conf +fail2ban/tests/config/filter.d/zzz-sshd-obsolete-multiline.conf fail2ban/tests/config/jail.conf -fail2ban/tests/config/paths-common.conf -fail2ban/tests/config/paths-debian.conf -fail2ban/tests/config/paths-freebsd.conf -fail2ban/tests/config/paths-osx.conf fail2ban/tests/databasetestcase.py fail2ban/tests/datedetectortestcase.py fail2ban/tests/dummyjail.py +fail2ban/tests/fail2banclienttestcase.py fail2ban/tests/fail2banregextestcase.py fail2ban/tests/failmanagertestcase.py fail2ban/tests/files/action.d/action_checkainfo.py @@ -262,7 +263,6 @@ fail2ban/tests/files/ignorecommand.py fail2ban/tests/files/logs/3proxy fail2ban/tests/files/logs/apache-auth fail2ban/tests/files/logs/apache-badbots -fail2ban/tests/files/logs/apache-botscripts fail2ban/tests/files/logs/apache-botsearch fail2ban/tests/files/logs/apache-fakegooglebot fail2ban/tests/files/logs/apache-modsecurity @@ -312,11 +312,10 @@ fail2ban/tests/files/logs/openwebmail fail2ban/tests/files/logs/oracleims fail2ban/tests/files/logs/pam-generic fail2ban/tests/files/logs/perdition +fail2ban/tests/files/logs/phpmyadmin-syslog fail2ban/tests/files/logs/php-url-fopen fail2ban/tests/files/logs/portsentry fail2ban/tests/files/logs/postfix -fail2ban/tests/files/logs/postfix-rbl -fail2ban/tests/files/logs/postfix-sasl fail2ban/tests/files/logs/proftpd fail2ban/tests/files/logs/pure-ftpd fail2ban/tests/files/logs/qmail @@ -326,7 +325,6 @@ fail2ban/tests/files/logs/screensharingd fail2ban/tests/files/logs/selinux-ssh fail2ban/tests/files/logs/sendmail-auth fail2ban/tests/files/logs/sendmail-reject -fail2ban/tests/files/logs/sendmail-spam fail2ban/tests/files/logs/sieve fail2ban/tests/files/logs/slapd fail2ban/tests/files/logs/sogo-auth @@ -334,8 +332,6 @@ fail2ban/tests/files/logs/solid-pop3d fail2ban/tests/files/logs/squid fail2ban/tests/files/logs/squirrelmail fail2ban/tests/files/logs/sshd -fail2ban/tests/files/logs/sshd-aggressive -fail2ban/tests/files/logs/sshd-ddos fail2ban/tests/files/logs/stunnel fail2ban/tests/files/logs/suhosin fail2ban/tests/files/logs/tine20 @@ -344,7 +340,10 @@ fail2ban/tests/files/logs/vsftpd fail2ban/tests/files/logs/webmin-auth fail2ban/tests/files/logs/wuftpd fail2ban/tests/files/logs/xinetd-fail +fail2ban/tests/files/logs/zoneminder fail2ban/tests/files/logs/zzz-generic-example +fail2ban/tests/files/logs/zzz-sshd-obsolete-multiline +fail2ban/tests/files/testcase01a.log fail2ban/tests/files/testcase01.log fail2ban/tests/files/testcase02.log fail2ban/tests/files/testcase03.log @@ -353,12 +352,14 @@ fail2ban/tests/files/testcase-journal.log fail2ban/tests/files/testcase-multiline.log fail2ban/tests/files/testcase-usedns.log fail2ban/tests/files/testcase-wrong-char.log +fail2ban/tests/files/zzz-sshd-obsolete-multiline.log fail2ban/tests/filtertestcase.py fail2ban/tests/__init__.py fail2ban/tests/misctestcase.py fail2ban/tests/samplestestcase.py fail2ban/tests/servertestcase.py fail2ban/tests/sockettestcase.py +fail2ban/tests/tickettestcase.py fail2ban/tests/utils.py fail2ban/version.py files/bash-completion @@ -367,7 +368,7 @@ files/cacti/fail2ban_stats.sh files/cacti/README files/debian-initd files/fail2ban-logrotate -files/fail2ban.service +files/fail2ban.service.in files/fail2ban-tmpfiles.conf files/fail2ban.upstart files/gen_badbots diff --git a/README.md b/README.md index 89844d1d..94485adb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ / _|__ _(_) |_ ) |__ __ _ _ _ | _/ _` | | |/ /| '_ \/ _` | ' \ |_| \__,_|_|_/___|_.__/\__,_|_||_| - v0.9.7 2017/05/11 + v0.10.2 2018/01/18 ## Fail2Ban: ban hosts that cause multiple authentication errors @@ -17,9 +17,13 @@ Though Fail2Ban is able to reduce the rate of incorrect authentications attempts, it cannot eliminate the risk that weak authentication presents. Configure services to use only two factor or public/private authentication mechanisms if you really want to protect services. + + | Since v0.10 fail2ban supports the matching of the IPv6 addresses. +------|------ This README is a quick introduction to Fail2ban. More documentation, FAQ, HOWTOs -are available in fail2ban(1) manpage and on the website http://www.fail2ban.org +are available in fail2ban(1) manpage, [Wiki](https://github.com/fail2ban/fail2ban/wiki) +and on the website http://www.fail2ban.org Installation: ------------- @@ -39,8 +43,8 @@ Optional: To install, just do: - tar xvfj fail2ban-0.9.6.tar.bz2 - cd fail2ban-0.9.6 + tar xvfj fail2ban-0.10.2.tar.bz2 + cd fail2ban-0.10.2 python setup.py install This will install Fail2Ban into the python library directory. The executable @@ -73,11 +77,11 @@ fail2ban(1) and jail.conf(5) manpages for further references. Code status: ------------ -* [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.png?branch=master)](https://travis-ci.org/fail2ban/fail2ban) travis-ci.org (master branch) +* [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.png?branch=0.10)](https://travis-ci.org/fail2ban/fail2ban?branch=0.10) travis-ci.org (0.10 branch) / [![tests status](https://secure.travis-ci.org/fail2ban/fail2ban.png?branch=master)](https://travis-ci.org/fail2ban/fail2ban) travis-ci.org (master branch) -* [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.png?branch=master)](https://coveralls.io/r/fail2ban/fail2ban) +* [![Coverage Status](https://coveralls.io/repos/fail2ban/fail2ban/badge.png?branch=0.10)](https://coveralls.io/github/fail2ban/fail2ban?branch=0.10) -* [![codecov.io](https://codecov.io/github/fail2ban/fail2ban/coverage.svg?branch=master)](https://codecov.io/github/fail2ban/fail2ban?branch=master) +* [![codecov.io](https://codecov.io/gh/fail2ban/fail2ban/coverage.svg?branch=0.10)](https://codecov.io/gh/fail2ban/fail2ban/branch/0.10) Contact: -------- @@ -86,7 +90,7 @@ Contact: See [CONTRIBUTING.md](https://github.com/fail2ban/fail2ban/blob/master/CONTRIBUTING.md) ### You just appreciate this program: -send kudos to the original author ([Cyril Jaquier](mailto: Cyril Jaquier )) +send kudos to the original author ([Cyril Jaquier](mailto:cyril.jaquier@fail2ban.org)) or *better* to the [mailing list](https://lists.sourceforge.net/lists/listinfo/fail2ban-users) since Fail2Ban is "community-driven" for years now. diff --git a/RELEASE b/RELEASE index c4f62d7a..2b2bc58e 100644 --- a/RELEASE +++ b/RELEASE @@ -53,7 +53,7 @@ Preparation or an alternative for comparison with previous release - git diff 0.9.6 | grep -B2 'index 0000000..' | grep -B1 'new file mode' | sed -n -e '/^diff /s,.* b/,,gp' >> MANIFEST + git diff 0.10.0 | grep -B2 'index 0000000..' | grep -B1 'new file mode' | sed -n -e '/^diff /s,.* b/,,gp' >> MANIFEST sort MANIFEST | uniq | sponge MANIFEST * Run:: @@ -70,7 +70,7 @@ Preparation * clean up current directory:: - diff -rul --exclude \*.pyc . /tmp/fail2ban-0.9.6/ + diff -rul --exclude \*.pyc . /tmp/fail2ban-0.10.0/ * Only differences should be files that you don't want distributed. @@ -83,7 +83,7 @@ Preparation * To generate a list of committers use e.g.:: - git shortlog -sn 0.9.6.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g' + git shortlog -sn 0.10.0.. | sed -e 's,^[ 0-9\t]*,,g' | tr '\n' '\|' | sed -e 's:|:, :g' * Ensure the top of the ChangeLog has the right version and current date. * Ensure the top entry of the ChangeLog has the right version and current date. @@ -106,7 +106,7 @@ Preparation * Tag the release by using a signed (and annotated) tag. Cut/paste release ChangeLog entry as tag annotation:: - git tag -s 0.9.6 + git tag -s 0.10.0 Pre Release =========== @@ -190,7 +190,7 @@ Post Release Add the following to the top of the ChangeLog:: - ver. 0.9.8 (2016/XX/XXX) - wanna-be-released + ver. 0.10.0 (2016/XX/XXX) - wanna-be-released ----------- ### Fixes diff --git a/THANKS b/THANKS index 7d9137d7..7861ceb5 100644 --- a/THANKS +++ b/THANKS @@ -12,9 +12,11 @@ Adrien Clerc ache ag4ve (Shawn) Alasdair D. Campbell +Alexander Koeppe (IPv6 support) Alexandre Perrin (kAworu) Amir Caspi Amy +Andrew James Collett (ajcollett) Andrew St. Jean Andrey G. Grozin Andy Fragen @@ -59,6 +61,7 @@ John Thoe Jacques Lav!gnotte Johannes Weberhofer Jason H Martin +Jeaye Wilkerson Jisoo Park Joel M Snyder Jonathan Kamens @@ -109,6 +112,8 @@ SATO Kentaro Sean DuBois Sebastian Arcus Serg G. Brester +Sergey Safarov +Shaun C. Sireyessire silviogarbes Stefan Tatschner diff --git a/bin/fail2ban-client b/bin/fail2ban-client index dc2f7d84..5e6843ed 100755 --- a/bin/fail2ban-client +++ b/bin/fail2ban-client @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 : @@ -18,458 +18,20 @@ # along with Fail2Ban; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -__author__ = "Cyril Jaquier" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +""" +Fail2Ban reads log file that contains password failure report +and bans the corresponding IP addresses using firewall rules. + +This tools starts/stops fail2ban server or does client/server communication, +to change/read parameters of the server or jails. + +""" + +__author__ = "Fail2Ban Developers" +__copyright__ = "Copyright (c) 2004-2008 Cyril Jaquier, 2012-2014 Yaroslav Halchenko, 2014-2016 Serg G. Brester" __license__ = "GPL" -import getopt -import logging -import os -import pickle -import re -import shlex -import signal -import socket -import string -import sys -import time +from fail2ban.client.fail2banclient import exec_command_line, sys -from fail2ban.version import version -from fail2ban.protocol import printFormatted -from fail2ban.client.csocket import CSocket -from fail2ban.client.configurator import Configurator -from fail2ban.client.beautifier import Beautifier -from fail2ban.helpers import getLogger - -# Gets the instance of the logger. -logSys = getLogger("fail2ban") - -## -# -# @todo This class needs cleanup. - -class Fail2banClient: - - SERVER = "fail2ban-server" - PROMPT = "fail2ban> " - - def __init__(self): - self.__argv = None - self.__stream = None - self.__configurator = Configurator() - self.__conf = dict() - self.__conf["conf"] = "/etc/fail2ban" - self.__conf["dump"] = False - self.__conf["force"] = False - self.__conf["background"] = True - self.__conf["verbose"] = 1 - self.__conf["interactive"] = False - self.__conf["socket"] = None - self.__conf["pidfile"] = None - - def dispVersion(self): - print "Fail2Ban v" + version - print - print "Copyright (c) 2004-2008 Cyril Jaquier, 2008- Fail2Ban Contributors" - print "Copyright of modifications held by their respective authors." - print "Licensed under the GNU General Public License v2 (GPL)." - print - print "Written by Cyril Jaquier ." - print "Many contributions by Yaroslav O. Halchenko ." - - def dispUsage(self): - """ Prints Fail2Ban command line options and exits - """ - print "Usage: "+self.__argv[0]+" [OPTIONS] " - print - print "Fail2Ban v" + version + " reads log file that contains password failure report" - print "and bans the corresponding IP addresses using firewall rules." - print - print "Options:" - print " -c configuration directory" - print " -s socket path" - print " -p pidfile path" - print " -d dump configuration. For debugging" - print " -i interactive mode" - print " -v increase verbosity" - print " -q decrease verbosity" - print " -x force execution of the server (remove socket file)" - print " -b start server in background (default)" - print " -f start server in foreground (note that the client forks once itself)" - print " -h, --help display this help message" - print " -V, --version print the version" - print - print "Command:" - - # Prints the protocol - printFormatted() - - print - print "Report bugs to https://github.com/fail2ban/fail2ban/issues" - - def dispInteractive(self): - print "Fail2Ban v" + version + " reads log file that contains password failure report" - print "and bans the corresponding IP addresses using firewall rules." - print - - def __sigTERMhandler(self, signum, frame): - # Print a new line because we probably come from wait - print - logSys.warning("Caught signal %d. Exiting" % signum) - sys.exit(-1) - - def __getCmdLineOptions(self, optList): - """ Gets the command line options - """ - for opt in optList: - if opt[0] == "-c": - self.__conf["conf"] = opt[1] - elif opt[0] == "-s": - self.__conf["socket"] = opt[1] - elif opt[0] == "-p": - self.__conf["pidfile"] = opt[1] - elif opt[0] == "-d": - self.__conf["dump"] = True - elif opt[0] == "-v": - self.__conf["verbose"] = self.__conf["verbose"] + 1 - elif opt[0] == "-q": - self.__conf["verbose"] = self.__conf["verbose"] - 1 - elif opt[0] == "-x": - self.__conf["force"] = True - elif opt[0] == "-i": - self.__conf["interactive"] = True - elif opt[0] == "-b": - self.__conf["background"] = True - elif opt[0] == "-f": - self.__conf["background"] = False - elif opt[0] in ["-h", "--help"]: - self.dispUsage() - sys.exit(0) - elif opt[0] in ["-V", "--version"]: - self.dispVersion() - sys.exit(0) - - def __ping(self): - return self.__processCmd([["ping"]], False) - - def __processCmd(self, cmd, showRet = True): - client = None - try: - beautifier = Beautifier() - streamRet = True - for c in cmd: - beautifier.setInputCmd(c) - try: - if not client: - client = CSocket(self.__conf["socket"]) - ret = client.send(c) - if ret[0] == 0: - logSys.debug("OK : " + `ret[1]`) - if showRet: - print beautifier.beautify(ret[1]) - else: - logSys.error("NOK: " + `ret[1].args`) - if showRet: - print beautifier.beautifyError(ret[1]) - streamRet = False - except socket.error: - if showRet: - self.__logSocketError() - return False - except Exception as e: - if showRet: - logSys.error(e) - return False - finally: - if client: - client.close() - return streamRet - - def __logSocketError(self): - try: - if os.access(self.__conf["socket"], os.F_OK): - # This doesn't check if path is a socket, - # but socket.error should be raised - if os.access(self.__conf["socket"], os.W_OK): - # Permissions look good, but socket.error was raised - logSys.error("Unable to contact server. Is it running?") - else: - logSys.error("Permission denied to socket: %s," - " (you must be root)", self.__conf["socket"]) - else: - logSys.error("Failed to access socket path: %s." - " Is fail2ban running?", - self.__conf["socket"]) - except Exception as e: - logSys.error("Exception while checking socket access: %s", - self.__conf["socket"]) - logSys.error(e) - - ## - # Process a command line. - # - # Process one command line and exit. - # @param cmd the command line - - def __processCommand(self, cmd): - if len(cmd) == 1 and cmd[0] == "start": - if self.__ping(): - logSys.error("Server already running") - return False - else: - # Read the config - ret = self.__readConfig() - # Do not continue if configuration is not 100% valid - if not ret: - return False - # verify that directory for the socket file exists - socket_dir = os.path.dirname(self.__conf["socket"]) - if not os.path.exists(socket_dir): - logSys.error( - "There is no directory %s to contain the socket file %s." - % (socket_dir, self.__conf["socket"])) - return False - if not os.access(socket_dir, os.W_OK | os.X_OK): - logSys.error( - "Directory %s exists but not accessible for writing" - % (socket_dir,)) - return False - # Start the server - self.__startServerAsync(self.__conf["socket"], - self.__conf["pidfile"], - self.__conf["force"], - self.__conf["background"]) - try: - # Wait for the server to start - self.__waitOnServer() - # Configure the server - self.__processCmd(self.__stream, False) - return True - except ServerExecutionException: - logSys.error("Could not start server. Maybe an old " - "socket file is still present. Try to " - "remove " + self.__conf["socket"] + ". If " - "you used fail2ban-client to start the " - "server, adding the -x option will do it") - return False - elif len(cmd) == 1 and cmd[0] == "reload": - if self.__ping(): - ret = self.__readConfig() - # Do not continue if configuration is not 100% valid - if not ret: - return False - self.__processCmd([['stop', 'all']], False) - # Configure the server - return self.__processCmd(self.__stream, False) - else: - logSys.error("Could not find server") - return False - elif len(cmd) == 2 and cmd[0] == "reload": - if self.__ping(): - jail = cmd[1] - ret = self.__readConfig(jail) - # Do not continue if configuration is not 100% valid - if not ret: - return False - self.__processCmd([['stop', jail]], False) - # Configure the server - return self.__processCmd(self.__stream, False) - else: - logSys.error("Could not find server") - return False - else: - return self.__processCmd([cmd]) - - - ## - # Start Fail2Ban server. - # - # Start the Fail2ban server in daemon mode. - - def __startServerAsync(self, socket, pidfile, force = False, background = True): - # Forks the current process. - pid = os.fork() - if pid == 0: - args = list() - args.append(self.SERVER) - # Set the socket path. - args.append("-s") - args.append(socket) - # Set the pidfile - args.append("-p") - args.append(pidfile) - # Force the execution if needed. - if force: - args.append("-x") - # Start in foreground mode if requested. - if background: - args.append("-b") - else: - args.append("-f") - - try: - # Use the current directory. - exe = os.path.abspath(os.path.join(sys.path[0], self.SERVER)) - logSys.debug("Starting %r with args %r" % (exe, args)) - os.execv(exe, args) - except OSError: - try: - # Use the PATH env. - logSys.warning("Initial start attempt failed. Starting %r with the same args" % (self.SERVER,)) - os.execvp(self.SERVER, args) - except OSError: - logSys.error("Could not start %s" % self.SERVER) - os.exit(-1) - - def __waitOnServer(self): - # Wait for the server to start - cnt = 0 - if self.__conf["verbose"] > 1: - pos = 0 - delta = 1 - mask = "[ ]" - while not self.__ping(): - # Wonderful visual :) - if self.__conf["verbose"] > 1: - pos += delta - sys.stdout.write("\rINFO " + mask[:pos] + '#' + mask[pos+1:] + - " Waiting on the server...") - sys.stdout.flush() - if pos > len(mask)-3: - delta = -1 - elif pos < 2: - delta = 1 - # The server has 30 seconds to start. - if cnt >= 300: - if self.__conf["verbose"] > 1: - sys.stdout.write('\n') - raise ServerExecutionException("Failed to start server") - time.sleep(0.1) - cnt += 1 - if self.__conf["verbose"] > 1: - sys.stdout.write('\n') - - - def start(self, argv): - # Command line options - self.__argv = argv - - # Install signal handlers - signal.signal(signal.SIGTERM, self.__sigTERMhandler) - signal.signal(signal.SIGINT, self.__sigTERMhandler) - - # Reads the command line options. - try: - cmdOpts = 'hc:s:p:xfbdviqV' - cmdLongOpts = ['help', 'version'] - optList, args = getopt.getopt(self.__argv[1:], cmdOpts, cmdLongOpts) - except getopt.GetoptError: - self.dispUsage() - return False - - self.__getCmdLineOptions(optList) - - verbose = self.__conf["verbose"] - if verbose <= 0: - logSys.setLevel(logging.ERROR) - elif verbose == 1: - logSys.setLevel(logging.WARNING) - elif verbose == 2: - logSys.setLevel(logging.INFO) - elif verbose == 3: - logSys.setLevel(logging.DEBUG) - else: - logSys.setLevel(logging.HEAVYDEBUG) - # Add the default logging handler to dump to stderr - logout = logging.StreamHandler(sys.stderr) - # set a format which is simpler for console use - formatter = logging.Formatter('%(levelname)-6s %(message)s') - # tell the handler to use this format - logout.setFormatter(formatter) - logSys.addHandler(logout) - - # Set the configuration path - self.__configurator.setBaseDir(self.__conf["conf"]) - - # Set socket path - self.__configurator.readEarly() - conf = self.__configurator.getEarlyOptions() - if self.__conf["socket"] is None: - self.__conf["socket"] = conf["socket"] - if self.__conf["pidfile"] is None: - self.__conf["pidfile"] = conf["pidfile"] - logSys.info("Using socket file " + self.__conf["socket"]) - - if self.__conf["dump"]: - ret = self.__readConfig() - self.dumpConfig(self.__stream) - return ret - - # Interactive mode - if self.__conf["interactive"]: - try: - import readline - except ImportError: - logSys.error("Readline not available") - return False - try: - ret = True - if len(args) > 0: - ret = self.__processCommand(args) - if ret: - readline.parse_and_bind("tab: complete") - self.dispInteractive() - while True: - cmd = raw_input(self.PROMPT) - if cmd == "exit" or cmd == "quit": - # Exit - return True - if cmd == "help": - self.dispUsage() - elif not cmd == "": - try: - self.__processCommand(shlex.split(cmd)) - except Exception as e: - logSys.error(e) - except (EOFError, KeyboardInterrupt): - print - return True - # Single command mode - else: - if len(args) < 1: - self.dispUsage() - return False - return self.__processCommand(args) - - def __readConfig(self, jail=None): - # Read the configuration - # TODO: get away from stew of return codes and exception - # handling -- handle via exceptions - try: - self.__configurator.Reload() - self.__configurator.readAll() - ret = self.__configurator.getOptions(jail) - self.__configurator.convertToProtocol() - self.__stream = self.__configurator.getConfigStream() - except Exception as e: - logSys.error("Failed during configuration: %s" % e) - ret = False - return ret - - @staticmethod - def dumpConfig(cmd): - for c in cmd: - print c - return True - - -class ServerExecutionException(Exception): - pass - -if __name__ == "__main__": # pragma: no cover - can't test main - client = Fail2banClient() - # Exit with correct return value - if client.start(sys.argv): - sys.exit(0) - else: - sys.exit(-1) +if __name__ == "__main__": + exec_command_line(sys.argv) diff --git a/bin/fail2ban-regex b/bin/fail2ban-regex index 584c1ea7..09044f0a 100755 --- a/bin/fail2ban-regex +++ b/bin/fail2ban-regex @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 : # diff --git a/bin/fail2ban-server b/bin/fail2ban-server index 23eae136..860a7607 100755 --- a/bin/fail2ban-server +++ b/bin/fail2ban-server @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 : @@ -18,123 +18,20 @@ # along with Fail2Ban; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -__author__ = "Cyril Jaquier" -__copyright__ = "Copyright (c) 2004 Cyril Jaquier" +""" +Fail2Ban reads log file that contains password failure report +and bans the corresponding IP addresses using firewall rules. + +This tools starts/stops fail2ban server or does client/server communication, +to change/read parameters of the server or jails. + +""" + +__author__ = "Fail2Ban Developers" +__copyright__ = "Copyright (c) 2004-2008 Cyril Jaquier, 2012-2014 Yaroslav Halchenko, 2014-2016 Serg G. Brester" __license__ = "GPL" -import getopt -import os -import sys - -from fail2ban.version import version -from fail2ban.server.server import Server -from fail2ban.helpers import getLogger - -# Gets the instance of the logger. -logSys = getLogger("fail2ban") - -## -# \mainpage Fail2Ban -# -# \section Introduction -# -# Fail2ban is designed to protect your server against brute force attacks. -# Its first goal was to protect a SSH server. - -class Fail2banServer: - - def __init__(self): - self.__server = None - self.__argv = None - self.__conf = dict() - self.__conf["background"] = True - self.__conf["force"] = False - self.__conf["socket"] = "/var/run/fail2ban/fail2ban.sock" - self.__conf["pidfile"] = "/var/run/fail2ban/fail2ban.pid" - - def dispVersion(self): - print "Fail2Ban v" + version - print - print "Copyright (c) 2004-2008 Cyril Jaquier, 2008- Fail2Ban Contributors" - print "Copyright of modifications held by their respective authors." - print "Licensed under the GNU General Public License v2 (GPL)." - print - print "Written by Cyril Jaquier ." - print "Many contributions by Yaroslav O. Halchenko ." - - def dispUsage(self): - """ Prints Fail2Ban command line options and exits - """ - print "Usage: "+self.__argv[0]+" [OPTIONS]" - print - print "Fail2Ban v" + version + " reads log file that contains password failure report" - print "and bans the corresponding IP addresses using firewall rules." - print - print "Only use this command for debugging purpose. Start the server with" - print "fail2ban-client instead. The default behaviour is to start the server" - print "in background." - print - print "Options:" - print " -b start in background" - print " -f start in foreground" - print " -s socket path" - print " -p pidfile path" - print " -x force execution of the server (remove socket file)" - print " -h, --help display this help message" - print " -V, --version print the version" - print - print "Report bugs to https://github.com/fail2ban/fail2ban/issues" - - def __getCmdLineOptions(self, optList): - """ Gets the command line options - """ - for opt in optList: - if opt[0] == "-b": - self.__conf["background"] = True - if opt[0] == "-f": - self.__conf["background"] = False - if opt[0] == "-s": - self.__conf["socket"] = opt[1] - if opt[0] == "-p": - self.__conf["pidfile"] = opt[1] - if opt[0] == "-x": - self.__conf["force"] = True - if opt[0] in ["-h", "--help"]: - self.dispUsage() - sys.exit(0) - if opt[0] in ["-V", "--version"]: - self.dispVersion() - sys.exit(0) - - def start(self, argv): - # Command line options - self.__argv = argv - - # Reads the command line options. - try: - cmdOpts = 'bfs:p:xhV' - cmdLongOpts = ['help', 'version'] - optList, args = getopt.getopt(self.__argv[1:], cmdOpts, cmdLongOpts) - except getopt.GetoptError: - self.dispUsage() - sys.exit(-1) - - self.__getCmdLineOptions(optList) - - try: - self.__server = Server(self.__conf["background"]) - self.__server.start(self.__conf["socket"], - self.__conf["pidfile"], - self.__conf["force"]) - return True - except Exception as e: - logSys.exception(e) - self.__server.quit() - return False +from fail2ban.client.fail2banserver import exec_command_line, sys if __name__ == "__main__": - server = Fail2banServer() - if server.start(sys.argv): - sys.exit(0) - else: - sys.exit(-1) + exec_command_line(sys.argv) diff --git a/bin/fail2ban-testcases b/bin/fail2ban-testcases index a711e07c..5539d4c6 100755 --- a/bin/fail2ban-testcases +++ b/bin/fail2ban-testcases @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/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 @@ -30,19 +30,15 @@ import sys import time import unittest -# Check if local fail2ban module exists, and use if it exists by +# Check if local fail2ban module exists, and use if it exists by # modifying the path. This is such that tests can be used in dev # environment. if os.path.exists("fail2ban/__init__.py"): sys.path.insert(0, ".") from fail2ban.version import version -from fail2ban.tests.utils import gatherTests -from fail2ban.helpers import FormatterWithTraceBack, getLogger +from fail2ban.tests.utils import getOptParser, initProcess, gatherTests from fail2ban.setup import updatePyExec -from fail2ban.server.mytime import MyTime - -from optparse import OptionParser, Option # Update fail2ban-python env to current python version (where f2b-modules located/installed) bindir = os.path.dirname( @@ -51,84 +47,19 @@ bindir = os.path.dirname( ) updatePyExec(bindir) -def get_opt_parser(): - # use module docstring for help output - p = OptionParser( - usage="%s [OPTIONS] [regexps]\n" % sys.argv[0] + __doc__, - version="%prog " + version) - - p.add_options([ - Option('-l', "--log-level", type="choice", - dest="log_level", - choices=('heavydebug', 'debug', 'info', 'notice', 'warning', 'error', 'critical'), - default=None, - help="Log level for the logger to use during running tests"), - Option('-n', "--no-network", action="store_true", - dest="no_network", - help="Do not run tests that require the network"), - Option("-t", "--log-traceback", action='store_true', - help="Enrich log-messages with compressed tracebacks"), - Option("--full-traceback", action='store_true', - help="Either to make the tracebacks full, not compressed (as by default)"), - - ]) - - return p - -parser = get_opt_parser() -(opts, regexps) = parser.parse_args() +(opts, regexps) = getOptParser(__doc__).parse_args() # -# Logging +# Process initialization corresponding options (logging, default options, etc.) # -logSys = getLogger("fail2ban") - -# Numerical level of verbosity corresponding to a log "level" -verbosity = {'heavydebug': 4, - 'debug': 3, - 'info': 2, - 'notice': 2, - 'warning': 1, - 'error': 1, - 'critical': 0, - None: 1}[opts.log_level] - -if opts.log_level is not None: # pragma: no cover - # so we had explicit settings - logSys.setLevel(getattr(logging, opts.log_level.upper())) -else: # pragma: no cover - # suppress the logging but it would leave unittests' progress dots - # ticking, unless like with '-l critical' which would be silent - # unless error occurs - logSys.setLevel(getattr(logging, 'CRITICAL')) - -# Add the default logging handler -stdout = logging.StreamHandler(sys.stdout) - -fmt = ' %(message)s' - -if opts.log_traceback: - Formatter = FormatterWithTraceBack - fmt = (opts.full_traceback and ' %(tb)s' or ' %(tbc)s') + fmt -else: - Formatter = logging.Formatter - -# Custom log format for the verbose tests runs -if verbosity > 1: # pragma: no cover - stdout.setFormatter(Formatter(' %(asctime)-15s %(thread)s' + fmt)) -else: # pragma: no cover - # just prefix with the space - stdout.setFormatter(Formatter(fmt)) -logSys.addHandler(stdout) +opts = initProcess(opts) +verbosity = opts.verbosity # -# Let know the version +# Gather tests (and filter corresponding options) # -if not opts.log_level or opts.log_level != 'critical': # pragma: no cover - print("Fail2ban %s test suite. Python %s. Please wait..." \ - % (version, str(sys.version).replace('\n', ''))) +tests = gatherTests(regexps, opts) -tests = gatherTests(regexps, opts.no_network) # # Run the tests # diff --git a/config/action.d/abuseipdb.conf b/config/action.d/abuseipdb.conf new file mode 100644 index 00000000..15e41fbe --- /dev/null +++ b/config/action.d/abuseipdb.conf @@ -0,0 +1,105 @@ +# Fail2ban configuration file +# +# Action to report IP address to abuseipdb.com +# You must sign up to obtain an API key from abuseipdb.com. +# +# NOTE: These reports may include sensitive Info. +# If you want cleaner reports that ensure no user data see the helper script at the below website. +# +# IMPORTANT: +# +# Reporting an IP of abuse is a serious complaint. Make sure that it is +# serious. Fail2ban developers and network owners recommend you only use this +# action for: +# * The recidive where the IP has been banned multiple times +# * Where maxretry has been set quite high, beyond the normal user typing +# password incorrectly. +# * For filters that have a low likelihood of receiving human errors +# +# This action relies on a api_key being added to the above action conf, +# and the appropriate categories set. +# +# Example, for ssh bruteforce (in section [sshd] of `jail.local`): +# action = %(known/action)s +# %(action_abuseipdb)s[abuseipdb_apikey="my-api-key", abuseipdb_category="18,22"] +# +# See below for catagories. +# +# Original Ref: https://wiki.shaunc.com/wikka.php?wakka=ReportingToAbuseIPDBWithFail2Ban +# Added to fail2ban by Andrew James Collett (ajcollett) + +## abuseIPDB Catagories, `the abuseipdb_category` MUST be set in the jail.conf action call. +# Example, for ssh bruteforce: action = %(action_abuseipdb)s[abuseipdb_category="18,22"] +# ID Title Description +# 3 Fraud Orders +# 4 DDoS Attack +# 9 Open Proxy +# 10 Web Spam +# 11 Email Spam +# 14 Port Scan +# 18 Brute-Force +# 19 Bad Web Bot +# 20 Exploited Host +# 21 Web App Attack +# 22 SSH Secure Shell (SSH) abuse. Use this category in combination with more specific categories. +# 23 IoT Targeted +# See https://abuseipdb.com/categories for more descriptions + +[Definition] + +# Option: actionstart +# Notes.: command executed once at the start of Fail2Ban. +# Values: CMD +# +actionstart = + +# Option: actionstop +# Notes.: command executed once at the end of Fail2Ban +# Values: CMD +# +actionstop = + +# Option: actioncheck +# Notes.: command executed once before each actionban command +# Values: CMD +# +actioncheck = + +# Option: actionban +# Notes.: command executed when banning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# +# ** IMPORTANT! ** +# +# By default, this posts directly to AbuseIPDB's API, unfortunately +# this results in a lot of backslashes/escapes appearing in the +# reports. This also may include info like your hostname. +# If you have your own web server with PHP available, you can +# 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 +# +# +# --ciphers ecdhe_ecdsa_aes_256_sha is used to workaround a +# "NSS error -12286" from curl as it attempts to connect using +# SSLv3. See https://www.centos.org/forums/viewtopic.php?t=52732 +# Tags: See jail.conf(5) man page +# Values: CMD +# +actionban = curl --fail --ciphers ecdhe_ecdsa_aes_256_sha --data 'key=' --data-urlencode 'comment=' --data 'ip=' --data 'category=' "https://www.abuseipdb.com/report/json" + +# Option: actionunban +# Notes.: command executed when unbanning an IP. Take care that the +# command is executed with Fail2Ban user rights. +# Tags: See jail.conf(5) man page +# Values: CMD +# +actionunban = + +[Init] +# Option: abuseipdb_apikey +# Notes Your API key from abuseipdb.com +# Values: STRING Default: None +# Register for abuseipdb [https://www.abuseipdb.com], get api key and set below. +# You will need to set the catagory in the action call. +abuseipdb_apikey = diff --git a/config/action.d/badips.py b/config/action.d/badips.py index 4bc879a1..473fbf33 100644 --- a/config/action.d/badips.py +++ b/config/action.d/badips.py @@ -34,7 +34,7 @@ else: from fail2ban.server.actions import ActionBase -class BadIPsAction(ActionBase): +class BadIPsAction(ActionBase): # pragma: no cover - may be unavailable """Fail2Ban action which reports bans to badips.com, and also blacklist bad IPs listed on badips.com by using another action's ban method. @@ -105,6 +105,16 @@ class BadIPsAction(ActionBase): # Used later for threading.Timer for updating badips self._timer = None + @staticmethod + def isAvailable(timeout=1): + try: + response = urlopen(Request("/".join([BadIPsAction._badips]), + headers={'User-Agent': "Fail2Ban"}), timeout=timeout) + return True, '' + except Exception as e: # pragma: no cover + return False, e + + def getCategories(self, incParents=False): """Get badips.com categories. diff --git a/config/action.d/bsd-ipfw.conf b/config/action.d/bsd-ipfw.conf index 8b0a51aa..cbd6a15d 100644 --- a/config/action.d/bsd-ipfw.conf +++ b/config/action.d/bsd-ipfw.conf @@ -14,7 +14,7 @@ # Notes.: command executed once at the start of Fail2Ban. # Values: CMD # -actionstart = ipfw show | fgrep -q 'table()' || ( ipfw show | awk 'BEGIN { b = 1 } { if ($1 <= b) { b = $1 + 1 } else { e = b } } END { if (e) exit e
else exit b }'; num=$?; ipfw -q add $num from table\(
\) to me ; echo $num > "" ) +actionstart = ipfw show | fgrep -c -m 1 -s 'table(
)' > /dev/null 2>&1 || ( ipfw show | awk 'BEGIN { b = } { if ($1 < b) {} else if ($1 == b) { b = $1 + 1 } else { e = b } } END { if (e) exit e
else exit b }'; num=$?; ipfw -q add $num from table\(
\) to me ; echo $num > "" ) # Option: actionstop @@ -81,3 +81,11 @@ block = ip # Values: STRING # blocktype = unreach port + +# Option: lowest_rule_num +# Notes: When fail2ban starts with action and there is no rule for the given table yet +# then fail2ban will start looking for an empty slot starting with this rule number. +# Values: NUM +lowest_rule_num = 111 + + diff --git a/config/action.d/cloudflare.conf b/config/action.d/cloudflare.conf index aa87163c..89df5b9e 100644 --- a/config/action.d/cloudflare.conf +++ b/config/action.d/cloudflare.conf @@ -40,7 +40,12 @@ actioncheck = #