Project

General

Profile

Download (56.7 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['pingcheck'] = $dhcpdconf['pingcheck'];
188
	$pconfig['ddnsclientupdates'] = $dhcpdconf['ddnsclientupdates'];
189
}
190

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

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

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

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

    
207
	return true;
208
}
209

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

    
212
	unset($input_errors);
213

    
214
	$pconfig = $_POST;
215

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

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

    
234
	/* input validation */
235

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
524
		$dhcpd_enable_changed = false;
525

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

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

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

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

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

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

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

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

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

    
625
		// Handle the custom options rowhelper
626
		if (isset($dhcpdconf['numberoptions']['item'])) {
627
			unset($dhcpdconf['numberoptions']['item']);
628
		}
629

    
630
		$dhcpdconf['numberoptions'] = $numberoptions;
631

    
632
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
633
			$a_pools[$pool] = $dhcpdconf;
634
		} elseif ($act == "newpool") {
635
			$a_pools[] = $dhcpdconf;
636
		} else {
637
			$config['dhcpd'][$if] = $dhcpdconf;
638
		}
639

    
640
		write_config();
641
	}
642
}
643

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

    
699
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
700
		$retval = 1;
701
	}
702
}
703

    
704
if ($act == "delpool") {
705
	if ($a_pools[$_POST['id']]) {
706
		unset($a_pools[$_POST['id']]);
707
		write_config();
708
		header("Location: services_dhcp.php?if={$if}");
709
		exit;
710
	}
711
}
712

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

    
728
		header("Location: services_dhcp.php?if={$if}");
729
		exit;
730
	}
731
}
732

    
733
// Build an HTML table that can be inserted into a Form_StaticText element
734
function build_pooltable() {
735
	global $a_pools, $if;
736

    
737
	$pooltbl =	'<div class="table-responsive">';
738
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
739
	$pooltbl .=			'<thead>';
740
	$pooltbl .=				'<tr>';
741
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
742
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
743
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
744
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
745
	$pooltbl .=				'</tr>';
746
	$pooltbl .=			'</thead>';
747
	$pooltbl .=			'<tbody>';
748

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

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

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

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

    
765
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" usepost></a></td>';
766
				$pooltbl .= '</tr>';
767
			}
768
		$i++;
769
		}
770
	}
771

    
772
	$pooltbl .=			'</tbody>';
773
	$pooltbl .=		'</table>';
774
	$pooltbl .= '</div>';
775

    
776
	return($pooltbl);
777
}
778

    
779
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
780
$pglinks = array("", "services_dhcp.php");
781

    
782
if (!empty($if) && isset($iflist[$if])) {
783
	$pgtitle[] = $iflist[$if];
784
	$pglinks[] = "@self";
785
}
786
$shortcut_section = "dhcp";
787

    
788
include("head.inc");
789

    
790
if ($input_errors) {
791
	print_input_errors($input_errors);
792
}
793

    
794
if ($changes_applied) {
795
	print_apply_result_box($retval);
796
}
797

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

    
802
/* active tabs */
803
$tab_array = array();
804
$tabscounter = 0;
805
$i = 0;
806
$have_small_subnet = false;
807

    
808
foreach ($iflist as $ifent => $ifname) {
809
	$oc = $config['interfaces'][$ifent];
810

    
811
	/* Not static IPv4 or subnet >= 31 */
812
	if ($oc['subnet'] >= 31) {
813
		$have_small_subnet = true;
814
		$example_name = $ifname;
815
		$example_cidr = $oc['subnet'];
816
		continue;
817
	}
818
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
819
		continue;
820
	}
821

    
822
	if ($ifent == $if) {
823
		$active = true;
824
	} else {
825
		$active = false;
826
	}
827

    
828
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
829
	$tabscounter++;
830
}
831

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

    
843
display_top_tabs($tab_array);
844

    
845
$form = new Form();
846

    
847
$section = new Form_Section('General Options');
848

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

    
869
$section->addInput(new Form_Checkbox(
870
	'ignorebootp',
871
	'BOOTP',
872
	'Ignore BOOTP queries',
873
	$pconfig['ignorebootp']
874
));
875

    
876
$section->addInput(new Form_Checkbox(
877
	'denyunknown',
878
	'Deny unknown clients',
879
	'Only the clients defined below will get DHCP leases from this server.',
880
	$pconfig['denyunknown']
881
));
882

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

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

    
897

    
898
if (is_numeric($pool) || ($act == "newpool")) {
899
	$section->addInput(new Form_Input(
900
		'descr',
901
		'Pool Description',
902
		'text',
903
		$pconfig['descr']
904
	));
905
}
906

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

    
912
$section->addInput(new Form_StaticText(
913
	'Subnet mask',
914
	gen_subnet_mask($ifcfgsn)
915
));
916

    
917
// Compose a string to display the required address ranges
918
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
919

    
920
if (is_numeric($pool) || ($act == "newpool")) {
921
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
922
	if (is_array($config['dhcpd'][$if]['range'])) {
923
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
924
	}
925

    
926
	foreach ($a_pools as $p) {
927
		if (is_array($p['range'])) {
928
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
929
		}
930
	}
931
}
932

    
933
$section->addInput(new Form_StaticText(
934
	'Available range',
935
	$rangestr
936
));
937

    
938
$group = new Form_Group('*Range');
939

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

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

    
954
$section->add($group);
955

    
956
$form->add($section);
957

    
958
if (!is_numeric($pool) && !($act == "newpool")) {
959
	$section = new Form_Section('Additional Pools');
960

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

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

    
974
	if (is_array($a_pools)) {
975
		$section->addInput(new Form_StaticText(
976
			null,
977
			build_pooltable()
978
		));
979
	}
980

    
981
	$form->add($section);
982
}
983

    
984
$section = new Form_Section('Servers');
985

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

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

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

    
1009
$form->add($section);
1010

    
1011
$section = new Form_Section('Other Options');
1012

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

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

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

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

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

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

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

    
1067
	$section->addInput(new Form_Checkbox(
1068
		'dhcpleaseinlocaltime',
1069
		'Time format change',
1070
		'Change DHCP display lease time from UTC to local time',
1071
		$pconfig['dhcpleaseinlocaltime']
1072
	))->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.' .
1073
				' This will be used for all DHCP interfaces lease time.');
1074
	$section->addInput(new Form_Checkbox(
1075
		'statsgraph',
1076
		'Statistics graphs',
1077
		'Enable RRD statistics graphs',
1078
		$pconfig['statsgraph']
1079
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1080
	$section->addInput(new Form_Checkbox(
1081
		'pingcheck',
1082
		'Ping check',
1083
		'Disable ping check',
1084
		$pconfig['pingcheck']
1085
	))->setHelp('When enabled dhcpd sends a ping to the address being assigned, and if no response has been heard, it assigns the address. Enabled by default.');
1086
}
1087

    
1088
// DDNS
1089
$btnadv = new Form_Button(
1090
	'btnadvdns',
1091
	'Display Advanced',
1092
	null,
1093
	'fa-cog'
1094
);
1095

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

    
1098
$section->addInput(new Form_StaticText(
1099
	'Dynamic DNS',
1100
	$btnadv
1101
));
1102

    
1103
$section->addInput(new Form_Checkbox(
1104
	'ddnsupdate',
1105
	null,
1106
	'Enable registration of DHCP client names in DNS',
1107
	$pconfig['ddnsupdate']
1108
));
1109

    
1110
$section->addInput(new Form_Input(
1111
	'ddnsdomain',
1112
	'DDNS Domain',
1113
	'text',
1114
	$pconfig['ddnsdomain']
1115
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1116

    
1117
$section->addInput(new Form_Checkbox(
1118
	'ddnsforcehostname',
1119
	'DDNS Hostnames',
1120
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1121
	$pconfig['ddnsforcehostname']
1122
))->setHelp('Default registers host name option supplied by DHCP client.');
1123

    
1124
$section->addInput(new Form_IpAddress(
1125
	'ddnsdomainprimary',
1126
	'Primary DDNS address',
1127
	$pconfig['ddnsdomainprimary'],
1128
	'V4'
1129
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1130

    
1131
$section->addInput(new Form_Input(
1132
	'ddnsdomainkeyname',
1133
	'DNS Domain key',
1134
	'text',
1135
	$pconfig['ddnsdomainkeyname']
1136
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1137

    
1138
$section->addInput(new Form_Select(
1139
	'ddnsdomainkeyalgorithm',
1140
	'Key algorithm',
1141
	$pconfig['ddnsdomainkeyalgorithm'],
1142
	array(
1143
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1144
		'hmac-sha1' => 'HMAC-SHA1',
1145
		'hmac-sha224' => 'HMAC-SHA224',
1146
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1147
		'hmac-sha384' => 'HMAC-SHA384',
1148
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1149
	)
1150
));
1151

    
1152
$section->addInput(new Form_Input(
1153
	'ddnsdomainkey',
1154
	'DNS Domain key secret',
1155
	'text',
1156
	$pconfig['ddnsdomainkey']
1157
))->setHelp('Dynamic DNS domain key secret which will be used to register client names in the DNS server.');
1158

    
1159
$section->addInput(new Form_Select(
1160
	'ddnsclientupdates',
1161
	'DDNS Client Updates',
1162
	$pconfig['ddnsclientupdates'],
1163
	array(
1164
	    'allow' => gettext('Allow'),
1165
	    'deny' => gettext('Deny'),
1166
	    'ignore' => gettext('Ignore'))
1167
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
1168
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
1169
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
1170
	    'update and the client can also attempt the update usually using a different domain name.');
1171

    
1172
// Advanced MAC
1173
$btnadv = new Form_Button(
1174
	'btnadvmac',
1175
	'Display Advanced',
1176
	null,
1177
	'fa-cog'
1178
);
1179

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

    
1182
$section->addInput(new Form_StaticText(
1183
	'MAC address control',
1184
	$btnadv
1185
));
1186

    
1187
$section->addInput(new Form_Input(
1188
	'mac_allow',
1189
	'MAC Allow',
1190
	'text',
1191
	$pconfig['mac_allow']
1192
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1193

    
1194
$section->addInput(new Form_Input(
1195
	'mac_deny',
1196
	'MAC Deny',
1197
	'text',
1198
	$pconfig['mac_deny']
1199
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1200

    
1201
// Advanced NTP
1202
$btnadv = new Form_Button(
1203
	'btnadvntp',
1204
	'Display Advanced',
1205
	null,
1206
	'fa-cog'
1207
);
1208

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

    
1211
$section->addInput(new Form_StaticText(
1212
	'NTP',
1213
	$btnadv
1214
));
1215

    
1216
$section->addInput(new Form_IpAddress(
1217
	'ntp1',
1218
	'NTP Server 1',
1219
	$pconfig['ntp1'],
1220
	'HOSTV4'
1221
));
1222

    
1223
$section->addInput(new Form_IpAddress(
1224
	'ntp2',
1225
	'NTP Server 2',
1226
	$pconfig['ntp2'],
1227
	'HOSTV4'
1228
));
1229

    
1230
// Advanced TFTP
1231
$btnadv = new Form_Button(
1232
	'btnadvtftp',
1233
	'Display Advanced',
1234
	null,
1235
	'fa-cog'
1236
);
1237

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

    
1240
$section->addInput(new Form_StaticText(
1241
	'TFTP',
1242
	$btnadv
1243
));
1244

    
1245
$section->addInput(new Form_Input(
1246
	'tftp',
1247
	'TFTP Server',
1248
	'text',
1249
	$pconfig['tftp']
1250
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1251

    
1252
// Advanced LDAP
1253
$btnadv = new Form_Button(
1254
	'btnadvldap',
1255
	'Display Advanced',
1256
	null,
1257
	'fa-cog'
1258
);
1259

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

    
1262
$section->addInput(new Form_StaticText(
1263
	'LDAP',
1264
	$btnadv
1265
));
1266

    
1267
$section->addInput(new Form_Input(
1268
	'ldap',
1269
	'LDAP Server URI',
1270
	'text',
1271
	$pconfig['ldap']
1272
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1273

    
1274
// Advanced Network Booting options
1275
$btnadv = new Form_Button(
1276
	'btnadvnwkboot',
1277
	'Display Advanced',
1278
	null,
1279
	'fa-cog'
1280
);
1281

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

    
1284
$section->addInput(new Form_StaticText(
1285
	'Network Booting',
1286
	$btnadv
1287
));
1288

    
1289
$section->addInput(new Form_Checkbox(
1290
	'netboot',
1291
	'Enable',
1292
	'Enables network booting',
1293
	$pconfig['netboot']
1294
));
1295

    
1296
$section->addInput(new Form_IpAddress(
1297
	'nextserver',
1298
	'Next Server',
1299
	$pconfig['nextserver'],
1300
	'V4'
1301
))->setHelp('Enter the IP address of the next server');
1302

    
1303
$section->addInput(new Form_Input(
1304
	'filename',
1305
	'Default BIOS file name',
1306
	'text',
1307
	$pconfig['filename']
1308
));
1309

    
1310
$section->addInput(new Form_Input(
1311
	'filename32',
1312
	'UEFI 32 bit file name',
1313
	'text',
1314
	$pconfig['filename32']
1315
));
1316

    
1317
$section->addInput(new Form_Input(
1318
	'filename64',
1319
	'UEFI 64 bit file name',
1320
	'text',
1321
	$pconfig['filename64']
1322
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1323
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1324

    
1325
$section->addInput(new Form_Input(
1326
	'rootpath',
1327
	'Root path',
1328
	'text',
1329
	$pconfig['rootpath']
1330
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1331

    
1332
// Advanced Additional options
1333
$btnadv = new Form_Button(
1334
	'btnadvopts',
1335
	'Display Advanced',
1336
	null,
1337
	'fa-cog'
1338
);
1339

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

    
1342
$section->addInput(new Form_StaticText(
1343
	'Additional BOOTP/DHCP Options',
1344
	$btnadv
1345
));
1346

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

    
1349
$section = new Form_Section('Additional BOOTP/DHCP Options');
1350
$section->addClass('adnlopts');
1351

    
1352
$section->addInput(new Form_StaticText(
1353
	null,
1354
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1355
	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>')
1356
));
1357

    
1358
if (!$pconfig['numberoptions']) {
1359
	$pconfig['numberoptions'] = array();
1360
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1361
}
1362

    
1363
$customitemtypes = array(
1364
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1365
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1366
	'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')
1367
);
1368

    
1369
$numrows = count($item) -1;
1370
$counter = 0;
1371

    
1372
$numrows = count($pconfig['numberoptions']['item']) -1;
1373

    
1374
foreach ($pconfig['numberoptions']['item'] as $item) {
1375
	$number = $item['number'];
1376
	$itemtype = $item['type'];
1377
	$value = base64_decode($item['value']);
1378

    
1379
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1380
	$group->addClass('repeatable');
1381

    
1382
	$group->add(new Form_Input(
1383
		'number' . $counter,
1384
		null,
1385
		'number',
1386
		$number,
1387
		['min'=>'1', 'max'=>'254']
1388
	))->setHelp($numrows == $counter ? 'Number':null);
1389

    
1390

    
1391
	$group->add(new Form_Select(
1392
		'itemtype' . $counter,
1393
		null,
1394
		$itemtype,
1395
		$customitemtypes
1396
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1397

    
1398
	$group->add(new Form_Input(
1399
		'value' . $counter,
1400
		null,
1401
		'text',
1402
		$value
1403
	))->setHelp($numrows == $counter ? 'Value':null);
1404

    
1405
	$group->add(new Form_Button(
1406
		'deleterow' . $counter,
1407
		'Delete',
1408
		null,
1409
		'fa-trash'
1410
	))->addClass('btn-warning');
1411

    
1412
	$section->add($group);
1413

    
1414
	$counter++;
1415
}
1416

    
1417
$section->addInput(new Form_Button(
1418
	'addrow',
1419
	'Add',
1420
	null,
1421
	'fa-plus'
1422
))->addClass('btn-success');
1423

    
1424
$form->add($section);
1425

    
1426
if ($act == "newpool") {
1427
	$form->addGlobal(new Form_Input(
1428
		'act',
1429
		null,
1430
		'hidden',
1431
		'newpool'
1432
	));
1433
}
1434

    
1435
if (is_numeric($pool)) {
1436
	$form->addGlobal(new Form_Input(
1437
		'pool',
1438
		null,
1439
		'hidden',
1440
		$pool
1441
	));
1442
}
1443

    
1444
$form->addGlobal(new Form_Input(
1445
	'if',
1446
	null,
1447
	'hidden',
1448
	$if
1449
));
1450

    
1451
print($form);
1452

    
1453
// DHCP Static Mappings table
1454

    
1455
if (!is_numeric($pool) && !($act == "newpool")) {
1456

    
1457
	// Decide whether display of the Client Id column is needed.
1458
	$got_cid = false;
1459
	if (is_array($a_maps)) {
1460
		foreach ($a_maps as $map) {
1461
			if (!empty($map['cid'])) {
1462
				$got_cid = true;
1463
				break;
1464
			}
1465
		}
1466
	}
1467
?>
1468

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

    
1542
<nav class="action-buttons">
1543
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1544
		<i class="fa fa-plus icon-embed-btn"></i>
1545
		<?=gettext("Add")?>
1546
	</a>
1547
</nav>
1548
<?php
1549
}
1550
?>
1551

    
1552
<script type="text/javascript">
1553
//<![CDATA[
1554
events.push(function() {
1555

    
1556
	// Show advanced DNS options ======================================================================================
1557
	var showadvdns = false;
1558

    
1559
	function show_advdns(ispageload) {
1560
		var text;
1561
		// On page load decide the initial state based on the data.
1562
		if (ispageload) {
1563
<?php
1564
			if (!$pconfig['ddnsupdate'] &&
1565
				!$pconfig['ddnsforcehostname'] &&
1566
				empty($pconfig['ddnsdomain']) &&
1567
				empty($pconfig['ddnsdomainprimary']) &&
1568
			    empty($pconfig['ddnsdomainkeyname']) &&
1569
			    (empty($pconfig['ddnsdomainkeyalgorithm']) || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1570
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1571
			    empty($pconfig['ddnsdomainkey'])) {
1572
				$showadv = false;
1573
			} else {
1574
				$showadv = true;
1575
			}
1576
?>
1577
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1578
		} else {
1579
			// It was a click, swap the state.
1580
			showadvdns = !showadvdns;
1581
		}
1582

    
1583
		hideCheckbox('ddnsupdate', !showadvdns);
1584
		hideInput('ddnsdomain', !showadvdns);
1585
		hideCheckbox('ddnsforcehostname', !showadvdns);
1586
		hideInput('ddnsdomainprimary', !showadvdns);
1587
		hideInput('ddnsdomainkeyname', !showadvdns);
1588
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1589
		hideInput('ddnsdomainkey', !showadvdns);
1590
		hideInput('ddnsclientupdates', !showadvdns);
1591

    
1592
		if (showadvdns) {
1593
			text = "<?=gettext('Hide Advanced');?>";
1594
		} else {
1595
			text = "<?=gettext('Display Advanced');?>";
1596
		}
1597
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1598
	}
1599

    
1600
	$('#btnadvdns').click(function(event) {
1601
		show_advdns();
1602
	});
1603

    
1604
	// Show advanced MAC options ======================================================================================
1605
	var showadvmac = false;
1606

    
1607
	function show_advmac(ispageload) {
1608
		var text;
1609
		// On page load decide the initial state based on the data.
1610
		if (ispageload) {
1611
<?php
1612
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1613
				$showadv = false;
1614
			} else {
1615
				$showadv = true;
1616
			}
1617
?>
1618
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1619
		} else {
1620
			// It was a click, swap the state.
1621
			showadvmac = !showadvmac;
1622
		}
1623

    
1624
		hideInput('mac_allow', !showadvmac);
1625
		hideInput('mac_deny', !showadvmac);
1626

    
1627
		if (showadvmac) {
1628
			text = "<?=gettext('Hide Advanced');?>";
1629
		} else {
1630
			text = "<?=gettext('Display Advanced');?>";
1631
		}
1632
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1633
	}
1634

    
1635
	$('#btnadvmac').click(function(event) {
1636
		show_advmac();
1637
	});
1638

    
1639
	// Show advanced NTP options ======================================================================================
1640
	var showadvntp = false;
1641

    
1642
	function show_advntp(ispageload) {
1643
		var text;
1644
		// On page load decide the initial state based on the data.
1645
		if (ispageload) {
1646
<?php
1647
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1648
				$showadv = false;
1649
			} else {
1650
				$showadv = true;
1651
			}
1652
?>
1653
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1654
		} else {
1655
			// It was a click, swap the state.
1656
			showadvntp = !showadvntp;
1657
		}
1658

    
1659
		hideInput('ntp1', !showadvntp);
1660
		hideInput('ntp2', !showadvntp);
1661

    
1662
		if (showadvntp) {
1663
			text = "<?=gettext('Hide Advanced');?>";
1664
		} else {
1665
			text = "<?=gettext('Display Advanced');?>";
1666
		}
1667
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1668
	}
1669

    
1670
	$('#btnadvntp').click(function(event) {
1671
		show_advntp();
1672
	});
1673

    
1674
	// Show advanced TFTP options ======================================================================================
1675
	var showadvtftp = false;
1676

    
1677
	function show_advtftp(ispageload) {
1678
		var text;
1679
		// On page load decide the initial state based on the data.
1680
		if (ispageload) {
1681
<?php
1682
			if (empty($pconfig['tftp'])) {
1683
				$showadv = false;
1684
			} else {
1685
				$showadv = true;
1686
			}
1687
?>
1688
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1689
		} else {
1690
			// It was a click, swap the state.
1691
			showadvtftp = !showadvtftp;
1692
		}
1693

    
1694
		hideInput('tftp', !showadvtftp);
1695

    
1696
		if (showadvtftp) {
1697
			text = "<?=gettext('Hide Advanced');?>";
1698
		} else {
1699
			text = "<?=gettext('Display Advanced');?>";
1700
		}
1701
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1702
	}
1703

    
1704
	$('#btnadvtftp').click(function(event) {
1705
		show_advtftp();
1706
	});
1707

    
1708
	// Show advanced LDAP options ======================================================================================
1709
	var showadvldap = false;
1710

    
1711
	function show_advldap(ispageload) {
1712
		var text;
1713
		// On page load decide the initial state based on the data.
1714
		if (ispageload) {
1715
<?php
1716
			if (empty($pconfig['ldap'])) {
1717
				$showadv = false;
1718
			} else {
1719
				$showadv = true;
1720
			}
1721
?>
1722
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1723
		} else {
1724
			// It was a click, swap the state.
1725
			showadvldap = !showadvldap;
1726
		}
1727

    
1728
		hideInput('ldap', !showadvldap);
1729

    
1730
		if (showadvldap) {
1731
			text = "<?=gettext('Hide Advanced');?>";
1732
		} else {
1733
			text = "<?=gettext('Display Advanced');?>";
1734
		}
1735
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1736
	}
1737

    
1738
	$('#btnadvldap').click(function(event) {
1739
		show_advldap();
1740
	});
1741

    
1742
	// Show advanced additional opts options ===========================================================================
1743
	var showadvopts = false;
1744

    
1745
	function show_advopts(ispageload) {
1746
		var text;
1747
		// On page load decide the initial state based on the data.
1748
		if (ispageload) {
1749
<?php
1750
			if (empty($pconfig['numberoptions']) ||
1751
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1752
				$showadv = false;
1753
			} else {
1754
				$showadv = true;
1755
			}
1756
?>
1757
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1758
		} else {
1759
			// It was a click, swap the state.
1760
			showadvopts = !showadvopts;
1761
		}
1762

    
1763
		hideClass('adnlopts', !showadvopts);
1764

    
1765
		if (showadvopts) {
1766
			text = "<?=gettext('Hide Advanced');?>";
1767
		} else {
1768
			text = "<?=gettext('Display Advanced');?>";
1769
		}
1770
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1771
	}
1772

    
1773
	$('#btnadvopts').click(function(event) {
1774
		show_advopts();
1775
	});
1776

    
1777
	// Show advanced Network Booting options ===========================================================================
1778
	var showadvnwkboot = false;
1779

    
1780
	function show_advnwkboot(ispageload) {
1781
		var text;
1782
		// On page load decide the initial state based on the data.
1783
		if (ispageload) {
1784
<?php
1785
			if (empty($pconfig['netboot'])) {
1786
				$showadv = false;
1787
			} else {
1788
				$showadv = true;
1789
			}
1790
?>
1791
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1792
		} else {
1793
			// It was a click, swap the state.
1794
			showadvnwkboot = !showadvnwkboot;
1795
		}
1796

    
1797
		hideCheckbox('netboot', !showadvnwkboot);
1798
		hideInput('nextserver', !showadvnwkboot);
1799
		hideInput('filename', !showadvnwkboot);
1800
		hideInput('filename32', !showadvnwkboot);
1801
		hideInput('filename64', !showadvnwkboot);
1802
		hideInput('rootpath', !showadvnwkboot);
1803

    
1804
		if (showadvnwkboot) {
1805
			text = "<?=gettext('Hide Advanced');?>";
1806
		} else {
1807
			text = "<?=gettext('Display Advanced');?>";
1808
		}
1809
		$('#btnadvnwkboot').html('<i class="fa fa-cog"></i> ' + text);
1810
	}
1811

    
1812
	$('#btnadvnwkboot').click(function(event) {
1813
		show_advnwkboot();
1814
	});
1815

    
1816
	// ---------- On initial page load ------------------------------------------------------------
1817

    
1818
	show_advdns(true);
1819
	show_advmac(true);
1820
	show_advntp(true);
1821
	show_advtftp(true);
1822
	show_advldap(true);
1823
	show_advopts(true);
1824
	show_advnwkboot(true);
1825

    
1826
	// Suppress "Delete row" button if there are fewer than two rows
1827
	checkLastRow();
1828
});
1829
//]]>
1830
</script>
1831

    
1832
<?php include("foot.inc");
(124-124/234)