Project

General

Profile

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

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

    
35
require_once("guiconfig.inc");
36
require_once("filter.inc");
37
require_once('rrd.inc');
38
require_once("shaper.inc");
39
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
	$pconfig['denyunknown'] = isset($dhcpdconf['denyunknown']);
167
	$pconfig['ignoreclientuids'] = isset($dhcpdconf['ignoreclientuids']);
168
	$pconfig['nonak'] = isset($dhcpdconf['nonak']);
169
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
170
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
171
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
172
	$pconfig['ddnsdomainkeyalgorithm'] = $dhcpdconf['ddnsdomainkeyalgorithm'];
173
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
174
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
175
	$pconfig['ddnsforcehostname'] = isset($dhcpdconf['ddnsforcehostname']);
176
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
177
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
178
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
179
	$pconfig['tftp'] = $dhcpdconf['tftp'];
180
	$pconfig['ldap'] = $dhcpdconf['ldap'];
181
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
182
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
183
	$pconfig['filename'] = $dhcpdconf['filename'];
184
	$pconfig['filename32'] = $dhcpdconf['filename32'];
185
	$pconfig['filename64'] = $dhcpdconf['filename64'];
186
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
187
	$pconfig['netmask'] = $dhcpdconf['netmask'];
188
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
189
	$pconfig['statsgraph'] = $dhcpdconf['statsgraph'];
190
	$pconfig['disablepingcheck'] = $dhcpdconf['disablepingcheck'];
191
	$pconfig['ddnsclientupdates'] = $dhcpdconf['ddnsclientupdates'];
192

    
193
	// OMAPI Settings
194
	if(isset($dhcpdconf['omapi_port'])) {
195
		$pconfig['omapi_port'] = $dhcpdconf['omapi_port'];
196
		$pconfig['omapi_key'] = $dhcpdconf['omapi_key'];
197
		$pconfig['omapi_key_algorithm'] = $dhcpdconf['omapi_key_algorithm'];
198
	}
199
}
200

    
201
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
202
$ifcfgsn = $config['interfaces'][$if]['subnet'];
203

    
204
$subnet_start = gen_subnetv4($ifcfgip, $ifcfgsn);
205
$subnet_end = gen_subnetv4_max($ifcfgip, $ifcfgsn);
206

    
207
function validate_partial_mac_list($maclist) {
208
	$macs = explode(',', $maclist);
209

    
210
	// Loop through and look for invalid MACs.
211
	foreach ($macs as $mac) {
212
		if (!is_macaddr($mac, true)) {
213
			return false;
214
		}
215
	}
216

    
217
	return true;
218
}
219

    
220
if (isset($_POST['save'])) {
221

    
222
	unset($input_errors);
223

    
224
	$pconfig = $_POST;
225

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

    
241
	// Reload the new pconfig variable that the form uses.
242
	$pconfig['numberoptions'] = $numberoptions;
243

    
244
	/* input validation */
245

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

    
263
		// Define the minimum base64 character length for each algorithm
264
		$key_char_len_by_alg = array(
265
			'hmac-md5' => 24,
266
			'hmac-sha1' => 28,
267
			'hmac-sha224' => 40,
268
			'hmac-sha256' => 44,
269
			'hmac-sha384' => 64,
270
			'hmac-sha512' => 88
271
		);
272

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

    
288
			// Convert the bits to bytes
289
			$key_bytes_len = $key_bit_len / 8; // 8 bits = 1 Byte
290

    
291
			// Generate random bytes based on key length
292
			$ran_bytes = openssl_random_pseudo_bytes($key_bytes_len);
293

    
294
			// Encode the bytes to get the key string
295
			$key_str = base64_encode($ran_bytes);
296

    
297
			// Set the key
298
			$_POST['omapi_key'] = $key_str;
299
			$pconfig['omapi_key'] = $key_str;
300

    
301
			// Uncheck the generate box
302
			unset($_POST['omapi_gen_key']);
303
			unset($pconfig['omapi_gen_key']);
304
		} elseif (!empty($_POST['omapi_key'])) { // Check the key if it's not being generated
305
			if (strlen($_POST['omapi_key']) < $key_char_len_by_alg[$_POST['omapi_key_algorithm']]) {
306
				$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']}.");
307
			}
308
		} else {
309
			$input_errors[] = gettext("A key is required when OMAPI is enabled (port specified).");
310
		}
311
	}
312

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

    
318
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
319
	}
320

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

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

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

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

    
356
	if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
357
		$deftime = 7200; // Default value if it's empty
358
		if (is_numeric($_POST['deftime'])) {
359
			$deftime = $_POST['deftime'];
360
		}
361

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

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

    
402
	// Validate MACs
403
	if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
404
		$input_errors[] = gettext("If a mac allow list is specified, it must contain only valid partial MAC addresses.");
405
	}
406
	if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
407
		$input_errors[] = gettext("If a mac deny list is specified, it must contain only valid partial MAC addresses.");
408
	}
409

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

    
423
	if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
424
		$input_errors[] = gettext("The network address cannot be used in the starting subnet range.");
425
	}
426
	if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
427
		$input_errors[] = gettext("The broadcast address cannot be used in the ending subnet range.");
428
	}
429

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

    
441
	$noip = false;
442
	if (is_array($a_maps)) {
443
		foreach ($a_maps as $map) {
444
			if (empty($map['ipaddr'])) {
445
				$noip = true;
446
			}
447
		}
448
	}
449

    
450
	if ($_POST['staticarp'] && $noip) {
451
		$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.");
452
	}
453

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

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

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

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

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

    
529
		if (!is_inrange_v4($_POST['range_from'], $subnet_start, $subnet_end) ||
530
			!is_inrange_v4($_POST['range_to'], $subnet_start, $subnet_end)) {
531
			$input_errors[] = gettext("The specified range lies outside of the current subnet.");
532
		}
533

    
534
		if (is_numeric($pool) || ($act == "newpool")) {
535
			if (is_inrange_v4($_POST['range_from'],
536
				$config['dhcpd'][$if]['range']['from'],
537
				$config['dhcpd'][$if]['range']['to']) ||
538
				is_inrange_v4($_POST['range_to'],
539
				$config['dhcpd'][$if]['range']['from'],
540
				$config['dhcpd'][$if]['range']['to'])) {
541
				$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
542
			}
543
		}
544

    
545
		foreach ($a_pools as $id => $p) {
546
			if (is_numeric($pool) && ($id == $pool)) {
547
				continue;
548
			}
549

    
550
			if (is_inrange_v4($_POST['range_from'],
551
				$p['range']['from'], $p['range']['to']) ||
552
				is_inrange_v4($_POST['range_to'],
553
				$p['range']['from'], $p['range']['to'])) {
554
				$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
555
				break;
556
			}
557
		}
558

    
559
		if (is_array($a_maps)) {
560
			foreach ($a_maps as $map) {
561
				if (empty($map['ipaddr'])) {
562
					continue;
563
				}
564
				if (is_inrange_v4($map['ipaddr'], $_POST['range_from'], $_POST['range_to'])) {
565
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
566
					break;
567
				}
568
			}
569
		}
570
	}
571

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

    
601
		$dhcpd_enable_changed = false;
602

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

    
612
			$dhcpdconf['enable'] = $new_dhcpd_enable;
613
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
614
			$previous = $dhcpdconf['failover_peerip'];
615
			if ($previous != $_POST['failover_peerip']) {
616
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
617
			}
618

    
619
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
620
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
621
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
622
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
623
			}
624
		} else {
625
			// Options that exist only in pools
626
			$dhcpdconf['descr'] = $_POST['descr'];
627
		}
628

    
629
		// Options that can be global or per-pool.
630
		$dhcpdconf['range']['from'] = $_POST['range_from'];
631
		$dhcpdconf['range']['to'] = $_POST['range_to'];
632
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
633
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
634
		$dhcpdconf['netmask'] = $_POST['netmask'];
635

    
636
		unset($dhcpdconf['winsserver']);
637
		if ($_POST['wins1']) {
638
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
639
		}
640
		if ($_POST['wins2']) {
641
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
642
		}
643

    
644
		unset($dhcpdconf['dnsserver']);
645
		if ($_POST['dns1']) {
646
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
647
		}
648
		if ($_POST['dns2']) {
649
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
650
		}
651
		if ($_POST['dns3']) {
652
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
653
		}
654
		if ($_POST['dns4']) {
655
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
656
		}
657

    
658
		$dhcpdconf['gateway'] = $_POST['gateway'];
659
		$dhcpdconf['domain'] = $_POST['domain'];
660
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
661
		$dhcpdconf['ignorebootp'] = ($_POST['ignorebootp']) ? true : false;
662
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
663
		$dhcpdconf['ignoreclientuids'] = ($_POST['ignoreclientuids']) ? true : false;
664
		$dhcpdconf['nonak'] = ($_POST['nonak']) ? true : false;
665
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
666
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
667
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
668
		$dhcpdconf['ddnsdomainkeyalgorithm'] = $_POST['ddnsdomainkeyalgorithm'];
669
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
670
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
671
		$dhcpdconf['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
672
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
673
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
674
		$dhcpdconf['ddnsclientupdates'] = $_POST['ddnsclientupdates'];
675

    
676
		unset($dhcpdconf['ntpserver']);
677
		if ($_POST['ntp1']) {
678
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
679
		}
680
		if ($_POST['ntp2']) {
681
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
682
		}
683

    
684
		$dhcpdconf['tftp'] = $_POST['tftp'];
685
		$dhcpdconf['ldap'] = $_POST['ldap'];
686
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
687
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
688
		$dhcpdconf['filename'] = $_POST['filename'];
689
		$dhcpdconf['filename32'] = $_POST['filename32'];
690
		$dhcpdconf['filename64'] = $_POST['filename64'];
691
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
692
		unset($dhcpdconf['statsgraph']);
693
		if ($_POST['statsgraph']) {
694
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
695
			enable_rrd_graphing();
696
		}
697
		unset($dhcpdconf['disablepingcheck']);
698
		if ($_POST['disablepingcheck']) {
699
			$dhcpdconf['disablepingcheck'] = $_POST['disablepingcheck'];
700
		}
701

    
702
		// Handle the custom options rowhelper
703
		if (isset($dhcpdconf['numberoptions']['item'])) {
704
			unset($dhcpdconf['numberoptions']['item']);
705
		}
706

    
707
		$dhcpdconf['numberoptions'] = $numberoptions;
708

    
709
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
710
			$a_pools[$pool] = $dhcpdconf;
711
		} elseif ($act == "newpool") {
712
			$a_pools[] = $dhcpdconf;
713
		} else {
714
			$config['dhcpd'][$if] = $dhcpdconf;
715
		}
716

    
717
		// OMAPI Settings
718
		if ($_POST['omapi_port'] == ""){
719
			unset($dhcpdconf['omapi_port']);
720
			unset($dhcpdconf['omapi_key']);
721
			unset($dhcpdconf['omapi_key_algorithm']);
722

    
723
			unset($pconfig['omapi_port']);
724
			unset($pconfig['omapi_key']);
725
			unset($pconfig['omapi_key_algorithm']);
726
		} else {
727
			$dhcpdconf['omapi_port'] = $_POST['omapi_port'];
728
			$dhcpdconf['omapi_key'] = $_POST['omapi_key'];
729
			$dhcpdconf['omapi_key_algorithm'] = $_POST['omapi_key_algorithm'];
730
		}
731

    
732
		write_config(gettext("DHCP Server - Settings changed for interface " . strtoupper($if)));
733
	}
734
}
735

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

    
791
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
792
		$retval = 1;
793
	}
794
}
795

    
796
if ($act == "delpool") {
797
	if ($a_pools[$_POST['id']]) {
798
		unset($a_pools[$_POST['id']]);
799
		write_config();
800
		header("Location: services_dhcp.php?if={$if}");
801
		exit;
802
	}
803
}
804

    
805
if ($act == "del") {
806
	if (isset($a_maps[$_POST['id']])) {
807
		/* Remove static ARP entry, if necessary */
808
		if (isset($a_maps[$_POST['id']]['arp_table_static_entry'])) {
809
			mwexec("/usr/sbin/arp -d " . escapeshellarg($a_maps[$_POST['id']]['ipaddr']));
810
		}
811
		unset($a_maps[$_POST['id']]);
812
		write_config();
813
		if (isset($config['dhcpd'][$if]['enable'])) {
814
			mark_subsystem_dirty('staticmaps');
815
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
816
				mark_subsystem_dirty('hosts');
817
			}
818
		}
819

    
820
		header("Location: services_dhcp.php?if={$if}");
821
		exit;
822
	}
823
}
824

    
825
// Build an HTML table that can be inserted into a Form_StaticText element
826
function build_pooltable() {
827
	global $a_pools, $if;
828

    
829
	$pooltbl =	'<div class="table-responsive">';
830
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
831
	$pooltbl .=			'<thead>';
832
	$pooltbl .=				'<tr>';
833
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
834
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
835
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
836
	$pooltbl .=					'<th>' . gettext("Actions") . '</th>';
837
	$pooltbl .=				'</tr>';
838
	$pooltbl .=			'</thead>';
839
	$pooltbl .=			'<tbody>';
840

    
841
	if (is_array($a_pools)) {
842
		$i = 0;
843
		foreach ($a_pools as $poolent) {
844
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
845
				$pooltbl .= '<tr>';
846
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
847
							htmlspecialchars($poolent['range']['from']) . '</td>';
848

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

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

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

    
857
				$pooltbl .= ' <a class="fa fa-trash" title="'. gettext("Delete pool") . '" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" usepost></a></td>';
858
				$pooltbl .= '</tr>';
859
			}
860
		$i++;
861
		}
862
	}
863

    
864
	$pooltbl .=			'</tbody>';
865
	$pooltbl .=		'</table>';
866
	$pooltbl .= '</div>';
867

    
868
	return($pooltbl);
869
}
870

    
871
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
872
$pglinks = array("", "services_dhcp.php");
873

    
874
if (!empty($if) && isset($iflist[$if])) {
875
	$pgtitle[] = $iflist[$if];
876
	$pglinks[] = "@self";
877
}
878
$shortcut_section = "dhcp";
879

    
880
include("head.inc");
881

    
882
if ($input_errors) {
883
	print_input_errors($input_errors);
884
}
885

    
886
if ($changes_applied) {
887
	print_apply_result_box($retval);
888
}
889

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

    
894
/* active tabs */
895
$tab_array = array();
896
$tabscounter = 0;
897
$i = 0;
898
$have_small_subnet = false;
899

    
900
foreach ($iflist as $ifent => $ifname) {
901
	$oc = $config['interfaces'][$ifent];
902

    
903
	/* Not static IPv4 or subnet >= 31 */
904
	if ($oc['subnet'] >= 31) {
905
		$have_small_subnet = true;
906
		$example_name = $ifname;
907
		$example_cidr = $oc['subnet'];
908
		continue;
909
	}
910
	if (!is_ipaddrv4($oc['ipaddr']) || empty($oc['subnet'])) {
911
		continue;
912
	}
913

    
914
	if ($ifent == $if) {
915
		$active = true;
916
	} else {
917
		$active = false;
918
	}
919

    
920
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
921
	$tabscounter++;
922
}
923

    
924
if ($tabscounter == 0) {
925
	if ($have_small_subnet) {
926
		$sentence2 = sprintf(gettext('%1$s has a CIDR mask of %2$s, which does not contain enough addresses.'), htmlspecialchars($example_name), htmlspecialchars($example_cidr));
927
	} else {
928
		$sentence2 = gettext("This system has no interfaces configured with a static IPv4 address.");
929
	}
930
	print_info_box(gettext("The DHCP Server requires a static IPv4 subnet large enough to serve addresses to clients.") . " " . $sentence2);
931
	include("foot.inc");
932
	exit;
933
}
934

    
935
display_top_tabs($tab_array);
936

    
937
$form = new Form();
938

    
939
$section = new Form_Section('General Options');
940

    
941
if (!is_numeric($pool) && !($act == "newpool")) {
942
	if (isset($config['dhcrelay']['enable'])) {
943
		$section->addInput(new Form_Checkbox(
944
			'enable',
945
			'Enable',
946
			gettext("DHCP Relay is currently enabled. DHCP Server canot be enabled while the DHCP Relay is enabled on any interface."),
947
			$pconfig['enable']
948
		))->setAttribute('disabled', true);
949
	} else {
950
		$section->addInput(new Form_Checkbox(
951
			'enable',
952
			'Enable',
953
			sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
954
			$pconfig['enable']
955
		));
956
	}
957
} else {
958
	print_info_box(gettext('Editing pool-specific options. To return to the Interface, click its tab above.'), 'info', false);
959
}
960

    
961
$section->addInput(new Form_Checkbox(
962
	'ignorebootp',
963
	'BOOTP',
964
	'Ignore BOOTP queries',
965
	$pconfig['ignorebootp']
966
));
967

    
968
$section->addInput(new Form_Checkbox(
969
	'denyunknown',
970
	'Deny unknown clients',
971
	'Only the clients defined below will get DHCP leases from this server.',
972
	$pconfig['denyunknown']
973
));
974

    
975
$section->addInput(new Form_Checkbox(
976
	'nonak',
977
	'Ignore denied clients',
978
	'Denied clients will be ignored rather than rejected.',
979
	$pconfig['nonak']
980
))->setHelp("This option is not compatible with failover and cannot be enabled when a Failover Peer IP address is configured.");
981

    
982
$section->addInput(new Form_Checkbox(
983
	'ignoreclientuids',
984
	'Ignore client identifiers',
985
	'If a client includes a unique identifier in its DHCP request, that UID will not be recorded in its lease.',
986
	$pconfig['ignoreclientuids']
987
))->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.");
988

    
989

    
990
if (is_numeric($pool) || ($act == "newpool")) {
991
	$section->addInput(new Form_Input(
992
		'descr',
993
		'Pool Description',
994
		'text',
995
		$pconfig['descr']
996
	));
997
}
998

    
999
$section->addInput(new Form_StaticText(
1000
	'Subnet',
1001
	gen_subnet($ifcfgip, $ifcfgsn)
1002
));
1003

    
1004
$section->addInput(new Form_StaticText(
1005
	'Subnet mask',
1006
	gen_subnet_mask($ifcfgsn)
1007
));
1008

    
1009
// Compose a string to display the required address ranges
1010
$rangestr = ip_after($subnet_start) . ' - ' . ip_before($subnet_end);
1011

    
1012
if (is_numeric($pool) || ($act == "newpool")) {
1013
	$rangestr .= '<br />' . gettext('In-use DHCP Pool Ranges:');
1014
	if (is_array($config['dhcpd'][$if]['range'])) {
1015
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
1016
	}
1017

    
1018
	foreach ($a_pools as $p) {
1019
		if (is_array($p['range'])) {
1020
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
1021
		}
1022
	}
1023
}
1024

    
1025
$section->addInput(new Form_StaticText(
1026
	'Available range',
1027
	$rangestr
1028
));
1029

    
1030
$group = new Form_Group('*Range');
1031

    
1032
$group->add(new Form_IpAddress(
1033
	'range_from',
1034
	null,
1035
	$pconfig['range_from'],
1036
	'V4'
1037
))->setHelp('From');
1038

    
1039
$group->add(new Form_IpAddress(
1040
	'range_to',
1041
	null,
1042
	$pconfig['range_to'],
1043
	'V4'
1044
))->setHelp('To');
1045

    
1046
$section->add($group);
1047

    
1048
$form->add($section);
1049

    
1050
if (!is_numeric($pool) && !($act == "newpool")) {
1051
	$section = new Form_Section('Additional Pools');
1052

    
1053
	$btnaddpool = new Form_Button(
1054
		'btnaddpool',
1055
		'Add pool',
1056
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool',
1057
		'fa-plus'
1058
	);
1059
	$btnaddpool->addClass('btn-success');
1060

    
1061
	$section->addInput(new Form_StaticText(
1062
		'Add',
1063
		$btnaddpool
1064
	))->setHelp('If additional pools of addresses are needed inside of this subnet outside the above Range, they may be specified here.');
1065

    
1066
	if (is_array($a_pools)) {
1067
		$section->addInput(new Form_StaticText(
1068
			null,
1069
			build_pooltable()
1070
		));
1071
	}
1072

    
1073
	$form->add($section);
1074
}
1075

    
1076
$section = new Form_Section('Servers');
1077

    
1078
$section->addInput(new Form_IpAddress(
1079
	'wins1',
1080
	'WINS servers',
1081
	$pconfig['wins1'],
1082
	'V4'
1083
))->setAttribute('placeholder', 'WINS Server 1');
1084

    
1085
$section->addInput(new Form_IpAddress(
1086
	'wins2',
1087
	null,
1088
	$pconfig['wins2'],
1089
	'V4'
1090
))->setAttribute('placeholder', 'WINS Server 2');
1091

    
1092
for ($idx=1; $idx<=4; $idx++) {
1093
	$section->addInput(new Form_IpAddress(
1094
		'dns' . $idx,
1095
		($idx == 1) ? 'DNS servers':null,
1096
		$pconfig['dns' . $idx],
1097
		'V4'
1098
	))->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.':'');
1099
}
1100

    
1101
$form->add($section);
1102

    
1103
//OMAPI
1104
$section = new Form_Section('OMAPI');
1105

    
1106
$section->addInput(new Form_Input(
1107
	'omapi_port',
1108
	'OMAPI Port',
1109
	'text',
1110
	$pconfig['omapi_port']
1111
))->setAttribute('placeholder', 'OMAPI Port')
1112
  ->setHelp('Set the port that OMAPI will listen on. The default port is 7911, leave blank to disable.');
1113

    
1114
$group = new Form_Group('OMAPI Key');
1115

    
1116
$group->add(new Form_Input(
1117
	'omapi_key',
1118
	'OMAPI Key',
1119
	'text',
1120
	$pconfig['omapi_key']
1121
))->setAttribute('placeholder', 'OMAPI Key')
1122
  ->setHelp('Enter a key matching the selected algorithm<br />to secure connections to the OMAPI endpoint.');
1123

    
1124
$group->add(new Form_Checkbox(
1125
	'omapi_gen_key',
1126
	'',
1127
	'Generate New Key',
1128
	$pconfig['omapi_gen_key']
1129
))->setHelp('Generate a new key based<br />on the selected algorithm.');
1130

    
1131
$section->add($group);
1132

    
1133
$section->addInput(new Form_Select(
1134
	'omapi_key_algorithm',
1135
	'Key Algorithm',
1136
	empty($pconfig['omapi_key_algorithm']) ? 'hmac-sha256' : $pconfig['omapi_key_algorithm'], // Set the default algorithm if not previous defined
1137
	array(
1138
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1139
		'hmac-sha1' => 'HMAC-SHA1',
1140
		'hmac-sha224' => 'HMAC-SHA224',
1141
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1142
		'hmac-sha384' => 'HMAC-SHA384',
1143
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1144
	)
1145
))->setHelp('Set the algorithm that OMAPI key will use.');
1146

    
1147
$form->add($section);
1148

    
1149
$section = new Form_Section('Other Options');
1150

    
1151
$section->addInput(new Form_IpAddress(
1152
	'gateway',
1153
	'Gateway',
1154
	$pconfig['gateway'],
1155
	'V4'
1156
))->setPattern('[.a-zA-Z0-9_]+')
1157
  ->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.');
1158

    
1159
$section->addInput(new Form_Input(
1160
	'domain',
1161
	'Domain name',
1162
	'text',
1163
	$pconfig['domain']
1164
))->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.');
1165

    
1166
$section->addInput(new Form_Input(
1167
	'domainsearchlist',
1168
	'Domain search list',
1169
	'text',
1170
	$pconfig['domainsearchlist']
1171
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
1172

    
1173
$section->addInput(new Form_Input(
1174
	'deftime',
1175
	'Default lease time',
1176
	'number',
1177
	$pconfig['deftime']
1178
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds.');
1179

    
1180
$section->addInput(new Form_Input(
1181
	'maxtime',
1182
	'Maximum lease time',
1183
	'number',
1184
	$pconfig['maxtime']
1185
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds.');
1186

    
1187
if (!is_numeric($pool) && !($act == "newpool")) {
1188
	$section->addInput(new Form_IpAddress(
1189
		'failover_peerip',
1190
		'Failover peer IP',
1191
		$pconfig['failover_peerip'],
1192
		'V4'
1193
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP. ' .
1194
				'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).');
1195

    
1196
	$section->addInput(new Form_Checkbox(
1197
		'staticarp',
1198
		'Static ARP',
1199
		'Enable Static ARP entries',
1200
		$pconfig['staticarp']
1201
	))->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.');
1202

    
1203
	$section->addInput(new Form_Checkbox(
1204
		'dhcpleaseinlocaltime',
1205
		'Time format change',
1206
		'Change DHCP display lease time from UTC to local time',
1207
		$pconfig['dhcpleaseinlocaltime']
1208
	))->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.' .
1209
				' This will be used for all DHCP interfaces lease time.');
1210

    
1211
	$section->addInput(new Form_Checkbox(
1212
		'statsgraph',
1213
		'Statistics graphs',
1214
		'Enable RRD statistics graphs',
1215
		$pconfig['statsgraph']
1216
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
1217

    
1218
	$section->addInput(new Form_Checkbox(
1219
		'disablepingcheck',
1220
		'Ping check',
1221
		'Disable ping check',
1222
		$pconfig['disablepingcheck']
1223
	))->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.');
1224
}
1225

    
1226
// DDNS
1227
$btnadv = new Form_Button(
1228
	'btnadvdns',
1229
	'Display Advanced',
1230
	null,
1231
	'fa-cog'
1232
);
1233

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

    
1236
$section->addInput(new Form_StaticText(
1237
	'Dynamic DNS',
1238
	$btnadv
1239
));
1240

    
1241
$section->addInput(new Form_Checkbox(
1242
	'ddnsupdate',
1243
	null,
1244
	'Enable registration of DHCP client names in DNS',
1245
	$pconfig['ddnsupdate']
1246
));
1247

    
1248
$section->addInput(new Form_Input(
1249
	'ddnsdomain',
1250
	'DDNS Domain',
1251
	'text',
1252
	$pconfig['ddnsdomain']
1253
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
1254

    
1255
$section->addInput(new Form_Checkbox(
1256
	'ddnsforcehostname',
1257
	'DDNS Hostnames',
1258
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
1259
	$pconfig['ddnsforcehostname']
1260
))->setHelp('Default registers host name option supplied by DHCP client.');
1261

    
1262
$section->addInput(new Form_IpAddress(
1263
	'ddnsdomainprimary',
1264
	'Primary DDNS address',
1265
	$pconfig['ddnsdomainprimary'],
1266
	'V4'
1267
))->setHelp('Primary domain name server IP address for the dynamic domain name.');
1268

    
1269
$section->addInput(new Form_Input(
1270
	'ddnsdomainkeyname',
1271
	'DNS Domain key',
1272
	'text',
1273
	$pconfig['ddnsdomainkeyname']
1274
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server.');
1275

    
1276
$section->addInput(new Form_Select(
1277
	'ddnsdomainkeyalgorithm',
1278
	'Key algorithm',
1279
	$pconfig['ddnsdomainkeyalgorithm'],
1280
	array(
1281
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
1282
		'hmac-sha1' => 'HMAC-SHA1',
1283
		'hmac-sha224' => 'HMAC-SHA224',
1284
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
1285
		'hmac-sha384' => 'HMAC-SHA384',
1286
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
1287
	)
1288
));
1289

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

    
1297
$section->addInput(new Form_Select(
1298
	'ddnsclientupdates',
1299
	'DDNS Client Updates',
1300
	$pconfig['ddnsclientupdates'],
1301
	array(
1302
	    'allow' => gettext('Allow'),
1303
	    'deny' => gettext('Deny'),
1304
	    'ignore' => gettext('Ignore'))
1305
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
1306
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
1307
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
1308
	    'update and the client can also attempt the update usually using a different domain name.');
1309

    
1310
// Advanced MAC
1311
$btnadv = new Form_Button(
1312
	'btnadvmac',
1313
	'Display Advanced',
1314
	null,
1315
	'fa-cog'
1316
);
1317

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

    
1320
$section->addInput(new Form_StaticText(
1321
	'MAC address control',
1322
	$btnadv
1323
));
1324

    
1325
$section->addInput(new Form_Input(
1326
	'mac_allow',
1327
	'MAC Allow',
1328
	'text',
1329
	$pconfig['mac_allow']
1330
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1331

    
1332
$section->addInput(new Form_Input(
1333
	'mac_deny',
1334
	'MAC Deny',
1335
	'text',
1336
	$pconfig['mac_deny']
1337
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1338

    
1339
// Advanced NTP
1340
$btnadv = new Form_Button(
1341
	'btnadvntp',
1342
	'Display Advanced',
1343
	null,
1344
	'fa-cog'
1345
);
1346

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

    
1349
$section->addInput(new Form_StaticText(
1350
	'NTP',
1351
	$btnadv
1352
));
1353

    
1354
$section->addInput(new Form_IpAddress(
1355
	'ntp1',
1356
	'NTP Server 1',
1357
	$pconfig['ntp1'],
1358
	'HOSTV4'
1359
));
1360

    
1361
$section->addInput(new Form_IpAddress(
1362
	'ntp2',
1363
	'NTP Server 2',
1364
	$pconfig['ntp2'],
1365
	'HOSTV4'
1366
));
1367

    
1368
// Advanced TFTP
1369
$btnadv = new Form_Button(
1370
	'btnadvtftp',
1371
	'Display Advanced',
1372
	null,
1373
	'fa-cog'
1374
);
1375

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

    
1378
$section->addInput(new Form_StaticText(
1379
	'TFTP',
1380
	$btnadv
1381
));
1382

    
1383
$section->addInput(new Form_Input(
1384
	'tftp',
1385
	'TFTP Server',
1386
	'text',
1387
	$pconfig['tftp']
1388
))->setHelp('Leave blank to disable. Enter a valid IP address, hostname or URL for the TFTP server.');
1389

    
1390
// Advanced LDAP
1391
$btnadv = new Form_Button(
1392
	'btnadvldap',
1393
	'Display Advanced',
1394
	null,
1395
	'fa-cog'
1396
);
1397

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

    
1400
$section->addInput(new Form_StaticText(
1401
	'LDAP',
1402
	$btnadv
1403
));
1404

    
1405
$section->addInput(new Form_Input(
1406
	'ldap',
1407
	'LDAP Server URI',
1408
	'text',
1409
	$pconfig['ldap']
1410
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1411

    
1412
// Advanced Network Booting options
1413
$btnadv = new Form_Button(
1414
	'btnadvnwkboot',
1415
	'Display Advanced',
1416
	null,
1417
	'fa-cog'
1418
);
1419

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

    
1422
$section->addInput(new Form_StaticText(
1423
	'Network Booting',
1424
	$btnadv
1425
));
1426

    
1427
$section->addInput(new Form_Checkbox(
1428
	'netboot',
1429
	'Enable',
1430
	'Enables network booting',
1431
	$pconfig['netboot']
1432
));
1433

    
1434
$section->addInput(new Form_IpAddress(
1435
	'nextserver',
1436
	'Next Server',
1437
	$pconfig['nextserver'],
1438
	'V4'
1439
))->setHelp('Enter the IP address of the next server');
1440

    
1441
$section->addInput(new Form_Input(
1442
	'filename',
1443
	'Default BIOS file name',
1444
	'text',
1445
	$pconfig['filename']
1446
));
1447

    
1448
$section->addInput(new Form_Input(
1449
	'filename32',
1450
	'UEFI 32 bit file name',
1451
	'text',
1452
	$pconfig['filename32']
1453
));
1454

    
1455
$section->addInput(new Form_Input(
1456
	'filename64',
1457
	'UEFI 64 bit file name',
1458
	'text',
1459
	$pconfig['filename64']
1460
))->setHelp('Both a filename and a boot server must be configured for this to work! ' .
1461
			'All three filenames and a configured boot server are necessary for UEFI to work! ');
1462

    
1463
$section->addInput(new Form_Input(
1464
	'rootpath',
1465
	'Root path',
1466
	'text',
1467
	$pconfig['rootpath']
1468
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1469

    
1470
// Advanced Additional options
1471
$btnadv = new Form_Button(
1472
	'btnadvopts',
1473
	'Display Advanced',
1474
	null,
1475
	'fa-cog'
1476
);
1477

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

    
1480
$section->addInput(new Form_StaticText(
1481
	'Additional BOOTP/DHCP Options',
1482
	$btnadv
1483
));
1484

    
1485
$form->add($section);
1486

    
1487
$section = new Form_Section('Additional BOOTP/DHCP Options');
1488
$section->addClass('adnlopts');
1489

    
1490
$section->addInput(new Form_StaticText(
1491
	null,
1492
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item to include in the DHCP lease information.') . ' ' .
1493
	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>')
1494
));
1495

    
1496
if (!$pconfig['numberoptions']) {
1497
	$pconfig['numberoptions'] = array();
1498
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1499
}
1500

    
1501
$customitemtypes = array(
1502
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1503
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1504
	'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')
1505
);
1506

    
1507
$numrows = count($item) -1;
1508
$counter = 0;
1509

    
1510
$numrows = count($pconfig['numberoptions']['item']) -1;
1511

    
1512
foreach ($pconfig['numberoptions']['item'] as $item) {
1513
	$number = $item['number'];
1514
	$itemtype = $item['type'];
1515
	$value = base64_decode($item['value']);
1516

    
1517
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1518
	$group->addClass('repeatable');
1519

    
1520
	$group->add(new Form_Input(
1521
		'number' . $counter,
1522
		null,
1523
		'number',
1524
		$number,
1525
		['min'=>'1', 'max'=>'254']
1526
	))->setHelp($numrows == $counter ? 'Number':null);
1527

    
1528

    
1529
	$group->add(new Form_Select(
1530
		'itemtype' . $counter,
1531
		null,
1532
		$itemtype,
1533
		$customitemtypes
1534
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1535

    
1536
	$group->add(new Form_Input(
1537
		'value' . $counter,
1538
		null,
1539
		'text',
1540
		$value
1541
	))->setHelp($numrows == $counter ? 'Value':null);
1542

    
1543
	$group->add(new Form_Button(
1544
		'deleterow' . $counter,
1545
		'Delete',
1546
		null,
1547
		'fa-trash'
1548
	))->addClass('btn-warning');
1549

    
1550
	$section->add($group);
1551

    
1552
	$counter++;
1553
}
1554

    
1555
$section->addInput(new Form_Button(
1556
	'addrow',
1557
	'Add',
1558
	null,
1559
	'fa-plus'
1560
))->addClass('btn-success');
1561

    
1562
$form->add($section);
1563

    
1564
if ($act == "newpool") {
1565
	$form->addGlobal(new Form_Input(
1566
		'act',
1567
		null,
1568
		'hidden',
1569
		'newpool'
1570
	));
1571
}
1572

    
1573
if (is_numeric($pool)) {
1574
	$form->addGlobal(new Form_Input(
1575
		'pool',
1576
		null,
1577
		'hidden',
1578
		$pool
1579
	));
1580
}
1581

    
1582
$form->addGlobal(new Form_Input(
1583
	'if',
1584
	null,
1585
	'hidden',
1586
	$if
1587
));
1588

    
1589
print($form);
1590

    
1591
// DHCP Static Mappings table
1592

    
1593
if (!is_numeric($pool) && !($act == "newpool")) {
1594

    
1595
	// Decide whether display of the Client Id column is needed.
1596
	$got_cid = false;
1597
	if (is_array($a_maps)) {
1598
		foreach ($a_maps as $map) {
1599
			if (!empty($map['cid'])) {
1600
				$got_cid = true;
1601
				break;
1602
			}
1603
		}
1604
	}
1605
?>
1606

    
1607
<div class="panel panel-default">
1608
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this Interface")?></h2></div>
1609
	<div class="table-responsive">
1610
			<table class="table table-striped table-hover table-condensed sortable-theme-bootstrap" data-sortable>
1611
				<thead>
1612
					<tr>
1613
						<th><?=gettext("Static ARP")?></th>
1614
						<th><?=gettext("MAC address")?></th>
1615
<?php
1616
	if ($got_cid):
1617
?>
1618
						<th><?=gettext("Client Id")?></th>
1619
<?php
1620
	endif;
1621
?>
1622
						<th><?=gettext("IP address")?></th>
1623
						<th><?=gettext("Hostname")?></th>
1624
						<th><?=gettext("Description")?></th>
1625
						<th></th>
1626
					</tr>
1627
				</thead>
1628
<?php
1629
	if (is_array($a_maps)) {
1630
		$i = 0;
1631
?>
1632
				<tbody>
1633
<?php
1634
		foreach ($a_maps as $mapent) {
1635
?>
1636
					<tr>
1637
						<td class="text-center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1638
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1639
								<i class="fa fa-check"></i>
1640
							<?php endif; ?>
1641
						</td>
1642
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1643
							<?=htmlspecialchars($mapent['mac'])?>
1644
						</td>
1645
<?php
1646
			if ($got_cid):
1647
?>
1648
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1649
							<?=htmlspecialchars($mapent['cid'])?>
1650
						</td>
1651
<?php
1652
			endif;
1653
?>
1654
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1655
							<?=htmlspecialchars($mapent['ipaddr'])?>
1656
						</td>
1657
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1658
							<?=htmlspecialchars($mapent['hostname'])?>
1659
						</td>
1660
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1661
							<?=htmlspecialchars($mapent['descr'])?>
1662
						</td>
1663
						<td>
1664
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1665
							<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>
1666
						</td>
1667
					</tr>
1668
<?php
1669
		$i++;
1670
		}
1671
?>
1672
				</tbody>
1673
<?php
1674
	}
1675
?>
1676
		</table>
1677
	</div>
1678
</div>
1679

    
1680
<nav class="action-buttons">
1681
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1682
		<i class="fa fa-plus icon-embed-btn"></i>
1683
		<?=gettext("Add")?>
1684
	</a>
1685
</nav>
1686
<?php
1687
}
1688
?>
1689

    
1690
<script type="text/javascript">
1691
//<![CDATA[
1692
events.push(function() {
1693

    
1694
	// Show advanced DNS options ======================================================================================
1695
	var showadvdns = false;
1696

    
1697
	function show_advdns(ispageload) {
1698
		var text;
1699
		// On page load decide the initial state based on the data.
1700
		if (ispageload) {
1701
<?php
1702
			if (!$pconfig['ddnsupdate'] &&
1703
				!$pconfig['ddnsforcehostname'] &&
1704
				empty($pconfig['ddnsdomain']) &&
1705
				empty($pconfig['ddnsdomainprimary']) &&
1706
			    empty($pconfig['ddnsdomainkeyname']) &&
1707
			    (empty($pconfig['ddnsdomainkeyalgorithm']) || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1708
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1709
			    empty($pconfig['ddnsdomainkey'])) {
1710
				$showadv = false;
1711
			} else {
1712
				$showadv = true;
1713
			}
1714
?>
1715
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1716
		} else {
1717
			// It was a click, swap the state.
1718
			showadvdns = !showadvdns;
1719
		}
1720

    
1721
		hideCheckbox('ddnsupdate', !showadvdns);
1722
		hideInput('ddnsdomain', !showadvdns);
1723
		hideCheckbox('ddnsforcehostname', !showadvdns);
1724
		hideInput('ddnsdomainprimary', !showadvdns);
1725
		hideInput('ddnsdomainkeyname', !showadvdns);
1726
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1727
		hideInput('ddnsdomainkey', !showadvdns);
1728
		hideInput('ddnsclientupdates', !showadvdns);
1729

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

    
1738
	$('#btnadvdns').click(function(event) {
1739
		show_advdns();
1740
	});
1741

    
1742
	// Show advanced MAC options ======================================================================================
1743
	var showadvmac = false;
1744

    
1745
	function show_advmac(ispageload) {
1746
		var text;
1747
		// On page load decide the initial state based on the data.
1748
		if (ispageload) {
1749
<?php
1750
			if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1751
				$showadv = false;
1752
			} else {
1753
				$showadv = true;
1754
			}
1755
?>
1756
			showadvmac = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1757
		} else {
1758
			// It was a click, swap the state.
1759
			showadvmac = !showadvmac;
1760
		}
1761

    
1762
		hideInput('mac_allow', !showadvmac);
1763
		hideInput('mac_deny', !showadvmac);
1764

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

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

    
1777
	// Show advanced NTP options ======================================================================================
1778
	var showadvntp = false;
1779

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

    
1797
		hideInput('ntp1', !showadvntp);
1798
		hideInput('ntp2', !showadvntp);
1799

    
1800
		if (showadvntp) {
1801
			text = "<?=gettext('Hide Advanced');?>";
1802
		} else {
1803
			text = "<?=gettext('Display Advanced');?>";
1804
		}
1805
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1806
	}
1807

    
1808
	$('#btnadvntp').click(function(event) {
1809
		show_advntp();
1810
	});
1811

    
1812
	// Show advanced TFTP options ======================================================================================
1813
	var showadvtftp = false;
1814

    
1815
	function show_advtftp(ispageload) {
1816
		var text;
1817
		// On page load decide the initial state based on the data.
1818
		if (ispageload) {
1819
<?php
1820
			if (empty($pconfig['tftp'])) {
1821
				$showadv = false;
1822
			} else {
1823
				$showadv = true;
1824
			}
1825
?>
1826
			showadvtftp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1827
		} else {
1828
			// It was a click, swap the state.
1829
			showadvtftp = !showadvtftp;
1830
		}
1831

    
1832
		hideInput('tftp', !showadvtftp);
1833

    
1834
		if (showadvtftp) {
1835
			text = "<?=gettext('Hide Advanced');?>";
1836
		} else {
1837
			text = "<?=gettext('Display Advanced');?>";
1838
		}
1839
		$('#btnadvtftp').html('<i class="fa fa-cog"></i> ' + text);
1840
	}
1841

    
1842
	$('#btnadvtftp').click(function(event) {
1843
		show_advtftp();
1844
	});
1845

    
1846
	// Show advanced LDAP options ======================================================================================
1847
	var showadvldap = false;
1848

    
1849
	function show_advldap(ispageload) {
1850
		var text;
1851
		// On page load decide the initial state based on the data.
1852
		if (ispageload) {
1853
<?php
1854
			if (empty($pconfig['ldap'])) {
1855
				$showadv = false;
1856
			} else {
1857
				$showadv = true;
1858
			}
1859
?>
1860
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1861
		} else {
1862
			// It was a click, swap the state.
1863
			showadvldap = !showadvldap;
1864
		}
1865

    
1866
		hideInput('ldap', !showadvldap);
1867

    
1868
		if (showadvldap) {
1869
			text = "<?=gettext('Hide Advanced');?>";
1870
		} else {
1871
			text = "<?=gettext('Display Advanced');?>";
1872
		}
1873
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1874
	}
1875

    
1876
	$('#btnadvldap').click(function(event) {
1877
		show_advldap();
1878
	});
1879

    
1880
	// Show advanced additional opts options ===========================================================================
1881
	var showadvopts = false;
1882

    
1883
	function show_advopts(ispageload) {
1884
		var text;
1885
		// On page load decide the initial state based on the data.
1886
		if (ispageload) {
1887
<?php
1888
			if (empty($pconfig['numberoptions']) ||
1889
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1890
				$showadv = false;
1891
			} else {
1892
				$showadv = true;
1893
			}
1894
?>
1895
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1896
		} else {
1897
			// It was a click, swap the state.
1898
			showadvopts = !showadvopts;
1899
		}
1900

    
1901
		hideClass('adnlopts', !showadvopts);
1902

    
1903
		if (showadvopts) {
1904
			text = "<?=gettext('Hide Advanced');?>";
1905
		} else {
1906
			text = "<?=gettext('Display Advanced');?>";
1907
		}
1908
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1909
	}
1910

    
1911
	$('#btnadvopts').click(function(event) {
1912
		show_advopts();
1913
	});
1914

    
1915
	// Show advanced Network Booting options ===========================================================================
1916
	var showadvnwkboot = false;
1917

    
1918
	function show_advnwkboot(ispageload) {
1919
		var text;
1920
		// On page load decide the initial state based on the data.
1921
		if (ispageload) {
1922
<?php
1923
			if (empty($pconfig['netboot'])) {
1924
				$showadv = false;
1925
			} else {
1926
				$showadv = true;
1927
			}
1928
?>
1929
			showadvnwkboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1930
		} else {
1931
			// It was a click, swap the state.
1932
			showadvnwkboot = !showadvnwkboot;
1933
		}
1934

    
1935
		hideCheckbox('netboot', !showadvnwkboot);
1936
		hideInput('nextserver', !showadvnwkboot);
1937
		hideInput('filename', !showadvnwkboot);
1938
		hideInput('filename32', !showadvnwkboot);
1939
		hideInput('filename64', !showadvnwkboot);
1940
		hideInput('rootpath', !showadvnwkboot);
1941

    
1942
		if (showadvnwkboot) {
1943
			text = "<?=gettext('Hide Advanced');?>";
1944
		} else {
1945
			text = "<?=gettext('Display Advanced');?>";
1946
		}
1947
		$('#btnadvnwkboot').html('<i class="fa fa-cog"></i> ' + text);
1948
	}
1949

    
1950
	$('#btnadvnwkboot').click(function(event) {
1951
		show_advnwkboot();
1952
	});
1953

    
1954
	// ---------- On initial page load ------------------------------------------------------------
1955

    
1956
	show_advdns(true);
1957
	show_advmac(true);
1958
	show_advntp(true);
1959
	show_advtftp(true);
1960
	show_advldap(true);
1961
	show_advopts(true);
1962
	show_advnwkboot(true);
1963

    
1964
	// Suppress "Delete row" button if there are fewer than two rows
1965
	checkLastRow();
1966
});
1967
//]]>
1968
</script>
1969

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