Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

    
99
$a_pools = array();
100

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

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

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

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

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

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

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

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

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

    
158
	$pconfig['deftime'] = $dhcpdconf['defaultleasetime'];
159
	$pconfig['maxtime'] = $dhcpdconf['maxleasetime'];
160
	$pconfig['gateway'] = $dhcpdconf['gateway'];
161
	$pconfig['domain'] = $dhcpdconf['domain'];
162
	$pconfig['domainsearchlist'] = $dhcpdconf['domainsearchlist'];
163
	list($pconfig['wins1'], $pconfig['wins2']) = $dhcpdconf['winsserver'];
164
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $dhcpdconf['dnsserver'];
165
	$pconfig['ignorebootp'] = isset($dhcpdconf['ignorebootp']);
166

    
167
	if (isset($dhcpdconf['denyunknown'])) {
168
		$pconfig['denyunknown'] = empty($dhcpdconf['denyunknown']) ? "enabled" : $dhcpdconf['denyunknown'];
169
	} else {
170
		$pconfig['denyunknown'] = "disabled";
171
	}
172

    
173
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
174
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
175
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
176
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
177
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
178
	$pconfig['ddnsdomainkeyalgorithm'] = $dhcpdconf['ddnsdomainkeyalgorithm'];
179
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
180
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
181
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
182
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
183
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
184
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
185
	$pconfig['tftp'] = $dhcpdconf['tftp'];
186
	$pconfig['ldap'] = $dhcpdconf['ldap'];
187
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
188
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
189
	$pconfig['filename'] = $dhcpdconf['filename'];
190
	$pconfig['filename32'] = $dhcpdconf['filename32'];
191
	$pconfig['filename64'] = $dhcpdconf['filename64'];
192
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
193
	$pconfig['netmask'] = $dhcpdconf['netmask'];
194
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
195
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
196
	$pconfig['disablepingcheck'] = $dhcpdconf['disablepingcheck'];
197
	$pconfig['ddnsclientupdates'] = $dhcpdconf['ddnsclientupdates'];
198

    
199
	// OMAPI Settings
200
	if(isset($dhcpdconf['omapi_port'])) {
201
		$pconfig['omapi_port'] = $dhcpdconf['omapi_port'];
202
		$pconfig['omapi_key'] = $dhcpdconf['omapi_key'];
203
		$pconfig['omapi_key_algorithm'] = $dhcpdconf['omapi_key_algorithm'];
204
	}
205
}
206

    
207
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
208
$ifcfgsn = $config['interfaces'][$if]['subnet'];
209

    
210
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
211
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
212

    
213
function validate_partial_mac_list($maclist) {
214
	$macs = explode(',', $maclist);
215

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

    
223
	return true;
224
}
225

    
226
if (isset($_POST['save'])) {
227

    
228
	unset($input_errors);
229

    
230
	$pconfig = $_POST;
231

    
232
	$numberoptions = array();
233
	for ($x = 0; $x < 99; $x++) {
234
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
235
			if ($_POST["number{$x}"] < 1 || $_POST["number{$x}"] > 254) {
236
				$input_errors[] = gettext("The DHCP option must be a number between 1 and 254.");
237
				continue;
238
			}
239
			$numbervalue = array();
240
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
241
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
242
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
243
			$numberoptions['item'][] = $numbervalue;
244
		}
245
	}
246

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

    
250
	/* input validation */
251

    
252
	/*
253
	 * Check the OMAPI settings
254
	 * - Make sure that if the port is defined, that it is valid and isn't in use
255
	 * - Make sure the key is defined and the length is appropriate for the selected algorithm
256
	 * - Generate a new key if selected
257
	 */
258
	if (!empty($_POST['omapi_port'])) {
259
		// Check the port entry
260
		switch(true){
261
			case !is_port($_POST['omapi_port']) || $_POST['omapi_port'] <= 1024:
262
				$input_errors[] = gettext("The specified OMAPI port number is invalid. Port number must be between 1024 and 65635.");
263
				break;
264
			case is_port_in_use($_POST['omapi_port']) && $_POST['omapi_port'] != $dhcpdconf['omapi_port']:
265
				$input_errors[] = gettext("Specified port number for OMAPI is in use. Please choose another port or consider using the default.");
266
				break;
267
		}
268

    
269
		// Define the minimum base64 character length for each algorithm
270
		$key_char_len_by_alg = array(
271
			'hmac-md5' => 24,
272
			'hmac-sha1' => 28,
273
			'hmac-sha224' => 40,
274
			'hmac-sha256' => 44,
275
			'hmac-sha384' => 64,
276
			'hmac-sha512' => 88
277
		);
278

    
279
		// Generate a key if checked
280
		if ($_POST['omapi_gen_key'] == "yes") {
281
			// Figure out the key bits from the selected algorithm
282
			switch ($_POST['omapi_key_algorithm']) {
283
				case "hmac-md5":
284
					$key_bit_len = 128;
285
					break;
286
				case "hmac-sha1":
287
					$key_bit_len = 160;
288
					break;
289
				default:
290
					$key_bit_len = str_replace("hmac-sha","",$_POST['omapi_key_algorithm']);
291
					break;
292
			}
293

    
294
			// Convert the bits to bytes
295
			$key_bytes_len = $key_bit_len / 8; // 8 bits = 1 Byte
296

    
297
			// Generate random bytes based on key length
298
			$ran_bytes = openssl_random_pseudo_bytes($key_bytes_len);
299

    
300
			// Encode the bytes to get the key string
301
			$key_str = base64_encode($ran_bytes);
302

    
303
			// Set the key
304
			$_POST['omapi_key'] = $key_str;
305
			$pconfig['omapi_key'] = $key_str;
306

    
307
			// Uncheck the generate box
308
			unset($_POST['omapi_gen_key']);
309
			unset($pconfig['omapi_gen_key']);
310
		} elseif (!empty($_POST['omapi_key'])) { // Check the key if it's not being generated
311
			if (strlen($_POST['omapi_key']) < $key_char_len_by_alg[$_POST['omapi_key_algorithm']]) {
312
				$input_errors[] = gettext("Please specify a valid OMAPI key. Key does not meet the minimum length requirement of {$key_char_len_by_alg[$_POST['omapi_key_algorithm']]} for the selected algorithm {$_POST['omapi_key_algorithm']}.");
313
			}
314
		} else {
315
			$input_errors[] = gettext("A key is required when OMAPI is enabled (port specified).");
316
		}
317
	}
318

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

    
324
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
325
	}
326

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

    
331
	if ($_POST['range_from'] && !is_ipaddrv4($_POST['range_from'])) {
332
		$input_errors[] = gettext("A valid IPv4 address must be specified for range from.");
333
	}
334
	if ($_POST['range_to'] && !is_ipaddrv4($_POST['range_to'])) {
335
		$input_errors[] = gettext("A valid IPv4 address must be specified for range to.");
336
	}
337
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
338
		$input_errors[] = gettext("Range From and Range To must both be entered.");
339
	}
340
	if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
341
		$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
342
	}
343
	if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
344
		$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
345
	}
346
	$parent_ip = get_interface_ip($_POST['if']);
347
	if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
348
		$parent_sn = get_interface_subnet($_POST['if']);
349
		if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
350
			$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
351
		}
352
	}
353

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

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

    
362
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
363
		$deftime = 7200; // Default value if it's empty
364
		if (is_numeric($_POST['deftime'])) {
365
			$deftime = $_POST['deftime'];
366
		}
367

    
368
		foreach ($config['captiveportal'] as $cpZone => $cpdata) {
369
			if (!isset($cpdata['enable'])) {
370
				continue;
371
			}
372
			if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
373
				continue;
374
			}
375
			$cp_ifs = explode(',', $cpdata['interface']);
376
			if (!in_array($if, $cp_ifs)) {
377
				continue;
378
			}
379
			if ($cpdata['timeout'] > $deftime) {
380
				$input_errors[] = sprintf(gettext(
381
					'The Captive Portal zone (%1$s) has Hard Timeout parameter set to a value bigger than Default lease time (%2$s).'), $cpZone, $deftime);
382
			}
383
		}
384
	}
385

    
386
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
387
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
388
	}
389
	if ($_POST['ddnsupdate'] && !is_domain($_POST['ddnsdomain'])) {
390
		$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
391
	}
392
	if ($_POST['ddnsupdate'] && !is_ipaddrv4($_POST['ddnsdomainprimary'])) {
393
		$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
394
	}
395
	if ($_POST['ddnsupdate'] && (!$_POST['ddnsdomainkeyname'] || !$_POST['ddnsdomainkeyalgorithm'] || !$_POST['ddnsdomainkey'])) {
396
		$input_errors[] = gettext("A valid domain key name, algorithm and secret must be specified.");
397
	}
398
	if ($_POST['domainsearchlist']) {
399
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
400
		foreach ($domain_array as $curdomain) {
401
			if (!is_domain($curdomain)) {
402
				$input_errors[] = gettext("A valid domain search list must be specified.");
403
				break;
404
			}
405
		}
406
	}
407

    
408
	// Validate MACs
409
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
410
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
411
	}
412
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
413
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
414
	}
415

    
416
	if (($_POST['ntp1'] && (!is_ipaddrv4($_POST['ntp1']) && !is_hostname($_POST['ntp1']))) || ($_POST['ntp2'] && (!is_ipaddrv4($_POST['ntp2']) && !is_hostname($_POST['ntp2'])))) {
417
		$input_errors[] = gettext("A valid IP address or hostname must be specified for the primary/secondary NTP servers.");
418
	}
419
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
420
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
421
	}
422
	if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !filter_var($_POST['tftp'], FILTER_VALIDATE_URL)) {
423
		$input_errors[] = gettext("A valid IP address, hostname or URL must be specified for the TFTP server.");
424
	}
425
	if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
426
		$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
427
	}
428

    
429
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
430
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
431
	}
432
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
433
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
434
	}
435

    
436
	// Disallow a range that includes the virtualip
437
	if (is_array($config['virtualip']['vip'])) {
438
		foreach ($config['virtualip']['vip'] as $vip) {
439
			if ($vip['interface'] == $if) {
440
				if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
441
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
442
				}
443
			}
444
		}
445
	}
446

    
447
	$noip = false;
448
	if (is_array($a_maps)) {
449
		foreach ($a_maps as $map) {
450
			if (empty($map['ipaddr'])) {
451
				$noip = true;
452
			}
453
		}
454
	}
455

    
456
	if ($_POST['staticarp'] && $noip) {
457
		$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.");
458
	}
459

    
460
	if (is_array($pconfig['numberoptions']['item'])) {
461
		foreach ($pconfig['numberoptions']['item'] as $numberoption) {
462
			$numberoption_value = base64_decode($numberoption['value']);
463
			if ($numberoption['type'] == 'text' && strstr($numberoption_value, '"')) {
464
				$input_errors[] = gettext("Text type cannot include quotation marks.");
465
			} else if ($numberoption['type'] == 'string' && !preg_match('/^"[^"]*"$/', $numberoption_value) && !preg_match('/^[0-9a-f]{2}(?:\:[0-9a-f]{2})*$/i', $numberoption_value)) {
466
				$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");
467
			} else if ($numberoption['type'] == 'boolean' && $numberoption_value != 'true' && $numberoption_value != 'false' && $numberoption_value != 'on' && $numberoption_value != 'off') {
468
				$input_errors[] = gettext("Boolean type must be true, false, on, or off.");
469
			} else if ($numberoption['type'] == 'unsigned integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 255)) {
470
				$input_errors[] = gettext("Unsigned 8-bit integer type must be a number in the range 0 to 255.");
471
			} else if ($numberoption['type'] == 'unsigned integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 65535)) {
472
				$input_errors[] = gettext("Unsigned 16-bit integer type must be a number in the range 0 to 65535.");
473
			} else if ($numberoption['type'] == 'unsigned integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < 0 || $numberoption_value > 4294967295)) {
474
				$input_errors[] = gettext("Unsigned 32-bit integer type must be a number in the range 0 to 4294967295.");
475
			} else if ($numberoption['type'] == 'signed integer 8' && (!is_numeric($numberoption_value) || $numberoption_value < -128 || $numberoption_value > 127)) {
476
				$input_errors[] = gettext("Signed 8-bit integer type must be a number in the range -128 to 127.");
477
			} else if ($numberoption['type'] == 'signed integer 16' && (!is_numeric($numberoption_value) || $numberoption_value < -32768 || $numberoption_value > 32767)) {
478
				$input_errors[] = gettext("Signed 16-bit integer type must be a number in the range -32768 to 32767.");
479
			} else if ($numberoption['type'] == 'signed integer 32' && (!is_numeric($numberoption_value) || $numberoption_value < -2147483648 || $numberoption_value > 2147483647)) {
480
				$input_errors[] = gettext("Signed 32-bit integer type must be a number in the range -2147483648 to 2147483647.");
481
			} else if ($numberoption['type'] == 'ip-address' && !is_ipaddrv4($numberoption_value) && !is_hostname($numberoption_value)) {
482
				$input_errors[] = gettext("IP address or host type must be an IP address or host name.");
483
			}
484
		}
485
	}
486

    
487
	if ((!isset($pool) || !is_numeric($pool)) && $act != "newpool") {
488
		/* If enabling DHCP Server, make sure that the DHCP Relay isn't enabled on this interface */
489
		if ($_POST['enable'] && isset($config['dhcrelay']['enable']) &&
490
		    (stristr($config['dhcrelay']['interface'], $if) !== false)) {
491
			$input_errors[] = sprintf(gettext(
492
			    "The DHCP relay on the %s interface must be disabled before enabling the DHCP server."),
493
			    $iflist[$if]);
494
		}
495

    
496
		/* If disabling DHCP Server, make sure that DHCP registration isn't enabled for DNS forwarder/resolver */
497
		if (!$_POST['enable']) {
498
			/* Find out how many other interfaces have DHCP enabled. */
499
			$dhcp_enabled_count = 0;
500
			foreach ($config['dhcpd'] as $dhif => $dhcps) {
501
				if ($dhif == $if) {
502
					/* Skip this interface, we only want to know how many others are enabled. */
503
					continue;
504
				}
505
				if (isset($dhcps['enable'])) {
506
					$dhcp_enabled_count++;
507
				}
508
			}
509

    
510
			if (isset($config['dnsmasq']['enable']) &&
511
			    ($dhcp_enabled_count == 0) &&
512
			    (isset($config['dnsmasq']['regdhcp']) ||
513
			    isset($config['dnsmasq']['regdhcpstatic']) ||
514
			    isset($config['dnsmasq']['dhcpfirst']))) {
515
				$input_errors[] = gettext(
516
				    "DHCP Registration features in the DNS Forwarder are active and require at least one enabled DHCP Server.");
517
			}
518
			if (isset($config['unbound']['enable']) &&
519
			    ($dhcp_enabled_count == 0) &&
520
			    (isset($config['unbound']['regdhcp']) ||
521
			    isset($config['unbound']['regdhcpstatic']))) {
522
				$input_errors[] = gettext(
523
				    "DHCP Registration features in the DNS Resolver are active and require at least one enabled DHCP Server.");
524
			}
525
		}
526
	}
527

    
528
	// 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.
529
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
530
		/* make sure the range lies within the current subnet */
531
		if (ip_greater_than($_POST['range_from'], $_POST['range_to'])) {
532
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
533
		}
534

    
535
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
536
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
537
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
538
		}
539

    
540
		if (is_numeric($pool) || ($act == "newpool")) {
541
			if (is_inrange_v4($_POST['range_from'],
542
				$config['dhcpd'][$if]['range']['from'],
543
				$config['dhcpd'][$if]['range']['to']) ||
544
				is_inrange_v4($_POST['range_to'],
545
				$config['dhcpd'][$if]['range']['from'],
546
				$config['dhcpd'][$if]['range']['to'])) {
547
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
548
			}
549
		}
550

    
551
		foreach ($a_pools as $id => $p) {
552
			if (is_numeric($pool) && ($id == $pool)) {
553
				continue;
554
			}
555

    
556
			if (is_inrange_v4($_POST['range_from'],
557
				$p['range']['from'], $p['range']['to']) ||
558
				is_inrange_v4($_POST['range_to'],
559
				$p['range']['from'], $p['range']['to'])) {
560
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
561
				break;
562
			}
563
		}
564

    
565
		if (is_array($a_maps)) {
566
			foreach ($a_maps as $map) {
567
				if (empty($map['ipaddr'])) {
568
					continue;
569
				}
570
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
571
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
572
					break;
573
				}
574
			}
575
		}
576
	}
577

    
578
	if (!$input_errors) {
579
		if (!is_numeric($pool)) {
580
			if ($act == "newpool") {
581
				$dhcpdconf = array();
582
			} else {
583
				if (!is_array($config['dhcpd'])) {
584
					$config['dhcpd']= array();
585
				}
586
				if (!is_array($config['dhcpd'][$if])) {
587
					$config['dhcpd'][$if] = array();
588
				}
589
				$dhcpdconf = $config['dhcpd'][$if];
590
			}
591
		} else {
592
			if (is_array($a_pools[$pool])) {
593
				$dhcpdconf = $a_pools[$pool];
594
			} else {
595
				// Someone specified a pool but it doesn't exist. Punt.
596
				header("Location: services_dhcp.php");
597
				exit;
598
			}
599
		}
600
		if (!is_array($dhcpdconf)) {
601
			$dhcpdconf = array();
602
		}
603
		if (!is_array($dhcpdconf['range'])) {
604
			$dhcpdconf['range'] = array();
605
		}
606

    
607
		$dhcpd_enable_changed = false;
608

    
609
		// Global Options
610
		if (!is_numeric($pool) && !($act == "newpool")) {
611
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
612
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
613
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
614
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
615
				$dhcpd_enable_changed = true;
616
			}
617

    
618
			$dhcpdconf['enable'] = $new_dhcpd_enable;
619
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
620
			$previous = $dhcpdconf['failover_peerip'];
621
			if ($previous != $_POST['failover_peerip']) {
622
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
623
			}
624

    
625
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
626
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
627
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
628
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
629
			}
630
		} else {
631
			// Options that exist only in pools
632
			$dhcpdconf['descr'] = $_POST['descr'];
633
		}
634

    
635
		// Options that can be global or per-pool.
636
		$dhcpdconf['range']['from'] = $_POST['range_from'];
637
		$dhcpdconf['range']['to'] = $_POST['range_to'];
638
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
639
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
640
		$dhcpdconf['netmask'] = $_POST['netmask'];
641

    
642
		unset($dhcpdconf['winsserver']);
643
		if ($_POST['wins1']) {
644
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
645
		}
646
		if ($_POST['wins2']) {
647
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
648
		}
649

    
650
		unset($dhcpdconf['dnsserver']);
651
		if ($_POST['dns1']) {
652
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
653
		}
654
		if ($_POST['dns2']) {
655
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
656
		}
657
		if ($_POST['dns3']) {
658
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
659
		}
660
		if ($_POST['dns4']) {
661
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
662
		}
663

    
664
		$dhcpdconf['gateway'] = $_POST['gateway'];
665
		$dhcpdconf['domain'] = $_POST['domain'];
666
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
667
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
668

    
669
		if (in_array($_POST['denyunknown'], array("enabled", "class"))) {
670
			$dhcpdconf['denyunknown'] = $_POST['denyunknown'];
671
		} else {
672
			unset($dhcpdconf['denyunknown']);
673
		}
674

    
675
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
676
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
677
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
678
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
679
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
680
		$dhcpdconf['ddnsdomainkeyalgorithm'] = $_POST['ddnsdomainkeyalgorithm'];
681
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
682
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
683
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
684
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
685
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
686
		$dhcpdconf['ddnsclientupdates'] = $_POST['ddnsclientupdates'];
687

    
688
		unset($dhcpdconf['ntpserver']);
689
		if ($_POST['ntp1']) {
690
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
691
		}
692
		if ($_POST['ntp2']) {
693
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
694
		}
695

    
696
		$dhcpdconf['tftp'] = $_POST['tftp'];
697
		$dhcpdconf['ldap'] = $_POST['ldap'];
698
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
699
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
700
		$dhcpdconf['filename'] = $_POST['filename'];
701
		$dhcpdconf['filename32'] = $_POST['filename32'];
702
		$dhcpdconf['filename64'] = $_POST['filename64'];
703
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
704
		unset($dhcpdconf['statsgraph']);
705
		if ($_POST['statsgraph']) {
706
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
707
			enable_rrd_graphing();
708
		}
709
		unset($dhcpdconf['disablepingcheck']);
710
		if ($_POST['disablepingcheck']) {
711
			$dhcpdconf['disablepingcheck'] = $_POST['disablepingcheck'];
712
		}
713

    
714
		// Handle the custom options rowhelper
715
		if (isset($dhcpdconf['numberoptions']['item'])) {
716
			unset($dhcpdconf['numberoptions']['item']);
717
		}
718

    
719
		$dhcpdconf['numberoptions'] = $numberoptions;
720

    
721
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
722
			$a_pools[$pool] = $dhcpdconf;
723
		} elseif ($act == "newpool") {
724
			$a_pools[] = $dhcpdconf;
725
		} else {
726
			$config['dhcpd'][$if] = $dhcpdconf;
727
		}
728

    
729
		// OMAPI Settings
730
		if ($_POST['omapi_port'] == ""){
731
			unset($dhcpdconf['omapi_port']);
732
			unset($dhcpdconf['omapi_key']);
733
			unset($dhcpdconf['omapi_key_algorithm']);
734

    
735
			unset($pconfig['omapi_port']);
736
			unset($pconfig['omapi_key']);
737
			unset($pconfig['omapi_key_algorithm']);
738
		} else {
739
			$dhcpdconf['omapi_port'] = $_POST['omapi_port'];
740
			$dhcpdconf['omapi_key'] = $_POST['omapi_key'];
741
			$dhcpdconf['omapi_key_algorithm'] = $_POST['omapi_key_algorithm'];
742
		}
743

    
744
		write_config(gettext("DHCP Server - Settings changed for interface " . strtoupper($if)));
745
	}
746
}
747

    
748
if ((isset($_POST['save']) || isset($_POST['apply'])) && (!$input_errors)) {
749
	$changes_applied = true;
750
	$retval = 0;
751
	$retvaldhcp = 0;
752
	$retvaldns = 0;
753
	/* dnsmasq_configure calls dhcpd_configure */
754
	/* no need to restart dhcpd twice */
755
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
756
		$retvaldns |= services_dnsmasq_configure();
757
		if ($retvaldns == 0) {
758
			clear_subsystem_dirty('hosts');
759
			clear_subsystem_dirty('staticmaps');
760
		}
761
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
762
		$retvaldns |= services_unbound_configure();
763
		if ($retvaldns == 0) {
764
			clear_subsystem_dirty('unbound');
765
			clear_subsystem_dirty('hosts');
766
			clear_subsystem_dirty('staticmaps');
767
		}
768
	} else {
769
		$retvaldhcp |= services_dhcpd_configure();
770
		if ($retvaldhcp == 0) {
771
			clear_subsystem_dirty('staticmaps');
772
		}
773
	}
774
	/* BIND package - Bug #3710 */
775
	if (!function_exists('is_package_installed')) {
776
		require_once('pkg-utils.inc');
777
	}
778
	if (is_package_installed('pfSense-pkg-bind') && isset($config['installedpackages']['bind']['config'][0]['enable_bind'])) {
779
		$reloadbind = false;
780
		if (is_array($config['installedpackages']['bindzone'])) {
781
			$bindzone = $config['installedpackages']['bindzone']['config'];
782
		} else {
783
			$bindzone = array();
784
		}
785
		for ($x = 0; $x < sizeof($bindzone); $x++) {
786
			$zone = $bindzone[$x];
787
			if ($zone['regdhcpstatic'] == 'on') {
788
				$reloadbind = true;
789
				break;
790
			}
791
		}
792
		if ($reloadbind === true) {
793
			if (file_exists("/usr/local/pkg/bind.inc")) {
794
				require_once("/usr/local/pkg/bind.inc");
795
				bind_sync();
796
			}
797
		}
798
	}
799
	if ($dhcpd_enable_changed) {
800
		$retvalfc |= filter_configure();
801
	}
802

    
803
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
804
		$retval = 1;
805
	}
806
}
807

    
808
if ($act == "delpool") {
809
	if ($a_pools[$_POST['id']]) {
810
		unset($a_pools[$_POST['id']]);
811
		write_config();
812
		header("Location: services_dhcp.php?if={$if}");
813
		exit;
814
	}
815
}
816

    
817
if ($act == "del") {
818
	if (isset($a_maps[$_POST['id']])) {
819
		/* Remove static ARP entry, if necessary */
820
		if (isset($a_maps[$_POST['id']]['arp_table_static_entry'])) {
821
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_POST['id']]['ipaddr']));
822
		}
823
		unset($a_maps[$_POST['id']]);
824
		write_config();
825
		if (isset($config['dhcpd'][$if]['enable'])) {
826
			mark_subsystem_dirty('staticmaps');
827
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
828
				mark_subsystem_dirty('hosts');
829
			}
830
		}
831

    
832
		header("Location: services_dhcp.php?if={$if}");
833
		exit;
834
	}
835
}
836

    
837
// Build an HTML table that can be inserted into a Form_StaticText element
838
function build_pooltable() {
839
	global $a_pools, $if;
840

    
841
	$pooltbl =	'<div class="table-responsive">';
842
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
843
	$pooltbl .=			'<thead>';
844
	$pooltbl .=				'<tr>';
845
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
846
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
847
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
848
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
849
	$pooltbl .=				'</tr>';
850
	$pooltbl .=			'</thead>';
851
	$pooltbl .=			'<tbody>';
852

    
853
	if (is_array($a_pools)) {
854
		$i = 0;
855
		foreach ($a_pools as $poolent) {
856
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
857
				$pooltbl .= '<tr>';
858
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
859
							htmlspecialchars($poolent['range']['from']) . '</td>';
860

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

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

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

    
869
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" usepost></a></td>';
870
				$pooltbl .= '</tr>';
871
			}
872
		$i++;
873
		}
874
	}
875

    
876
	$pooltbl .=			'</tbody>';
877
	$pooltbl .=		'</table>';
878
	$pooltbl .= '</div>';
879

    
880
	return($pooltbl);
881
}
882

    
883
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
884
$pglinks = array("", "services_dhcp.php");
885

    
886
if (!empty($if) && isset($iflist[$if])) {
887
	$pgtitle[] = $iflist[$if];
888
	$pglinks[] = "@self";
889
}
890
$shortcut_section = "dhcp";
891

    
892
include("head.inc");
893

    
894
if ($input_errors) {
895
	print_input_errors($input_errors);
896
}
897

    
898
if ($changes_applied) {
899
	print_apply_result_box($retval);
900
}
901

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

    
906
/* active tabs */
907
$tab_array = array();
908
$tabscounter = 0;
909
$i = 0;
910
$have_small_subnet = false;
911

    
912
foreach ($iflist as $ifent => $ifname) {
913
	$oc = $config['interfaces'][$ifent];
914

    
915
	/* Not static IPv4 or subnet >= 31 */
916
	if ($oc['subnet'] >= 31) {
917
		$have_small_subnet = true;
918
		$example_name = $ifname;
919
		$example_cidr = $oc['subnet'];
920
		continue;
921
	}
922
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
923
		continue;
924
	}
925

    
926
	if ($ifent == $if) {
927
		$active = true;
928
	} else {
929
		$active = false;
930
	}
931

    
932
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
933
	$tabscounter++;
934
}
935

    
936
if ($tabscounter == 0) {
937
	if ($have_small_subnet) {
938
		$sentence2 = sprintf(gettext('%1$s has a CIDR mask of %2$s, which does not contain enough addresses.'), htmlspecialchars($example_name), htmlspecialchars($example_cidr));
939
	} else {
940
		$sentence2 = gettext("This system has no interfaces configured with a static IPv4 address.");
941
	}
942
	print_info_box(gettext("The DHCP Server requires a static IPv4 subnet large enough to serve addresses to clients.") . " " . $sentence2);
943
	include("foot.inc");
944
	exit;
945
}
946

    
947
display_top_tabs($tab_array);
948

    
949
$form = new Form();
950

    
951
$section = new Form_Section('General Options');
952

    
953
if (!is_numeric($pool) && !($act == "newpool")) {
954
	if (isset($config['dhcrelay']['enable'])) {
955
		$section->addInput(new Form_Checkbox(
956
			'enable',
957
			'Enable',
958
			gettext("DHCP Relay is currently enabled. DHCP Server canot be enabled while the DHCP Relay is enabled on any interface."),
959
			$pconfig['enable']
960
		))->setAttribute('disabled', true);
961
	} else {
962
		$section->addInput(new Form_Checkbox(
963
			'enable',
964
			'Enable',
965
			sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
966
			$pconfig['enable']
967
		));
968
	}
969
} else {
970
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
971
}
972

    
973
$section->addInput(new Form_Checkbox(
974
	'ignorebootp',
975
	'BOOTP',
976
	'Ignore BOOTP queries',
977
	$pconfig['ignorebootp']
978
));
979

    
980
$section->addInput(new Form_Select(
981
	'denyunknown',
982
	'Deny unknown clients',
983
	$pconfig['denyunknown'],
984
	array(
985
		"disabled" => "Allow all clients",
986
		"enabled" => "Allow known clients from any interface",
987
		"class" => "Allow known clients from only this interface",
988
	)
989
))->setHelp('When set to %3$sAllow all clients%4$s, any DHCP client will get an IP address within this scope/range on this interface. '.
990
	'If set to %3$sAllow known clients from any interface%4$s, any DHCP client with a MAC address listed on %1$s%3$sany%4$s%2$s scope(s)/interface(s) will get an IP address. ' .
991
	'If set to %3$sAllow known clients from only this interface%4$s, only MAC addresses listed below (i.e. for this interface) will get an IP address within this scope/range.',
992
	'<i>', '</i>', '<b>', '</b>');
993

    
994
$section->addInput(new Form_Checkbox(
995
	'nonak',
996
	'Ignore denied clients',
997
	'Denied clients will be ignored rather than rejected.',
998
	$pconfig['nonak']
999
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
1000

    
1001
$section->addInput(new Form_Checkbox(
1002
	'ignoreclientuids',
1003
	'Ignore client identifiers',
1004
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
1005
	$pconfig['ignoreclientuids']
1006
))->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.");
1007

    
1008

    
1009
if (is_numeric($pool) || ($act == "newpool")) {
1010
	$section->addInput(new Form_Input(
1011
		'descr',
1012
		'Pool Description',
1013
		'text',
1014
		$pconfig['descr']
1015
	));
1016
}
1017

    
1018
$section->addInput(new Form_StaticText(
1019
	'Subnet',
1020
	gen_subnet($ifcfgip, $ifcfgsn)
1021
));
1022

    
1023
$section->addInput(new Form_StaticText(
1024
	'Subnet mask',
1025
	gen_subnet_mask($ifcfgsn)
1026
));
1027

    
1028
// Compose a string to display the required address ranges
1029
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
1030

    
1031
if (is_numeric($pool) || ($act == "newpool")) {
1032
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
1033
	if (is_array($config['dhcpd'][$if]['range'])) {
1034
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
1035
	}
1036

    
1037
	foreach ($a_pools as $p) {
1038
		if (is_array($p['range'])) {
1039
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
1040
		}
1041
	}
1042
}
1043

    
1044
$section->addInput(new Form_StaticText(
1045
	'Available range',
1046
	$rangestr
1047
));
1048

    
1049
$group = new Form_Group('*Range');
1050

    
1051
$group->add(new Form_IpAddress(
1052
	'range_from',
1053
	null,
1054
	$pconfig['range_from'],
1055
	'V4'
1056
))->setHelp('From');
1057

    
1058
$group->add(new Form_IpAddress(
1059
	'range_to',
1060
	null,
1061
	$pconfig['range_to'],
1062
	'V4'
1063
))->setHelp('To');
1064

    
1065
$section->add($group);
1066

    
1067
$form->add($section);
1068

    
1069
if (!is_numeric($pool) && !($act == "newpool")) {
1070
	$section = new Form_Section('Additional Pools');
1071

    
1072
	$btnaddpool = new Form_Button(
1073
		'btnaddpool',
1074
		'Add pool',
1075
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
1076
		'fa-plus'
1077
	);
1078
	$btnaddpool->addClass('btn-success');
1079

    
1080
	$section->addInput(new Form_StaticText(
1081
		'Add',
1082
		$btnaddpool
1083
	))->setHelp('If additional pools of addresses are needed inside of this subnet outside the above Range, they may be specified here.');
1084

    
1085
	if (is_array($a_pools)) {
1086
		$section->addInput(new Form_StaticText(
1087
			null,
1088
			build_pooltable()
1089
		));
1090
	}
1091

    
1092
	$form->add($section);
1093
}
1094

    
1095
$section = new Form_Section('Servers');
1096

    
1097
$section->addInput(new Form_IpAddress(
1098
	'wins1',
1099
	'WINS servers',
1100
	$pconfig['wins1'],
1101
	'V4'
1102
))->setAttribute('placeholder', 'WINS Server 1');
1103

    
1104
$section->addInput(new Form_IpAddress(
1105
	'wins2',
1106
	null,
1107
	$pconfig['wins2'],
1108
	'V4'
1109
))->setAttribute('placeholder', 'WINS Server 2');
1110

    
1111
for ($idx=1; $idx<=4; $idx++) {
1112
	$section->addInput(new Form_IpAddress(
1113
		'dns' . $idx,
1114
		($idx == 1) ? 'DNS servers':null,
1115
		$pconfig['dns' . $idx],
1116
		'V4'
1117
	))->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.':'');
1118
}
1119

    
1120
$form->add($section);
1121

    
1122
//OMAPI
1123
$section = new Form_Section('OMAPI');
1124

    
1125
$section->addInput(new Form_Input(
1126
	'omapi_port',
1127
	'OMAPI Port',
1128
	'text',
1129
	$pconfig['omapi_port']
1130
))->setAttribute('placeholder', 'OMAPI Port')
1131
  ->setHelp('Set the port that OMAPI will listen on. The default port is 7911, leave blank to disable.');
1132

    
1133
$group = new Form_Group('OMAPI Key');
1134

    
1135
$group->add(new Form_Input(
1136
	'omapi_key',
1137
	'OMAPI Key',
1138
	'text',
1139
	$pconfig['omapi_key']
1140
))->setAttribute('placeholder', 'OMAPI Key')
1141
  ->setHelp('Enter a key matching the selected algorithm<br />to secure connections to the OMAPI endpoint.');
1142

    
1143
$group->add(new Form_Checkbox(
1144
	'omapi_gen_key',
1145
	'',
1146
	'Generate New Key',
1147
	$pconfig['omapi_gen_key']
1148
))->setHelp('Generate a new key based<br />on the selected algorithm.');
1149

    
1150
$section->add($group);
1151

    
1152
$section->addInput(new Form_Select(
1153
	'omapi_key_algorithm',
1154
	'Key Algorithm',
1155
	empty($pconfig['omapi_key_algorithm']) ? 'hmac-sha256' : $pconfig['omapi_key_algorithm'], // Set the default algorithm if not previous defined
1156
	array(
1157
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1158
		'hmac-sha1' => 'HMAC-SHA1',
1159
		'hmac-sha224' => 'HMAC-SHA224',
1160
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1161
		'hmac-sha384' => 'HMAC-SHA384',
1162
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1163
	)
1164
))->setHelp('Set the algorithm that OMAPI key will use.');
1165

    
1166
$form->add($section);
1167

    
1168
$section = new Form_Section('Other Options');
1169

    
1170
$section->addInput(new Form_IpAddress(
1171
	'gateway',
1172
	'Gateway',
1173
	$pconfig['gateway'],
1174
	'V4'
1175
))->setPattern('[.a-zA-Z0-9_]+')
1176
  ->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.');
1177

    
1178
$section->addInput(new Form_Input(
1179
	'domain',
1180
	'Domain name',
1181
	'text',
1182
	$pconfig['domain']
1183
))->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.');
1184

    
1185
$section->addInput(new Form_Input(
1186
	'domainsearchlist',
1187
	'Domain search list',
1188
	'text',
1189
	$pconfig['domainsearchlist']
1190
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
1191

    
1192
$section->addInput(new Form_Input(
1193
	'deftime',
1194
	'Default lease time',
1195
	'number',
1196
	$pconfig['deftime']
1197
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds.');
1198

    
1199
$section->addInput(new Form_Input(
1200
	'maxtime',
1201
	'Maximum lease time',
1202
	'number',
1203
	$pconfig['maxtime']
1204
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds.');
1205

    
1206
if (!is_numeric($pool) && !($act == "newpool")) {
1207
	$section->addInput(new Form_IpAddress(
1208
		'failover_peerip',
1209
		'Failover peer IP',
1210
		$pconfig['failover_peerip'],
1211
		'V4'
1212
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
1213
				'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).');
1214

    
1215
	$section->addInput(new Form_Checkbox(
1216
		'staticarp',
1217
		'Static ARP',
1218
		'Enable Static ARP entries',
1219
		$pconfig['staticarp']
1220
	))->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.');
1221

    
1222
	$section->addInput(new Form_Checkbox(
1223
		'dhcpleaseinlocaltime',
1224
		'Time format change',
1225
		'Change DHCP display lease time from UTC to local time',
1226
		$pconfig['dhcpleaseinlocaltime']
1227
	))->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.' .
1228
				' This will be used for all DHCP interfaces lease time.');
1229

    
1230
	$section->addInput(new Form_Checkbox(
1231
		'statsgraph',
1232
		'Statistics graphs',
1233
		'Enable RRD statistics graphs',
1234
		$pconfig['statsgraph']
1235
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1236

    
1237
	$section->addInput(new Form_Checkbox(
1238
		'disablepingcheck',
1239
		'Ping check',
1240
		'Disable ping check',
1241
		$pconfig['disablepingcheck']
1242
	))->setHelp('When enabled dhcpd sends a ping to the address being assigned, and if no response has been heard, it assigns the address. Enabled by default.');
1243
}
1244

    
1245
// DDNS
1246
$btnadv = new Form_Button(
1247
	'btnadvdns',
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
	'Dynamic DNS',
1257
	$btnadv
1258
));
1259

    
1260
$section->addInput(new Form_Checkbox(
1261
	'ddnsupdate',
1262
	null,
1263
	'Enable registration of DHCP client names in DNS',
1264
	$pconfig['ddnsupdate']
1265
));
1266

    
1267
$section->addInput(new Form_Input(
1268
	'ddnsdomain',
1269
	'DDNS Domain',
1270
	'text',
1271
	$pconfig['ddnsdomain']
1272
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1273

    
1274
$section->addInput(new Form_Checkbox(
1275
	'ddnsforcehostname',
1276
	'DDNS Hostnames',
1277
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1278
	$pconfig['ddnsforcehostname']
1279
))->setHelp('Default registers host name option supplied by DHCP client.');
1280

    
1281
$section->addInput(new Form_IpAddress(
1282
	'ddnsdomainprimary',
1283
	'Primary DDNS address',
1284
	$pconfig['ddnsdomainprimary'],
1285
	'V4'
1286
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1287

    
1288
$section->addInput(new Form_Input(
1289
	'ddnsdomainkeyname',
1290
	'DNS Domain key',
1291
	'text',
1292
	$pconfig['ddnsdomainkeyname']
1293
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1294

    
1295
$section->addInput(new Form_Select(
1296
	'ddnsdomainkeyalgorithm',
1297
	'Key algorithm',
1298
	$pconfig['ddnsdomainkeyalgorithm'],
1299
	array(
1300
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1301
		'hmac-sha1' => 'HMAC-SHA1',
1302
		'hmac-sha224' => 'HMAC-SHA224',
1303
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1304
		'hmac-sha384' => 'HMAC-SHA384',
1305
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1306
	)
1307
));
1308

    
1309
$section->addInput(new Form_Input(
1310
	'ddnsdomainkey',
1311
	'DNS Domain key secret',
1312
	'text',
1313
	$pconfig['ddnsdomainkey']
1314
))->setHelp('Dynamic DNS domain key secret which will be used to register client names in the DNS server.');
1315

    
1316
$section->addInput(new Form_Select(
1317
	'ddnsclientupdates',
1318
	'DDNS Client Updates',
1319
	$pconfig['ddnsclientupdates'],
1320
	array(
1321
	    'allow' => gettext('Allow'),
1322
	    'deny' => gettext('Deny'),
1323
	    'ignore' => gettext('Ignore'))
1324
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
1325
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
1326
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
1327
	    'update and the client can also attempt the update usually using a different domain name.');
1328

    
1329
// Advanced MAC
1330
$btnadv = new Form_Button(
1331
	'btnadvmac',
1332
	'Display Advanced',
1333
	null,
1334
	'fa-cog'
1335
);
1336

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

    
1339
$section->addInput(new Form_StaticText(
1340
	'MAC address control',
1341
	$btnadv
1342
));
1343

    
1344
$section->addInput(new Form_Input(
1345
	'mac_allow',
1346
	'MAC Allow',
1347
	'text',
1348
	$pconfig['mac_allow']
1349
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1350

    
1351
$section->addInput(new Form_Input(
1352
	'mac_deny',
1353
	'MAC Deny',
1354
	'text',
1355
	$pconfig['mac_deny']
1356
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1357

    
1358
// Advanced NTP
1359
$btnadv = new Form_Button(
1360
	'btnadvntp',
1361
	'Display Advanced',
1362
	null,
1363
	'fa-cog'
1364
);
1365

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

    
1368
$section->addInput(new Form_StaticText(
1369
	'NTP',
1370
	$btnadv
1371
));
1372

    
1373
$section->addInput(new Form_IpAddress(
1374
	'ntp1',
1375
	'NTP Server 1',
1376
	$pconfig['ntp1'],
1377
	'HOSTV4'
1378
));
1379

    
1380
$section->addInput(new Form_IpAddress(
1381
	'ntp2',
1382
	'NTP Server 2',
1383
	$pconfig['ntp2'],
1384
	'HOSTV4'
1385
));
1386

    
1387
// Advanced TFTP
1388
$btnadv = new Form_Button(
1389
	'btnadvtftp',
1390
	'Display Advanced',
1391
	null,
1392
	'fa-cog'
1393
);
1394

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

    
1397
$section->addInput(new Form_StaticText(
1398
	'TFTP',
1399
	$btnadv
1400
));
1401

    
1402
$section->addInput(new Form_Input(
1403
	'tftp',
1404
	'TFTP Server',
1405
	'text',
1406
	$pconfig['tftp']
1407
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1408

    
1409
// Advanced LDAP
1410
$btnadv = new Form_Button(
1411
	'btnadvldap',
1412
	'Display Advanced',
1413
	null,
1414
	'fa-cog'
1415
);
1416

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

    
1419
$section->addInput(new Form_StaticText(
1420
	'LDAP',
1421
	$btnadv
1422
));
1423

    
1424
$section->addInput(new Form_Input(
1425
	'ldap',
1426
	'LDAP Server URI',
1427
	'text',
1428
	$pconfig['ldap']
1429
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1430

    
1431
// Advanced Network Booting options
1432
$btnadv = new Form_Button(
1433
	'btnadvnwkboot',
1434
	'Display Advanced',
1435
	null,
1436
	'fa-cog'
1437
);
1438

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

    
1441
$section->addInput(new Form_StaticText(
1442
	'Network Booting',
1443
	$btnadv
1444
));
1445

    
1446
$section->addInput(new Form_Checkbox(
1447
	'netboot',
1448
	'Enable',
1449
	'Enables network booting',
1450
	$pconfig['netboot']
1451
));
1452

    
1453
$section->addInput(new Form_IpAddress(
1454
	'nextserver',
1455
	'Next Server',
1456
	$pconfig['nextserver'],
1457
	'V4'
1458
))->setHelp('Enter the IP address of the next server');
1459

    
1460
$section->addInput(new Form_Input(
1461
	'filename',
1462
	'Default BIOS file name',
1463
	'text',
1464
	$pconfig['filename']
1465
));
1466

    
1467
$section->addInput(new Form_Input(
1468
	'filename32',
1469
	'UEFI 32 bit file name',
1470
	'text',
1471
	$pconfig['filename32']
1472
));
1473

    
1474
$section->addInput(new Form_Input(
1475
	'filename64',
1476
	'UEFI 64 bit file name',
1477
	'text',
1478
	$pconfig['filename64']
1479
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1480
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1481

    
1482
$section->addInput(new Form_Input(
1483
	'rootpath',
1484
	'Root path',
1485
	'text',
1486
	$pconfig['rootpath']
1487
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1488

    
1489
// Advanced Additional options
1490
$btnadv = new Form_Button(
1491
	'btnadvopts',
1492
	'Display Advanced',
1493
	null,
1494
	'fa-cog'
1495
);
1496

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

    
1499
$section->addInput(new Form_StaticText(
1500
	'Additional BOOTP/DHCP Options',
1501
	$btnadv
1502
));
1503

    
1504
$form->add($section);
1505

    
1506
$section = new Form_Section('Additional BOOTP/DHCP Options');
1507
$section->addClass('adnlopts');
1508

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

    
1515
if (!$pconfig['numberoptions']) {
1516
	$pconfig['numberoptions'] = array();
1517
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1518
}
1519

    
1520
$customitemtypes = array(
1521
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1522
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1523
	'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')
1524
);
1525

    
1526
$numrows = count($item) -1;
1527
$counter = 0;
1528

    
1529
$numrows = count($pconfig['numberoptions']['item']) -1;
1530

    
1531
foreach ($pconfig['numberoptions']['item'] as $item) {
1532
	$number = $item['number'];
1533
	$itemtype = $item['type'];
1534
	$value = base64_decode($item['value']);
1535

    
1536
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1537
	$group->addClass('repeatable');
1538

    
1539
	$group->add(new Form_Input(
1540
		'number' . $counter,
1541
		null,
1542
		'number',
1543
		$number,
1544
		['min'=>'1', 'max'=>'254']
1545
	))->setHelp($numrows == $counter ? 'Number':null);
1546

    
1547

    
1548
	$group->add(new Form_Select(
1549
		'itemtype' . $counter,
1550
		null,
1551
		$itemtype,
1552
		$customitemtypes
1553
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1554

    
1555
	$group->add(new Form_Input(
1556
		'value' . $counter,
1557
		null,
1558
		'text',
1559
		$value
1560
	))->setHelp($numrows == $counter ? 'Value':null);
1561

    
1562
	$group->add(new Form_Button(
1563
		'deleterow' . $counter,
1564
		'Delete',
1565
		null,
1566
		'fa-trash'
1567
	))->addClass('btn-warning');
1568

    
1569
	$section->add($group);
1570

    
1571
	$counter++;
1572
}
1573

    
1574
$section->addInput(new Form_Button(
1575
	'addrow',
1576
	'Add',
1577
	null,
1578
	'fa-plus'
1579
))->addClass('btn-success');
1580

    
1581
$form->add($section);
1582

    
1583
if ($act == "newpool") {
1584
	$form->addGlobal(new Form_Input(
1585
		'act',
1586
		null,
1587
		'hidden',
1588
		'newpool'
1589
	));
1590
}
1591

    
1592
if (is_numeric($pool)) {
1593
	$form->addGlobal(new Form_Input(
1594
		'pool',
1595
		null,
1596
		'hidden',
1597
		$pool
1598
	));
1599
}
1600

    
1601
$form->addGlobal(new Form_Input(
1602
	'if',
1603
	null,
1604
	'hidden',
1605
	$if
1606
));
1607

    
1608
print($form);
1609

    
1610
// DHCP Static Mappings table
1611

    
1612
if (!is_numeric($pool) && !($act == "newpool")) {
1613

    
1614
	// Decide whether display of the Client Id column is needed.
1615
	$got_cid = false;
1616
	if (is_array($a_maps)) {
1617
		foreach ($a_maps as $map) {
1618
			if (!empty($map['cid'])) {
1619
				$got_cid = true;
1620
				break;
1621
			}
1622
		}
1623
	}
1624
?>
1625

    
1626
<div class="panel panel-default">
1627
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1628
	<div class="table-responsive">
1629
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1630
				<thead>
1631
					<tr>
1632
						<th><?=gettext("Static ARP")?></th>
1633
						<th><?=gettext("MAC address")?></th>
1634
<?php
1635
	if ($got_cid):
1636
?>
1637
						<th><?=gettext("Client Id")?></th>
1638
<?php
1639
	endif;
1640
?>
1641
						<th><?=gettext("IP address")?></th>
1642
						<th><?=gettext("Hostname")?></th>
1643
						<th><?=gettext("Description")?></th>
1644
						<th></th>
1645
					</tr>
1646
				</thead>
1647
<?php
1648
	if (is_array($a_maps)) {
1649
		$i = 0;
1650
?>
1651
				<tbody>
1652
<?php
1653
		foreach ($a_maps as $mapent) {
1654
?>
1655
					<tr>
1656
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1657
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1658
								<i class="fa fa-check"></i>
1659
							<?php endif; ?>
1660
						</td>
1661
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1662
							<?=htmlspecialchars($mapent['mac'])?>
1663
						</td>
1664
<?php
1665
			if ($got_cid):
1666
?>
1667
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1668
							<?=htmlspecialchars($mapent['cid'])?>
1669
						</td>
1670
<?php
1671
			endif;
1672
?>
1673
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1674
							<?=htmlspecialchars($mapent['ipaddr'])?>
1675
						</td>
1676
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1677
							<?=htmlspecialchars($mapent['hostname'])?>
1678
						</td>
1679
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1680
							<?=htmlspecialchars($mapent['descr'])?>
1681
						</td>
1682
						<td>
1683
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1684
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
1685
						</td>
1686
					</tr>
1687
<?php
1688
		$i++;
1689
		}
1690
?>
1691
				</tbody>
1692
<?php
1693
	}
1694
?>
1695
		</table>
1696
	</div>
1697
</div>
1698

    
1699
<nav class="action-buttons">
1700
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1701
		<i class="fa fa-plus icon-embed-btn"></i>
1702
		<?=gettext("Add")?>
1703
	</a>
1704
</nav>
1705
<?php
1706
}
1707
?>
1708

    
1709
<script type="text/javascript">
1710
//<![CDATA[
1711
events.push(function() {
1712

    
1713
	// Show advanced DNS options ======================================================================================
1714
	var showadvdns = false;
1715

    
1716
	function show_advdns(ispageload) {
1717
		var text;
1718
		// On page load decide the initial state based on the data.
1719
		if (ispageload) {
1720
<?php
1721
			if (!$pconfig['ddnsupdate'] &&
1722
				!$pconfig['ddnsforcehostname'] &&
1723
				empty($pconfig['ddnsdomain']) &&
1724
				empty($pconfig['ddnsdomainprimary']) &&
1725
			    empty($pconfig['ddnsdomainkeyname']) &&
1726
			    (empty($pconfig['ddnsdomainkeyalgorithm']) || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1727
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1728
			    empty($pconfig['ddnsdomainkey'])) {
1729
				$showadv = false;
1730
			} else {
1731
				$showadv = true;
1732
			}
1733
?>
1734
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1735
		} else {
1736
			// It was a click, swap the state.
1737
			showadvdns = !showadvdns;
1738
		}
1739

    
1740
		hideCheckbox('ddnsupdate', !showadvdns);
1741
		hideInput('ddnsdomain', !showadvdns);
1742
		hideCheckbox('ddnsforcehostname', !showadvdns);
1743
		hideInput('ddnsdomainprimary', !showadvdns);
1744
		hideInput('ddnsdomainkeyname', !showadvdns);
1745
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1746
		hideInput('ddnsdomainkey', !showadvdns);
1747
		hideInput('ddnsclientupdates', !showadvdns);
1748

    
1749
		if (showadvdns) {
1750
			text = "<?=gettext('Hide Advanced');?>";
1751
		} else {
1752
			text = "<?=gettext('Display Advanced');?>";
1753
		}
1754
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1755
	}
1756

    
1757
	$('#btnadvdns').click(function(event) {
1758
		show_advdns();
1759
	});
1760

    
1761
	// Show advanced MAC options ======================================================================================
1762
	var showadvmac = false;
1763

    
1764
	function show_advmac(ispageload) {
1765
		var text;
1766
		// On page load decide the initial state based on the data.
1767
		if (ispageload) {
1768
<?php
1769
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1770
				$showadv = false;
1771
			} else {
1772
				$showadv = true;
1773
			}
1774
?>
1775
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1776
		} else {
1777
			// It was a click, swap the state.
1778
			showadvmac = !showadvmac;
1779
		}
1780

    
1781
		hideInput('mac_allow', !showadvmac);
1782
		hideInput('mac_deny', !showadvmac);
1783

    
1784
		if (showadvmac) {
1785
			text = "<?=gettext('Hide Advanced');?>";
1786
		} else {
1787
			text = "<?=gettext('Display Advanced');?>";
1788
		}
1789
		$('#btnadvmac').html('<i class="fa fa-cog"></i> ' + text);
1790
	}
1791

    
1792
	$('#btnadvmac').click(function(event) {
1793
		show_advmac();
1794
	});
1795

    
1796
	// Show advanced NTP options ======================================================================================
1797
	var showadvntp = false;
1798

    
1799
	function show_advntp(ispageload) {
1800
		var text;
1801
		// On page load decide the initial state based on the data.
1802
		if (ispageload) {
1803
<?php
1804
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1805
				$showadv = false;
1806
			} else {
1807
				$showadv = true;
1808
			}
1809
?>
1810
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1811
		} else {
1812
			// It was a click, swap the state.
1813
			showadvntp = !showadvntp;
1814
		}
1815

    
1816
		hideInput('ntp1', !showadvntp);
1817
		hideInput('ntp2', !showadvntp);
1818

    
1819
		if (showadvntp) {
1820
			text = "<?=gettext('Hide Advanced');?>";
1821
		} else {
1822
			text = "<?=gettext('Display Advanced');?>";
1823
		}
1824
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1825
	}
1826

    
1827
	$('#btnadvntp').click(function(event) {
1828
		show_advntp();
1829
	});
1830

    
1831
	// Show advanced TFTP options ======================================================================================
1832
	var showadvtftp = false;
1833

    
1834
	function show_advtftp(ispageload) {
1835
		var text;
1836
		// On page load decide the initial state based on the data.
1837
		if (ispageload) {
1838
<?php
1839
			if (empty($pconfig['tftp'])) {
1840
				$showadv = false;
1841
			} else {
1842
				$showadv = true;
1843
			}
1844
?>
1845
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1846
		} else {
1847
			// It was a click, swap the state.
1848
			showadvtftp = !showadvtftp;
1849
		}
1850

    
1851
		hideInput('tftp', !showadvtftp);
1852

    
1853
		if (showadvtftp) {
1854
			text = "<?=gettext('Hide Advanced');?>";
1855
		} else {
1856
			text = "<?=gettext('Display Advanced');?>";
1857
		}
1858
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1859
	}
1860

    
1861
	$('#btnadvtftp').click(function(event) {
1862
		show_advtftp();
1863
	});
1864

    
1865
	// Show advanced LDAP options ======================================================================================
1866
	var showadvldap = false;
1867

    
1868
	function show_advldap(ispageload) {
1869
		var text;
1870
		// On page load decide the initial state based on the data.
1871
		if (ispageload) {
1872
<?php
1873
			if (empty($pconfig['ldap'])) {
1874
				$showadv = false;
1875
			} else {
1876
				$showadv = true;
1877
			}
1878
?>
1879
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1880
		} else {
1881
			// It was a click, swap the state.
1882
			showadvldap = !showadvldap;
1883
		}
1884

    
1885
		hideInput('ldap', !showadvldap);
1886

    
1887
		if (showadvldap) {
1888
			text = "<?=gettext('Hide Advanced');?>";
1889
		} else {
1890
			text = "<?=gettext('Display Advanced');?>";
1891
		}
1892
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1893
	}
1894

    
1895
	$('#btnadvldap').click(function(event) {
1896
		show_advldap();
1897
	});
1898

    
1899
	// Show advanced additional opts options ===========================================================================
1900
	var showadvopts = false;
1901

    
1902
	function show_advopts(ispageload) {
1903
		var text;
1904
		// On page load decide the initial state based on the data.
1905
		if (ispageload) {
1906
<?php
1907
			if (empty($pconfig['numberoptions']) ||
1908
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1909
				$showadv = false;
1910
			} else {
1911
				$showadv = true;
1912
			}
1913
?>
1914
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1915
		} else {
1916
			// It was a click, swap the state.
1917
			showadvopts = !showadvopts;
1918
		}
1919

    
1920
		hideClass('adnlopts', !showadvopts);
1921

    
1922
		if (showadvopts) {
1923
			text = "<?=gettext('Hide Advanced');?>";
1924
		} else {
1925
			text = "<?=gettext('Display Advanced');?>";
1926
		}
1927
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1928
	}
1929

    
1930
	$('#btnadvopts').click(function(event) {
1931
		show_advopts();
1932
	});
1933

    
1934
	// Show advanced Network Booting options ===========================================================================
1935
	var showadvnwkboot = false;
1936

    
1937
	function show_advnwkboot(ispageload) {
1938
		var text;
1939
		// On page load decide the initial state based on the data.
1940
		if (ispageload) {
1941
<?php
1942
			if (empty($pconfig['netboot'])) {
1943
				$showadv = false;
1944
			} else {
1945
				$showadv = true;
1946
			}
1947
?>
1948
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1949
		} else {
1950
			// It was a click, swap the state.
1951
			showadvnwkboot = !showadvnwkboot;
1952
		}
1953

    
1954
		hideCheckbox('netboot', !showadvnwkboot);
1955
		hideInput('nextserver', !showadvnwkboot);
1956
		hideInput('filename', !showadvnwkboot);
1957
		hideInput('filename32', !showadvnwkboot);
1958
		hideInput('filename64', !showadvnwkboot);
1959
		hideInput('rootpath', !showadvnwkboot);
1960

    
1961
		if (showadvnwkboot) {
1962
			text = "<?=gettext('Hide Advanced');?>";
1963
		} else {
1964
			text = "<?=gettext('Display Advanced');?>";
1965
		}
1966
		$('#btnadvnwkboot').html('<i class="fa fa-cog"></i> ' + text);
1967
	}
1968

    
1969
	$('#btnadvnwkboot').click(function(event) {
1970
		show_advnwkboot();
1971
	});
1972

    
1973
	// ---------- On initial page load ------------------------------------------------------------
1974

    
1975
	show_advdns(true);
1976
	show_advmac(true);
1977
	show_advntp(true);
1978
	show_advtftp(true);
1979
	show_advldap(true);
1980
	show_advopts(true);
1981
	show_advnwkboot(true);
1982

    
1983
	// Suppress "Delete row" button if there are fewer than two rows
1984
	checkLastRow();
1985
});
1986
//]]>
1987
</script>
1988

    
1989
<?php include("foot.inc");
(118-118/227)