Project

General

Profile

Download (55.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_dhcp.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-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 ((!isset($pool) || !is_numeric($pool)) && $act != "newpool") {
453
		/* If enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
454
		if ($_POST['enable'] && isset($config['dhcrelay']['enable']) &&
455
		    (stristr($config['dhcrelay']['interface'], $if) !== false)) {
456
			$input_errors[] = sprintf(gettext(
457
			    "The DHCP relay on the %s interface must be disabled before enabling the DHCP server."),
458
			    $iflist[$if]);
459
		}
460

    
461
		/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
462
		if (!$_POST['enable']) {
463
			if (isset($config['dnsmasq']['enable']) &&
464
			    (isset($config['dnsmasq']['regdhcp']) ||
465
			    isset($config['dnsmasq']['regdhcpstatic']) ||
466
			    isset($config['dnsmasq']['dhcpfirst']))) {
467
				$input_errors[] = gettext(
468
				    "Disable DHCP Registration features in DNS Forwarder before disabling DHCP Server.");
469
			}
470
			if (isset($config['unbound']['enable']) &&
471
			    (isset($config['unbound']['regdhcp']) ||
472
			    isset($config['unbound']['regdhcpstatic']))) {
473
				$input_errors[] = gettext(
474
				    "Disable DHCP Registration features in DNS Resolver before disabling DHCP Server.");
475
			}
476
		}
477
	}
478

    
479
	// 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.
480
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
481
		/* make sure the range lies within the current subnet */
482
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
483
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
484
		}
485

    
486
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
487
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
488
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
489
		}
490

    
491
		if (is_numeric($pool) || ($act == "newpool")) {
492
			if (is_inrange_v4($_POST['range_from'],
493
				$config['dhcpd'][$if]['range']['from'],
494
				$config['dhcpd'][$if]['range']['to']) ||
495
				is_inrange_v4($_POST['range_to'],
496
				$config['dhcpd'][$if]['range']['from'],
497
				$config['dhcpd'][$if]['range']['to'])) {
498
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
499
			}
500
		}
501

    
502
		foreach ($a_pools as $id => $p) {
503
			if (is_numeric($pool) && ($id == $pool)) {
504
				continue;
505
			}
506

    
507
			if (is_inrange_v4($_POST['range_from'],
508
				$p['range']['from'], $p['range']['to']) ||
509
				is_inrange_v4($_POST['range_to'],
510
				$p['range']['from'], $p['range']['to'])) {
511
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
512
				break;
513
			}
514
		}
515

    
516
		if (is_array($a_maps)) {
517
			foreach ($a_maps as $map) {
518
				if (empty($map['ipaddr'])) {
519
					continue;
520
				}
521
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
522
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
523
					break;
524
				}
525
			}
526
		}
527
	}
528

    
529
	if (!$input_errors) {
530
		if (!is_numeric($pool)) {
531
			if ($act == "newpool") {
532
				$dhcpdconf = array();
533
			} else {
534
				if (!is_array($config['dhcpd'][$if])) {
535
					$config['dhcpd'][$if] = array();
536
				}
537
				$dhcpdconf = $config['dhcpd'][$if];
538
			}
539
		} else {
540
			if (is_array($a_pools[$pool])) {
541
				$dhcpdconf = $a_pools[$pool];
542
			} else {
543
				// Someone specified a pool but it doesn't exist. Punt.
544
				header("Location: services_dhcp.php");
545
				exit;
546
			}
547
		}
548
		if (!is_array($dhcpdconf['range'])) {
549
			$dhcpdconf['range'] = array();
550
		}
551

    
552
		$dhcpd_enable_changed = false;
553

    
554
		// Global Options
555
		if (!is_numeric($pool) && !($act == "newpool")) {
556
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
557
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
558
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
559
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
560
				$dhcpd_enable_changed = true;
561
			}
562

    
563
			$dhcpdconf['enable'] = $new_dhcpd_enable;
564
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
565
			$previous = $dhcpdconf['failover_peerip'];
566
			if ($previous != $_POST['failover_peerip']) {
567
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
568
			}
569

    
570
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
571
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
572
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
573
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
574
			}
575
		} else {
576
			// Options that exist only in pools
577
			$dhcpdconf['descr'] = $_POST['descr'];
578
		}
579

    
580
		// Options that can be global or per-pool.
581
		$dhcpdconf['range']['from'] = $_POST['range_from'];
582
		$dhcpdconf['range']['to'] = $_POST['range_to'];
583
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
584
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
585
		$dhcpdconf['netmask'] = $_POST['netmask'];
586

    
587
		unset($dhcpdconf['winsserver']);
588
		if ($_POST['wins1']) {
589
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
590
		}
591
		if ($_POST['wins2']) {
592
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
593
		}
594

    
595
		unset($dhcpdconf['dnsserver']);
596
		if ($_POST['dns1']) {
597
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
598
		}
599
		if ($_POST['dns2']) {
600
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
601
		}
602
		if ($_POST['dns3']) {
603
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
604
		}
605
		if ($_POST['dns4']) {
606
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
607
		}
608

    
609
		$dhcpdconf['gateway'] = $_POST['gateway'];
610
		$dhcpdconf['domain'] = $_POST['domain'];
611
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
612
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
613
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
614
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
615
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
616
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
617
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
618
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
619
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
620
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
621
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
622
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
623
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
624

    
625
		unset($dhcpdconf['ntpserver']);
626
		if ($_POST['ntp1']) {
627
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
628
		}
629
		if ($_POST['ntp2']) {
630
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
631
		}
632

    
633
		$dhcpdconf['tftp'] = $_POST['tftp'];
634
		$dhcpdconf['ldap'] = $_POST['ldap'];
635
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
636
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
637
		$dhcpdconf['filename'] = $_POST['filename'];
638
		$dhcpdconf['filename32'] = $_POST['filename32'];
639
		$dhcpdconf['filename64'] = $_POST['filename64'];
640
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
641
		unset($dhcpdconf['statsgraph']);
642
		if ($_POST['statsgraph']) {
643
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
644
			enable_rrd_graphing();
645
		}
646

    
647
		// Handle the custom options rowhelper
648
		if (isset($dhcpdconf['numberoptions']['item'])) {
649
			unset($dhcpdconf['numberoptions']['item']);
650
		}
651

    
652
		$dhcpdconf['numberoptions'] = $numberoptions;
653

    
654
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
655
			$a_pools[$pool] = $dhcpdconf;
656
		} elseif ($act == "newpool") {
657
			$a_pools[] = $dhcpdconf;
658
		} else {
659
			$config['dhcpd'][$if] = $dhcpdconf;
660
		}
661

    
662
		write_config();
663
	}
664
}
665

    
666
if ((isset($_POST['save']) || isset($_POST['apply'])) && (!$input_errors)) {
667
	$retval = 0;
668
	$retvaldhcp = 0;
669
	$retvaldns = 0;
670
	/* dnsmasq_configure calls dhcpd_configure */
671
	/* no need to restart dhcpd twice */
672
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
673
		$retvaldns = services_dnsmasq_configure();
674
		if ($retvaldns == 0) {
675
			clear_subsystem_dirty('hosts');
676
			clear_subsystem_dirty('staticmaps');
677
		}
678
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
679
		$retvaldns = services_unbound_configure();
680
		if ($retvaldns == 0) {
681
			clear_subsystem_dirty('unbound');
682
			clear_subsystem_dirty('hosts');
683
			clear_subsystem_dirty('staticmaps');
684
		}
685
	} else {
686
		$retvaldhcp = services_dhcpd_configure();
687
		if ($retvaldhcp == 0) {
688
			clear_subsystem_dirty('staticmaps');
689
		}
690
	}
691
	if ($dhcpd_enable_changed) {
692
		$retvalfc = filter_configure();
693
	}
694

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

    
699
	$savemsg = get_std_save_message($retval);
700
}
701

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

    
711
if ($act == "del") {
712
	if (isset($a_maps[$_GET['id']])) {
713
		unset($a_maps[$_GET['id']]);
714
		write_config();
715
		if (isset($config['dhcpd'][$if]['enable'])) {
716
			mark_subsystem_dirty('staticmaps');
717
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
718
				mark_subsystem_dirty('hosts');
719
			}
720
		}
721

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

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

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

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

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

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

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

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

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

    
770
	return($pooltbl);
771
}
772

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

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

    
782
include("head.inc");
783

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

    
788
if ($savemsg) {
789
	print_info_box($savemsg, 'success');
790
}
791

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

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

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

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

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

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

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

    
837
display_top_tabs($tab_array);
838

    
839
$form = new Form();
840

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

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

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

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

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

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

    
891

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

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

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

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

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

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

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

    
932
if ($is_olsr_enabled) {
933
	$section->addInput(new Form_Select(
934
		'netmask',
935
		'Subnet mask',
936
		$pconfig['netmask'],
937
		array_combine(range(32, 1, -1), range(32, 1, -1))
938
	));
939
}
940

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1095
$section->addInput(new Form_StaticText(
1096
	'Dynamic DNS',
1097
	$btnadv
1098
));
1099

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

    
1107
$section->addInput(new Form_Input(
1108
	'ddnsdomain',
1109
	'DDNS Domain',
1110
	'text',
1111
	$pconfig['ddnsdomain']
1112
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
1113
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1114

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

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

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

    
1136
$section->addInput(new Form_Input(
1137
	'ddnsdomainkey',
1138
	'DNS Domain key secret',
1139
	'text',
1140
	$pconfig['ddnsdomainkey']
1141
))->setHelp('Dynamic DNS domain key secret (HMAC-MD5) which will be used to register client names in the DNS server.');
1142

    
1143
// Advanced MAC
1144
$btnadv = new Form_Button(
1145
	'btnadvmac',
1146
	'Display Advanced',
1147
	null,
1148
	'fa-cog'
1149
);
1150

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

    
1153
$section->addInput(new Form_StaticText(
1154
	'MAC address control',
1155
	$btnadv
1156
));
1157

    
1158
$section->addInput(new Form_Input(
1159
	'mac_allow',
1160
	'MAC Allow',
1161
	'text',
1162
	$pconfig['mac_allow']
1163
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1164

    
1165
$section->addInput(new Form_Input(
1166
	'mac_deny',
1167
	'MAC Deny',
1168
	'text',
1169
	$pconfig['mac_deny']
1170
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1171

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

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

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

    
1187
$section->addInput(new Form_IpAddress(
1188
	'ntp1',
1189
	'NTP Server 1',
1190
	$pconfig['ntp1'],
1191
	'HOSTV4'
1192
));
1193

    
1194
$section->addInput(new Form_IpAddress(
1195
	'ntp2',
1196
	'NTP Server 2',
1197
	$pconfig['ntp2'],
1198
	'HOSTV4'
1199
));
1200

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

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

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

    
1216
$section->addInput(new Form_Input(
1217
	'tftp',
1218
	'TFTP Server',
1219
	'text',
1220
	$pconfig['tftp']
1221
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1222

    
1223
// Advanced LDAP
1224
$btnadv = new Form_Button(
1225
	'btnadvldap',
1226
	'Display Advanced',
1227
	null,
1228
	'fa-cog'
1229
);
1230

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

    
1233
$section->addInput(new Form_StaticText(
1234
	'LDAP',
1235
	$btnadv
1236
));
1237

    
1238
$section->addInput(new Form_Input(
1239
	'ldap',
1240
	'LDAP Server URI',
1241
	'text',
1242
	$pconfig['ldap']
1243
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1244

    
1245
// Advanced Network Booting options
1246
$btnadv = new Form_Button(
1247
	'btnadvnwkboot',
1248
	'Display Advanced',
1249
	null,
1250
	'fa-cog'
1251
);
1252

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

    
1255
$section->addInput(new Form_StaticText(
1256
	'Network Booting',
1257
	$btnadv
1258
));
1259

    
1260
$section->addInput(new Form_Checkbox(
1261
	'netboot',
1262
	'Enable',
1263
	'Enables network booting',
1264
	$pconfig['netboot']
1265
));
1266

    
1267
$section->addInput(new Form_IpAddress(
1268
	'nextserver',
1269
	'Next Server',
1270
	$pconfig['nextserver'],
1271
	'V4'
1272
))->setHelp('Enter the IP address of the next server');
1273

    
1274
$section->addInput(new Form_Input(
1275
	'filename',
1276
	'Default BIOS file name',
1277
	'text',
1278
	$pconfig['filename']
1279
));
1280

    
1281
$section->addInput(new Form_Input(
1282
	'filename32',
1283
	'UEFI 32 bit file name',
1284
	'text',
1285
	$pconfig['filename32']
1286
));
1287

    
1288
$section->addInput(new Form_Input(
1289
	'filename64',
1290
	'UEFI 64 bit file name',
1291
	'text',
1292
	$pconfig['filename64']
1293
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1294
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1295

    
1296
$section->addInput(new Form_Input(
1297
	'rootpath',
1298
	'Root path',
1299
	'text',
1300
	$pconfig['rootpath']
1301
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1302

    
1303
// Advanced Additional options
1304
$btnadv = new Form_Button(
1305
	'btnadvopts',
1306
	'Display Advanced',
1307
	null,
1308
	'fa-cog'
1309
);
1310

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

    
1313
$section->addInput(new Form_StaticText(
1314
	'Additional BOOTP/DHCP Options',
1315
	$btnadv
1316
));
1317

    
1318
$form->add($section);
1319

    
1320
$section = new Form_Section('Additional BOOTP/DHCP Options');
1321
$section->addClass('adnlopts');
1322

    
1323
$section->addInput(new Form_StaticText(
1324
	null,
1325
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1326
	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>')
1327
));
1328

    
1329
if (!$pconfig['numberoptions']) {
1330
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1331
}
1332

    
1333
$customitemtypes = array(
1334
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1335
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1336
	'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')
1337
);
1338

    
1339
$numrows = count($item) -1;
1340
$counter = 0;
1341

    
1342
$numrows = count($pconfig['numberoptions']['item']) -1;
1343

    
1344
foreach ($pconfig['numberoptions']['item'] as $item) {
1345
	$number = $item['number'];
1346
	$itemtype = $item['type'];
1347
	$value = base64_decode($item['value']);
1348

    
1349
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1350
	$group->addClass('repeatable');
1351

    
1352
	$group->add(new Form_Input(
1353
		'number' . $counter,
1354
		null,
1355
		'text',
1356
		$number
1357
	))->setHelp($numrows == $counter ? 'Number':null);
1358

    
1359

    
1360
	$group->add(new Form_Select(
1361
		'itemtype' . $counter,
1362
		null,
1363
		$itemtype,
1364
		$customitemtypes
1365
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1366

    
1367
	$group->add(new Form_Input(
1368
		'value' . $counter,
1369
		null,
1370
		'text',
1371
		$value
1372
	))->setHelp($numrows == $counter ? 'Value':null);
1373

    
1374
	$group->add(new Form_Button(
1375
		'deleterow' . $counter,
1376
		'Delete',
1377
		null,
1378
		'fa-trash'
1379
	))->addClass('btn-warning');
1380

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

    
1383
	$counter++;
1384
}
1385

    
1386
$section->addInput(new Form_Button(
1387
	'addrow',
1388
	'Add',
1389
	null,
1390
	'fa-plus'
1391
))->addClass('btn-success');
1392

    
1393
$form->add($section);
1394

    
1395
if ($act == "newpool") {
1396
	$form->addGlobal(new Form_Input(
1397
		'act',
1398
		null,
1399
		'hidden',
1400
		'newpool'
1401
	));
1402
}
1403

    
1404
if (is_numeric($pool)) {
1405
	$form->addGlobal(new Form_Input(
1406
		'pool',
1407
		null,
1408
		'hidden',
1409
		$pool
1410
	));
1411
}
1412

    
1413
$form->addGlobal(new Form_Input(
1414
	'if',
1415
	null,
1416
	'hidden',
1417
	$if
1418
));
1419

    
1420
print($form);
1421

    
1422
// DHCP Static Mappings table
1423

    
1424
if (!is_numeric($pool) && !($act == "newpool")) {
1425

    
1426
	// Decide whether display of the Client Id column is needed.
1427
	$got_cid = false;
1428
	if (is_array($a_maps)) {
1429
		foreach ($a_maps as $map) {
1430
			if (!empty($map['cid'])) {
1431
				$got_cid = true;
1432
				break;
1433
			}
1434
		}
1435
	}
1436
?>
1437

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

    
1511
<nav class="action-buttons">
1512
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1513
		<i class="fa fa-plus icon-embed-btn"></i>
1514
		<?=gettext("Add")?>
1515
	</a>
1516
</nav>
1517
<?php
1518
}
1519
?>
1520

    
1521
<script type="text/javascript">
1522
//<![CDATA[
1523
events.push(function() {
1524

    
1525
	// Show advanced DNS options ======================================================================================
1526
	var showadvdns = false;
1527

    
1528
	function show_advdns(ispageload) {
1529
		var text;
1530
		// On page load decide the initial state based on the data.
1531
		if (ispageload) {
1532
<?php
1533
			if (!$pconfig['ddnsupdate'] && !$pconfig['ddnsforcehostname'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1534
			    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1535
				$showadv = false;
1536
			} else {
1537
				$showadv = true;
1538
			}
1539
?>
1540
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1541
		} else {
1542
			// It was a click, swap the state.
1543
			showadvdns = !showadvdns;
1544
		}
1545

    
1546
		hideCheckbox('ddnsupdate', !showadvdns);
1547
		hideInput('ddnsdomain', !showadvdns);
1548
		hideCheckbox('ddnsforcehostname', !showadvdns);
1549
		hideInput('ddnsdomainprimary', !showadvdns);
1550
		hideInput('ddnsdomainkeyname', !showadvdns);
1551
		hideInput('ddnsdomainkey', !showadvdns);
1552

    
1553
		if (showadvdns) {
1554
			text = "<?=gettext('Hide Advanced');?>";
1555
		} else {
1556
			text = "<?=gettext('Display Advanced');?>";
1557
		}
1558
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1559
	}
1560

    
1561
	$('#btnadvdns').click(function(event) {
1562
		show_advdns();
1563
	});
1564

    
1565
	// Show advanced MAC options ======================================================================================
1566
	var showadvmac = false;
1567

    
1568
	function show_advmac(ispageload) {
1569
		var text;
1570
		// On page load decide the initial state based on the data.
1571
		if (ispageload) {
1572
<?php
1573
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1574
				$showadv = false;
1575
			} else {
1576
				$showadv = true;
1577
			}
1578
?>
1579
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1580
		} else {
1581
			// It was a click, swap the state.
1582
			showadvmac = !showadvmac;
1583
		}
1584

    
1585
		hideInput('mac_allow', !showadvmac);
1586
		hideInput('mac_deny', !showadvmac);
1587

    
1588
		if (showadvmac) {
1589
			text = "<?=gettext('Hide Advanced');?>";
1590
		} else {
1591
			text = "<?=gettext('Display Advanced');?>";
1592
		}
1593
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1594
	}
1595

    
1596
	$('#btnadvmac').click(function(event) {
1597
		show_advmac();
1598
	});
1599

    
1600
	// Show advanced NTP options ======================================================================================
1601
	var showadvntp = false;
1602

    
1603
	function show_advntp(ispageload) {
1604
		var text;
1605
		// On page load decide the initial state based on the data.
1606
		if (ispageload) {
1607
<?php
1608
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1609
				$showadv = false;
1610
			} else {
1611
				$showadv = true;
1612
			}
1613
?>
1614
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1615
		} else {
1616
			// It was a click, swap the state.
1617
			showadvntp = !showadvntp;
1618
		}
1619

    
1620
		hideInput('ntp1', !showadvntp);
1621
		hideInput('ntp2', !showadvntp);
1622

    
1623
		if (showadvntp) {
1624
			text = "<?=gettext('Hide Advanced');?>";
1625
		} else {
1626
			text = "<?=gettext('Display Advanced');?>";
1627
		}
1628
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1629
	}
1630

    
1631
	$('#btnadvntp').click(function(event) {
1632
		show_advntp();
1633
	});
1634

    
1635
	// Show advanced TFTP options ======================================================================================
1636
	var showadvtftp = false;
1637

    
1638
	function show_advtftp(ispageload) {
1639
		var text;
1640
		// On page load decide the initial state based on the data.
1641
		if (ispageload) {
1642
<?php
1643
			if (empty($pconfig['tftp'])) {
1644
				$showadv = false;
1645
			} else {
1646
				$showadv = true;
1647
			}
1648
?>
1649
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1650
		} else {
1651
			// It was a click, swap the state.
1652
			showadvtftp = !showadvtftp;
1653
		}
1654

    
1655
		hideInput('tftp', !showadvtftp);
1656

    
1657
		if (showadvtftp) {
1658
			text = "<?=gettext('Hide Advanced');?>";
1659
		} else {
1660
			text = "<?=gettext('Display Advanced');?>";
1661
		}
1662
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1663
	}
1664

    
1665
	$('#btnadvtftp').click(function(event) {
1666
		show_advtftp();
1667
	});
1668

    
1669
	// Show advanced LDAP options ======================================================================================
1670
	var showadvldap = false;
1671

    
1672
	function show_advldap(ispageload) {
1673
		var text;
1674
		// On page load decide the initial state based on the data.
1675
		if (ispageload) {
1676
<?php
1677
			if (empty($pconfig['ldap'])) {
1678
				$showadv = false;
1679
			} else {
1680
				$showadv = true;
1681
			}
1682
?>
1683
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1684
		} else {
1685
			// It was a click, swap the state.
1686
			showadvldap = !showadvldap;
1687
		}
1688

    
1689
		hideInput('ldap', !showadvldap);
1690

    
1691
		if (showadvldap) {
1692
			text = "<?=gettext('Hide Advanced');?>";
1693
		} else {
1694
			text = "<?=gettext('Display Advanced');?>";
1695
		}
1696
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1697
	}
1698

    
1699
	$('#btnadvldap').click(function(event) {
1700
		show_advldap();
1701
	});
1702

    
1703
	// Show advanced additional opts options ===========================================================================
1704
	var showadvopts = false;
1705

    
1706
	function show_advopts(ispageload) {
1707
		var text;
1708
		// On page load decide the initial state based on the data.
1709
		if (ispageload) {
1710
<?php
1711
			if (empty($pconfig['numberoptions']) ||
1712
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1713
				$showadv = false;
1714
			} else {
1715
				$showadv = true;
1716
			}
1717
?>
1718
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1719
		} else {
1720
			// It was a click, swap the state.
1721
			showadvopts = !showadvopts;
1722
		}
1723

    
1724
		hideClass('adnlopts', !showadvopts);
1725

    
1726
		if (showadvopts) {
1727
			text = "<?=gettext('Hide Advanced');?>";
1728
		} else {
1729
			text = "<?=gettext('Display Advanced');?>";
1730
		}
1731
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1732
	}
1733

    
1734
	$('#btnadvopts').click(function(event) {
1735
		show_advopts();
1736
	});
1737

    
1738
	// Show advanced Network Booting options ===========================================================================
1739
	var showadvnwkboot = false;
1740

    
1741
	function show_advnwkboot(ispageload) {
1742
		var text;
1743
		// On page load decide the initial state based on the data.
1744
		if (ispageload) {
1745
<?php
1746
			if (empty($pconfig['netboot'])) {
1747
				$showadv = false;
1748
			} else {
1749
				$showadv = true;
1750
			}
1751
?>
1752
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1753
		} else {
1754
			// It was a click, swap the state.
1755
			showadvnwkboot = !showadvnwkboot;
1756
		}
1757

    
1758
		hideCheckbox('netboot', !showadvnwkboot);
1759
		hideInput('nextserver', !showadvnwkboot);
1760
		hideInput('filename', !showadvnwkboot);
1761
		hideInput('filename32', !showadvnwkboot);
1762
		hideInput('filename64', !showadvnwkboot);
1763
		hideInput('rootpath', !showadvnwkboot);
1764

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

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

    
1777
	// ---------- On initial page load ------------------------------------------------------------
1778

    
1779
	show_advdns(true);
1780
	show_advmac(true);
1781
	show_advntp(true);
1782
	show_advtftp(true);
1783
	show_advldap(true);
1784
	show_advopts(true);
1785
	show_advnwkboot(true);
1786

    
1787
	// Suppress "Delete row" button if there are fewer than two rows
1788
	checkLastRow();
1789
});
1790
//]]>
1791
</script>
1792

    
1793
<?php include("foot.inc");
(125-125/233)