From 67d1519bad3dc2c8a6640d9090303c03ce6dd0d5 Mon Sep 17 00:00:00 2001 From: mbedworth Date: Thu, 29 Jan 2026 23:07:58 -0500 Subject: [PATCH 1/2] security/wazuh-agent: fix syntax error in opnsense-fw active response Fix critical syntax error in opnsense-fw active response script that prevents IPs from being added to the __wazuh_agent_drop alias. ## Problem The script contains invalid Python syntax - a variable assignment inside a dictionary literal: ```python "parameters":{ unique_key = "%s-%s" % (...) # Invalid Python syntax "keys": [unique_key] } ``` This causes the script to fail with a SyntaxError on all 'add' commands, meaning attacking IPs are never blocked. ## Changes - Move unique_key assignment outside dictionary literal (fixes SyntaxError) - Fix typo: 'even' -> 'event' in error message - Add debug logging for easier troubleshooting ## Testing - Verified syntax with `python3 -m py_compile` - Tested active response add/delete operations on OPNsense 26.1 --- .../src/opnsense/scripts/wazuh/opnsense-fw | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/security/wazuh-agent/src/opnsense/scripts/wazuh/opnsense-fw b/security/wazuh-agent/src/opnsense/scripts/wazuh/opnsense-fw index 3eefe8154c..aff38306c6 100755 --- a/security/wazuh-agent/src/opnsense/scripts/wazuh/opnsense-fw +++ b/security/wazuh-agent/src/opnsense/scripts/wazuh/opnsense-fw @@ -101,7 +101,7 @@ def main(params): try: ipaddress.ip_address(srcip) except ValueError: - send_log('Unable to process even, invalid srcip (%s)' % srcip) + send_log('Unable to process event, invalid srcip (%s)' % srcip) return -1 if skip_alias != '' and command == 'add': @@ -113,16 +113,17 @@ def main(params): if command == 'add': # return rule id for timeout list try: + unique_key = "%s-%s" % (event['parameters']['alert']['rule']['id'], srcip) + send_log('Sending check_keys for: %s' % unique_key) print(json.dumps({ "version": 1, "origin": { "name": sys.argv[0], - "module":"active-response" + "module": "active-response" }, "command": "check_keys", - "parameters":{ - unique_key = "%s-%s" % (event['parameters']['alert']['rule']['id'], srcip) - "keys": [unique_key] + "parameters": { + "keys": [unique_key] } })) sys.stdout.flush() @@ -131,6 +132,7 @@ def main(params): # When attached to stdin we're likely running inside the agent, in which case we will read a second event which # may abort the first one. if params.input == '/dev/stdin': + send_log('Waiting for manager response...') timeout_event = None try: timeout_event=json.loads(read_data(params.input)) @@ -138,6 +140,7 @@ def main(params): pass if timeout_event: send_log('Received : %s' % json.dumps(timeout_event)) + send_log('Manager says: %s' % timeout_event.get('command')) if timeout_event.get('command') == 'abort': send_log('Aborted') return 0 From 5d48eb3e8b2466a1a87b8636e6038dc26f940e13 Mon Sep 17 00:00:00 2001 From: mbedworth Date: Sat, 2 May 2026 19:10:48 -0400 Subject: [PATCH 2/2] dns/bind: add native DNS-over-TLS (DoT) server support Add GUI configuration for incoming DNS-over-TLS connections (RFC 7858). BIND 9.18+ supports a native tls clause, but the plugin had no way to configure it. This adds three fields to the general settings model and form: dotenable, dotport (default 853), and dotcertificate. A new generate_certs.php script reads the selected certificate from the OPNsense trust store and writes the PEM files to /var/etc/named/ before named starts. The configd [start] and [restart] actions are updated to call this script first, ensuring cert files are present on every boot (since /var/etc/ is a tmpfs ramdisk). A standalone [certsetup] action is also added for on-demand use. The named.conf template emits a tls dot-tls stanza and listen-on lines for port 853 when dotenable is set, reusing the existing listen addresses. Requires BIND 9.18+. --- .../OPNsense/Bind/forms/general.xml | 22 ++++++ .../mvc/app/models/OPNsense/Bind/General.xml | 14 +++- .../scripts/OPNsense/Bind/generate_certs.php | 69 +++++++++++++++++++ .../service/conf/actions.d/actions_bind.conf | 11 ++- .../templates/OPNsense/Bind/named.conf | 15 ++++ 5 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 dns/bind/src/opnsense/scripts/OPNsense/Bind/generate_certs.php diff --git a/dns/bind/src/opnsense/mvc/app/controllers/OPNsense/Bind/forms/general.xml b/dns/bind/src/opnsense/mvc/app/controllers/OPNsense/Bind/forms/general.xml index 23e9c92026..89e11ab844 100644 --- a/dns/bind/src/opnsense/mvc/app/controllers/OPNsense/Bind/forms/general.xml +++ b/dns/bind/src/opnsense/mvc/app/controllers/OPNsense/Bind/forms/general.xml @@ -195,4 +195,26 @@ true The base64-encoded RNDC key. This requires a restart of the Bind Service. + + header + + + + general.dotenable + + checkbox + Accept incoming DNS-over-TLS (port 853) connections. Requires BIND 9.18+ and a valid certificate. The same listen addresses used for plain DNS are also used for DoT. + + + general.dotport + + text + Port to listen on for DNS-over-TLS connections. Default is 853. + + + general.dotcertificate + + dropdown + TLS certificate to present to DNS-over-TLS clients. Select a certificate from System > Trust > Certificates. + diff --git a/dns/bind/src/opnsense/mvc/app/models/OPNsense/Bind/General.xml b/dns/bind/src/opnsense/mvc/app/models/OPNsense/Bind/General.xml index 238c9dc248..201ad79d4d 100644 --- a/dns/bind/src/opnsense/mvc/app/models/OPNsense/Bind/General.xml +++ b/dns/bind/src/opnsense/mvc/app/models/OPNsense/Bind/General.xml @@ -1,7 +1,7 @@ //OPNsense/bind/general BIND configuration - 1.0.12 + 1.0.13 0 @@ -167,5 +167,17 @@ Y VxtIzJevSQXqnr7h2qerrcwjnZlMWSGGFBndKeNIDfw= + + 0 + Y + + + 853 + Y + + + N + Please select a valid certificate for DNS over TLS. + diff --git a/dns/bind/src/opnsense/scripts/OPNsense/Bind/generate_certs.php b/dns/bind/src/opnsense/scripts/OPNsense/Bind/generate_certs.php new file mode 100644 index 0000000000..df76502b91 --- /dev/null +++ b/dns/bind/src/opnsense/scripts/OPNsense/Bind/generate_certs.php @@ -0,0 +1,69 @@ +#!/usr/local/bin/php +object(); +$general = $cfg->OPNsense->bind->general ?? new \stdClass(); + +$dotenable = (string)($general->dotenable ?? '0'); +$certref = (string)($general->dotcertificate ?? ''); + +if ($dotenable === '1' && $certref !== '') { + $cert = Store::getCertificate($certref); + if ($cert && isset($cert['prv'])) { + File::file_update_contents($certfile, $cert['crt'], 0640); + File::file_update_contents($keyfile, $cert['prv'], 0640); + chown($certfile, 'bind'); + chgrp($certfile, 'bind'); + chown($keyfile, 'bind'); + chgrp($keyfile, 'bind'); + exit(0); + } +} + +foreach ([$certfile, $keyfile] as $f) { + if (file_exists($f)) { + unlink($f); + } +} diff --git a/dns/bind/src/opnsense/service/conf/actions.d/actions_bind.conf b/dns/bind/src/opnsense/service/conf/actions.d/actions_bind.conf index c3d4a47a5e..ff9f2e7f7f 100644 --- a/dns/bind/src/opnsense/service/conf/actions.d/actions_bind.conf +++ b/dns/bind/src/opnsense/service/conf/actions.d/actions_bind.conf @@ -1,5 +1,12 @@ +[certsetup] +command:/usr/local/bin/php /usr/local/opnsense/scripts/OPNsense/Bind/generate_certs.php +parameters: +type:script +message:setting up BIND TLS certificates +description: Write BIND DoT certificate files from OPNsense trust store + [start] -command:/usr/local/etc/rc.d/named start +command:/usr/local/bin/php /usr/local/opnsense/scripts/OPNsense/Bind/generate_certs.php && /usr/local/etc/rc.d/named start parameters: type:script message:starting BIND @@ -11,7 +18,7 @@ type:script message:stopping BIND [restart] -command:/usr/local/etc/rc.d/named restart +command:/usr/local/bin/php /usr/local/opnsense/scripts/OPNsense/Bind/generate_certs.php && /usr/local/etc/rc.d/named restart parameters: type:script message:restarting BIND diff --git a/dns/bind/src/opnsense/service/templates/OPNsense/Bind/named.conf b/dns/bind/src/opnsense/service/templates/OPNsense/Bind/named.conf index 9196b5de3e..1bcdd01297 100644 --- a/dns/bind/src/opnsense/service/templates/OPNsense/Bind/named.conf +++ b/dns/bind/src/opnsense/service/templates/OPNsense/Bind/named.conf @@ -8,6 +8,13 @@ acl "{{ acl_list.name }}" { {{ acl_list.networks.replace(',', '; ') }}; }; {% endfor %} {% endif %} +{% if helpers.exists('OPNsense.bind.general.dotenable') and OPNsense.bind.general.dotenable == '1' %} +tls dot-tls { + cert-file "/var/etc/named/dot.crt"; + key-file "/var/etc/named/dot.key"; +}; +{% endif %} + options { directory "/usr/local/etc/namedb/working"; @@ -21,6 +28,14 @@ options { {% for listenv6 in OPNsense.bind.general.listenv6.split(',') %} listen-on-v6 port {{ OPNsense.bind.general.port }} { {% if listenv6 == '::' %}any{% else %}{{ listenv6 }}{% endif %}; }; {% endfor %} +{% if helpers.exists('OPNsense.bind.general.dotenable') and OPNsense.bind.general.dotenable == '1' %} +{% for listenv4 in OPNsense.bind.general.listenv4.split(',') %} + listen-on port {{ OPNsense.bind.general.dotport }} tls dot-tls { {% if listenv4 == '0.0.0.0' %}any{% else %}{{ listenv4 }}{% endif %}; }; +{% endfor %} +{% for listenv6 in OPNsense.bind.general.listenv6.split(',') %} + listen-on-v6 port {{ OPNsense.bind.general.dotport }} tls dot-tls { {% if listenv6 == '::' %}any{% else %}{{ listenv6 }}{% endif %}; }; +{% endfor %} +{% endif %} {% if helpers.exists('OPNsense.bind.general.querysource') and OPNsense.bind.general.querysource != '' %} query-source {{ OPNsense.bind.general.querysource }};