Project

General

Profile

Download (19.1 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-2016 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2014 Warren Baker (warren@pfsense.org)
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

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

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

    
35
if (!is_array($config['unbound'])) {
36
	$config['unbound'] = array();
37
}
38

    
39
$a_unboundcfg =& $config['unbound'];
40

    
41
if (!is_array($a_unboundcfg['hosts'])) {
42
	$a_unboundcfg['hosts'] = array();
43
}
44

    
45
$a_hosts =& $a_unboundcfg['hosts'];
46

    
47
if (!is_array($a_unboundcfg['domainoverrides'])) {
48
	$a_unboundcfg['domainoverrides'] = array();
49
}
50

    
51
$a_domainOverrides = &$a_unboundcfg['domainoverrides'];
52

    
53
if (isset($a_unboundcfg['enable'])) {
54
	$pconfig['enable'] = true;
55
}
56
if (isset($a_unboundcfg['dnssec'])) {
57
	$pconfig['dnssec'] = true;
58
}
59
if (isset($a_unboundcfg['forwarding'])) {
60
	$pconfig['forwarding'] = true;
61
}
62
if (isset($a_unboundcfg['regdhcp'])) {
63
	$pconfig['regdhcp'] = true;
64
}
65
if (isset($a_unboundcfg['regdhcpstatic'])) {
66
	$pconfig['regdhcpstatic'] = true;
67
}
68

    
69
$pconfig['port'] = $a_unboundcfg['port'];
70
$pconfig['custom_options'] = base64_decode($a_unboundcfg['custom_options']);
71

    
72
if (empty($a_unboundcfg['active_interface'])) {
73
	$pconfig['active_interface'] = array();
74
} else {
75
	$pconfig['active_interface'] = explode(",", $a_unboundcfg['active_interface']);
76
}
77

    
78
if (empty($a_unboundcfg['outgoing_interface'])) {
79
	$pconfig['outgoing_interface'] = array();
80
} else {
81
	$pconfig['outgoing_interface'] = explode(",", $a_unboundcfg['outgoing_interface']);
82
}
83

    
84
if (empty($a_unboundcfg['system_domain_local_zone_type'])) {
85
	$pconfig['system_domain_local_zone_type'] = "transparent";
86
} else {
87
	$pconfig['system_domain_local_zone_type'] = $a_unboundcfg['system_domain_local_zone_type'];
88
}
89

    
90

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

    
103
if ($_POST['save']) {
104
	$pconfig = $_POST;
105
	unset($input_errors);
106

    
107
	if (isset($pconfig['enable']) && isset($config['dnsmasq']['enable'])) {
108
		if ($pconfig['port'] == $config['dnsmasq']['port']) {
109
			$input_errors[] = gettext("The DNS Forwarder is enabled using this port. Choose a non-conflicting port, or disable the DNS Forwarder.");
110
		}
111
	}
112

    
113
	// forwarding mode requires having valid DNS servers
114
	if (isset($pconfig['forwarding'])) {
115
		$founddns = false;
116
		if (isset($config['system']['dnsallowoverride'])) {
117
			$dns_servers = get_dns_servers();
118
			if (is_array($dns_servers)) {
119
				foreach ($dns_servers as $dns_server) {
120
					if (!ip_in_subnet($dns_server, "127.0.0.0/8")) {
121
						$founddns = true;
122
					}
123
				}
124
			}
125
		}
126
		if (is_array($config['system']['dnsserver'])) {
127
			foreach ($config['system']['dnsserver'] as $dnsserver) {
128
				if (is_ipaddr($dnsserver)) {
129
					$founddns = true;
130
				}
131
			}
132
		}
133
		if ($founddns == false) {
134
			$input_errors[] = gettext("At least one DNS server must be specified under System &gt; General Setup to enable Forwarding mode.");
135
		}
136
	}
137

    
138
	if (empty($pconfig['active_interface'])) {
139
		$input_errors[] = gettext("One or more Network Interfaces must be selected for binding.");
140
	} else if (!isset($config['system']['dnslocalhost']) && (!in_array("lo0", $pconfig['active_interface']) && !in_array("all", $pconfig['active_interface']))) {
141
		$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.");
142
	}
143

    
144
	if (empty($pconfig['outgoing_interface'])) {
145
		$input_errors[] = gettext("One or more Outgoing Network Interfaces must be selected.");
146
	}
147

    
148
	if ($pconfig['port'] && !is_port($pconfig['port'])) {
149
		$input_errors[] = gettext("A valid port number must be specified.");
150
	}
151

    
152
	if (is_array($pconfig['active_interface']) && !empty($pconfig['active_interface'])) {
153
		$display_active_interface = $pconfig['active_interface'];
154
		$pconfig['active_interface'] = implode(",", $pconfig['active_interface']);
155
	}
156

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

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

    
165
	$display_custom_options = $pconfig['custom_options'];
166
	$pconfig['custom_options'] = base64_encode(str_replace("\r\n", "\n", $pconfig['custom_options']));
167

    
168
	if (is_array($pconfig['outgoing_interface']) && !empty($pconfig['outgoing_interface'])) {
169
		$display_outgoing_interface = $pconfig['outgoing_interface'];
170
		$pconfig['outgoing_interface'] = implode(",", $pconfig['outgoing_interface']);
171
	}
172

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

    
179
	if (!$input_errors) {
180
		$a_unboundcfg['enable'] = isset($pconfig['enable']);
181
		$a_unboundcfg['port'] = $pconfig['port'];
182
		$a_unboundcfg['dnssec'] = isset($pconfig['dnssec']);
183
		$a_unboundcfg['forwarding'] = isset($pconfig['forwarding']);
184
		$a_unboundcfg['regdhcp'] = isset($pconfig['regdhcp']);
185
		$a_unboundcfg['regdhcpstatic'] = isset($pconfig['regdhcpstatic']);
186
		$a_unboundcfg['active_interface'] = $pconfig['active_interface'];
187
		$a_unboundcfg['outgoing_interface'] = $pconfig['outgoing_interface'];
188
		$a_unboundcfg['system_domain_local_zone_type'] = $pconfig['system_domain_local_zone_type'];
189
		$a_unboundcfg['custom_options'] = $pconfig['custom_options'];
190

    
191
		write_config(gettext("DNS Resolver configured."));
192
		mark_subsystem_dirty('unbound');
193
	}
194

    
195
	$pconfig['active_interface'] = $display_active_interface;
196
	$pconfig['outgoing_interface'] = $display_outgoing_interface;
197
	$pconfig['custom_options'] = $display_custom_options;
198
}
199

    
200

    
201
if ($pconfig['custom_options']) {
202
	$customoptions = true;
203
} else {
204
	$customoptions = false;
205
}
206

    
207
if ($_POST['act'] == "del") {
208
	if ($_POST['type'] == 'host') {
209
		if ($a_hosts[$_POST['id']]) {
210
			unset($a_hosts[$_POST['id']]);
211
			write_config(gettext("Host override deleted from DNS Resolver."));
212
			mark_subsystem_dirty('unbound');
213
			header("Location: services_unbound.php");
214
			exit;
215
		}
216
	} elseif ($_POST['type'] == 'doverride') {
217
		if ($a_domainOverrides[$_POST['id']]) {
218
			unset($a_domainOverrides[$_POST['id']]);
219
			write_config(gettext("Domain override deleted from DNS Resolver."));
220
			mark_subsystem_dirty('unbound');
221
			header("Location: services_unbound.php");
222
			exit;
223
		}
224
	}
225
}
226

    
227
function build_if_list($selectedifs) {
228
	$interface_addresses = get_possible_listen_ips(true);
229
	$iflist = array('options' => array(), 'selected' => array());
230

    
231
	$iflist['options']['all']	= gettext("All");
232
	if (empty($selectedifs) || empty($selectedifs[0]) || in_array("all", $selectedifs)) {
233
		array_push($iflist['selected'], "all");
234
	}
235

    
236
	foreach ($interface_addresses as $laddr => $ldescr) {
237
		$iflist['options'][$laddr] = htmlspecialchars($ldescr);
238

    
239
		if ($selectedifs && in_array($laddr, $selectedifs)) {
240
			array_push($iflist['selected'], $laddr);
241
		}
242
	}
243

    
244
	unset($interface_addresses);
245

    
246
	return($iflist);
247
}
248

    
249
$pgtitle = array(gettext("Services"), gettext("DNS Resolver"), gettext("General Settings"));
250
$pglinks = array("", "@self", "@self");
251
$shortcut_section = "resolver";
252

    
253
include_once("head.inc");
254

    
255
if ($input_errors) {
256
	print_input_errors($input_errors);
257
}
258

    
259
if ($_POST['apply']) {
260
	print_apply_result_box($retval);
261
}
262

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

    
267
$tab_array = array();
268
$tab_array[] = array(gettext("General Settings"), true, "services_unbound.php");
269
$tab_array[] = array(gettext("Advanced Settings"), false, "services_unbound_advanced.php");
270
$tab_array[] = array(gettext("Access Lists"), false, "/services_unbound_acls.php");
271
display_top_tabs($tab_array, true);
272

    
273
$form = new Form();
274

    
275
$section = new Form_Section('General DNS Resolver Options');
276

    
277
$section->addInput(new Form_Checkbox(
278
	'enable',
279
	'Enable',
280
	'Enable DNS resolver',
281
	$pconfig['enable']
282
));
283

    
284
$section->addInput(new Form_Input(
285
	'port',
286
	'Listen Port',
287
	'number',
288
	$pconfig['port'],
289
	['placeholder' => '53']
290
))->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.');
291

    
292
$activeiflist = build_if_list($pconfig['active_interface']);
293

    
294
$section->addInput(new Form_Select(
295
	'active_interface',
296
	'*Network Interfaces',
297
	$activeiflist['selected'],
298
	$activeiflist['options'],
299
	true
300
))->addClass('general', 'resizable')->setHelp('Interface IPs used by the DNS Resolver for responding to queries from clients. If an interface has both IPv4 and IPv6 IPs, both are used. Queries to other interface IPs not selected below are discarded. ' .
301
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
302

    
303
$outiflist = build_if_list($pconfig['outgoing_interface']);
304

    
305
$section->addInput(new Form_Select(
306
	'outgoing_interface',
307
	'*Outgoing Network Interfaces',
308
	$outiflist['selected'],
309
	$outiflist['options'],
310
	true
311
))->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.');
312

    
313
$section->addInput(new Form_Select(
314
	'system_domain_local_zone_type',
315
	'*System Domain Local Zone Type',
316
	$pconfig['system_domain_local_zone_type'],
317
	unbound_local_zone_types()
318
))->setHelp('The local-zone type used for the pfSense system domain (System | General Setup | Domain).  Transparent is the default.  Local-Zone type descriptions are available in the unbound.conf(5) manual pages.');
319

    
320
$section->addInput(new Form_Checkbox(
321
	'dnssec',
322
	'DNSSEC',
323
	'Enable DNSSEC Support',
324
	$pconfig['dnssec']
325
));
326

    
327
$section->addInput(new Form_Checkbox(
328
	'forwarding',
329
	'DNS Query Forwarding',
330
	'Enable Forwarding Mode',
331
	$pconfig['forwarding']
332
))->setHelp('If this option is set, DNS queries will be forwarded to the upstream DNS servers defined under'.
333
					' %1$sSystem &gt; General Setup%2$s or those obtained via DHCP/PPP on WAN'.
334
					' (if DNS Server Override is enabled there).','<a href="system.php">','</a>');
335

    
336
$section->addInput(new Form_Checkbox(
337
	'regdhcp',
338
	'DHCP Registration',
339
	'Register DHCP leases in the DNS Resolver',
340
	$pconfig['regdhcp']
341
))->setHelp('If this option is set, then machines that specify their hostname when requesting a DHCP lease will be registered'.
342
					' in the DNS Resolver, so that their name can be resolved.'.
343
					' The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.','<a href="system.php">','</a>');
344

    
345
$section->addInput(new Form_Checkbox(
346
	'regdhcpstatic',
347
	'Static DHCP',
348
	'Register DHCP static mappings in the DNS Resolver',
349
	$pconfig['regdhcpstatic']
350
))->setHelp('If this option is set, then DHCP static mappings will be registered in the DNS Resolver, so that their name can be resolved. '.
351
					'The domain in %1$sSystem &gt; General Setup%2$s should also be set to the proper value.','<a href="system.php">','</a>');
352

    
353
$btnadv = new Form_Button(
354
	'btnadvcustom',
355
	'Custom options',
356
	null,
357
	'fa-cog'
358
);
359

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

    
362
$section->addInput(new Form_StaticText(
363
	'Display Custom Options',
364
	$btnadv
365
));
366

    
367
$section->addInput(new Form_Textarea (
368
	'custom_options',
369
	'Custom options',
370
	$pconfig['custom_options']
371
))->setHelp('Enter any additional configuration parameters to add to the DNS Resolver configuration here, separated by a newline.');
372

    
373
$form->add($section);
374
print($form);
375
?>
376

    
377
<script type="text/javascript">
378
//<![CDATA[
379
events.push(function() {
380

    
381
	// Show advanced custom options ==============================================
382
	var showadvcustom = false;
383

    
384
	function show_advcustom(ispageload) {
385
		var text;
386
		// On page load decide the initial state based on the data.
387
		if (ispageload) {
388
			showadvcustom = <?=($customoptions ? 'true' : 'false');?>;
389
		} else {
390
			// It was a click, swap the state.
391
			showadvcustom = !showadvcustom;
392
		}
393

    
394
		hideInput('custom_options', !showadvcustom);
395

    
396
		if (showadvcustom) {
397
			text = "<?=gettext('Hide Custom Options');?>";
398
		} else {
399
			text = "<?=gettext('Display Custom Options');?>";
400
		}
401
		$('#btnadvcustom').html('<i class="fa fa-cog"></i> ' + text);
402
	}
403

    
404
	// If the enable checkbox is not checked, hide all inputs
405
	function hideGeneral() {
406
		var hide = ! $('#enable').prop('checked');
407

    
408
		hideMultiClass('general', hide);
409
		hideInput('port', hide);
410
		hideSelect('system_domain_local_zone_type', hide);
411
		hideCheckbox('dnssec', hide);
412
		hideCheckbox('forwarding', hide);
413
		hideCheckbox('regdhcp', hide);
414
		hideCheckbox('regdhcpstatic', hide);
415
		hideInput('btnadvcustom', hide);
416
		hideInput('custom_options', hide || !showadvcustom);
417
	}
418

    
419
	// Un-hide additional controls
420
	$('#btnadvcustom').click(function(event) {
421
		show_advcustom();
422
	});
423

    
424
	// When 'enable' is clicked, disable/enable the following hide inputs
425
	$('#enable').click(function() {
426
		hideGeneral();
427
	});
428

    
429
	// On initial load
430
	if ($('#custom_options').val().length == 0) {
431
		hideInput('custom_options', true);
432
	}
433

    
434
	hideGeneral();
435
	show_advcustom(true);
436

    
437
});
438
//]]>
439
</script>
440

    
441
<div class="panel panel-default">
442
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
443
	<div class="panel-body table-responsive">
444
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
445
			<thead>
446
				<tr>
447
					<th><?=gettext("Host")?></th>
448
					<th><?=gettext("Parent domain of host")?></th>
449
					<th><?=gettext("IP to return for host")?></th>
450
					<th><?=gettext("Description")?></th>
451
					<th><?=gettext("Actions")?></th>
452
				</tr>
453
			</thead>
454
			<tbody>
455
<?php
456
$i = 0;
457
foreach ($a_hosts as $hostent):
458
?>
459
				<tr>
460
					<td>
461
						<?=$hostent['host']?>
462
					</td>
463
					<td>
464
						<?=$hostent['domain']?>
465
					</td>
466
					<td>
467
						<?=$hostent['ip']?>
468
					</td>
469
					<td>
470
						<?=htmlspecialchars($hostent['descr'])?>
471
					</td>
472
					<td>
473
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" href="services_unbound_host_edit.php?id=<?=$i?>"></a>
474
						<a class="fa fa-trash"	title="<?=gettext('Delete host override')?>" href="services_unbound.php?type=host&amp;act=del&amp;id=<?=$i?>" usepost></a>
475
					</td>
476
				</tr>
477

    
478
<?php
479
	if ($hostent['aliases']['item'] && is_array($hostent['aliases']['item'])):
480
		foreach ($hostent['aliases']['item'] as $alias):
481
?>
482
				<tr>
483
					<td>
484
						<?=$alias['host']?>
485
					</td>
486
					<td>
487
						<?=$alias['domain']?>
488
					</td>
489
					<td>
490
						<?=gettext("Alias for ");?><?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
491
					</td>
492
					<td>
493
						<i class="fa fa-angle-double-right text-info"></i>
494
						<?=htmlspecialchars($alias['description'])?>
495
					</td>
496
					<td>
497
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_unbound_host_edit.php?id=<?=$i?>"></a>
498
					</td>
499
				</tr>
500
<?php
501
		endforeach;
502
	endif;
503
	$i++;
504
endforeach;
505
?>
506
			</tbody>
507
		</table>
508
	</div>
509
</div>
510

    
511
<span class="help-block">
512
	Enter any individual hosts for which the resolver's standard DNS lookup process should be overridden and a specific
513
	IPv4 or IPv6 address should automatically be returned by the resolver. Standard and also non-standard names and parent domains 
514
	can be entered, such as 'test', 'mycompany.localdomain', '1.168.192.in-addr.arpa', or 'somesite.com'. Any lookup attempt for 
515
	the host will automatically return the given IP address, and the usual lookup server for the domain will not be queried for 
516
	the host's records.
517
</span>
518

    
519
<nav class="action-buttons">
520
	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
521
		<i class="fa fa-plus icon-embed-btn"></i>
522
		<?=gettext('Add')?>
523
	</a>
524
</nav>
525

    
526
<div class="panel panel-default">
527
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain 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("Domain")?></th>
533
					<th><?=gettext("Lookup Server IP Address")?></th>
534
					<th><?=gettext("Description")?></th>
535
					<th><?=gettext("Actions")?></th>
536
				</tr>
537
			</thead>
538

    
539
			<tbody>
540
<?php
541
$i = 0;
542
foreach ($a_domainOverrides as $doment):
543
?>
544
				<tr>
545
					<td>
546
						<?=$doment['domain']?>&nbsp;
547
					</td>
548
					<td>
549
						<?=$doment['ip']?>&nbsp;
550
					</td>
551
					<td>
552
						<?=htmlspecialchars($doment['descr'])?>&nbsp;
553
					</td>
554
					<td>
555
						<a class="fa fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_unbound_domainoverride_edit.php?id=<?=$i?>"></a>
556
						<a class="fa fa-trash"	title="<?=gettext('Delete domain override')?>" href="services_unbound.php?act=del&amp;type=doverride&amp;id=<?=$i?>" usepost></a>
557
					</td>
558
				</tr>
559
<?php
560
	$i++;
561
endforeach;
562
?>
563
			</tbody>
564
		</table>
565
	</div>
566
</div>
567

    
568
<span class="help-block">
569
	Enter any domains for which the resolver's standard DNS lookup process should be overridden and a different (non-standard) 
570
	lookup server should be queried instead. Non-standard, 'invalid' and local domains, and subdomains, can also be entered, 
571
	such as 'test', 'mycompany.localdomain', '1.168.192.in-addr.arpa', or 'somesite.com'. The IP address is treated as the 
572
	authoritative lookup server for the domain (including all of its subdomains), and other lookup servers will not be queried.
573
</span>
574

    
575
<nav class="action-buttons">
576
	<a href="services_unbound_domainoverride_edit.php" class="btn btn-sm btn-success">
577
		<i class="fa fa-plus icon-embed-btn"></i>
578
		<?=gettext('Add')?>
579
	</a>
580
</nav>
581

    
582
<div class="infoblock">
583
	<?php print_info_box(sprintf(gettext('If the DNS Resolver is enabled, the DHCP'.
584
		' service (if enabled) will automatically serve the LAN IP'.
585
		' address as a DNS server to DHCP clients so they will use'.
586
		' the DNS Resolver. If Forwarding is enabled, the DNS Resolver will use the DNS servers'.
587
		' entered in %1$sSystem &gt; General Setup%2$s'.
588
		' or those obtained via DHCP or PPP on WAN if &quot;Allow'.
589
		' DNS server list to be overridden by DHCP/PPP on WAN&quot;'.
590
		' is checked.'), '<a href="system.php">', '</a>'), 'info', false); ?>
591
</div>
592

    
593
<?php include("foot.inc");
(139-139/224)