Project

General

Profile

Download (56 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-2018 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['ddnsdomainkeyalgorithm'] = $dhcpdconf['ddnsdomainkeyalgorithm'];
187
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
188
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
189
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
190
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
191
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
192
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
193
	$pconfig['tftp'] = $dhcpdconf['tftp'];
194
	$pconfig['ldap'] = $dhcpdconf['ldap'];
195
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
196
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
197
	$pconfig['filename'] = $dhcpdconf['filename'];
198
	$pconfig['filename32'] = $dhcpdconf['filename32'];
199
	$pconfig['filename64'] = $dhcpdconf['filename64'];
200
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
201
	$pconfig['netmask'] = $dhcpdconf['netmask'];
202
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
203
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
204
	$pconfig['ddnsclientupdates'] = $dhcpdconf['ddnsclientupdates'];
205
}
206

    
207
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
208
$ifcfgsn = $config['interfaces'][$if]['subnet'];
209

    
210
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
211
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
212

    
213
function validate_partial_mac_list($maclist) {
214
	$macs = explode(',', $maclist);
215

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

    
223
	return true;
224
}
225

    
226
if (isset($_POST['save'])) {
227

    
228
	unset($input_errors);
229

    
230
	$pconfig = $_POST;
231

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

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

    
246
	/* input validation */
247

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

    
253
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
254
	}
255

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

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

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

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

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

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

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

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

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

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

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

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

    
385
	if ($_POST['staticarp'] && $noip) {
386
		$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.");
387
	}
388

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

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

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

    
443
	// 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.
444
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
445
		/* make sure the range lies within the current subnet */
446
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
447
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
448
		}
449

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

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

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

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

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

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

    
516
		$dhcpd_enable_changed = false;
517

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

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

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

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

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

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

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

    
591
		unset($dhcpdconf['ntpserver']);
592
		if ($_POST['ntp1']) {
593
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
594
		}
595
		if ($_POST['ntp2']) {
596
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
597
		}
598

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

    
613
		// Handle the custom options rowhelper
614
		if (isset($dhcpdconf['numberoptions']['item'])) {
615
			unset($dhcpdconf['numberoptions']['item']);
616
		}
617

    
618
		$dhcpdconf['numberoptions'] = $numberoptions;
619

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

    
628
		write_config();
629
	}
630
}
631

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

    
687
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
688
		$retval = 1;
689
	}
690
}
691

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

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

    
716
		header("Location: services_dhcp.php?if={$if}");
717
		exit;
718
	}
719
}
720

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

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

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

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

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

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

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

    
760
	$pooltbl .=			'</tbody>';
761
	$pooltbl .=		'</table>';
762
	$pooltbl .= '</div>';
763

    
764
	return($pooltbl);
765
}
766

    
767
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
768
$pglinks = array("", "services_dhcp.php");
769

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

    
776
include("head.inc");
777

    
778
if ($input_errors) {
779
	print_input_errors($input_errors);
780
}
781

    
782
if ($changes_applied) {
783
	print_apply_result_box($retval);
784
}
785

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

    
790
/* active tabs */
791
$tab_array = array();
792
$tabscounter = 0;
793
$i = 0;
794
$have_small_subnet = false;
795

    
796
foreach ($iflist as $ifent => $ifname) {
797
	$oc = $config['interfaces'][$ifent];
798

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

    
810
	if ($ifent == $if) {
811
		$active = true;
812
	} else {
813
		$active = false;
814
	}
815

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

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

    
831
display_top_tabs($tab_array);
832

    
833
$form = new Form();
834

    
835
$section = new Form_Section('General Options');
836

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

    
857
$section->addInput(new Form_Checkbox(
858
	'ignorebootp',
859
	'BOOTP',
860
	'Ignore BOOTP queries',
861
	$pconfig['ignorebootp']
862
));
863

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

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

    
878
$section->addInput(new Form_Checkbox(
879
	'ignoreclientuids',
880
	'Ignore client identifiers',
881
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
882
	$pconfig['ignoreclientuids']
883
))->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.");
884

    
885

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

    
895
$section->addInput(new Form_StaticText(
896
	'Subnet',
897
	gen_subnet($ifcfgip, $ifcfgsn)
898
));
899

    
900
$section->addInput(new Form_StaticText(
901
	'Subnet mask',
902
	gen_subnet_mask($ifcfgsn)
903
));
904

    
905
// Compose a string to display the required address ranges
906
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
907

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

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

    
921
$section->addInput(new Form_StaticText(
922
	'Available range',
923
	$rangestr
924
));
925

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

    
935
$group = new Form_Group('*Range');
936

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

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

    
951
$section->add($group);
952

    
953
$form->add($section);
954

    
955
if (!is_numeric($pool) && !($act == "newpool")) {
956
	$section = new Form_Section('Additional Pools');
957

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

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

    
971
	if (is_array($a_pools)) {
972
		$section->addInput(new Form_StaticText(
973
			null,
974
			build_pooltable()
975
		));
976
	}
977

    
978
	$form->add($section);
979
}
980

    
981
$section = new Form_Section('Servers');
982

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

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

    
997
for ($idx=1; $idx<=4; $idx++) {
998
	$section->addInput(new Form_IpAddress(
999
		'dns' . $idx,
1000
		($idx == 1) ? 'DNS servers':null,
1001
		$pconfig['dns' . $idx],
1002
		'V4'
1003
	))->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.':'');
1004
}
1005

    
1006
$form->add($section);
1007

    
1008
$section = new Form_Section('Other Options');
1009

    
1010
$section->addInput(new Form_IpAddress(
1011
	'gateway',
1012
	'Gateway',
1013
	$pconfig['gateway'],
1014
	'V4'
1015
))->setPattern('[.a-zA-Z0-9_]+')
1016
  ->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.');
1017

    
1018
$section->addInput(new Form_Input(
1019
	'domain',
1020
	'Domain name',
1021
	'text',
1022
	$pconfig['domain']
1023
))->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.');
1024

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

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

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

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

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

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

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

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

    
1089
$section->addInput(new Form_StaticText(
1090
	'Dynamic DNS',
1091
	$btnadv
1092
));
1093

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

    
1101
$section->addInput(new Form_Input(
1102
	'ddnsdomain',
1103
	'DDNS Domain',
1104
	'text',
1105
	$pconfig['ddnsdomain']
1106
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1107

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

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

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

    
1129
$section->addInput(new Form_Select(
1130
	'ddnsdomainkeyalgorithm',
1131
	'Key algorithm',
1132
	$pconfig['ddnsdomainkeyalgorithm'],
1133
	array(
1134
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1135
		'hmac-sha1' => 'HMAC-SHA1',
1136
		'hmac-sha224' => 'HMAC-SHA224',
1137
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1138
		'hmac-sha384' => 'HMAC-SHA384',
1139
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1140
	)
1141
));
1142

    
1143
$section->addInput(new Form_Input(
1144
	'ddnsdomainkey',
1145
	'DNS Domain key secret',
1146
	'text',
1147
	$pconfig['ddnsdomainkey']
1148
))->setHelp('Dynamic DNS domain key secret which will be used to register client names in the DNS server.');
1149

    
1150
$section->addInput(new Form_Select(
1151
	'ddnsclientupdates',
1152
	'DDNS Client Updates',
1153
	$pconfig['ddnsclientupdates'],
1154
	array(
1155
	    'allow' => gettext('Allow'),
1156
	    'deny' => gettext('Deny'),
1157
	    'ignore' => gettext('Ignore'))
1158
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
1159
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
1160
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
1161
	    'update and the client can also attempt the update usually using a different domain name.');
1162

    
1163
// Advanced MAC
1164
$btnadv = new Form_Button(
1165
	'btnadvmac',
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
	'MAC address control',
1175
	$btnadv
1176
));
1177

    
1178
$section->addInput(new Form_Input(
1179
	'mac_allow',
1180
	'MAC Allow',
1181
	'text',
1182
	$pconfig['mac_allow']
1183
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1184

    
1185
$section->addInput(new Form_Input(
1186
	'mac_deny',
1187
	'MAC Deny',
1188
	'text',
1189
	$pconfig['mac_deny']
1190
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1191

    
1192
// Advanced NTP
1193
$btnadv = new Form_Button(
1194
	'btnadvntp',
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
	'NTP',
1204
	$btnadv
1205
));
1206

    
1207
$section->addInput(new Form_IpAddress(
1208
	'ntp1',
1209
	'NTP Server 1',
1210
	$pconfig['ntp1'],
1211
	'HOSTV4'
1212
));
1213

    
1214
$section->addInput(new Form_IpAddress(
1215
	'ntp2',
1216
	'NTP Server 2',
1217
	$pconfig['ntp2'],
1218
	'HOSTV4'
1219
));
1220

    
1221
// Advanced TFTP
1222
$btnadv = new Form_Button(
1223
	'btnadvtftp',
1224
	'Display Advanced',
1225
	null,
1226
	'fa-cog'
1227
);
1228

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

    
1231
$section->addInput(new Form_StaticText(
1232
	'TFTP',
1233
	$btnadv
1234
));
1235

    
1236
$section->addInput(new Form_Input(
1237
	'tftp',
1238
	'TFTP Server',
1239
	'text',
1240
	$pconfig['tftp']
1241
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1242

    
1243
// Advanced LDAP
1244
$btnadv = new Form_Button(
1245
	'btnadvldap',
1246
	'Display Advanced',
1247
	null,
1248
	'fa-cog'
1249
);
1250

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

    
1253
$section->addInput(new Form_StaticText(
1254
	'LDAP',
1255
	$btnadv
1256
));
1257

    
1258
$section->addInput(new Form_Input(
1259
	'ldap',
1260
	'LDAP Server URI',
1261
	'text',
1262
	$pconfig['ldap']
1263
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1264

    
1265
// Advanced Network Booting options
1266
$btnadv = new Form_Button(
1267
	'btnadvnwkboot',
1268
	'Display Advanced',
1269
	null,
1270
	'fa-cog'
1271
);
1272

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

    
1275
$section->addInput(new Form_StaticText(
1276
	'Network Booting',
1277
	$btnadv
1278
));
1279

    
1280
$section->addInput(new Form_Checkbox(
1281
	'netboot',
1282
	'Enable',
1283
	'Enables network booting',
1284
	$pconfig['netboot']
1285
));
1286

    
1287
$section->addInput(new Form_IpAddress(
1288
	'nextserver',
1289
	'Next Server',
1290
	$pconfig['nextserver'],
1291
	'V4'
1292
))->setHelp('Enter the IP address of the next server');
1293

    
1294
$section->addInput(new Form_Input(
1295
	'filename',
1296
	'Default BIOS file name',
1297
	'text',
1298
	$pconfig['filename']
1299
));
1300

    
1301
$section->addInput(new Form_Input(
1302
	'filename32',
1303
	'UEFI 32 bit file name',
1304
	'text',
1305
	$pconfig['filename32']
1306
));
1307

    
1308
$section->addInput(new Form_Input(
1309
	'filename64',
1310
	'UEFI 64 bit file name',
1311
	'text',
1312
	$pconfig['filename64']
1313
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1314
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1315

    
1316
$section->addInput(new Form_Input(
1317
	'rootpath',
1318
	'Root path',
1319
	'text',
1320
	$pconfig['rootpath']
1321
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1322

    
1323
// Advanced Additional options
1324
$btnadv = new Form_Button(
1325
	'btnadvopts',
1326
	'Display Advanced',
1327
	null,
1328
	'fa-cog'
1329
);
1330

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

    
1333
$section->addInput(new Form_StaticText(
1334
	'Additional BOOTP/DHCP Options',
1335
	$btnadv
1336
));
1337

    
1338
$form->add($section);
1339

    
1340
$section = new Form_Section('Additional BOOTP/DHCP Options');
1341
$section->addClass('adnlopts');
1342

    
1343
$section->addInput(new Form_StaticText(
1344
	null,
1345
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1346
	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>')
1347
));
1348

    
1349
if (!$pconfig['numberoptions']) {
1350
	$pconfig['numberoptions'] = array();
1351
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1352
}
1353

    
1354
$customitemtypes = array(
1355
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1356
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1357
	'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')
1358
);
1359

    
1360
$numrows = count($item) -1;
1361
$counter = 0;
1362

    
1363
$numrows = count($pconfig['numberoptions']['item']) -1;
1364

    
1365
foreach ($pconfig['numberoptions']['item'] as $item) {
1366
	$number = $item['number'];
1367
	$itemtype = $item['type'];
1368
	$value = base64_decode($item['value']);
1369

    
1370
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1371
	$group->addClass('repeatable');
1372

    
1373
	$group->add(new Form_Input(
1374
		'number' . $counter,
1375
		null,
1376
		'text',
1377
		$number
1378
	))->setHelp($numrows == $counter ? 'Number':null);
1379

    
1380

    
1381
	$group->add(new Form_Select(
1382
		'itemtype' . $counter,
1383
		null,
1384
		$itemtype,
1385
		$customitemtypes
1386
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1387

    
1388
	$group->add(new Form_Input(
1389
		'value' . $counter,
1390
		null,
1391
		'text',
1392
		$value
1393
	))->setHelp($numrows == $counter ? 'Value':null);
1394

    
1395
	$group->add(new Form_Button(
1396
		'deleterow' . $counter,
1397
		'Delete',
1398
		null,
1399
		'fa-trash'
1400
	))->addClass('btn-warning');
1401

    
1402
	$section->add($group);
1403

    
1404
	$counter++;
1405
}
1406

    
1407
$section->addInput(new Form_Button(
1408
	'addrow',
1409
	'Add',
1410
	null,
1411
	'fa-plus'
1412
))->addClass('btn-success');
1413

    
1414
$form->add($section);
1415

    
1416
if ($act == "newpool") {
1417
	$form->addGlobal(new Form_Input(
1418
		'act',
1419
		null,
1420
		'hidden',
1421
		'newpool'
1422
	));
1423
}
1424

    
1425
if (is_numeric($pool)) {
1426
	$form->addGlobal(new Form_Input(
1427
		'pool',
1428
		null,
1429
		'hidden',
1430
		$pool
1431
	));
1432
}
1433

    
1434
$form->addGlobal(new Form_Input(
1435
	'if',
1436
	null,
1437
	'hidden',
1438
	$if
1439
));
1440

    
1441
print($form);
1442

    
1443
// DHCP Static Mappings table
1444

    
1445
if (!is_numeric($pool) && !($act == "newpool")) {
1446

    
1447
	// Decide whether display of the Client Id column is needed.
1448
	$got_cid = false;
1449
	if (is_array($a_maps)) {
1450
		foreach ($a_maps as $map) {
1451
			if (!empty($map['cid'])) {
1452
				$got_cid = true;
1453
				break;
1454
			}
1455
		}
1456
	}
1457
?>
1458

    
1459
<div class="panel panel-default">
1460
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1461
	<div class="table-responsive">
1462
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1463
				<thead>
1464
					<tr>
1465
						<th><?=gettext("Static ARP")?></th>
1466
						<th><?=gettext("MAC address")?></th>
1467
<?php
1468
	if ($got_cid):
1469
?>
1470
						<th><?=gettext("Client Id")?></th>
1471
<?php
1472
	endif;
1473
?>
1474
						<th><?=gettext("IP address")?></th>
1475
						<th><?=gettext("Hostname")?></th>
1476
						<th><?=gettext("Description")?></th>
1477
						<th></th>
1478
					</tr>
1479
				</thead>
1480
<?php
1481
	if (is_array($a_maps)) {
1482
		$i = 0;
1483
?>
1484
				<tbody>
1485
<?php
1486
		foreach ($a_maps as $mapent) {
1487
?>
1488
					<tr>
1489
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1490
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1491
								<i class="fa fa-check"></i>
1492
							<?php endif; ?>
1493
						</td>
1494
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1495
							<?=htmlspecialchars($mapent['mac'])?>
1496
						</td>
1497
<?php
1498
			if ($got_cid):
1499
?>
1500
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1501
							<?=htmlspecialchars($mapent['cid'])?>
1502
						</td>
1503
<?php
1504
			endif;
1505
?>
1506
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1507
							<?=htmlspecialchars($mapent['ipaddr'])?>
1508
						</td>
1509
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1510
							<?=htmlspecialchars($mapent['hostname'])?>
1511
						</td>
1512
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1513
							<?=htmlspecialchars($mapent['descr'])?>
1514
						</td>
1515
						<td>
1516
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1517
							<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>
1518
						</td>
1519
					</tr>
1520
<?php
1521
		$i++;
1522
		}
1523
?>
1524
				</tbody>
1525
<?php
1526
	}
1527
?>
1528
		</table>
1529
	</div>
1530
</div>
1531

    
1532
<nav class="action-buttons">
1533
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1534
		<i class="fa fa-plus icon-embed-btn"></i>
1535
		<?=gettext("Add")?>
1536
	</a>
1537
</nav>
1538
<?php
1539
}
1540
?>
1541

    
1542
<script type="text/javascript">
1543
//<![CDATA[
1544
events.push(function() {
1545

    
1546
	// Show advanced DNS options ======================================================================================
1547
	var showadvdns = false;
1548

    
1549
	function show_advdns(ispageload) {
1550
		var text;
1551
		// On page load decide the initial state based on the data.
1552
		if (ispageload) {
1553
<?php
1554
			if (!$pconfig['ddnsupdate'] &&
1555
				!$pconfig['ddnsforcehostname'] &&
1556
				empty($pconfig['ddnsdomain']) &&
1557
				empty($pconfig['ddnsdomainprimary']) &&
1558
			    empty($pconfig['ddnsdomainkeyname']) &&
1559
			    (empty($pconfig['ddnsdomainkeyalgorithm']) || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1560
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1561
			    empty($pconfig['ddnsdomainkey'])) {
1562
				$showadv = false;
1563
			} else {
1564
				$showadv = true;
1565
			}
1566
?>
1567
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1568
		} else {
1569
			// It was a click, swap the state.
1570
			showadvdns = !showadvdns;
1571
		}
1572

    
1573
		hideCheckbox('ddnsupdate', !showadvdns);
1574
		hideInput('ddnsdomain', !showadvdns);
1575
		hideCheckbox('ddnsforcehostname', !showadvdns);
1576
		hideInput('ddnsdomainprimary', !showadvdns);
1577
		hideInput('ddnsdomainkeyname', !showadvdns);
1578
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1579
		hideInput('ddnsdomainkey', !showadvdns);
1580
		hideInput('ddnsclientupdates', !showadvdns);
1581

    
1582
		if (showadvdns) {
1583
			text = "<?=gettext('Hide Advanced');?>";
1584
		} else {
1585
			text = "<?=gettext('Display Advanced');?>";
1586
		}
1587
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1588
	}
1589

    
1590
	$('#btnadvdns').click(function(event) {
1591
		show_advdns();
1592
	});
1593

    
1594
	// Show advanced MAC options ======================================================================================
1595
	var showadvmac = false;
1596

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

    
1614
		hideInput('mac_allow', !showadvmac);
1615
		hideInput('mac_deny', !showadvmac);
1616

    
1617
		if (showadvmac) {
1618
			text = "<?=gettext('Hide Advanced');?>";
1619
		} else {
1620
			text = "<?=gettext('Display Advanced');?>";
1621
		}
1622
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1623
	}
1624

    
1625
	$('#btnadvmac').click(function(event) {
1626
		show_advmac();
1627
	});
1628

    
1629
	// Show advanced NTP options ======================================================================================
1630
	var showadvntp = false;
1631

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

    
1649
		hideInput('ntp1', !showadvntp);
1650
		hideInput('ntp2', !showadvntp);
1651

    
1652
		if (showadvntp) {
1653
			text = "<?=gettext('Hide Advanced');?>";
1654
		} else {
1655
			text = "<?=gettext('Display Advanced');?>";
1656
		}
1657
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1658
	}
1659

    
1660
	$('#btnadvntp').click(function(event) {
1661
		show_advntp();
1662
	});
1663

    
1664
	// Show advanced TFTP options ======================================================================================
1665
	var showadvtftp = false;
1666

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

    
1684
		hideInput('tftp', !showadvtftp);
1685

    
1686
		if (showadvtftp) {
1687
			text = "<?=gettext('Hide Advanced');?>";
1688
		} else {
1689
			text = "<?=gettext('Display Advanced');?>";
1690
		}
1691
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1692
	}
1693

    
1694
	$('#btnadvtftp').click(function(event) {
1695
		show_advtftp();
1696
	});
1697

    
1698
	// Show advanced LDAP options ======================================================================================
1699
	var showadvldap = false;
1700

    
1701
	function show_advldap(ispageload) {
1702
		var text;
1703
		// On page load decide the initial state based on the data.
1704
		if (ispageload) {
1705
<?php
1706
			if (empty($pconfig['ldap'])) {
1707
				$showadv = false;
1708
			} else {
1709
				$showadv = true;
1710
			}
1711
?>
1712
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1713
		} else {
1714
			// It was a click, swap the state.
1715
			showadvldap = !showadvldap;
1716
		}
1717

    
1718
		hideInput('ldap', !showadvldap);
1719

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

    
1728
	$('#btnadvldap').click(function(event) {
1729
		show_advldap();
1730
	});
1731

    
1732
	// Show advanced additional opts options ===========================================================================
1733
	var showadvopts = false;
1734

    
1735
	function show_advopts(ispageload) {
1736
		var text;
1737
		// On page load decide the initial state based on the data.
1738
		if (ispageload) {
1739
<?php
1740
			if (empty($pconfig['numberoptions']) ||
1741
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1742
				$showadv = false;
1743
			} else {
1744
				$showadv = true;
1745
			}
1746
?>
1747
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1748
		} else {
1749
			// It was a click, swap the state.
1750
			showadvopts = !showadvopts;
1751
		}
1752

    
1753
		hideClass('adnlopts', !showadvopts);
1754

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

    
1763
	$('#btnadvopts').click(function(event) {
1764
		show_advopts();
1765
	});
1766

    
1767
	// Show advanced Network Booting options ===========================================================================
1768
	var showadvnwkboot = false;
1769

    
1770
	function show_advnwkboot(ispageload) {
1771
		var text;
1772
		// On page load decide the initial state based on the data.
1773
		if (ispageload) {
1774
<?php
1775
			if (empty($pconfig['netboot'])) {
1776
				$showadv = false;
1777
			} else {
1778
				$showadv = true;
1779
			}
1780
?>
1781
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1782
		} else {
1783
			// It was a click, swap the state.
1784
			showadvnwkboot = !showadvnwkboot;
1785
		}
1786

    
1787
		hideCheckbox('netboot', !showadvnwkboot);
1788
		hideInput('nextserver', !showadvnwkboot);
1789
		hideInput('filename', !showadvnwkboot);
1790
		hideInput('filename32', !showadvnwkboot);
1791
		hideInput('filename64', !showadvnwkboot);
1792
		hideInput('rootpath', !showadvnwkboot);
1793

    
1794
		if (showadvnwkboot) {
1795
			text = "<?=gettext('Hide Advanced');?>";
1796
		} else {
1797
			text = "<?=gettext('Display Advanced');?>";
1798
		}
1799
		$('#btnadvnwkboot').html('<i class="fa fa-cog"></i> ' + text);
1800
	}
1801

    
1802
	$('#btnadvnwkboot').click(function(event) {
1803
		show_advnwkboot();
1804
	});
1805

    
1806
	// ---------- On initial page load ------------------------------------------------------------
1807

    
1808
	show_advdns(true);
1809
	show_advmac(true);
1810
	show_advntp(true);
1811
	show_advtftp(true);
1812
	show_advldap(true);
1813
	show_advopts(true);
1814
	show_advnwkboot(true);
1815

    
1816
	// Suppress "Delete row" button if there are fewer than two rows
1817
	checkLastRow();
1818
});
1819
//]]>
1820
</script>
1821

    
1822
<?php include("foot.inc");
(122-122/232)