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 23e9c9202..89e11ab84 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 238c9dc24..201ad79d4 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 000000000..df76502b9
--- /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 c3d4a47a5..ff9f2e7f7 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 9196b5de3..1bcdd0129 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 }};