]> git.ipfire.org Git - dbl.git/commitdiff
exporters: Compose Suricata ruleset from a dict
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Jan 2026 10:45:51 +0000 (10:45 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 7 Jan 2026 10:45:51 +0000 (10:45 +0000)
This makes it slightly easier to swap out some fields where needed than
manipulating a really large string.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/dnsbl/exporters.py

index 04b18959e19d39f19696463ce98f6d1152f6f64d..e154c143005c00f5f5980a565b4ab7b0d02eef45 100644 (file)
@@ -423,84 +423,133 @@ class SuricataRulesExporter(TextExporter):
                # Write the header
                self.write_header(f)
 
-               args = {
-                       "name" : self.list,
-                       "list" : self.list.slug,
-               }
-
                # XXX Maybe we should look into having different priority for different lists.
                # For example, blocking some advertising has a lower priority than accessing
                # a malware/phishing domain.
 
-               rules = (
+               rules = {
                        # DNS
-                       (
-                               "alert dns any any -> any any ("
-                               " msg:\"IPFire DNSBL [%(name)s] Blocked DNS Query\";"
-                               " dns.query; "
-                               " domain; "
-                               " dataset:isset,%(list)s,type string,load datasets/%(list)s.txt;"
-                               " classtype:policy-violation;"
-                               " priority:3;"
-                               " sid:1;"
-                               " rev:1;"
-                               " reference:url,https://www.ipfire.org/dnsbl/%(list)s;"
-                               " metadata:dnsbl %(list)s.dnsbl.ipfire.org;"
-                               ")\n"
-                       ),
+                       "dns" : {
+                               "msg"       : "\"IPFire DNSBL [%s] Blocked DNS Query\"" % self.list,
+                               "dns.query" : None,
+                               "domain"    : None,
+                               "dataset"   : (
+                                       "isset",
+                                       self.list.slug,
+                                       "type string",
+                                       "load datasets/%s.txt" % self.list.slug,
+                               ),
+                               "classtype" : "policy-violation",
+                               "priority"  : "3",
+                               "sid"       : "1",
+                               "rev"       : "1",
+                               "reference" : (
+                                       "url",
+                                       "https://www.ipfire.org/dnsbl/%s" % self.list.slug,
+                               ),
+                               "metadata"  : {
+                                       "dnsbl" : "%s.dnsbl.ipfire.org" % self.list.slug,
+                               },
+                       },
 
                        # HTTP
-                       (
-                               "alert http any any -> any any ("
-                               " msg:\"IPFire DNSBL [%(name)s] Blocked HTTP Request\";"
-                               " http.host;"
-                               " domain;"
-                               " dataset:isset,%(list)s,type string,load datasets/%(list)s.txt;"
-                               " classtype:policy-violation;"
-                               " priority:3;"
-                               " sid:2;"
-                               " rev:1;"
-                               " reference:url,https://www.ipfire.org/dnsbl/%(list)s;"
-                               " metadata:dnsbl %(list)s.dnsbl.ipfire.org;"
-                               ")\n"
-                       ),
+                       "http" : {
+                               "msg"       : "\"IPFire DNSBL [%s] Blocked HTTP Request\"" % self.list,
+                               "http.host" : None,
+                               "domain"    : None,
+                               "dataset"   : (
+                                       "isset",
+                                       self.list.slug,
+                                       "type string",
+                                       "load datasets/%s.txt" % self.list.slug,
+                               ),
+                               "classtype" : "policy-violation",
+                               "priority"  : "3",
+                               "sid"       : "1",
+                               "rev"       : "1",
+                               "reference" : (
+                                       "url",
+                                       "https://www.ipfire.org/dnsbl/%s" % self.list.slug,
+                               ),
+                               "metadata"  : {
+                                       "dnsbl" : "%s.dnsbl.ipfire.org" % self.list.slug,
+                               },
+                       },
 
                        # TLS
-                       (
-                               "alert tls any any -> any any ("
-                               " msg:\"IPFire DNSBL [%(name)s] Blocked TLS SNI\";"
-                               " tls.sni;"
-                               " domain; "
-                               " dataset:isset,%(list)s,type string,load datasets/%(list)s.txt;"
-                               " classtype:policy-violation;"
-                               " priority:3;"
-                               " sid:3;"
-                               " rev:1;"
-                               " reference:url,https://www.ipfire.org/dnsbl/%(list)s;"
-                               " metadata:dnsbl %(list)s.dnsbl.ipfire.org;"
-                               ")\n"
-                       ),
+                       "tls" : {
+                               "msg"       : "\"IPFire DNSBL [%s] Blocked TLS Connection\"" % self.list,
+                               "tls.sni"   : None,
+                               "domain"    : None,
+                               "dataset"   : (
+                                       "isset",
+                                       self.list.slug,
+                                       "type string",
+                                       "load datasets/%s.txt" % self.list.slug,
+                               ),
+                               "classtype" : "policy-violation",
+                               "priority"  : "3",
+                               "sid"       : "1",
+                               "rev"       : "1",
+                               "reference" : (
+                                       "url",
+                                       "https://www.ipfire.org/dnsbl/%s" % self.list.slug,
+                               ),
+                               "metadata"  : {
+                                       "dnsbl" : "%s.dnsbl.ipfire.org" % self.list.slug,
+                               },
+                       },
 
                        # QUIC
-                       (
-                               "alert quic any any -> any any ("
-                               " msg:\"IPFire DNSBL [%(name)s] Blocked QUIC SNI\";"
-                               " quic.sni;"
-                               " domain; "
-                               " dataset:isset,%(list)s,type string,load datasets/%(list)s.txt;"
-                               " classtype:policy-violation;"
-                               " priority:3;"
-                               " sid:4;"
-                               " rev:1;"
-                               " reference:url,https://www.ipfire.org/dnsbl/%(list)s;"
-                               " metadata:dnsbl %(list)s.dnsbl.ipfire.org;"
-                               ")\n"
-                       ),
-               )
+                       "quic" : {
+                               "msg"       : "\"IPFire DNSBL [%s] Blocked QUIC Connection\"" % self.list,
+                               "quic.sni"  : None,
+                               "domain"    : None,
+                               "dataset"   : (
+                                       "isset",
+                                       self.list.slug,
+                                       "type string",
+                                       "load datasets/%s.txt" % self.list.slug,
+                               ),
+                               "classtype" : "policy-violation",
+                               "priority"  : "3",
+                               "sid"       : "1",
+                               "rev"       : "1",
+                               "reference" : (
+                                       "url",
+                                       "https://www.ipfire.org/dnsbl/%s" % self.list.slug,
+                               ),
+                               "metadata"  : {
+                                       "dnsbl" : "%s.dnsbl.ipfire.org" % self.list.slug,
+                               },
+                       },
+               }
 
                # Write all rules
-               for rule in rules:
-                       f.write(rule % args)
+               for engine, attrs in rules.items():
+                       rule = []
+
+                       for attr, value in attrs.items():
+                               # Attributes without a value go on their own
+                               if value is None:
+                                       rule.append(attr)
+
+                               # Join values in a tuple together
+                               elif type(value) == tuple:
+                                       rule.append("%s:%s" % (attr, ",".join(value)))
+
+                               # Join values in a dict together
+                               elif type(value) == dict:
+                                       value = ",".join((
+                                               "%s %s" % (key, value[key]) for key in value
+                                       ))
+                                       rule.append("%s:%s" % (attr, value))
+
+                               # Pass anything else on as it is
+                               else:
+                                       rule.append("%s:%s" % (attr, value))
+
+                       f.write("alert %s any any -> any any (%s)\n" % (engine, "; ".join(rule)))
 
 
 class SuricataDatasetExporter(TextExporter):