Project

General

Profile

Download (56.8 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-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2019 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * originally based on m0n0wall (http://m0n0.ch/wall)
12
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
13
 * All rights reserved.
14
 *
15
 * Licensed under the Apache License, Version 2.0 (the "License");
16
 * you may not use this file except in compliance with the License.
17
 * You may obtain a copy of the License at
18
 *
19
 * http://www.apache.org/licenses/LICENSE-2.0
20
 *
21
 * Unless required by applicable law or agreed to in writing, software
22
 * distributed under the License is distributed on an "AS IS" BASIS,
23
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
 * See the License for the specific language governing permissions and
25
 * limitations under the License.
26
 */
27

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

    
35
require_once("guiconfig.inc");
36
require_once("filter.inc");
37
require_once('rrd.inc');
38
require_once("shaper.inc");
39

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

    
45
$if = $_REQUEST['if'];
46
$iflist = get_configured_interface_with_descr();
47

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

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

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

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

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

    
90
			$if = $ifent;
91
			break;
92
		}
93
	}
94
}
95

    
96
$act = $_REQUEST['act'];
97

    
98
$a_pools = array();
99

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

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

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

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

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

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

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

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

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

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

    
193
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
194
$ifcfgsn = $config['interfaces'][$if]['subnet'];
195

    
196
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
197
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
198

    
199
function validate_partial_mac_list($maclist) {
200
	$macs = explode(',', $maclist);
201

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

    
209
	return true;
210
}
211

    
212
if (isset($_POST['save'])) {
213

    
214
	unset($input_errors);
215

    
216
	$pconfig = $_POST;
217

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

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

    
236
	/* input validation */
237

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

    
243
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
244
	}
245

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
526
		$dhcpd_enable_changed = false;
527

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

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

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

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

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

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

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

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

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

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

    
632
		$dhcpdconf['numberoptions'] = $numberoptions;
633

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

    
642
		write_config();
643
	}
644
}
645

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

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

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

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

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

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

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

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

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

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

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

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

    
774
	$pooltbl .=			'</tbody>';
775
	$pooltbl .=		'</table>';
776
	$pooltbl .= '</div>';
777

    
778
	return($pooltbl);
779
}
780

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

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

    
790
include("head.inc");
791

    
792
if ($input_errors) {
793
	print_input_errors($input_errors);
794
}
795

    
796
if ($changes_applied) {
797
	print_apply_result_box($retval);
798
}
799

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

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

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

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

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

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

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

    
845
display_top_tabs($tab_array);
846

    
847
$form = new Form();
848

    
849
$section = new Form_Section('General Options');
850

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

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

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

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

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

    
899

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

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

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

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

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

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

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

    
940
$group = new Form_Group('*Range');
941

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

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

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

    
958
$form->add($section);
959

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

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

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

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

    
983
	$form->add($section);
984
}
985

    
986
$section = new Form_Section('Servers');
987

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

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

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

    
1011
$form->add($section);
1012

    
1013
$section = new Form_Section('Other Options');
1014

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

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

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

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

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

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

    
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

    
1075
	$section->addInput(new Form_Checkbox(
1076
		'statsgraph',
1077
		'Statistics graphs',
1078
		'Enable RRD statistics graphs',
1079
		$pconfig['statsgraph']
1080
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1081

    
1082
	$section->addInput(new Form_Checkbox(
1083
		'disablepingcheck',
1084
		'Ping check',
1085
		'Disable ping check',
1086
		$pconfig['disablepingcheck']
1087
	))->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.');
1088
}
1089

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1349
$form->add($section);
1350

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

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

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

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

    
1371
$numrows = count($item) -1;
1372
$counter = 0;
1373

    
1374
$numrows = count($pconfig['numberoptions']['item']) -1;
1375

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

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

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

    
1392

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

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

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

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

    
1416
	$counter++;
1417
}
1418

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

    
1426
$form->add($section);
1427

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

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

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

    
1453
print($form);
1454

    
1455
// DHCP Static Mappings table
1456

    
1457
if (!is_numeric($pool) && !($act == "newpool")) {
1458

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

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

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

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

    
1558
	// Show advanced DNS options ======================================================================================
1559
	var showadvdns = false;
1560

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

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

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

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

    
1606
	// Show advanced MAC options ======================================================================================
1607
	var showadvmac = false;
1608

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

    
1626
		hideInput('mac_allow', !showadvmac);
1627
		hideInput('mac_deny', !showadvmac);
1628

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

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

    
1641
	// Show advanced NTP options ======================================================================================
1642
	var showadvntp = false;
1643

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

    
1661
		hideInput('ntp1', !showadvntp);
1662
		hideInput('ntp2', !showadvntp);
1663

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

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

    
1676
	// Show advanced TFTP options ======================================================================================
1677
	var showadvtftp = false;
1678

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

    
1696
		hideInput('tftp', !showadvtftp);
1697

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

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

    
1710
	// Show advanced LDAP options ======================================================================================
1711
	var showadvldap = false;
1712

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

    
1730
		hideInput('ldap', !showadvldap);
1731

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

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

    
1744
	// Show advanced additional opts options ===========================================================================
1745
	var showadvopts = false;
1746

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

    
1765
		hideClass('adnlopts', !showadvopts);
1766

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

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

    
1779
	// Show advanced Network Booting options ===========================================================================
1780
	var showadvnwkboot = false;
1781

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

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

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

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

    
1818
	// ---------- On initial page load ------------------------------------------------------------
1819

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

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

    
1834
<?php include("foot.inc");
(118-118/226)