diff --git a/pycommon/reporter_config/Config.py b/pycommon/reporter_config/Config.py index 104c3233..6cd0a60a 100644 --- a/pycommon/reporter_config/Config.py +++ b/pycommon/reporter_config/Config.py @@ -3,8 +3,7 @@ import copy import logging -from pynspect.compilers import IDEAFilterCompiler -from pynspect.gparser import PynspectFilterParser +from ransack import Parser as RansackParser from .actions.Drop import DropAction, DropMsg from .actions.Action import Action @@ -49,9 +48,7 @@ def __init__(self, path, dry = False, trap = None, wardenargs = None, module_nam overrided the name by -n and only the module_name is used. """ - self.compiler = IDEAFilterCompiler() - self.parser = PynspectFilterParser() - self.parser.build() + self.parser = RansackParser() self.trap = trap self.autoreload = autoreload self.path = path @@ -146,6 +143,7 @@ def loadConfig(self): raise SyntaxError("Yaml parsing error: " + str(e)) addrGroups = dict() + parser_context = dict() smtp_conns = dict() actions = dict() rules = list() @@ -157,6 +155,9 @@ def loadConfig(self): if "addressgroups" in conf: for i in conf["addressgroups"]: addrGroups[i["id"]] = AddressGroup(i) + parser_context[i["id"]] = addrGroups[i["id"]].content + # Pass address groups as a context for the parser + self.parser = RansackParser(parser_context) # Check if "smtp_connections" exists when there is some "email" action in "custom_actions" @@ -219,14 +220,12 @@ def loadConfig(self): actions["drop"] = DropAction() - # Parse all rules and match them with actions and address groups + # Parse all rules and match them with actions # There must be at least one rule (mandatory field) if "rules" in conf: if conf["rules"]: for i in conf["rules"]: - r = Rule(i, actions, addrGroups, - parser = self.parser, compiler = self.compiler, - module_name = self.module_name) + r = Rule(i, actions, parser = self.parser, module_name = self.module_name) rules.append(r) if not rules: raise SyntaxError("YAML file should contain at least one `rule` in `rules`.") diff --git a/pycommon/reporter_config/Rule.py b/pycommon/reporter_config/Rule.py index 3711725b..6824f83c 100644 --- a/pycommon/reporter_config/Rule.py +++ b/pycommon/reporter_config/Rule.py @@ -1,10 +1,7 @@ import re import logging import redis -#from pynspect.rules import * -from pynspect.filters import DataObjectFilter -from pynspect.compilers import IDEAFilterCompiler -from pynspect.gparser import PynspectFilterParser +from ransack import Parser, Filter from idea import lite logger = logging.getLogger(__name__) @@ -41,7 +38,7 @@ def clearCounters(prefix, module): logging.error("redis: Could not update statistics.") class Rule(): - def __init__(self, rule, actions, addrGroups, parser=None, compiler=None, module_name=""): + def __init__(self, rule, actions, parser=None, module_name=""): if not "condition" in rule: raise SyntaxError("Missing 'condition' in the rule: " + str(rule)) @@ -49,33 +46,25 @@ def __init__(self, rule, actions, addrGroups, parser=None, compiler=None, module if not "id" in rule: raise SyntaxError("Missing 'id' in the rule: " + str(rule)) - # Check is we got parser instance + # Check if we got parser instance if parser is None: - self.parser = PynspectFilterParser() - self.parser.build() + self.parser = Parser() else: self.parser = parser - # Check is we got compiler instance - if compiler is None: - self.compiler = IDEAFilterCompiler() - else: - self.compiler = compiler - # Instantiate filter - self.__filter = DataObjectFilter() + self.__filter = Filter() # Store rule condition in raw form self.__conditionRaw = rule["condition"] - if not self.__matchvar(rule["condition"], addrGroups): - self.__condition = self.__conditionRaw - self.module_name = module_name # Set inner rule ID self.id = rule["id"] + # Store the parsed condition + self.__condition = self.__conditionRaw if (self.__condition != None): self.parseRule() @@ -109,7 +98,6 @@ def parseRule(self): else: try: self.__condition = self.parser.parse(self.__condition) - self.__condition = self.compiler.compile(self.__condition) except Exception as e: raise SyntaxError("Error while parsing condition: {0}\nOriginal exception: {1}".format(self.__condition, e)) @@ -136,7 +124,7 @@ def filter(self, record): res = False else: # Match the record with non-empty rule's condition - res = self.__filter.filter(self.__condition, record) + res = self.__filter.eval(self.__condition, record) logger.debug("RESULT: %s", res) @@ -185,27 +173,3 @@ def __str__(self): def rule(self): return str(self.__condition) - def __matchvar(self, rule, addrGroups): - """ - Since pyncspect doesn't support variables yet we had to provide - a solution where every address group's name is matched against - the rule's condition and eventually replaced with address group's values - """ - - matched = False - - """ - Tautology - empty rule should always match - Don't try to match or replace any address group - """ - if rule is None or isinstance(rule, bool): - return False - - for key in addrGroups: - if key in rule: - rule = re.sub(r"\b{0}\b".format(re.escape(key)), addrGroups[key].iplist(), rule) - matched = True - self.__condition = rule - - return matched - diff --git a/pycommon/test/rc_config/iprange_stdout.yaml b/pycommon/test/rc_config/iprange_stdout.yaml index db06b0a6..a0dc32bd 100644 --- a/pycommon/test/rc_config/iprange_stdout.yaml +++ b/pycommon/test/rc_config/iprange_stdout.yaml @@ -6,21 +6,21 @@ custom_actions: path: /dev/stdout rules: - id: 1 - condition: Source.IP4 in [ "192.168.0.0/24" ] + condition: Source.IP4 in 192.168.0.0/24 actions: - stdout - id: 1 - condition: Source.IP4 in [ "192.168.1.0/24" ] + condition: Source.IP4 in 192.168.1.0/24 actions: - stdout - id: 1 - condition: Source.IP4 in [ "10.0.0.0/8" ] + condition: Source.IP4 in 10.0.0.0/8 actions: - stdout - id: 1 - condition: Source.IP4 in [ "10.1.0.0/16" ] + condition: Source.IP4 in 10.1.0.0/16 actions: - stdout