mirror of
https://github.com/opnsense/plugins.git
synced 2026-02-18 18:19:25 -05:00
Security: Q-Feeds Connect - add new options as available in integrated blocklists (#5226)
* Security: Q-Feeds Connect - add new options as available in integrated blocklists, closes https://github.com/opnsense/plugins/issues/5197 This adds allowlists (regex patterns), source_nets Q-Feeds applies on, address to return and optional NXDOMAIN responses. Please note this version is only compatible with current community versions, business edition installs will have to wait for 26.4. * Security: Q-Feeds Connect - update version and changelog
This commit is contained in:
parent
449323e6a5
commit
de4c98eee2
7 changed files with 121 additions and 8 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -15,4 +15,42 @@
|
|||
<type>checkbox</type>
|
||||
<help>Use domain feeds in Unbound DNS blocklist, requires blocklists to be enabled in order to have effect</help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
<label>Unbound blocklist settings</label>
|
||||
<style>unbound_options</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>connect.unbound.allowlists</id>
|
||||
<label>Allowlist Domains</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>List of domains to allow. You can use regular expressions. This allow list only applies to blocklist matches on items in this policy.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connect.unbound.source_nets</id>
|
||||
<label>Source Net(s)</label>
|
||||
<type>select_multiple</type>
|
||||
<style>tokenize</style>
|
||||
<allownew>true</allownew>
|
||||
<help>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. </help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connect.unbound.address</id>
|
||||
<label>Destination Address</label>
|
||||
<type>text</type>
|
||||
<advanced>true</advanced>
|
||||
<help>
|
||||
Destination ip address for entries in the blocklist (leave empty to use default: 0.0.0.0).
|
||||
Not used when "Return NXDOMAIN" is checked.
|
||||
</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>connect.unbound.nxdomain</id>
|
||||
<label>Return NXDOMAIN</label>
|
||||
<type>checkbox</type>
|
||||
<advanced>true</advanced>
|
||||
<help>Use the DNS response code NXDOMAIN instead of a destination address.</help>
|
||||
</field>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -7,5 +7,21 @@
|
|||
<apikey type="TextField"/>
|
||||
<enable_unbound_bl type="BooleanField"/>
|
||||
</general>
|
||||
<unbound>
|
||||
<allowlists type="CSVListField"/>
|
||||
<source_nets type="NetworkField">
|
||||
<Multiple>Y</Multiple>
|
||||
<Strict>Y</Strict>
|
||||
<ValidationMessage>Please specify a valid network segment or address (IPv4/IPv6). If a mask is provided, please omit the host bits.</ValidationMessage>
|
||||
<WildcardEnabled>N</WildcardEnabled>
|
||||
<NetMaskRequired>N</NetMaskRequired>
|
||||
<AsList>Y</AsList>
|
||||
</source_nets>
|
||||
<address type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
<AddressFamily>ipv4</AddressFamily>
|
||||
</address>
|
||||
<nxdomain type="BooleanField"/>
|
||||
</unbound>
|
||||
</items>
|
||||
</model>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -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 %}
|
||||
|
|
|
|||
Loading…
Reference in a new issue