Project

General

Profile

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

    
26
##|+PRIV
27
##|*IDENT=page-services-dhcpserver
28
##|*NAME=Services: DHCP Server
29
##|*DESCR=Allow access to the 'Services: DHCP Server' page.
30
##|*MATCH=services_dhcp.php*
31
##|-PRIV
32

    
33
require_once("guiconfig.inc");
34
require_once("filter.inc");
35
require_once('rrd.inc');
36
require_once("shaper.inc");
37

    
38
if (!$g['services_dhcp_server_enable']) {
39
	header("Location: /");
40
	exit;
41
}
42

    
43
$if = $_REQUEST['if'];
44

    
45
/* if OLSRD is enabled, allow WAN to house DHCP. */
46
if ($config['installedpackages']['olsrd']) {
47
	foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
48
		if ($olsrd['enable']) {
49
			$is_olsr_enabled = true;
50
			break;
51
		}
52
	}
53
}
54

    
55
$iflist = get_configured_interface_with_descr();
56

    
57
/* set the starting interface */
58
if (!$if || !isset($iflist[$if])) {
59
	$found_starting_if = false;
60
	// First look for an interface with DHCP already enabled.
61
	foreach ($iflist as $ifent => $ifname) {
62
		$oc = $config['interfaces'][$ifent];
63
		if (is_array($config['dhcpd'][$ifent]) &&
64
		    isset($config['dhcpd'][$ifent]['enable']) &&
65
		    is_ipaddrv4($oc['ipaddr']) && $oc['subnet'] < 31) {
66
			$if = $ifent;
67
			$found_starting_if = true;
68
			break;
69
		}
70
	}
71

    
72
	/*
73
	 * If there is no DHCP-enabled interface and LAN is a candidate,
74
	 * then choose LAN.
75
	 */
76
	if (!$found_starting_if && isset($iflist['lan']) &&
77
	    is_ipaddrv4($config['interfaces']['lan']['ipaddr']) &&
78
	    $config['interfaces']['lan']['subnet'] < 31) {
79
		$if = 'lan';
80
		$found_starting_if = true;
81
	}
82

    
83
	// At the last select whatever can be found.
84
	if (!$found_starting_if) {
85
		foreach ($iflist as $ifent => $ifname) {
86
			$oc = $config['interfaces'][$ifent];
87

    
88
			/* Not static IPv4 or subnet >= 31 */
89
			if (!is_ipaddrv4($oc['ipaddr']) ||
90
			    empty($oc['subnet']) || $oc['subnet'] < 31) {
91
				continue;
92
			}
93

    
94
			if (!is_array($config['dhcpd'][$ifent]) ||
95
			    !isset($config['dhcpd'][$ifent]['enable'])) {
96
				continue;
97
			}
98

    
99
			$if = $ifent;
100
			break;
101
		}
102
	}
103
}
104

    
105
$act = $_REQUEST['act'];
106

    
107
$a_pools = array();
108

    
109
if (is_array($config['dhcpd'][$if])) {
110
	$pool = $_REQUEST['pool'];
111
	if (is_numeric($_POST['pool'])) {
112
		$pool = $_POST['pool'];
113
	}
114

    
115
	// If we have a pool but no interface name, that's not valid. Redirect away.
116
	if (is_numeric($pool) && empty($if)) {
117
		header("Location: services_dhcp.php");
118
		exit;
119
	}
120

    
121
	if (!is_array($config['dhcpd'][$if]['pool'])) {
122
		$config['dhcpd'][$if]['pool'] = array();
123
	}
124

    
125
	$a_pools = &$config['dhcpd'][$if]['pool'];
126

    
127
	if (is_numeric($pool) && $a_pools[$pool]) {
128
		$dhcpdconf = &$a_pools[$pool];
129
	} elseif ($act == "newpool") {
130
		$dhcpdconf = array();
131
	} else {
132
		$dhcpdconf = &$config['dhcpd'][$if];
133
	}
134

    
135
	if (!is_array($config['dhcpd'][$if]['staticmap'])) {
136
		$dhcpdconf['staticmap'] = array();
137
	}
138

    
139
	$a_maps = &$config['dhcpd'][$if]['staticmap'];
140
}
141

    
142
if (is_array($dhcpdconf)) {
143
	// Global Options
144
	if (!is_numeric($pool) && !($act == "newpool")) {
145
		$pconfig['enable'] = isset($dhcpdconf['enable']);
146
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
147
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
148
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
149
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
150

    
151
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
152
		// then show it true/checked.
153
		foreach ($config['dhcpd'] as $dhcpdifitem) {
154
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
155
			if ($dhcpleaseinlocaltime) {
156
				break;
157
			}
158
		}
159

    
160
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
161
	} else {
162
		// Options that exist only in pools
163
		$pconfig['descr'] = $dhcpdconf['descr'];
164
	}
165

    
166
	// Options that can be global or per-pool.
167
	if (is_array($dhcpdconf['range'])) {
168
		$pconfig['range_from'] = $dhcpdconf['range']['from'];
169
		$pconfig['range_to'] = $dhcpdconf['range']['to'];
170
	}
171

    
172
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
173
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
174
	$pconfig['gateway'] = $dhcpdconf['gateway'];
175
	$pconfig['domain'] = $dhcpdconf['domain'];
176
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
177
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
178
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
179
	$pconfig['ignorebootp'] = isset($dhcpdconf['ignorebootp']);
180
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
181
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
182
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
183
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
184
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
185
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
186
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
187
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
188
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
189
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
190
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
191
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
192
	$pconfig['tftp'] = $dhcpdconf['tftp'];
193
	$pconfig['ldap'] = $dhcpdconf['ldap'];
194
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
195
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
196
	$pconfig['filename'] = $dhcpdconf['filename'];
197
	$pconfig['filename32'] = $dhcpdconf['filename32'];
198
	$pconfig['filename64'] = $dhcpdconf['filename64'];
199
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
200
	$pconfig['netmask'] = $dhcpdconf['netmask'];
201
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
202
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
203
}
204

    
205
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
206
$ifcfgsn = $config['interfaces'][$if]['subnet'];
207

    
208
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
209
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
210

    
211
function validate_partial_mac_list($maclist) {
212
	$macs = explode(',', $maclist);
213

    
214
	// Loop through and look for invalid MACs.
215
	foreach ($macs as $mac) {
216
		if (!is_macaddr($mac, true)) {
217
			return false;
218
		}
219
	}
220

    
221
	return true;
222
}
223

    
224
if (isset($_POST['save'])) {
225

    
226
	unset($input_errors);
227

    
228
	$pconfig = $_POST;
229

    
230
	$numberoptions = array();
231
	for ($x = 0; $x < 99; $x++) {
232
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
233
			$numbervalue = array();
234
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
235
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
236
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
237
			$numberoptions['item'][] = $numbervalue;
238
		}
239
	}
240

    
241
	// Reload the new pconfig variable that the form uses.
242
	$pconfig['numberoptions'] = $numberoptions;
243

    
244
	/* input validation */
245

    
246
	// Note: if DHCP Server is not enabled, then it is OK to adjust other parameters without specifying range from-to.
247
	if ($_POST['enable'] || is_numeric($pool) || $act == "newpool") {
248
		$reqdfields = explode(" ", "range_from range_to");
249
		$reqdfieldsn = array(gettext("Range begin"), gettext("Range end"));
250

    
251
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
252
	}
253

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

    
258
	if ($_POST['range_from'] && !is_ipaddrv4($_POST['range_from'])) {
259
		$input_errors[] = gettext("A valid IPv4 address must be specified for range from.");
260
	}
261
	if ($_POST['range_to'] && !is_ipaddrv4($_POST['range_to'])) {
262
		$input_errors[] = gettext("A valid IPv4 address must be specified for range to.");
263
	}
264
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
265
		$input_errors[] = gettext("Range From and Range To must both be entered.");
266
	}
267
	if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
268
		$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
269
	}
270
	if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
271
		$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
272
	}
273
	$parent_ip = get_interface_ip($_POST['if']);
274
	if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
275
		$parent_sn = get_interface_subnet($_POST['if']);
276
		if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
277
			$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
278
		}
279
	}
280

    
281
	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']))) {
282
		$input_errors[] = gettext("A valid IP address must be specified for each of the DNS servers.");
283
	}
284

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

    
289
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
290
		$deftime = 7200; // Default value if it's empty
291
		if (is_numeric($_POST['deftime'])) {
292
			$deftime = $_POST['deftime'];
293
		}
294

    
295
		foreach ($config['captiveportal'] as $cpZone => $cpdata) {
296
			if (!isset($cpdata['enable'])) {
297
				continue;
298
			}
299
			if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
300
				continue;
301
			}
302
			$cp_ifs = explode(',', $cpdata['interface']);
303
			if (!in_array($if, $cp_ifs)) {
304
				continue;
305
			}
306
			if ($cpdata['timeout'] > $deftime) {
307
				$input_errors[] = sprintf(gettext(
308
					'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
309
			}
310
		}
311
	}
312

    
313
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
314
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
315
	}
316
	if (($_POST['ddnsdomain'] && !is_domain($_POST['ddnsdomain']))) {
317
		$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
318
	}
319
	if (($_POST['ddnsdomain'] && !is_ipaddrv4($_POST['ddnsdomainprimary']))) {
320
		$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
321
	}
322
	if (($_POST['ddnsdomainkey'] && !$_POST['ddnsdomainkeyname']) ||
323
		($_POST['ddnsdomainkeyname'] && !$_POST['ddnsdomainkey'])) {
324
		$input_errors[] = gettext("Both a valid domain key and key name must be specified.");
325
	}
326
	if ($_POST['domainsearchlist']) {
327
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
328
		foreach ($domain_array as $curdomain) {
329
			if (!is_domain($curdomain)) {
330
				$input_errors[] = gettext("A valid domain search list must be specified.");
331
				break;
332
			}
333
		}
334
	}
335

    
336
	// Validate MACs
337
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
338
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
339
	}
340
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
341
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
342
	}
343

    
344
	if (($_POST['ntp1'] && (!is_ipaddrv4($_POST['ntp1']) && !is_hostname($_POST['ntp1']))) || ($_POST['ntp2'] && (!is_ipaddrv4($_POST['ntp2']) && !is_hostname($_POST['ntp2'])))) {
345
		$input_errors[] = gettext("A valid IP address or hostname must be specified for the primary/secondary NTP servers.");
346
	}
347
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
348
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
349
	}
350
	if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !filter_var($_POST['tftp'], FILTER_VALIDATE_URL)) {
351
		$input_errors[] = gettext("A valid IP address, hostname or URL must be specified for the TFTP server.");
352
	}
353
	if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
354
		$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
355
	}
356

    
357
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
358
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
359
	}
360
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
361
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
362
	}
363

    
364
	// Disallow a range that includes the virtualip
365
	if (is_array($config['virtualip']['vip'])) {
366
		foreach ($config['virtualip']['vip'] as $vip) {
367
			if ($vip['interface'] == $if) {
368
				if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
369
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
370
				}
371
			}
372
		}
373
	}
374

    
375
	$noip = false;
376
	if (is_array($a_maps)) {
377
		foreach ($a_maps as $map) {
378
			if (empty($map['ipaddr'])) {
379
				$noip = true;
380
			}
381
		}
382
	}
383

    
384
	if ($_POST['staticarp'] && $noip) {
385
		$input_errors[] = gettext("Cannot enable static ARP when there are static map entries without IP addresses. Ensure all static maps have IP addresses and try again.");
386
	}
387

    
388
	if (is_array($pconfig['numberoptions']['item'])) {
389
		foreach ($pconfig['numberoptions']['item'] as $numberoption) {
390
			$numberoption_value = base64_decode($numberoption['value']);
391
			if ($numberoption['type'] == 'text' && strstr($numberoption_value, '"')) {
392
				$input_errors[] = gettext("Text type cannot include quotation marks.");
393
			} else if ($numberoption['type'] == 'string' && !preg_match('/^"[^"]*"$/', $numberoption_value) && !preg_match('/^[0-9a-f]{2}(?:\:[0-9a-f]{2})*$/i', $numberoption_value)) {
394
				$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");
395
			} else if ($numberoption['type'] == 'boolean' && $numberoption_value != 'true' && $numberoption_value != 'false' && $numberoption_value != 'on' && $numberoption_value != 'off') {
396
				$input_errors[] = gettext("Boolean type must be true, false, on, or off.");
397
			} else if ($numberoption['type'] == 'unsigned integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 255)) {
398
				$input_errors[] = gettext("Unsigned 8-bit integer type must be a number in the range 0 to 255.");
399
			} else if ($numberoption['type'] == 'unsigned integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 65535)) {
400
				$input_errors[] = gettext("Unsigned 16-bit integer type must be a number in the range 0 to 65535.");
401
			} else if ($numberoption['type'] == 'unsigned integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 4294967295)) {
402
				$input_errors[] = gettext("Unsigned 32-bit integer type must be a number in the range 0 to 4294967295.");
403
			} else if ($numberoption['type'] == 'signed integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < -128 || $numberoption_value > 127)) {
404
				$input_errors[] = gettext("Signed 8-bit integer type must be a number in the range -128 to 127.");
405
			} else if ($numberoption['type'] == 'signed integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < -32768 || $numberoption_value > 32767)) {
406
				$input_errors[] = gettext("Signed 16-bit integer type must be a number in the range -32768 to 32767.");
407
			} else if ($numberoption['type'] == 'signed integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < -2147483648 || $numberoption_value > 2147483647)) {
408
				$input_errors[] = gettext("Signed 32-bit integer type must be a number in the range -2147483648 to 2147483647.");
409
			} else if ($numberoption['type'] == 'ip-address' && !is_ipaddrv4($numberoption_value) && !is_hostname($numberoption_value)) {
410
				$input_errors[] = gettext("IP address or host type must be an IP address or host name.");
411
			}
412
		}
413
	}
414

    
415
	if ((!isset($pool) || !is_numeric($pool)) && $act != "newpool") {
416
		/* If enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
417
		if ($_POST['enable'] && isset($config['dhcrelay']['enable']) &&
418
		    (stristr($config['dhcrelay']['interface'], $if) !== false)) {
419
			$input_errors[] = sprintf(gettext(
420
			    "The DHCP relay on the %s interface must be disabled before enabling the DHCP server."),
421
			    $iflist[$if]);
422
		}
423

    
424
		/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
425
		if (!$_POST['enable']) {
426
			if (isset($config['dnsmasq']['enable']) &&
427
			    (isset($config['dnsmasq']['regdhcp']) ||
428
			    isset($config['dnsmasq']['regdhcpstatic']) ||
429
			    isset($config['dnsmasq']['dhcpfirst']))) {
430
				$input_errors[] = gettext(
431
				    "Disable DHCP Registration features in DNS Forwarder before disabling DHCP Server.");
432
			}
433
			if (isset($config['unbound']['enable']) &&
434
			    (isset($config['unbound']['regdhcp']) ||
435
			    isset($config['unbound']['regdhcpstatic']))) {
436
				$input_errors[] = gettext(
437
				    "Disable DHCP Registration features in DNS Resolver before disabling DHCP Server.");
438
			}
439
		}
440
	}
441

    
442
	// If nothing is wrong so far, and we have range from and to, then check conditions related to the values of range from and to.
443
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
444
		/* make sure the range lies within the current subnet */
445
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
446
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
447
		}
448

    
449
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
450
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
451
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
452
		}
453

    
454
		if (is_numeric($pool) || ($act == "newpool")) {
455
			if (is_inrange_v4($_POST['range_from'],
456
				$config['dhcpd'][$if]['range']['from'],
457
				$config['dhcpd'][$if]['range']['to']) ||
458
				is_inrange_v4($_POST['range_to'],
459
				$config['dhcpd'][$if]['range']['from'],
460
				$config['dhcpd'][$if]['range']['to'])) {
461
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
462
			}
463
		}
464

    
465
		foreach ($a_pools as $id => $p) {
466
			if (is_numeric($pool) && ($id == $pool)) {
467
				continue;
468
			}
469

    
470
			if (is_inrange_v4($_POST['range_from'],
471
				$p['range']['from'], $p['range']['to']) ||
472
				is_inrange_v4($_POST['range_to'],
473
				$p['range']['from'], $p['range']['to'])) {
474
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
475
				break;
476
			}
477
		}
478

    
479
		if (is_array($a_maps)) {
480
			foreach ($a_maps as $map) {
481
				if (empty($map['ipaddr'])) {
482
					continue;
483
				}
484
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
485
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
486
					break;
487
				}
488
			}
489
		}
490
	}
491

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

    
515
		$dhcpd_enable_changed = false;
516

    
517
		// Global Options
518
		if (!is_numeric($pool) && !($act == "newpool")) {
519
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
520
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
521
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
522
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
523
				$dhcpd_enable_changed = true;
524
			}
525

    
526
			$dhcpdconf['enable'] = $new_dhcpd_enable;
527
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
528
			$previous = $dhcpdconf['failover_peerip'];
529
			if ($previous != $_POST['failover_peerip']) {
530
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
531
			}
532

    
533
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
534
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
535
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
536
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
537
			}
538
		} else {
539
			// Options that exist only in pools
540
			$dhcpdconf['descr'] = $_POST['descr'];
541
		}
542

    
543
		// Options that can be global or per-pool.
544
		$dhcpdconf['range']['from'] = $_POST['range_from'];
545
		$dhcpdconf['range']['to'] = $_POST['range_to'];
546
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
547
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
548
		$dhcpdconf['netmask'] = $_POST['netmask'];
549

    
550
		unset($dhcpdconf['winsserver']);
551
		if ($_POST['wins1']) {
552
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
553
		}
554
		if ($_POST['wins2']) {
555
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
556
		}
557

    
558
		unset($dhcpdconf['dnsserver']);
559
		if ($_POST['dns1']) {
560
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
561
		}
562
		if ($_POST['dns2']) {
563
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
564
		}
565
		if ($_POST['dns3']) {
566
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
567
		}
568
		if ($_POST['dns4']) {
569
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
570
		}
571

    
572
		$dhcpdconf['gateway'] = $_POST['gateway'];
573
		$dhcpdconf['domain'] = $_POST['domain'];
574
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
575
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
576
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
577
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
578
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
579
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
580
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
581
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
582
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
583
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
584
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
585
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
586
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
587

    
588
		unset($dhcpdconf['ntpserver']);
589
		if ($_POST['ntp1']) {
590
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
591
		}
592
		if ($_POST['ntp2']) {
593
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
594
		}
595

    
596
		$dhcpdconf['tftp'] = $_POST['tftp'];
597
		$dhcpdconf['ldap'] = $_POST['ldap'];
598
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
599
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
600
		$dhcpdconf['filename'] = $_POST['filename'];
601
		$dhcpdconf['filename32'] = $_POST['filename32'];
602
		$dhcpdconf['filename64'] = $_POST['filename64'];
603
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
604
		unset($dhcpdconf['statsgraph']);
605
		if ($_POST['statsgraph']) {
606
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
607
			enable_rrd_graphing();
608
		}
609

    
610
		// Handle the custom options rowhelper
611
		if (isset($dhcpdconf['numberoptions']['item'])) {
612
			unset($dhcpdconf['numberoptions']['item']);
613
		}
614

    
615
		$dhcpdconf['numberoptions'] = $numberoptions;
616

    
617
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
618
			$a_pools[$pool] = $dhcpdconf;
619
		} elseif ($act == "newpool") {
620
			$a_pools[] = $dhcpdconf;
621
		} else {
622
			$config['dhcpd'][$if] = $dhcpdconf;
623
		}
624

    
625
		write_config();
626
	}
627
}
628

    
629
if ((isset($_POST['save']) || isset($_POST['apply'])) && (!$input_errors)) {
630
	$changes_applied = true;
631
	$retval = 0;
632
	$retvaldhcp = 0;
633
	$retvaldns = 0;
634
	/* dnsmasq_configure calls dhcpd_configure */
635
	/* no need to restart dhcpd twice */
636
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
637
		$retvaldns |= services_dnsmasq_configure();
638
		if ($retvaldns == 0) {
639
			clear_subsystem_dirty('hosts');
640
			clear_subsystem_dirty('staticmaps');
641
		}
642
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
643
		$retvaldns |= services_unbound_configure();
644
		if ($retvaldns == 0) {
645
			clear_subsystem_dirty('unbound');
646
			clear_subsystem_dirty('hosts');
647
			clear_subsystem_dirty('staticmaps');
648
		}
649
	} else {
650
		$retvaldhcp |= services_dhcpd_configure();
651
		if ($retvaldhcp == 0) {
652
			clear_subsystem_dirty('staticmaps');
653
		}
654
	}
655
	/* BIND package - Bug #3710 */
656
	if (!function_exists('is_package_installed')) {
657
		require_once('pkg-utils.inc');
658
	}
659
	if (is_package_installed('pfSense-pkg-bind') && isset($config['installedpackages']['bind']['config'][0]['enable_bind'])) {
660
		$reloadbind = false;
661
		if (is_array($config['installedpackages']['bindzone'])) {
662
			$bindzone = $config['installedpackages']['bindzone']['config'];
663
		} else {
664
			$bindzone = array();
665
		}
666
		for ($x = 0; $x < sizeof($bindzone); $x++) {
667
			$zone = $bindzone[$x];
668
			if ($zone['regdhcpstatic'] == 'on') {
669
				$reloadbind = true;
670
				break;
671
			}
672
		}
673
		if ($reloadbind === true) {
674
			if (file_exists("/usr/local/pkg/bind.inc")) {
675
				require_once("/usr/local/pkg/bind.inc");
676
				bind_sync();
677
			}
678
		}
679
	}
680
	if ($dhcpd_enable_changed) {
681
		$retvalfc |= filter_configure();
682
	}
683

    
684
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
685
		$retval = 1;
686
	}
687
}
688

    
689
if ($act == "delpool") {
690
	if ($a_pools[$_POST['id']]) {
691
		unset($a_pools[$_POST['id']]);
692
		write_config();
693
		header("Location: services_dhcp.php?if={$if}");
694
		exit;
695
	}
696
}
697

    
698
if ($act == "del") {
699
	if (isset($a_maps[$_POST['id']])) {
700
		/* Remove static ARP entry, if necessary */
701
		if (isset($a_maps[$_POST['id']]['arp_table_static_entry'])) {
702
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_POST['id']]['ipaddr']));
703
		}
704
		unset($a_maps[$_POST['id']]);
705
		write_config();
706
		if (isset($config['dhcpd'][$if]['enable'])) {
707
			mark_subsystem_dirty('staticmaps');
708
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
709
				mark_subsystem_dirty('hosts');
710
			}
711
		}
712

    
713
		header("Location: services_dhcp.php?if={$if}");
714
		exit;
715
	}
716
}
717

    
718
// Build an HTML table that can be inserted into a Form_StaticText element
719
function build_pooltable() {
720
	global $a_pools, $if;
721

    
722
	$pooltbl =	'<div class="table-responsive">';
723
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
724
	$pooltbl .=			'<thead>';
725
	$pooltbl .=				'<tr>';
726
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
727
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
728
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
729
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
730
	$pooltbl .=				'</tr>';
731
	$pooltbl .=			'</thead>';
732
	$pooltbl .=			'<tbody>';
733

    
734
	if (is_array($a_pools)) {
735
		$i = 0;
736
		foreach ($a_pools as $poolent) {
737
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
738
				$pooltbl .= '<tr>';
739
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
740
							htmlspecialchars($poolent['range']['from']) . '</td>';
741

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

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

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

    
750
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" usepost></a></td>';
751
				$pooltbl .= '</tr>';
752
			}
753
		$i++;
754
		}
755
	}
756

    
757
	$pooltbl .=			'</tbody>';
758
	$pooltbl .=		'</table>';
759
	$pooltbl .= '</div>';
760

    
761
	return($pooltbl);
762
}
763

    
764
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
765
$pglinks = array("", "services_dhcp.php");
766

    
767
if (!empty($if) && isset($iflist[$if])) {
768
	$pgtitle[] = $iflist[$if];
769
	$pglinks[] = "@self";
770
}
771
$shortcut_section = "dhcp";
772

    
773
include("head.inc");
774

    
775
if ($input_errors) {
776
	print_input_errors($input_errors);
777
}
778

    
779
if ($changes_applied) {
780
	print_apply_result_box($retval);
781
}
782

    
783
if (is_subsystem_dirty('staticmaps')) {
784
	print_apply_box(gettext("The static mapping configuration has been changed.") . "<br />" . gettext("The changes must be applied for them to take effect."));
785
}
786

    
787
/* active tabs */
788
$tab_array = array();
789
$tabscounter = 0;
790
$i = 0;
791
$have_small_subnet = false;
792

    
793
foreach ($iflist as $ifent => $ifname) {
794
	$oc = $config['interfaces'][$ifent];
795

    
796
	/* Not static IPv4 or subnet >= 31 */
797
	if ($oc['subnet'] >= 31) {
798
		$have_small_subnet = true;
799
		$example_name = $ifname;
800
		$example_cidr = $oc['subnet'];
801
		continue;
802
	}
803
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
804
		continue;
805
	}
806

    
807
	if ($ifent == $if) {
808
		$active = true;
809
	} else {
810
		$active = false;
811
	}
812

    
813
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
814
	$tabscounter++;
815
}
816

    
817
if ($tabscounter == 0) {
818
	if ($have_small_subnet) {
819
		$sentence2 = sprintf(gettext('%1$s has a CIDR mask of %2$s, which does not contain enough addresses.'), htmlspecialchars($example_name), htmlspecialchars($example_cidr));
820
	} else {
821
		$sentence2 = gettext("This system has no interfaces configured with a static IPv4 address.");
822
	}
823
	print_info_box(gettext("The DHCP Server requires a static IPv4 subnet large enough to serve addresses to clients.") . " " . $sentence2);
824
	include("foot.inc");
825
	exit;
826
}
827

    
828
display_top_tabs($tab_array);
829

    
830
$form = new Form();
831

    
832
$section = new Form_Section('General Options');
833

    
834
if (!is_numeric($pool) && !($act == "newpool")) {
835
	if (isset($config['dhcrelay']['enable'])) {
836
		$section->addInput(new Form_Checkbox(
837
			'enable',
838
			'Enable',
839
			gettext("DHCP Relay is currently enabled. DHCP Server canot be enabled while the DHCP Relay is enabled on any interface."),
840
			$pconfig['enable']
841
		))->setAttribute('disabled', true);
842
	} else {
843
		$section->addInput(new Form_Checkbox(
844
			'enable',
845
			'Enable',
846
			sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
847
			$pconfig['enable']
848
		));
849
	}
850
} else {
851
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
852
}
853

    
854
$section->addInput(new Form_Checkbox(
855
	'ignorebootp',
856
	'BOOTP',
857
	'Ignore BOOTP queries',
858
	$pconfig['ignorebootp']
859
));
860

    
861
$section->addInput(new Form_Checkbox(
862
	'denyunknown',
863
	'Deny unknown clients',
864
	'Only the clients defined below will get DHCP leases from this server.',
865
	$pconfig['denyunknown']
866
));
867

    
868
$section->addInput(new Form_Checkbox(
869
	'nonak',
870
	'Ignore denied clients',
871
	'Denied clients will be ignored rather than rejected.',
872
	$pconfig['nonak']
873
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
874

    
875
$section->addInput(new Form_Checkbox(
876
	'ignoreclientuids',
877
	'Ignore client identifiers',
878
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
879
	$pconfig['ignoreclientuids']
880
))->setHelp("This option may be useful when a client can dual boot using different client identifiers but the same hardware (MAC) address.  Note that the resulting server behavior violates the official DHCP specification.");
881

    
882

    
883
if (is_numeric($pool) || ($act == "newpool")) {
884
	$section->addInput(new Form_Input(
885
		'descr',
886
		'Pool Description',
887
		'text',
888
		$pconfig['descr']
889
	));
890
}
891

    
892
$section->addInput(new Form_StaticText(
893
	'Subnet',
894
	gen_subnet($ifcfgip, $ifcfgsn)
895
));
896

    
897
$section->addInput(new Form_StaticText(
898
	'Subnet mask',
899
	gen_subnet_mask($ifcfgsn)
900
));
901

    
902
// Compose a string to display the required address ranges
903
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
904

    
905
if (is_numeric($pool) || ($act == "newpool")) {
906
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
907
	if (is_array($config['dhcpd'][$if]['range'])) {
908
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
909
	}
910

    
911
	foreach ($a_pools as $p) {
912
		if (is_array($p['range'])) {
913
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
914
		}
915
	}
916
}
917

    
918
$section->addInput(new Form_StaticText(
919
	'Available range',
920
	$rangestr
921
));
922

    
923
if ($is_olsr_enabled) {
924
	$section->addInput(new Form_Select(
925
		'netmask',
926
		'Subnet mask',
927
		$pconfig['netmask'],
928
		array_combine(range(32, 1, -1), range(32, 1, -1))
929
	));
930
}
931

    
932
$group = new Form_Group('*Range');
933

    
934
$group->add(new Form_IpAddress(
935
	'range_from',
936
	null,
937
	$pconfig['range_from'],
938
	'V4'
939
))->setHelp('From');
940

    
941
$group->add(new Form_IpAddress(
942
	'range_to',
943
	null,
944
	$pconfig['range_to'],
945
	'V4'
946
))->setHelp('To');
947

    
948
$section->add($group);
949

    
950
$form->add($section);
951

    
952
if (!is_numeric($pool) && !($act == "newpool")) {
953
	$section = new Form_Section('Additional Pools');
954

    
955
	$btnaddpool = new Form_Button(
956
		'btnaddpool',
957
		'Add pool',
958
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
959
		'fa-plus'
960
	);
961
	$btnaddpool->addClass('btn-success');
962

    
963
	$section->addInput(new Form_StaticText(
964
		'Add',
965
		$btnaddpool
966
	))->setHelp('If additional pools of addresses are needed inside of this subnet outside the above Range, they may be specified here.');
967

    
968
	if (is_array($a_pools)) {
969
		$section->addInput(new Form_StaticText(
970
			null,
971
			build_pooltable()
972
		));
973
	}
974

    
975
	$form->add($section);
976
}
977

    
978
$section = new Form_Section('Servers');
979

    
980
$section->addInput(new Form_IpAddress(
981
	'wins1',
982
	'WINS servers',
983
	$pconfig['wins1'],
984
	'V4'
985
))->setAttribute('placeholder', 'WINS Server 1');
986

    
987
$section->addInput(new Form_IpAddress(
988
	'wins2',
989
	null,
990
	$pconfig['wins2'],
991
	'V4'
992
))->setAttribute('placeholder', 'WINS Server 2');
993

    
994
for ($idx=1; $idx<=4; $idx++) {
995
	$section->addInput(new Form_IpAddress(
996
		'dns' . $idx,
997
		($idx == 1) ? 'DNS servers':null,
998
		$pconfig['dns' . $idx],
999
		'V4'
1000
	))->setAttribute('placeholder', 'DNS Server ' . $idx)->setHelp(($idx == 4) ? 'Leave blank to use the system default DNS servers: this interface\'s IP if DNS Forwarder or Resolver is enabled, otherwise the servers configured on the System / General Setup page.':'');
1001
}
1002

    
1003
$form->add($section);
1004

    
1005
$section = new Form_Section('Other Options');
1006

    
1007
$section->addInput(new Form_IpAddress(
1008
	'gateway',
1009
	'Gateway',
1010
	$pconfig['gateway'],
1011
	'V4'
1012
))->setPattern('[.a-zA-Z0-9_]+')
1013
  ->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 the network. Type "none" for no gateway assignment.');
1014

    
1015
$section->addInput(new Form_Input(
1016
	'domain',
1017
	'Domain name',
1018
	'text',
1019
	$pconfig['domain']
1020
))->setHelp('The default is to use the domain name of this system as the default domain name provided by DHCP. An alternate domain name may be specified here.');
1021

    
1022
$section->addInput(new Form_Input(
1023
	'domainsearchlist',
1024
	'Domain search list',
1025
	'text',
1026
	$pconfig['domainsearchlist']
1027
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
1028

    
1029
$section->addInput(new Form_Input(
1030
	'deftime',
1031
	'Default lease time',
1032
	'number',
1033
	$pconfig['deftime']
1034
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds.');
1035

    
1036
$section->addInput(new Form_Input(
1037
	'maxtime',
1038
	'Maximum lease time',
1039
	'number',
1040
	$pconfig['maxtime']
1041
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds.');
1042

    
1043
if (!is_numeric($pool) && !($act == "newpool")) {
1044
	$section->addInput(new Form_IpAddress(
1045
		'failover_peerip',
1046
		'Failover peer IP',
1047
		$pconfig['failover_peerip'],
1048
		'V4'
1049
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
1050
				'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).');
1051
}
1052

    
1053
if (!is_numeric($pool) && !($act == "newpool")) {
1054
	$section->addInput(new Form_Checkbox(
1055
		'staticarp',
1056
		'Static ARP',
1057
		'Enable Static ARP entries',
1058
		$pconfig['staticarp']
1059
	))->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.');
1060

    
1061
	$section->addInput(new Form_Checkbox(
1062
		'dhcpleaseinlocaltime',
1063
		'Time format change',
1064
		'Change DHCP display lease time from UTC to local time',
1065
		$pconfig['dhcpleaseinlocaltime']
1066
	))->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.' .
1067
				' This will be used for all DHCP interfaces lease time.');
1068
	$section->addInput(new Form_Checkbox(
1069
		'statsgraph',
1070
		'Statistics graphs',
1071
		'Enable RRD statistics graphs',
1072
		$pconfig['statsgraph']
1073
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1074
}
1075

    
1076
// DDNS
1077
$btnadv = new Form_Button(
1078
	'btnadvdns',
1079
	'Display Advanced',
1080
	null,
1081
	'fa-cog'
1082
);
1083

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

    
1086
$section->addInput(new Form_StaticText(
1087
	'Dynamic DNS',
1088
	$btnadv
1089
));
1090

    
1091
$section->addInput(new Form_Checkbox(
1092
	'ddnsupdate',
1093
	null,
1094
	'Enable registration of DHCP client names in DNS',
1095
	$pconfig['ddnsupdate']
1096
));
1097

    
1098
$section->addInput(new Form_Input(
1099
	'ddnsdomain',
1100
	'DDNS Domain',
1101
	'text',
1102
	$pconfig['ddnsdomain']
1103
))->setHelp('Leave blank to disable dynamic DNS registration.%1$s' .
1104
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.', '<br />');
1105

    
1106
$section->addInput(new Form_Checkbox(
1107
	'ddnsforcehostname',
1108
	'DDNS Hostnames',
1109
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1110
	$pconfig['ddnsforcehostname']
1111
))->setHelp('Default registers host name option supplied by DHCP client.');
1112

    
1113
$section->addInput(new Form_IpAddress(
1114
	'ddnsdomainprimary',
1115
	'Primary DDNS address',
1116
	$pconfig['ddnsdomainprimary'],
1117
	'V4'
1118
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1119

    
1120
$section->addInput(new Form_Input(
1121
	'ddnsdomainkeyname',
1122
	'DNS Domain key',
1123
	'text',
1124
	$pconfig['ddnsdomainkeyname']
1125
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1126

    
1127
$section->addInput(new Form_Input(
1128
	'ddnsdomainkey',
1129
	'DNS Domain key secret',
1130
	'text',
1131
	$pconfig['ddnsdomainkey']
1132
))->setHelp('Dynamic DNS domain key secret (HMAC-MD5) which will be used to register client names in the DNS server.');
1133

    
1134
// Advanced MAC
1135
$btnadv = new Form_Button(
1136
	'btnadvmac',
1137
	'Display Advanced',
1138
	null,
1139
	'fa-cog'
1140
);
1141

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

    
1144
$section->addInput(new Form_StaticText(
1145
	'MAC address control',
1146
	$btnadv
1147
));
1148

    
1149
$section->addInput(new Form_Input(
1150
	'mac_allow',
1151
	'MAC Allow',
1152
	'text',
1153
	$pconfig['mac_allow']
1154
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1155

    
1156
$section->addInput(new Form_Input(
1157
	'mac_deny',
1158
	'MAC Deny',
1159
	'text',
1160
	$pconfig['mac_deny']
1161
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1162

    
1163
// Advanced NTP
1164
$btnadv = new Form_Button(
1165
	'btnadvntp',
1166
	'Display Advanced',
1167
	null,
1168
	'fa-cog'
1169
);
1170

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

    
1173
$section->addInput(new Form_StaticText(
1174
	'NTP',
1175
	$btnadv
1176
));
1177

    
1178
$section->addInput(new Form_IpAddress(
1179
	'ntp1',
1180
	'NTP Server 1',
1181
	$pconfig['ntp1'],
1182
	'HOSTV4'
1183
));
1184

    
1185
$section->addInput(new Form_IpAddress(
1186
	'ntp2',
1187
	'NTP Server 2',
1188
	$pconfig['ntp2'],
1189
	'HOSTV4'
1190
));
1191

    
1192
// Advanced TFTP
1193
$btnadv = new Form_Button(
1194
	'btnadvtftp',
1195
	'Display Advanced',
1196
	null,
1197
	'fa-cog'
1198
);
1199

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

    
1202
$section->addInput(new Form_StaticText(
1203
	'TFTP',
1204
	$btnadv
1205
));
1206

    
1207
$section->addInput(new Form_Input(
1208
	'tftp',
1209
	'TFTP Server',
1210
	'text',
1211
	$pconfig['tftp']
1212
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1213

    
1214
// Advanced LDAP
1215
$btnadv = new Form_Button(
1216
	'btnadvldap',
1217
	'Display Advanced',
1218
	null,
1219
	'fa-cog'
1220
);
1221

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

    
1224
$section->addInput(new Form_StaticText(
1225
	'LDAP',
1226
	$btnadv
1227
));
1228

    
1229
$section->addInput(new Form_Input(
1230
	'ldap',
1231
	'LDAP Server URI',
1232
	'text',
1233
	$pconfig['ldap']
1234
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1235

    
1236
// Advanced Network Booting options
1237
$btnadv = new Form_Button(
1238
	'btnadvnwkboot',
1239
	'Display Advanced',
1240
	null,
1241
	'fa-cog'
1242
);
1243

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

    
1246
$section->addInput(new Form_StaticText(
1247
	'Network Booting',
1248
	$btnadv
1249
));
1250

    
1251
$section->addInput(new Form_Checkbox(
1252
	'netboot',
1253
	'Enable',
1254
	'Enables network booting',
1255
	$pconfig['netboot']
1256
));
1257

    
1258
$section->addInput(new Form_IpAddress(
1259
	'nextserver',
1260
	'Next Server',
1261
	$pconfig['nextserver'],
1262
	'V4'
1263
))->setHelp('Enter the IP address of the next server');
1264

    
1265
$section->addInput(new Form_Input(
1266
	'filename',
1267
	'Default BIOS file name',
1268
	'text',
1269
	$pconfig['filename']
1270
));
1271

    
1272
$section->addInput(new Form_Input(
1273
	'filename32',
1274
	'UEFI 32 bit file name',
1275
	'text',
1276
	$pconfig['filename32']
1277
));
1278

    
1279
$section->addInput(new Form_Input(
1280
	'filename64',
1281
	'UEFI 64 bit file name',
1282
	'text',
1283
	$pconfig['filename64']
1284
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1285
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1286

    
1287
$section->addInput(new Form_Input(
1288
	'rootpath',
1289
	'Root path',
1290
	'text',
1291
	$pconfig['rootpath']
1292
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1293

    
1294
// Advanced Additional options
1295
$btnadv = new Form_Button(
1296
	'btnadvopts',
1297
	'Display Advanced',
1298
	null,
1299
	'fa-cog'
1300
);
1301

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

    
1304
$section->addInput(new Form_StaticText(
1305
	'Additional BOOTP/DHCP Options',
1306
	$btnadv
1307
));
1308

    
1309
$form->add($section);
1310

    
1311
$section = new Form_Section('Additional BOOTP/DHCP Options');
1312
$section->addClass('adnlopts');
1313

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

    
1320
if (!$pconfig['numberoptions']) {
1321
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1322
}
1323

    
1324
$customitemtypes = array(
1325
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1326
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1327
	'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')
1328
);
1329

    
1330
$numrows = count($item) -1;
1331
$counter = 0;
1332

    
1333
$numrows = count($pconfig['numberoptions']['item']) -1;
1334

    
1335
foreach ($pconfig['numberoptions']['item'] as $item) {
1336
	$number = $item['number'];
1337
	$itemtype = $item['type'];
1338
	$value = base64_decode($item['value']);
1339

    
1340
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1341
	$group->addClass('repeatable');
1342

    
1343
	$group->add(new Form_Input(
1344
		'number' . $counter,
1345
		null,
1346
		'text',
1347
		$number
1348
	))->setHelp($numrows == $counter ? 'Number':null);
1349

    
1350

    
1351
	$group->add(new Form_Select(
1352
		'itemtype' . $counter,
1353
		null,
1354
		$itemtype,
1355
		$customitemtypes
1356
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1357

    
1358
	$group->add(new Form_Input(
1359
		'value' . $counter,
1360
		null,
1361
		'text',
1362
		$value
1363
	))->setHelp($numrows == $counter ? 'Value':null);
1364

    
1365
	$group->add(new Form_Button(
1366
		'deleterow' . $counter,
1367
		'Delete',
1368
		null,
1369
		'fa-trash'
1370
	))->addClass('btn-warning');
1371

    
1372
	$section->add($group);
1373

    
1374
	$counter++;
1375
}
1376

    
1377
$section->addInput(new Form_Button(
1378
	'addrow',
1379
	'Add',
1380
	null,
1381
	'fa-plus'
1382
))->addClass('btn-success');
1383

    
1384
$form->add($section);
1385

    
1386
if ($act == "newpool") {
1387
	$form->addGlobal(new Form_Input(
1388
		'act',
1389
		null,
1390
		'hidden',
1391
		'newpool'
1392
	));
1393
}
1394

    
1395
if (is_numeric($pool)) {
1396
	$form->addGlobal(new Form_Input(
1397
		'pool',
1398
		null,
1399
		'hidden',
1400
		$pool
1401
	));
1402
}
1403

    
1404
$form->addGlobal(new Form_Input(
1405
	'if',
1406
	null,
1407
	'hidden',
1408
	$if
1409
));
1410

    
1411
print($form);
1412

    
1413
// DHCP Static Mappings table
1414

    
1415
if (!is_numeric($pool) && !($act == "newpool")) {
1416

    
1417
	// Decide whether display of the Client Id column is needed.
1418
	$got_cid = false;
1419
	if (is_array($a_maps)) {
1420
		foreach ($a_maps as $map) {
1421
			if (!empty($map['cid'])) {
1422
				$got_cid = true;
1423
				break;
1424
			}
1425
		}
1426
	}
1427
?>
1428

    
1429
<div class="panel panel-default">
1430
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1431
	<div class="table-responsive">
1432
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1433
				<thead>
1434
					<tr>
1435
						<th><?=gettext("Static ARP")?></th>
1436
						<th><?=gettext("MAC address")?></th>
1437
<?php
1438
	if ($got_cid):
1439
?>
1440
						<th><?=gettext("Client Id")?></th>
1441
<?php
1442
	endif;
1443
?>
1444
						<th><?=gettext("IP address")?></th>
1445
						<th><?=gettext("Hostname")?></th>
1446
						<th><?=gettext("Description")?></th>
1447
						<th></th>
1448
					</tr>
1449
				</thead>
1450
<?php
1451
	if (is_array($a_maps)) {
1452
		$i = 0;
1453
?>
1454
				<tbody>
1455
<?php
1456
		foreach ($a_maps as $mapent) {
1457
?>
1458
					<tr>
1459
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1460
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1461
								<i class="fa fa-check"></i>
1462
							<?php endif; ?>
1463
						</td>
1464
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1465
							<?=htmlspecialchars($mapent['mac'])?>
1466
						</td>
1467
<?php
1468
			if ($got_cid):
1469
?>
1470
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1471
							<?=htmlspecialchars($mapent['cid'])?>
1472
						</td>
1473
<?php
1474
			endif;
1475
?>
1476
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1477
							<?=htmlspecialchars($mapent['ipaddr'])?>
1478
						</td>
1479
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1480
							<?=htmlspecialchars($mapent['hostname'])?>
1481
						</td>
1482
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1483
							<?=htmlspecialchars($mapent['descr'])?>
1484
						</td>
1485
						<td>
1486
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1487
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
1488
						</td>
1489
					</tr>
1490
<?php
1491
		$i++;
1492
		}
1493
?>
1494
				</tbody>
1495
<?php
1496
	}
1497
?>
1498
		</table>
1499
	</div>
1500
</div>
1501

    
1502
<nav class="action-buttons">
1503
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1504
		<i class="fa fa-plus icon-embed-btn"></i>
1505
		<?=gettext("Add")?>
1506
	</a>
1507
</nav>
1508
<?php
1509
}
1510
?>
1511

    
1512
<script type="text/javascript">
1513
//<![CDATA[
1514
events.push(function() {
1515

    
1516
	// Show advanced DNS options ======================================================================================
1517
	var showadvdns = false;
1518

    
1519
	function show_advdns(ispageload) {
1520
		var text;
1521
		// On page load decide the initial state based on the data.
1522
		if (ispageload) {
1523
<?php
1524
			if (!$pconfig['ddnsupdate'] && !$pconfig['ddnsforcehostname'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1525
			    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1526
				$showadv = false;
1527
			} else {
1528
				$showadv = true;
1529
			}
1530
?>
1531
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1532
		} else {
1533
			// It was a click, swap the state.
1534
			showadvdns = !showadvdns;
1535
		}
1536

    
1537
		hideCheckbox('ddnsupdate', !showadvdns);
1538
		hideInput('ddnsdomain', !showadvdns);
1539
		hideCheckbox('ddnsforcehostname', !showadvdns);
1540
		hideInput('ddnsdomainprimary', !showadvdns);
1541
		hideInput('ddnsdomainkeyname', !showadvdns);
1542
		hideInput('ddnsdomainkey', !showadvdns);
1543

    
1544
		if (showadvdns) {
1545
			text = "<?=gettext('Hide Advanced');?>";
1546
		} else {
1547
			text = "<?=gettext('Display Advanced');?>";
1548
		}
1549
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1550
	}
1551

    
1552
	$('#btnadvdns').click(function(event) {
1553
		show_advdns();
1554
	});
1555

    
1556
	// Show advanced MAC options ======================================================================================
1557
	var showadvmac = false;
1558

    
1559
	function show_advmac(ispageload) {
1560
		var text;
1561
		// On page load decide the initial state based on the data.
1562
		if (ispageload) {
1563
<?php
1564
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1565
				$showadv = false;
1566
			} else {
1567
				$showadv = true;
1568
			}
1569
?>
1570
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1571
		} else {
1572
			// It was a click, swap the state.
1573
			showadvmac = !showadvmac;
1574
		}
1575

    
1576
		hideInput('mac_allow', !showadvmac);
1577
		hideInput('mac_deny', !showadvmac);
1578

    
1579
		if (showadvmac) {
1580
			text = "<?=gettext('Hide Advanced');?>";
1581
		} else {
1582
			text = "<?=gettext('Display Advanced');?>";
1583
		}
1584
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1585
	}
1586

    
1587
	$('#btnadvmac').click(function(event) {
1588
		show_advmac();
1589
	});
1590

    
1591
	// Show advanced NTP options ======================================================================================
1592
	var showadvntp = false;
1593

    
1594
	function show_advntp(ispageload) {
1595
		var text;
1596
		// On page load decide the initial state based on the data.
1597
		if (ispageload) {
1598
<?php
1599
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1600
				$showadv = false;
1601
			} else {
1602
				$showadv = true;
1603
			}
1604
?>
1605
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1606
		} else {
1607
			// It was a click, swap the state.
1608
			showadvntp = !showadvntp;
1609
		}
1610

    
1611
		hideInput('ntp1', !showadvntp);
1612
		hideInput('ntp2', !showadvntp);
1613

    
1614
		if (showadvntp) {
1615
			text = "<?=gettext('Hide Advanced');?>";
1616
		} else {
1617
			text = "<?=gettext('Display Advanced');?>";
1618
		}
1619
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1620
	}
1621

    
1622
	$('#btnadvntp').click(function(event) {
1623
		show_advntp();
1624
	});
1625

    
1626
	// Show advanced TFTP options ======================================================================================
1627
	var showadvtftp = false;
1628

    
1629
	function show_advtftp(ispageload) {
1630
		var text;
1631
		// On page load decide the initial state based on the data.
1632
		if (ispageload) {
1633
<?php
1634
			if (empty($pconfig['tftp'])) {
1635
				$showadv = false;
1636
			} else {
1637
				$showadv = true;
1638
			}
1639
?>
1640
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1641
		} else {
1642
			// It was a click, swap the state.
1643
			showadvtftp = !showadvtftp;
1644
		}
1645

    
1646
		hideInput('tftp', !showadvtftp);
1647

    
1648
		if (showadvtftp) {
1649
			text = "<?=gettext('Hide Advanced');?>";
1650
		} else {
1651
			text = "<?=gettext('Display Advanced');?>";
1652
		}
1653
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1654
	}
1655

    
1656
	$('#btnadvtftp').click(function(event) {
1657
		show_advtftp();
1658
	});
1659

    
1660
	// Show advanced LDAP options ======================================================================================
1661
	var showadvldap = false;
1662

    
1663
	function show_advldap(ispageload) {
1664
		var text;
1665
		// On page load decide the initial state based on the data.
1666
		if (ispageload) {
1667
<?php
1668
			if (empty($pconfig['ldap'])) {
1669
				$showadv = false;
1670
			} else {
1671
				$showadv = true;
1672
			}
1673
?>
1674
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1675
		} else {
1676
			// It was a click, swap the state.
1677
			showadvldap = !showadvldap;
1678
		}
1679

    
1680
		hideInput('ldap', !showadvldap);
1681

    
1682
		if (showadvldap) {
1683
			text = "<?=gettext('Hide Advanced');?>";
1684
		} else {
1685
			text = "<?=gettext('Display Advanced');?>";
1686
		}
1687
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1688
	}
1689

    
1690
	$('#btnadvldap').click(function(event) {
1691
		show_advldap();
1692
	});
1693

    
1694
	// Show advanced additional opts options ===========================================================================
1695
	var showadvopts = false;
1696

    
1697
	function show_advopts(ispageload) {
1698
		var text;
1699
		// On page load decide the initial state based on the data.
1700
		if (ispageload) {
1701
<?php
1702
			if (empty($pconfig['numberoptions']) ||
1703
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1704
				$showadv = false;
1705
			} else {
1706
				$showadv = true;
1707
			}
1708
?>
1709
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1710
		} else {
1711
			// It was a click, swap the state.
1712
			showadvopts = !showadvopts;
1713
		}
1714

    
1715
		hideClass('adnlopts', !showadvopts);
1716

    
1717
		if (showadvopts) {
1718
			text = "<?=gettext('Hide Advanced');?>";
1719
		} else {
1720
			text = "<?=gettext('Display Advanced');?>";
1721
		}
1722
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1723
	}
1724

    
1725
	$('#btnadvopts').click(function(event) {
1726
		show_advopts();
1727
	});
1728

    
1729
	// Show advanced Network Booting options ===========================================================================
1730
	var showadvnwkboot = false;
1731

    
1732
	function show_advnwkboot(ispageload) {
1733
		var text;
1734
		// On page load decide the initial state based on the data.
1735
		if (ispageload) {
1736
<?php
1737
			if (empty($pconfig['netboot'])) {
1738
				$showadv = false;
1739
			} else {
1740
				$showadv = true;
1741
			}
1742
?>
1743
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1744
		} else {
1745
			// It was a click, swap the state.
1746
			showadvnwkboot = !showadvnwkboot;
1747
		}
1748

    
1749
		hideCheckbox('netboot', !showadvnwkboot);
1750
		hideInput('nextserver', !showadvnwkboot);
1751
		hideInput('filename', !showadvnwkboot);
1752
		hideInput('filename32', !showadvnwkboot);
1753
		hideInput('filename64', !showadvnwkboot);
1754
		hideInput('rootpath', !showadvnwkboot);
1755

    
1756
		if (showadvnwkboot) {
1757
			text = "<?=gettext('Hide Advanced');?>";
1758
		} else {
1759
			text = "<?=gettext('Display Advanced');?>";
1760
		}
1761
		$('#btnadvnwkboot').html('<i class="fa fa-cog"></i> ' + text);
1762
	}
1763

    
1764
	$('#btnadvnwkboot').click(function(event) {
1765
		show_advnwkboot();
1766
	});
1767

    
1768
	// ---------- On initial page load ------------------------------------------------------------
1769

    
1770
	show_advdns(true);
1771
	show_advmac(true);
1772
	show_advntp(true);
1773
	show_advtftp(true);
1774
	show_advldap(true);
1775
	show_advopts(true);
1776
	show_advnwkboot(true);
1777

    
1778
	// Suppress "Delete row" button if there are fewer than two rows
1779
	checkLastRow();
1780
});
1781
//]]>
1782
</script>
1783

    
1784
<?php include("foot.inc");
(120-120/228)