diff --git a/security/q-feeds-connector/Makefile b/security/q-feeds-connector/Makefile index 70ee9f0eb..f690fad92 100644 --- a/security/q-feeds-connector/Makefile +++ b/security/q-feeds-connector/Makefile @@ -1,6 +1,5 @@ PLUGIN_NAME= q-feeds-connector -PLUGIN_VERSION= 1.4 -PLUGIN_REVISION= 1 +PLUGIN_VERSION= 1.5 PLUGIN_COMMENT= Connector for Q-Feeds threat intel PLUGIN_MAINTAINER= devel@qfeeds.com PLUGIN_TIER= 2 diff --git a/security/q-feeds-connector/pkg-descr b/security/q-feeds-connector/pkg-descr index 08c3c9cb7..699c60849 100644 --- a/security/q-feeds-connector/pkg-descr +++ b/security/q-feeds-connector/pkg-descr @@ -3,6 +3,14 @@ Connector for Q-Feeds threat intel Plugin Changelog ================ +1.5 + +* Feature: Add passlist option for unbound +* Feature: Add effective networks for unbound +* Feature: Add NXDOMAIN option for unbound +* Feature: Add dest address for unbound + + 1.4 * Feature: Added DNSCrypt-Proxy integration diff --git a/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/forms/settings.xml b/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/forms/settings.xml index 0469ed6ca..acb834253 100644 --- a/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/forms/settings.xml +++ b/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/forms/settings.xml @@ -15,4 +15,42 @@ checkbox Use domain feeds in Unbound DNS blocklist, requires blocklists to be enabled in order to have effect + + header + + + + + connect.unbound.allowlists + + select_multiple + + true + List of domains to allow. You can use regular expressions. This allow list only applies to blocklist matches on items in this policy. + + + connect.unbound.source_nets + + select_multiple + + true + Source networks to apply policy on. Examples are 192.168.1.0/24 or 192.168.1.1. Leave empty to apply on everything. All specified networks should use the same protocol family and have equal sizes to avoid priority issues. + + + connect.unbound.address + + text + true + + Destination ip address for entries in the blocklist (leave empty to use default: 0.0.0.0). + Not used when "Return NXDOMAIN" is checked. + + + + connect.unbound.nxdomain + + checkbox + true + Use the DNS response code NXDOMAIN instead of a destination address. + diff --git a/security/q-feeds-connector/src/opnsense/mvc/app/models/OPNsense/QFeeds/Connector.xml b/security/q-feeds-connector/src/opnsense/mvc/app/models/OPNsense/QFeeds/Connector.xml index fb158adcf..d748a54ef 100644 --- a/security/q-feeds-connector/src/opnsense/mvc/app/models/OPNsense/QFeeds/Connector.xml +++ b/security/q-feeds-connector/src/opnsense/mvc/app/models/OPNsense/QFeeds/Connector.xml @@ -7,5 +7,21 @@ + + + + Y + Y + Please specify a valid network segment or address (IPv4/IPv6). If a mask is provided, please omit the host bits. + N + N + Y + +
+ N + ipv4 +
+ +
diff --git a/security/q-feeds-connector/src/opnsense/mvc/app/views/OPNsense/QFeeds/index.volt b/security/q-feeds-connector/src/opnsense/mvc/app/views/OPNsense/QFeeds/index.volt index 21d3b54c7..c015c8094 100644 --- a/security/q-feeds-connector/src/opnsense/mvc/app/views/OPNsense/QFeeds/index.volt +++ b/security/q-feeds-connector/src/opnsense/mvc/app/views/OPNsense/QFeeds/index.volt @@ -99,6 +99,13 @@ POSSIBILITY OF SUCH DAMAGE. } }); + $("#connect\\.general\\.enable_unbound_bl").change(function(){ + if ($(this).is(':checked')) { + $(".unbound_options").closest('table').show(); + } else { + $(".unbound_options").closest('table').hide(); + } + }); let selected_tab = window.location.hash != "" ? window.location.hash : "#settings"; $('a[href="' +selected_tab + '"]').tab('show'); diff --git a/security/q-feeds-connector/src/opnsense/scripts/unbound/blocklists/qfeeds_bl.py b/security/q-feeds-connector/src/opnsense/scripts/unbound/blocklists/qfeeds_bl.py index d880d1e86..1675557ba 100755 --- a/security/q-feeds-connector/src/opnsense/scripts/unbound/blocklists/qfeeds_bl.py +++ b/security/q-feeds-connector/src/opnsense/scripts/unbound/blocklists/qfeeds_bl.py @@ -27,12 +27,19 @@ """ import os +import re +import syslog +import uuid from . import BaseBlocklistHandler -class DefaultBlocklistHandler(BaseBlocklistHandler): +class QFeedsBlocklistHandler(BaseBlocklistHandler): def __init__(self): super().__init__('/usr/local/etc/unbound/qfeeds-blocklists.conf') self.priority = 50 + self._compat_id = str(uuid.uuid4()) + + def _is_enabled(self): + return self.cnf and self.cnf.has_section('settings') and self.cnf.has_option('settings', 'filenames') def get_config(self): # do not use, unbound worker settings @@ -41,11 +48,10 @@ class DefaultBlocklistHandler(BaseBlocklistHandler): def get_blocklist(self): # Only return domains if integration is enabled (filenames are offered) qfeeds_filenames = [] - if self.cnf and self.cnf.has_section('settings'): - if self.cnf.has_option('settings', 'filenames'): - qfeeds_filenames = self.cnf.get('settings', 'filenames').split(',') - # touch a file to help qfeedsctl detect the current instance uses its list - open('/tmp/qfeeds-unbound-bl.stat', 'w').write('') + if self._is_enabled(): + qfeeds_filenames = self.cnf.get('settings', 'filenames').split(',') + # touch a file to help qfeedsctl detect the current instance uses its list + open('/tmp/qfeeds-unbound-bl.stat', 'w').write('') result = {} for filename in qfeeds_filenames: @@ -58,3 +64,35 @@ class DefaultBlocklistHandler(BaseBlocklistHandler): def get_passlist_patterns(self): return [] + + def get_policies(self): + if not self._is_enabled(): + return [] + + cfg = { + 'source_nets': [], + 'address': '', + 'rcode': '', + 'id': self._compat_id, + 'allowlists': [] + } + for k,v in self.cnf['settings'].items(): + if k in cfg and v.strip() != '': + if type(cfg[k]) is list: + cfg[k] = v.split(',') + else: + cfg[k] = v.strip() + + if cfg['allowlists']: + compiled_passlist = set() + for pattern in cfg['allowlists']: + try: + re.compile(pattern, re.IGNORECASE) + compiled_passlist.add(pattern) + except re.error: + syslog.syslog(syslog.LOG_ERR,'Q-Feeds : skip invalid whitelist exclude pattern "%s"' % pattern) + + cfg['passlist'] = '|'.join(compiled_passlist) + del cfg['allowlists'] + + return [cfg] \ No newline at end of file diff --git a/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/qfeeds-blocklists.conf b/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/qfeeds-blocklists.conf index 611317775..fb4bbd7e4 100644 --- a/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/qfeeds-blocklists.conf +++ b/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/qfeeds-blocklists.conf @@ -2,4 +2,11 @@ not helpers.empty('OPNsense.QFeedsConnector.general.enable_unbound_bl') %} [settings] filenames=/var/db/qfeeds-tables/malware_domains.txt +{% if not helpers.empty('OPNsense.QFeedsConnector.unbound') %} +allowlists={{OPNsense.QFeedsConnector.unbound.allowlists|default('')}} +source_nets={{OPNsense.QFeedsConnector.unbound.source_nets|default('')}} +address={{OPNsense.QFeedsConnector.unbound.address|default('0.0.0.0')}} +rcode={% if OPNsense.QFeedsConnector.unbound.nxdomain|default('0') == '1' %}NXDOMAIN{%else%}NOERROR{%endif +%} +cache_ttl={{OPNsense.QFeedsConnector.unbound.cache_ttl|default('72000')}} +{% endif %} {% endif %}