mirror of
https://github.com/opnsense/plugins.git
synced 2026-05-28 04:34:15 -04:00
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.
This commit is contained in:
parent
449323e6a5
commit
cd23399ea4
5 changed files with 112 additions and 6 deletions
|
|
@ -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