From 3fae8a7e432217c5ff650ef156a35663e4ccc78d Mon Sep 17 00:00:00 2001 From: sebres Date: Thu, 16 Feb 2017 14:53:57 +0100 Subject: [PATCH] amend to fc315be4ea88c3619f984542b21c95820f53d87b: parse and interpolate all options in section "Definition" (section "Init" no more needed), because of better performance with this solution; --- fail2ban/client/configreader.py | 33 +++++++++++++++++---------------- fail2ban/server/action.py | 9 +++++---- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/fail2ban/client/configreader.py b/fail2ban/client/configreader.py index b44a8c57..8098433e 100644 --- a/fail2ban/client/configreader.py +++ b/fail2ban/client/configreader.py @@ -221,13 +221,10 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes): # Or it is a dict: # {name: [type, default], ...} - def getOptions(self, sec, options, pOptions=None, - allOpts=None, shouldExist=False - ): + def getOptions(self, sec, options, pOptions=None, shouldExist=False): values = dict() if pOptions is None: pOptions = {} - # Get only specified options: for optname in options: if isinstance(options, (list,tuple)): @@ -265,15 +262,6 @@ class ConfigReaderUnshared(SafeConfigParserWithIncludes): logSys.warning("Wrong value for '" + optname + "' in '" + sec + "'. Using default one: '" + repr(optvalue) + "'") values[optname] = optvalue - - # Fill all option of the section (used for replacement): - if allOpts is not None and self.has_section(sec): - for optname in self.options(sec): - v = values.get(optname) - if v is None: - v = self.get(sec, optname, vars=pOptions) - allOpts[optname] = v - return values @@ -293,6 +281,8 @@ class DefinitionInitConfigReader(ConfigReader): self.setFile(file_) self.setJailName(jailName) self._initOpts = initOpts + self._pOpts = dict() + self._defCache = dict() def setFile(self, fileName): self._file = fileName @@ -323,9 +313,9 @@ class DefinitionInitConfigReader(ConfigReader): if not pOpts: pOpts = dict() pOpts = _merge_dicts(pOpts, self._initOpts) - self._allOpts = dict() self._opts = ConfigReader.getOptions( - self, "Definition", self._configOpts, pOpts, allOpts=self._allOpts) + self, "Definition", self._configOpts, pOpts) + self._pOpts = pOpts if self.has_section("Init"): for opt in self.options("Init"): v = self.get("Init", opt) @@ -337,6 +327,17 @@ class DefinitionInitConfigReader(ConfigReader): def _convert_to_boolean(self, value): return value.lower() in ("1", "yes", "true", "on") + def getCombOption(self, optname): + try: + return self._defCache[optname] + except KeyError: + try: + v = self.get("Definition", optname, vars=self._pOpts) + except (NoSectionError, NoOptionError, ValueError): + v = None + self._defCache[optname] = v + return v + def getCombined(self, ignore=()): combinedopts = self._opts ignore = set(ignore).copy() @@ -352,7 +353,7 @@ class DefinitionInitConfigReader(ConfigReader): ignore.add(n) # substiture options already specified direct: opts = CommandAction.substituteRecursiveTags(combinedopts, - ignore=ignore, addtags=self._allOpts) + ignore=ignore, addrepl=self.getCombOption) if not opts: raise ValueError('recursive tag definitions unable to be resolved') return opts diff --git a/fail2ban/server/action.py b/fail2ban/server/action.py index 69cd84a3..d14c9aab 100644 --- a/fail2ban/server/action.py +++ b/fail2ban/server/action.py @@ -366,7 +366,7 @@ class CommandAction(ActionBase): @classmethod def substituteRecursiveTags(cls, inptags, conditional='', - ignore=(), addtags={} + ignore=(), addrepl=None ): """Sort out tag definitions within other tags. Since v.0.9.2 supports embedded interpolation (see test cases for examples). @@ -419,11 +419,12 @@ class CommandAction(ActionBase): (tag, found_tag, refCounts, value)) repl = None if found_tag not in cls._escapedTags: - repl = tags.get(found_tag + '?' + conditional) + if conditional: + repl = tags.get(found_tag + '?' + conditional) if repl is None: repl = tags.get(found_tag) - if repl is None: - repl = addtags.get(found_tag) + if repl is None and addrepl is not None: + repl = addrepl(found_tag) if repl is None: # Escaped or missing tags - just continue on searching after end of match # Missing tags are ok - cInfo can contain aInfo elements like and valid shell