Project

General

Profile

Download (53.6 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 enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
416
	if ($_POST['enable'] && isset($config['dhcrelay']['enable']) && (stristr($config['dhcrelay']['interface'], $if) !== false)) {
417
		$input_errors[] = sprintf(gettext("The DHCP relay on the %s interface must be disabled before enabling the DHCP server."), $iflist[$if]);
418
	}
419

    
420
	/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
421
	if (!$_POST['enable']) {
422
		if (isset($config['dnsmasq']['enable']) && (isset($config['dnsmasq']['regdhcp']) || isset($config['dnsmasq']['regdhcpstatic']) || isset($config['dnsmasq']['dhcpfirst']))) {
423
			$input_errors[] = gettext("Disable DHCP Registration features in DNS Forwarder before disabling DHCP Server.");
424
		}
425
		if (isset($config['unbound']['enable']) && (isset($config['unbound']['regdhcp']) || isset($config['unbound']['regdhcpstatic']))) {
426
			$input_errors[] = gettext("Disable DHCP Registration features in DNS Resolver before disabling DHCP Server.");
427
		}
428
	}
429

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

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

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

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

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

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

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

    
503
		$dhcpd_enable_changed = false;
504

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

    
514
			$dhcpdconf['enable'] = $new_dhcpd_enable;
515
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
516
			$previous = $dhcpdconf['failover_peerip'];
517
			if ($previous != $_POST['failover_peerip']) {
518
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
519
			}
520

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

    
531
		// Options that can be global or per-pool.
532
		$dhcpdconf['range']['from'] = $_POST['range_from'];
533
		$dhcpdconf['range']['to'] = $_POST['range_to'];
534
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
535
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
536
		$dhcpdconf['netmask'] = $_POST['netmask'];
537

    
538
		unset($dhcpdconf['winsserver']);
539
		if ($_POST['wins1']) {
540
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
541
		}
542
		if ($_POST['wins2']) {
543
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
544
		}
545

    
546
		unset($dhcpdconf['dnsserver']);
547
		if ($_POST['dns1']) {
548
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
549
		}
550
		if ($_POST['dns2']) {
551
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
552
		}
553
		if ($_POST['dns3']) {
554
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
555
		}
556
		if ($_POST['dns4']) {
557
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
558
		}
559

    
560
		$dhcpdconf['gateway'] = $_POST['gateway'];
561
		$dhcpdconf['domain'] = $_POST['domain'];
562
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
563
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
564
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
565
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
566
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
567
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
568
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
569
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
570
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
571
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
572
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
573
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
574
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
575

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

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

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

    
603
		$dhcpdconf['numberoptions'] = $numberoptions;
604

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

    
613
		write_config();
614
	}
615
}
616

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

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

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

    
661
if ($act == "del") {
662
	if (isset($a_maps[$_POST['id']])) {
663
		/* Remove static ARP entry, if necessary */
664
		if (isset($a_maps[$_POST['id']]['arp_table_static_entry'])) {
665
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_POST['id']]['ipaddr']));
666
		}
667
		unset($a_maps[$_POST['id']]);
668
		write_config();
669
		if (isset($config['dhcpd'][$if]['enable'])) {
670
			mark_subsystem_dirty('staticmaps');
671
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
672
				mark_subsystem_dirty('hosts');
673
			}
674
		}
675

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

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

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

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

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

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

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

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

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

    
724
	return($pooltbl);
725
}
726

    
727
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
728
$pglinks = array("", "services_dhcp.php");
729

    
730
if (!empty($if) && isset($iflist[$if])) {
731
	$pgtitle[] = $iflist[$if];
732
	$pglinks[] = "@self";
733
}
734
$shortcut_section = "dhcp";
735

    
736
include("head.inc");
737

    
738
if ($input_errors) {
739
	print_input_errors($input_errors);
740
}
741

    
742
if ($changes_applied) {
743
	print_apply_result_box($retval);
744
}
745

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

    
750
/* active tabs */
751
$tab_array = array();
752
$tabscounter = 0;
753
$i = 0;
754
$have_small_subnet = false;
755

    
756
foreach ($iflist as $ifent => $ifname) {
757
	$oc = $config['interfaces'][$ifent];
758

    
759
	/* Not static IPv4 or subnet >= 31 */
760
	if ($oc['subnet'] >= 31) {
761
		$have_small_subnet = true;
762
		$example_name = $ifname;
763
		$example_cidr = $oc['subnet'];
764
		continue;
765
	}
766
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
767
		continue;
768
	}
769

    
770
	if ($ifent == $if) {
771
		$active = true;
772
	} else {
773
		$active = false;
774
	}
775

    
776
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
777
	$tabscounter++;
778
}
779

    
780
if ($tabscounter == 0) {
781
	if ($have_small_subnet) {
782
		$sentence2 = sprintf(gettext('%1$s has a CIDR mask of %2$s, which does not contain enough addresses.'), htmlspecialchars($example_name), htmlspecialchars($example_cidr));
783
	} else {
784
		$sentence2 = gettext("This system has no interfaces configured with a static IPv4 address.");
785
	}
786
	print_info_box(gettext("The DHCP Server requires a static IPv4 subnet large enough to serve addresses to clients.") . " " . $sentence2);
787
	include("foot.inc");
788
	exit;
789
}
790

    
791
display_top_tabs($tab_array);
792

    
793
$form = new Form();
794

    
795
$section = new Form_Section('General Options');
796

    
797
if (!is_numeric($pool) && !($act == "newpool")) {
798
	if (isset($config['dhcrelay']['enable'])) {
799
		$section->addInput(new Form_Checkbox(
800
			'enable',
801
			'Enable',
802
			gettext("DHCP Relay is currently enabled. DHCP Server canot be enabled while the DHCP Relay is enabled on any interface."),
803
			$pconfig['enable']
804
		))->setAttribute('disabled', true);
805
	} else {
806
		$section->addInput(new Form_Checkbox(
807
			'enable',
808
			'Enable',
809
			sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
810
			$pconfig['enable']
811
		));
812
	}
813
} else {
814
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
815
}
816

    
817
$section->addInput(new Form_Checkbox(
818
	'ignorebootp',
819
	'BOOTP',
820
	'Ignore BOOTP queries',
821
	$pconfig['ignorebootp']
822
));
823

    
824
$section->addInput(new Form_Checkbox(
825
	'denyunknown',
826
	'Deny unknown clients',
827
	'Only the clients defined below will get DHCP leases from this server.',
828
	$pconfig['denyunknown']
829
));
830

    
831
$section->addInput(new Form_Checkbox(
832
	'nonak',
833
	'Ignore denied clients',
834
	'Denied clients will be ignored rather than rejected.',
835
	$pconfig['nonak']
836
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
837

    
838
$section->addInput(new Form_Checkbox(
839
	'ignoreclientuids',
840
	'Ignore client identifiers',
841
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
842
	$pconfig['ignoreclientuids']
843
))->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.");
844

    
845

    
846
if (is_numeric($pool) || ($act == "newpool")) {
847
	$section->addInput(new Form_Input(
848
		'descr',
849
		'Pool Description',
850
		'text',
851
		$pconfig['descr']
852
	));
853
}
854

    
855
$section->addInput(new Form_StaticText(
856
	'Subnet',
857
	gen_subnet($ifcfgip, $ifcfgsn)
858
));
859

    
860
$section->addInput(new Form_StaticText(
861
	'Subnet mask',
862
	gen_subnet_mask($ifcfgsn)
863
));
864

    
865
// Compose a string to display the required address ranges
866
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
867

    
868
if (is_numeric($pool) || ($act == "newpool")) {
869
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
870
	if (is_array($config['dhcpd'][$if]['range'])) {
871
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
872
	}
873

    
874
	foreach ($a_pools as $p) {
875
		if (is_array($p['range'])) {
876
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
877
		}
878
	}
879
}
880

    
881
$section->addInput(new Form_StaticText(
882
	'Available range',
883
	$rangestr
884
));
885

    
886
if ($is_olsr_enabled) {
887
	$section->addInput(new Form_Select(
888
		'netmask',
889
		'Subnet mask',
890
		$pconfig['netmask'],
891
		array_combine(range(32, 1, -1), range(32, 1, -1))
892
	));
893
}
894

    
895
$group = new Form_Group('*Range');
896

    
897
$group->add(new Form_IpAddress(
898
	'range_from',
899
	null,
900
	$pconfig['range_from'],
901
	'V4'
902
))->setHelp('From');
903

    
904
$group->add(new Form_IpAddress(
905
	'range_to',
906
	null,
907
	$pconfig['range_to'],
908
	'V4'
909
))->setHelp('To');
910

    
911
$section->add($group);
912

    
913
$form->add($section);
914

    
915
if (!is_numeric($pool) && !($act == "newpool")) {
916
	$section = new Form_Section('Additional Pools');
917

    
918
	$btnaddpool = new Form_Button(
919
		'btnaddpool',
920
		'Add pool',
921
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
922
		'fa-plus'
923
	);
924
	$btnaddpool->addClass('btn-success');
925

    
926
	$section->addInput(new Form_StaticText(
927
		'Add',
928
		$btnaddpool
929
	))->setHelp('If additional pools of addresses are needed inside of this subnet outside the above Range, they may be specified here.');
930

    
931
	if (is_array($a_pools)) {
932
		$section->addInput(new Form_StaticText(
933
			null,
934
			build_pooltable()
935
		));
936
	}
937

    
938
	$form->add($section);
939
}
940

    
941
$section = new Form_Section('Servers');
942

    
943
$section->addInput(new Form_IpAddress(
944
	'wins1',
945
	'WINS servers',
946
	$pconfig['wins1'],
947
	'V4'
948
))->setAttribute('placeholder', 'WINS Server 1');
949

    
950
$section->addInput(new Form_IpAddress(
951
	'wins2',
952
	null,
953
	$pconfig['wins2'],
954
	'V4'
955
))->setAttribute('placeholder', 'WINS Server 2');
956

    
957
for ($idx=1; $idx<=4; $idx++) {
958
	$section->addInput(new Form_IpAddress(
959
		'dns' . $idx,
960
		($idx == 1) ? 'DNS servers':null,
961
		$pconfig['dns' . $idx],
962
		'V4'
963
	))->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.':'');
964
}
965

    
966
$form->add($section);
967

    
968
$section = new Form_Section('Other Options');
969

    
970
$section->addInput(new Form_IpAddress(
971
	'gateway',
972
	'Gateway',
973
	$pconfig['gateway'],
974
	'V4'
975
))->setPattern('[.a-zA-Z0-9_]+')
976
  ->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.');
977

    
978
$section->addInput(new Form_Input(
979
	'domain',
980
	'Domain name',
981
	'text',
982
	$pconfig['domain']
983
))->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.');
984

    
985
$section->addInput(new Form_Input(
986
	'domainsearchlist',
987
	'Domain search list',
988
	'text',
989
	$pconfig['domainsearchlist']
990
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
991

    
992
$section->addInput(new Form_Input(
993
	'deftime',
994
	'Default lease time',
995
	'number',
996
	$pconfig['deftime']
997
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds.');
998

    
999
$section->addInput(new Form_Input(
1000
	'maxtime',
1001
	'Maximum lease time',
1002
	'number',
1003
	$pconfig['maxtime']
1004
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds.');
1005

    
1006
if (!is_numeric($pool) && !($act == "newpool")) {
1007
	$section->addInput(new Form_IpAddress(
1008
		'failover_peerip',
1009
		'Failover peer IP',
1010
		$pconfig['failover_peerip'],
1011
		'V4'
1012
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
1013
				'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).');
1014
}
1015

    
1016
if (!is_numeric($pool) && !($act == "newpool")) {
1017
	$section->addInput(new Form_Checkbox(
1018
		'staticarp',
1019
		'Static ARP',
1020
		'Enable Static ARP entries',
1021
		$pconfig['staticarp']
1022
	))->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.');
1023

    
1024
	$section->addInput(new Form_Checkbox(
1025
		'dhcpleaseinlocaltime',
1026
		'Time format change',
1027
		'Change DHCP display lease time from UTC to local time',
1028
		$pconfig['dhcpleaseinlocaltime']
1029
	))->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.' .
1030
				' This will be used for all DHCP interfaces lease time.');
1031
	$section->addInput(new Form_Checkbox(
1032
		'statsgraph',
1033
		'Statistics graphs',
1034
		'Enable RRD statistics graphs',
1035
		$pconfig['statsgraph']
1036
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1037
}
1038

    
1039
// DDNS
1040
$btnadv = new Form_Button(
1041
	'btnadvdns',
1042
	'Display Advanced',
1043
	null,
1044
	'fa-cog'
1045
);
1046

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

    
1049
$section->addInput(new Form_StaticText(
1050
	'Dynamic DNS',
1051
	$btnadv
1052
));
1053

    
1054
$section->addInput(new Form_Checkbox(
1055
	'ddnsupdate',
1056
	null,
1057
	'Enable registration of DHCP client names in DNS',
1058
	$pconfig['ddnsupdate']
1059
));
1060

    
1061
$section->addInput(new Form_Input(
1062
	'ddnsdomain',
1063
	'DDNS Domain',
1064
	'text',
1065
	$pconfig['ddnsdomain']
1066
))->setHelp('Leave blank to disable dynamic DNS registration.%1$s' .
1067
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.', '<br />');
1068

    
1069
$section->addInput(new Form_Checkbox(
1070
	'ddnsforcehostname',
1071
	'DDNS Hostnames',
1072
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1073
	$pconfig['ddnsforcehostname']
1074
))->setHelp('Default registers host name option supplied by DHCP client.');
1075

    
1076
$section->addInput(new Form_IpAddress(
1077
	'ddnsdomainprimary',
1078
	'Primary DDNS address',
1079
	$pconfig['ddnsdomainprimary'],
1080
	'V4'
1081
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1082

    
1083
$section->addInput(new Form_Input(
1084
	'ddnsdomainkeyname',
1085
	'DNS Domain key',
1086
	'text',
1087
	$pconfig['ddnsdomainkeyname']
1088
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1089

    
1090
$section->addInput(new Form_Input(
1091
	'ddnsdomainkey',
1092
	'DNS Domain key secret',
1093
	'text',
1094
	$pconfig['ddnsdomainkey']
1095
))->setHelp('Dynamic DNS domain key secret (HMAC-MD5) which will be used to register client names in the DNS server.');
1096

    
1097
// Advanced MAC
1098
$btnadv = new Form_Button(
1099
	'btnadvmac',
1100
	'Display Advanced',
1101
	null,
1102
	'fa-cog'
1103
);
1104

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

    
1107
$section->addInput(new Form_StaticText(
1108
	'MAC address control',
1109
	$btnadv
1110
));
1111

    
1112
$section->addInput(new Form_Input(
1113
	'mac_allow',
1114
	'MAC Allow',
1115
	'text',
1116
	$pconfig['mac_allow']
1117
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1118

    
1119
$section->addInput(new Form_Input(
1120
	'mac_deny',
1121
	'MAC Deny',
1122
	'text',
1123
	$pconfig['mac_deny']
1124
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1125

    
1126
// Advanced NTP
1127
$btnadv = new Form_Button(
1128
	'btnadvntp',
1129
	'Display Advanced',
1130
	null,
1131
	'fa-cog'
1132
);
1133

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

    
1136
$section->addInput(new Form_StaticText(
1137
	'NTP',
1138
	$btnadv
1139
));
1140

    
1141
$section->addInput(new Form_IpAddress(
1142
	'ntp1',
1143
	'NTP Server 1',
1144
	$pconfig['ntp1'],
1145
	'HOSTV4'
1146
));
1147

    
1148
$section->addInput(new Form_IpAddress(
1149
	'ntp2',
1150
	'NTP Server 2',
1151
	$pconfig['ntp2'],
1152
	'HOSTV4'
1153
));
1154

    
1155
// Advanced TFTP
1156
$btnadv = new Form_Button(
1157
	'btnadvtftp',
1158
	'Display Advanced',
1159
	null,
1160
	'fa-cog'
1161
);
1162

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

    
1165
$section->addInput(new Form_StaticText(
1166
	'TFTP',
1167
	$btnadv
1168
));
1169

    
1170
$section->addInput(new Form_Input(
1171
	'tftp',
1172
	'TFTP Server',
1173
	'text',
1174
	$pconfig['tftp']
1175
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1176

    
1177
// Advanced LDAP
1178
$btnadv = new Form_Button(
1179
	'btnadvldap',
1180
	'Display Advanced',
1181
	null,
1182
	'fa-cog'
1183
);
1184

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

    
1187
$section->addInput(new Form_StaticText(
1188
	'LDAP',
1189
	$btnadv
1190
));
1191

    
1192
$section->addInput(new Form_Input(
1193
	'ldap',
1194
	'LDAP Server URI',
1195
	'text',
1196
	$pconfig['ldap']
1197
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1198

    
1199
// Advanced Network Booting options
1200
$btnadv = new Form_Button(
1201
	'btnadvnwkboot',
1202
	'Display Advanced',
1203
	null,
1204
	'fa-cog'
1205
);
1206

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

    
1209
$section->addInput(new Form_StaticText(
1210
	'Network Booting',
1211
	$btnadv
1212
));
1213

    
1214
$section->addInput(new Form_Checkbox(
1215
	'netboot',
1216
	'Enable',
1217
	'Enables network booting',
1218
	$pconfig['netboot']
1219
));
1220

    
1221
$section->addInput(new Form_IpAddress(
1222
	'nextserver',
1223
	'Next Server',
1224
	$pconfig['nextserver'],
1225
	'V4'
1226
))->setHelp('Enter the IP address of the next server');
1227

    
1228
$section->addInput(new Form_Input(
1229
	'filename',
1230
	'Default BIOS file name',
1231
	'text',
1232
	$pconfig['filename']
1233
));
1234

    
1235
$section->addInput(new Form_Input(
1236
	'filename32',
1237
	'UEFI 32 bit file name',
1238
	'text',
1239
	$pconfig['filename32']
1240
));
1241

    
1242
$section->addInput(new Form_Input(
1243
	'filename64',
1244
	'UEFI 64 bit file name',
1245
	'text',
1246
	$pconfig['filename64']
1247
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1248
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1249

    
1250
$section->addInput(new Form_Input(
1251
	'rootpath',
1252
	'Root path',
1253
	'text',
1254
	$pconfig['rootpath']
1255
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1256

    
1257
// Advanced Additional options
1258
$btnadv = new Form_Button(
1259
	'btnadvopts',
1260
	'Display Advanced',
1261
	null,
1262
	'fa-cog'
1263
);
1264

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

    
1267
$section->addInput(new Form_StaticText(
1268
	'Additional BOOTP/DHCP Options',
1269
	$btnadv
1270
));
1271

    
1272
$form->add($section);
1273

    
1274
$section = new Form_Section('Additional BOOTP/DHCP Options');
1275
$section->addClass('adnlopts');
1276

    
1277
$section->addInput(new Form_StaticText(
1278
	null,
1279
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1280
	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>')
1281
));
1282

    
1283
if (!$pconfig['numberoptions']) {
1284
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1285
}
1286

    
1287
$customitemtypes = array(
1288
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1289
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1290
	'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')
1291
);
1292

    
1293
$numrows = count($item) -1;
1294
$counter = 0;
1295

    
1296
$numrows = count($pconfig['numberoptions']['item']) -1;
1297

    
1298
foreach ($pconfig['numberoptions']['item'] as $item) {
1299
	$number = $item['number'];
1300
	$itemtype = $item['type'];
1301
	$value = base64_decode($item['value']);
1302

    
1303
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1304
	$group->addClass('repeatable');
1305

    
1306
	$group->add(new Form_Input(
1307
		'number' . $counter,
1308
		null,
1309
		'text',
1310
		$number
1311
	))->setHelp($numrows == $counter ? 'Number':null);
1312

    
1313

    
1314
	$group->add(new Form_Select(
1315
		'itemtype' . $counter,
1316
		null,
1317
		$itemtype,
1318
		$customitemtypes
1319
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1320

    
1321
	$group->add(new Form_Input(
1322
		'value' . $counter,
1323
		null,
1324
		'text',
1325
		$value
1326
	))->setHelp($numrows == $counter ? 'Value':null);
1327

    
1328
	$group->add(new Form_Button(
1329
		'deleterow' . $counter,
1330
		'Delete',
1331
		null,
1332
		'fa-trash'
1333
	))->addClass('btn-warning');
1334

    
1335
	$section->add($group);
1336

    
1337
	$counter++;
1338
}
1339

    
1340
$section->addInput(new Form_Button(
1341
	'addrow',
1342
	'Add',
1343
	null,
1344
	'fa-plus'
1345
))->addClass('btn-success');
1346

    
1347
$form->add($section);
1348

    
1349
if ($act == "newpool") {
1350
	$form->addGlobal(new Form_Input(
1351
		'act',
1352
		null,
1353
		'hidden',
1354
		'newpool'
1355
	));
1356
}
1357

    
1358
if (is_numeric($pool)) {
1359
	$form->addGlobal(new Form_Input(
1360
		'pool',
1361
		null,
1362
		'hidden',
1363
		$pool
1364
	));
1365
}
1366

    
1367
$form->addGlobal(new Form_Input(
1368
	'if',
1369
	null,
1370
	'hidden',
1371
	$if
1372
));
1373

    
1374
print($form);
1375

    
1376
// DHCP Static Mappings table
1377

    
1378
if (!is_numeric($pool) && !($act == "newpool")) {
1379

    
1380
	// Decide whether display of the Client Id column is needed.
1381
	$got_cid = false;
1382
	if (is_array($a_maps)) {
1383
		foreach ($a_maps as $map) {
1384
			if (!empty($map['cid'])) {
1385
				$got_cid = true;
1386
				break;
1387
			}
1388
		}
1389
	}
1390
?>
1391

    
1392
<div class="panel panel-default">
1393
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1394
	<div class="table-responsive">
1395
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1396
				<thead>
1397
					<tr>
1398
						<th><?=gettext("Static ARP")?></th>
1399
						<th><?=gettext("MAC address")?></th>
1400
<?php
1401
	if ($got_cid):
1402
?>
1403
						<th><?=gettext("Client Id")?></th>
1404
<?php
1405
	endif;
1406
?>
1407
						<th><?=gettext("IP address")?></th>
1408
						<th><?=gettext("Hostname")?></th>
1409
						<th><?=gettext("Description")?></th>
1410
						<th></th>
1411
					</tr>
1412
				</thead>
1413
<?php
1414
	if (is_array($a_maps)) {
1415
		$i = 0;
1416
?>
1417
				<tbody>
1418
<?php
1419
		foreach ($a_maps as $mapent) {
1420
?>
1421
					<tr>
1422
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1423
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1424
								<i class="fa fa-check"></i>
1425
							<?php endif; ?>
1426
						</td>
1427
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1428
							<?=htmlspecialchars($mapent['mac'])?>
1429
						</td>
1430
<?php
1431
			if ($got_cid):
1432
?>
1433
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1434
							<?=htmlspecialchars($mapent['cid'])?>
1435
						</td>
1436
<?php
1437
			endif;
1438
?>
1439
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1440
							<?=htmlspecialchars($mapent['ipaddr'])?>
1441
						</td>
1442
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1443
							<?=htmlspecialchars($mapent['hostname'])?>
1444
						</td>
1445
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1446
							<?=htmlspecialchars($mapent['descr'])?>
1447
						</td>
1448
						<td>
1449
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1450
							<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>
1451
						</td>
1452
					</tr>
1453
<?php
1454
		$i++;
1455
		}
1456
?>
1457
				</tbody>
1458
<?php
1459
	}
1460
?>
1461
		</table>
1462
	</div>
1463
</div>
1464

    
1465
<nav class="action-buttons">
1466
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1467
		<i class="fa fa-plus icon-embed-btn"></i>
1468
		<?=gettext("Add")?>
1469
	</a>
1470
</nav>
1471
<?php
1472
}
1473
?>
1474

    
1475
<script type="text/javascript">
1476
//<![CDATA[
1477
events.push(function() {
1478

    
1479
	// Show advanced DNS options ======================================================================================
1480
	var showadvdns = false;
1481

    
1482
	function show_advdns(ispageload) {
1483
		var text;
1484
		// On page load decide the initial state based on the data.
1485
		if (ispageload) {
1486
<?php
1487
			if (!$pconfig['ddnsupdate'] && !$pconfig['ddnsforcehostname'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1488
			    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1489
				$showadv = false;
1490
			} else {
1491
				$showadv = true;
1492
			}
1493
?>
1494
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1495
		} else {
1496
			// It was a click, swap the state.
1497
			showadvdns = !showadvdns;
1498
		}
1499

    
1500
		hideCheckbox('ddnsupdate', !showadvdns);
1501
		hideInput('ddnsdomain', !showadvdns);
1502
		hideCheckbox('ddnsforcehostname', !showadvdns);
1503
		hideInput('ddnsdomainprimary', !showadvdns);
1504
		hideInput('ddnsdomainkeyname', !showadvdns);
1505
		hideInput('ddnsdomainkey', !showadvdns);
1506

    
1507
		if (showadvdns) {
1508
			text = "<?=gettext('Hide Advanced');?>";
1509
		} else {
1510
			text = "<?=gettext('Display Advanced');?>";
1511
		}
1512
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1513
	}
1514

    
1515
	$('#btnadvdns').click(function(event) {
1516
		show_advdns();
1517
	});
1518

    
1519
	// Show advanced MAC options ======================================================================================
1520
	var showadvmac = false;
1521

    
1522
	function show_advmac(ispageload) {
1523
		var text;
1524
		// On page load decide the initial state based on the data.
1525
		if (ispageload) {
1526
<?php
1527
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1528
				$showadv = false;
1529
			} else {
1530
				$showadv = true;
1531
			}
1532
?>
1533
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1534
		} else {
1535
			// It was a click, swap the state.
1536
			showadvmac = !showadvmac;
1537
		}
1538

    
1539
		hideInput('mac_allow', !showadvmac);
1540
		hideInput('mac_deny', !showadvmac);
1541

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

    
1550
	$('#btnadvmac').click(function(event) {
1551
		show_advmac();
1552
	});
1553

    
1554
	// Show advanced NTP options ======================================================================================
1555
	var showadvntp = false;
1556

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

    
1574
		hideInput('ntp1', !showadvntp);
1575
		hideInput('ntp2', !showadvntp);
1576

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

    
1585
	$('#btnadvntp').click(function(event) {
1586
		show_advntp();
1587
	});
1588

    
1589
	// Show advanced TFTP options ======================================================================================
1590
	var showadvtftp = false;
1591

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

    
1609
		hideInput('tftp', !showadvtftp);
1610

    
1611
		if (showadvtftp) {
1612
			text = "<?=gettext('Hide Advanced');?>";
1613
		} else {
1614
			text = "<?=gettext('Display Advanced');?>";
1615
		}
1616
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1617
	}
1618

    
1619
	$('#btnadvtftp').click(function(event) {
1620
		show_advtftp();
1621
	});
1622

    
1623
	// Show advanced LDAP options ======================================================================================
1624
	var showadvldap = false;
1625

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

    
1643
		hideInput('ldap', !showadvldap);
1644

    
1645
		if (showadvldap) {
1646
			text = "<?=gettext('Hide Advanced');?>";
1647
		} else {
1648
			text = "<?=gettext('Display Advanced');?>";
1649
		}
1650
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1651
	}
1652

    
1653
	$('#btnadvldap').click(function(event) {
1654
		show_advldap();
1655
	});
1656

    
1657
	// Show advanced additional opts options ===========================================================================
1658
	var showadvopts = false;
1659

    
1660
	function show_advopts(ispageload) {
1661
		var text;
1662
		// On page load decide the initial state based on the data.
1663
		if (ispageload) {
1664
<?php
1665
			if (empty($pconfig['numberoptions']) ||
1666
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1667
				$showadv = false;
1668
			} else {
1669
				$showadv = true;
1670
			}
1671
?>
1672
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1673
		} else {
1674
			// It was a click, swap the state.
1675
			showadvopts = !showadvopts;
1676
		}
1677

    
1678
		hideClass('adnlopts', !showadvopts);
1679

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

    
1688
	$('#btnadvopts').click(function(event) {
1689
		show_advopts();
1690
	});
1691

    
1692
	// Show advanced Network Booting options ===========================================================================
1693
	var showadvnwkboot = false;
1694

    
1695
	function show_advnwkboot(ispageload) {
1696
		var text;
1697
		// On page load decide the initial state based on the data.
1698
		if (ispageload) {
1699
<?php
1700
			if (empty($pconfig['netboot'])) {
1701
				$showadv = false;
1702
			} else {
1703
				$showadv = true;
1704
			}
1705
?>
1706
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1707
		} else {
1708
			// It was a click, swap the state.
1709
			showadvnwkboot = !showadvnwkboot;
1710
		}
1711

    
1712
		hideCheckbox('netboot', !showadvnwkboot);
1713
		hideInput('nextserver', !showadvnwkboot);
1714
		hideInput('filename', !showadvnwkboot);
1715
		hideInput('filename32', !showadvnwkboot);
1716
		hideInput('filename64', !showadvnwkboot);
1717
		hideInput('rootpath', !showadvnwkboot);
1718

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

    
1727
	$('#btnadvnwkboot').click(function(event) {
1728
		show_advnwkboot();
1729
	});
1730

    
1731
	// ---------- On initial page load ------------------------------------------------------------
1732

    
1733
	show_advdns(true);
1734
	show_advmac(true);
1735
	show_advntp(true);
1736
	show_advtftp(true);
1737
	show_advldap(true);
1738
	show_advopts(true);
1739
	show_advnwkboot(true);
1740

    
1741
	// Suppress "Delete row" button if there are fewer than two rows
1742
	checkLastRow();
1743
});
1744
//]]>
1745
</script>
1746

    
1747
<?php include("foot.inc");
(115-115/223)