]> git.ipfire.org Git - thirdparty/suricata-update.git/commitdiff
validate rule vars, disabling rules on error
authorJason Ish <ish@unx.ca>
Mon, 26 Feb 2018 17:33:27 +0000 (11:33 -0600)
committerJason Ish <ish@unx.ca>
Mon, 26 Feb 2018 17:33:27 +0000 (11:33 -0600)
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.

suricata/update/engine.py
suricata/update/main.py
suricata/update/rule.py

index d8743e56ca0849ef579ab3400947bf30b5f81759..2cfa13187d512b38c7d9dfba3d4e4f7133395d16 100644 (file)
@@ -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(
index edaf82bfc592bec83764cbe6497736037a0d3b63..570636b7067ff26de357f52862173d519dac36cd 100644 (file)
@@ -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))
index 1a1e57c75df73f1239ff8219268f738c3aa8be03..a400e3f03a199e8dafd32e3da047be3fbe738f79 100644 (file)
@@ -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)