Project

General

Profile

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

    
59
##|+PRIV
60
##|*IDENT=page-services-dhcpserver
61
##|*NAME=Services: DHCP Server
62
##|*DESCR=Allow access to the 'Services: DHCP Server' page.
63
##|*MATCH=services_dhcp.php*
64
##|-PRIV
65

    
66
require("guiconfig.inc");
67
require_once("filter.inc");
68
require_once('rrd.inc');
69
require_once("shaper.inc");
70

    
71
if (!$g['services_dhcp_server_enable']) {
72
	header("Location: /");
73
	exit;
74
}
75

    
76
$if = $_GET['if'];
77
if (!empty($_POST['if'])) {
78
	$if = $_POST['if'];
79
}
80

    
81
/* if OLSRD is enabled, allow WAN to house DHCP. */
82
if ($config['installedpackages']['olsrd']) {
83
	foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
84
		if ($olsrd['enable']) {
85
			$is_olsr_enabled = true;
86
			break;
87
		}
88
	}
89
}
90

    
91
$iflist = get_configured_interface_with_descr();
92

    
93
/* set the starting interface */
94
if (!$if || !isset($iflist[$if])) {
95
	$found_starting_if = false;
96
	// First look for an interface with DHCP already enabled.
97
	foreach ($iflist as $ifent => $ifname) {
98
		$oc = $config['interfaces'][$ifent];
99
		if (is_array($config['dhcpd'][$ifent]) && isset($config['dhcpd'][$ifent]['enable']) && (is_ipaddrv4($oc['ipaddr']))) {
100
			$if = $ifent;
101
			$found_starting_if = true;
102
			break;
103
		}
104
	}
105

    
106
	// If there is no DHCP-enabled interface and LAN is a candidate, then choose LAN.
107
	if (!$found_starting_if && isset($iflist['lan']) && is_ipaddrv4($config['interfaces']['lan']['ipaddr'])) {
108
		$if = 'lan';
109
		$found_starting_if = true;
110
	}
111

    
112
	// At the last select whatever can be found.
113
	if (!$found_starting_if) {
114
		foreach ($iflist as $ifent => $ifname) {
115
			$oc = $config['interfaces'][$ifent];
116
			if ((is_array($config['dhcpd'][$ifent]) && !isset($config['dhcpd'][$ifent]['enable']) && (!is_ipaddrv4($oc['ipaddr']))) ||
117
				(!is_array($config['dhcpd'][$ifent]) && (!is_ipaddrv4($oc['ipaddr'])))) {
118
				continue;
119
			}
120

    
121
			$if = $ifent;
122
			break;
123
		}
124
	}
125
}
126

    
127
$act = $_GET['act'];
128
if (!empty($_POST['act'])) {
129
	$act = $_POST['act'];
130
}
131

    
132
$a_pools = array();
133

    
134
if (is_array($config['dhcpd'][$if])) {
135
	$pool = $_GET['pool'];
136
	if (is_numeric($_POST['pool'])) {
137
		$pool = $_POST['pool'];
138
	}
139

    
140
	// If we have a pool but no interface name, that's not valid. Redirect away.
141
	if (is_numeric($pool) && empty($if)) {
142
		header("Location: services_dhcp.php");
143
		exit;
144
	}
145

    
146
	if (!is_array($config['dhcpd'][$if]['pool'])) {
147
		$config['dhcpd'][$if]['pool'] = array();
148
	}
149

    
150
	$a_pools = &$config['dhcpd'][$if]['pool'];
151

    
152
	if (is_numeric($pool) && $a_pools[$pool]) {
153
		$dhcpdconf = &$a_pools[$pool];
154
	} elseif ($act == "newpool") {
155
		$dhcpdconf = array();
156
	} else {
157
		$dhcpdconf = &$config['dhcpd'][$if];
158
	}
159

    
160
	if (!is_array($config['dhcpd'][$if]['staticmap'])) {
161
		$dhcpdconf['staticmap'] = array();
162
	}
163

    
164
	$a_maps = &$config['dhcpd'][$if]['staticmap'];
165
}
166
if (is_array($dhcpdconf)) {
167
	// Global Options
168
	if (!is_numeric($pool) && !($act == "newpool")) {
169
		$pconfig['enable'] = isset($dhcpdconf['enable']);
170
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
171
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
172
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
173
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
174

    
175
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
176
		// then show it true/checked.
177
		foreach ($config['dhcpd'] as $dhcpdifitem) {
178
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
179
			if ($dhcpleaseinlocaltime) {
180
				break;
181
			}
182
		}
183

    
184
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
185
	} else {
186
		// Options that exist only in pools
187
		$pconfig['descr'] = $dhcpdconf['descr'];
188
	}
189

    
190
	// Options that can be global or per-pool.
191
	if (is_array($dhcpdconf['range'])) {
192
		$pconfig['range_from'] = $dhcpdconf['range']['from'];
193
		$pconfig['range_to'] = $dhcpdconf['range']['to'];
194
	}
195

    
196
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
197
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
198
	$pconfig['gateway'] = $dhcpdconf['gateway'];
199
	$pconfig['domain'] = $dhcpdconf['domain'];
200
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
201
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
202
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
203
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
204
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
205
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
206
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
207
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
208
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
209
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
210
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
211
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
212
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
213
	$pconfig['tftp'] = $dhcpdconf['tftp'];
214
	$pconfig['ldap'] = $dhcpdconf['ldap'];
215
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
216
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
217
	$pconfig['filename'] = $dhcpdconf['filename'];
218
	$pconfig['filename32'] = $dhcpdconf['filename32'];
219
	$pconfig['filename64'] = $dhcpdconf['filename64'];
220
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
221
	$pconfig['netmask'] = $dhcpdconf['netmask'];
222
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
223
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
224
}
225

    
226
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
227
$ifcfgsn = $config['interfaces'][$if]['subnet'];
228

    
229
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
230
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
231

    
232
function validate_partial_mac_list($maclist) {
233
	$macs = explode(',', $maclist);
234

    
235
	// Loop through and look for invalid MACs.
236
	foreach ($macs as $mac) {
237
		if (!is_macaddr($mac, true)) {
238
			return false;
239
		}
240
	}
241

    
242
	return true;
243
}
244

    
245
if (isset($_POST['submit'])) {
246

    
247
	unset($input_errors);
248

    
249
	$pconfig = $_POST;
250

    
251
	$numberoptions = array();
252
	for ($x = 0; $x < 99; $x++) {
253
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
254
			$numbervalue = array();
255
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
256
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
257
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
258
			$numberoptions['item'][] = $numbervalue;
259
		}
260
	}
261

    
262
	// Reload the new pconfig variable that the form uses.
263
	$pconfig['numberoptions'] = $numberoptions;
264

    
265
	/* input validation */
266
	if ($_POST['enable'] || is_numeric($pool) || $act == "newpool") {
267
		$reqdfields = explode(" ", "range_from range_to");
268
		$reqdfieldsn = array(gettext("Range begin"), gettext("Range end"));
269

    
270
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
271

    
272
		if (($_POST['nonak']) && !empty($_POST['failover_peerip'])) {
273
			$input_errors[] = gettext("Ignore Denied Clients may not be used when a Failover Peer IP is defined.");
274
		}
275

    
276
		if (($_POST['range_from'] && !is_ipaddrv4($_POST['range_from']))) {
277
			$input_errors[] = gettext("A valid range must be specified.");
278
		}
279
		if (($_POST['range_to'] && !is_ipaddrv4($_POST['range_to']))) {
280
			$input_errors[] = gettext("A valid range must be specified.");
281
		}
282
		if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
283
			$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
284
		}
285
		if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
286
			$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
287
		}
288
		$parent_ip = get_interface_ip($_POST['if']);
289
		if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
290
			$parent_sn = get_interface_subnet($_POST['if']);
291
			if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
292
				$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
293
			}
294
		}
295

    
296
		if (($_POST['dns1'] && !is_ipaddrv4($_POST['dns1'])) || ($_POST['dns2'] && !is_ipaddrv4($_POST['dns2'])) || ($_POST['dns3'] && !is_ipaddrv4($_POST['dns3'])) || ($_POST['dns4'] && !is_ipaddrv4($_POST['dns4']))) {
297
			$input_errors[] = gettext("A valid IP address must be specified for each of the DNS servers.");
298
		}
299

    
300
		if ($_POST['deftime'] && (!is_numeric($_POST['deftime']) || ($_POST['deftime'] < 60))) {
301
			$input_errors[] = gettext("The default lease time must be at least 60 seconds.");
302
		}
303

    
304
		if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
305
			$deftime = 7200; // Default value if it's empty
306
			if (is_numeric($_POST['deftime'])) {
307
				$deftime = $_POST['deftime'];
308
			}
309

    
310
			foreach ($config['captiveportal'] as $cpZone => $cpdata) {
311
				if (!isset($cpdata['enable'])) {
312
					continue;
313
				}
314
				if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
315
					continue;
316
				}
317
				$cp_ifs = explode(',', $cpdata['interface']);
318
				if (!in_array($if, $cp_ifs)) {
319
					continue;
320
				}
321
				if ($cpdata['timeout'] > $deftime) {
322
					$input_errors[] = sprintf(gettext(
323
						'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
324
				}
325
			}
326
		}
327

    
328
		if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
329
			$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
330
		}
331
		if (($_POST['ddnsdomain'] && !is_domain($_POST['ddnsdomain']))) {
332
			$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
333
		}
334
		if (($_POST['ddnsdomain'] && !is_ipaddrv4($_POST['ddnsdomainprimary']))) {
335
			$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
336
		}
337
		if (($_POST['ddnsdomainkey'] && !$_POST['ddnsdomainkeyname']) ||
338
		    ($_POST['ddnsdomainkeyname'] && !$_POST['ddnsdomainkey'])) {
339
			$input_errors[] = gettext("You must specify both a valid domain key and key name.");
340
		}
341
		if ($_POST['domainsearchlist']) {
342
			$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
343
			foreach ($domain_array as $curdomain) {
344
				if (!is_domain($curdomain)) {
345
					$input_errors[] = gettext("A valid domain search list must be specified.");
346
					break;
347
				}
348
			}
349
		}
350

    
351
		// Validate MACs
352
		if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
353
			$input_errors[] = gettext("If you specify a mac allow list, it must contain only valid partial MAC addresses.");
354
		}
355
		if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
356
			$input_errors[] = gettext("If you specify a mac deny list, it must contain only valid partial MAC addresses.");
357
		}
358

    
359
		if (($_POST['ntp1'] && !is_ipaddrv4($_POST['ntp1'])) || ($_POST['ntp2'] && !is_ipaddrv4($_POST['ntp2']))) {
360
			$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary NTP servers.");
361
		}
362
		if (($_POST['domain'] && !is_domain($_POST['domain']))) {
363
			$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
364
		}
365
		if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !is_URL($_POST['tftp'])) {
366
			$input_errors[] = gettext("A valid IP address or hostname must be specified for the TFTP server.");
367
		}
368
		if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
369
			$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
370
		}
371

    
372
		if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
373
			$input_errors[] = gettext("You cannot use the network address in the starting subnet range.");
374
		}
375
		if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
376
			$input_errors[] = gettext("You cannot use the broadcast address in the ending subnet range.");
377
		}
378

    
379
		// Disallow a range that includes the virtualip
380
		if (is_array($config['virtualip']['vip'])) {
381
			foreach ($config['virtualip']['vip'] as $vip) {
382
				if ($vip['interface'] == $if) {
383
					if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
384
						$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
385
					}
386
				}
387
			}
388
		}
389

    
390
		$noip = false;
391
		if (is_array($a_maps)) {
392
			foreach ($a_maps as $map) {
393
				if (empty($map['ipaddr'])) {
394
					$noip = true;
395
				}
396
			}
397
		}
398

    
399
		if ($_POST['staticarp'] && $noip) {
400
			$input_errors[] = gettext("Cannot enable static ARP when you have static map entries without IP addresses. Ensure all static maps have IP addresses and try again.");
401
		}
402

    
403
		if (is_array($pconfig['numberoptions']['item'])) {
404
			foreach ($pconfig['numberoptions']['item'] as $numberoption) {
405
				$numberoption_value = base64_decode($numberoption['value']);
406
				if ($numberoption['type'] == 'text' && strstr($numberoption_value, '"')) {
407
					$input_errors[] = gettext("Text type cannot include quotation marks.");
408
				} else if ($numberoption['type'] == 'string' && !preg_match('/^"[^"]*"$/', $numberoption_value) && !preg_match('/^[0-9a-f]{2}(?:\:[0-9a-f]{2})*$/i', $numberoption_value)) {
409
					$input_errors[] = gettext("String type must be enclosed in quotes like \"this\" or must be a series of octets specified in hexadecimal, separated by colons, like 01:23:45:67:89:ab:cd:ef");
410
				} else if ($numberoption['type'] == 'boolean' && $numberoption_value != 'true' && $numberoption_value != 'false' && $numberoption_value != 'on' && $numberoption_value != 'off') {
411
					$input_errors[] = gettext("Boolean type must be true, false, on, or off.");
412
				} else if ($numberoption['type'] == 'unsigned integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 255)) {
413
					$input_errors[] = gettext("Unsigned 8-bit integer type must be a number in the range 0 to 255.");
414
				} else if ($numberoption['type'] == 'unsigned integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 65535)) {
415
					$input_errors[] = gettext("Unsigned 16-bit integer type must be a number in the range 0 to 65535.");
416
				} else if ($numberoption['type'] == 'unsigned integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 4294967295)) {
417
					$input_errors[] = gettext("Unsigned 32-bit integer type must be a number in the range 0 to 4294967295.");
418
				} else if ($numberoption['type'] == 'signed integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < -128 || $numberoption_value > 127)) {
419
					$input_errors[] = gettext("Signed 8-bit integer type must be a number in the range -128 to 127.");
420
				} else if ($numberoption['type'] == 'signed integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < -32768 || $numberoption_value > 32767)) {
421
					$input_errors[] = gettext("Signed 16-bit integer type must be a number in the range -32768 to 32767.");
422
				} else if ($numberoption['type'] == 'signed integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < -2147483648 || $numberoption_value > 2147483647)) {
423
					$input_errors[] = gettext("Signed 32-bit integer type must be a number in the range -2147483648 to 2147483647.");
424
				} else if ($numberoption['type'] == 'ip-address' && !is_ipaddrv4($numberoption_value) && !is_hostname($numberoption_value)) {
425
					$input_errors[] = gettext("IP address or host type must be an IP address or host name.");
426
				}
427
			}
428
		}
429

    
430
		if (!$input_errors) {
431
			/* make sure the range lies within the current subnet */
432
			if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
433
				$input_errors[] = gettext("The range is invalid (first element higher than second element).");
434
			}
435

    
436
			if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
437
			    !is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
438
				$input_errors[] = gettext("The specified range lies outside of the current subnet.");
439
			}
440

    
441
			if (is_numeric($pool) || ($act == "newpool")) {
442
				if (is_inrange_v4($_POST['range_from'],
443
				    $config['dhcpd'][$if]['range']['from'],
444
				    $config['dhcpd'][$if]['range']['to']) ||
445
				    is_inrange_v4($_POST['range_to'],
446
				    $config['dhcpd'][$if]['range']['from'],
447
				    $config['dhcpd'][$if]['range']['to'])) {
448
					$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
449
				}
450
			}
451

    
452
			foreach ($a_pools as $id => $p) {
453
				if (is_numeric($pool) && ($id == $pool)) {
454
					continue;
455
				}
456

    
457
				if (is_inrange_v4($_POST['range_from'],
458
				    $p['range']['from'], $p['range']['to']) ||
459
				    is_inrange_v4($_POST['range_to'],
460
				    $p['range']['from'], $p['range']['to'])) {
461
					$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
462
					break;
463
				}
464
			}
465

    
466
			/* make sure that the DHCP Relay isn't enabled on this interface */
467
			if (isset($config['dhcrelay']['enable']) && (stristr($config['dhcrelay']['interface'], $if) !== false)) {
468
				$input_errors[] = sprintf(gettext("You must disable the DHCP relay on the %s interface before enabling the DHCP server."), $iflist[$if]);
469
			}
470

    
471
			if (is_array($a_maps)) {
472
				foreach ($a_maps as $map) {
473
					if (empty($map['ipaddr'])) {
474
						continue;
475
					}
476
					if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
477
						$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
478
						break;
479
					}
480
				}
481
			}
482
		}
483
	}
484

    
485
	if (!$input_errors) {
486
		if (!is_numeric($pool)) {
487
			if ($act == "newpool") {
488
				$dhcpdconf = array();
489
			} else {
490
				if (!is_array($config['dhcpd'][$if])) {
491
					$config['dhcpd'][$if] = array();
492
				}
493
				$dhcpdconf = $config['dhcpd'][$if];
494
			}
495
		} else {
496
			if (is_array($a_pools[$pool])) {
497
				$dhcpdconf = $a_pools[$pool];
498
			} else {
499
				// Someone specified a pool but it doesn't exist. Punt.
500
				header("Location: services_dhcp.php");
501
				exit;
502
			}
503
		}
504
		if (!is_array($dhcpdconf['range'])) {
505
			$dhcpdconf['range'] = array();
506
		}
507

    
508
		$dhcpd_enable_changed = false;
509

    
510
		// Global Options
511
		if (!is_numeric($pool) && !($act == "newpool")) {
512
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
513
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
514
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
515
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
516
				$dhcpd_enable_changed = true;
517
			}
518

    
519
			$dhcpdconf['enable'] = $new_dhcpd_enable;
520
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
521
			$previous = $dhcpdconf['failover_peerip'];
522
			if ($previous != $_POST['failover_peerip']) {
523
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
524
			}
525

    
526
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
527
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
528
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
529
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
530
			}
531
		} else {
532
			// Options that exist only in pools
533
			$dhcpdconf['descr'] = $_POST['descr'];
534
		}
535

    
536
		// Options that can be global or per-pool.
537
		$dhcpdconf['range']['from'] = $_POST['range_from'];
538
		$dhcpdconf['range']['to'] = $_POST['range_to'];
539
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
540
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
541
		$dhcpdconf['netmask'] = $_POST['netmask'];
542

    
543
		unset($dhcpdconf['winsserver']);
544
		if ($_POST['wins1']) {
545
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
546
		}
547
		if ($_POST['wins2']) {
548
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
549
		}
550

    
551
		unset($dhcpdconf['dnsserver']);
552
		if ($_POST['dns1']) {
553
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
554
		}
555
		if ($_POST['dns2']) {
556
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
557
		}
558
		if ($_POST['dns3']) {
559
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
560
		}
561
		if ($_POST['dns4']) {
562
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
563
		}
564

    
565
		$dhcpdconf['gateway'] = $_POST['gateway'];
566
		$dhcpdconf['domain'] = $_POST['domain'];
567
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
568
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
569
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
570
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
571
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
572
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
573
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
574
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
575
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
576
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
577

    
578
		unset($dhcpdconf['ntpserver']);
579
		if ($_POST['ntp1']) {
580
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
581
		}
582
		if ($_POST['ntp2']) {
583
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
584
		}
585

    
586
		$dhcpdconf['tftp'] = $_POST['tftp'];
587
		$dhcpdconf['ldap'] = $_POST['ldap'];
588
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
589
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
590
		$dhcpdconf['filename'] = $_POST['filename'];
591
		$dhcpdconf['filename32'] = $_POST['filename32'];
592
		$dhcpdconf['filename64'] = $_POST['filename64'];
593
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
594
		unset($dhcpdconf['statsgraph']);
595
		if ($_POST['statsgraph']) {
596
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
597
			enable_rrd_graphing();
598
		}
599

    
600
		// Handle the custom options rowhelper
601
		if (isset($dhcpdconf['numberoptions']['item'])) {
602
			unset($dhcpdconf['numberoptions']['item']);
603
		}
604

    
605
		$dhcpdconf['numberoptions'] = $numberoptions;
606

    
607
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
608
			$a_pools[$pool] = $dhcpdconf;
609
		} elseif ($act == "newpool") {
610
			$a_pools[] = $dhcpdconf;
611
		} else {
612
			$config['dhcpd'][$if] = $dhcpdconf;
613
		}
614

    
615
		write_config();
616
	}
617
}
618

    
619
if ((isset($_POST['submit']) || isset($_POST['apply'])) && (!$input_errors)) {
620
	$retval = 0;
621
	$retvaldhcp = 0;
622
	$retvaldns = 0;
623
	/* dnsmasq_configure calls dhcpd_configure */
624
	/* no need to restart dhcpd twice */
625
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
626
		$retvaldns = services_dnsmasq_configure();
627
		if ($retvaldns == 0) {
628
			clear_subsystem_dirty('hosts');
629
			clear_subsystem_dirty('staticmaps');
630
		}
631
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
632
		$retvaldns = services_unbound_configure();
633
		if ($retvaldns == 0) {
634
			clear_subsystem_dirty('unbound');
635
			clear_subsystem_dirty('hosts');
636
			clear_subsystem_dirty('staticmaps');
637
		}
638
	} else {
639
		$retvaldhcp = services_dhcpd_configure();
640
		if ($retvaldhcp == 0) {
641
			clear_subsystem_dirty('staticmaps');
642
		}
643
	}
644
	if ($dhcpd_enable_changed) {
645
		$retvalfc = filter_configure();
646
	}
647

    
648
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
649
		$retval = 1;
650
	}
651

    
652
	$savemsg = get_std_save_message($retval);
653
}
654

    
655
if ($act == "delpool") {
656
	if ($a_pools[$_GET['id']]) {
657
		unset($a_pools[$_GET['id']]);
658
		write_config();
659
		header("Location: services_dhcp.php?if={$if}");
660
		exit;
661
	}
662
}
663

    
664
if ($act == "del") {
665
	if ($a_maps[$_GET['id']]) {
666
		unset($a_maps[$_GET['id']]);
667
		write_config();
668
		if (isset($config['dhcpd'][$if]['enable'])) {
669
			mark_subsystem_dirty('staticmaps');
670
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
671
				mark_subsystem_dirty('hosts');
672
			}
673
		}
674

    
675
		header("Location: services_dhcp.php?if={$if}");
676
		exit;
677
	}
678
}
679

    
680
// Build an HTML table that can be inserted into a Form_StaticText element
681
function build_pooltable() {
682
	global $a_pools;
683

    
684
	$pooltbl =	'<div class="table-responsive">';
685
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
686
	$pooltbl .=			'<thead>';
687
	$pooltbl .=				'<tr>';
688
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
689
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
690
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
691
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
692
	$pooltbl .=				'</tr>';
693
	$pooltbl .=			'</thead>';
694
	$pooltbl .=			'<tbody>';
695

    
696
	if (is_array($a_pools)) {
697
		$i = 0;
698
		foreach ($a_pools as $poolent) {
699
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
700
				$pooltbl .= '<tr>';
701
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
702
							htmlspecialchars($poolent['range']['from']) . '</td>';
703

    
704
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
705
							htmlspecialchars($poolent['range']['to']) . '</td>';
706

    
707
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
708
							htmlspecialchars($poolent['descr']) . '</td>';
709

    
710
				$pooltbl .= '<td><a class="fa fa-pencil" title="'. gettext("Edit pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '"></a>';
711

    
712
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '"></a></td>';
713
				$pooltbl .= '</tr>';
714
			}
715
		$i++;
716
		}
717
	}
718

    
719
	$pooltbl .=			'</tbody>';
720
	$pooltbl .=		'</table>';
721
	$pooltbl .= '</div>';
722

    
723
	return($pooltbl);
724
}
725

    
726
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
727

    
728
if (!empty($if) && !isset($config['dhcrelay']['enable']) && isset($iflist[$if])) {
729
	$pgtitle[] = $iflist[$if];
730
}
731
$shortcut_section = "dhcp";
732

    
733
include("head.inc");
734

    
735
if ($input_errors) {
736
	print_input_errors($input_errors);
737
}
738

    
739
if ($savemsg) {
740
	print_info_box($savemsg, 'success');
741
}
742

    
743
if (isset($config['dhcrelay']['enable'])) {
744
	print_info_box(gettext("DHCP Relay is currently enabled. Cannot enable the DHCP Server service while the DHCP Relay is enabled on any interface."));
745
	include("foot.inc");
746
	exit;
747
}
748

    
749
if (is_subsystem_dirty('staticmaps')) {
750
	print_apply_box(gettext("The static mapping configuration has been changed.") . "<br />" . gettext("You must apply the changes in order for them to take effect."));
751
}
752

    
753
/* active tabs */
754
$tab_array = array();
755
$tabscounter = 0;
756
$i = 0;
757

    
758
foreach ($iflist as $ifent => $ifname) {
759
	$oc = $config['interfaces'][$ifent];
760
	if ((is_array($config['dhcpd'][$ifent]) && !isset($config['dhcpd'][$ifent]['enable']) && (!is_ipaddrv4($oc['ipaddr']))) ||
761
	    (!is_array($config['dhcpd'][$ifent]) && (!is_ipaddrv4($oc['ipaddr'])))) {
762
		continue;
763
	}
764

    
765
	if ($ifent == $if) {
766
		$active = true;
767
	} else {
768
		$active = false;
769
	}
770

    
771
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
772
	$tabscounter++;
773
}
774

    
775
if ($tabscounter == 0) {
776
	print_info_box(gettext("The DHCP Server can only be enabled on interfaces configured with a static IPv4 address. This system has none."));
777
	include("foot.inc");
778
	exit;
779
}
780

    
781
display_top_tabs($tab_array);
782

    
783
// This form uses a non-standard submit button name
784
$form = new Form();
785

    
786
$section = new Form_Section('General Options');
787

    
788
if (!is_numeric($pool) && !($act == "newpool")) {
789
	$section->addInput(new Form_Checkbox(
790
		'enable',
791
		'Enable',
792
		sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
793
		$pconfig['enable']
794
	));
795
} else {
796
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
797
}
798

    
799
$section->addInput(new Form_Checkbox(
800
	'denyunknown',
801
	'Deny unknown clients',
802
	'Only the clients defined below will get DHCP leases from this server.',
803
	$pconfig['denyunknown']
804
));
805

    
806
$section->addInput(new Form_Checkbox(
807
	'nonak',
808
	'Ignore denied clients',
809
	'Denied clients will be ignored rather than rejected.',
810
	$pconfig['nonak']
811
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
812

    
813

    
814
if (is_numeric($pool) || ($act == "newpool")) {
815
	$section->addInput(new Form_Input(
816
		'descr',
817
		'Pool Description',
818
		'text',
819
		$pconfig['descr']
820
	));
821
}
822

    
823
$section->addInput(new Form_StaticText(
824
	'Subnet',
825
	gen_subnet($ifcfgip, $ifcfgsn)
826
));
827

    
828
$section->addInput(new Form_StaticText(
829
	'Subnet mask',
830
	gen_subnet_mask($ifcfgsn)
831
));
832

    
833
// Compose a string to display the required address ranges
834
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
835

    
836
if (is_numeric($pool) || ($act == "newpool")) {
837
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
838
	if (is_array($config['dhcpd'][$if]['range'])) {
839
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
840
	}
841

    
842
	foreach ($a_pools as $p) {
843
		if (is_array($p['range'])) {
844
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
845
		}
846
	}
847
}
848

    
849
$section->addInput(new Form_StaticText(
850
	'Available range',
851
	$rangestr
852
));
853

    
854
if ($is_olsr_enabled) {
855
	$section->addInput(new Form_Select(
856
		'netmask',
857
		'Subnet mask',
858
		$pconfig['netmask'],
859
		array_combine(range(32, 1, -1), range(32, 1, -1))
860
	));
861
}
862

    
863
$group = new Form_Group('Range');
864

    
865
$group->add(new Form_IpAddress(
866
	'range_from',
867
	null,
868
	$pconfig['range_from']
869
))->setHelp('From');
870

    
871
$group->add(new Form_IpAddress(
872
	'range_to',
873
	null,
874
	$pconfig['range_to']
875
))->setHelp('To');
876

    
877
$section->add($group);
878

    
879
$form->add($section);
880

    
881
if (!is_numeric($pool) && !($act == "newpool")) {
882
	$section = new Form_Section('Additional Pools');
883

    
884
	$btnaddpool = new Form_Button(
885
		'btnaddpool',
886
		'Add pool',
887
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
888
		'fa-plus'
889
	);
890
	$btnaddpool->addClass('btn-success');
891

    
892
	$section->addInput(new Form_StaticText(
893
		'Add',
894
		$btnaddpool
895
	))->setHelp('If you need additional pools of addresses inside of this subnet outside the above Range, they may be specified here');
896

    
897
	if (is_array($a_pools)) {
898
		$section->addInput(new Form_StaticText(
899
			null,
900
			build_pooltable()
901
		));
902
	}
903

    
904
	$form->add($section);
905
}
906

    
907
$section = new Form_Section('Servers');
908

    
909
$section->addInput(new Form_IpAddress(
910
	'wins1',
911
	'WINS servers',
912
	$pconfig['wins1']
913
))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'WINS Server 1');
914

    
915
$section->addInput(new Form_IpAddress(
916
	'wins2',
917
	null,
918
	$pconfig['wins2']
919
))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'WINS Server 2');
920

    
921
for ($idx=1; $idx<=4; $idx++) {
922
	$section->addInput(new Form_IpAddress(
923
		'dns' . $idx,
924
		($idx == 1) ? 'DNS servers':null,
925
		$pconfig['dns' . $idx]
926
	))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'DNS Server ' . $idx)->setHelp(($idx == 4) ? 'Leave blank to use the system default DNS servers, use this interface\'s IP if DNS Forwarder or Resolver is enabled, otherwise use the servers configured on the General page':'');
927
}
928

    
929
$form->add($section);
930

    
931
$section = new Form_Section('Other Options');
932

    
933
$section->addInput(new Form_IpAddress(
934
	'gateway',
935
	'Gateway',
936
	$pconfig['gateway']
937
))->setPattern('[.a-zA-Z0-9_]+')
938
  ->setHelp('The default is to use the IP on this interface of the firewall as the gateway. Specify an alternate gateway here if this is not the correct gateway for your network. Type "none" for no gateway assignment');
939

    
940
$section->addInput(new Form_Input(
941
	'domain',
942
	'Domain name',
943
	'text',
944
	$pconfig['domain']
945
))->setHelp('The default is to use the domain name of this system as the default domain name provided by DHCP. You may specify an alternate domain name here');
946

    
947
$section->addInput(new Form_Input(
948
	'domainsearchlist',
949
	'Domain search list',
950
	'text',
951
	$pconfig['domainsearchlist']
952
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator');
953

    
954
$section->addInput(new Form_Input(
955
	'deftime',
956
	'Default lease time',
957
	'number',
958
	$pconfig['deftime']
959
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds');
960

    
961
$section->addInput(new Form_Input(
962
	'maxtime',
963
	'Maximum lease time',
964
	'number',
965
	$pconfig['maxtime']
966
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds');
967

    
968
if (!is_numeric($pool) && !($act == "newpool")) {
969
	$section->addInput(new Form_IpAddress(
970
		'failover_peerip',
971
		'Failover peer IP',
972
		$pconfig['failover_peerip']
973
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
974
				'Interface\'s advskew determines whether the DHCPd process is Primary or Secondary. Ensure one machine\'s advskew &lt; 20 (and the other is &gt; 20).');
975
}
976

    
977
if (!is_numeric($pool) && !($act == "newpool")) {
978
	$section->addInput(new Form_Checkbox(
979
		'staticarp',
980
		'Static ARP',
981
		'Enable Static ARP entries',
982
		$pconfig['staticarp']
983
	))->setHelp('This option persists even if DHCP server is disabled. Only the machines listed below will be able to communicate with the firewall on this interface.');
984

    
985
	$section->addInput(new Form_Checkbox(
986
		'dhcpleaseinlocaltime',
987
		'Time format change',
988
		'Change DHCP display lease time from UTC to local time',
989
		$pconfig['dhcpleaseinlocaltime']
990
	))->setHelp('By default DHCP leases are displayed in UTC time.	By checking this box DHCP lease time will be displayed in local time and set to the time zone selected.' .
991
				' This will be used for all DHCP interfaces lease time');
992
	$section->addInput(new Form_Checkbox(
993
		'statsgraph',
994
		'Statistics graphs',
995
		'Enable RRD statistics graphs',
996
		$pconfig['statsgraph']
997
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
998
}
999

    
1000
// DDNS
1001
$btnadv = new Form_Button(
1002
	'btnadvdns',
1003
	'Advanced'
1004
);
1005

    
1006
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1007

    
1008
$section->addInput(new Form_StaticText(
1009
	'Dynamic DNS',
1010
	$btnadv
1011
));
1012

    
1013
$section->addInput(new Form_Checkbox(
1014
	'ddnsupdate',
1015
	null,
1016
	'Enable registration of DHCP client names in DNS',
1017
	$pconfig['ddnsupdate']
1018
));
1019

    
1020
$section->addInput(new Form_Input(
1021
	'ddnsdomain',
1022
	'DDNS Domain',
1023
	'text',
1024
	$pconfig['ddnsdomain']
1025
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
1026
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1027

    
1028
$section->addInput(new Form_IpAddress(
1029
	'ddnsdomainprimary',
1030
	'Primary DDNS address',
1031
	$pconfig['ddnsdomainprimary']
1032
))->setHelp('Primary domain name server IP address for the dynamic domain name');
1033

    
1034
$section->addInput(new Form_Input(
1035
	'ddnsdomainkeyname',
1036
	'DNS Domain key',
1037
	'text',
1038
	$pconfig['ddnsdomainkeyname']
1039
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server');
1040

    
1041
$section->addInput(new Form_Input(
1042
	'ddnsdomainkey',
1043
	'DNS Domain key secret',
1044
	'text',
1045
	$pconfig['ddnsdomainkey']
1046
))->setHelp('Dynamic DNS domain key secret which will be used to register client names in the DNS server');
1047

    
1048
// Advanced MAC
1049
$btnadv = new Form_Button(
1050
	'btnadvmac',
1051
	'Advanced'
1052
);
1053

    
1054
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1055

    
1056
$section->addInput(new Form_StaticText(
1057
	'MAC address control',
1058
	$btnadv
1059
));
1060

    
1061
$section->addInput(new Form_Input(
1062
	'mac_allow',
1063
	'MAC Allow',
1064
	'text',
1065
	$pconfig['mac_allow']
1066
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1067

    
1068
$section->addInput(new Form_Input(
1069
	'mac_deny',
1070
	'MAC Deny',
1071
	'text',
1072
	$pconfig['mac_deny']
1073
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1074

    
1075
// Advanced NTP
1076
$btnadv = new Form_Button(
1077
	'btnadvntp',
1078
	'Advanced'
1079
);
1080

    
1081
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1082

    
1083
$section->addInput(new Form_StaticText(
1084
	'NTP',
1085
	$btnadv
1086
));
1087

    
1088
$section->addInput(new Form_IpAddress(
1089
	'ntp1',
1090
	'NTP Server 1',
1091
	$pconfig['ntp1']
1092
));
1093

    
1094
$section->addInput(new Form_IpAddress(
1095
	'ntp2',
1096
	'NTP Server 2',
1097
	$pconfig['ntp2']
1098
));
1099

    
1100
// Advanced TFTP
1101
$btnadv = new Form_Button(
1102
	'btnadvtftp',
1103
	'Advanced'
1104
);
1105

    
1106
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1107

    
1108
$section->addInput(new Form_StaticText(
1109
	'TFTP',
1110
	$btnadv
1111
));
1112

    
1113
$section->addInput(new Form_IpAddress(
1114
	'tftp',
1115
	'TFTP Server',
1116
	$pconfig['tftp']
1117
))->setHelp('Leave blank to disable.  Enter a full hostname or IP for the TFTP server')->setPattern('[.a-zA-Z0-9_]+');
1118

    
1119
// Advanced LDAP
1120
$btnadv = new Form_Button(
1121
	'btnadvldap',
1122
	'Advanced'
1123
);
1124

    
1125
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1126

    
1127
$section->addInput(new Form_StaticText(
1128
	'LDAP',
1129
	$btnadv
1130
));
1131

    
1132
$section->addInput(new Form_Input(
1133
	'ldap',
1134
	'LDAP Server URI',
1135
	'text',
1136
	$pconfig['ldap']
1137
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1138

    
1139
$form->add($section);
1140

    
1141
// Advanced Additional options
1142
$btnadv = new Form_Button(
1143
	'btnadvopts',
1144
	'Advanced'
1145
);
1146

    
1147
$btnadv->removeClass('btn-primary')->addClass('btn-info btn-sm');
1148

    
1149
$section->addInput(new Form_StaticText(
1150
	'Additional BOOTP/DHCP Options',
1151
	$btnadv
1152
));
1153

    
1154
$section = new Form_Section('Additional BOOTP/DHCP Options');
1155
$section->addClass('adnlopts');
1156

    
1157
$section->addInput(new Form_StaticText(
1158
	null,
1159
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item you would like to include in the DHCP lease information.') . ' ' .
1160
	sprintf(gettext('For a list of available options please visit this %1$s URL%2$s'), '<a href="http://www.iana.org/assignments/bootp-dhcp-parameters/" target="_blank">', '</a></div>')
1161
));
1162

    
1163
if (!$pconfig['numberoptions']) {
1164
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1165
}
1166

    
1167
$customitemtypes = array(
1168
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1169
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1170
	'signed integer 8' => gettext('Signed 8-bit integer'), 'signed integer 16' => gettext('Signed 16-bit integer'), 'signed integer 32' => gettext('Signed 32-bit integer'), 'ip-address' => gettext('IP address or host')
1171
);
1172

    
1173
$numrows = count($item) -1;
1174
$counter = 0;
1175

    
1176
$numrows = count($pconfig['numberoptions']['item']) -1;
1177

    
1178
foreach ($pconfig['numberoptions']['item'] as $item) {
1179
	$number = $item['number'];
1180
	$itemtype = $item['type'];
1181
	$value = base64_decode($item['value']);
1182

    
1183
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1184
	$group->addClass('repeatable');
1185

    
1186
	$group->add(new Form_Input(
1187
		'number' . $counter,
1188
		null,
1189
		'text',
1190
		$number
1191
	))->setHelp($numrows == $counter ? 'Number':null);
1192

    
1193

    
1194
	$group->add(new Form_Select(
1195
		'itemtype' . $counter,
1196
		null,
1197
		$itemtype,
1198
		$customitemtypes
1199
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1200

    
1201
	$group->add(new Form_Input(
1202
		'value' . $counter,
1203
		null,
1204
		'text',
1205
		$value
1206
	))->setHelp($numrows == $counter ? 'Value':null);
1207

    
1208
	$group->add(new Form_Button(
1209
		'deleterow' . $counter,
1210
		'Delete',
1211
		null,
1212
		'fa-trash'
1213
	))->addClass('btn-warning');
1214

    
1215
	$section->add($group);
1216

    
1217
	$counter++;
1218
}
1219

    
1220
$section->addInput(new Form_Button(
1221
	'addrow',
1222
	'Add',
1223
	null,
1224
	'fa-plus'
1225
))->addClass('btn-success');
1226

    
1227
$form->add($section);
1228

    
1229
if ($pconfig['netboot']) {
1230
	$sectate = COLLAPSIBLE|SEC_OPEN;
1231
} else {
1232
	$sectate = COLLAPSIBLE|SEC_CLOSED;
1233
}
1234
$section = new Form_Section("Network Booting", nwkbootsec, $sectate);
1235

    
1236
$section->addInput(new Form_Checkbox(
1237
	'netboot',
1238
	'Enable',
1239
	'Enables network booting',
1240
	$pconfig['netboot']
1241
));
1242

    
1243
$section->addInput(new Form_IpAddress(
1244
	'nextserver',
1245
	'Next Server',
1246
	$pconfig['nextserver']
1247
))->setHelp('Enter the IP address of the next server');
1248

    
1249
$section->addInput(new Form_Input(
1250
	'filename',
1251
	'Default BIOS file name',
1252
	'text',
1253
	$pconfig['filename']
1254
));
1255

    
1256
$section->addInput(new Form_Input(
1257
	'filename32',
1258
	'UEFI 32 bit file name',
1259
	'text',
1260
	$pconfig['filename32']
1261
));
1262

    
1263
$section->addInput(new Form_Input(
1264
	'filename64',
1265
	'UEFI 64 bit file name',
1266
	'text',
1267
	$pconfig['filename64']
1268
))->setHelp('You need both a filename and a boot server configured for this to work! ' .
1269
			'You will need all three filenames and a boot server configured for UEFI to work! ');
1270

    
1271
$section->addInput(new Form_Input(
1272
	'rootpath',
1273
	'Root path',
1274
	'text',
1275
	$pconfig['rootpath']
1276
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1277

    
1278
$form->add($section);
1279

    
1280
if ($act == "newpool") {
1281
	$form->addGlobal(new Form_Input(
1282
		'act',
1283
		null,
1284
		'hidden',
1285
		'newpool'
1286
	));
1287
}
1288

    
1289
if (is_numeric($pool)) {
1290
	$form->addGlobal(new Form_Input(
1291
		'pool',
1292
		null,
1293
		'hidden',
1294
		$pool
1295
	));
1296
}
1297

    
1298
$form->addGlobal(new Form_Input(
1299
	'if',
1300
	null,
1301
	'hidden',
1302
	$if
1303
));
1304

    
1305
print($form);
1306

    
1307
// DHCP Static Mappings table
1308

    
1309
if (!is_numeric($pool) && !($act == "newpool")) {
1310
?>
1311

    
1312
<div class="panel panel-default">
1313
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1314
	<div class="table-responsive">
1315
			<table class="table table-striped table-hover table-condensed">
1316
				<thead>
1317
					<tr>
1318
						<th><?=gettext("Static ARP")?></th>
1319
						<th><?=gettext("MAC address")?></th>
1320
						<th><?=gettext("IP address")?></th>
1321
						<th><?=gettext("Hostname")?></th>
1322
						<th><?=gettext("Description")?></th>
1323
						<th></th>
1324
					</tr>
1325
				</thead>
1326
<?php
1327
	if (is_array($a_maps)) {
1328
		$i = 0;
1329
?>
1330
				<tbody>
1331
<?php
1332
		foreach ($a_maps as $mapent) {
1333
?>
1334
					<tr>
1335
						<td align="center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1336
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1337
								<i class="fa fa-check"></i>
1338
							<?php endif; ?>
1339
						</td>
1340
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1341
							<?=htmlspecialchars($mapent['mac'])?>
1342
						</td>
1343
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1344
							<?=htmlspecialchars($mapent['ipaddr'])?>
1345
						</td>
1346
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1347
							<?=htmlspecialchars($mapent['hostname'])?>
1348
						</td>
1349
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1350
							<?=htmlspecialchars($mapent['descr'])?>
1351
						</td>
1352
						<td>
1353
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1354
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>"></a>
1355
						</td>
1356
					</tr>
1357
<?php
1358
		$i++;
1359
		}
1360
?>
1361
				</tbody>
1362
<?php
1363
	}
1364
?>
1365
		</table>
1366
	</div>
1367
</div>
1368

    
1369
<nav class="action-buttons">
1370
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1371
		<i class="fa fa-plus icon-embed-btn"></i>
1372
		<?=gettext("Add")?>
1373
	</a>
1374
</nav>
1375
<?php
1376
}
1377
?>
1378

    
1379
<script type="text/javascript">
1380
//<![CDATA[
1381
events.push(function() {
1382

    
1383
	// Show advanced DNS options ======================================================================================
1384
	var showadvdns = false;
1385

    
1386
	function show_advdns() {
1387
<?php
1388
		if (!$pconfig['ddnsupdate'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1389
		    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1390
			$hide = false;
1391
		} else {
1392
			$hide = true;
1393
		}
1394
?>
1395
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1396

    
1397
		hideCheckbox('ddnsupdate', !showadvdns && !hide);
1398
		hideInput('ddnsdomain', !showadvdns && !hide);
1399
		hideInput('ddnsdomainprimary', !showadvdns && !hide);
1400
		hideInput('ddnsdomainkeyname', !showadvdns && !hide);
1401
		hideInput('ddnsdomainkey', !showadvdns && !hide);
1402
		hideInput('btnadvdns', hide);
1403
		showadvdns = !showadvdns;
1404
	}
1405

    
1406
	$('#btnadvdns').prop('type', 'button');
1407

    
1408
	$('#btnadvdns').click(function(event) {
1409
		show_advdns();
1410
	});
1411

    
1412
 // Show advanced MAC options ======================================================================================
1413
	var showadvmac = false;
1414

    
1415
	function show_advmac() {
1416
<?php
1417
		if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1418
			$hide = false;
1419
		} else {
1420
			$hide = true;
1421
		}
1422
?>
1423
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1424

    
1425
		hideInput('mac_allow', !showadvmac && !hide);
1426
		hideInput('mac_deny', !showadvmac && !hide);
1427

    
1428
		showadvmac = !showadvmac;
1429
	}
1430

    
1431
	$('#btnadvmac').prop('type', 'button');
1432

    
1433
	$('#btnadvmac').click(function(event) {
1434
		show_advmac(true);
1435
	});
1436

    
1437
  // Show advanced NTP options ======================================================================================
1438
	var showadvntp = false;
1439

    
1440
	function show_advntp() {
1441
<?php
1442
		if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1443
			$hide = false;
1444
		} else {
1445
			$hide = true;
1446
		}
1447
?>
1448
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1449

    
1450
		hideInput('ntp1', !showadvntp && !hide);
1451
		hideInput('ntp2', !showadvntp && !hide);
1452
		hideInput('btnadvntp', hide);
1453

    
1454
		showadvntp = !showadvntp;
1455
	}
1456

    
1457
	$('#btnadvntp').prop('type', 'button');
1458

    
1459
	$('#btnadvntp').click(function(event) {
1460
		show_advntp();
1461
	});
1462

    
1463
   // Show advanced TFTP options ======================================================================================
1464
	var showtftp = false;
1465

    
1466
	function show_advtftp() {
1467
<?php
1468
		if (empty($pconfig['tftp'])) {
1469
			$hide = false;
1470
		} else {
1471
			$hide = true;
1472
		}
1473
?>
1474
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1475

    
1476
		hideInput('tftp', !showtftp & !hide);
1477

    
1478
		showtftp = !showtftp;
1479
	}
1480

    
1481
	$('#btnadvtftp').prop('type', 'button');
1482

    
1483
	$('#btnadvtftp').click(function(event) {
1484
		show_advtftp();
1485
	});
1486

    
1487
   // Show advanced LDAP options ======================================================================================
1488
	var showadvldap = false;
1489

    
1490
	function show_advldap() {
1491
<?php
1492
		if (empty($pconfig['ldap'])) {
1493
			$hide = false;
1494
		} else {
1495
			$hide = true;
1496
		}
1497
?>
1498
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1499

    
1500
		hideInput('ldap', !showadvldap && !hide);
1501
		hideInput('btnadvldap', hide);
1502

    
1503
		showadvldap = !showadvldap;
1504
	}
1505

    
1506
	$('#btnadvldap').prop('type', 'button');
1507

    
1508
	$('#btnadvldap').click(function(event) {
1509
		show_advldap();
1510
	});
1511

    
1512
	// Show advanced additional opts options ===========================================================================
1513
	var showadvopts = false;
1514

    
1515
	function show_advopts() {
1516
<?php
1517
		if (empty($pconfig['numberoptions']) ||
1518
		    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1519
			$hide = false;
1520
		} else {
1521
			$hide = true;
1522
		}
1523
?>
1524
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1525

    
1526
		hideClass('adnlopts', !showadvopts && !hide);
1527
		hideInput('btnadvopts', hide);
1528

    
1529
		showadvopts = !showadvopts;
1530
	}
1531

    
1532
	$('#btnadvopts').prop('type', 'button');
1533

    
1534
	$('#btnadvopts').click(function(event) {
1535
		show_advopts();
1536
	});
1537

    
1538
	// ---------- On initial page load ------------------------------------------------------------
1539

    
1540
	show_advdns();
1541
	show_advmac();
1542
	show_advntp();
1543
	show_advtftp();
1544
	show_advldap();
1545
	show_advopts();
1546

    
1547
	// Suppress "Delete row" button if there are fewer than two rows
1548
	checkLastRow();
1549
});
1550
//]]>
1551
</script>
1552

    
1553
<?php include("foot.inc");
(118-118/227)