From d12b3127c76e2f58b83ef4ebbbe4e3d6261458c6 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Thu, 21 Jun 2018 10:18:18 -0600 Subject: [PATCH] sid matchers: allow command separated sids Inspired by patch from Russel Fulton. --- suricata/update/main.py | 49 ++++++++++++++++++++++++++--------------- tests/test_matchers.py | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/suricata/update/main.py b/suricata/update/main.py index e10824b..e4c64ba 100644 --- a/suricata/update/main.py +++ b/suricata/update/main.py @@ -112,29 +112,42 @@ class IdRuleMatcher(object): """Matcher object to match an idstools rule object by its signature ID.""" - def __init__(self, generatorId, signatureId): - self.generatorId = generatorId - self.signatureId = signatureId + def __init__(self, generatorId=None, signatureId=None): + self.signatureIds = [] + if generatorId and signatureId: + self.signatureIds.append((generatorId, signatureId)) def match(self, rule): - return self.generatorId == rule.gid and self.signatureId == rule.sid + for (generatorId, signatureId) in self.signatureIds: + if generatorId == rule.gid and signatureId == rule.sid: + return True + return False @classmethod def parse(cls, buf): - logger.debug("Parsing ID matcher: %s" % (buf)) - try: - signatureId = int(buf) - return cls(1, signatureId) - except: - pass - try: - generatorString, signatureString = buf.split(":") - generatorId = int(generatorString) - signatureId = int(signatureString) - return cls(generatorId, signatureId) - except: - pass - return None + matcher = cls() + + for entry in buf.split(","): + entry = entry.strip() + + parts = entry.split(":", 1) + if not parts: + return None + if len(parts) == 1: + try: + signatureId = int(parts[0]) + matcher.signatureIds.append((1, signatureId)) + except: + return None + else: + try: + generatorId = int(parts[0]) + signatureId = int(parts[1]) + matcher.signatureIds.append((generatorId, signatureId)) + except: + return None + + return matcher class FilenameMatcher(object): """Matcher object to match a rule by its filename. This is similar to diff --git a/tests/test_matchers.py b/tests/test_matchers.py index e567a3f..c0df407 100644 --- a/tests/test_matchers.py +++ b/tests/test_matchers.py @@ -66,3 +66,43 @@ re:.# This is a comment* matchers[1].__class__, suricata.update.main.ReRuleMatcher) self.assertEquals( matchers[2].__class__, suricata.update.main.IdRuleMatcher) + +class IdRuleMatcherTestCase(unittest.TestCase): + + def test_parse_single_sid(self): + matcher = main.IdRuleMatcher.parse("123") + self.assertIsNotNone(matcher) + self.assertEquals(1, len(matcher.signatureIds)) + + def test_parse_single_gidsid(self): + matcher = main.IdRuleMatcher.parse("1:123") + self.assertIsNotNone(matcher) + self.assertEquals(1, len(matcher.signatureIds)) + + def test_parse_multi_sid(self): + matcher = main.IdRuleMatcher.parse("1,2,3") + self.assertIsNotNone(matcher) + self.assertEquals(3, len(matcher.signatureIds)) + + def test_parse_multi_gidsid(self): + matcher = main.IdRuleMatcher.parse("1:1000,2:2000, 3:3000, 4:4000") + self.assertIsNotNone(matcher) + self.assertEquals(4, len(matcher.signatureIds)) + + def test_parse_multi_mixed(self): + matcher = main.IdRuleMatcher.parse("1:1000, 2000, 3:3000, 4000") + self.assertIsNotNone(matcher) + self.assertEquals(4, len(matcher.signatureIds)) + + def test_parse_invalid(self): + matcher = main.IdRuleMatcher.parse("a") + self.assertIsNone(matcher) + + matcher = main.IdRuleMatcher.parse("1, a") + self.assertIsNone(matcher) + + matcher = main.IdRuleMatcher.parse("1a") + self.assertIsNone(matcher) + + matcher = main.IdRuleMatcher.parse("1:a") + self.assertIsNone(matcher) -- 2.47.3