Project

General

Profile

Download (56.3 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-2019 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
$iflist = get_configured_interface_with_descr();
45

    
46
/* set the starting interface */
47
if (!$if || !isset($iflist[$if])) {
48
	$found_starting_if = false;
49
	// First look for an interface with DHCP already enabled.
50
	foreach ($iflist as $ifent => $ifname) {
51
		$oc = $config['interfaces'][$ifent];
52
		if (is_array($config['dhcpd'][$ifent]) &&
53
		    isset($config['dhcpd'][$ifent]['enable']) &&
54
		    is_ipaddrv4($oc['ipaddr']) && $oc['subnet'] < 31) {
55
			$if = $ifent;
56
			$found_starting_if = true;
57
			break;
58
		}
59
	}
60

    
61
	/*
62
	 * If there is no DHCP-enabled interface and LAN is a candidate,
63
	 * then choose LAN.
64
	 */
65
	if (!$found_starting_if && isset($iflist['lan']) &&
66
	    is_ipaddrv4($config['interfaces']['lan']['ipaddr']) &&
67
	    $config['interfaces']['lan']['subnet'] < 31) {
68
		$if = 'lan';
69
		$found_starting_if = true;
70
	}
71

    
72
	// At the last select whatever can be found.
73
	if (!$found_starting_if) {
74
		foreach ($iflist as $ifent => $ifname) {
75
			$oc = $config['interfaces'][$ifent];
76

    
77
			/* Not static IPv4 or subnet >= 31 */
78
			if (!is_ipaddrv4($oc['ipaddr']) ||
79
			    empty($oc['subnet']) || $oc['subnet'] < 31) {
80
				continue;
81
			}
82

    
83
			if (!is_array($config['dhcpd'][$ifent]) ||
84
			    !isset($config['dhcpd'][$ifent]['enable'])) {
85
				continue;
86
			}
87

    
88
			$if = $ifent;
89
			break;
90
		}
91
	}
92
}
93

    
94
$act = $_REQUEST['act'];
95

    
96
$a_pools = array();
97

    
98
if (is_array($config['dhcpd'][$if])) {
99
	$pool = $_REQUEST['pool'];
100
	if (is_numeric($_POST['pool'])) {
101
		$pool = $_POST['pool'];
102
	}
103

    
104
	// If we have a pool but no interface name, that's not valid. Redirect away.
105
	if (is_numeric($pool) && empty($if)) {
106
		header("Location: services_dhcp.php");
107
		exit;
108
	}
109

    
110
	init_config_arr(array('dhcpd', $if, 'pool'));
111
	$a_pools = &$config['dhcpd'][$if]['pool'];
112

    
113
	if (is_numeric($pool) && $a_pools[$pool]) {
114
		$dhcpdconf = &$a_pools[$pool];
115
	} elseif ($act == "newpool") {
116
		$dhcpdconf = array();
117
	} else {
118
		$dhcpdconf = &$config['dhcpd'][$if];
119
	}
120

    
121
	init_config_arr(array('dhcpd', $if, 'staticmap'));
122
	$a_maps = &$config['dhcpd'][$if]['staticmap'];
123
}
124

    
125
if (is_array($dhcpdconf)) {
126
	// Global Options
127
	if (!is_numeric($pool) && !($act == "newpool")) {
128
		$pconfig['enable'] = isset($dhcpdconf['enable']);
129
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
130
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
131
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
132
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
133

    
134
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
135
		// then show it true/checked.
136
		foreach ($config['dhcpd'] as $dhcpdifitem) {
137
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
138
			if ($dhcpleaseinlocaltime) {
139
				break;
140
			}
141
		}
142

    
143
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
144
	} else {
145
		// Options that exist only in pools
146
		$pconfig['descr'] = $dhcpdconf['descr'];
147
	}
148

    
149
	// Options that can be global or per-pool.
150
	if (is_array($dhcpdconf['range'])) {
151
		$pconfig['range_from'] = $dhcpdconf['range']['from'];
152
		$pconfig['range_to'] = $dhcpdconf['range']['to'];
153
	}
154

    
155
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
156
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
157
	$pconfig['gateway'] = $dhcpdconf['gateway'];
158
	$pconfig['domain'] = $dhcpdconf['domain'];
159
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
160
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
161
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
162
	$pconfig['ignorebootp'] = isset($dhcpdconf['ignorebootp']);
163
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
164
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
165
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
166
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
167
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
168
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
169
	$pconfig['ddnsdomainkeyalgorithm'] = $dhcpdconf['ddnsdomainkeyalgorithm'];
170
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
171
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
172
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
173
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
174
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
175
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
176
	$pconfig['tftp'] = $dhcpdconf['tftp'];
177
	$pconfig['ldap'] = $dhcpdconf['ldap'];
178
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
179
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
180
	$pconfig['filename'] = $dhcpdconf['filename'];
181
	$pconfig['filename32'] = $dhcpdconf['filename32'];
182
	$pconfig['filename64'] = $dhcpdconf['filename64'];
183
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
184
	$pconfig['netmask'] = $dhcpdconf['netmask'];
185
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
186
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
187
	$pconfig['ddnsclientupdates'] = $dhcpdconf['ddnsclientupdates'];
188
}
189

    
190
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
191
$ifcfgsn = $config['interfaces'][$if]['subnet'];
192

    
193
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
194
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
195

    
196
function validate_partial_mac_list($maclist) {
197
	$macs = explode(',', $maclist);
198

    
199
	// Loop through and look for invalid MACs.
200
	foreach ($macs as $mac) {
201
		if (!is_macaddr($mac, true)) {
202
			return false;
203
		}
204
	}
205

    
206
	return true;
207
}
208

    
209
if (isset($_POST['save'])) {
210

    
211
	unset($input_errors);
212

    
213
	$pconfig = $_POST;
214

    
215
	$numberoptions = array();
216
	for ($x = 0; $x < 99; $x++) {
217
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
218
			if ($_POST["number{$x}"] < 1 || $_POST["number{$x}"] > 254) {
219
				$input_errors[] = gettext("The DHCP option must be a number between 1 and 254.");
220
				continue;
221
			}
222
			$numbervalue = array();
223
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
224
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
225
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
226
			$numberoptions['item'][] = $numbervalue;
227
		}
228
	}
229

    
230
	// Reload the new pconfig variable that the form uses.
231
	$pconfig['numberoptions'] = $numberoptions;
232

    
233
	/* input validation */
234

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

    
240
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
241
	}
242

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

    
247
	if ($_POST['range_from'] && !is_ipaddrv4($_POST['range_from'])) {
248
		$input_errors[] = gettext("A valid IPv4 address must be specified for range from.");
249
	}
250
	if ($_POST['range_to'] && !is_ipaddrv4($_POST['range_to'])) {
251
		$input_errors[] = gettext("A valid IPv4 address must be specified for range to.");
252
	}
253
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
254
		$input_errors[] = gettext("Range From and Range To must both be entered.");
255
	}
256
	if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
257
		$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
258
	}
259
	if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
260
		$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
261
	}
262
	$parent_ip = get_interface_ip($_POST['if']);
263
	if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
264
		$parent_sn = get_interface_subnet($_POST['if']);
265
		if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
266
			$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
267
		}
268
	}
269

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

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

    
278
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
279
		$deftime = 7200; // Default value if it's empty
280
		if (is_numeric($_POST['deftime'])) {
281
			$deftime = $_POST['deftime'];
282
		}
283

    
284
		foreach ($config['captiveportal'] as $cpZone => $cpdata) {
285
			if (!isset($cpdata['enable'])) {
286
				continue;
287
			}
288
			if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
289
				continue;
290
			}
291
			$cp_ifs = explode(',', $cpdata['interface']);
292
			if (!in_array($if, $cp_ifs)) {
293
				continue;
294
			}
295
			if ($cpdata['timeout'] > $deftime) {
296
				$input_errors[] = sprintf(gettext(
297
					'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
298
			}
299
		}
300
	}
301

    
302
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
303
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
304
	}
305
	if ($_POST['ddnsupdate'] && !is_domain($_POST['ddnsdomain'])) {
306
		$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
307
	}
308
	if ($_POST['ddnsupdate'] && !is_ipaddrv4($_POST['ddnsdomainprimary'])) {
309
		$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
310
	}
311
	if ($_POST['ddnsupdate'] && (!$_POST['ddnsdomainkeyname'] || !$_POST['ddnsdomainkeyalgorithm'] || !$_POST['ddnsdomainkey'])) {
312
		$input_errors[] = gettext("A valid domain key name, algorithm and secret must be specified.");
313
	}
314
	if ($_POST['domainsearchlist']) {
315
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
316
		foreach ($domain_array as $curdomain) {
317
			if (!is_domain($curdomain)) {
318
				$input_errors[] = gettext("A valid domain search list must be specified.");
319
				break;
320
			}
321
		}
322
	}
323

    
324
	// Validate MACs
325
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
326
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
327
	}
328
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
329
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
330
	}
331

    
332
	if (($_POST['ntp1'] && (!is_ipaddrv4($_POST['ntp1']) && !is_hostname($_POST['ntp1']))) || ($_POST['ntp2'] && (!is_ipaddrv4($_POST['ntp2']) && !is_hostname($_POST['ntp2'])))) {
333
		$input_errors[] = gettext("A valid IP address or hostname must be specified for the primary/secondary NTP servers.");
334
	}
335
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
336
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
337
	}
338
	if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !filter_var($_POST['tftp'], FILTER_VALIDATE_URL)) {
339
		$input_errors[] = gettext("A valid IP address, hostname or URL must be specified for the TFTP server.");
340
	}
341
	if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
342
		$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
343
	}
344

    
345
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
346
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
347
	}
348
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
349
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
350
	}
351

    
352
	// Disallow a range that includes the virtualip
353
	if (is_array($config['virtualip']['vip'])) {
354
		foreach ($config['virtualip']['vip'] as $vip) {
355
			if ($vip['interface'] == $if) {
356
				if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
357
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
358
				}
359
			}
360
		}
361
	}
362

    
363
	$noip = false;
364
	if (is_array($a_maps)) {
365
		foreach ($a_maps as $map) {
366
			if (empty($map['ipaddr'])) {
367
				$noip = true;
368
			}
369
		}
370
	}
371

    
372
	if ($_POST['staticarp'] && $noip) {
373
		$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.");
374
	}
375

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

    
403
	if ((!isset($pool) || !is_numeric($pool)) && $act != "newpool") {
404
		/* If enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
405
		if ($_POST['enable'] && isset($config['dhcrelay']['enable']) &&
406
		    (stristr($config['dhcrelay']['interface'], $if) !== false)) {
407
			$input_errors[] = sprintf(gettext(
408
			    "The DHCP relay on the %s interface must be disabled before enabling the DHCP server."),
409
			    $iflist[$if]);
410
		}
411

    
412
		/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
413
		if (!$_POST['enable']) {
414
			/* Find out how many other interfaces have DHCP enabled. */
415
			$dhcp_enabled_count = 0;
416
			foreach ($config['dhcpd'] as $dhif => $dhcps) {
417
				if ($dhif == $if) {
418
					/* Skip this interface, we only want to know how many others are enabled. */
419
					continue;
420
				}
421
				if (isset($dhcps['enable'])) {
422
					$dhcp_enabled_count++;
423
				}
424
			}
425

    
426
			if (isset($config['dnsmasq']['enable']) &&
427
			    ($dhcp_enabled_count == 0) &&
428
			    (isset($config['dnsmasq']['regdhcp']) ||
429
			    isset($config['dnsmasq']['regdhcpstatic']) ||
430
			    isset($config['dnsmasq']['dhcpfirst']))) {
431
				$input_errors[] = gettext(
432
				    "DHCP Registration features in the DNS Forwarder are active and require at least one enabled DHCP Server.");
433
			}
434
			if (isset($config['unbound']['enable']) &&
435
			    ($dhcp_enabled_count == 0) &&
436
			    (isset($config['unbound']['regdhcp']) ||
437
			    isset($config['unbound']['regdhcpstatic']))) {
438
				$input_errors[] = gettext(
439
				    "DHCP Registration features in the DNS Resolver are active and require at least one enabled DHCP Server.");
440
			}
441
		}
442
	}
443

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

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

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

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

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

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

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

    
523
		$dhcpd_enable_changed = false;
524

    
525
		// Global Options
526
		if (!is_numeric($pool) && !($act == "newpool")) {
527
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
528
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
529
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
530
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
531
				$dhcpd_enable_changed = true;
532
			}
533

    
534
			$dhcpdconf['enable'] = $new_dhcpd_enable;
535
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
536
			$previous = $dhcpdconf['failover_peerip'];
537
			if ($previous != $_POST['failover_peerip']) {
538
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
539
			}
540

    
541
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
542
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
543
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
544
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
545
			}
546
		} else {
547
			// Options that exist only in pools
548
			$dhcpdconf['descr'] = $_POST['descr'];
549
		}
550

    
551
		// Options that can be global or per-pool.
552
		$dhcpdconf['range']['from'] = $_POST['range_from'];
553
		$dhcpdconf['range']['to'] = $_POST['range_to'];
554
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
555
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
556
		$dhcpdconf['netmask'] = $_POST['netmask'];
557

    
558
		unset($dhcpdconf['winsserver']);
559
		if ($_POST['wins1']) {
560
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
561
		}
562
		if ($_POST['wins2']) {
563
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
564
		}
565

    
566
		unset($dhcpdconf['dnsserver']);
567
		if ($_POST['dns1']) {
568
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
569
		}
570
		if ($_POST['dns2']) {
571
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
572
		}
573
		if ($_POST['dns3']) {
574
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
575
		}
576
		if ($_POST['dns4']) {
577
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
578
		}
579

    
580
		$dhcpdconf['gateway'] = $_POST['gateway'];
581
		$dhcpdconf['domain'] = $_POST['domain'];
582
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
583
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
584
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
585
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
586
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
587
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
588
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
589
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
590
		$dhcpdconf['ddnsdomainkeyalgorithm'] = $_POST['ddnsdomainkeyalgorithm'];
591
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
592
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
593
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
594
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
595
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
596
		$dhcpdconf['ddnsclientupdates'] = $_POST['ddnsclientupdates'];
597

    
598
		unset($dhcpdconf['ntpserver']);
599
		if ($_POST['ntp1']) {
600
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
601
		}
602
		if ($_POST['ntp2']) {
603
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
604
		}
605

    
606
		$dhcpdconf['tftp'] = $_POST['tftp'];
607
		$dhcpdconf['ldap'] = $_POST['ldap'];
608
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
609
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
610
		$dhcpdconf['filename'] = $_POST['filename'];
611
		$dhcpdconf['filename32'] = $_POST['filename32'];
612
		$dhcpdconf['filename64'] = $_POST['filename64'];
613
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
614
		unset($dhcpdconf['statsgraph']);
615
		if ($_POST['statsgraph']) {
616
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
617
			enable_rrd_graphing();
618
		}
619

    
620
		// Handle the custom options rowhelper
621
		if (isset($dhcpdconf['numberoptions']['item'])) {
622
			unset($dhcpdconf['numberoptions']['item']);
623
		}
624

    
625
		$dhcpdconf['numberoptions'] = $numberoptions;
626

    
627
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
628
			$a_pools[$pool] = $dhcpdconf;
629
		} elseif ($act == "newpool") {
630
			$a_pools[] = $dhcpdconf;
631
		} else {
632
			$config['dhcpd'][$if] = $dhcpdconf;
633
		}
634

    
635
		write_config();
636
	}
637
}
638

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

    
694
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
695
		$retval = 1;
696
	}
697
}
698

    
699
if ($act == "delpool") {
700
	if ($a_pools[$_POST['id']]) {
701
		unset($a_pools[$_POST['id']]);
702
		write_config();
703
		header("Location: services_dhcp.php?if={$if}");
704
		exit;
705
	}
706
}
707

    
708
if ($act == "del") {
709
	if (isset($a_maps[$_POST['id']])) {
710
		/* Remove static ARP entry, if necessary */
711
		if (isset($a_maps[$_POST['id']]['arp_table_static_entry'])) {
712
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_POST['id']]['ipaddr']));
713
		}
714
		unset($a_maps[$_POST['id']]);
715
		write_config();
716
		if (isset($config['dhcpd'][$if]['enable'])) {
717
			mark_subsystem_dirty('staticmaps');
718
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
719
				mark_subsystem_dirty('hosts');
720
			}
721
		}
722

    
723
		header("Location: services_dhcp.php?if={$if}");
724
		exit;
725
	}
726
}
727

    
728
// Build an HTML table that can be inserted into a Form_StaticText element
729
function build_pooltable() {
730
	global $a_pools, $if;
731

    
732
	$pooltbl =	'<div class="table-responsive">';
733
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
734
	$pooltbl .=			'<thead>';
735
	$pooltbl .=				'<tr>';
736
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
737
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
738
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
739
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
740
	$pooltbl .=				'</tr>';
741
	$pooltbl .=			'</thead>';
742
	$pooltbl .=			'<tbody>';
743

    
744
	if (is_array($a_pools)) {
745
		$i = 0;
746
		foreach ($a_pools as $poolent) {
747
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
748
				$pooltbl .= '<tr>';
749
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
750
							htmlspecialchars($poolent['range']['from']) . '</td>';
751

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

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

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

    
760
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" usepost></a></td>';
761
				$pooltbl .= '</tr>';
762
			}
763
		$i++;
764
		}
765
	}
766

    
767
	$pooltbl .=			'</tbody>';
768
	$pooltbl .=		'</table>';
769
	$pooltbl .= '</div>';
770

    
771
	return($pooltbl);
772
}
773

    
774
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
775
$pglinks = array("", "services_dhcp.php");
776

    
777
if (!empty($if) && isset($iflist[$if])) {
778
	$pgtitle[] = $iflist[$if];
779
	$pglinks[] = "@self";
780
}
781
$shortcut_section = "dhcp";
782

    
783
include("head.inc");
784

    
785
if ($input_errors) {
786
	print_input_errors($input_errors);
787
}
788

    
789
if ($changes_applied) {
790
	print_apply_result_box($retval);
791
}
792

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

    
797
/* active tabs */
798
$tab_array = array();
799
$tabscounter = 0;
800
$i = 0;
801
$have_small_subnet = false;
802

    
803
foreach ($iflist as $ifent => $ifname) {
804
	$oc = $config['interfaces'][$ifent];
805

    
806
	/* Not static IPv4 or subnet >= 31 */
807
	if ($oc['subnet'] >= 31) {
808
		$have_small_subnet = true;
809
		$example_name = $ifname;
810
		$example_cidr = $oc['subnet'];
811
		continue;
812
	}
813
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
814
		continue;
815
	}
816

    
817
	if ($ifent == $if) {
818
		$active = true;
819
	} else {
820
		$active = false;
821
	}
822

    
823
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
824
	$tabscounter++;
825
}
826

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

    
838
display_top_tabs($tab_array);
839

    
840
$form = new Form();
841

    
842
$section = new Form_Section('General Options');
843

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

    
864
$section->addInput(new Form_Checkbox(
865
	'ignorebootp',
866
	'BOOTP',
867
	'Ignore BOOTP queries',
868
	$pconfig['ignorebootp']
869
));
870

    
871
$section->addInput(new Form_Checkbox(
872
	'denyunknown',
873
	'Deny unknown clients',
874
	'Only the clients defined below will get DHCP leases from this server.',
875
	$pconfig['denyunknown']
876
));
877

    
878
$section->addInput(new Form_Checkbox(
879
	'nonak',
880
	'Ignore denied clients',
881
	'Denied clients will be ignored rather than rejected.',
882
	$pconfig['nonak']
883
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
884

    
885
$section->addInput(new Form_Checkbox(
886
	'ignoreclientuids',
887
	'Ignore client identifiers',
888
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
889
	$pconfig['ignoreclientuids']
890
))->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.");
891

    
892

    
893
if (is_numeric($pool) || ($act == "newpool")) {
894
	$section->addInput(new Form_Input(
895
		'descr',
896
		'Pool Description',
897
		'text',
898
		$pconfig['descr']
899
	));
900
}
901

    
902
$section->addInput(new Form_StaticText(
903
	'Subnet',
904
	gen_subnet($ifcfgip, $ifcfgsn)
905
));
906

    
907
$section->addInput(new Form_StaticText(
908
	'Subnet mask',
909
	gen_subnet_mask($ifcfgsn)
910
));
911

    
912
// Compose a string to display the required address ranges
913
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
914

    
915
if (is_numeric($pool) || ($act == "newpool")) {
916
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
917
	if (is_array($config['dhcpd'][$if]['range'])) {
918
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
919
	}
920

    
921
	foreach ($a_pools as $p) {
922
		if (is_array($p['range'])) {
923
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
924
		}
925
	}
926
}
927

    
928
$section->addInput(new Form_StaticText(
929
	'Available range',
930
	$rangestr
931
));
932

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1161
// Advanced MAC
1162
$btnadv = new Form_Button(
1163
	'btnadvmac',
1164
	'Display Advanced',
1165
	null,
1166
	'fa-cog'
1167
);
1168

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

    
1171
$section->addInput(new Form_StaticText(
1172
	'MAC address control',
1173
	$btnadv
1174
));
1175

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

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

    
1190
// Advanced NTP
1191
$btnadv = new Form_Button(
1192
	'btnadvntp',
1193
	'Display Advanced',
1194
	null,
1195
	'fa-cog'
1196
);
1197

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

    
1200
$section->addInput(new Form_StaticText(
1201
	'NTP',
1202
	$btnadv
1203
));
1204

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1336
$form->add($section);
1337

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

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

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

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

    
1358
$numrows = count($item) -1;
1359
$counter = 0;
1360

    
1361
$numrows = count($pconfig['numberoptions']['item']) -1;
1362

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

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

    
1371
	$group->add(new Form_Input(
1372
		'number' . $counter,
1373
		null,
1374
		'number',
1375
		$number,
1376
		['min'=>'1', 'max'=>'254']
1377
	))->setHelp($numrows == $counter ? 'Number':null);
1378

    
1379

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

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

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

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

    
1403
	$counter++;
1404
}
1405

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

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

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

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

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

    
1440
print($form);
1441

    
1442
// DHCP Static Mappings table
1443

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1805
	// ---------- On initial page load ------------------------------------------------------------
1806

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

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

    
1821
<?php include("foot.inc");
(125-125/235)