Project

General

Profile

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

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

    
62
require_once("guiconfig.inc");
63
require_once("unbound.inc");
64
require_once("system.inc");
65

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

    
70
$a_unboundcfg =& $config['unbound'];
71

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

    
76
$a_hosts =& $a_unboundcfg['hosts'];
77

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

    
82
$a_domainOverrides = &$a_unboundcfg['domainoverrides'];
83

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

    
100
$pconfig['port'] = $a_unboundcfg['port'];
101
$pconfig['custom_options'] = base64_decode($a_unboundcfg['custom_options']);
102

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

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

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

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

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

    
142
		// forwarding mode requires having valid DNS servers
143
		if (isset($pconfig['forwarding'])) {
144
			$founddns = false;
145
			if (isset($config['system']['dnsallowoverride'])) {
146
				$dns_servers = get_dns_servers();
147
				if (is_array($dns_servers)) {
148
					foreach ($dns_servers as $dns_server) {
149
						if (!ip_in_subnet($dns_server, "127.0.0.0/8")) {
150
							$founddns = true;
151
						}
152
					}
153
				}
154
			}
155
			if (is_array($config['system']['dnsserver'])) {
156
				foreach ($config['system']['dnsserver'] as $dnsserver) {
157
					if (is_ipaddr($dnsserver)) {
158
						$founddns = true;
159
					}
160
				}
161
			}
162
			if ($founddns == false) {
163
				$input_errors[] = gettext("At least one DNS server must be specified under System>General Setup to enable Forwarding mode.");
164
			}
165
		}
166

    
167
		if (empty($pconfig['active_interface'])) {
168
			$input_errors[] = gettext("One or more Network Interfaces must be selected for binding.");
169
		} else if (!isset($config['system']['dnslocalhost']) && (!in_array("lo0", $pconfig['active_interface']) && !in_array("all", $pconfig['active_interface']))) {
170
			$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.");
171
		}
172

    
173
		if (empty($pconfig['outgoing_interface'])) {
174
			$input_errors[] = gettext("One or more Outgoing Network Interfaces must be selected.");
175
		}
176

    
177
		if ($pconfig['port'] && !is_port($pconfig['port'])) {
178
			$input_errors[] = gettext("A valid port number must be specified.");
179
		}
180

    
181
		if (is_array($pconfig['active_interface']) && !empty($pconfig['active_interface'])) {
182
			$display_active_interface = $pconfig['active_interface'];
183
			$pconfig['active_interface'] = implode(",", $pconfig['active_interface']);
184
		}
185

    
186
		$display_custom_options = $pconfig['custom_options'];
187
		$pconfig['custom_options'] = base64_encode(str_replace("\r\n", "\n", $pconfig['custom_options']));
188

    
189
		if (is_array($pconfig['outgoing_interface']) && !empty($pconfig['outgoing_interface'])) {
190
			$display_outgoing_interface = $pconfig['outgoing_interface'];
191
			$pconfig['outgoing_interface'] = implode(",", $pconfig['outgoing_interface']);
192
		}
193

    
194
		$test_output = array();
195
		if (test_unbound_config($pconfig, $test_output)) {
196
			$input_errors[] = gettext("The generated config file cannot be parsed by unbound. Please correct the following errors:");
197
			$input_errors = array_merge($input_errors, $test_output);
198
		}
199

    
200
		if (!$input_errors) {
201
			$a_unboundcfg['enable'] = isset($pconfig['enable']);
202
			$a_unboundcfg['port'] = $pconfig['port'];
203
			$a_unboundcfg['dnssec'] = isset($pconfig['dnssec']);
204
			$a_unboundcfg['forwarding'] = isset($pconfig['forwarding']);
205
			$a_unboundcfg['regdhcp'] = isset($pconfig['regdhcp']);
206
			$a_unboundcfg['regdhcpstatic'] = isset($pconfig['regdhcpstatic']);
207
			$a_unboundcfg['active_interface'] = $pconfig['active_interface'];
208
			$a_unboundcfg['outgoing_interface'] = $pconfig['outgoing_interface'];
209
			$a_unboundcfg['system_domain_local_zone_type'] = $pconfig['system_domain_local_zone_type'];
210
			$a_unboundcfg['custom_options'] = $pconfig['custom_options'];
211

    
212
			write_config(gettext("DNS Resolver configured."));
213
			mark_subsystem_dirty('unbound');
214
		}
215

    
216
		$pconfig['active_interface'] = $display_active_interface;
217
		$pconfig['outgoing_interface'] = $display_outgoing_interface;
218
		$pconfig['custom_options'] = $display_custom_options;
219
	}
220
}
221

    
222
if ($pconfig['custom_options']) {
223
	$customoptions = true;
224
} else {
225
	$customoptions = false;
226
}
227

    
228
if ($_GET['act'] == "del") {
229
	if ($_GET['type'] == 'host') {
230
		if ($a_hosts[$_GET['id']]) {
231
			unset($a_hosts[$_GET['id']]);
232
			write_config();
233
			mark_subsystem_dirty('unbound');
234
			header("Location: services_unbound.php");
235
			exit;
236
		}
237
	} elseif ($_GET['type'] == 'doverride') {
238
		if ($a_domainOverrides[$_GET['id']]) {
239
			unset($a_domainOverrides[$_GET['id']]);
240
			write_config();
241
			mark_subsystem_dirty('unbound');
242
			header("Location: services_unbound.php");
243
			exit;
244
		}
245
	}
246
}
247

    
248
function build_if_list($selectedifs) {
249
	$interface_addresses = get_possible_listen_ips(true);
250
	$iflist = array('options' => array(), 'selected' => array());
251

    
252
	$iflist['options']['all']	= gettext("All");
253
	if (empty($selectedifs) || empty($selectedifs[0]) || in_array("all", $selectedifs)) {
254
		array_push($iflist['selected'], "all");
255
	}
256

    
257
	foreach ($interface_addresses as $laddr => $ldescr) {
258
		$iflist['options'][$laddr] = htmlspecialchars($ldescr);
259

    
260
		if ($selectedifs && in_array($laddr, $selectedifs)) {
261
			array_push($iflist['selected'], $laddr);
262
		}
263
	}
264

    
265
	unset($interface_addresses);
266

    
267
	return($iflist);
268
}
269

    
270
$pgtitle = array(gettext("Services"), gettext("DNS Resolver"), gettext("General Settings"));
271
$shortcut_section = "resolver";
272

    
273
include_once("head.inc");
274

    
275
if ($input_errors) {
276
	print_input_errors($input_errors);
277
}
278

    
279
if ($savemsg) {
280
	print_info_box($savemsg, 'success');
281
}
282

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

    
287
$tab_array = array();
288
$tab_array[] = array(gettext("General Settings"), true, "services_unbound.php");
289
$tab_array[] = array(gettext("Advanced Settings"), false, "services_unbound_advanced.php");
290
$tab_array[] = array(gettext("Access Lists"), false, "/services_unbound_acls.php");
291
display_top_tabs($tab_array, true);
292

    
293
$form = new Form();
294

    
295
$section = new Form_Section('General DNS Resolver Options');
296

    
297
$section->addInput(new Form_Checkbox(
298
	'enable',
299
	'Enable',
300
	'Enable DNS resolver',
301
	$pconfig['enable']
302
));
303

    
304
$section->addInput(new Form_Input(
305
	'port',
306
	'Listen Port',
307
	'number',
308
	$pconfig['port'],
309
	['placeholder' => '53']
310
))->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.');
311

    
312
$activeiflist = build_if_list($pconfig['active_interface']);
313

    
314
$section->addInput(new Form_Select(
315
	'active_interface',
316
	'Network Interfaces',
317
	$activeiflist['selected'],
318
	$activeiflist['options'],
319
	true
320
))->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. ' .
321
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
322

    
323
$outiflist = build_if_list($pconfig['outgoing_interface']);
324

    
325
$section->addInput(new Form_Select(
326
	'outgoing_interface',
327
	'Outgoing Network Interfaces',
328
	$outiflist['selected'],
329
	$outiflist['options'],
330
	true
331
))->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.');
332

    
333
$section->addInput(new Form_Select(
334
	'system_domain_local_zone_type',
335
	'System Domain Local Zone Type',
336
	$pconfig['system_domain_local_zone_type'],
337
	unbound_local_zone_types()
338
))->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.');
339

    
340
$section->addInput(new Form_Checkbox(
341
	'dnssec',
342
	'DNSSEC',
343
	'Enable DNSSEC Support',
344
	$pconfig['dnssec']
345
));
346

    
347
$section->addInput(new Form_Checkbox(
348
	'forwarding',
349
	'DNS Query Forwarding',
350
	'Enable Forwarding Mode',
351
	$pconfig['forwarding']
352
));
353

    
354
$section->addInput(new Form_Checkbox(
355
	'regdhcp',
356
	'DHCP Registration',
357
	'Register DHCP leases in the DNS Resolver',
358
	$pconfig['regdhcp']
359
))->setHelp(sprintf('If this option is set, then machines that specify their hostname when requesting a DHCP lease will be registered'.
360
					' in the DNS Resolver, so that their name can be resolved.'.
361
					' The domain in %sSystem: General Setup%s should also be set to the proper value.','<a href="system.php">','</a>'));
362

    
363
$section->addInput(new Form_Checkbox(
364
	'regdhcpstatic',
365
	'Static DHCP',
366
	'Register DHCP static mappings in the DNS Resolver',
367
	$pconfig['regdhcpstatic']
368
))->setHelp(sprintf('If this option is set, then DHCP static mappings will be registered in the DNS Resolver, so that their name can be resolved. '.
369
					'The domain in %sSystem: General Setup%s should also be set to the proper value.','<a href="system.php">','</a>'));
370

    
371
$btnadv = new Form_Button(
372
	'btnadvcustom',
373
	'Custom options',
374
	null,
375
	'fa-cog'
376
);
377

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

    
380
$section->addInput(new Form_StaticText(
381
	'Display Custom Options',
382
	$btnadv
383
));
384

    
385
$section->addInput(new Form_Textarea (
386
	'custom_options',
387
	'Custom options',
388
	$pconfig['custom_options']
389
))->setHelp('Enter any additional configuration parameters to add to the DNS Resolver configuration here, separated by a newline.');
390

    
391
$form->add($section);
392
print($form);
393
?>
394

    
395
<script type="text/javascript">
396
//<![CDATA[
397
events.push(function() {
398

    
399
	// Show advanced custom options ==============================================
400
	var showadvcustom = false;
401

    
402
	function show_advcustom(ispageload) {
403
		var text;
404
		// On page load decide the initial state based on the data.
405
		if (ispageload) {
406
			showadvcustom = <?=($customoptions ? 'true' : 'false');?>;
407
		} else {
408
			// It was a click, swap the state.
409
			showadvcustom = !showadvcustom;
410
		}
411

    
412
		hideInput('custom_options', !showadvcustom);
413

    
414
		if (showadvcustom) {
415
			text = "<?=gettext('Hide Custom Options');?>";
416
		} else {
417
			text = "<?=gettext('Display Custom Options');?>";
418
		}
419
		$('#btnadvcustom').html('<i class="fa fa-cog"></i> ' + text);
420
	}
421

    
422
	// If the enable checkbox is not checked, hide all inputs
423
	function hideGeneral() {
424
		var hide = ! $('#enable').prop('checked');
425

    
426
		hideMultiClass('general', hide);
427
		hideInput('port', hide);
428
		hideSelect('system_domain_local_zone_type', hide);
429
		hideCheckbox('dnssec', hide);
430
		hideCheckbox('forwarding', hide);
431
		hideCheckbox('regdhcp', hide);
432
		hideCheckbox('regdhcpstatic', hide);
433
		hideInput('btnadvcustom', hide);
434
		hideInput('custom_options', hide || !showadvcustom);
435
	}
436

    
437
	// Un-hide additional controls
438
	$('#btnadvcustom').click(function(event) {
439
		show_advcustom();
440
	});
441

    
442
	// When 'enable' is clicked, disable/enable the following hide inputs
443
	$('#enable').click(function() {
444
		hideGeneral();
445
	});
446

    
447
	// On initial load
448
	if ($('#custom_options').val().length == 0) {
449
		hideInput('custom_options', true);
450
	}
451

    
452
	hideGeneral();
453
	show_advcustom(true);
454

    
455
});
456
//]]>
457
</script>
458

    
459
<div class="panel panel-default">
460
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
461
	<div class="panel-body table-responsive">
462
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
463
			<thead>
464
				<tr>
465
					<th><?=gettext("Host")?></th>
466
					<th><?=gettext("Domain")?></th>
467
					<th><?=gettext("IP")?></th>
468
					<th><?=gettext("Description")?></th>
469
					<th><?=gettext("Actions")?></th>
470
				</tr>
471
			</thead>
472
			<tbody>
473
<?php
474
$i = 0;
475
foreach ($a_hosts as $hostent):
476
?>
477
				<tr>
478
					<td>
479
						<?=$hostent['host']?>
480
					</td>
481
					<td>
482
						<?=$hostent['domain']?>
483
					</td>
484
					<td>
485
						<?=$hostent['ip']?>
486
					</td>
487
					<td>
488
						<?=htmlspecialchars($hostent['descr'])?>
489
					</td>
490
					<td>
491
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" href="services_unbound_host_edit.php?id=<?=$i?>"></a>
492
						<a class="fa fa-trash"	title="<?=gettext('Delete host override')?>" href="services_unbound.php?type=host&amp;act=del&amp;id=<?=$i?>"></a>
493
					</td>
494
				</tr>
495

    
496
<?php
497
	if ($hostent['aliases']['item'] && is_array($hostent['aliases']['item'])):
498
		foreach ($hostent['aliases']['item'] as $alias):
499
?>
500
				<tr>
501
					<td>
502
						<?=$alias['host']?>
503
					</td>
504
					<td>
505
						<?=$alias['domain']?>
506
					</td>
507
					<td>
508
						<?=gettext("Alias for ");?><?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
509
					</td>
510
					<td>
511
						<i class="fa fa-angle-double-right text-info"></i>
512
						<?=htmlspecialchars($alias['description'])?>
513
					</td>
514
					<td>
515
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_unbound_host_edit.php?id=<?=$i?>"></a>
516
					</td>
517
				</tr>
518
<?php
519
		endforeach;
520
	endif;
521
	$i++;
522
endforeach;
523
?>
524
			</tbody>
525
		</table>
526
	</div>
527
</div>
528

    
529
<nav class="action-buttons">
530
	<a href="services_unbound_host_edit.php" class="btn btn-sm btn-success">
531
		<i class="fa fa-plus icon-embed-btn"></i>
532
		<?=gettext('Add')?>
533
	</a>
534
</nav>
535

    
536
<div class="panel panel-default">
537
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain Overrides")?></h2></div>
538
	<div class="panel-body table-responsive">
539
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
540
			<thead>
541
				<tr>
542
					<th><?=gettext("Domain")?></th>
543
					<th><?=gettext("IP")?></th>
544
					<th><?=gettext("Description")?></th>
545
					<th><?=gettext("Actions")?></th>
546
				</tr>
547
			</thead>
548

    
549
			<tbody>
550
<?php
551
$i = 0;
552
foreach ($a_domainOverrides as $doment):
553
?>
554
				<tr>
555
					<td>
556
						<?=$doment['domain']?>&nbsp;
557
					</td>
558
					<td>
559
						<?=$doment['ip']?>&nbsp;
560
					</td>
561
					<td>
562
						<?=htmlspecialchars($doment['descr'])?>&nbsp;
563
					</td>
564
					<td>
565
						<a class="fa fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_unbound_domainoverride_edit.php?id=<?=$i?>"></a>
566
						<a class="fa fa-trash"	title="<?=gettext('Delete domain override')?>" href="services_unbound.php?act=del&amp;type=doverride&amp;id=<?=$i?>"></a>
567
					</td>
568
				</tr>
569
<?php
570
	$i++;
571
endforeach;
572
?>
573
			</tbody>
574
		</table>
575
	</div>
576
</div>
577

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

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

    
596
<?php include("foot.inc");
(142-142/227)