]> git.ipfire.org Git - thirdparty/suricata-update.git/commitdiff
matching: allow a rule revision to be matched as well
authorJason Ish <jason.ish@oisf.net>
Wed, 15 Jan 2025 16:22:38 +0000 (10:22 -0600)
committerJason Ish <jason.ish@oisf.net>
Tue, 8 Apr 2025 22:16:09 +0000 (16:16 -0600)
A rule ID can now be matched with a revision given the following
format of:

<gid>:<sid>:<rev>

The <gid> has to be specified for a revision match, as a specifier
with 2 components is read as "gid" and "rev".

Ticket: https://redmine.openinfosecfoundation.org/issues/7425

suricata/update/configs/disable.conf
suricata/update/configs/enable.conf
suricata/update/main.py
suricata/update/matchers.py
tests/test_matchers.py

index 59d0e18a195538f4fe86fc846dab1b6fa3c91938..035ef1ad3fe9be4adca14d21aeea841735a22dc6 100644 (file)
@@ -4,6 +4,10 @@
 # 1:2019401
 # 2019401
 
+# A rule revision can also be provided, but the GID must also be
+# specified.
+#1:3321408:2
+
 # Example of disabling a rule by regular expression.
 # - All regular expression matches are case insensitive.
 # re:heartbleed
index ad7b4e2ae4e76e4a8c2fc51f46edb8e54302291a..f83a1d1445c48de19f4729c68454fbf99eb96b80 100644 (file)
@@ -4,6 +4,10 @@
 # 1:2019401
 # 2019401
 
+# A rule revision can also be provided, but the GID must also be
+# specified.
+#1:3321408:2
+
 # Example of enabling a rule by regular expression.
 # - All regular expression matches are case insensitive.
 # re:heartbleed
index bbb28085f8d8fcb92f9e3bfd8eb7852bc8136dac..6b3d16dc3f141370877a06c9ba2aea00dd55e79a 100644 (file)
@@ -290,8 +290,15 @@ def parse_matchers(fileobj):
         else:
             # If matcher is an IdRuleMatcher
             if isinstance(matcher, matchers_mod.IdRuleMatcher):
-                for (gid, sid) in matcher.signatureIds:
-                    id_set_matcher.add(gid, sid)
+                for sig in matcher.signatureIds:
+                    if len(sig) == 2:
+                        # The "set" matcher only supports gid:sid.
+                        id_set_matcher.add(sig[0], sig[1])
+                    elif len(sig) == 3:
+                        # This must also have a rev, don't add to set,
+                        # but add as its own IdSetRuleMatcher.
+                        matchers.append(
+                            matchers_mod.IdRuleMatcher(sig[0], sig[1], sig[2]))
             else:
                 matchers.append(matcher)
 
index 4d61289e5b2cdcf53052744b4682eb7153a76994..9cbf1fa70c9950a2890d8fda81ec2a854c608206 100644 (file)
@@ -74,15 +74,21 @@ class IdRuleMatcher(object):
     """Matcher object to match an idstools rule object by its signature
     ID."""
 
-    def __init__(self, generatorId=None, signatureId=None):
+    def __init__(self, generatorId=None, signatureId=None, rev=None):
         self.signatureIds = []
-        if generatorId and signatureId:
+        if generatorId and signatureId and rev:
+            self.signatureIds.append((generatorId, signatureId, rev))
+        elif generatorId and signatureId:
             self.signatureIds.append((generatorId, signatureId))
 
     def match(self, rule):
-        for (generatorId, signatureId) in self.signatureIds:
-            if generatorId == rule.gid and signatureId == rule.sid:
-                return True
+        for sig in self.signatureIds:
+            if len(sig) == 3:
+                if sig[0] == rule.gid and sig[1] == rule.sid and sig[2] == rule.rev:
+                    return True
+            elif len(sig) == 2:
+                if sig[0] == rule.gid and sig[1] == rule.sid:
+                    return True
         return False
 
     @classmethod
@@ -92,7 +98,7 @@ class IdRuleMatcher(object):
         for entry in buf.split(","):
             entry = entry.strip()
 
-            parts = entry.split(":", 1)
+            parts = entry.split(":")
             if not parts:
                 return None
             if len(parts) == 1:
@@ -101,13 +107,21 @@ class IdRuleMatcher(object):
                     matcher.signatureIds.append((1, signatureId))
                 except:
                     return None
-            else:
+            elif len(parts) == 2:
                 try:
                     generatorId = int(parts[0])
                     signatureId = int(parts[1])
                     matcher.signatureIds.append((generatorId, signatureId))
                 except:
                     return None
+            elif len(parts) == 3:
+                try:
+                    generatorId = int(parts[0])
+                    signatureId = int(parts[1])
+                    rev = int(parts[2])
+                    matcher.signatureIds.append((generatorId, signatureId, rev))
+                except:
+                    return None
 
         return matcher
 
index ee360be8633a87b4e5d5337f0bb02e09c9db4cf7..adaec72428b32cede7f93bac2f8a58f7baa32f21 100644 (file)
@@ -108,6 +108,13 @@ class IdRuleMatcherTestCase(unittest.TestCase):
         matcher = matchers_mod.IdRuleMatcher.parse("1:a")
         self.assertIsNone(matcher)
 
+    def test_parse_gid_sid_rev(self):
+        matcher = matchers_mod.IdRuleMatcher.parse("1:234:5")
+        self.assertIsNotNone(matcher)
+        self.assertEqual(1, len(matcher.signatureIds))
+        self.assertEqual(matcher.signatureIds[0], (1, 234, 5))
+
+
 class MetadataAddTestCase(unittest.TestCase):
 
     def test_metadata_add(self):