mirror of https://github.com/fail2ban/fail2ban
do type-convert only in getCombined (otherwise int/bool conversion prevents substitution or section-related interpolation of tags)
parent
1707560df8
commit
7b05c1ce7a
|
@ -38,17 +38,17 @@ class ActionReader(DefinitionInitConfigReader):
|
||||||
|
|
||||||
_configOpts = {
|
_configOpts = {
|
||||||
"actionstart": ["string", None],
|
"actionstart": ["string", None],
|
||||||
"actionstart_on_demand": ["string", None],
|
"actionstart_on_demand": ["bool", None],
|
||||||
"actionstop": ["string", None],
|
"actionstop": ["string", None],
|
||||||
"actionflush": ["string", None],
|
"actionflush": ["string", None],
|
||||||
"actionreload": ["string", None],
|
"actionreload": ["string", None],
|
||||||
"actioncheck": ["string", None],
|
"actioncheck": ["string", None],
|
||||||
"actionrepair": ["string", None],
|
"actionrepair": ["string", None],
|
||||||
"actionrepair_on_unban": ["string", None],
|
"actionrepair_on_unban": ["bool", None],
|
||||||
"actionban": ["string", None],
|
"actionban": ["string", None],
|
||||||
"actionreban": ["string", None],
|
"actionreban": ["string", None],
|
||||||
"actionunban": ["string", None],
|
"actionunban": ["string", None],
|
||||||
"norestored": ["string", None],
|
"norestored": ["bool", None],
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, file_, jailName, initOpts, **kwargs):
|
def __init__(self, file_, jailName, initOpts, **kwargs):
|
||||||
|
@ -83,11 +83,6 @@ class ActionReader(DefinitionInitConfigReader):
|
||||||
def convert(self):
|
def convert(self):
|
||||||
opts = self.getCombined(
|
opts = self.getCombined(
|
||||||
ignore=CommandAction._escapedTags | set(('timeout', 'bantime')))
|
ignore=CommandAction._escapedTags | set(('timeout', 'bantime')))
|
||||||
# type-convert only after combined (otherwise boolean converting prevents substitution):
|
|
||||||
for o in ('norestored', 'actionstart_on_demand', 'actionrepair_on_unban'):
|
|
||||||
if opts.get(o):
|
|
||||||
opts[o] = self._convert_to_boolean(opts[o])
|
|
||||||
|
|
||||||
# stream-convert:
|
# stream-convert:
|
||||||
head = ["set", self._jailName]
|
head = ["set", self._jailName]
|
||||||
stream = list()
|
stream = list()
|
||||||
|
|
|
@ -228,7 +228,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
||||||
# Or it is a dict:
|
# Or it is a dict:
|
||||||
# {name: [type, default], ...}
|
# {name: [type, default], ...}
|
||||||
|
|
||||||
def getOptions(self, sec, options, pOptions=None, shouldExist=False):
|
def getOptions(self, sec, options, pOptions=None, shouldExist=False, convert=True):
|
||||||
values = dict()
|
values = dict()
|
||||||
if pOptions is None:
|
if pOptions is None:
|
||||||
pOptions = {}
|
pOptions = {}
|
||||||
|
@ -244,12 +244,15 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
||||||
if optname in pOptions:
|
if optname in pOptions:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
if opttype == "bool":
|
if convert:
|
||||||
v = self.getboolean(sec, optname)
|
if opttype == "bool":
|
||||||
if v is None: continue
|
v = self.getboolean(sec, optname)
|
||||||
elif opttype == "int":
|
if v is None: continue
|
||||||
v = self.getint(sec, optname)
|
elif opttype == "int":
|
||||||
if v is None: continue
|
v = self.getint(sec, optname)
|
||||||
|
if v is None: continue
|
||||||
|
else:
|
||||||
|
v = self.get(sec, optname, vars=pOptions)
|
||||||
else:
|
else:
|
||||||
v = self.get(sec, optname, vars=pOptions)
|
v = self.get(sec, optname, vars=pOptions)
|
||||||
values[optname] = v
|
values[optname] = v
|
||||||
|
@ -267,7 +270,7 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes):
|
||||||
values[optname] = optvalue
|
values[optname] = optvalue
|
||||||
# elif logSys.getEffectiveLevel() <= logLevel:
|
# elif logSys.getEffectiveLevel() <= logLevel:
|
||||||
# logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", optname, sec)
|
# logSys.log(logLevel, "Non essential option '%s' not defined in '%s'.", optname, sec)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logSys.warning("Wrong value for '" + optname + "' in '" + sec +
|
logSys.warning("Wrong value for '" + optname + "' in '" + sec +
|
||||||
"'. Using default one: '" + repr(optvalue) + "'")
|
"'. Using default one: '" + repr(optvalue) + "'")
|
||||||
values[optname] = optvalue
|
values[optname] = optvalue
|
||||||
|
@ -324,8 +327,9 @@ class DefinitionInitConfigReader(ConfigReader):
|
||||||
pOpts = dict()
|
pOpts = dict()
|
||||||
if self._initOpts:
|
if self._initOpts:
|
||||||
pOpts = _merge_dicts(pOpts, self._initOpts)
|
pOpts = _merge_dicts(pOpts, self._initOpts)
|
||||||
|
# type-convert only in combined (otherwise int/bool converting prevents substitution):
|
||||||
self._opts = ConfigReader.getOptions(
|
self._opts = ConfigReader.getOptions(
|
||||||
self, "Definition", self._configOpts, pOpts)
|
self, "Definition", self._configOpts, pOpts, convert=False)
|
||||||
self._pOpts = pOpts
|
self._pOpts = pOpts
|
||||||
if self.has_section("Init"):
|
if self.has_section("Init"):
|
||||||
# get only own options (without options from default):
|
# get only own options (without options from default):
|
||||||
|
@ -346,10 +350,34 @@ class DefinitionInitConfigReader(ConfigReader):
|
||||||
if opt == '__name__' or opt in self._opts: continue
|
if opt == '__name__' or opt in self._opts: continue
|
||||||
self._opts[opt] = self.get("Definition", opt)
|
self._opts[opt] = self.get("Definition", opt)
|
||||||
|
|
||||||
|
def convertOptions(self, opts, pOptions={}):
|
||||||
|
options = self._configOpts
|
||||||
|
for optname in options:
|
||||||
|
if isinstance(options, (list,tuple)):
|
||||||
|
if len(optname) > 2:
|
||||||
|
opttype, optname, optvalue = optname
|
||||||
|
else:
|
||||||
|
(opttype, optname), optvalue = optname, None
|
||||||
|
else:
|
||||||
|
opttype, optvalue = options[optname]
|
||||||
|
if optname in pOptions:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if opttype == "bool":
|
||||||
|
v = opts.get(optname)
|
||||||
|
if v is None or isinstance(v, bool): continue
|
||||||
|
v = _as_bool(v)
|
||||||
|
opts[optname] = v
|
||||||
|
elif opttype == "int":
|
||||||
|
v = opts.get(optname)
|
||||||
|
if v is None or isinstance(v, (int, long)): continue
|
||||||
|
v = int(v)
|
||||||
|
opts[optname] = v
|
||||||
|
except ValueError:
|
||||||
|
logSys.warning("Wrong %s value %r for %r. Using default one: %r",
|
||||||
|
opttype, v, optname, optvalue)
|
||||||
|
opts[optname] = optvalue
|
||||||
|
|
||||||
def _convert_to_boolean(self, value):
|
|
||||||
return _as_bool(value)
|
|
||||||
|
|
||||||
def getCombOption(self, optname):
|
def getCombOption(self, optname):
|
||||||
"""Get combined definition option (as string) using pre-set and init
|
"""Get combined definition option (as string) using pre-set and init
|
||||||
options as preselection (values with higher precedence as specified in section).
|
options as preselection (values with higher precedence as specified in section).
|
||||||
|
@ -384,6 +412,8 @@ class DefinitionInitConfigReader(ConfigReader):
|
||||||
ignore=ignore, addrepl=self.getCombOption)
|
ignore=ignore, addrepl=self.getCombOption)
|
||||||
if not opts:
|
if not opts:
|
||||||
raise ValueError('recursive tag definitions unable to be resolved')
|
raise ValueError('recursive tag definitions unable to be resolved')
|
||||||
|
# convert options after all interpolations:
|
||||||
|
self.convertOptions(opts)
|
||||||
return opts
|
return opts
|
||||||
|
|
||||||
def convert(self):
|
def convert(self):
|
||||||
|
|
|
@ -490,7 +490,9 @@ class FilterReaderTest(unittest.TestCase):
|
||||||
self.__share_cfg = {}
|
self.__share_cfg = {}
|
||||||
|
|
||||||
def testConvert(self):
|
def testConvert(self):
|
||||||
output = [['multi-set', 'testcase01', 'addfailregex', [
|
output = [
|
||||||
|
['set', 'testcase01', 'maxlines', 1],
|
||||||
|
['multi-set', 'testcase01', 'addfailregex', [
|
||||||
"^\\s*(?:\\S+ )?(?:kernel: \\[\\d+\\.\\d+\\] )?(?:@vserver_\\S+ )"
|
"^\\s*(?:\\S+ )?(?:kernel: \\[\\d+\\.\\d+\\] )?(?:@vserver_\\S+ )"
|
||||||
"?(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|"
|
"?(?:(?:\\[\\d+\\])?:\\s+[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?|"
|
||||||
"[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:)?\\s*(?:"
|
"[\\[\\(]?sshd(?:\\(\\S+\\))?[\\]\\)]?:?(?:\\[\\d+\\])?:)?\\s*(?:"
|
||||||
|
@ -512,7 +514,6 @@ class FilterReaderTest(unittest.TestCase):
|
||||||
['set', 'testcase01', 'addjournalmatch',
|
['set', 'testcase01', 'addjournalmatch',
|
||||||
"FIELD= with spaces ", "+", "AFIELD= with + char and spaces"],
|
"FIELD= with spaces ", "+", "AFIELD= with + char and spaces"],
|
||||||
['set', 'testcase01', 'datepattern', "%Y %m %d %H:%M:%S"],
|
['set', 'testcase01', 'datepattern', "%Y %m %d %H:%M:%S"],
|
||||||
['set', 'testcase01', 'maxlines', 1], # Last for overide test
|
|
||||||
]
|
]
|
||||||
filterReader = FilterReader("testcase01", "testcase01", {})
|
filterReader = FilterReader("testcase01", "testcase01", {})
|
||||||
filterReader.setBaseDir(TEST_FILES_DIR)
|
filterReader.setBaseDir(TEST_FILES_DIR)
|
||||||
|
@ -529,7 +530,7 @@ class FilterReaderTest(unittest.TestCase):
|
||||||
filterReader.read()
|
filterReader.read()
|
||||||
#filterReader.getOptions(["failregex", "ignoreregex"])
|
#filterReader.getOptions(["failregex", "ignoreregex"])
|
||||||
filterReader.getOptions(None)
|
filterReader.getOptions(None)
|
||||||
output[-1][-1] = "5"
|
output[0][-1] = 5; # maxlines = 5
|
||||||
self.assertSortedEqual(filterReader.convert(), output)
|
self.assertSortedEqual(filterReader.convert(), output)
|
||||||
|
|
||||||
def testFilterReaderSubstitionDefault(self):
|
def testFilterReaderSubstitionDefault(self):
|
||||||
|
|
Loading…
Reference in New Issue