This commit is contained in:
schreibubi 2026-02-03 09:42:52 +01:00 committed by GitHub
commit 19d280c5c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 151 additions and 6 deletions

View file

@ -30,6 +30,19 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once('certs.inc');
function export_pem_file($filename, $data, $post_append = null)
{
$pem_content = trim(str_replace("\n\n", "\n", str_replace(
"\r",
"",
base64_decode((string)$data)
) . ($post_append == null ? '' : "\n" . $post_append)));
file_put_contents($filename, $pem_content);
chmod($filename, 0640);
}
function unbound_enabled()
{
return !(new \OPNsense\Unbound\Unbound())->general->enabled->isEmpty();
@ -234,6 +247,10 @@ function unbound_generate_config()
}
}
$port = $general['port'];
$port_doh = $general['port_doh'];
$port_dot = $general['port_dot'];
$bindints = '';
if (!empty($general['active_interface'])) {
$active_interfaces = explode(',', $general['active_interface']);
@ -255,12 +272,25 @@ function unbound_generate_config()
}
foreach ($addresses as $address) {
$bindints .= "interface: $address\n";
$bindints .= "interface: $address@$port\n";
if (!empty($general['enable_dot'])) {
$bindints .= "interface: $address@$port_dot\n";
}
if (!empty($general['enable_doh'])) {
$bindints .= "interface: $address@$port_doh\n";
}
}
} else {
$bindints .= "interface: 0.0.0.0\n";
$bindints .= "interface: ::\n";
$bindints .= "interface-automatic: yes\n";
$bindints .= "interface: 0.0.0.0@$port\n";
$bindints .= "interface: ::@$port\n";
if (!empty($general['enable_dot'])) {
$bindints .= "interface: 0.0.0.0@$port_dot\n";
$bindints .= "interface: ::@$port_dot\n";
}
if (!empty($general['enable_doh'])) {
$bindints .= "interface: 0.0.0.0@$port_doh\n";
$bindints .= "interface: ::@$port_doh\n";
}
}
$outgoingints = '';
@ -282,7 +312,7 @@ function unbound_generate_config()
unbound_add_host_entries($ifconfig_details);
$port = $general['port'];
/* do not touch prefer-ip6 as it is defaulting to 'no' anyway */
$do_ip6 = is_ipv6_allowed() ? 'yes' : 'no';
@ -329,6 +359,38 @@ EOD;
$so_reuseport = empty(system_sysctl_get()['net.inet.rss.enabled']) ? 'yes' : 'no';
$dohdot_settings = '';
if (!empty($general['enable_doh']) || !empty($general['enable_dot'])) {
$cert =& lookup_cert($general['dohdot_cert']);
$chain = [];
$ca_chain = ca_chain_array($cert);
if (is_array($ca_chain)) {
foreach ($ca_chain as $entry) {
$chain[] = base64_decode($entry['crt']);
}
}
if (isset($cert)) {
export_pem_file(
'/var/unbound/dohdot.pem',
$cert['crt'],
implode("\n", $chain)
);
export_pem_file(
'/var/unbound/dohdot.key',
$cert['prv']
);
$dohdot_settings .= "# DoH and DoT\n";
if (!empty($general['enable_dot'])) {
$dohdot_settings .= "tls-port: $port_dot\n";
}
if (!empty($general['enable_doh'])) {
$dohdot_settings .= "https-port: $port_doh\n";
}
$dohdot_settings .= "tls-service-key: /var/unbound/dohdot.key\n";
$dohdot_settings .= "tls-service-pem: /var/unbound/dohdot.pem\n";
}
}
$unboundconf = <<<EOD
##########################
# Unbound Configuration
@ -362,6 +424,7 @@ module-config: "{$module_config}"
{$anchor_file}
{$forward_local}
{$dns64_config}
{$dohdot_settings}
# Interface IP(s) to bind to
{$bindints}

View file

@ -10,6 +10,35 @@
<type>text</type>
<help>The TCP/UDP port used for responding to DNS queries.</help>
</field>
<field>
<id>unbound.general.enable_doh</id>
<label>Enable DoH</label>
<type>checkbox</type>
<help>Only enable this on port 443 when the web-interface is not listening on the same port!</help>
</field>
<field>
<id>unbound.general.port_doh</id>
<label>Listen Port for DoH</label>
<type>text</type>
<help>The TCP/UDP port used for responding to DoH queries.</help>
</field>
<field>
<id>unbound.general.enable_dot</id>
<label>Enable DoT</label>
<type>checkbox</type>
</field>
<field>
<id>unbound.general.port_dot</id>
<label>Listen Port for DoT</label>
<type>text</type>
<help>The TCP/UDP port used for responding to DoT queries.</help>
</field>
<field>
<id>unbound.general.dohdot_cert</id>
<label>Certificate</label>
<type>dropdown</type>
<help>DoH and DoT Certificate to use</help>
</field>
<field>
<id>unbound.general.active_interface</id>
<label>Network Interfaces</label>

View file

@ -12,6 +12,26 @@
<Default>53</Default>
<Required>Y</Required>
</port>
<enable_doh type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enable_doh>
<port_doh type="PortField">
<default>443</default>
<Required>Y</Required>
</port_doh>
<enable_dot type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enable_dot>
<port_dot type="PortField">
<default>853</default>
<Required>Y</Required>
</port_dot>
<dohdot_cert type="CertificateField">
<Required>N</Required>
<ValidationMessage>Please select a valid certificate from the list</ValidationMessage>
</dohdot_cert>
<stats type="BooleanField"/>
<active_interface type=".\UnboundInterfaceField">
<Multiple>Y</Multiple>

View file

@ -62,6 +62,26 @@
'elapsed': "{{ lang._('Elapsed') }}"
};
const descriptionNumQuery = {
'query': {
'type': {
'A': "{{ lang._('A') }}",
'AAAA': "{{ lang._('AAAA') }}",
'CNAME': "{{ lang._('CNAME') }}",
'SOA': "{{ lang._('SOA') }}",
'PTR': "{{ lang._('PTR') }}",
'TXT': "{{ lang._('TXT') }}",
'SRV': "{{ lang._('SRV') }}",
'NAPTR': "{{ lang._('NAPTR') }}",
},
'tls': {
'__value__': "{{ lang._('DoT') }}"
},
'https': "{{ lang._('DoH') }}",
'ipv6': "{{ lang._('IPv6') }}"
}
};
function writeDescs(parent, data, descriptions) {
$.each(descriptions, function(descKey, descValue) {
if (typeof descValue !== 'object') {
@ -136,6 +156,19 @@
writeDescs(tbody, value, descriptionMapTime);
table.append(tbody);
statsView.append(table);
} else if (key === "num") {
let title = document.createElement("h2");
title.innerHTML = "Query Types";
statsView.append(title);
let table = document.createElement('table');
table.classList.add('table');
table.classList.add('table-striped');
table.style.width = 'auto';
let tbody = document.createElement('tbody');
writeDescs(tbody, value, descriptionNumQuery);
table.append(tbody);
statsView.append(table);
}
});
}
@ -155,7 +188,7 @@
// initial fetch
updateStats();
updateServiceControlUI('unbound');
updateServiceControlUI('unbound');
});
</script>