diff --git a/security/q-feeds-connector/Makefile b/security/q-feeds-connector/Makefile
index dffd163a2..295ca12f0 100644
--- a/security/q-feeds-connector/Makefile
+++ b/security/q-feeds-connector/Makefile
@@ -1,5 +1,5 @@
PLUGIN_NAME= q-feeds-connector
-PLUGIN_VERSION= 1.0
+PLUGIN_VERSION= 1.1
PLUGIN_COMMENT= Connector for Q-Feeds threat intel
PLUGIN_MAINTAINER= devel@qfeeds.com
diff --git a/security/q-feeds-connector/pkg-descr b/security/q-feeds-connector/pkg-descr
index c6c57300e..345782502 100644
--- a/security/q-feeds-connector/pkg-descr
+++ b/security/q-feeds-connector/pkg-descr
@@ -3,6 +3,13 @@ Connector for Q-Feeds threat intel
Plugin Changelog
================
+1.1
+
+* remove QfeedsStatus as the new table defaults are different
+* add unbound blocklist support
+* Events: fix empty interface names
+
+
1.0
* Intial release version
diff --git a/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/Api/SettingsController.php b/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/Api/SettingsController.php
index ed8a3a27b..b65b7b1a6 100644
--- a/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/Api/SettingsController.php
+++ b/security/q-feeds-connector/src/opnsense/mvc/app/controllers/OPNsense/QFeeds/Api/SettingsController.php
@@ -73,7 +73,7 @@ class SettingsController extends ApiMutableModelControllerBase
$ifnames = [];
foreach (Config::getInstance()->object()->interfaces->children() as $key => $node) {
if (!empty((string)$node->if)) {
- $ifnames[(string)$node->if] = (string)($node->descr ?? strtoupper($key));
+ $ifnames[(string)$node->if] = !empty((string)($node->descr)) ? (string)($node->descr) : strtoupper($key);
}
}
$data = json_decode((new Backend())->configdRun('qfeeds logs') ?? '[]', true);
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 742ceb3cc..0469ed6ca 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
@@ -9,4 +9,10 @@
textclick here]]>
+
+ connect.general.enable_unbound_bl
+
+ checkbox
+ Use domain feeds in Unbound DNS blocklist, requires blocklists to be enabled in order to have effect
+
diff --git a/security/q-feeds-connector/src/opnsense/mvc/app/library/OPNsense/System/Status/QfeedsStatus.php b/security/q-feeds-connector/src/opnsense/mvc/app/library/OPNsense/System/Status/QfeedsStatus.php
deleted file mode 100644
index 5477729d6..000000000
--- a/security/q-feeds-connector/src/opnsense/mvc/app/library/OPNsense/System/Status/QfeedsStatus.php
+++ /dev/null
@@ -1,61 +0,0 @@
-internalPriority = 2;
- $this->internalPersistent = true;
- $this->internalIsBanner = true;
- $this->internalTitle = gettext('QFeeds');
- $this->internalScope = [
- '/ui/q_feeds/'
- ];
- }
-
- public function collectStatus()
- {
- $cnf = Config::getInstance()->object();
- if (!empty($cnf->system->maximumtableentries) && $cnf->system->maximumtableentries >= 2000000) {
- return;
- }
- $this->internalStatus = SystemStatusCode::ERROR;
- $this->internalMessage = gettext(
- 'QFeeds requires additional memory to be reserved for aliases. ' .
- 'Please increase `Firewall Maximum Table Entries` in `Firewall: Settings: Advanced` to at least' .
- ' 2 million items.'
- );
- }
-}
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 9aeebb308..fb158adcf 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
@@ -5,6 +5,7 @@
+
diff --git a/security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/__init__.py b/security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/__init__.py
index bf4c528aa..f0f029c1d 100644
--- a/security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/__init__.py
+++ b/security/q-feeds-connector/src/opnsense/scripts/qfeeds/lib/__init__.py
@@ -45,6 +45,7 @@ class QFeedsActions:
'fetch',
'show_index',
'firewall_load',
+ 'unbound_load',
'update',
'stats',
'logs'
@@ -113,6 +114,13 @@ class QFeedsActions:
)
yield 'load feed %s [%s]' % (feed['feed_type'], sp.stderr.strip().replace("\n", " "))
+ def unbound_load(self):
+ bl_conf = '/usr/local/etc/unbound/qfeeds-blocklists.conf'
+ if os.path.exists(bl_conf) and os.path.getsize(bl_conf) > 20:
+ # when qfeeds-blocklists.conf is ~empty, skip updates
+ subprocess.run(['/usr/local/sbin/configctl', 'unbound', 'dnsbl'])
+ yield 'update unbound blocklist'
+
def update(self):
update_sleep = 99999
try:
@@ -128,7 +136,7 @@ class QFeedsActions:
if do_update:
if 0 < update_sleep <= 300:
time.sleep(update_sleep)
- for action in ['fetch_index', 'fetch', 'firewall_load']:
+ for action in ['fetch_index', 'fetch', 'firewall_load', 'unbound_load']:
yield from getattr(self, action)()
def stats(self):
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
new file mode 100755
index 000000000..ff3413a85
--- /dev/null
+++ b/security/q-feeds-connector/src/opnsense/scripts/unbound/blocklists/qfeeds_bl.py
@@ -0,0 +1,55 @@
+#!/usr/local/bin/python3
+
+"""
+ Copyright (c) 2025 Deciso B.V.
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os
+from . import BaseBlocklistHandler
+
+class DefaultBlocklistHandler(BaseBlocklistHandler):
+ def __init__(self):
+ super().__init__('/usr/local/etc/unbound/qfeeds-blocklists.conf')
+ self.priority = 100
+
+ def get_config(self):
+ cfg = {'qfeeds_filenames': []}
+ if self.cnf and self.cnf.has_section('settings'):
+ if self.cnf.has_option('settings', 'filenames'):
+ cfg['qfeeds_filenames'] = self.cnf.get('settings', 'filenames').split(',')
+ return cfg
+
+ def get_blocklist(self):
+ result = {}
+ for filename in self.get_config()['qfeeds_filenames']:
+ bl_shortcode = "qf_%s" % os.path.splitext(os.path.basename(filename).strip())[0]
+ if os.path.exists(filename):
+ with open(filename, 'r') as f_in:
+ for line in f_in:
+ result[line.strip()] = {'bl': bl_shortcode, 'wildcard': False}
+ return result
+
+ def get_passlist_patterns(self):
+ return []
diff --git a/security/q-feeds-connector/src/opnsense/service/conf/actions.d/actions_qfeeds.conf b/security/q-feeds-connector/src/opnsense/service/conf/actions.d/actions_qfeeds.conf
index b693285e2..e2fba096e 100644
--- a/security/q-feeds-connector/src/opnsense/service/conf/actions.d/actions_qfeeds.conf
+++ b/security/q-feeds-connector/src/opnsense/service/conf/actions.d/actions_qfeeds.conf
@@ -1,5 +1,5 @@
[reconfigure]
-command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py fetch_index fetch firewall_load && echo 'EXIT OK'
+command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py fetch_index fetch firewall_load unbound_load && echo 'EXIT OK'
parameters:
type:script_output
message:reconfigure QFeeds
diff --git a/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/+TARGETS b/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/+TARGETS
index da2b51f08..219dc39f8 100644
--- a/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/+TARGETS
+++ b/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/+TARGETS
@@ -1 +1,2 @@
qfeeds.conf:/usr/local/etc/qfeeds.conf
+qfeeds-blocklists.conf:/usr/local/etc/unbound/qfeeds-blocklists.conf
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
new file mode 100644
index 000000000..1f985bf4b
--- /dev/null
+++ b/security/q-feeds-connector/src/opnsense/service/templates/OPNsense/QFeeds/qfeeds-blocklists.conf
@@ -0,0 +1,5 @@
+{% if not helpers.empty('OPNsense.QFeedsConnector.general.apikey') and
+ not helpers.empty('OPNsense.QFeedsConnector.general.enable_unbound_bl') %}
+[settings]
+filenames=/var/db/qfeeds-tables/malware_domains.txt
+{% endif %}
\ No newline at end of file