From: Michael Tremer Date: Mon, 5 Jan 2026 15:05:46 +0000 (+0000) Subject: exporters: Implement exporting Suricata rules X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=419a3217924ab6a357a4c27b6d62b623575dfd02;p=dbl.git exporters: Implement exporting Suricata rules Signed-off-by: Michael Tremer --- diff --git a/src/dnsbl/exporters.py b/src/dnsbl/exporters.py index ef54366..9026802 100644 --- a/src/dnsbl/exporters.py +++ b/src/dnsbl/exporters.py @@ -400,3 +400,117 @@ class CombinedSquidGuardExporter(object): for list in self.lists: exporter = SquidGuardExporter(self.backend, list) exporter._write_list(tarball) + + +class SuricataExporter(TextExporter): + """ + Export domains as a set of rules for Suricata + """ + @abc.abstractproperty + def sid_offset(self): + """ + The value that is being added to any SIDs + """ + raise NotImplementedError + + @abc.abstractproperty + def rule(self): + """ + The rule string + """ + raise NotImplementedError + + # Default rule revision + rev = 1 + + def export(self, f): + # Write the header + self.write_header(f) + + # Write all domains + for domain in self.list.domains: + args = { + "list" : "%s" % self.list, + "domain" : domain.name, + "sid" : domain.id + self.sid_offset, + "rev" : self.rev, + } + + # Write the rule + f.write(self.rule % args) + + +class SuricataDNSExporter(SuricataExporter): + """ + Exports the lists as a Suricata ruleset that filters DNS queries. + """ + sid_offset = 1000000000 + + rule = ( + "alert dns any any -> any any (" + " msg:\"IPFire DNSBL [%(list)s] Blocked DNS Query for *.%(domain)s\";" + " dns.query; " + " content:\"%(domain)s\";" + " nocase;" + " endswith;" + " sid:%(sid)s;" + " rev:%(rev)s;" + ")\n" + ) + + +class SuricataHTTPExporter(SuricataExporter): + """ + Exports the lists as a Suricata ruleset that filters HTTP requests. + """ + sid_offset = 2000000000 + + rule = ( + "alert dns any any -> any any (" + " msg:\"IPFire DNSBL [%(list)s] Blocked HTTP Request to *.%(domain)s\";" + " http.host;" + " content:\"%(domain)s\";" + " nocase;" + " endswith;" + " sid:%(sid)s;" + " rev:%(rev)s;" + ")\n" + ) + + +class SuricataTLSExporter(SuricataExporter): + """ + Exports the lists as a Suricata ruleset that filters TLS connections. + """ + sid_offset = 3000000000 + + rule = ( + "alert dns any any -> any any (" + " msg:\"IPFire DNSBL [%(list)s] Blocked TLS SNI to *.%(domain)s\";" + " tls.sni;" + " content:\"%(domain)s\";" + " nocase;" + " endswith;" + " sid:%(sid)s;" + " rev:%(rev)s;" + ")\n" + ) + + +class SuricataQUICExporter(SuricataExporter): + """ + Exports the lists as a Suricata ruleset that filters QUIC connections. + """ + sid_offset = 4000000000 + + rule = ( + "alert dns any any -> any any (" + " msg:\"IPFire DNSBL [%(list)s] Blocked QUIC SNI to *.%(domain)s\";" + " quic.sni;" + " content:\"%(domain)s\";" + " nocase;" + " endswith;" + " sid:%(sid)s;" + " rev:%(rev)s;" + ")\n" + ) diff --git a/src/dnsbl/lists.py b/src/dnsbl/lists.py index 3f81c4c..76b80fa 100644 --- a/src/dnsbl/lists.py +++ b/src/dnsbl/lists.py @@ -471,12 +471,18 @@ class List(sqlmodel.SQLModel, database.BackendMixin, table=True): Exports the list """ formats = { - "abp" : exporters.AdBlockPlusExporter, - "domains" : exporters.DomainsExporter, - "dnsbl" : exporters.BlocklistExporter, - "hosts" : exporters.HostsExporter, - "rpz" : exporters.RPZExporter, - "squidguard" : exporters.SquidGuardExporter, + "abp" : exporters.AdBlockPlusExporter, + "domains" : exporters.DomainsExporter, + "dnsbl" : exporters.BlocklistExporter, + "hosts" : exporters.HostsExporter, + "rpz" : exporters.RPZExporter, + "squidguard" : exporters.SquidGuardExporter, + + # Suricata + "suricata-dns" : exporters.SuricataDNSExporter, + "suricata-http" : exporters.SuricataHTTPExporter, + "suricata-tls" : exporters.SuricataTLSExporter, + "suricata-quic" : exporters.SuricataQUICExporter, } # Fetch the exporter diff --git a/src/scripts/dnsbl.in b/src/scripts/dnsbl.in index a5f8e6d..5c83db2 100644 --- a/src/scripts/dnsbl.in +++ b/src/scripts/dnsbl.in @@ -111,7 +111,8 @@ class CLI(object): export.add_argument("output", type=argparse.FileType("wb"), help=_("The output file")) export.add_argument("--format", default="domains", - choices=("abp", "domains", "dnsbl", "hosts", "rpz", "squidguard",), + choices=("abp", "domains", "dnsbl", "hosts", "rpz", "squidguard", + "suricata-dns", "suricata-http", "suricata-tls", "suricata-quic"), help=_("Output Format")) export.set_defaults(func=self.__export) @@ -382,12 +383,18 @@ class CLI(object): Exports all lists """ formats = { - "abp" : "abp.txt", - "domains" : "domains.txt", - "dnsbl" : "dnsbl.zone", - "hosts" : "hosts.txt", - "rpz" : "rpz.zone", - "squidguard" : "squidguard.tar.gz", + "abp" : "abp.txt", + "domains" : "domains.txt", + "dnsbl" : "dnsbl.zone", + "hosts" : "hosts.txt", + "rpz" : "rpz.zone", + "squidguard" : "squidguard.tar.gz", + + # Suricata + "suricata-dns" : "suricata-dns.rules", + "suricata-http" : "suricata-http.rules", + "suricata-tls" : "suricata-tls.rules", + "suricata-quic" : "suricata-quic.rules", } # Ensure the output directory exists