From: Jason Ish Date: Mon, 26 Feb 2018 17:33:27 +0000 (-0600) Subject: validate rule vars, disabling rules on error X-Git-Tag: 1.0.0rc1~20 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=841324caf423da89ebf12c86e4523c8cb115f919;p=thirdparty%2Fsuricata-update.git validate rule vars, disabling rules on error If the Suricata config is available, suricata-update will check that all rule vars are defined. If a rule uses a var that is not defined a warning message will be logged, and the rule will be disabled. --- diff --git a/suricata/update/engine.py b/suricata/update/engine.py index d8743e5..2cfa131 100644 --- a/suricata/update/engine.py +++ b/suricata/update/engine.py @@ -64,6 +64,9 @@ class Configuration: def keys(self): return self.conf.keys() + def has_key(self, key): + return key in self.conf + def is_true(self, key, truthy=[]): if not key in self.conf: logger.warning( diff --git a/suricata/update/main.py b/suricata/update/main.py index edaf82b..570636b 100644 --- a/suricata/update/main.py +++ b/suricata/update/main.py @@ -786,6 +786,48 @@ def ignore_file(ignore_files, filename): return True return False +def check_vars(suriconf, rulemap): + """Check that all vars referenced by a rule exist. If a var is not + found, disable the rule. + """ + if suriconf is None: + # Can't continue without a valid Suricata configuration + # object. + return + for rule in rulemap.itervalues(): + disable = False + for var in suricata.update.rule.parse_var_names( + rule["source_addr"]): + if not suriconf.has_key("vars.address-groups.%s" % (var)): + logger.warning( + "Rule has unknown source address var and will be disabled: %s: %s" % ( + var, rule.brief())) + disable = True + for var in suricata.update.rule.parse_var_names( + rule["dest_addr"]): + if not suriconf.has_key("vars.address-groups.%s" % (var)): + logger.warning( + "Rule has unknown dest address var and will be disabled: %s: %s" % ( + var, rule.brief())) + disable = True + for var in suricata.update.rule.parse_var_names( + rule["source_port"]): + if not suriconf.has_key("vars.port-groups.%s" % (var)): + logger.warning( + "Rule has unknown source port var and will be disabled: %s: %s" % ( + var, rule.brief())) + disable = True + for var in suricata.update.rule.parse_var_names( + rule["dest_port"]): + if not suriconf.has_key("vars.port-groups.%s" % (var)): + logger.warning( + "Rule has unknown dest port var and will be disabled: %s: %s" % ( + var, rule.brief())) + disable = True + + if disable: + rule.enabled = False + def test_suricata(suricata_path): if not suricata_path: logger.info("No suricata application binary found, skipping test.") @@ -1196,11 +1238,16 @@ def _main(): logger.info("Loading %s.", drop_conf_filename) drop_filters += load_drop_filters(drop_conf_filename) + # Load the Suricata configuration if we can. + suriconf = None if os.path.exists(config.get("suricata-conf")) and \ suricata_path and os.path.exists(suricata_path): logger.info("Loading %s",config.get("suricata-conf")) suriconf = suricata.update.engine.Configuration.load( config.get("suricata-conf"), suricata_path=suricata_path) + + # Disable rule that are for app-layers that are not enabled. + if suriconf: for key in suriconf.keys(): if key.startswith("app-layer.protocols") and \ key.endswith(".enabled"): @@ -1277,6 +1324,9 @@ def _main(): rulemap[rule.id] = new_rule modify_count += 1 + # Check rule vars, disabling rules that use unknown vars. + check_vars(suriconf, rulemap) + logger.info("Disabled %d rules." % (len(disabled_rules))) logger.info("Enabled %d rules." % (enable_count)) logger.info("Modified %d rules." % (modify_count)) diff --git a/suricata/update/rule.py b/suricata/update/rule.py index 1a1e57c..a400e3f 100644 --- a/suricata/update/rule.py +++ b/suricata/update/rule.py @@ -88,7 +88,11 @@ class Rule(dict): self["enabled"] = enabled self["action"] = action self["proto"] = None + self["source_addr"] = None + self["source_port"] = None self["direction"] = None + self["dest_addr"] = None + self["dest_port"] = None self["group"] = group self["gid"] = 1 self["sid"] = None @@ -448,3 +452,9 @@ def format_sidmsgmap_v2(rule): logger.error("Failed to format rule as sid-msg-v2.map: %s" % ( str(rule))) return None + +def parse_var_names(var): + """ Parse out the variable names from a string. """ + if var is None: + return [] + return re.findall("\$([\w_]+)", var)