Project

General

Profile

Download (53 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
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 * http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25

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

    
33
require_once("guiconfig.inc");
34
require_once("filter.inc");
35
require_once('rrd.inc');
36
require_once("shaper.inc");
37

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

    
43
$if = $_GET['if'];
44
if (!empty($_POST['if'])) {
45
	$if = $_POST['if'];
46
}
47

    
48
/* if OLSRD is enabled, allow WAN to house DHCP. */
49
if ($config['installedpackages']['olsrd']) {
50
	foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
51
		if ($olsrd['enable']) {
52
			$is_olsr_enabled = true;
53
			break;
54
		}
55
	}
56
}
57

    
58
$iflist = get_configured_interface_with_descr();
59

    
60
/* set the starting interface */
61
if (!$if || !isset($iflist[$if])) {
62
	$found_starting_if = false;
63
	// First look for an interface with DHCP already enabled.
64
	foreach ($iflist as $ifent => $ifname) {
65
		$oc = $config['interfaces'][$ifent];
66
		if (is_array($config['dhcpd'][$ifent]) &&
67
		    isset($config['dhcpd'][$ifent]['enable']) &&
68
		    is_ipaddrv4($oc['ipaddr']) && $oc['subnet'] < 31) {
69
			$if = $ifent;
70
			$found_starting_if = true;
71
			break;
72
		}
73
	}
74

    
75
	/*
76
	 * If there is no DHCP-enabled interface and LAN is a candidate,
77
	 * then choose LAN.
78
	 */
79
	if (!$found_starting_if && isset($iflist['lan']) &&
80
	    is_ipaddrv4($config['interfaces']['lan']['ipaddr']) &&
81
	    $config['interfaces']['lan']['subnet'] < 31) {
82
		$if = 'lan';
83
		$found_starting_if = true;
84
	}
85

    
86
	// At the last select whatever can be found.
87
	if (!$found_starting_if) {
88
		foreach ($iflist as $ifent => $ifname) {
89
			$oc = $config['interfaces'][$ifent];
90

    
91
			/* Not static IPv4 or subnet >= 31 */
92
			if (!is_ipaddrv4($oc['ipaddr']) ||
93
			    empty($oc['subnet']) || $oc['subnet'] < 31) {
94
				continue;
95
			}
96

    
97
			if (!is_array($config['dhcpd'][$ifent]) ||
98
			    !isset($config['dhcpd'][$ifent]['enable'])) {
99
				continue;
100
			}
101

    
102
			$if = $ifent;
103
			break;
104
		}
105
	}
106
}
107

    
108
$act = $_GET['act'];
109
if (!empty($_POST['act'])) {
110
	$act = $_POST['act'];
111
}
112

    
113
$a_pools = array();
114

    
115
if (is_array($config['dhcpd'][$if])) {
116
	$pool = $_GET['pool'];
117
	if (is_numeric($_POST['pool'])) {
118
		$pool = $_POST['pool'];
119
	}
120

    
121
	// If we have a pool but no interface name, that's not valid. Redirect away.
122
	if (is_numeric($pool) && empty($if)) {
123
		header("Location: services_dhcp.php");
124
		exit;
125
	}
126

    
127
	if (!is_array($config['dhcpd'][$if]['pool'])) {
128
		$config['dhcpd'][$if]['pool'] = array();
129
	}
130

    
131
	$a_pools = &$config['dhcpd'][$if]['pool'];
132

    
133
	if (is_numeric($pool) && $a_pools[$pool]) {
134
		$dhcpdconf = &$a_pools[$pool];
135
	} elseif ($act == "newpool") {
136
		$dhcpdconf = array();
137
	} else {
138
		$dhcpdconf = &$config['dhcpd'][$if];
139
	}
140

    
141
	if (!is_array($config['dhcpd'][$if]['staticmap'])) {
142
		$dhcpdconf['staticmap'] = array();
143
	}
144

    
145
	$a_maps = &$config['dhcpd'][$if]['staticmap'];
146
}
147
if (is_array($dhcpdconf)) {
148
	// Global Options
149
	if (!is_numeric($pool) && !($act == "newpool")) {
150
		$pconfig['enable'] = isset($dhcpdconf['enable']);
151
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
152
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
153
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
154
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
155

    
156
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
157
		// then show it true/checked.
158
		foreach ($config['dhcpd'] as $dhcpdifitem) {
159
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
160
			if ($dhcpleaseinlocaltime) {
161
				break;
162
			}
163
		}
164

    
165
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
166
	} else {
167
		// Options that exist only in pools
168
		$pconfig['descr'] = $dhcpdconf['descr'];
169
	}
170

    
171
	// Options that can be global or per-pool.
172
	if (is_array($dhcpdconf['range'])) {
173
		$pconfig['range_from'] = $dhcpdconf['range']['from'];
174
		$pconfig['range_to'] = $dhcpdconf['range']['to'];
175
	}
176

    
177
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
178
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
179
	$pconfig['gateway'] = $dhcpdconf['gateway'];
180
	$pconfig['domain'] = $dhcpdconf['domain'];
181
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
182
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
183
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
184
	$pconfig['ignorebootp'] = isset($dhcpdconf['ignorebootp']);
185
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
186
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
187
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
188
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
189
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
190
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
191
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
192
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
193
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
194
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
195
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
196
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
197
	$pconfig['tftp'] = $dhcpdconf['tftp'];
198
	$pconfig['ldap'] = $dhcpdconf['ldap'];
199
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
200
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
201
	$pconfig['filename'] = $dhcpdconf['filename'];
202
	$pconfig['filename32'] = $dhcpdconf['filename32'];
203
	$pconfig['filename64'] = $dhcpdconf['filename64'];
204
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
205
	$pconfig['netmask'] = $dhcpdconf['netmask'];
206
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
207
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
208
}
209

    
210
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
211
$ifcfgsn = $config['interfaces'][$if]['subnet'];
212

    
213
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
214
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
215

    
216
function validate_partial_mac_list($maclist) {
217
	$macs = explode(',', $maclist);
218

    
219
	// Loop through and look for invalid MACs.
220
	foreach ($macs as $mac) {
221
		if (!is_macaddr($mac, true)) {
222
			return false;
223
		}
224
	}
225

    
226
	return true;
227
}
228

    
229
if (isset($_POST['save'])) {
230

    
231
	unset($input_errors);
232

    
233
	$pconfig = $_POST;
234

    
235
	$numberoptions = array();
236
	for ($x = 0; $x < 99; $x++) {
237
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
238
			$numbervalue = array();
239
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
240
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
241
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
242
			$numberoptions['item'][] = $numbervalue;
243
		}
244
	}
245

    
246
	// Reload the new pconfig variable that the form uses.
247
	$pconfig['numberoptions'] = $numberoptions;
248

    
249
	/* input validation */
250

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

    
256
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
257
	}
258

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

    
263
	if ($_POST['range_from'] && !is_ipaddrv4($_POST['range_from'])) {
264
		$input_errors[] = gettext("A valid IPv4 address must be specified for range from.");
265
	}
266
	if ($_POST['range_to'] && !is_ipaddrv4($_POST['range_to'])) {
267
		$input_errors[] = gettext("A valid IPv4 address must be specified for range to.");
268
	}
269
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
270
		$input_errors[] = gettext("Range From and Range To must both be entered.");
271
	}
272
	if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
273
		$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
274
	}
275
	if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
276
		$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
277
	}
278
	$parent_ip = get_interface_ip($_POST['if']);
279
	if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
280
		$parent_sn = get_interface_subnet($_POST['if']);
281
		if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
282
			$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
283
		}
284
	}
285

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

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

    
294
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
295
		$deftime = 7200; // Default value if it's empty
296
		if (is_numeric($_POST['deftime'])) {
297
			$deftime = $_POST['deftime'];
298
		}
299

    
300
		foreach ($config['captiveportal'] as $cpZone => $cpdata) {
301
			if (!isset($cpdata['enable'])) {
302
				continue;
303
			}
304
			if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
305
				continue;
306
			}
307
			$cp_ifs = explode(',', $cpdata['interface']);
308
			if (!in_array($if, $cp_ifs)) {
309
				continue;
310
			}
311
			if ($cpdata['timeout'] > $deftime) {
312
				$input_errors[] = sprintf(gettext(
313
					'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
314
			}
315
		}
316
	}
317

    
318
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
319
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
320
	}
321
	if (($_POST['ddnsdomain'] && !is_domain($_POST['ddnsdomain']))) {
322
		$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
323
	}
324
	if (($_POST['ddnsdomain'] && !is_ipaddrv4($_POST['ddnsdomainprimary']))) {
325
		$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
326
	}
327
	if (($_POST['ddnsdomainkey'] && !$_POST['ddnsdomainkeyname']) ||
328
		($_POST['ddnsdomainkeyname'] && !$_POST['ddnsdomainkey'])) {
329
		$input_errors[] = gettext("Both a valid domain key and key name must be specified.");
330
	}
331
	if ($_POST['domainsearchlist']) {
332
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
333
		foreach ($domain_array as $curdomain) {
334
			if (!is_domain($curdomain)) {
335
				$input_errors[] = gettext("A valid domain search list must be specified.");
336
				break;
337
			}
338
		}
339
	}
340

    
341
	// Validate MACs
342
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
343
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
344
	}
345
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
346
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
347
	}
348

    
349
	if (($_POST['ntp1'] && (!is_ipaddrv4($_POST['ntp1']) && !is_hostname($_POST['ntp1']))) || ($_POST['ntp2'] && (!is_ipaddrv4($_POST['ntp2']) && !is_hostname($_POST['ntp2'])))) {
350
		$input_errors[] = gettext("A valid IP address or hostname must be specified for the primary/secondary NTP servers.");
351
	}
352
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
353
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
354
	}
355
	if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !filter_var($_POST['tftp'], FILTER_VALIDATE_URL)) {
356
		$input_errors[] = gettext("A valid IP address, hostname or URL must be specified for the TFTP server.");
357
	}
358
	if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
359
		$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
360
	}
361

    
362
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
363
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
364
	}
365
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
366
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
367
	}
368

    
369
	// Disallow a range that includes the virtualip
370
	if (is_array($config['virtualip']['vip'])) {
371
		foreach ($config['virtualip']['vip'] as $vip) {
372
			if ($vip['interface'] == $if) {
373
				if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
374
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
375
				}
376
			}
377
		}
378
	}
379

    
380
	$noip = false;
381
	if (is_array($a_maps)) {
382
		foreach ($a_maps as $map) {
383
			if (empty($map['ipaddr'])) {
384
				$noip = true;
385
			}
386
		}
387
	}
388

    
389
	if ($_POST['staticarp'] && $noip) {
390
		$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.");
391
	}
392

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

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

    
425
	// 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.
426
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
427
		/* make sure the range lies within the current subnet */
428
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
429
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
430
		}
431

    
432
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
433
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
434
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
435
		}
436

    
437
		if (is_numeric($pool) || ($act == "newpool")) {
438
			if (is_inrange_v4($_POST['range_from'],
439
				$config['dhcpd'][$if]['range']['from'],
440
				$config['dhcpd'][$if]['range']['to']) ||
441
				is_inrange_v4($_POST['range_to'],
442
				$config['dhcpd'][$if]['range']['from'],
443
				$config['dhcpd'][$if]['range']['to'])) {
444
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
445
			}
446
		}
447

    
448
		foreach ($a_pools as $id => $p) {
449
			if (is_numeric($pool) && ($id == $pool)) {
450
				continue;
451
			}
452

    
453
			if (is_inrange_v4($_POST['range_from'],
454
				$p['range']['from'], $p['range']['to']) ||
455
				is_inrange_v4($_POST['range_to'],
456
				$p['range']['from'], $p['range']['to'])) {
457
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
458
				break;
459
			}
460
		}
461

    
462
		if (is_array($a_maps)) {
463
			foreach ($a_maps as $map) {
464
				if (empty($map['ipaddr'])) {
465
					continue;
466
				}
467
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
468
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
469
					break;
470
				}
471
			}
472
		}
473
	}
474

    
475
	if (!$input_errors) {
476
		if (!is_numeric($pool)) {
477
			if ($act == "newpool") {
478
				$dhcpdconf = array();
479
			} else {
480
				if (!is_array($config['dhcpd'][$if])) {
481
					$config['dhcpd'][$if] = array();
482
				}
483
				$dhcpdconf = $config['dhcpd'][$if];
484
			}
485
		} else {
486
			if (is_array($a_pools[$pool])) {
487
				$dhcpdconf = $a_pools[$pool];
488
			} else {
489
				// Someone specified a pool but it doesn't exist. Punt.
490
				header("Location: services_dhcp.php");
491
				exit;
492
			}
493
		}
494
		if (!is_array($dhcpdconf['range'])) {
495
			$dhcpdconf['range'] = array();
496
		}
497

    
498
		$dhcpd_enable_changed = false;
499

    
500
		// Global Options
501
		if (!is_numeric($pool) && !($act == "newpool")) {
502
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
503
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
504
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
505
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
506
				$dhcpd_enable_changed = true;
507
			}
508

    
509
			$dhcpdconf['enable'] = $new_dhcpd_enable;
510
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
511
			$previous = $dhcpdconf['failover_peerip'];
512
			if ($previous != $_POST['failover_peerip']) {
513
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
514
			}
515

    
516
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
517
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
518
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
519
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
520
			}
521
		} else {
522
			// Options that exist only in pools
523
			$dhcpdconf['descr'] = $_POST['descr'];
524
		}
525

    
526
		// Options that can be global or per-pool.
527
		$dhcpdconf['range']['from'] = $_POST['range_from'];
528
		$dhcpdconf['range']['to'] = $_POST['range_to'];
529
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
530
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
531
		$dhcpdconf['netmask'] = $_POST['netmask'];
532

    
533
		unset($dhcpdconf['winsserver']);
534
		if ($_POST['wins1']) {
535
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
536
		}
537
		if ($_POST['wins2']) {
538
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
539
		}
540

    
541
		unset($dhcpdconf['dnsserver']);
542
		if ($_POST['dns1']) {
543
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
544
		}
545
		if ($_POST['dns2']) {
546
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
547
		}
548
		if ($_POST['dns3']) {
549
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
550
		}
551
		if ($_POST['dns4']) {
552
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
553
		}
554

    
555
		$dhcpdconf['gateway'] = $_POST['gateway'];
556
		$dhcpdconf['domain'] = $_POST['domain'];
557
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
558
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
559
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
560
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
561
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
562
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
563
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
564
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
565
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
566
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
567
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
568
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
569
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
570

    
571
		unset($dhcpdconf['ntpserver']);
572
		if ($_POST['ntp1']) {
573
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
574
		}
575
		if ($_POST['ntp2']) {
576
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
577
		}
578

    
579
		$dhcpdconf['tftp'] = $_POST['tftp'];
580
		$dhcpdconf['ldap'] = $_POST['ldap'];
581
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
582
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
583
		$dhcpdconf['filename'] = $_POST['filename'];
584
		$dhcpdconf['filename32'] = $_POST['filename32'];
585
		$dhcpdconf['filename64'] = $_POST['filename64'];
586
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
587
		unset($dhcpdconf['statsgraph']);
588
		if ($_POST['statsgraph']) {
589
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
590
			enable_rrd_graphing();
591
		}
592

    
593
		// Handle the custom options rowhelper
594
		if (isset($dhcpdconf['numberoptions']['item'])) {
595
			unset($dhcpdconf['numberoptions']['item']);
596
		}
597

    
598
		$dhcpdconf['numberoptions'] = $numberoptions;
599

    
600
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
601
			$a_pools[$pool] = $dhcpdconf;
602
		} elseif ($act == "newpool") {
603
			$a_pools[] = $dhcpdconf;
604
		} else {
605
			$config['dhcpd'][$if] = $dhcpdconf;
606
		}
607

    
608
		write_config();
609
	}
610
}
611

    
612
if ((isset($_POST['save']) || isset($_POST['apply'])) && (!$input_errors)) {
613
	$changes_applied = true;
614
	$retval = 0;
615
	$retvaldhcp = 0;
616
	$retvaldns = 0;
617
	/* dnsmasq_configure calls dhcpd_configure */
618
	/* no need to restart dhcpd twice */
619
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
620
		$retvaldns |= services_dnsmasq_configure();
621
		if ($retvaldns == 0) {
622
			clear_subsystem_dirty('hosts');
623
			clear_subsystem_dirty('staticmaps');
624
		}
625
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
626
		$retvaldns |= services_unbound_configure();
627
		if ($retvaldns == 0) {
628
			clear_subsystem_dirty('unbound');
629
			clear_subsystem_dirty('hosts');
630
			clear_subsystem_dirty('staticmaps');
631
		}
632
	} else {
633
		$retvaldhcp |= services_dhcpd_configure();
634
		if ($retvaldhcp == 0) {
635
			clear_subsystem_dirty('staticmaps');
636
		}
637
	}
638
	if ($dhcpd_enable_changed) {
639
		$retvalfc |= filter_configure();
640
	}
641

    
642
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
643
		$retval = 1;
644
	}
645
}
646

    
647
if ($act == "delpool") {
648
	if ($a_pools[$_GET['id']]) {
649
		unset($a_pools[$_GET['id']]);
650
		write_config();
651
		header("Location: services_dhcp.php?if={$if}");
652
		exit;
653
	}
654
}
655

    
656
if ($act == "del") {
657
	if ($a_maps[$_GET['id']]) {
658
		/* Remove static ARP entry, if necessary */
659
		if (isset($a_maps[$_GET['id']]['arp_table_static_entry'])) {
660
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_GET['id']]['ipaddr']));
661
		}
662
		unset($a_maps[$_GET['id']]);
663
		write_config();
664
		if (isset($config['dhcpd'][$if]['enable'])) {
665
			mark_subsystem_dirty('staticmaps');
666
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
667
				mark_subsystem_dirty('hosts');
668
			}
669
		}
670

    
671
		header("Location: services_dhcp.php?if={$if}");
672
		exit;
673
	}
674
}
675

    
676
// Build an HTML table that can be inserted into a Form_StaticText element
677
function build_pooltable() {
678
	global $a_pools, $if;
679

    
680
	$pooltbl =	'<div class="table-responsive">';
681
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
682
	$pooltbl .=			'<thead>';
683
	$pooltbl .=				'<tr>';
684
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
685
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
686
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
687
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
688
	$pooltbl .=				'</tr>';
689
	$pooltbl .=			'</thead>';
690
	$pooltbl .=			'<tbody>';
691

    
692
	if (is_array($a_pools)) {
693
		$i = 0;
694
		foreach ($a_pools as $poolent) {
695
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
696
				$pooltbl .= '<tr>';
697
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
698
							htmlspecialchars($poolent['range']['from']) . '</td>';
699

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

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

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

    
708
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '"></a></td>';
709
				$pooltbl .= '</tr>';
710
			}
711
		$i++;
712
		}
713
	}
714

    
715
	$pooltbl .=			'</tbody>';
716
	$pooltbl .=		'</table>';
717
	$pooltbl .= '</div>';
718

    
719
	return($pooltbl);
720
}
721

    
722
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
723
$pglinks = array("", "services_dhcp.php");
724

    
725
if (!empty($if) && isset($iflist[$if])) {
726
	$pgtitle[] = $iflist[$if];
727
	$pglinks[] = "@self";
728
}
729
$shortcut_section = "dhcp";
730

    
731
include("head.inc");
732

    
733
if ($input_errors) {
734
	print_input_errors($input_errors);
735
}
736

    
737
if ($changes_applied) {
738
	print_apply_result_box($retval);
739
}
740

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

    
745
/* active tabs */
746
$tab_array = array();
747
$tabscounter = 0;
748
$i = 0;
749
$have_small_subnet = false;
750

    
751
foreach ($iflist as $ifent => $ifname) {
752
	$oc = $config['interfaces'][$ifent];
753

    
754
	/* Not static IPv4 or subnet >= 31 */
755
	if ($oc['subnet'] >= 31) {
756
		$have_small_subnet = true;
757
		$example_name = $ifname;
758
		$example_cidr = $oc['subnet'];
759
		continue;
760
	}
761
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
762
		continue;
763
	}
764

    
765
	if ($ifent == $if) {
766
		$active = true;
767
	} else {
768
		$active = false;
769
	}
770

    
771
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
772
	$tabscounter++;
773
}
774

    
775
if ($tabscounter == 0) {
776
	if ($have_small_subnet) {
777
		$sentence2 = sprintf(gettext('%1$s has a CIDR mask of %2$s, which does not contain enough addresses.'), htmlspecialchars($example_name), htmlspecialchars($example_cidr));
778
	} else {
779
		$sentence2 = gettext("This system has no interfaces configured with a static IPv4 address.");
780
	}
781
	print_info_box(gettext("The DHCP Server requires a static IPv4 subnet large enough to serve addresses to clients.") . " " . $sentence2);
782
	include("foot.inc");
783
	exit;
784
}
785

    
786
display_top_tabs($tab_array);
787

    
788
$form = new Form();
789

    
790
$section = new Form_Section('General Options');
791

    
792
if (!is_numeric($pool) && !($act == "newpool")) {
793
	if (isset($config['dhcrelay']['enable'])) {
794
		$section->addInput(new Form_Checkbox(
795
			'enable',
796
			'Enable',
797
			gettext("DHCP Relay is currently enabled. DHCP Server canot be enabled while the DHCP Relay is enabled on any interface."),
798
			$pconfig['enable']
799
		))->setAttribute('disabled', true);
800
	} else {
801
		$section->addInput(new Form_Checkbox(
802
			'enable',
803
			'Enable',
804
			sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
805
			$pconfig['enable']
806
		));
807
	}
808
} else {
809
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
810
}
811

    
812
$section->addInput(new Form_Checkbox(
813
	'ignorebootp',
814
	'BOOTP',
815
	'Ignore BOOTP queries',
816
	$pconfig['ignorebootp']
817
));
818

    
819
$section->addInput(new Form_Checkbox(
820
	'denyunknown',
821
	'Deny unknown clients',
822
	'Only the clients defined below will get DHCP leases from this server.',
823
	$pconfig['denyunknown']
824
));
825

    
826
$section->addInput(new Form_Checkbox(
827
	'nonak',
828
	'Ignore denied clients',
829
	'Denied clients will be ignored rather than rejected.',
830
	$pconfig['nonak']
831
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
832

    
833
$section->addInput(new Form_Checkbox(
834
	'ignoreclientuids',
835
	'Ignore client identifiers',
836
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
837
	$pconfig['ignoreclientuids']
838
))->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.");
839

    
840

    
841
if (is_numeric($pool) || ($act == "newpool")) {
842
	$section->addInput(new Form_Input(
843
		'descr',
844
		'Pool Description',
845
		'text',
846
		$pconfig['descr']
847
	));
848
}
849

    
850
$section->addInput(new Form_StaticText(
851
	'Subnet',
852
	gen_subnet($ifcfgip, $ifcfgsn)
853
));
854

    
855
$section->addInput(new Form_StaticText(
856
	'Subnet mask',
857
	gen_subnet_mask($ifcfgsn)
858
));
859

    
860
// Compose a string to display the required address ranges
861
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
862

    
863
if (is_numeric($pool) || ($act == "newpool")) {
864
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
865
	if (is_array($config['dhcpd'][$if]['range'])) {
866
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
867
	}
868

    
869
	foreach ($a_pools as $p) {
870
		if (is_array($p['range'])) {
871
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
872
		}
873
	}
874
}
875

    
876
$section->addInput(new Form_StaticText(
877
	'Available range',
878
	$rangestr
879
));
880

    
881
if ($is_olsr_enabled) {
882
	$section->addInput(new Form_Select(
883
		'netmask',
884
		'Subnet mask',
885
		$pconfig['netmask'],
886
		array_combine(range(32, 1, -1), range(32, 1, -1))
887
	));
888
}
889

    
890
$group = new Form_Group('*Range');
891

    
892
$group->add(new Form_IpAddress(
893
	'range_from',
894
	null,
895
	$pconfig['range_from'],
896
	'V4'
897
))->setHelp('From');
898

    
899
$group->add(new Form_IpAddress(
900
	'range_to',
901
	null,
902
	$pconfig['range_to'],
903
	'V4'
904
))->setHelp('To');
905

    
906
$section->add($group);
907

    
908
$form->add($section);
909

    
910
if (!is_numeric($pool) && !($act == "newpool")) {
911
	$section = new Form_Section('Additional Pools');
912

    
913
	$btnaddpool = new Form_Button(
914
		'btnaddpool',
915
		'Add pool',
916
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
917
		'fa-plus'
918
	);
919
	$btnaddpool->addClass('btn-success');
920

    
921
	$section->addInput(new Form_StaticText(
922
		'Add',
923
		$btnaddpool
924
	))->setHelp('If additional pools of addresses are needed inside of this subnet outside the above Range, they may be specified here.');
925

    
926
	if (is_array($a_pools)) {
927
		$section->addInput(new Form_StaticText(
928
			null,
929
			build_pooltable()
930
		));
931
	}
932

    
933
	$form->add($section);
934
}
935

    
936
$section = new Form_Section('Servers');
937

    
938
$section->addInput(new Form_IpAddress(
939
	'wins1',
940
	'WINS servers',
941
	$pconfig['wins1'],
942
	'V4'
943
))->setAttribute('placeholder', 'WINS Server 1');
944

    
945
$section->addInput(new Form_IpAddress(
946
	'wins2',
947
	null,
948
	$pconfig['wins2'],
949
	'V4'
950
))->setAttribute('placeholder', 'WINS Server 2');
951

    
952
for ($idx=1; $idx<=4; $idx++) {
953
	$section->addInput(new Form_IpAddress(
954
		'dns' . $idx,
955
		($idx == 1) ? 'DNS servers':null,
956
		$pconfig['dns' . $idx],
957
		'V4'
958
	))->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.':'');
959
}
960

    
961
$form->add($section);
962

    
963
$section = new Form_Section('Other Options');
964

    
965
$section->addInput(new Form_IpAddress(
966
	'gateway',
967
	'Gateway',
968
	$pconfig['gateway'],
969
	'V4'
970
))->setPattern('[.a-zA-Z0-9_]+')
971
  ->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.');
972

    
973
$section->addInput(new Form_Input(
974
	'domain',
975
	'Domain name',
976
	'text',
977
	$pconfig['domain']
978
))->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.');
979

    
980
$section->addInput(new Form_Input(
981
	'domainsearchlist',
982
	'Domain search list',
983
	'text',
984
	$pconfig['domainsearchlist']
985
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
986

    
987
$section->addInput(new Form_Input(
988
	'deftime',
989
	'Default lease time',
990
	'number',
991
	$pconfig['deftime']
992
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds.');
993

    
994
$section->addInput(new Form_Input(
995
	'maxtime',
996
	'Maximum lease time',
997
	'number',
998
	$pconfig['maxtime']
999
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds.');
1000

    
1001
if (!is_numeric($pool) && !($act == "newpool")) {
1002
	$section->addInput(new Form_IpAddress(
1003
		'failover_peerip',
1004
		'Failover peer IP',
1005
		$pconfig['failover_peerip'],
1006
		'V4'
1007
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
1008
				'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).');
1009
}
1010

    
1011
if (!is_numeric($pool) && !($act == "newpool")) {
1012
	$section->addInput(new Form_Checkbox(
1013
		'staticarp',
1014
		'Static ARP',
1015
		'Enable Static ARP entries',
1016
		$pconfig['staticarp']
1017
	))->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.');
1018

    
1019
	$section->addInput(new Form_Checkbox(
1020
		'dhcpleaseinlocaltime',
1021
		'Time format change',
1022
		'Change DHCP display lease time from UTC to local time',
1023
		$pconfig['dhcpleaseinlocaltime']
1024
	))->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.' .
1025
				' This will be used for all DHCP interfaces lease time.');
1026
	$section->addInput(new Form_Checkbox(
1027
		'statsgraph',
1028
		'Statistics graphs',
1029
		'Enable RRD statistics graphs',
1030
		$pconfig['statsgraph']
1031
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1032
}
1033

    
1034
// DDNS
1035
$btnadv = new Form_Button(
1036
	'btnadvdns',
1037
	'Display Advanced',
1038
	null,
1039
	'fa-cog'
1040
);
1041

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

    
1044
$section->addInput(new Form_StaticText(
1045
	'Dynamic DNS',
1046
	$btnadv
1047
));
1048

    
1049
$section->addInput(new Form_Checkbox(
1050
	'ddnsupdate',
1051
	null,
1052
	'Enable registration of DHCP client names in DNS',
1053
	$pconfig['ddnsupdate']
1054
));
1055

    
1056
$section->addInput(new Form_Input(
1057
	'ddnsdomain',
1058
	'DDNS Domain',
1059
	'text',
1060
	$pconfig['ddnsdomain']
1061
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
1062
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1063

    
1064
$section->addInput(new Form_Checkbox(
1065
	'ddnsforcehostname',
1066
	'DDNS Hostnames',
1067
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1068
	$pconfig['ddnsforcehostname']
1069
))->setHelp('Default registers host name option supplied by DHCP client.');
1070

    
1071
$section->addInput(new Form_IpAddress(
1072
	'ddnsdomainprimary',
1073
	'Primary DDNS address',
1074
	$pconfig['ddnsdomainprimary'],
1075
	'V4'
1076
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1077

    
1078
$section->addInput(new Form_Input(
1079
	'ddnsdomainkeyname',
1080
	'DNS Domain key',
1081
	'text',
1082
	$pconfig['ddnsdomainkeyname']
1083
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1084

    
1085
$section->addInput(new Form_Input(
1086
	'ddnsdomainkey',
1087
	'DNS Domain key secret',
1088
	'text',
1089
	$pconfig['ddnsdomainkey']
1090
))->setHelp('Dynamic DNS domain key secret (HMAC-MD5) which will be used to register client names in the DNS server.');
1091

    
1092
// Advanced MAC
1093
$btnadv = new Form_Button(
1094
	'btnadvmac',
1095
	'Display Advanced',
1096
	null,
1097
	'fa-cog'
1098
);
1099

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

    
1102
$section->addInput(new Form_StaticText(
1103
	'MAC address control',
1104
	$btnadv
1105
));
1106

    
1107
$section->addInput(new Form_Input(
1108
	'mac_allow',
1109
	'MAC Allow',
1110
	'text',
1111
	$pconfig['mac_allow']
1112
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1113

    
1114
$section->addInput(new Form_Input(
1115
	'mac_deny',
1116
	'MAC Deny',
1117
	'text',
1118
	$pconfig['mac_deny']
1119
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1120

    
1121
// Advanced NTP
1122
$btnadv = new Form_Button(
1123
	'btnadvntp',
1124
	'Display Advanced',
1125
	null,
1126
	'fa-cog'
1127
);
1128

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

    
1131
$section->addInput(new Form_StaticText(
1132
	'NTP',
1133
	$btnadv
1134
));
1135

    
1136
$section->addInput(new Form_IpAddress(
1137
	'ntp1',
1138
	'NTP Server 1',
1139
	$pconfig['ntp1'],
1140
	'HOSTV4'
1141
));
1142

    
1143
$section->addInput(new Form_IpAddress(
1144
	'ntp2',
1145
	'NTP Server 2',
1146
	$pconfig['ntp2'],
1147
	'HOSTV4'
1148
));
1149

    
1150
// Advanced TFTP
1151
$btnadv = new Form_Button(
1152
	'btnadvtftp',
1153
	'Display Advanced',
1154
	null,
1155
	'fa-cog'
1156
);
1157

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

    
1160
$section->addInput(new Form_StaticText(
1161
	'TFTP',
1162
	$btnadv
1163
));
1164

    
1165
$section->addInput(new Form_Input(
1166
	'tftp',
1167
	'TFTP Server',
1168
	'text',
1169
	$pconfig['tftp']
1170
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1171

    
1172
// Advanced LDAP
1173
$btnadv = new Form_Button(
1174
	'btnadvldap',
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
	'LDAP',
1184
	$btnadv
1185
));
1186

    
1187
$section->addInput(new Form_Input(
1188
	'ldap',
1189
	'LDAP Server URI',
1190
	'text',
1191
	$pconfig['ldap']
1192
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1193

    
1194
// Advanced Network Booting options
1195
$btnadv = new Form_Button(
1196
	'btnadvnwkboot',
1197
	'Display Advanced',
1198
	null,
1199
	'fa-cog'
1200
);
1201

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

    
1204
$section->addInput(new Form_StaticText(
1205
	'Network Booting',
1206
	$btnadv
1207
));
1208

    
1209
$section->addInput(new Form_Checkbox(
1210
	'netboot',
1211
	'Enable',
1212
	'Enables network booting',
1213
	$pconfig['netboot']
1214
));
1215

    
1216
$section->addInput(new Form_IpAddress(
1217
	'nextserver',
1218
	'Next Server',
1219
	$pconfig['nextserver'],
1220
	'V4'
1221
))->setHelp('Enter the IP address of the next server');
1222

    
1223
$section->addInput(new Form_Input(
1224
	'filename',
1225
	'Default BIOS file name',
1226
	'text',
1227
	$pconfig['filename']
1228
));
1229

    
1230
$section->addInput(new Form_Input(
1231
	'filename32',
1232
	'UEFI 32 bit file name',
1233
	'text',
1234
	$pconfig['filename32']
1235
));
1236

    
1237
$section->addInput(new Form_Input(
1238
	'filename64',
1239
	'UEFI 64 bit file name',
1240
	'text',
1241
	$pconfig['filename64']
1242
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1243
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1244

    
1245
$section->addInput(new Form_Input(
1246
	'rootpath',
1247
	'Root path',
1248
	'text',
1249
	$pconfig['rootpath']
1250
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1251

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

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

    
1262
$section->addInput(new Form_StaticText(
1263
	'Additional BOOTP/DHCP Options',
1264
	$btnadv
1265
));
1266

    
1267
$form->add($section);
1268

    
1269
$section = new Form_Section('Additional BOOTP/DHCP Options');
1270
$section->addClass('adnlopts');
1271

    
1272
$section->addInput(new Form_StaticText(
1273
	null,
1274
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1275
	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>')
1276
));
1277

    
1278
if (!$pconfig['numberoptions']) {
1279
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1280
}
1281

    
1282
$customitemtypes = array(
1283
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1284
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1285
	'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')
1286
);
1287

    
1288
$numrows = count($item) -1;
1289
$counter = 0;
1290

    
1291
$numrows = count($pconfig['numberoptions']['item']) -1;
1292

    
1293
foreach ($pconfig['numberoptions']['item'] as $item) {
1294
	$number = $item['number'];
1295
	$itemtype = $item['type'];
1296
	$value = base64_decode($item['value']);
1297

    
1298
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1299
	$group->addClass('repeatable');
1300

    
1301
	$group->add(new Form_Input(
1302
		'number' . $counter,
1303
		null,
1304
		'text',
1305
		$number
1306
	))->setHelp($numrows == $counter ? 'Number':null);
1307

    
1308

    
1309
	$group->add(new Form_Select(
1310
		'itemtype' . $counter,
1311
		null,
1312
		$itemtype,
1313
		$customitemtypes
1314
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1315

    
1316
	$group->add(new Form_Input(
1317
		'value' . $counter,
1318
		null,
1319
		'text',
1320
		$value
1321
	))->setHelp($numrows == $counter ? 'Value':null);
1322

    
1323
	$group->add(new Form_Button(
1324
		'deleterow' . $counter,
1325
		'Delete',
1326
		null,
1327
		'fa-trash'
1328
	))->addClass('btn-warning');
1329

    
1330
	$section->add($group);
1331

    
1332
	$counter++;
1333
}
1334

    
1335
$section->addInput(new Form_Button(
1336
	'addrow',
1337
	'Add',
1338
	null,
1339
	'fa-plus'
1340
))->addClass('btn-success');
1341

    
1342
$form->add($section);
1343

    
1344
if ($act == "newpool") {
1345
	$form->addGlobal(new Form_Input(
1346
		'act',
1347
		null,
1348
		'hidden',
1349
		'newpool'
1350
	));
1351
}
1352

    
1353
if (is_numeric($pool)) {
1354
	$form->addGlobal(new Form_Input(
1355
		'pool',
1356
		null,
1357
		'hidden',
1358
		$pool
1359
	));
1360
}
1361

    
1362
$form->addGlobal(new Form_Input(
1363
	'if',
1364
	null,
1365
	'hidden',
1366
	$if
1367
));
1368

    
1369
print($form);
1370

    
1371
// DHCP Static Mappings table
1372

    
1373
if (!is_numeric($pool) && !($act == "newpool")) {
1374

    
1375
	// Decide whether display of the Client Id column is needed.
1376
	$got_cid = false;
1377
	if (is_array($a_maps)) {
1378
		foreach ($a_maps as $map) {
1379
			if (!empty($map['cid'])) {
1380
				$got_cid = true;
1381
				break;
1382
			}
1383
		}
1384
	}
1385
?>
1386

    
1387
<div class="panel panel-default">
1388
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1389
	<div class="table-responsive">
1390
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1391
				<thead>
1392
					<tr>
1393
						<th><?=gettext("Static ARP")?></th>
1394
						<th><?=gettext("MAC address")?></th>
1395
<?php
1396
	if ($got_cid):
1397
?>
1398
						<th><?=gettext("Client Id")?></th>
1399
<?php
1400
	endif;
1401
?>
1402
						<th><?=gettext("IP address")?></th>
1403
						<th><?=gettext("Hostname")?></th>
1404
						<th><?=gettext("Description")?></th>
1405
						<th></th>
1406
					</tr>
1407
				</thead>
1408
<?php
1409
	if (is_array($a_maps)) {
1410
		$i = 0;
1411
?>
1412
				<tbody>
1413
<?php
1414
		foreach ($a_maps as $mapent) {
1415
?>
1416
					<tr>
1417
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1418
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1419
								<i class="fa fa-check"></i>
1420
							<?php endif; ?>
1421
						</td>
1422
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1423
							<?=htmlspecialchars($mapent['mac'])?>
1424
						</td>
1425
<?php
1426
			if ($got_cid):
1427
?>
1428
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1429
							<?=htmlspecialchars($mapent['cid'])?>
1430
						</td>
1431
<?php
1432
			endif;
1433
?>
1434
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1435
							<?=htmlspecialchars($mapent['ipaddr'])?>
1436
						</td>
1437
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1438
							<?=htmlspecialchars($mapent['hostname'])?>
1439
						</td>
1440
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1441
							<?=htmlspecialchars($mapent['descr'])?>
1442
						</td>
1443
						<td>
1444
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1445
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>"></a>
1446
						</td>
1447
					</tr>
1448
<?php
1449
		$i++;
1450
		}
1451
?>
1452
				</tbody>
1453
<?php
1454
	}
1455
?>
1456
		</table>
1457
	</div>
1458
</div>
1459

    
1460
<nav class="action-buttons">
1461
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1462
		<i class="fa fa-plus icon-embed-btn"></i>
1463
		<?=gettext("Add")?>
1464
	</a>
1465
</nav>
1466
<?php
1467
}
1468
?>
1469

    
1470
<script type="text/javascript">
1471
//<![CDATA[
1472
events.push(function() {
1473

    
1474
	// Show advanced DNS options ======================================================================================
1475
	var showadvdns = false;
1476

    
1477
	function show_advdns(ispageload) {
1478
		var text;
1479
		// On page load decide the initial state based on the data.
1480
		if (ispageload) {
1481
<?php
1482
			if (!$pconfig['ddnsupdate'] && !$pconfig['ddnsforcehostname'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1483
			    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1484
				$showadv = false;
1485
			} else {
1486
				$showadv = true;
1487
			}
1488
?>
1489
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1490
		} else {
1491
			// It was a click, swap the state.
1492
			showadvdns = !showadvdns;
1493
		}
1494

    
1495
		hideCheckbox('ddnsupdate', !showadvdns);
1496
		hideInput('ddnsdomain', !showadvdns);
1497
		hideCheckbox('ddnsforcehostname', !showadvdns);
1498
		hideInput('ddnsdomainprimary', !showadvdns);
1499
		hideInput('ddnsdomainkeyname', !showadvdns);
1500
		hideInput('ddnsdomainkey', !showadvdns);
1501

    
1502
		if (showadvdns) {
1503
			text = "<?=gettext('Hide Advanced');?>";
1504
		} else {
1505
			text = "<?=gettext('Display Advanced');?>";
1506
		}
1507
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1508
	}
1509

    
1510
	$('#btnadvdns').click(function(event) {
1511
		show_advdns();
1512
	});
1513

    
1514
	// Show advanced MAC options ======================================================================================
1515
	var showadvmac = false;
1516

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

    
1534
		hideInput('mac_allow', !showadvmac);
1535
		hideInput('mac_deny', !showadvmac);
1536

    
1537
		if (showadvmac) {
1538
			text = "<?=gettext('Hide Advanced');?>";
1539
		} else {
1540
			text = "<?=gettext('Display Advanced');?>";
1541
		}
1542
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1543
	}
1544

    
1545
	$('#btnadvmac').click(function(event) {
1546
		show_advmac();
1547
	});
1548

    
1549
	// Show advanced NTP options ======================================================================================
1550
	var showadvntp = false;
1551

    
1552
	function show_advntp(ispageload) {
1553
		var text;
1554
		// On page load decide the initial state based on the data.
1555
		if (ispageload) {
1556
<?php
1557
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1558
				$showadv = false;
1559
			} else {
1560
				$showadv = true;
1561
			}
1562
?>
1563
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1564
		} else {
1565
			// It was a click, swap the state.
1566
			showadvntp = !showadvntp;
1567
		}
1568

    
1569
		hideInput('ntp1', !showadvntp);
1570
		hideInput('ntp2', !showadvntp);
1571

    
1572
		if (showadvntp) {
1573
			text = "<?=gettext('Hide Advanced');?>";
1574
		} else {
1575
			text = "<?=gettext('Display Advanced');?>";
1576
		}
1577
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1578
	}
1579

    
1580
	$('#btnadvntp').click(function(event) {
1581
		show_advntp();
1582
	});
1583

    
1584
	// Show advanced TFTP options ======================================================================================
1585
	var showadvtftp = false;
1586

    
1587
	function show_advtftp(ispageload) {
1588
		var text;
1589
		// On page load decide the initial state based on the data.
1590
		if (ispageload) {
1591
<?php
1592
			if (empty($pconfig['tftp'])) {
1593
				$showadv = false;
1594
			} else {
1595
				$showadv = true;
1596
			}
1597
?>
1598
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1599
		} else {
1600
			// It was a click, swap the state.
1601
			showadvtftp = !showadvtftp;
1602
		}
1603

    
1604
		hideInput('tftp', !showadvtftp);
1605

    
1606
		if (showadvtftp) {
1607
			text = "<?=gettext('Hide Advanced');?>";
1608
		} else {
1609
			text = "<?=gettext('Display Advanced');?>";
1610
		}
1611
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1612
	}
1613

    
1614
	$('#btnadvtftp').click(function(event) {
1615
		show_advtftp();
1616
	});
1617

    
1618
	// Show advanced LDAP options ======================================================================================
1619
	var showadvldap = false;
1620

    
1621
	function show_advldap(ispageload) {
1622
		var text;
1623
		// On page load decide the initial state based on the data.
1624
		if (ispageload) {
1625
<?php
1626
			if (empty($pconfig['ldap'])) {
1627
				$showadv = false;
1628
			} else {
1629
				$showadv = true;
1630
			}
1631
?>
1632
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1633
		} else {
1634
			// It was a click, swap the state.
1635
			showadvldap = !showadvldap;
1636
		}
1637

    
1638
		hideInput('ldap', !showadvldap);
1639

    
1640
		if (showadvldap) {
1641
			text = "<?=gettext('Hide Advanced');?>";
1642
		} else {
1643
			text = "<?=gettext('Display Advanced');?>";
1644
		}
1645
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1646
	}
1647

    
1648
	$('#btnadvldap').click(function(event) {
1649
		show_advldap();
1650
	});
1651

    
1652
	// Show advanced additional opts options ===========================================================================
1653
	var showadvopts = false;
1654

    
1655
	function show_advopts(ispageload) {
1656
		var text;
1657
		// On page load decide the initial state based on the data.
1658
		if (ispageload) {
1659
<?php
1660
			if (empty($pconfig['numberoptions']) ||
1661
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1662
				$showadv = false;
1663
			} else {
1664
				$showadv = true;
1665
			}
1666
?>
1667
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1668
		} else {
1669
			// It was a click, swap the state.
1670
			showadvopts = !showadvopts;
1671
		}
1672

    
1673
		hideClass('adnlopts', !showadvopts);
1674

    
1675
		if (showadvopts) {
1676
			text = "<?=gettext('Hide Advanced');?>";
1677
		} else {
1678
			text = "<?=gettext('Display Advanced');?>";
1679
		}
1680
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1681
	}
1682

    
1683
	$('#btnadvopts').click(function(event) {
1684
		show_advopts();
1685
	});
1686

    
1687
	// Show advanced Network Booting options ===========================================================================
1688
	var showadvnwkboot = false;
1689

    
1690
	function show_advnwkboot(ispageload) {
1691
		var text;
1692
		// On page load decide the initial state based on the data.
1693
		if (ispageload) {
1694
<?php
1695
			if (empty($pconfig['netboot'])) {
1696
				$showadv = false;
1697
			} else {
1698
				$showadv = true;
1699
			}
1700
?>
1701
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1702
		} else {
1703
			// It was a click, swap the state.
1704
			showadvnwkboot = !showadvnwkboot;
1705
		}
1706

    
1707
		hideCheckbox('netboot', !showadvnwkboot);
1708
		hideInput('nextserver', !showadvnwkboot);
1709
		hideInput('filename', !showadvnwkboot);
1710
		hideInput('filename32', !showadvnwkboot);
1711
		hideInput('filename64', !showadvnwkboot);
1712
		hideInput('rootpath', !showadvnwkboot);
1713

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

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

    
1726
	// ---------- On initial page load ------------------------------------------------------------
1727

    
1728
	show_advdns(true);
1729
	show_advmac(true);
1730
	show_advntp(true);
1731
	show_advtftp(true);
1732
	show_advldap(true);
1733
	show_advopts(true);
1734
	show_advnwkboot(true);
1735

    
1736
	// Suppress "Delete row" button if there are fewer than two rows
1737
	checkLastRow();
1738
});
1739
//]]>
1740
</script>
1741

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