Project

General

Profile

Download (18.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services_unbound.php
4
*/
5
/* ====================================================================
6
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
7
 *	Copyright (c)  2014 Warren Baker (warren@pfsense.org)
8
 *
9
 *	Redistribution and use in source and binary forms, with or without modification,
10
 *	are permitted provided that the following conditions are met:
11
 *
12
 *	1. Redistributions of source code must retain the above copyright notice,
13
 *		this list of conditions and the following disclaimer.
14
 *
15
 *	2. Redistributions in binary form must reproduce the above copyright
16
 *		notice, this list of conditions and the following disclaimer in
17
 *		the documentation and/or other materials provided with the
18
 *		distribution.
19
 *
20
 *	3. All advertising materials mentioning features or use of this software
21
 *		must display the following acknowledgment:
22
 *		"This product includes software developed by the pfSense Project
23
 *		 for use in the pfSense software distribution. (http://www.pfsense.org/).
24
 *
25
 *	4. The names "pfSense" and "pfSense Project" must not be used to
26
 *		 endorse or promote products derived from this software without
27
 *		 prior written permission. For written permission, please contact
28
 *		 coreteam@pfsense.org.
29
 *
30
 *	5. Products derived from this software may not be called "pfSense"
31
 *		nor may "pfSense" appear in their names without prior written
32
 *		permission of the Electric Sheep Fencing, LLC.
33
 *
34
 *	6. Redistributions of any form whatsoever must retain the following
35
 *		acknowledgment:
36
 *
37
 *	"This product includes software developed by the pfSense Project
38
 *	for use in the pfSense software distribution (http://www.pfsense.org/).
39
 *
40
 *	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
 *	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 *	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
 *	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 *	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 *	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 *	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 *	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 *	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
52
 *
53
 *	====================================================================
54
 *
55
 */
56

    
57
##|+PRIV
58
##|*IDENT=page-services-dnsresolver
59
##|*NAME=Services: DNS Resolver
60
##|*DESCR=Allow access to the 'Services: DNS Resolver' page.
61
##|*MATCH=services_unbound.php*
62
##|-PRIV
63

    
64
require_once("guiconfig.inc");
65
require_once("unbound.inc");
66
require_once("system.inc");
67

    
68
if (!is_array($config['unbound'])) {
69
	$config['unbound'] = array();
70
}
71

    
72
$a_unboundcfg =& $config['unbound'];
73

    
74
if (!is_array($a_unboundcfg['hosts'])) {
75
	$a_unboundcfg['hosts'] = array();
76
}
77

    
78
$a_hosts =& $a_unboundcfg['hosts'];
79

    
80
if (!is_array($a_unboundcfg['domainoverrides'])) {
81
	$a_unboundcfg['domainoverrides'] = array();
82
}
83

    
84
$a_domainOverrides = &$a_unboundcfg['domainoverrides'];
85

    
86
if (isset($a_unboundcfg['enable'])) {
87
	$pconfig['enable'] = true;
88
}
89
if (isset($a_unboundcfg['dnssec'])) {
90
	$pconfig['dnssec'] = true;
91
}
92
if (isset($a_unboundcfg['forwarding'])) {
93
	$pconfig['forwarding'] = true;
94
}
95
if (isset($a_unboundcfg['regdhcp'])) {
96
	$pconfig['regdhcp'] = true;
97
}
98
if (isset($a_unboundcfg['regdhcpstatic'])) {
99
	$pconfig['regdhcpstatic'] = true;
100
}
101

    
102
$pconfig['port'] = $a_unboundcfg['port'];
103
$pconfig['custom_options'] = base64_decode($a_unboundcfg['custom_options']);
104

    
105
if (empty($a_unboundcfg['active_interface'])) {
106
	$pconfig['active_interface'] = array();
107
} else {
108
	$pconfig['active_interface'] = explode(",", $a_unboundcfg['active_interface']);
109
}
110

    
111
if (empty($a_unboundcfg['outgoing_interface'])) {
112
	$pconfig['outgoing_interface'] = array();
113
} else {
114
	$pconfig['outgoing_interface'] = explode(",", $a_unboundcfg['outgoing_interface']);
115
}
116

    
117
if (empty($a_unboundcfg['system_domain_local_zone_type'])) {
118
	$pconfig['system_domain_local_zone_type'] = "transparent";
119
} else {
120
	$pconfig['system_domain_local_zone_type'] = $a_unboundcfg['system_domain_local_zone_type'];
121
}
122

    
123
if ($_POST) {
124
	if ($_POST['apply']) {
125
		$retval = services_unbound_configure();
126
		$savemsg = get_std_save_message($retval);
127
		if ($retval == 0) {
128
			clear_subsystem_dirty('unbound');
129
		}
130
		/* Update resolv.conf in case the interface bindings exclude localhost. */
131
		system_resolvconf_generate();
132
		/* Start or restart dhcpleases when it's necessary */
133
		system_dhcpleases_configure();
134
	} else {
135
		$pconfig = $_POST;
136
		unset($input_errors);
137

    
138
		if (isset($pconfig['enable']) && isset($config['dnsmasq']['enable'])) {
139
			if ($pconfig['port'] == $config['dnsmasq']['port']) {
140
				$input_errors[] = gettext("The DNS Forwarder is enabled using this port. Choose a non-conflicting port, or disable the DNS Forwarder.");
141
			}
142
		}
143

    
144
		if (empty($pconfig['active_interface'])) {
145
			$input_errors[] = gettext("One or more Network Interfaces must be selected for binding.");
146
		} else if (!isset($config['system']['dnslocalhost']) && (!in_array("lo0", $pconfig['active_interface']) && !in_array("all", $pconfig['active_interface']))) {
147
			$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.");
148
		}
149

    
150
		if (empty($pconfig['outgoing_interface'])) {
151
			$input_errors[] = gettext("One or more Outgoing Network Interfaces must be selected.");
152
		}
153

    
154
		if (empty($pconfig['system_domain_local_zone_type'])) {
155
			$input_errors[] = gettext("A System Domain Local-Zone Type must be selected.");
156
		}
157

    
158
		if ($pconfig['port'] && !is_port($pconfig['port'])) {
159
			$input_errors[] = gettext("You must specify a valid port number.");
160
		}
161

    
162
		if (is_array($pconfig['active_interface']) && !empty($pconfig['active_interface'])) {
163
			$display_active_interface = $pconfig['active_interface'];
164
			$pconfig['active_interface'] = implode(",", $pconfig['active_interface']);
165
		}
166

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

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

    
175
		if (isset($pconfig['system_domain_local_zone_type']) && !empty($pconfig['system_domain_local_zone_type'])) {
176
			$display_system_domain_local_zone_type = $pconfig['system_domain_local_zone_type'];
177
			$pconfig['system_domain_local_zone_type'] = $pconfig['system_domain_local_zone_type'];
178
		}
179

    
180
		$test_output = array();
181
		if (test_unbound_config($pconfig, $test_output)) {
182
			$input_errors[] = gettext("The generated config file cannot be parsed by unbound. Please correct the following errors:");
183
			$input_errors = array_merge($input_errors, $test_output);
184
		}
185

    
186
		if (!$input_errors) {
187
			$a_unboundcfg['enable'] = isset($pconfig['enable']);
188
			$a_unboundcfg['port'] = $pconfig['port'];
189
			$a_unboundcfg['dnssec'] = isset($pconfig['dnssec']);
190
			$a_unboundcfg['forwarding'] = isset($pconfig['forwarding']);
191
			$a_unboundcfg['regdhcp'] = isset($pconfig['regdhcp']);
192
			$a_unboundcfg['regdhcpstatic'] = isset($pconfig['regdhcpstatic']);
193
			$a_unboundcfg['active_interface'] = $pconfig['active_interface'];
194
			$a_unboundcfg['outgoing_interface'] = $pconfig['outgoing_interface'];
195
			$a_unboundcfg['system_domain_local_zone_type'] = $pconfig['system_domain_local_zone_type'];
196
			$a_unboundcfg['custom_options'] = $pconfig['custom_options'];
197

    
198
			write_config(gettext("DNS Resolver configured."));
199
			mark_subsystem_dirty('unbound');
200
		}
201

    
202
		$pconfig['active_interface'] = $display_active_interface;
203
		$pconfig['outgoing_interface'] = $display_outgoing_interface;
204
		$pconfig['system_domain_local_zone_type'] = $display_system_domain_local_zone_type;
205
		$pconfig['custom_options'] = $display_custom_options;
206
	}
207
}
208

    
209
if ($_GET['act'] == "del") {
210
	if ($_GET['type'] == 'host') {
211
		if ($a_hosts[$_GET['id']]) {
212
			unset($a_hosts[$_GET['id']]);
213
			write_config();
214
			mark_subsystem_dirty('unbound');
215
			header("Location: services_unbound.php");
216
			exit;
217
		}
218
	} elseif ($_GET['type'] == 'doverride') {
219
		if ($a_domainOverrides[$_GET['id']]) {
220
			unset($a_domainOverrides[$_GET['id']]);
221
			write_config();
222
			mark_subsystem_dirty('unbound');
223
			header("Location: services_unbound.php");
224
			exit;
225
		}
226
	}
227
}
228

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

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

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

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

    
246
	unset($interface_addresses);
247

    
248
	return($iflist);
249
}
250

    
251
$pgtitle = array(gettext("Services"), gettext("DNS Resolver"), gettext("General"));
252
$shortcut_section = "resolver";
253

    
254
include_once("head.inc");
255

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

    
260
if ($savemsg) {
261
	print_info_box($savemsg, 'success');
262
}
263

    
264
if (is_subsystem_dirty('unbound')) {
265
	print_apply_box(gettext("The DNS Resolver configuration has been changed.") . "<br />" . gettext("You must apply the changes in order for them to take effect."));
266
}
267

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

    
274
$form = new Form();
275

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

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

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

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

    
295
$section->addInput(new Form_Select(
296
	'active_interface',
297
	'Network Interfaces',
298
	$activeiflist['selected'],
299
	$activeiflist['options'],
300
	true
301
))->addClass('general')->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. ' .
302
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
303

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

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

    
314
$unbound_local_zone_types = array("deny" => gettext("Deny"), "refuse" => gettext("Refuse"), "static" => gettext("Static"), "transparent" => gettext("Transparent"), "typetransparent" => gettext("Type Transparent"), "redirect" => gettext("Redirect"), "inform" => gettext("Inform"), "inform_deny" => gettext("Inform Deny"), "nodefault" => gettext("No Default"));
315

    
316
$section->addInput(new Form_Select(
317
	'system_domain_local_zone_type',
318
	'System Domain Local Zone Type',
319
	$pconfig['system_domain_local_zone_type'],
320
	$unbound_local_zone_types
321
))->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.');
322

    
323
$section->addInput(new Form_Checkbox(
324
	'dnssec',
325
	'DNSSEC',
326
	'Enable DNSSEC Support',
327
	$pconfig['dnssec']
328
));
329

    
330
$section->addInput(new Form_Checkbox(
331
	'forwarding',
332
	'DNS Query Forwarding',
333
	'Enable Forwarding Mode',
334
	$pconfig['forwarding']
335
));
336

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

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

    
355
$btnadvdns = new Form_Button(
356
	'btnadvdns',
357
	'Custom options'
358
);
359

    
360
$btnadvdns->removeClass('btn-primary')->addClass('btn-default btn-sm');
361

    
362
$section->addInput(new Form_StaticText(
363
	'Custom options',
364
	$btnadvdns . '&nbsp;' . 'Show custom options'
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
	// If the enable checkbox is not checked, hide all inputs
382
	function hideGeneral() {
383
		var hide = ! $('#enable').prop('checked');
384

    
385
		hideMultiClass('general', hide);
386
		hideInput('port', hide);
387
		hideSelect('system_domain_local_zone_type', hide);
388
		hideCheckbox('dnssec', hide);
389
		hideCheckbox('forwarding', hide);
390
		hideCheckbox('regdhcp', hide);
391
		hideCheckbox('regdhcpstatic', hide);
392
		hideInput('btnadvdns', hide);
393
	}
394

    
395
	// Make the 'additional options' button a plain button, not a submit button
396
	$("#btnadvdns").prop('type','button');
397

    
398
	// Un-hide additional  controls
399
	$("#btnadvdns").click(function() {
400
		hideInput('custom_options', false);
401
	});
402

    
403
	// When 'enable' is clicked, disable/enable the following hide inputs
404
	$('#enable').click(function() {
405
		hideGeneral();
406
	});
407

    
408
	// On initial load
409
	if ($('#custom_options').val().length == 0) {
410
		hideInput('custom_options', true);
411
	}
412

    
413
	hideGeneral();
414

    
415
});
416
//]]>
417
</script>
418

    
419
<div class="panel panel-default">
420
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
421
	<div class="panel-body table-responsive">
422
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
423
			<thead>
424
				<tr>
425
					<th><?=gettext("Host")?></th>
426
					<th><?=gettext("Domain")?></th>
427
					<th><?=gettext("IP")?></th>
428
					<th><?=gettext("Description")?></th>
429
					<th></th>
430
				</tr>
431
			</thead>
432
			<tbody>
433
<?php
434
$i = 0;
435
foreach ($a_hosts as $hostent):
436
?>
437
				<tr>
438
					<td>
439
						<?=$hostent['host']?>
440
					</td>
441
					<td>
442
						<?=$hostent['domain']?>
443
					</td>
444
					<td>
445
						<?=$hostent['ip']?>
446
					</td>
447
					<td>
448
						<?=htmlspecialchars($hostent['descr'])?>
449
					</td>
450
					<td>
451
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" href="services_unbound_host_edit.php?id=<?=$i?>"></a>
452
						<a class="fa fa-trash"	title="<?=gettext('Delete host override')?>" href="services_unbound.php?type=host&amp;act=del&amp;id=<?=$i?>"></a>
453
					</td>
454
				</tr>
455

    
456
<?php
457
	if ($hostent['aliases']['item'] && is_array($hostent['aliases']['item'])):
458
		foreach ($hostent['aliases']['item'] as $alias):
459
?>
460
				<tr>
461
					<td>
462
						<?=$alias['host']?>
463
					</td>
464
					<td>
465
						<?=$alias['domain']?>
466
					</td>
467
					<td>
468
						<?=gettext("Alias for ");?><?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
469
					</td>
470
					<td>
471
						<i class="fa fa-angle-double-right text-info"></i>
472
						<?=htmlspecialchars($alias['description'])?>
473
					</td>
474
					<td>
475
						<a a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_unbound_host_edit.php?id=<?=$i?>"></a>
476
					</td>
477
				</tr>
478
<?php
479
		endforeach;
480
	endif;
481
	$i++;
482
endforeach;
483
?>
484
			</tbody>
485
		</table>
486
	</div>
487
</div>
488

    
489
<nav class="action-buttons">
490
	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
491
		<i class="fa fa-plus icon-embed-btn"></i>
492
		<?=gettext('Add')?>
493
	</a>
494
</nav>
495

    
496
<div class="panel panel-default">
497
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain Overrides")?></h2></div>
498
	<div class="panel-body table-responsive">
499
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
500
			<thead>
501
				<tr>
502
					<th><?=gettext("Domain")?></th>
503
					<th><?=gettext("IP")?></th>
504
					<th><?=gettext("Description")?></th>
505
					<th></th>
506
				</tr>
507
			</thead>
508

    
509
			<tbody>
510
<?php
511
$i = 0;
512
foreach ($a_domainOverrides as $doment):
513
?>
514
				<tr>
515
					<td>
516
						<?=$doment['domain']?>&nbsp;
517
					</td>
518
					<td>
519
						<?=$doment['ip']?>&nbsp;
520
					</td>
521
					<td>
522
						<?=htmlspecialchars($doment['descr'])?>&nbsp;
523
					</td>
524
					<td>
525
						<a class="fa fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_unbound_domainoverride_edit.php?id=<?=$i?>"></a>
526
						<a class="fa fa-trash"	title="<?=gettext('Delete domain override')?>" href="services_unbound.php?act=del&amp;type=doverride&amp;id=<?=$i?>"></a>
527
					</td>
528
				</tr>
529
<?php
530
	$i++;
531
endforeach;
532
?>
533
			</tbody>
534
		</table>
535
	</div>
536
</div>
537

    
538
<nav class="action-buttons">
539
	<a href="services_unbound_domainoverride_edit.php" class="btn btn-sm btn-success">
540
		<i class="fa fa-plus icon-embed-btn"></i>
541
		<?=gettext('Add')?>
542
	</a>
543
</nav>
544

    
545
<div class="infoblock">
546
	<?=print_info_box(sprintf(gettext("If the DNS Resolver is enabled, the DHCP".
547
		" service (if enabled) will automatically serve the LAN IP".
548
		" address as a DNS server to DHCP clients so they will use".
549
		" the DNS Resolver. If Forwarding is enabled, the DNS Resolver will use the DNS servers".
550
		" entered in %sSystem: General setup%s".
551
		" or those obtained via DHCP or PPP on WAN if &quot;Allow".
552
		" DNS server list to be overridden by DHCP/PPP on WAN&quot;".
553
		" is checked."), '<a href="system.php">', '</a>'), 'info', false)?>
554
</div>
555

    
556
<?php include("foot.inc");
(140-140/229)