Project

General

Profile

Download (15.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_dnsmasq.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * Copyright (c) 2003-2004 Bob Zoller <bob@kludgebox.com>
8
 * All rights reserved.
9
 *
10
 * originally based on m0n0wall (http://m0n0.ch/wall)
11
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
12
 * All rights reserved.
13
 *
14
 * Licensed under the Apache License, Version 2.0 (the "License");
15
 * you may not use this file except in compliance with the License.
16
 * You may obtain a copy of the License at
17
 *
18
 * http://www.apache.org/licenses/LICENSE-2.0
19
 *
20
 * Unless required by applicable law or agreed to in writing, software
21
 * distributed under the License is distributed on an "AS IS" BASIS,
22
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23
 * See the License for the specific language governing permissions and
24
 * limitations under the License.
25
 */
26

    
27
##|+PRIV
28
##|*IDENT=page-services-dnsforwarder
29
##|*NAME=Services: DNS Forwarder
30
##|*DESCR=Allow access to the 'Services: DNS Forwarder' page.
31
##|*MATCH=services_dnsmasq.php*
32
##|-PRIV
33

    
34
require_once("guiconfig.inc");
35
require_once("functions.inc");
36
require_once("filter.inc");
37
require_once("shaper.inc");
38
require_once("system.inc");
39

    
40
// Sort host entries for display in alphabetical order
41
function hostcmp($a, $b) {
42
	return strcasecmp($a['host'], $b['host']);
43
}
44

    
45
function hosts_sort() {
46
	global $a_hosts;
47

    
48
	if (!is_array($a_hosts)) {
49
		return;
50
	}
51

    
52
	usort($a_hosts, "hostcmp");
53
}
54

    
55
// Sort domain entries for display in alphabetical order
56
function domaincmp($a, $b) {
57
	return strcasecmp($a['domain'], $b['domain']);
58
}
59

    
60
function domains_sort() {
61
	global $a_domainOverrides;
62

    
63
	if (!is_array($a_domainOverrides)) {
64
		return;
65
	}
66

    
67
	usort($a_domainOverrides, "domaincmp");
68
}
69

    
70
$pconfig['enable'] = isset($config['dnsmasq']['enable']);
71
$pconfig['regdhcp'] = isset($config['dnsmasq']['regdhcp']);
72
$pconfig['regdhcpstatic'] = isset($config['dnsmasq']['regdhcpstatic']);
73
$pconfig['dhcpfirst'] = isset($config['dnsmasq']['dhcpfirst']);
74
$pconfig['strict_order'] = isset($config['dnsmasq']['strict_order']);
75
$pconfig['domain_needed'] = isset($config['dnsmasq']['domain_needed']);
76
$pconfig['no_private_reverse'] = isset($config['dnsmasq']['no_private_reverse']);
77
$pconfig['port'] = $config['dnsmasq']['port'];
78
$pconfig['custom_options'] = $config['dnsmasq']['custom_options'];
79
$pconfig['strictbind'] = isset($config['dnsmasq']['strictbind']);
80

    
81
if (!empty($config['dnsmasq']['interface'])) {
82
	$pconfig['interface'] = explode(",", $config['dnsmasq']['interface']);
83
} else {
84
	$pconfig['interface'] = array();
85
}
86

    
87
if (!is_array($config['dnsmasq']['hosts'])) {
88
	$config['dnsmasq']['hosts'] = array();
89
}
90

    
91
if (!is_array($config['dnsmasq']['domainoverrides'])) {
92
	$config['dnsmasq']['domainoverrides'] = array();
93
}
94

    
95
$a_hosts = &$config['dnsmasq']['hosts'];
96

    
97
// Add a temporary index so we don't lose the order after sorting
98
for ($idx=0; $idx<count($a_hosts); $idx++) {
99
	$a_hosts[$idx]['idx'] = $idx;
100
}
101

    
102
hosts_sort();
103

    
104
$a_domainOverrides = &$config['dnsmasq']['domainoverrides'];
105

    
106
// Add a temporary index so we don't lose the order after sorting
107
for ($idx=0; $idx<count($a_domainOverrides); $idx++) {
108
	$a_domainOverrides[$idx]['idx'] = $idx;
109
}
110

    
111
domains_sort();
112

    
113

    
114
if ($_POST['apply']) {
115
	$retval = 0;
116
	$retval |= services_dnsmasq_configure();
117

    
118
	// Reload filter (we might need to sync to CARP hosts)
119
	filter_configure();
120
	/* Update resolv.conf in case the interface bindings exclude localhost. */
121
	system_resolvconf_generate();
122
	/* Start or restart dhcpleases when it's necessary */
123
	system_dhcpleases_configure();
124

    
125
	if ($retval == 0) {
126
		clear_subsystem_dirty('hosts');
127
	}
128
}
129

    
130
if ($_POST['save']) {
131
	$pconfig = $_POST;
132
	unset($input_errors);
133

    
134
	$config['dnsmasq']['enable'] = ($_POST['enable']) ? true : false;
135
	$config['dnsmasq']['regdhcp'] = ($_POST['regdhcp']) ? true : false;
136
	$config['dnsmasq']['regdhcpstatic'] = ($_POST['regdhcpstatic']) ? true : false;
137
	$config['dnsmasq']['dhcpfirst'] = ($_POST['dhcpfirst']) ? true : false;
138
	$config['dnsmasq']['strict_order'] = ($_POST['strict_order']) ? true : false;
139
	$config['dnsmasq']['domain_needed'] = ($_POST['domain_needed']) ? true : false;
140
	$config['dnsmasq']['no_private_reverse'] = ($_POST['no_private_reverse']) ? true : false;
141
	$config['dnsmasq']['custom_options'] = str_replace("\r\n", "\n", $_POST['custom_options']);
142
	$config['dnsmasq']['strictbind'] = ($_POST['strictbind']) ? true : false;
143

    
144
	if (isset($_POST['enable']) && isset($config['unbound']['enable'])) {
145
		if ($_POST['port'] == $config['unbound']['port']) {
146
			$input_errors[] = gettext("The DNS Resolver is enabled using this port. Choose a non-conflicting port, or disable DNS Resolver.");
147
		}
148
	}
149

    
150
	if ($_POST['port']) {
151
		if (is_port($_POST['port'])) {
152
			$config['dnsmasq']['port'] = $_POST['port'];
153
		} else {
154
			$input_errors[] = gettext("A valid port number must be specified.");
155
		}
156
	} else if (isset($config['dnsmasq']['port'])) {
157
		unset($config['dnsmasq']['port']);
158
	}
159

    
160
	if (is_array($_POST['interface'])) {
161
		$config['dnsmasq']['interface'] = implode(",", $_POST['interface']);
162
	} elseif (isset($config['dnsmasq']['interface'])) {
163
		unset($config['dnsmasq']['interface']);
164
	}
165

    
166
	if ($config['dnsmasq']['custom_options']) {
167
		$args = '';
168
		foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
169
			$args .= escapeshellarg("--{$c}") . " ";
170
		}
171
		exec("/usr/local/sbin/dnsmasq --test $args", $output, $rc);
172
		if ($rc != 0) {
173
			$input_errors[] = gettext("Invalid custom options");
174
		}
175
	}
176

    
177
	if (!$input_errors) {
178
		write_config();
179
		mark_subsystem_dirty('hosts');
180
	}
181
}
182

    
183

    
184
if ($_POST['act'] == "del") {
185
	if ($_POST['type'] == 'host') {
186
		if ($a_hosts[$_POST['id']]) {
187
			unset($a_hosts[$_POST['id']]);
188
			write_config();
189
			mark_subsystem_dirty('hosts');
190
			header("Location: services_dnsmasq.php");
191
			exit;
192
		}
193
	} elseif ($_POST['type'] == 'doverride') {
194
		if ($a_domainOverrides[$_POST['id']]) {
195
			unset($a_domainOverrides[$_POST['id']]);
196
			write_config();
197
			mark_subsystem_dirty('hosts');
198
			header("Location: services_dnsmasq.php");
199
			exit;
200
		}
201
	}
202
}
203

    
204
function build_if_list() {
205
	global $pconfig;
206

    
207
	$interface_addresses = get_possible_listen_ips(true);
208
	$iflist = array('options' => array(), 'selected' => array());
209

    
210
	$iflist['options'][""]	= "All";
211
	if (empty($pconfig['interface']) || empty($pconfig['interface'][0])) {
212
		array_push($iflist['selected'], "");
213
	}
214

    
215
	foreach ($interface_addresses as $laddr => $ldescr) {
216
		$iflist['options'][$laddr] = htmlspecialchars($ldescr);
217

    
218
		if ($pconfig['interface'] && in_array($laddr, $pconfig['interface'])) {
219
			array_push($iflist['selected'], $laddr);
220
		}
221
	}
222

    
223
	unset($interface_addresses);
224

    
225
	return($iflist);
226
}
227

    
228
$pgtitle = array(gettext("Services"), gettext("DNS Forwarder"));
229
$shortcut_section = "forwarder";
230
include("head.inc");
231

    
232
if ($input_errors) {
233
	print_input_errors($input_errors);
234
}
235

    
236
if ($_POST['apply']) {
237
	print_apply_result_box($retval);
238
}
239

    
240
if (is_subsystem_dirty('hosts')) {
241
	print_apply_box(gettext("The DNS forwarder configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
242
}
243

    
244
$form = new Form();
245

    
246
$section = new Form_Section('General DNS Forwarder Options');
247

    
248
$section->addInput(new Form_Checkbox(
249
	'enable',
250
	'Enable',
251
	'Enable DNS forwarder',
252
	$pconfig['enable']
253
))->toggles('.toggle-dhcp', 'disable');
254

    
255
$section->addInput(new Form_Checkbox(
256
	'regdhcp',
257
	'DHCP Registration',
258
	'Register DHCP leases in DNS forwarder',
259
	$pconfig['regdhcp']
260
))->setHelp('If this option is set machines that specify'.
261
			' their hostname when requesting a DHCP lease will be registered'.
262
			' in the DNS forwarder, so that their name can be resolved.'.
263
			' The domain in %1$sSystem: General Setup%2$s should also'.
264
			' be set to the proper value.', '<a href="system.php">', '</a>')
265
	->addClass('toggle-dhcp');
266

    
267
$section->addInput(new Form_Checkbox(
268
	'regdhcpstatic',
269
	'Static DHCP',
270
	'Register DHCP static mappings in DNS forwarder',
271
	$pconfig['regdhcpstatic']
272
))->setHelp('If this option is set, DHCP static mappings will '.
273
					'be registered in the DNS forwarder, so that their name can be '.
274
					'resolved. The domain in %1$sSystem: General Setup%2$s should also '.
275
					'be set to the proper value.', '<a href="system.php">', '</a>')
276
	->addClass('toggle-dhcp');
277

    
278
$section->addInput(new Form_Checkbox(
279
	'dhcpfirst',
280
	'Prefer DHCP',
281
	'Resolve DHCP mappings first',
282
	$pconfig['dhcpfirst']
283
))->setHelp("If this option is set DHCP mappings will ".
284
					"be resolved before the manual list of names below. This only ".
285
					"affects the name given for a reverse lookup (PTR).")
286
	->addClass('toggle-dhcp');
287

    
288
$group = new Form_Group('DNS Query Forwarding');
289

    
290
$group->add(new Form_Checkbox(
291
	'strict_order',
292
	'DNS Query Forwarding',
293
	'Query DNS servers sequentially',
294
	$pconfig['strict_order']
295
))->setHelp('If this option is set %1$s DNS Forwarder (dnsmasq) will '.
296
					'query the DNS servers sequentially in the order specified (%2$sSystem - General Setup - DNS Servers%3$s), '.
297
					'rather than all at once in parallel. ', $g['product_name'], '<i>', '</i>');
298

    
299
$group->add(new Form_Checkbox(
300
	'domain_needed',
301
	null,
302
	'Require domain',
303
	$pconfig['domain_needed']
304
))->setHelp("If this option is set %s DNS Forwarder (dnsmasq) will ".
305
					"not forward A or AAAA queries for plain names, without dots or domain parts, to upstream name servers.	 ".
306
					"If the name is not known from /etc/hosts or DHCP then a \"not found\" answer is returned. ", $g['product_name']);
307

    
308
$group->add(new Form_Checkbox(
309
	'no_private_reverse',
310
	null,
311
	'Do not forward private reverse lookups',
312
	$pconfig['no_private_reverse']
313
))->setHelp("If this option is set %s DNS Forwarder (dnsmasq) will ".
314
					"not forward reverse DNS lookups (PTR) for private addresses (RFC 1918) to upstream name servers.  ".
315
					"Any entries in the Domain Overrides section forwarding private \"n.n.n.in-addr.arpa\" names to a specific server are still forwarded. ".
316
					"If the IP to name is not known from /etc/hosts, DHCP or a specific domain override then a \"not found\" answer is immediately returned. ", $g['product_name']);
317

    
318
$section->add($group);
319

    
320
$section->addInput(new Form_Input(
321
	'port',
322
	'Listen Port',
323
	'number',
324
	$pconfig['port'],
325
	['placeholder' => '53']
326
))->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.');
327

    
328
$iflist = build_if_list();
329

    
330
$section->addInput(new Form_Select(
331
	'interface',
332
	'*Interfaces',
333
	$iflist['selected'],
334
	$iflist['options'],
335
	true
336
))->setHelp('Interface IPs used by the DNS Forwarder 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. ' .
337
			'The default behavior is to respond to queries on every available IPv4 and IPv6 address.');
338

    
339
$section->addInput(new Form_Checkbox(
340
	'strictbind',
341
	'Strict binding',
342
	'Strict interface binding',
343
	$pconfig['strictbind']
344
))->setHelp('If this option is set, the DNS forwarder will only bind to the interfaces containing the IP addresses selected above, ' .
345
					'rather than binding to all interfaces and discarding queries to other addresses.%1$s' .
346
					'This option does NOT work with IPv6. If set, dnsmasq will not bind to IPv6 addresses.', '<br /><br />');
347

    
348
$section->addInput(new Form_Textarea(
349
	'custom_options',
350
	'Custom options',
351
	$pconfig['custom_options']
352
))->setHelp('Enter any additional options to add to the dnsmasq configuration here, separated by a space or newline.')
353
  ->addClass('advanced');
354

    
355
$form->add($section);
356
print($form);
357

    
358
?>
359
<div class="panel panel-default">
360
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Host Overrides")?></h2></div>
361
	<div class="panel-body table-responsive">
362
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
363
			<thead>
364
				<tr>
365
					<th><?=gettext("Host")?></th>
366
					<th><?=gettext("Domain")?></th>
367
					<th><?=gettext("IP")?></th>
368
					<th><?=gettext("Description")?></th>
369
					<th><?=gettext("Actions")?></th>
370
				</tr>
371
			</thead>
372
			<tbody>
373
<?php
374
foreach ($a_hosts as $i => $hostent):
375
?>
376
				<tr>
377
					<td>
378
						<?=$hostent['host']?>
379
					</td>
380
					<td>
381
						<?=$hostent['domain']?>
382
					</td>
383
					<td>
384
						<?=$hostent['ip']?>
385
					</td>
386
					<td>
387
						<?=htmlspecialchars($hostent['descr'])?>
388
					</td>
389
					<td>
390
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_dnsmasq_edit.php?id=<?=$hostent['idx']?>"></a>
391
						<a class="fa fa-trash"	title="<?=gettext('Delete host override')?>"	href="services_dnsmasq.php?type=host&amp;act=del&amp;id=<?=$hostent['idx']?>" usepost></a>
392
					</td>
393
				</tr>
394

    
395
<?php
396
	if ($hostent['aliases']['item'] && is_array($hostent['aliases']['item'])):
397
		foreach ($hostent['aliases']['item'] as $alias):
398
?>
399
				<tr>
400
					<td>
401
						<?=$alias['host']?>
402
					</td>
403
					<td>
404
						<?=$alias['domain']?>
405
					</td>
406
					<td>
407
						<?=gettext("Alias for ");?><?=$hostent['host'] ? $hostent['host'] . '.' . $hostent['domain'] : $hostent['domain']?>
408
					</td>
409
					<td>
410
						<i class="fa fa-angle-double-right text-info"></i>
411
						<?=htmlspecialchars($alias['description'])?>
412
					</td>
413
					<td>
414
						<a class="fa fa-pencil"	title="<?=gettext('Edit host override')?>" 	href="services_dnsmasq_edit.php?id=<?=$i?>"></a>
415
					</td>
416
				</tr>
417
<?php
418
		endforeach;
419
	endif;
420
endforeach;
421
?>
422
			</tbody>
423
		</table>
424
	</div>
425
</div>
426

    
427
<nav class="action-buttons">
428
	<a href="services_dnsmasq_edit.php" class="btn btn-sm btn-success btn-sm">
429
		<i class="fa fa-plus icon-embed-btn"></i>
430
		<?=gettext('Add')?>
431
	</a>
432
</nav>
433

    
434
<div class="panel panel-default">
435
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("Domain Overrides")?></h2></div>
436
	<div class="panel-body table-responsive">
437
		<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap table-rowdblclickedit" data-sortable>
438
			<thead>
439
				<tr>
440
					<th><?=gettext("Domain")?></th>
441
					<th><?=gettext("IP")?></th>
442
					<th><?=gettext("Description")?></th>
443
					<th><?=gettext("Actions")?></th>
444
				</tr>
445
			</thead>
446

    
447
			<tbody>
448
<?php
449
foreach ($a_domainOverrides as $i => $doment):
450
?>
451
				<tr>
452
					<td>
453
						<?=$doment['domain']?>
454
					</td>
455
					<td>
456
						<?=$doment['ip']?>
457
					</td>
458
					<td>
459
						<?=htmlspecialchars($doment['descr'])?>
460
					</td>
461
					<td>
462
						<a class="fa fa-pencil"	title="<?=gettext('Edit domain override')?>" href="services_dnsmasq_domainoverride_edit.php?id=<?=$doment['idx']?>"></a>
463
						<a class="fa fa-trash"	title="<?=gettext('Delete domain override')?>" href="services_dnsmasq.php?act=del&amp;type=doverride&amp;id=<?=$doment['idx']?>" usepost></a>
464
					</td>
465
				</tr>
466
<?php
467
endforeach;
468
?>
469
			</tbody>
470
		</table>
471
	</div>
472
</div>
473

    
474
<nav class="action-buttons">
475
	<a href="services_dnsmasq_domainoverride_edit.php" class="btn btn-sm btn-success btn-sm">
476
		<i class="fa fa-plus icon-embed-btn"></i>
477
		<?=gettext('Add')?>
478
	</a>
479
</nav>
480
<div class="infoblock">
481
<?php
482
print_info_box(
483
	'<p>' .
484
	gettext('If the DNS forwarder is enabled, the DHCP service (if enabled) will automatically' .
485
		    ' serve the LAN IP address as a DNS server to DHCP clients so they will use the forwarder.') . '</p><p>' .
486
	sprintf(gettext('The DNS forwarder will use the DNS servers entered in %1$sSystem > General Setup%2$s or' .
487
				    ' those obtained via DHCP or PPP on WAN if &quot;Allow DNS server list to be overridden by DHCP/PPP on WAN&quot; is checked.' .
488
				    ' If that option is not used (or if a static IP address is used on WAN),' .
489
				    ' at least one DNS server must be manually specified on the %1$sSystem > General Setup%2$s page.'),
490
			'<a href="system.php">',
491
			'</a>') .
492
	'</p>',
493
	'info',
494
	false
495
);
496
?>
497
</div>
498

    
499
<?php
500
include("foot.inc");
(121-121/223)