Project

General

Profile

Download (17 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
	pfSense_MODULE: dnsresolver
58
*/
59

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

    
67
require_once("guiconfig.inc");
68
require_once("unbound.inc");
69
require_once("system.inc");
70

    
71
if (!is_array($config['unbound'])) {
72
	$config['unbound'] = array();
73
}
74

    
75
$a_unboundcfg =& $config['unbound'];
76

    
77
if (!is_array($a_unboundcfg['hosts'])) {
78
	$a_unboundcfg['hosts'] = array();
79
}
80

    
81
$a_hosts =& $a_unboundcfg['hosts'];
82

    
83
if (!is_array($a_unboundcfg['domainoverrides'])) {
84
	$a_unboundcfg['domainoverrides'] = array();
85
}
86

    
87
$a_domainOverrides = &$a_unboundcfg['domainoverrides'];
88

    
89
if (isset($a_unboundcfg['enable'])) {
90
	$pconfig['enable'] = true;
91
}
92
if (isset($a_unboundcfg['dnssec'])) {
93
	$pconfig['dnssec'] = true;
94
}
95
if (isset($a_unboundcfg['forwarding'])) {
96
	$pconfig['forwarding'] = true;
97
}
98
if (isset($a_unboundcfg['regdhcp'])) {
99
	$pconfig['regdhcp'] = true;
100
}
101
if (isset($a_unboundcfg['regdhcpstatic'])) {
102
	$pconfig['regdhcpstatic'] = true;
103
}
104
if (isset($a_unboundcfg['txtsupport'])) {
105
	$pconfig['txtsupport'] = true;
106
}
107

    
108
$pconfig['port'] = $a_unboundcfg['port'];
109
$pconfig['custom_options'] = base64_decode($a_unboundcfg['custom_options']);
110

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

    
117
if (empty($a_unboundcfg['outgoing_interface'])) {
118
	$pconfig['outgoing_interface'] = array();
119
} else {
120
	$pconfig['outgoing_interface'] = explode(",", $a_unboundcfg['outgoing_interface']);
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[] = "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[] = "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[] = "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[] = "One or more Outgoing Network Interfaces must be selected.";
152
		}
153

    
154
		if ($pconfig['port'] && !is_port($pconfig['port'])) {
155
			$input_errors[] = gettext("You must specify a valid port number.");
156
		}
157

    
158
		if (is_array($pconfig['active_interface']) && !empty($pconfig['active_interface'])) {
159
			$display_active_interface = $pconfig['active_interface'];
160
			$pconfig['active_interface'] = implode(",", $pconfig['active_interface']);
161
		}
162

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

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

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

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

    
188
			write_config("DNS Resolver configured.");
189
			mark_subsystem_dirty('unbound');
190
		}
191

    
192
		$pconfig['active_interface'] = $display_active_interface;
193
		$pconfig['outgoing_interface'] = $display_outgoing_interface;
194
		$pconfig['custom_options'] = $display_custom_options;
195
	}
196
}
197

    
198
if ($_GET['act'] == "del") {
199
	if ($_GET['type'] == 'host') {
200
		if ($a_hosts[$_GET['id']]) {
201
			unset($a_hosts[$_GET['id']]);
202
			write_config();
203
			mark_subsystem_dirty('unbound');
204
			header("Location: services_unbound.php");
205
			exit;
206
		}
207
	} elseif ($_GET['type'] == 'doverride') {
208
		if ($a_domainOverrides[$_GET['id']]) {
209
			unset($a_domainOverrides[$_GET['id']]);
210
			write_config();
211
			mark_subsystem_dirty('unbound');
212
			header("Location: services_unbound.php");
213
			exit;
214
		}
215
	}
216
}
217

    
218
function build_if_list($selectedifs) {
219
	$interface_addresses = get_possible_listen_ips(true);
220
	$iflist = array('options' => array(), 'selected' => array());
221

    
222
	$iflist['options']['all']	= "All";
223
	if (empty($selectedifs) || empty($selectedifs[0]) || in_array("all", $selectedifs)) {
224
		array_push($iflist['selected'], "all");
225
	}
226

    
227
	foreach ($interface_addresses as $laddr => $ldescr) {
228
		$iflist['options'][$laddr] = htmlspecialchars($ldescr);
229

    
230
		if ($selectedifs && in_array($laddr, $selectedifs))
231
			array_push($iflist['selected'], $laddr);
232
	}
233

    
234
	unset($interface_addresses);
235

    
236
	return($iflist);
237
}
238

    
239
$closehead = false;
240
$pgtitle = array(gettext("Services"), gettext("DNS Resolver"));
241
$shortcut_section = "resolver";
242

    
243
include_once("head.inc");
244

    
245
if ($input_errors)
246
	print_input_errors($input_errors);
247

    
248
if ($savemsg)
249
	print_info_box($savemsg, 'success');
250

    
251
if (is_subsystem_dirty('unbound')) {
252
	print_info_box_np(gettext("The configuration of the DNS Resolver has been changed. You must apply changes for them to take effect."));
253
}
254

    
255
$tab_array = array();
256
$tab_array[] = array(gettext("General settings"), true, "services_unbound.php");
257
$tab_array[] = array(gettext("Advanced settings"), false, "services_unbound_advanced.php");
258
$tab_array[] = array(gettext("Access Lists"), false, "/services_unbound_acls.php");
259
display_top_tabs($tab_array, true);
260

    
261
$form = new Form();
262

    
263
$section = new Form_Section('General DNS Resolver Options');
264

    
265
$section->addInput(new Form_Checkbox(
266
	'enable',
267
	'Enable',
268
	'Enable DNS resolver',
269
	$pconfig['enable']
270
));
271

    
272
$section->addInput(new Form_Input(
273
	'port',
274
	'Listen Port',
275
	'text',
276
	$pconfig['port']
277
))->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.');
278

    
279
$activeiflist = build_if_list($pconfig['active_interface']);
280

    
281
$section->addInput(new Form_Select(
282
	'active_interface',
283
	'Network Interfaces',
284
	$activeiflist['selected'],
285
	$activeiflist['options'],
286
	true
287
))->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. ' .
288
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
289

    
290
$outiflist = build_if_list($pconfig['outgoing_interface']);
291

    
292
$section->addInput(new Form_Select(
293
	'outgoing_interface',
294
	'Outgoing Network Interfaces',
295
	$outiflist['selected'],
296
	$outiflist['options'],
297
	true
298
))->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.');
299

    
300
$section->addInput(new Form_Checkbox(
301
	'dnssec',
302
	'DNSSEC',
303
	'Enable DNSSEC Support',
304
	$pconfig['dnssec']
305
));
306

    
307
$section->addInput(new Form_Checkbox(
308
	'forwarding',
309
	'DNS Query Forwarding',
310
	'Enable Forwarding Mode',
311
	$pconfig['forwarding']
312
));
313

    
314
$section->addInput(new Form_Checkbox(
315
	'regdhcp',
316
	'DHCP Registration',
317
	'Register DHCP leases in the DNS Resolver',
318
	$pconfig['regdhcp']
319
))->setHelp(sprintf('If this option is set, then machines that specify their hostname when requesting a DHCP lease will be registered'.
320
					' in the DNS Resolver, so that their name can be resolved.'.
321
					' You should also set the domain in %sSystem: General setup%s to the proper value.','<a href="system.php">','</a>'));
322

    
323
$section->addInput(new Form_Checkbox(
324
	'regdhcpstatic',
325
	'Static DHCP',
326
	'Register DHCP static mappings in the DNS Resolver',
327
	$pconfig['regdhcpstatic']
328
))->setHelp(sprintf('If this option is set, then DHCP static mappings will be registered in the DNS Resolver, so that their name can be '.
329
					'resolved. You should also set the domain in %s'.
330
					'System: General setup%s to the proper value.','<a href="system.php">','</a>'));
331

    
332
$section->addInput(new Form_Checkbox(
333
	'txtsupport',
334
	'TXT Comment Support',
335
	'Create TXT records',
336
	$pconfig['txtsupport']
337
))->setHelp('Any descriptions associated with Host entries and DHCP Static mappings will create a corresponding TXT record.');
338

    
339
$btnadvdns = new Form_Button(
340
	'btnadvdns',
341
	'Custom options'
342
);
343

    
344
$btnadvdns->removeClass('btn-primary')->addClass('btn-default btn-sm');
345

    
346
$section->addInput(new Form_StaticText(
347
	'Custom options',
348
	$btnadvdns . '&nbsp;' . 'Show custom options'
349
));
350

    
351
$section->addInput(new Form_Textarea (
352
	'custom_options',
353
	'Custom options',
354
	$pconfig['custom_options']
355
))->setHelp('Enter any additional configuration parameters to add to the DNS Resolver configuration here, separated by a newline');
356

    
357
$form->add($section);
358
print($form);
359
?>
360

    
361
<script>
362
//<![CDATA[
363
events.push(function(){
364

    
365
	// If the enable checkbox is not checked, disable the next three checkboxes
366
	function disableDHCP() {
367
		var hide = ! $('#enable').prop('checked');
368

    
369
		disableInput('port', hide);
370
		disableInput('active_interface', hide);
371
		disableInput('outgoing_interface', hide);
372
		disableInput('regdhcpstatic', hide);
373
		disableInput('dnssec', hide);
374
		disableInput('forwarding', hide);
375
		disableInput('regdhcp', hide);
376
		disableInput('regdhcpstatic', hide);
377
		disableInput('txtsupport', hide);
378
		disableInput('btnadvdns', hide);
379
	}
380

    
381
	// Make the 'additional options' button a plain button, not a submit button
382
	$("#btnadvdns").prop('type','button');
383

    
384
	// Un-hide additional  controls
385
	$("#btnadvdns").click(function() {
386
		hideInput('custom_options', false);
387

    
388
	});
389

    
390
	// When 'enable' is clicked, disable/enable the following three checkboxes
391
	$('#enable').click(function() {
392
		disableDHCP();
393
	});
394

    
395
	// On initial load
396
	if($('#custom_options').val().length == 0) {
397
		hideInput('custom_options', true);
398
	}
399

    
400
	disableDHCP();
401

    
402
});
403
//]]>
404
</script>
405

    
406
<div class="panel panel-default">
407
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
408
	<div class="panel-body table-responsive">
409
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
410
			<thead>
411
				<tr>
412
					<th><?=gettext("Host")?></th>
413
					<th><?=gettext("Domain")?></th>
414
					<th><?=gettext("IP")?></th>
415
					<th><?=gettext("Description")?></th>
416
					<th></th>
417
				</tr>
418
			</thead>
419
			<tbody>
420
<?php
421
$i = 0;
422
foreach ($a_hosts as $hostent):
423
?>
424
				<tr>
425
					<td>
426
						<?=strtolower($hostent['host'])?>
427
					</td>
428
					<td>
429
						<?=strtolower($hostent['domain'])?>
430
					</td>
431
					<td>
432
						<?=$hostent['ip']?>
433
					</td>
434
					<td>
435
						<?=htmlspecialchars($hostent['descr'])?>
436
					</td>
437
					<td>
438
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" href="services_unbound_host_edit.php?id=<?=$i?>"></a>
439
						<a class="fa fa-trash"	title="<?=gettext('Delete host override')?>" href="services_unbound.php?type=host&amp;act=del&amp;id=<?=$i?>"></a>
440
					</td>
441
				</tr>
442

    
443
<?php
444
	if ($hostent['aliases']['item'] && is_array($hostent['aliases']['item'])):
445
		foreach ($hostent['aliases']['item'] as $alias):
446
?>
447
				<tr>
448
					<td>
449
						<?=strtolower($alias['host'])?>
450
					</td>
451
					<td>
452
						<?=strtolower($alias['domain'])?>
453
					</td>
454
					<td>
455
						Alias for <?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
456
					</td>
457
					<td>
458
						<?=htmlspecialchars($alias['description'])?>
459
					</td>
460
					<td>
461
						<a a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_unbound_host_edit.php?id=<?=$i?>"></a>
462
					</td>
463
				</tr>
464
<?php
465
		endforeach;
466
	endif;
467
	$i++;
468
endforeach;
469
?>
470
			</tbody>
471
		</table>
472
	</div>
473
</div>
474

    
475
<nav class="action-buttons">
476
	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
477
		<i class="fa fa-plus icon-embed-btn"></i>
478
		<?=gettext('Add')?>
479
	</a>
480
</nav>
481

    
482
<div class="panel panel-default">
483
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain Overrides")?></h2></div>
484
	<div class="panel-body table-responsive">
485
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
486
			<thead>
487
				<tr>
488
					<th><?=gettext("Domain")?></th>
489
					<th><?=gettext("IP")?></th>
490
					<th><?=gettext("Description")?></th>
491
					<th></th>
492
				</tr>
493
			</thead>
494

    
495
			<tbody>
496
<?php
497
$i = 0;
498
foreach ($a_domainOverrides as $doment):
499
?>
500
				<tr>
501
					<td>
502
						<?=strtolower($doment['domain'])?>&nbsp;
503
					</td>
504
					<td>
505
						<?=$doment['ip']?>&nbsp;
506
					</td>
507
					<td>
508
						<?=htmlspecialchars($doment['descr'])?>&nbsp;
509
					</td>
510
					<td>
511
						<a class="fa fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_unbound_domainoverride_edit.php?id=<?=$i?>"></a>
512
						<a class="fa fa-trash"	title="<?=gettext('Delete domain override')?>" href="services_unbound.php?act=del&amp;type=doverride&amp;id=<?=$i?>"></a>
513
					</td>
514
				</tr>
515
<?php
516
	$i++;
517
endforeach;
518
?>
519
			</tbody>
520
		</table>
521
	</div>
522
</div>
523

    
524
<nav class="action-buttons">
525
	<a href="services_unbound_domainoverride_edit.php" class="btn btn-sm btn-success">
526
		<i class="fa fa-plus icon-embed-btn"></i>
527
		<?=gettext('Add')?>
528
	</a>
529
</nav>
530

    
531
<div id="infoblock">
532
	<?=print_info_box(sprintf(gettext("If the DNS Resolver is enabled, the DHCP".
533
		" service (if enabled) will automatically serve the LAN IP".
534
		" address as a DNS server to DHCP clients so they will use".
535
		" the DNS Resolver. If Forwarding is enabled, the DNS Resolver will use the DNS servers".
536
		" entered in %sSystem: General setup%s".
537
		" or those obtained via DHCP or PPP on WAN if &quot;Allow".
538
		" DNS server list to be overridden by DHCP/PPP on WAN&quot;".
539
		" is checked."),'<a href="system.php">','</a>'), info)?>
540
</div>
541

    
542
<?php include("foot.inc");
(150-150/228)