Project

General

Profile

Download (55.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_dhcp.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally based on m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions are met:
15
 *
16
 * 1. Redistributions of source code must retain the above copyright notice,
17
 *    this list of conditions and the following disclaimer.
18
 *
19
 * 2. Redistributions in binary form must reproduce the above copyright
20
 *    notice, this list of conditions and the following disclaimer in
21
 *    the documentation and/or other materials provided with the
22
 *    distribution.
23
 *
24
 * 3. All advertising materials mentioning features or use of this software
25
 *    must display the following acknowledgment:
26
 *    "This product includes software developed by the pfSense Project
27
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
28
 *
29
 * 4. The names "pfSense" and "pfSense Project" must not be used to
30
 *    endorse or promote products derived from this software without
31
 *    prior written permission. For written permission, please contact
32
 *    coreteam@pfsense.org.
33
 *
34
 * 5. Products derived from this software may not be called "pfSense"
35
 *    nor may "pfSense" appear in their names without prior written
36
 *    permission of the Electric Sheep Fencing, LLC.
37
 *
38
 * 6. Redistributions of any form whatsoever must retain the following
39
 *    acknowledgment:
40
 *
41
 * "This product includes software developed by the pfSense Project
42
 * for use in the pfSense software distribution (http://www.pfsense.org/).
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
45
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
48
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55
 * OF THE POSSIBILITY OF SUCH DAMAGE.
56
 */
57

    
58
##|+PRIV
59
##|*IDENT=page-services-dhcpserver
60
##|*NAME=Services: DHCP Server
61
##|*DESCR=Allow access to the 'Services: DHCP Server' page.
62
##|*MATCH=services_dhcp.php*
63
##|-PRIV
64

    
65
require_once("guiconfig.inc");
66
require_once("filter.inc");
67
require_once('rrd.inc');
68
require_once("shaper.inc");
69

    
70
if (!$g['services_dhcp_server_enable']) {
71
	header("Location: /");
72
	exit;
73
}
74

    
75
$if = $_GET['if'];
76
if (!empty($_POST['if'])) {
77
	$if = $_POST['if'];
78
}
79

    
80
/* if OLSRD is enabled, allow WAN to house DHCP. */
81
if ($config['installedpackages']['olsrd']) {
82
	foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
83
		if ($olsrd['enable']) {
84
			$is_olsr_enabled = true;
85
			break;
86
		}
87
	}
88
}
89

    
90
$iflist = get_configured_interface_with_descr();
91

    
92
/* set the starting interface */
93
if (!$if || !isset($iflist[$if])) {
94
	$found_starting_if = false;
95
	// First look for an interface with DHCP already enabled.
96
	foreach ($iflist as $ifent => $ifname) {
97
		$oc = $config['interfaces'][$ifent];
98
		if (is_array($config['dhcpd'][$ifent]) &&
99
		    isset($config['dhcpd'][$ifent]['enable']) &&
100
		    is_ipaddrv4($oc['ipaddr']) && $oc['subnet'] < 31) {
101
			$if = $ifent;
102
			$found_starting_if = true;
103
			break;
104
		}
105
	}
106

    
107
	/*
108
	 * If there is no DHCP-enabled interface and LAN is a candidate,
109
	 * then choose LAN.
110
	 */
111
	if (!$found_starting_if && isset($iflist['lan']) &&
112
	    is_ipaddrv4($config['interfaces']['lan']['ipaddr']) &&
113
	    $config['interfaces']['lan']['subnet'] < 31) {
114
		$if = 'lan';
115
		$found_starting_if = true;
116
	}
117

    
118
	// At the last select whatever can be found.
119
	if (!$found_starting_if) {
120
		foreach ($iflist as $ifent => $ifname) {
121
			$oc = $config['interfaces'][$ifent];
122

    
123
			/* Not static IPv4 or subnet >= 31 */
124
			if (!is_ipaddrv4($oc['ipaddr']) ||
125
			    empty($oc['subnet']) || $oc['subnet'] < 31) {
126
				continue;
127
			}
128

    
129
			if (!is_array($config['dhcpd'][$ifent]) ||
130
			    !isset($config['dhcpd'][$ifent]['enable'])) {
131
				continue;
132
			}
133

    
134
			$if = $ifent;
135
			break;
136
		}
137
	}
138
}
139

    
140
$act = $_GET['act'];
141
if (!empty($_POST['act'])) {
142
	$act = $_POST['act'];
143
}
144

    
145
$a_pools = array();
146

    
147
if (is_array($config['dhcpd'][$if])) {
148
	$pool = $_GET['pool'];
149
	if (is_numeric($_POST['pool'])) {
150
		$pool = $_POST['pool'];
151
	}
152

    
153
	// If we have a pool but no interface name, that's not valid. Redirect away.
154
	if (is_numeric($pool) && empty($if)) {
155
		header("Location: services_dhcp.php");
156
		exit;
157
	}
158

    
159
	if (!is_array($config['dhcpd'][$if]['pool'])) {
160
		$config['dhcpd'][$if]['pool'] = array();
161
	}
162

    
163
	$a_pools = &$config['dhcpd'][$if]['pool'];
164

    
165
	if (is_numeric($pool) && $a_pools[$pool]) {
166
		$dhcpdconf = &$a_pools[$pool];
167
	} elseif ($act == "newpool") {
168
		$dhcpdconf = array();
169
	} else {
170
		$dhcpdconf = &$config['dhcpd'][$if];
171
	}
172

    
173
	if (!is_array($config['dhcpd'][$if]['staticmap'])) {
174
		$dhcpdconf['staticmap'] = array();
175
	}
176

    
177
	$a_maps = &$config['dhcpd'][$if]['staticmap'];
178
}
179
if (is_array($dhcpdconf)) {
180
	// Global Options
181
	if (!is_numeric($pool) && !($act == "newpool")) {
182
		$pconfig['enable'] = isset($dhcpdconf['enable']);
183
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
184
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
185
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
186
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
187

    
188
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
189
		// then show it true/checked.
190
		foreach ($config['dhcpd'] as $dhcpdifitem) {
191
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
192
			if ($dhcpleaseinlocaltime) {
193
				break;
194
			}
195
		}
196

    
197
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
198
	} else {
199
		// Options that exist only in pools
200
		$pconfig['descr'] = $dhcpdconf['descr'];
201
	}
202

    
203
	// Options that can be global or per-pool.
204
	if (is_array($dhcpdconf['range'])) {
205
		$pconfig['range_from'] = $dhcpdconf['range']['from'];
206
		$pconfig['range_to'] = $dhcpdconf['range']['to'];
207
	}
208

    
209
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
210
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
211
	$pconfig['gateway'] = $dhcpdconf['gateway'];
212
	$pconfig['domain'] = $dhcpdconf['domain'];
213
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
214
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
215
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
216
	$pconfig['ignorebootp'] = isset($dhcpdconf['ignorebootp']);
217
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
218
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
219
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
220
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
221
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
222
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
223
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
224
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
225
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
226
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
227
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
228
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
229
	$pconfig['tftp'] = $dhcpdconf['tftp'];
230
	$pconfig['ldap'] = $dhcpdconf['ldap'];
231
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
232
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
233
	$pconfig['filename'] = $dhcpdconf['filename'];
234
	$pconfig['filename32'] = $dhcpdconf['filename32'];
235
	$pconfig['filename64'] = $dhcpdconf['filename64'];
236
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
237
	$pconfig['netmask'] = $dhcpdconf['netmask'];
238
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
239
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
240
}
241

    
242
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
243
$ifcfgsn = $config['interfaces'][$if]['subnet'];
244

    
245
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
246
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
247

    
248
function validate_partial_mac_list($maclist) {
249
	$macs = explode(',', $maclist);
250

    
251
	// Loop through and look for invalid MACs.
252
	foreach ($macs as $mac) {
253
		if (!is_macaddr($mac, true)) {
254
			return false;
255
		}
256
	}
257

    
258
	return true;
259
}
260

    
261
if (isset($_POST['save'])) {
262

    
263
	unset($input_errors);
264

    
265
	$pconfig = $_POST;
266

    
267
	$numberoptions = array();
268
	for ($x = 0; $x < 99; $x++) {
269
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
270
			$numbervalue = array();
271
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
272
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
273
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
274
			$numberoptions['item'][] = $numbervalue;
275
		}
276
	}
277

    
278
	// Reload the new pconfig variable that the form uses.
279
	$pconfig['numberoptions'] = $numberoptions;
280

    
281
	/* input validation */
282

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

    
288
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
289
	}
290

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

    
295
	if ($_POST['range_from'] && !is_ipaddrv4($_POST['range_from'])) {
296
		$input_errors[] = gettext("A valid IPv4 address must be specified for range from.");
297
	}
298
	if ($_POST['range_to'] && !is_ipaddrv4($_POST['range_to'])) {
299
		$input_errors[] = gettext("A valid IPv4 address must be specified for range to.");
300
	}
301
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
302
		$input_errors[] = gettext("Range From and Range To must both be entered.");
303
	}
304
	if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
305
		$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
306
	}
307
	if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
308
		$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
309
	}
310
	$parent_ip = get_interface_ip($_POST['if']);
311
	if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
312
		$parent_sn = get_interface_subnet($_POST['if']);
313
		if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
314
			$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
315
		}
316
	}
317

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

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

    
326
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
327
		$deftime = 7200; // Default value if it's empty
328
		if (is_numeric($_POST['deftime'])) {
329
			$deftime = $_POST['deftime'];
330
		}
331

    
332
		foreach ($config['captiveportal'] as $cpZone => $cpdata) {
333
			if (!isset($cpdata['enable'])) {
334
				continue;
335
			}
336
			if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
337
				continue;
338
			}
339
			$cp_ifs = explode(',', $cpdata['interface']);
340
			if (!in_array($if, $cp_ifs)) {
341
				continue;
342
			}
343
			if ($cpdata['timeout'] > $deftime) {
344
				$input_errors[] = sprintf(gettext(
345
					'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
346
			}
347
		}
348
	}
349

    
350
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
351
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
352
	}
353
	if (($_POST['ddnsdomain'] && !is_domain($_POST['ddnsdomain']))) {
354
		$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
355
	}
356
	if (($_POST['ddnsdomain'] && !is_ipaddrv4($_POST['ddnsdomainprimary']))) {
357
		$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
358
	}
359
	if (($_POST['ddnsdomainkey'] && !$_POST['ddnsdomainkeyname']) ||
360
		($_POST['ddnsdomainkeyname'] && !$_POST['ddnsdomainkey'])) {
361
		$input_errors[] = gettext("Both a valid domain key and key name must be specified.");
362
	}
363
	if ($_POST['domainsearchlist']) {
364
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
365
		foreach ($domain_array as $curdomain) {
366
			if (!is_domain($curdomain)) {
367
				$input_errors[] = gettext("A valid domain search list must be specified.");
368
				break;
369
			}
370
		}
371
	}
372

    
373
	// Validate MACs
374
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
375
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
376
	}
377
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
378
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
379
	}
380

    
381
	if (($_POST['ntp1'] && (!is_ipaddrv4($_POST['ntp1']) && !is_hostname($_POST['ntp1']))) || ($_POST['ntp2'] && (!is_ipaddrv4($_POST['ntp2']) && !is_hostname($_POST['ntp2'])))) {
382
		$input_errors[] = gettext("A valid IP address or hostname must be specified for the primary/secondary NTP servers.");
383
	}
384
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
385
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
386
	}
387
	if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !filter_var($_POST['tftp'], FILTER_VALIDATE_URL)) {
388
		$input_errors[] = gettext("A valid IP address, hostname or URL must be specified for the TFTP server.");
389
	}
390
	if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
391
		$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
392
	}
393

    
394
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
395
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
396
	}
397
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
398
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
399
	}
400

    
401
	// Disallow a range that includes the virtualip
402
	if (is_array($config['virtualip']['vip'])) {
403
		foreach ($config['virtualip']['vip'] as $vip) {
404
			if ($vip['interface'] == $if) {
405
				if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
406
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
407
				}
408
			}
409
		}
410
	}
411

    
412
	$noip = false;
413
	if (is_array($a_maps)) {
414
		foreach ($a_maps as $map) {
415
			if (empty($map['ipaddr'])) {
416
				$noip = true;
417
			}
418
		}
419
	}
420

    
421
	if ($_POST['staticarp'] && $noip) {
422
		$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.");
423
	}
424

    
425
	if (is_array($pconfig['numberoptions']['item'])) {
426
		foreach ($pconfig['numberoptions']['item'] as $numberoption) {
427
			$numberoption_value = base64_decode($numberoption['value']);
428
			if ($numberoption['type'] == 'text' && strstr($numberoption_value, '"')) {
429
				$input_errors[] = gettext("Text type cannot include quotation marks.");
430
			} else if ($numberoption['type'] == 'string' && !preg_match('/^"[^"]*"$/', $numberoption_value) && !preg_match('/^[0-9a-f]{2}(?:\:[0-9a-f]{2})*$/i', $numberoption_value)) {
431
				$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");
432
			} else if ($numberoption['type'] == 'boolean' && $numberoption_value != 'true' && $numberoption_value != 'false' && $numberoption_value != 'on' && $numberoption_value != 'off') {
433
				$input_errors[] = gettext("Boolean type must be true, false, on, or off.");
434
			} else if ($numberoption['type'] == 'unsigned integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 255)) {
435
				$input_errors[] = gettext("Unsigned 8-bit integer type must be a number in the range 0 to 255.");
436
			} else if ($numberoption['type'] == 'unsigned integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 65535)) {
437
				$input_errors[] = gettext("Unsigned 16-bit integer type must be a number in the range 0 to 65535.");
438
			} else if ($numberoption['type'] == 'unsigned integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 4294967295)) {
439
				$input_errors[] = gettext("Unsigned 32-bit integer type must be a number in the range 0 to 4294967295.");
440
			} else if ($numberoption['type'] == 'signed integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < -128 || $numberoption_value > 127)) {
441
				$input_errors[] = gettext("Signed 8-bit integer type must be a number in the range -128 to 127.");
442
			} else if ($numberoption['type'] == 'signed integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < -32768 || $numberoption_value > 32767)) {
443
				$input_errors[] = gettext("Signed 16-bit integer type must be a number in the range -32768 to 32767.");
444
			} else if ($numberoption['type'] == 'signed integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < -2147483648 || $numberoption_value > 2147483647)) {
445
				$input_errors[] = gettext("Signed 32-bit integer type must be a number in the range -2147483648 to 2147483647.");
446
			} else if ($numberoption['type'] == 'ip-address' && !is_ipaddrv4($numberoption_value) && !is_hostname($numberoption_value)) {
447
				$input_errors[] = gettext("IP address or host type must be an IP address or host name.");
448
			}
449
		}
450
	}
451

    
452
	/* If enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
453
	if ($_POST['enable'] && isset($config['dhcrelay']['enable']) && (stristr($config['dhcrelay']['interface'], $if) !== false)) {
454
		$input_errors[] = sprintf(gettext("The DHCP relay on the %s interface must be disabled before enabling the DHCP server."), $iflist[$if]);
455
	}
456

    
457
	/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
458
	if (!$_POST['enable']) {
459
		if (isset($config['dnsmasq']['enable']) && (isset($config['dnsmasq']['regdhcp']) || isset($config['dnsmasq']['regdhcpstatic']) || isset($config['dnsmasq']['dhcpfirst']))) {
460
			$input_errors[] = gettext("Disable DHCP Registration features in DNS Forwarder before disabling DHCP Server.");
461
		}
462
		if (isset($config['unbound']['enable']) && (isset($config['unbound']['regdhcp']) || isset($config['unbound']['regdhcpstatic']))) {
463
			$input_errors[] = gettext("Disable DHCP Registration features in DNS Resolver before disabling DHCP Server.");
464
		}
465
	}
466

    
467
	// 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.
468
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
469
		/* make sure the range lies within the current subnet */
470
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
471
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
472
		}
473

    
474
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
475
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
476
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
477
		}
478

    
479
		if (is_numeric($pool) || ($act == "newpool")) {
480
			if (is_inrange_v4($_POST['range_from'],
481
				$config['dhcpd'][$if]['range']['from'],
482
				$config['dhcpd'][$if]['range']['to']) ||
483
				is_inrange_v4($_POST['range_to'],
484
				$config['dhcpd'][$if]['range']['from'],
485
				$config['dhcpd'][$if]['range']['to'])) {
486
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
487
			}
488
		}
489

    
490
		foreach ($a_pools as $id => $p) {
491
			if (is_numeric($pool) && ($id == $pool)) {
492
				continue;
493
			}
494

    
495
			if (is_inrange_v4($_POST['range_from'],
496
				$p['range']['from'], $p['range']['to']) ||
497
				is_inrange_v4($_POST['range_to'],
498
				$p['range']['from'], $p['range']['to'])) {
499
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
500
				break;
501
			}
502
		}
503

    
504
		if (is_array($a_maps)) {
505
			foreach ($a_maps as $map) {
506
				if (empty($map['ipaddr'])) {
507
					continue;
508
				}
509
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
510
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
511
					break;
512
				}
513
			}
514
		}
515
	}
516

    
517
	if (!$input_errors) {
518
		if (!is_numeric($pool)) {
519
			if ($act == "newpool") {
520
				$dhcpdconf = array();
521
			} else {
522
				if (!is_array($config['dhcpd'][$if])) {
523
					$config['dhcpd'][$if] = array();
524
				}
525
				$dhcpdconf = $config['dhcpd'][$if];
526
			}
527
		} else {
528
			if (is_array($a_pools[$pool])) {
529
				$dhcpdconf = $a_pools[$pool];
530
			} else {
531
				// Someone specified a pool but it doesn't exist. Punt.
532
				header("Location: services_dhcp.php");
533
				exit;
534
			}
535
		}
536
		if (!is_array($dhcpdconf['range'])) {
537
			$dhcpdconf['range'] = array();
538
		}
539

    
540
		$dhcpd_enable_changed = false;
541

    
542
		// Global Options
543
		if (!is_numeric($pool) && !($act == "newpool")) {
544
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
545
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
546
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
547
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
548
				$dhcpd_enable_changed = true;
549
			}
550

    
551
			$dhcpdconf['enable'] = $new_dhcpd_enable;
552
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
553
			$previous = $dhcpdconf['failover_peerip'];
554
			if ($previous != $_POST['failover_peerip']) {
555
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
556
			}
557

    
558
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
559
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
560
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
561
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
562
			}
563
		} else {
564
			// Options that exist only in pools
565
			$dhcpdconf['descr'] = $_POST['descr'];
566
		}
567

    
568
		// Options that can be global or per-pool.
569
		$dhcpdconf['range']['from'] = $_POST['range_from'];
570
		$dhcpdconf['range']['to'] = $_POST['range_to'];
571
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
572
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
573
		$dhcpdconf['netmask'] = $_POST['netmask'];
574

    
575
		unset($dhcpdconf['winsserver']);
576
		if ($_POST['wins1']) {
577
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
578
		}
579
		if ($_POST['wins2']) {
580
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
581
		}
582

    
583
		unset($dhcpdconf['dnsserver']);
584
		if ($_POST['dns1']) {
585
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
586
		}
587
		if ($_POST['dns2']) {
588
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
589
		}
590
		if ($_POST['dns3']) {
591
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
592
		}
593
		if ($_POST['dns4']) {
594
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
595
		}
596

    
597
		$dhcpdconf['gateway'] = $_POST['gateway'];
598
		$dhcpdconf['domain'] = $_POST['domain'];
599
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
600
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
601
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
602
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
603
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
604
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
605
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
606
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
607
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
608
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
609
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
610
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
611
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
612

    
613
		unset($dhcpdconf['ntpserver']);
614
		if ($_POST['ntp1']) {
615
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
616
		}
617
		if ($_POST['ntp2']) {
618
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
619
		}
620

    
621
		$dhcpdconf['tftp'] = $_POST['tftp'];
622
		$dhcpdconf['ldap'] = $_POST['ldap'];
623
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
624
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
625
		$dhcpdconf['filename'] = $_POST['filename'];
626
		$dhcpdconf['filename32'] = $_POST['filename32'];
627
		$dhcpdconf['filename64'] = $_POST['filename64'];
628
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
629
		unset($dhcpdconf['statsgraph']);
630
		if ($_POST['statsgraph']) {
631
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
632
			enable_rrd_graphing();
633
		}
634

    
635
		// Handle the custom options rowhelper
636
		if (isset($dhcpdconf['numberoptions']['item'])) {
637
			unset($dhcpdconf['numberoptions']['item']);
638
		}
639

    
640
		$dhcpdconf['numberoptions'] = $numberoptions;
641

    
642
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
643
			$a_pools[$pool] = $dhcpdconf;
644
		} elseif ($act == "newpool") {
645
			$a_pools[] = $dhcpdconf;
646
		} else {
647
			$config['dhcpd'][$if] = $dhcpdconf;
648
		}
649

    
650
		write_config();
651
	}
652
}
653

    
654
if ((isset($_POST['save']) || isset($_POST['apply'])) && (!$input_errors)) {
655
	$retval = 0;
656
	$retvaldhcp = 0;
657
	$retvaldns = 0;
658
	/* dnsmasq_configure calls dhcpd_configure */
659
	/* no need to restart dhcpd twice */
660
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
661
		$retvaldns = services_dnsmasq_configure();
662
		if ($retvaldns == 0) {
663
			clear_subsystem_dirty('hosts');
664
			clear_subsystem_dirty('staticmaps');
665
		}
666
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
667
		$retvaldns = services_unbound_configure();
668
		if ($retvaldns == 0) {
669
			clear_subsystem_dirty('unbound');
670
			clear_subsystem_dirty('hosts');
671
			clear_subsystem_dirty('staticmaps');
672
		}
673
	} else {
674
		$retvaldhcp = services_dhcpd_configure();
675
		if ($retvaldhcp == 0) {
676
			clear_subsystem_dirty('staticmaps');
677
		}
678
	}
679
	if ($dhcpd_enable_changed) {
680
		$retvalfc = filter_configure();
681
	}
682

    
683
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
684
		$retval = 1;
685
	}
686

    
687
	$savemsg = get_std_save_message($retval);
688
}
689

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

    
699
if ($act == "del") {
700
	if (isset($a_maps[$_GET['id']])) {
701
		unset($a_maps[$_GET['id']]);
702
		write_config();
703
		if (isset($config['dhcpd'][$if]['enable'])) {
704
			mark_subsystem_dirty('staticmaps');
705
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
706
				mark_subsystem_dirty('hosts');
707
			}
708
		}
709

    
710
		header("Location: services_dhcp.php?if={$if}");
711
		exit;
712
	}
713
}
714

    
715
// Build an HTML table that can be inserted into a Form_StaticText element
716
function build_pooltable() {
717
	global $a_pools, $if;
718

    
719
	$pooltbl =	'<div class="table-responsive">';
720
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
721
	$pooltbl .=			'<thead>';
722
	$pooltbl .=				'<tr>';
723
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
724
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
725
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
726
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
727
	$pooltbl .=				'</tr>';
728
	$pooltbl .=			'</thead>';
729
	$pooltbl .=			'<tbody>';
730

    
731
	if (is_array($a_pools)) {
732
		$i = 0;
733
		foreach ($a_pools as $poolent) {
734
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
735
				$pooltbl .= '<tr>';
736
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
737
							htmlspecialchars($poolent['range']['from']) . '</td>';
738

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

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

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

    
747
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '"></a></td>';
748
				$pooltbl .= '</tr>';
749
			}
750
		$i++;
751
		}
752
	}
753

    
754
	$pooltbl .=			'</tbody>';
755
	$pooltbl .=		'</table>';
756
	$pooltbl .= '</div>';
757

    
758
	return($pooltbl);
759
}
760

    
761
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
762
$pglinks = array("", "services_dhcp.php");
763

    
764
if (!empty($if) && isset($iflist[$if])) {
765
	$pgtitle[] = $iflist[$if];
766
	$pglinks[] = "@self";
767
}
768
$shortcut_section = "dhcp";
769

    
770
include("head.inc");
771

    
772
if ($input_errors) {
773
	print_input_errors($input_errors);
774
}
775

    
776
if ($savemsg) {
777
	print_info_box($savemsg, 'success');
778
}
779

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

    
784
/* active tabs */
785
$tab_array = array();
786
$tabscounter = 0;
787
$i = 0;
788
$have_small_subnet = false;
789

    
790
foreach ($iflist as $ifent => $ifname) {
791
	$oc = $config['interfaces'][$ifent];
792

    
793
	/* Not static IPv4 or subnet >= 31 */
794
	if ($oc['subnet'] >= 31) {
795
		$have_small_subnet = true;
796
		$example_name = $ifname;
797
		$example_cidr = $oc['subnet'];
798
		continue;
799
	}
800
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
801
		continue;
802
	}
803

    
804
	if ($ifent == $if) {
805
		$active = true;
806
	} else {
807
		$active = false;
808
	}
809

    
810
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
811
	$tabscounter++;
812
}
813

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

    
825
display_top_tabs($tab_array);
826

    
827
$form = new Form();
828

    
829
$section = new Form_Section('General Options');
830

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

    
851
$section->addInput(new Form_Checkbox(
852
	'ignorebootp',
853
	'BOOTP',
854
	'Ignore BOOTP queries',
855
	$pconfig['ignorebootp']
856
));
857

    
858
$section->addInput(new Form_Checkbox(
859
	'denyunknown',
860
	'Deny unknown clients',
861
	'Only the clients defined below will get DHCP leases from this server.',
862
	$pconfig['denyunknown']
863
));
864

    
865
$section->addInput(new Form_Checkbox(
866
	'nonak',
867
	'Ignore denied clients',
868
	'Denied clients will be ignored rather than rejected.',
869
	$pconfig['nonak']
870
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
871

    
872
$section->addInput(new Form_Checkbox(
873
	'ignoreclientuids',
874
	'Ignore client identifiers',
875
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
876
	$pconfig['ignoreclientuids']
877
))->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.");
878

    
879

    
880
if (is_numeric($pool) || ($act == "newpool")) {
881
	$section->addInput(new Form_Input(
882
		'descr',
883
		'Pool Description',
884
		'text',
885
		$pconfig['descr']
886
	));
887
}
888

    
889
$section->addInput(new Form_StaticText(
890
	'Subnet',
891
	gen_subnet($ifcfgip, $ifcfgsn)
892
));
893

    
894
$section->addInput(new Form_StaticText(
895
	'Subnet mask',
896
	gen_subnet_mask($ifcfgsn)
897
));
898

    
899
// Compose a string to display the required address ranges
900
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
901

    
902
if (is_numeric($pool) || ($act == "newpool")) {
903
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
904
	if (is_array($config['dhcpd'][$if]['range'])) {
905
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
906
	}
907

    
908
	foreach ($a_pools as $p) {
909
		if (is_array($p['range'])) {
910
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
911
		}
912
	}
913
}
914

    
915
$section->addInput(new Form_StaticText(
916
	'Available range',
917
	$rangestr
918
));
919

    
920
if ($is_olsr_enabled) {
921
	$section->addInput(new Form_Select(
922
		'netmask',
923
		'Subnet mask',
924
		$pconfig['netmask'],
925
		array_combine(range(32, 1, -1), range(32, 1, -1))
926
	));
927
}
928

    
929
$group = new Form_Group('*Range');
930

    
931
$group->add(new Form_IpAddress(
932
	'range_from',
933
	null,
934
	$pconfig['range_from'],
935
	'V4'
936
))->setHelp('From');
937

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

    
945
$section->add($group);
946

    
947
$form->add($section);
948

    
949
if (!is_numeric($pool) && !($act == "newpool")) {
950
	$section = new Form_Section('Additional Pools');
951

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

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

    
965
	if (is_array($a_pools)) {
966
		$section->addInput(new Form_StaticText(
967
			null,
968
			build_pooltable()
969
		));
970
	}
971

    
972
	$form->add($section);
973
}
974

    
975
$section = new Form_Section('Servers');
976

    
977
$section->addInput(new Form_IpAddress(
978
	'wins1',
979
	'WINS servers',
980
	$pconfig['wins1'],
981
	'V4'
982
))->setAttribute('placeholder', 'WINS Server 1');
983

    
984
$section->addInput(new Form_IpAddress(
985
	'wins2',
986
	null,
987
	$pconfig['wins2'],
988
	'V4'
989
))->setAttribute('placeholder', 'WINS Server 2');
990

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

    
1000
$form->add($section);
1001

    
1002
$section = new Form_Section('Other Options');
1003

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

    
1012
$section->addInput(new Form_Input(
1013
	'domain',
1014
	'Domain name',
1015
	'text',
1016
	$pconfig['domain']
1017
))->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.');
1018

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

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

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

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

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

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

    
1073
// DDNS
1074
$btnadv = new Form_Button(
1075
	'btnadvdns',
1076
	'Display Advanced',
1077
	null,
1078
	'fa-cog'
1079
);
1080

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

    
1083
$section->addInput(new Form_StaticText(
1084
	'Dynamic DNS',
1085
	$btnadv
1086
));
1087

    
1088
$section->addInput(new Form_Checkbox(
1089
	'ddnsupdate',
1090
	null,
1091
	'Enable registration of DHCP client names in DNS',
1092
	$pconfig['ddnsupdate']
1093
));
1094

    
1095
$section->addInput(new Form_Input(
1096
	'ddnsdomain',
1097
	'DDNS Domain',
1098
	'text',
1099
	$pconfig['ddnsdomain']
1100
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
1101
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1102

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

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

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

    
1124
$section->addInput(new Form_Input(
1125
	'ddnsdomainkey',
1126
	'DNS Domain key secret',
1127
	'text',
1128
	$pconfig['ddnsdomainkey']
1129
))->setHelp('Dynamic DNS domain key secret (HMAC-MD5) which will be used to register client names in the DNS server.');
1130

    
1131
// Advanced MAC
1132
$btnadv = new Form_Button(
1133
	'btnadvmac',
1134
	'Display Advanced',
1135
	null,
1136
	'fa-cog'
1137
);
1138

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

    
1141
$section->addInput(new Form_StaticText(
1142
	'MAC address control',
1143
	$btnadv
1144
));
1145

    
1146
$section->addInput(new Form_Input(
1147
	'mac_allow',
1148
	'MAC Allow',
1149
	'text',
1150
	$pconfig['mac_allow']
1151
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1152

    
1153
$section->addInput(new Form_Input(
1154
	'mac_deny',
1155
	'MAC Deny',
1156
	'text',
1157
	$pconfig['mac_deny']
1158
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1159

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

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

    
1170
$section->addInput(new Form_StaticText(
1171
	'NTP',
1172
	$btnadv
1173
));
1174

    
1175
$section->addInput(new Form_IpAddress(
1176
	'ntp1',
1177
	'NTP Server 1',
1178
	$pconfig['ntp1'],
1179
	'HOSTV4'
1180
));
1181

    
1182
$section->addInput(new Form_IpAddress(
1183
	'ntp2',
1184
	'NTP Server 2',
1185
	$pconfig['ntp2'],
1186
	'HOSTV4'
1187
));
1188

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

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

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

    
1204
$section->addInput(new Form_Input(
1205
	'tftp',
1206
	'TFTP Server',
1207
	'text',
1208
	$pconfig['tftp']
1209
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1210

    
1211
// Advanced LDAP
1212
$btnadv = new Form_Button(
1213
	'btnadvldap',
1214
	'Display Advanced',
1215
	null,
1216
	'fa-cog'
1217
);
1218

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

    
1221
$section->addInput(new Form_StaticText(
1222
	'LDAP',
1223
	$btnadv
1224
));
1225

    
1226
$section->addInput(new Form_Input(
1227
	'ldap',
1228
	'LDAP Server URI',
1229
	'text',
1230
	$pconfig['ldap']
1231
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1232

    
1233
// Advanced Network Booting options
1234
$btnadv = new Form_Button(
1235
	'btnadvnwkboot',
1236
	'Display Advanced',
1237
	null,
1238
	'fa-cog'
1239
);
1240

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

    
1243
$section->addInput(new Form_StaticText(
1244
	'Network Booting',
1245
	$btnadv
1246
));
1247

    
1248
$section->addInput(new Form_Checkbox(
1249
	'netboot',
1250
	'Enable',
1251
	'Enables network booting',
1252
	$pconfig['netboot']
1253
));
1254

    
1255
$section->addInput(new Form_IpAddress(
1256
	'nextserver',
1257
	'Next Server',
1258
	$pconfig['nextserver'],
1259
	'V4'
1260
))->setHelp('Enter the IP address of the next server');
1261

    
1262
$section->addInput(new Form_Input(
1263
	'filename',
1264
	'Default BIOS file name',
1265
	'text',
1266
	$pconfig['filename']
1267
));
1268

    
1269
$section->addInput(new Form_Input(
1270
	'filename32',
1271
	'UEFI 32 bit file name',
1272
	'text',
1273
	$pconfig['filename32']
1274
));
1275

    
1276
$section->addInput(new Form_Input(
1277
	'filename64',
1278
	'UEFI 64 bit file name',
1279
	'text',
1280
	$pconfig['filename64']
1281
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1282
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1283

    
1284
$section->addInput(new Form_Input(
1285
	'rootpath',
1286
	'Root path',
1287
	'text',
1288
	$pconfig['rootpath']
1289
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1290

    
1291
// Advanced Additional options
1292
$btnadv = new Form_Button(
1293
	'btnadvopts',
1294
	'Display Advanced',
1295
	null,
1296
	'fa-cog'
1297
);
1298

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

    
1301
$section->addInput(new Form_StaticText(
1302
	'Additional BOOTP/DHCP Options',
1303
	$btnadv
1304
));
1305

    
1306
$form->add($section);
1307

    
1308
$section = new Form_Section('Additional BOOTP/DHCP Options');
1309
$section->addClass('adnlopts');
1310

    
1311
$section->addInput(new Form_StaticText(
1312
	null,
1313
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1314
	sprintf(gettext('For a list of available options please visit this %1$s URL%2$s'), '<a href="http://www.iana.org/assignments/bootp-dhcp-parameters/" target="_blank">', '</a>.</div>')
1315
));
1316

    
1317
if (!$pconfig['numberoptions']) {
1318
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1319
}
1320

    
1321
$customitemtypes = array(
1322
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1323
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1324
	'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')
1325
);
1326

    
1327
$numrows = count($item) -1;
1328
$counter = 0;
1329

    
1330
$numrows = count($pconfig['numberoptions']['item']) -1;
1331

    
1332
foreach ($pconfig['numberoptions']['item'] as $item) {
1333
	$number = $item['number'];
1334
	$itemtype = $item['type'];
1335
	$value = base64_decode($item['value']);
1336

    
1337
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1338
	$group->addClass('repeatable');
1339

    
1340
	$group->add(new Form_Input(
1341
		'number' . $counter,
1342
		null,
1343
		'text',
1344
		$number
1345
	))->setHelp($numrows == $counter ? 'Number':null);
1346

    
1347

    
1348
	$group->add(new Form_Select(
1349
		'itemtype' . $counter,
1350
		null,
1351
		$itemtype,
1352
		$customitemtypes
1353
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1354

    
1355
	$group->add(new Form_Input(
1356
		'value' . $counter,
1357
		null,
1358
		'text',
1359
		$value
1360
	))->setHelp($numrows == $counter ? 'Value':null);
1361

    
1362
	$group->add(new Form_Button(
1363
		'deleterow' . $counter,
1364
		'Delete',
1365
		null,
1366
		'fa-trash'
1367
	))->addClass('btn-warning');
1368

    
1369
	$section->add($group);
1370

    
1371
	$counter++;
1372
}
1373

    
1374
$section->addInput(new Form_Button(
1375
	'addrow',
1376
	'Add',
1377
	null,
1378
	'fa-plus'
1379
))->addClass('btn-success');
1380

    
1381
$form->add($section);
1382

    
1383
if ($act == "newpool") {
1384
	$form->addGlobal(new Form_Input(
1385
		'act',
1386
		null,
1387
		'hidden',
1388
		'newpool'
1389
	));
1390
}
1391

    
1392
if (is_numeric($pool)) {
1393
	$form->addGlobal(new Form_Input(
1394
		'pool',
1395
		null,
1396
		'hidden',
1397
		$pool
1398
	));
1399
}
1400

    
1401
$form->addGlobal(new Form_Input(
1402
	'if',
1403
	null,
1404
	'hidden',
1405
	$if
1406
));
1407

    
1408
print($form);
1409

    
1410
// DHCP Static Mappings table
1411

    
1412
if (!is_numeric($pool) && !($act == "newpool")) {
1413

    
1414
	// Decide whether display of the Client Id column is needed.
1415
	$got_cid = false;
1416
	if (is_array($a_maps)) {
1417
		foreach ($a_maps as $map) {
1418
			if (!empty($map['cid'])) {
1419
				$got_cid = true;
1420
				break;
1421
			}
1422
		}
1423
	}
1424
?>
1425

    
1426
<div class="panel panel-default">
1427
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1428
	<div class="table-responsive">
1429
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1430
				<thead>
1431
					<tr>
1432
						<th><?=gettext("Static ARP")?></th>
1433
						<th><?=gettext("MAC address")?></th>
1434
<?php
1435
	if ($got_cid):
1436
?>
1437
						<th><?=gettext("Client Id")?></th>
1438
<?php
1439
	endif;
1440
?>
1441
						<th><?=gettext("IP address")?></th>
1442
						<th><?=gettext("Hostname")?></th>
1443
						<th><?=gettext("Description")?></th>
1444
						<th></th>
1445
					</tr>
1446
				</thead>
1447
<?php
1448
	if (is_array($a_maps)) {
1449
		$i = 0;
1450
?>
1451
				<tbody>
1452
<?php
1453
		foreach ($a_maps as $mapent) {
1454
?>
1455
					<tr>
1456
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1457
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1458
								<i class="fa fa-check"></i>
1459
							<?php endif; ?>
1460
						</td>
1461
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1462
							<?=htmlspecialchars($mapent['mac'])?>
1463
						</td>
1464
<?php
1465
			if ($got_cid):
1466
?>
1467
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1468
							<?=htmlspecialchars($mapent['cid'])?>
1469
						</td>
1470
<?php
1471
			endif;
1472
?>
1473
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1474
							<?=htmlspecialchars($mapent['ipaddr'])?>
1475
						</td>
1476
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1477
							<?=htmlspecialchars($mapent['hostname'])?>
1478
						</td>
1479
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1480
							<?=htmlspecialchars($mapent['descr'])?>
1481
						</td>
1482
						<td>
1483
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1484
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>"></a>
1485
						</td>
1486
					</tr>
1487
<?php
1488
		$i++;
1489
		}
1490
?>
1491
				</tbody>
1492
<?php
1493
	}
1494
?>
1495
		</table>
1496
	</div>
1497
</div>
1498

    
1499
<nav class="action-buttons">
1500
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1501
		<i class="fa fa-plus icon-embed-btn"></i>
1502
		<?=gettext("Add")?>
1503
	</a>
1504
</nav>
1505
<?php
1506
}
1507
?>
1508

    
1509
<script type="text/javascript">
1510
//<![CDATA[
1511
events.push(function() {
1512

    
1513
	// Show advanced DNS options ======================================================================================
1514
	var showadvdns = false;
1515

    
1516
	function show_advdns(ispageload) {
1517
		var text;
1518
		// On page load decide the initial state based on the data.
1519
		if (ispageload) {
1520
<?php
1521
			if (!$pconfig['ddnsupdate'] && !$pconfig['ddnsforcehostname'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1522
			    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1523
				$showadv = false;
1524
			} else {
1525
				$showadv = true;
1526
			}
1527
?>
1528
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1529
		} else {
1530
			// It was a click, swap the state.
1531
			showadvdns = !showadvdns;
1532
		}
1533

    
1534
		hideCheckbox('ddnsupdate', !showadvdns);
1535
		hideInput('ddnsdomain', !showadvdns);
1536
		hideCheckbox('ddnsforcehostname', !showadvdns);
1537
		hideInput('ddnsdomainprimary', !showadvdns);
1538
		hideInput('ddnsdomainkeyname', !showadvdns);
1539
		hideInput('ddnsdomainkey', !showadvdns);
1540

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

    
1549
	$('#btnadvdns').click(function(event) {
1550
		show_advdns();
1551
	});
1552

    
1553
	// Show advanced MAC options ======================================================================================
1554
	var showadvmac = false;
1555

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

    
1573
		hideInput('mac_allow', !showadvmac);
1574
		hideInput('mac_deny', !showadvmac);
1575

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

    
1584
	$('#btnadvmac').click(function(event) {
1585
		show_advmac();
1586
	});
1587

    
1588
	// Show advanced NTP options ======================================================================================
1589
	var showadvntp = false;
1590

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

    
1608
		hideInput('ntp1', !showadvntp);
1609
		hideInput('ntp2', !showadvntp);
1610

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

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

    
1623
	// Show advanced TFTP options ======================================================================================
1624
	var showadvtftp = false;
1625

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

    
1643
		hideInput('tftp', !showadvtftp);
1644

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

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

    
1657
	// Show advanced LDAP options ======================================================================================
1658
	var showadvldap = false;
1659

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

    
1677
		hideInput('ldap', !showadvldap);
1678

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

    
1687
	$('#btnadvldap').click(function(event) {
1688
		show_advldap();
1689
	});
1690

    
1691
	// Show advanced additional opts options ===========================================================================
1692
	var showadvopts = false;
1693

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

    
1712
		hideClass('adnlopts', !showadvopts);
1713

    
1714
		if (showadvopts) {
1715
			text = "<?=gettext('Hide Advanced');?>";
1716
		} else {
1717
			text = "<?=gettext('Display Advanced');?>";
1718
		}
1719
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1720
	}
1721

    
1722
	$('#btnadvopts').click(function(event) {
1723
		show_advopts();
1724
	});
1725

    
1726
	// Show advanced Network Booting options ===========================================================================
1727
	var showadvnwkboot = false;
1728

    
1729
	function show_advnwkboot(ispageload) {
1730
		var text;
1731
		// On page load decide the initial state based on the data.
1732
		if (ispageload) {
1733
<?php
1734
			if (empty($pconfig['netboot'])) {
1735
				$showadv = false;
1736
			} else {
1737
				$showadv = true;
1738
			}
1739
?>
1740
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1741
		} else {
1742
			// It was a click, swap the state.
1743
			showadvnwkboot = !showadvnwkboot;
1744
		}
1745

    
1746
		hideCheckbox('netboot', !showadvnwkboot);
1747
		hideInput('nextserver', !showadvnwkboot);
1748
		hideInput('filename', !showadvnwkboot);
1749
		hideInput('filename32', !showadvnwkboot);
1750
		hideInput('filename64', !showadvnwkboot);
1751
		hideInput('rootpath', !showadvnwkboot);
1752

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

    
1761
	$('#btnadvnwkboot').click(function(event) {
1762
		show_advnwkboot();
1763
	});
1764

    
1765
	// ---------- On initial page load ------------------------------------------------------------
1766

    
1767
	show_advdns(true);
1768
	show_advmac(true);
1769
	show_advntp(true);
1770
	show_advtftp(true);
1771
	show_advldap(true);
1772
	show_advopts(true);
1773
	show_advnwkboot(true);
1774

    
1775
	// Suppress "Delete row" button if there are fewer than two rows
1776
	checkLastRow();
1777
});
1778
//]]>
1779
</script>
1780

    
1781
<?php include("foot.inc");
(117-117/225)