mirror of
https://github.com/opnsense/plugins.git
synced 2026-02-03 20:40:37 -05:00
Feature/dnscrypt proxy blocklist support (#5083)
* Add ports to Events page * fixes race condition updating the blocklist * Native integration with DNSCrypt-proxy Added Q-Feeds domains to the DNSBL list of DNSCrypt-Proxy. Changed since the initial way, this is more native. Q-Feeds domains txt files only created if DNSCrypt-proxy is installed and if the list (qf) is selected.
This commit is contained in:
parent
81f3e21a1a
commit
d987a7e53e
7 changed files with 133 additions and 3 deletions
|
|
@ -19,6 +19,7 @@
|
|||
<ep>Easyprivacy List</ep>
|
||||
<nc>NoCoin List</nc>
|
||||
<pt>PornTop1M List</pt>
|
||||
<qf>Q-Feeds (when installed)</qf>
|
||||
<sa>Simple Ad List</sa>
|
||||
<st>Simple Tracker List</st>
|
||||
<sb>Steven Black List</sb>
|
||||
|
|
|
|||
|
|
@ -154,6 +154,13 @@ simpletrack() {
|
|||
rm ${WORKDIR}/simpletrack-raw
|
||||
}
|
||||
|
||||
qfeeds() {
|
||||
# Q-Feeds List
|
||||
if [ -f "/usr/local/etc/dnscrypt-proxy/blacklist-qfeeds.txt" ] && [ -s "/usr/local/etc/dnscrypt-proxy/blacklist-qfeeds.txt" ]; then
|
||||
sed "/\.$/d" /usr/local/etc/dnscrypt-proxy/blacklist-qfeeds.txt | sed "/^#/d" | sed "/\_/d" | sed "/^[[:space:]]*$/d" | sed "/\.\./d" | sed "s/^\.//g" > ${WORKDIR}/qfeeds
|
||||
fi
|
||||
}
|
||||
|
||||
install() {
|
||||
# Put all files in correct format
|
||||
for FILE in $(find ${WORKDIR} -type f); do
|
||||
|
|
@ -222,6 +229,9 @@ for CAT in $(echo ${DNSBL} | tr ',' ' '); do
|
|||
yy)
|
||||
yoyo
|
||||
;;
|
||||
qf)
|
||||
qfeeds
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
PLUGIN_NAME= q-feeds-connector
|
||||
PLUGIN_VERSION= 1.3
|
||||
PLUGIN_VERSION= 1.4
|
||||
PLUGIN_TIER= 2
|
||||
PLUGIN_COMMENT= Connector for Q-Feeds threat intel
|
||||
PLUGIN_MAINTAINER= devel@qfeeds.com
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@ Connector for Q-Feeds threat intel
|
|||
|
||||
Plugin Changelog
|
||||
================
|
||||
1.4
|
||||
|
||||
* Feature: Added DNSCrypt-Proxy
|
||||
|
||||
1.3
|
||||
|
||||
* Widget: Added license info
|
||||
* Events: added source and destination port
|
||||
|
||||
1.3
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
#!/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
|
||||
import glob
|
||||
import re
|
||||
|
||||
# Check if 'qf' is selected in DNSCrypt-proxy DNSBL configuration
|
||||
def is_qf_selected():
|
||||
rc_conf_file = '/etc/rc.conf.d/dnscrypt_proxy'
|
||||
if os.path.exists(rc_conf_file):
|
||||
try:
|
||||
with open(rc_conf_file, 'r') as f:
|
||||
for line in f:
|
||||
# Look for dnscrypt_proxy_dnsbl="..." line
|
||||
match = re.search(r'dnscrypt_proxy_dnsbl="([^"]*)"', line)
|
||||
if match:
|
||||
dnsbl_list = match.group(1)
|
||||
# Check if 'qf' is in the comma-separated list
|
||||
return 'qf' in [x.strip() for x in dnsbl_list.split(',')]
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
# Q-Feeds domain files directory
|
||||
qfeeds_tables_dir = '/var/db/qfeeds-tables'
|
||||
|
||||
# Automatically find all domain files (*_domains.txt) in qfeeds-tables directory
|
||||
# This will include malware_domains.txt, phishing_domains.txt, etc.
|
||||
qfeeds_filenames = []
|
||||
if os.path.isdir(qfeeds_tables_dir):
|
||||
# Find all files ending with _domains.txt (e.g., malware_domains.txt, phishing_domains.txt)
|
||||
pattern = os.path.join(qfeeds_tables_dir, '*_domains.txt')
|
||||
qfeeds_filenames = sorted(glob.glob(pattern))
|
||||
|
||||
# Collect q-feeds domains
|
||||
qfeeds_domains = set()
|
||||
for filename in qfeeds_filenames:
|
||||
if os.path.exists(filename):
|
||||
with open(filename, 'r') as f_in:
|
||||
for line in f_in:
|
||||
domain = line.strip()
|
||||
if domain:
|
||||
qfeeds_domains.add(domain)
|
||||
|
||||
# Write q-feeds domains to blacklist-qfeeds.txt
|
||||
# dnscrypt-proxy's dnsbl.sh qfeeds() function will read this file when 'qf' is selected in DNSBL config
|
||||
qfeeds_blacklist_file = '/usr/local/etc/dnscrypt-proxy/blacklist-qfeeds.txt'
|
||||
dnscrypt_proxy_dir = '/usr/local/etc/dnscrypt-proxy'
|
||||
|
||||
# Only proceed if DNSCrypt-proxy directory exists (plugin is installed) AND 'qf' is selected
|
||||
if os.path.isdir(dnscrypt_proxy_dir) and is_qf_selected():
|
||||
if qfeeds_domains:
|
||||
# Write q-feeds domains to separate file
|
||||
with open(qfeeds_blacklist_file, 'w') as f_out:
|
||||
for domain in sorted(qfeeds_domains):
|
||||
f_out.write("%s\n" % domain)
|
||||
else:
|
||||
# Remove q-feeds blacklist file if no domains available
|
||||
if os.path.exists(qfeeds_blacklist_file):
|
||||
os.remove(qfeeds_blacklist_file)
|
||||
elif os.path.isdir(dnscrypt_proxy_dir):
|
||||
# DNSCrypt-proxy is installed but 'qf' is not selected - remove the file if it exists
|
||||
if os.path.exists(qfeeds_blacklist_file):
|
||||
os.remove(qfeeds_blacklist_file)
|
||||
|
||||
|
||||
|
|
@ -46,6 +46,7 @@ class QFeedsActions:
|
|||
'show_index',
|
||||
'firewall_load',
|
||||
'unbound_load',
|
||||
'dnscryptproxy_load',
|
||||
'update',
|
||||
'stats',
|
||||
'logs'
|
||||
|
|
@ -121,6 +122,24 @@ class QFeedsActions:
|
|||
subprocess.run(['/usr/local/sbin/configctl', 'unbound', 'dnsbl'])
|
||||
yield 'update unbound blocklist'
|
||||
|
||||
def dnscryptproxy_load(self):
|
||||
script_path = '/usr/local/opnsense/scripts/dnscryptproxy/blocklists/qfeeds_bl.py'
|
||||
dnscrypt_proxy_dir = '/usr/local/etc/dnscrypt-proxy'
|
||||
if os.path.exists(script_path) and os.path.isdir(dnscrypt_proxy_dir):
|
||||
subprocess.run([script_path], capture_output=True, text=True)
|
||||
# Trigger dnscrypt-proxy DNSBL update to merge blacklist-qfeeds.txt
|
||||
# Only if DNSCrypt-proxy is installed (directory exists)
|
||||
result = subprocess.run(['/usr/local/sbin/configctl', 'dnscryptproxy', 'dnsbl'],
|
||||
capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
yield 'update dnscrypt-proxy blocklist'
|
||||
else:
|
||||
yield 'dnscrypt-proxy not available'
|
||||
elif not os.path.isdir(dnscrypt_proxy_dir):
|
||||
yield 'dnscrypt-proxy not installed'
|
||||
else:
|
||||
yield 'dnscrypt-proxy blocklist script not found'
|
||||
|
||||
def update(self):
|
||||
update_sleep = 99999
|
||||
try:
|
||||
|
|
@ -136,7 +155,7 @@ class QFeedsActions:
|
|||
if do_update:
|
||||
if 0 < update_sleep <= 300:
|
||||
time.sleep(update_sleep)
|
||||
for action in ['fetch_index', 'fetch', 'firewall_load', 'unbound_load']:
|
||||
for action in ['fetch_index', 'fetch', 'firewall_load', 'unbound_load', 'dnscryptproxy_load']:
|
||||
yield from getattr(self, action)()
|
||||
|
||||
def stats(self):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[reconfigure]
|
||||
command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py fetch_index fetch firewall_load unbound_load && echo 'EXIT OK'
|
||||
command:/usr/local/opnsense/scripts/qfeeds/qfeedsctl.py fetch_index fetch firewall_load unbound_load dnscryptproxy_load && echo 'EXIT OK'
|
||||
parameters:
|
||||
type:script_output
|
||||
message:reconfigure QFeeds
|
||||
|
|
|
|||
Loading…
Reference in a new issue