Project

General

Profile

Download (24.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_unbound.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2024 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2014 Warren Baker (warren@pfsense.org)
10
 * All rights reserved.
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24

    
25
##|+PRIV
26
##|*IDENT=page-services-dnsresolver
27
##|*NAME=Services: DNS Resolver
28
##|*DESCR=Allow access to the 'Services: DNS Resolver' page.
29
##|*MATCH=services_unbound.php*
30
##|-PRIV
31

    
32
require_once("guiconfig.inc");
33
require_once("unbound.inc");
34
require_once("pfsense-utils.inc");
35
require_once("system.inc");
36

    
37
$python_files = glob("{$g['unbound_chroot_path']}/*.py");
38
$python_scripts = array();
39
if (!empty($python_files)) {
40
	foreach ($python_files as $file) {
41
		$file = pathinfo($file, PATHINFO_FILENAME);
42
		$python_scripts[$file] = $file;
43
	}
44
}
45
else {
46
	$python_scripts = array('' => 'No Python Module scripts found');
47
}
48

    
49
$pconfig['enable'] = config_path_enabled('unbound');
50
$pconfig['enablessl'] = config_path_enabled('unbound', 'enablessl');
51
$pconfig['strictout'] = config_path_enabled('unbound', 'strictout');
52
$pconfig['dnssec'] = config_path_enabled('unbound', 'dnssec');
53
$pconfig['python'] = config_path_enabled('unbound', 'python');
54
$pconfig['forwarding'] = config_path_enabled('unbound', 'forwarding');
55
$pconfig['forward_tls_upstream'] = config_path_enabled('unbound', 'forward_tls_upstream');
56
$pconfig['regdhcp'] = config_path_enabled('unbound', 'regdhcp');
57
$pconfig['regdhcpstatic'] = config_path_enabled('unbound', 'regdhcpstatic');
58
$pconfig['regovpnclients'] = config_path_enabled('unbound', 'regovpnclients');
59

    
60
$pconfig['python_order'] = config_get_path('unbound/python_order');
61
$pconfig['python_script'] = config_get_path('unbound/python_script');
62
$pconfig['port'] = config_get_path('unbound/port');
63
$pconfig['tlsport'] = config_get_path('unbound/tlsport');
64
$pconfig['sslcertref'] = config_get_path('unbound/sslcertref');
65
$pconfig['custom_options'] = base64_decode(config_get_path('unbound/custom_options'));
66

    
67
if (config_get_path('unbound/active_interface')) {
68
	$pconfig['active_interface'] = explode(",", config_get_path('unbound/active_interface'));
69
} else {
70
	$pconfig['active_interface'] = array();
71
}
72

    
73
if (config_get_path('unbound/outgoing_interface')) {
74
	$pconfig['outgoing_interface'] = explode(",", config_get_path('unbound/outgoing_interface'));
75
} else {
76
	$pconfig['outgoing_interface'] = array();
77
}
78

    
79
$pconfig['system_domain_local_zone_type'] = config_get_path('unbound/system_domain_local_zone_type', 'transparent');
80

    
81
$certs_available = false;
82
if (count(config_get_path('cert', []))) {
83
	$certs_available = true;
84
}
85

    
86
if ($_POST['apply']) {
87
	$retval = 0;
88
	$retval |= services_unbound_configure();
89
	if ($retval == 0) {
90
		clear_subsystem_dirty('unbound');
91
	}
92
	/* Update resolv.conf in case the interface bindings exclude localhost. */
93
	system_resolvconf_generate();
94
	/* Start or restart dhcpleases when it's necessary */
95
	system_dhcpleases_configure();
96
}
97

    
98
if ($_POST['save']) {
99
	$pconfig = $_POST;
100
	unset($input_errors);
101

    
102
	if (isset($pconfig['enable']) && config_path_enabled('dnsmasq')) {
103
		if ($pconfig['port'] == config_get_path('dnsmasq/port')) {
104
			$input_errors[] = gettext("The DNS Forwarder is enabled using this port. Choose a non-conflicting port, or disable the DNS Forwarder.");
105
		}
106
	}
107

    
108
	if (isset($pconfig['enablessl']) && (!$certs_available || empty($pconfig['sslcertref']))) {
109
		$input_errors[] = gettext("Acting as an SSL/TLS server requires a valid server certificate");
110
	}
111

    
112
	// forwarding mode requires having valid DNS servers
113
	if (isset($pconfig['forwarding'])) {
114
		$founddns = false;
115
		foreach (get_dns_nameservers(false, true) as $dns_server) {
116
			if (!ip_in_subnet($dns_server, "127.0.0.0/8")) {
117
				$founddns = true;
118
			}
119
		}
120
		if ($founddns == false) {
121
			$input_errors[] = gettext("At least one DNS server must be specified under System > General Setup to enable Forwarding mode.");
122
		}
123
	}
124

    
125
	if (empty($pconfig['active_interface'])) {
126
		$input_errors[] = gettext("One or more Network Interfaces must be selected for binding.");
127
	} elseif ((config_get_path('system/dnslocalhost') != 'remote') && (!in_array("lo0", $pconfig['active_interface']) && !in_array("all", $pconfig['active_interface']))) {
128
		$input_errors[] = gettext("This system is configured to use the DNS Resolver as its DNS server, so Localhost or All must be selected in Network Interfaces.");
129
	}
130

    
131
	if (empty($pconfig['outgoing_interface'])) {
132
		$input_errors[] = gettext("One or more Outgoing Network Interfaces must be selected.");
133
	}
134

    
135
	if ($pconfig['port'] && !is_port($pconfig['port'])) {
136
		$input_errors[] = gettext("A valid port number must be specified.");
137
	}
138
	if ($pconfig['tlsport'] && !is_port($pconfig['tlsport'])) {
139
		$input_errors[] = gettext("A valid SSL/TLS port number must be specified.");
140
	}
141

    
142
	if (is_array($pconfig['active_interface']) && !empty($pconfig['active_interface'])) {
143
		$display_active_interface = $pconfig['active_interface'];
144
		$pconfig['active_interface'] = implode(",", $pconfig['active_interface']);
145
	}
146

    
147
	if ((isset($pconfig['regdhcp']) || isset($pconfig['regdhcpstatic'])) && !is_dhcp_server_enabled()) {
148
		$input_errors[] = gettext("DHCP Server must be enabled for DHCP Registration to work in DNS Resolver.");
149
	}
150

    
151
	if (($pconfig['system_domain_local_zone_type'] == "redirect") && isset($pconfig['regdhcp'])) {
152
		$input_errors[] = gettext('A System Domain Local Zone Type of "redirect" is not compatible with dynamic DHCP Registration.');
153
	}
154

    
155
	if (isset($pconfig['python']) &&
156
	    !array_key_exists(array_get_path($pconfig, 'python_script'), $python_scripts)) {
157
		array_del_path($pconfig, 'python_script');
158
		$input_errors[] = gettext('The submitted Python Module Script does not exist or is invalid.');
159
	}
160

    
161
	$display_custom_options = $pconfig['custom_options'];
162
	$pconfig['custom_options'] = base64_encode(str_replace("\r\n", "\n", $pconfig['custom_options']));
163

    
164
	if (is_array($pconfig['outgoing_interface']) && !empty($pconfig['outgoing_interface'])) {
165
		$display_outgoing_interface = $pconfig['outgoing_interface'];
166
		$pconfig['outgoing_interface'] = implode(",", $pconfig['outgoing_interface']);
167
	}
168

    
169
	$test_output = array();
170
	if (test_unbound_config($pconfig, $test_output)) {
171
		$input_errors[] = gettext("The generated config file cannot be parsed by unbound. Please correct the following errors:");
172
		$input_errors = array_merge($input_errors, $test_output);
173
	}
174

    
175
	if (!$input_errors) {
176
		config_set_path('unbound/enable', isset($pconfig['enable']));
177
		config_set_path('unbound/enablessl', isset($pconfig['enablessl']));
178
		config_set_path('unbound/port', $pconfig['port']);
179
		config_set_path('unbound/tlsport', $pconfig['tlsport']);
180
		config_set_path('unbound/sslcertref', $pconfig['sslcertref']);
181
		config_set_path('unbound/strictout', isset($pconfig['strictout']));
182
		config_set_path('unbound/dnssec', isset($pconfig['dnssec']));
183

    
184
		config_set_path('unbound/python', isset($pconfig['python']));
185
		if (isset($pconfig['python'])) {
186
			config_set_path('unbound/python_order', $pconfig['python_order']);
187
			config_set_path('unbound/python_script', $pconfig['python_script']);
188
		} else {
189
			config_del_path('unbound/python_order');
190
			config_del_path('unbound/python_script');
191
		}
192

    
193
		config_set_path('unbound/forwarding', isset($pconfig['forwarding']));
194
		config_set_path('unbound/forward_tls_upstream', isset($pconfig['forward_tls_upstream']));
195
		config_set_path('unbound/regdhcp', isset($pconfig['regdhcp']));
196
		config_set_path('unbound/regdhcpstatic', isset($pconfig['regdhcpstatic']));
197
		config_set_path('unbound/regovpnclients', isset($pconfig['regovpnclients']));
198
		config_set_path('unbound/active_interface', $pconfig['active_interface']);
199
		config_set_path('unbound/outgoing_interface', $pconfig['outgoing_interface']);
200
		config_set_path('unbound/system_domain_local_zone_type', $pconfig['system_domain_local_zone_type']);
201
		config_set_path('unbound/custom_options', $pconfig['custom_options']);
202

    
203
		write_config(gettext("DNS Resolver configured."));
204
		mark_subsystem_dirty('unbound');
205
	}
206

    
207
	$pconfig['active_interface'] = $display_active_interface;
208
	$pconfig['outgoing_interface'] = $display_outgoing_interface;
209
	$pconfig['custom_options'] = $display_custom_options;
210
}
211

    
212

    
213
if ($pconfig['custom_options']) {
214
	$customoptions = true;
215
} else {
216
	$customoptions = false;
217
}
218

    
219
if ($_POST['act'] == "del") {
220
	if ($_POST['type'] == 'host') {
221
		if (config_get_path('unbound/hosts/' . $_POST['id'])) {
222
			config_del_path('unbound/hosts/' . $_POST['id']);
223
			write_config(gettext("Host override deleted from DNS Resolver."));
224
			mark_subsystem_dirty('unbound');
225
			header("Location: services_unbound.php");
226
			exit;
227
		}
228
	} elseif ($_POST['type'] == 'doverride') {
229
		if (config_get_path('unbound/domainoverrides/' . $_POST['id'])) {
230
			config_del_path('unbound/domainoverrides/' . $_POST['id']);
231
			write_config(gettext("Domain override deleted from DNS Resolver."));
232
			mark_subsystem_dirty('unbound');
233
			header("Location: services_unbound.php");
234
			exit;
235
		}
236
	}
237
}
238

    
239
function build_if_list($selectedifs) {
240
	$interface_addresses = get_possible_listen_ips(true);
241
	$iflist = array('options' => array(), 'selected' => array());
242

    
243
	$iflist['options']['all']	= gettext("All");
244
	if (empty($selectedifs) || empty($selectedifs[0]) || in_array("all", $selectedifs)) {
245
		array_push($iflist['selected'], "all");
246
	}
247

    
248
	foreach ($interface_addresses as $laddr => $ldescr) {
249
		$iflist['options'][$laddr] = htmlspecialchars($ldescr);
250

    
251
		if ($selectedifs && in_array($laddr, $selectedifs)) {
252
			array_push($iflist['selected'], $laddr);
253
		}
254
	}
255

    
256
	unset($interface_addresses);
257

    
258
	return($iflist);
259
}
260

    
261
$pgtitle = array(gettext("Services"), gettext("DNS Resolver"), gettext("General Settings"));
262
$pglinks = array("", "@self", "@self");
263
$shortcut_section = "resolver";
264

    
265
include_once("head.inc");
266

    
267
if ($input_errors) {
268
	print_input_errors($input_errors);
269
}
270

    
271
if ($_POST['apply']) {
272
	print_apply_result_box($retval);
273
}
274

    
275
if (is_subsystem_dirty('unbound')) {
276
	print_apply_box(gettext("The DNS resolver configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
277
}
278

    
279
display_isc_warning();
280

    
281
$tab_array = array();
282
$tab_array[] = array(gettext("General Settings"), true, "services_unbound.php");
283
$tab_array[] = array(gettext("Advanced Settings"), false, "services_unbound_advanced.php");
284
$tab_array[] = array(gettext("Access Lists"), false, "/services_unbound_acls.php");
285
display_top_tabs($tab_array, true);
286

    
287
$form = new Form();
288

    
289
$section = new Form_Section('General DNS Resolver Options');
290

    
291
$section->addInput(new Form_Checkbox(
292
	'enable',
293
	'Enable',
294
	'Enable DNS resolver',
295
	$pconfig['enable']
296
));
297

    
298
$section->addInput(new Form_Input(
299
	'port',
300
	'Listen Port',
301
	'number',
302
	$pconfig['port'],
303
	['placeholder' => '53']
304
))->setHelp('The port used for responding to DNS queries. It should normally be left blank unless another service needs to bind to TCP/UDP port 53.');
305

    
306
$section->addInput(new Form_Checkbox(
307
	'enablessl',
308
	'Enable SSL/TLS Service',
309
	'Respond to incoming SSL/TLS queries from local clients',
310
	$pconfig['enablessl']
311
))->setHelp('Configures the DNS Resolver to act as a DNS over SSL/TLS server which can answer queries from clients which also support DNS over TLS. ' .
312
		'Activating this option disables automatic interface response routing behavior, thus it works best with specific interface bindings.' );
313

    
314
if ($certs_available) {
315
	$section->addInput($input = new Form_Select(
316
		'sslcertref',
317
		'SSL/TLS Certificate',
318
		$pconfig['sslcertref'],
319
		cert_build_list('cert', 'IPsec')
320
	))->setHelp('The server certificate to use for SSL/TLS service. The CA chain will be determined automatically.');
321
} else {
322
	$section->addInput(new Form_StaticText(
323
		'SSL/TLS Certificate',
324
		sprintf('No Certificates have been defined. A certificate is required before SSL/TLS can be enabled. %1$s Create or Import %2$s a Certificate.',
325
		'<a href="system_certmanager.php">', '</a>')
326
	));
327
}
328

    
329
$section->addInput(new Form_Input(
330
	'tlsport',
331
	'SSL/TLS Listen Port',
332
	'number',
333
	$pconfig['tlsport'],
334
	['placeholder' => '853']
335
))->setHelp('The port used for responding to SSL/TLS DNS queries. It should normally be left blank unless another service needs to bind to TCP/UDP port 853.');
336

    
337
$activeiflist = build_if_list($pconfig['active_interface']);
338

    
339
$section->addInput(new Form_Select(
340
	'active_interface',
341
	'*Network Interfaces',
342
	$activeiflist['selected'],
343
	$activeiflist['options'],
344
	true
345
))->addClass('general', 'resizable')->setHelp('Interface IP addresses used by the DNS Resolver for responding to queries from clients. If an interface has both IPv4 and IPv6 addresses, both are used. Queries to addresses not selected in this list are discarded. ' .
346
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
347

    
348
$outiflist = build_if_list($pconfig['outgoing_interface']);
349

    
350
$section->addInput(new Form_Select(
351
	'outgoing_interface',
352
	'*Outgoing Network Interfaces',
353
	$outiflist['selected'],
354
	$outiflist['options'],
355
	true
356
))->addClass('general', 'resizable')->setHelp('Utilize different network interface(s) that the DNS Resolver will use to send queries to authoritative servers and receive their replies. By default all interfaces are used.');
357

    
358
$section->addInput(new Form_Checkbox(
359
	'strictout',
360
	'Strict Outgoing Network Interface Binding',
361
	'Do not send recursive queries if none of the selected Outgoing Network Interfaces are available.',
362
	$pconfig['strictout']
363
))->setHelp('By default the DNS Resolver sends recursive DNS requests over any available interfaces if none of the selected Outgoing Network Interfaces are available. This option makes the DNS Resolver refuse recursive queries.');
364

    
365
$section->addInput(new Form_Select(
366
	'system_domain_local_zone_type',
367
	'*System Domain Local Zone Type',
368
	$pconfig['system_domain_local_zone_type'],
369
	unbound_local_zone_types()
370
))->setHelp('The local-zone type used for the %1$s system domain (System | General Setup | Domain).  Transparent is the default.', g_get('product_label'));
371

    
372
$section->addInput(new Form_Checkbox(
373
	'dnssec',
374
	'DNSSEC',
375
	'Enable DNSSEC Support',
376
	$pconfig['dnssec']
377
));
378

    
379
$section->addInput(new Form_Checkbox(
380
	'python',
381
	'Python Module',
382
	'Enable Python Module',
383
	$pconfig['python']
384
))->setHelp('Enable the Python Module.');
385

    
386
$section->addInput(new Form_Select(
387
	'python_order',
388
	'Python Module Order',
389
	$pconfig['python_order'],
390
	[ 'pre_validator' => 'Pre Validator', 'post_validator' => 'Post Validator' ]
391
))->setHelp('Select the Python Module ordering.');
392

    
393
$section->addInput(new Form_Select(
394
	'python_script',
395
	'Python Module Script',
396
	$pconfig['python_script'],
397
	$python_scripts
398
))->setHelp('Select the Python module script to utilize.');
399

    
400
$section->addInput(new Form_Checkbox(
401
	'forwarding',
402
	'DNS Query Forwarding',
403
	'Enable Forwarding Mode',
404
	$pconfig['forwarding']
405
))->setHelp('If this option is set, DNS queries will be forwarded to the upstream DNS servers defined under'.
406
					' %1$sSystem &gt; General Setup%2$s or those obtained via dynamic ' .
407
					'interfaces such as DHCP, PPP, or OpenVPN (if DNS Server Override ' .
408
				        'is enabled there).','<a href="system.php">','</a>');
409

    
410
$section->addInput(new Form_Checkbox(
411
	'forward_tls_upstream',
412
	null,
413
	'Use SSL/TLS for outgoing DNS Queries to Forwarding Servers',
414
	$pconfig['forward_tls_upstream']
415
))->setHelp('When set in conjunction with DNS Query Forwarding, queries to all upstream forwarding DNS servers will be sent using SSL/TLS on the default port of 853. Note that ALL configured forwarding servers MUST support SSL/TLS queries on port 853.');
416

    
417
if (dhcp_is_backend('isc')):
418
$section->addInput(new Form_Checkbox(
419
	'regdhcp',
420
	'DHCP Registration',
421
	'Register DHCP leases in the DNS Resolver',
422
	$pconfig['regdhcp']
423
))->setHelp('If this option is set, then machines that specify their hostname when requesting an IPv4 DHCP lease will be registered'.
424
					' in the DNS Resolver so that their name can be resolved.'.
425
	    				' Note that this will cause the Resolver to reload and flush its resolution cache whenever a DHCP lease is issued.'.
426
					' The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.','<a href="system.php">','</a>');
427

    
428
$section->addInput(new Form_Checkbox(
429
	'regdhcpstatic',
430
	'Static DHCP',
431
	'Register DHCP static mappings in the DNS Resolver',
432
	$pconfig['regdhcpstatic']
433
))->setHelp('If this option is set, then DHCP static mappings will be registered in the DNS Resolver, so that their name can be resolved. '.
434
					'The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.','<a href="system.php">','</a>');
435
endif;
436

    
437
$section->addInput(new Form_Checkbox(
438
	'regovpnclients',
439
	'OpenVPN Clients',
440
	'Register connected OpenVPN clients in the DNS Resolver',
441
	$pconfig['regovpnclients']
442
))->setHelp(sprintf('If this option is set, then the common name (CN) of connected OpenVPN clients will be ' .
443
	    'registered in the DNS Resolver, so that their name can be resolved. This only works for OpenVPN ' .
444
	    'servers (Remote Access SSL/TLS or User Auth with Username as Common Name option) operating ' .
445
	    'in "tun" mode. The domain in %sSystem: General Setup%s should also be set to the proper value.',
446
	    '<a href="system.php">','</a>'));
447

    
448
$btnadv = new Form_Button(
449
	'btnadvcustom',
450
	'Custom options',
451
	null,
452
	'fa-solid fa-cog'
453
);
454

    
455
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
456

    
457
$section->addInput(new Form_StaticText(
458
	'Display Custom Options',
459
	$btnadv
460
));
461

    
462
$section->addInput(new Form_Textarea (
463
	'custom_options',
464
	'Custom options',
465
	$pconfig['custom_options']
466
))->setHelp('Enter any additional configuration parameters to add to the DNS Resolver configuration here, separated by a newline.');
467

    
468
$form->add($section);
469
print($form);
470
?>
471

    
472
<script type="text/javascript">
473
//<![CDATA[
474
events.push(function() {
475

    
476
	// Show advanced custom options ==============================================
477
	var showadvcustom = false;
478

    
479
	function show_advcustom(ispageload) {
480
		var text;
481
		// On page load decide the initial state based on the data.
482
		if (ispageload) {
483
			showadvcustom = <?=($customoptions ? 'true' : 'false');?>;
484
		} else {
485
			// It was a click, swap the state.
486
			showadvcustom = !showadvcustom;
487
		}
488

    
489
		hideInput('custom_options', !showadvcustom);
490

    
491
		if (showadvcustom) {
492
			text = "<?=gettext('Hide Custom Options');?>";
493
		} else {
494
			text = "<?=gettext('Display Custom Options');?>";
495
		}
496
		$('#btnadvcustom').html('<i class="fa-solid fa-cog"></i> ' + text);
497
	}
498

    
499
	// Un-hide additional controls
500
	$('#btnadvcustom').click(function(event) {
501
		show_advcustom();
502
	});
503

    
504
	// On initial load
505
	if ($('#custom_options').val().length == 0) {
506
		hideInput('custom_options', true);
507
	}
508

    
509
	show_advcustom(true);
510

    
511
	// When the Python Module 'enable' is clicked, disable/enable the Python Module options
512
	function show_python_script() {
513
		var python = $('#python').prop('checked');
514
		hideInput('python_order', !python);
515
		hideInput('python_script', !python);
516
	}
517
	show_python_script();
518
	$('#python').click(function () {
519
		show_python_script();
520
	});
521

    
522
});
523
//]]>
524
</script>
525

    
526
<div class="panel panel-default">
527
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
528
	<div class="panel-body table-responsive">
529
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
530
			<thead>
531
				<tr>
532
					<th><?=gettext("Host")?></th>
533
					<th><?=gettext("Parent domain of host")?></th>
534
					<th><?=gettext("IP to return for host")?></th>
535
					<th><?=gettext("Description")?></th>
536
					<th><?=gettext("Actions")?></th>
537
				</tr>
538
			</thead>
539
			<tbody>
540
<?php
541
foreach (config_get_path('unbound/hosts', []) as $idx => $hostent):
542
?>
543
				<tr>
544
					<td>
545
						<?=$hostent['host']?>
546
					</td>
547
					<td>
548
						<?=$hostent['domain']?>
549
					</td>
550
					<td>
551
						<?=$hostent['ip']?>
552
					</td>
553
					<td>
554
						<?=htmlspecialchars($hostent['descr'])?>
555
					</td>
556
					<td>
557
						<a class="fa-solid fa-pencil"	title="<?=gettext('Edit host override')?>" href="services_unbound_host_edit.php?id=<?=$idx?>"></a>
558
						<a class="fa-solid fa-trash-can"	title="<?=gettext('Delete host override')?>" href="services_unbound.php?type=host&amp;act=del&amp;id=<?=$idx?>" usepost></a>
559
					</td>
560
				</tr>
561

    
562
<?php
563
	foreach (array_get_path($hostent, 'aliases/item', []) as $alias):
564
?>
565
				<tr>
566
					<td>
567
						<?=$alias['host']?>
568
					</td>
569
					<td>
570
						<?=$alias['domain']?>
571
					</td>
572
					<td>
573
						<?=gettext("Alias for ");?><?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
574
					</td>
575
					<td>
576
						<i class="fa-solid fa-angle-double-right text-info"></i>
577
						<?=htmlspecialchars($alias['description'])?>
578
					</td>
579
					<td>
580
						<a class="fa-solid fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_unbound_host_edit.php?id=<?=$idx?>"></a>
581
					</td>
582
				</tr>
583
<?php
584
	endforeach;
585
endforeach;
586
?>
587
			</tbody>
588
		</table>
589
	</div>
590
</div>
591

    
592
<span class="help-block">
593
	Enter any individual hosts for which the resolver's standard DNS lookup process should be overridden and a specific
594
	IPv4 or IPv6 address should automatically be returned by the resolver. Standard and also non-standard names and parent domains
595
	can be entered, such as 'test', 'nas.home.arpa', 'mycompany.localdomain', '1.168.192.in-addr.arpa', or 'somesite.com'. Any lookup attempt for
596
	the host will automatically return the given IP address, and the usual lookup server for the domain will not be queried for
597
	the host's records.
598
</span>
599

    
600
<nav class="action-buttons">
601
	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
602
		<i class="fa-solid fa-plus icon-embed-btn"></i>
603
		<?=gettext('Add')?>
604
	</a>
605
</nav>
606

    
607
<div class="panel panel-default">
608
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain Overrides")?></h2></div>
609
	<div class="panel-body table-responsive">
610
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
611
			<thead>
612
				<tr>
613
					<th><?=gettext("Domain")?></th>
614
					<th><?=gettext("Lookup Server IP Address")?></th>
615
					<th><?=gettext("Description")?></th>
616
					<th><?=gettext("Actions")?></th>
617
				</tr>
618
			</thead>
619

    
620
			<tbody>
621
<?php
622
$i = 0;
623
foreach (config_get_path('unbound/domainoverrides') as $doment):
624
?>
625
				<tr>
626
					<td>
627
						<?=$doment['domain']?>&nbsp;
628
					</td>
629
					<td>
630
						<?=$doment['ip']?>&nbsp;
631
					</td>
632
					<td>
633
						<?=htmlspecialchars($doment['descr'])?>&nbsp;
634
					</td>
635
					<td>
636
						<a class="fa-solid fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_unbound_domainoverride_edit.php?id=<?=$i?>"></a>
637
						<a class="fa-solid fa-trash-can"	title="<?=gettext('Delete domain override')?>" href="services_unbound.php?act=del&amp;type=doverride&amp;id=<?=$i?>" usepost></a>
638
					</td>
639
				</tr>
640
<?php
641
	$i++;
642
endforeach;
643
?>
644
			</tbody>
645
		</table>
646
	</div>
647
</div>
648

    
649
<span class="help-block">
650
	Enter any domains for which the resolver's standard DNS lookup process should be overridden and a different (non-standard)
651
	lookup server should be queried instead. Non-standard, 'invalid' and local domains, and subdomains, can also be entered,
652
	such as 'test', 'nas.home.arpa', 'mycompany.localdomain', '1.168.192.in-addr.arpa', or 'somesite.com'. The IP address is treated as the
653
	authoritative lookup server for the domain (including all of its subdomains), and other lookup servers will not be queried.
654
	If there are multiple authoritative DNS servers available for a domain then make a separate entry for each,
655
	using the same domain name.
656
</span>
657

    
658
<nav class="action-buttons">
659
	<a href="services_unbound_domainoverride_edit.php" class="btn btn-sm btn-success">
660
		<i class="fa-solid fa-plus icon-embed-btn"></i>
661
		<?=gettext('Add')?>
662
	</a>
663
</nav>
664

    
665
<div class="infoblock">
666
	<?php print_info_box(sprintf(gettext('If the DNS Resolver is enabled, the DHCP'.
667
		' service (if enabled) will automatically serve the LAN IP'.
668
		' address as a DNS server to DHCP clients so they will use'.
669
		' the DNS Resolver. If Forwarding is enabled, the DNS Resolver will use the DNS servers'.
670
		' entered in %1$sSystem &gt; General Setup%2$s'.
671
		' or those obtained via DHCP or PPP on WAN if &quot;Allow'.
672
		' DNS server list to be overridden by DHCP/PPP on WAN&quot;'.
673
		' is checked.'), '<a href="system.php">', '</a>'), 'info', false); ?>
674
</div>
675

    
676
<?php
677
include("foot.inc");
(141-141/228)