mirror of https://github.com/fail2ban/fail2ban
Merge pull request #4001 from sebres/f2b-regex--inverted-out
fail2ban-regex: new feature `-i` or `--invert` to output not-matched lines by `-o` or `--out`pull/3993/merge
commit
cfa3356e0f
|
@ -84,6 +84,8 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition
|
||||||
* `filter.d/proxmox.conf` - add support to Proxmox Web GUI (gh-2966)
|
* `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/openvpn.conf` - new filter and jail for openvpn recognizing failed TLS handshakes (gh-2702)
|
||||||
* `filter.d/vaultwarden.conf` - new filter and jail for Vaultwarden (gh-3979)
|
* `filter.d/vaultwarden.conf` - new filter and jail for Vaultwarden (gh-3979)
|
||||||
|
* `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
|
ver. 1.1.0 (2024/04/25) - object-found--norad-59479-cospar-2024-069a--altitude-36267km
|
||||||
-----------
|
-----------
|
||||||
|
|
|
@ -172,6 +172,8 @@ def get_opt_parser():
|
||||||
help="Disable check for all regex's"),
|
help="Disable check for all regex's"),
|
||||||
Option("-o", "--out", action="store", dest="out", default=None,
|
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, ...)"),
|
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',
|
Option("--print-no-missed", action='store_true',
|
||||||
help="Do not print any missed lines"),
|
help="Do not print any missed lines"),
|
||||||
Option("--print-no-ignored", action='store_true',
|
Option("--print-no-ignored", action='store_true',
|
||||||
|
@ -529,7 +531,7 @@ class Fail2banRegex(object):
|
||||||
except RegexException as e: # pragma: no cover
|
except RegexException as e: # pragma: no cover
|
||||||
output( 'ERROR: %s' % e )
|
output( 'ERROR: %s' % e )
|
||||||
return None, 0, None
|
return None, 0, None
|
||||||
if self._filter.getMaxLines() > 1:
|
if self._filter.getMaxLines() > 1 and not self._opts.out:
|
||||||
for bufLine in orgLineBuffer[int(fullBuffer):]:
|
for bufLine in orgLineBuffer[int(fullBuffer):]:
|
||||||
if bufLine not in self._filter._Filter__lineBuffer:
|
if bufLine not in self._filter._Filter__lineBuffer:
|
||||||
try:
|
try:
|
||||||
|
@ -619,8 +621,10 @@ class Fail2banRegex(object):
|
||||||
|
|
||||||
def process(self, test_lines):
|
def process(self, test_lines):
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
|
out = None
|
||||||
if self._opts.out: # get out function
|
if self._opts.out: # get out function
|
||||||
out = self._prepaireOutput()
|
out = self._prepaireOutput()
|
||||||
|
outinv = self._opts.invert
|
||||||
for line in test_lines:
|
for line in test_lines:
|
||||||
if isinstance(line, tuple):
|
if isinstance(line, tuple):
|
||||||
line_datetimestripped, ret, is_ignored = self.testRegex(line[0], line[1])
|
line_datetimestripped, ret, is_ignored = self.testRegex(line[0], line[1])
|
||||||
|
@ -632,8 +636,13 @@ class Fail2banRegex(object):
|
||||||
continue
|
continue
|
||||||
line_datetimestripped, ret, is_ignored = self.testRegex(line)
|
line_datetimestripped, ret, is_ignored = self.testRegex(line)
|
||||||
|
|
||||||
if self._opts.out: # (formatted) output:
|
if out: # (formatted) output:
|
||||||
if len(ret) > 0 and not is_ignored: out(ret)
|
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)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if is_ignored:
|
if is_ignored:
|
||||||
|
|
|
@ -432,8 +432,16 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
self.assertLogged('output: %s' % "['192.0.2.0'", "'ip4': '192.0.2.0'", "'user': 'kevin'", all=True)
|
self.assertLogged('output: %s' % "['192.0.2.0'", "'ip4': '192.0.2.0'", "'user': 'kevin'", all=True)
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
# log msg :
|
# log msg :
|
||||||
self.assertTrue(_test_exec('-o', 'msg', STR_00, RE_00_USER))
|
nmline = "Dec 31 12:00:00 [sshd] error: PAM: No failure for user from 192.0.2.123"
|
||||||
|
lines = STR_00+"\n"+nmline
|
||||||
|
self.assertTrue(_test_exec('-o', 'msg', lines, RE_00_USER))
|
||||||
self.assertLogged('output: %s' % STR_00)
|
self.assertLogged('output: %s' % STR_00)
|
||||||
|
self.assertNotLogged('output: %s' % nmline)
|
||||||
|
self.pruneLog()
|
||||||
|
# log msg (inverted) :
|
||||||
|
self.assertTrue(_test_exec('-o', 'msg', '-i', lines, RE_00_USER))
|
||||||
|
self.assertLogged('output: %s' % nmline)
|
||||||
|
self.assertNotLogged('output: %s' % STR_00)
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
# item of match (user):
|
# item of match (user):
|
||||||
self.assertTrue(_test_exec('-o', 'user', STR_00, RE_00_USER))
|
self.assertTrue(_test_exec('-o', 'user', STR_00, RE_00_USER))
|
||||||
|
@ -443,6 +451,17 @@ class Fail2banRegexTest(LogCaptureTestCase):
|
||||||
self.assertTrue(_test_exec('-o', '<ip>, <F-USER>, <family>', STR_00, RE_00_USER))
|
self.assertTrue(_test_exec('-o', '<ip>, <F-USER>, <family>', STR_00, RE_00_USER))
|
||||||
self.assertLogged('output: %s' % '192.0.2.0, kevin, inet4')
|
self.assertLogged('output: %s' % '192.0.2.0, kevin, inet4')
|
||||||
self.pruneLog()
|
self.pruneLog()
|
||||||
|
# log msg :
|
||||||
|
lines = nmline+"\n"+STR_00; # just reverse lines (to cover possible order dependencies)
|
||||||
|
self.assertTrue(_test_exec('-o', '<time> : <msg>', lines, RE_00_USER))
|
||||||
|
self.assertLogged('output: %s : %s' % (1104490799.0, STR_00))
|
||||||
|
self.assertNotLogged('output: %s' % nmline)
|
||||||
|
self.pruneLog()
|
||||||
|
# log msg (inverted) :
|
||||||
|
self.assertTrue(_test_exec('-o', '<time> : <msg>', '-i', lines, RE_00_USER))
|
||||||
|
self.assertLogged('output: %s : %s' % (1104490800.0, nmline))
|
||||||
|
self.assertNotLogged('output: %s' % STR_00)
|
||||||
|
self.pruneLog()
|
||||||
|
|
||||||
def testStalledIPByNoFailFrmtOutput(self):
|
def testStalledIPByNoFailFrmtOutput(self):
|
||||||
opts = (
|
opts = (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
|
||||||
.TH FAIL2BAN-REGEX "1" "April 2024" "fail2ban-regex 1.1.1.dev1" "User Commands"
|
.TH FAIL2BAN-REGEX "1" "June 2025" "fail2ban-regex 1.1.1.dev1" "User Commands"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fail2ban-regex \- test Fail2ban "failregex" option
|
fail2ban-regex \- test Fail2ban "failregex" option
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
@ -96,6 +96,10 @@ Disable check for all regex's
|
||||||
Set token to print failure information only (row, id,
|
Set token to print failure information only (row, id,
|
||||||
ip, msg, host, ip4, ip6, dns, matches, ...)
|
ip, msg, host, ip4, ip6, dns, matches, ...)
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-invert\fR
|
||||||
|
Invert the sense of matching, to output non\-matching
|
||||||
|
lines.
|
||||||
|
.TP
|
||||||
\fB\-\-print\-no\-missed\fR
|
\fB\-\-print\-no\-missed\fR
|
||||||
Do not print any missed lines
|
Do not print any missed lines
|
||||||
.TP
|
.TP
|
||||||
|
|
Loading…
Reference in New Issue