diff --git a/suricata/update/configs/disable.conf b/suricata/update/configs/disable.conf index 59d0e18..035ef1a 100644 --- a/suricata/update/configs/disable.conf +++ b/suricata/update/configs/disable.conf @@ -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 diff --git a/suricata/update/configs/enable.conf b/suricata/update/configs/enable.conf index ad7b4e2..f83a1d1 100644 --- a/suricata/update/configs/enable.conf +++ b/suricata/update/configs/enable.conf @@ -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 diff --git a/suricata/update/main.py b/suricata/update/main.py index bbb2808..6b3d16d 100644 --- a/suricata/update/main.py +++ b/suricata/update/main.py @@ -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) diff --git a/suricata/update/matchers.py b/suricata/update/matchers.py index 4d61289..9cbf1fa 100644 --- a/suricata/update/matchers.py +++ b/suricata/update/matchers.py @@ -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 @@ def parse(cls, buf): 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 @@ def parse(cls, buf): 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 diff --git a/tests/test_matchers.py b/tests/test_matchers.py index ee360be..adaec72 100644 --- a/tests/test_matchers.py +++ b/tests/test_matchers.py @@ -108,6 +108,13 @@ def test_parse_invalid(self): 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):