Project

General

Profile

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

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

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

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

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

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

    
91
$iflist = get_configured_interface_with_descr();
92

    
93
/* set the starting interface */
94
if (!$if || !isset($iflist[$if])) {
95
	foreach ($iflist as $ifent => $ifname) {
96
		$oc = $config['interfaces'][$ifent];
97
		if ((is_array($config['dhcpd'][$ifent]) && !isset($config['dhcpd'][$ifent]['enable']) && (!is_ipaddrv4($oc['ipaddr']))) ||
98
		    (!is_array($config['dhcpd'][$ifent]) && (!is_ipaddrv4($oc['ipaddr'])))) {
99
			continue;
100
		}
101

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

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

    
112
$a_pools = array();
113

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

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

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

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

    
132
	if (is_numeric($pool) && $a_pools[$pool]) {
133
		$dhcpdconf = &$a_pools[$pool];
134
	} elseif ($act == "newpool") {
135
		$dhcpdconf = array();
136
	} else {
137
		$dhcpdconf = &$config['dhcpd'][$if];
138
	}
139
}
140
if (is_array($dhcpdconf)) {
141
	// Global Options
142
	if (!is_numeric($pool) && !($act == "newpool")) {
143
		$pconfig['enable'] = isset($dhcpdconf['enable']);
144
		$pconfig['staticarp'] = isset($dhcpdconf['staticarp']);
145
		// No reason to specify this per-pool, per the dhcpd.conf man page it needs to be in every
146
		//	 pool and should be specified in every pool both nodes share, so we'll treat it as global
147
		$pconfig['failover_peerip'] = $dhcpdconf['failover_peerip'];
148

    
149
		// dhcpleaseinlocaltime is global to all interfaces. So if it is selected on any interface,
150
		// then show it true/checked.
151
		foreach ($config['dhcpd'] as $dhcpdifitem) {
152
			$dhcpleaseinlocaltime = $dhcpdifitem['dhcpleaseinlocaltime'];
153
			if ($dhcpleaseinlocaltime) {
154
				break;
155
			}
156
		}
157

    
158
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
159

    
160
		if (!is_array($dhcpdconf['staticmap'])) {
161
			$dhcpdconf['staticmap'] = array();
162
		}
163

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

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

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

    
205
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
206
$ifcfgsn = $config['interfaces'][$if]['subnet'];
207

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

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

    
218
	return true;
219
}
220

    
221
if (isset($_POST['submit'])) {
222

    
223
	unset($input_errors);
224

    
225
	$pconfig = $_POST;
226

    
227
	$numberoptions = array();
228
	for ($x = 0; $x < 99; $x++) {
229
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
230
			$numbervalue = array();
231
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
232
			$numbervalue['type'] = htmlspecialchars($_POST["itemtype{$x}"]);
233
			$numbervalue['value'] = str_replace('&quot;', '"', htmlspecialchars($_POST["value{$x}"]));
234
			$numberoptions['item'][] = $numbervalue;
235
		}
236
	}
237

    
238
	// Reload the new pconfig variable that the form uses.
239
	$pconfig['numberoptions'] = $numberoptions;
240

    
241
	/* input validation */
242
	if ($_POST['enable'] || is_numeric($pool) || $act == "newpool") {
243
		$reqdfields = explode(" ", "range_from range_to");
244
		$reqdfieldsn = array(gettext("Range begin"), gettext("Range end"));
245

    
246
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
247

    
248
		if (($_POST['range_from'] && !is_ipaddrv4($_POST['range_from']))) {
249
			$input_errors[] = gettext("A valid range must be specified.");
250
		}
251
		if (($_POST['range_to'] && !is_ipaddrv4($_POST['range_to']))) {
252
			$input_errors[] = gettext("A valid range must be specified.");
253
		}
254
		if (($_POST['gateway'] && $_POST['gateway'] != "none" && !is_ipaddrv4($_POST['gateway']))) {
255
			$input_errors[] = gettext("A valid IP address must be specified for the gateway.");
256
		}
257
		if (($_POST['wins1'] && !is_ipaddrv4($_POST['wins1'])) || ($_POST['wins2'] && !is_ipaddrv4($_POST['wins2']))) {
258
			$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary WINS servers.");
259
		}
260
		$parent_ip = get_interface_ip($_POST['if']);
261
		if (is_ipaddrv4($parent_ip) && $_POST['gateway'] && $_POST['gateway'] != "none") {
262
			$parent_sn = get_interface_subnet($_POST['if']);
263
			if (!ip_in_subnet($_POST['gateway'], gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn) && !ip_in_interface_alias_subnet($_POST['if'], $_POST['gateway'])) {
264
				$input_errors[] = sprintf(gettext("The gateway address %s does not lie within the chosen interface's subnet."), $_POST['gateway']);
265
			}
266
		}
267

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

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

    
276
		if (isset($config['captiveportal']) && is_array($config['captiveportal'])) {
277
			$deftime = 7200; // Default value if it's empty
278
			if (is_numeric($_POST['deftime'])) {
279
				$deftime = $_POST['deftime'];
280
			}
281

    
282
			foreach ($config['captiveportal'] as $cpZone => $cpdata) {
283
				if (!isset($cpdata['enable'])) {
284
					continue;
285
				}
286
				if (!isset($cpdata['timeout']) || !is_numeric($cpdata['timeout'])) {
287
					continue;
288
				}
289
				$cp_ifs = explode(',', $cpdata['interface']);
290
				if (!in_array($if, $cp_ifs)) {
291
					continue;
292
				}
293
				if ($cpdata['timeout'] > $deftime) {
294
					$input_errors[] = sprintf(gettext(
295
						"The Captive Portal zone '%s' has Hard Timeout parameter set to a value bigger than Default lease time (%s)."), $cpZone, $deftime);
296
				}
297
			}
298
		}
299

    
300
		if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
301
			$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
302
		}
303
		if (($_POST['ddnsdomain'] && !is_domain($_POST['ddnsdomain']))) {
304
			$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
305
		}
306
		if (($_POST['ddnsdomain'] && !is_ipaddrv4($_POST['ddnsdomainprimary']))) {
307
			$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
308
		}
309
		if (($_POST['ddnsdomainkey'] && !$_POST['ddnsdomainkeyname']) ||
310
		    ($_POST['ddnsdomainkeyname'] && !$_POST['ddnsdomainkey'])) {
311
			$input_errors[] = gettext("You must specify both a valid domain key and key name.");
312
		}
313
		if ($_POST['domainsearchlist']) {
314
			$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
315
			foreach ($domain_array as $curdomain) {
316
				if (!is_domain($curdomain)) {
317
					$input_errors[] = gettext("A valid domain search list must be specified.");
318
					break;
319
				}
320
			}
321
		}
322

    
323
		// Validate MACs
324
		if (!empty($_POST['mac_allow']) && !validate_partial_mac_list($_POST['mac_allow'])) {
325
			$input_errors[] = gettext("If you specify a mac allow list, it must contain only valid partial MAC addresses.");
326
		}
327
		if (!empty($_POST['mac_deny']) && !validate_partial_mac_list($_POST['mac_deny'])) {
328
			$input_errors[] = gettext("If you specify a mac deny list, it must contain only valid partial MAC addresses.");
329
		}
330

    
331
		if (($_POST['ntp1'] && !is_ipaddrv4($_POST['ntp1'])) || ($_POST['ntp2'] && !is_ipaddrv4($_POST['ntp2']))) {
332
			$input_errors[] = gettext("A valid IP address must be specified for the primary/secondary NTP servers.");
333
		}
334
		if (($_POST['domain'] && !is_domain($_POST['domain']))) {
335
			$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
336
		}
337
		if ($_POST['tftp'] && !is_ipaddrv4($_POST['tftp']) && !is_domain($_POST['tftp']) && !is_URL($_POST['tftp'])) {
338
			$input_errors[] = gettext("A valid IP address or hostname must be specified for the TFTP server.");
339
		}
340
		if (($_POST['nextserver'] && !is_ipaddrv4($_POST['nextserver']))) {
341
			$input_errors[] = gettext("A valid IP address must be specified for the network boot server.");
342
		}
343

    
344
		if (gen_subnet($ifcfgip, $ifcfgsn) == $_POST['range_from']) {
345
			$input_errors[] = gettext("You cannot use the network address in the starting subnet range.");
346
		}
347
		if (gen_subnet_max($ifcfgip, $ifcfgsn) == $_POST['range_to']) {
348
			$input_errors[] = gettext("You cannot use the broadcast address in the ending subnet range.");
349
		}
350

    
351
		// Disallow a range that includes the virtualip
352
		if (is_array($config['virtualip']['vip'])) {
353
			foreach ($config['virtualip']['vip'] as $vip) {
354
				if ($vip['interface'] == $if) {
355
					if ($vip['subnet'] && is_inrange_v4($vip['subnet'], $_POST['range_from'], $_POST['range_to'])) {
356
						$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IP address %s."), $vip['subnet']);
357
					}
358
				}
359
			}
360
		}
361

    
362
		$noip = false;
363
		if (is_array($a_maps)) {
364
			foreach ($a_maps as $map) {
365
				if (empty($map['ipaddr'])) {
366
					$noip = true;
367
				}
368
			}
369
		}
370

    
371
		if ($_POST['staticarp'] && $noip) {
372
			$input_errors[] = "Cannot enable static ARP when you have static map entries without IP addresses. Ensure all static maps have IP addresses and try again.";
373
		}
374

    
375
		if (is_array($pconfig['numberoptions']['item'])) {
376
			foreach ($pconfig['numberoptions']['item'] as $numberoption) {
377
				if ($numberoption['type'] == 'text' && strstr($numberoption['value'], '"')) {
378
					$input_errors[] = gettext("Text type cannot include quotation marks.");
379
				} else if ($numberoption['type'] == 'string' && !preg_match('/^"[^"]*"$/', $numberoption['value']) && !preg_match('/^[0-9a-f]{2}(?:\:[0-9a-f]{2})*$/i', $numberoption['value'])) {
380
					$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");
381
				} else if ($numberoption['type'] == 'boolean' && $numberoption['value'] != 'true' && $numberoption['value'] != 'false' && $numberoption['value'] != 'on' && $numberoption['value'] != 'off') {
382
					$input_errors[] = gettext("Boolean type must be true, false, on, or off.");
383
				} else if ($numberoption['type'] == 'unsigned integer 8' && (!is_numeric($numberoption['value']) || $numberoption['value'] < 0 || $numberoption['value'] > 255)) {
384
					$input_errors[] = gettext("Unsigned 8-bit integer type must be a number in the range 0 to 255.");
385
				} else if ($numberoption['type'] == 'unsigned integer 16' && (!is_numeric($numberoption['value']) || $numberoption['value'] < 0 || $numberoption['value'] > 65535)) {
386
					$input_errors[] = gettext("Unsigned 16-bit integer type must be a number in the range 0 to 65535.");
387
				} else if ($numberoption['type'] == 'unsigned integer 32' && (!is_numeric($numberoption['value']) || $numberoption['value'] < 0 || $numberoption['value'] > 4294967295)) {
388
					$input_errors[] = gettext("Unsigned 32-bit integer type must be a number in the range 0 to 4294967295.");
389
				} else if ($numberoption['type'] == 'signed integer 8' && (!is_numeric($numberoption['value']) || $numberoption['value'] < -128 || $numberoption['value'] > 127)) {
390
					$input_errors[] = gettext("Signed 8-bit integer type must be a number in the range -128 to 127.");
391
				} else if ($numberoption['type'] == 'signed integer 16' && (!is_numeric($numberoption['value']) || $numberoption['value'] < -32768 || $numberoption['value'] > 32767)) {
392
					$input_errors[] = gettext("Signed 16-bit integer type must be a number in the range -32768 to 32767.");
393
				} else if ($numberoption['type'] == 'signed integer 32' && (!is_numeric($numberoption['value']) || $numberoption['value'] < -2147483648 || $numberoption['value'] > 2147483647)) {
394
					$input_errors[] = gettext("Signed 32-bit integer type must be a number in the range -2147483648 to 2147483647.");
395
				} else if ($numberoption['type'] == 'ip-address' && !is_ipaddrv4($numberoption['value']) && !is_hostname($numberoption['value'])) {
396
					$input_errors[] = gettext("IP address or host type must be an IP address or host name.");
397
				}
398
			}
399
		}
400

    
401
		if (!$input_errors) {
402
			/* make sure the range lies within the current subnet */
403
			$subnet_start = ip2ulong(long2ip32(ip2long($ifcfgip) & gen_subnet_mask_long($ifcfgsn)));
404
			$subnet_end = ip2ulong(long2ip32(ip2long($ifcfgip) | (~gen_subnet_mask_long($ifcfgsn))));
405

    
406
			if (ip2ulong($_POST['range_from']) > ip2ulong($_POST['range_to'])) {
407
				$input_errors[] = gettext("The range is invalid (first element higher than second element).");
408
			}
409

    
410
			if (ip2ulong($_POST['range_from']) < $subnet_start || ip2ulong($_POST['range_to']) > $subnet_end) {
411
				$input_errors[] = gettext("The specified range lies outside of the current subnet.");
412
			}
413

    
414
			if (is_numeric($pool) || ($act == "newpool")) {
415
				$rfrom = $config['dhcpd'][$if]['range']['from'];
416
				$rto = $config['dhcpd'][$if]['range']['to'];
417

    
418
				if (is_inrange_v4($_POST['range_from'], $rfrom, $rto) || is_inrange_v4($_POST['range_to'], $rfrom, $rto)) {
419
					$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
420
				}
421
			}
422

    
423
			foreach ($a_pools as $id => $p) {
424
				if (is_numeric($pool) && ($id == $pool)) {
425
					continue;
426
				}
427

    
428
				if (is_inrange_v4($_POST['range_from'], $p['range']['from'], $p['range']['to']) ||
429
				    is_inrange_v4($_POST['range_to'], $p['range']['from'], $p['range']['to'])) {
430
					$input_errors[] = gettext("The specified range must not be within the range configured on a DHCP pool for this interface.");
431
					break;
432
				}
433
			}
434

    
435
			/* make sure that the DHCP Relay isn't enabled on this interface */
436
			if (isset($config['dhcrelay']['enable']) && (stristr($config['dhcrelay']['interface'], $if) !== false)) {
437
				$input_errors[] = sprintf(gettext("You must disable the DHCP relay on the %s interface before enabling the DHCP server."), $iflist[$if]);
438
			}
439

    
440
			$dynsubnet_start = ip2ulong($_POST['range_from']);
441
			$dynsubnet_end = ip2ulong($_POST['range_to']);
442
			if (is_array($a_maps)) {
443
				foreach ($a_maps as $map) {
444
					if (empty($map['ipaddr'])) {
445
						continue;
446
					}
447
					if ((ip2ulong($map['ipaddr']) > $dynsubnet_start) &&
448
					    (ip2ulong($map['ipaddr']) < $dynsubnet_end)) {
449
						$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
450
						break;
451
					}
452
				}
453
			}
454
		}
455
	}
456

    
457
	if (!$input_errors) {
458
		if (!is_numeric($pool)) {
459
			if ($act == "newpool") {
460
				$dhcpdconf = array();
461
			} else {
462
				if (!is_array($config['dhcpd'][$if])) {
463
					$config['dhcpd'][$if] = array();
464
				}
465
				$dhcpdconf = $config['dhcpd'][$if];
466
			}
467
		} else {
468
			if (is_array($a_pools[$pool])) {
469
				$dhcpdconf = $a_pools[$pool];
470
			} else {
471
				// Someone specified a pool but it doesn't exist. Punt.
472
				header("Location: services_dhcp.php");
473
				exit;
474
			}
475
		}
476
		if (!is_array($dhcpdconf['range'])) {
477
			$dhcpdconf['range'] = array();
478
		}
479

    
480
		$dhcpd_enable_changed = false;
481

    
482
		// Global Options
483
		if (!is_numeric($pool) && !($act == "newpool")) {
484
			$old_dhcpd_enable = isset($dhcpdconf['enable']);
485
			$new_dhcpd_enable = ($_POST['enable']) ? true : false;
486
			if ($old_dhcpd_enable != $new_dhcpd_enable) {
487
				/* DHCP has been enabled or disabled. The pf ruleset will need to be rebuilt to allow or disallow DHCP. */
488
				$dhcpd_enable_changed = true;
489
			}
490

    
491
			$dhcpdconf['enable'] = $new_dhcpd_enable;
492
			$dhcpdconf['staticarp'] = ($_POST['staticarp']) ? true : false;
493
			$previous = $dhcpdconf['failover_peerip'];
494
			if ($previous != $_POST['failover_peerip']) {
495
				mwexec("/bin/rm -rf /var/dhcpd/var/db/*");
496
			}
497

    
498
			$dhcpdconf['failover_peerip'] = $_POST['failover_peerip'];
499
			// dhcpleaseinlocaltime is global to all interfaces. So update the setting on all interfaces.
500
			foreach ($config['dhcpd'] as &$dhcpdifitem) {
501
				$dhcpdifitem['dhcpleaseinlocaltime'] = $_POST['dhcpleaseinlocaltime'];
502
			}
503
		} else {
504
			// Options that exist only in pools
505
			$dhcpdconf['descr'] = $_POST['descr'];
506
		}
507

    
508
		// Options that can be global or per-pool.
509
		$dhcpdconf['range']['from'] = $_POST['range_from'];
510
		$dhcpdconf['range']['to'] = $_POST['range_to'];
511
		$dhcpdconf['defaultleasetime'] = $_POST['deftime'];
512
		$dhcpdconf['maxleasetime'] = $_POST['maxtime'];
513
		$dhcpdconf['netmask'] = $_POST['netmask'];
514

    
515
		unset($dhcpdconf['winsserver']);
516
		if ($_POST['wins1']) {
517
			$dhcpdconf['winsserver'][] = $_POST['wins1'];
518
		}
519
		if ($_POST['wins2']) {
520
			$dhcpdconf['winsserver'][] = $_POST['wins2'];
521
		}
522

    
523
		unset($dhcpdconf['dnsserver']);
524
		if ($_POST['dns1']) {
525
			$dhcpdconf['dnsserver'][] = $_POST['dns1'];
526
		}
527
		if ($_POST['dns2']) {
528
			$dhcpdconf['dnsserver'][] = $_POST['dns2'];
529
		}
530
		if ($_POST['dns3']) {
531
			$dhcpdconf['dnsserver'][] = $_POST['dns3'];
532
		}
533
		if ($_POST['dns4']) {
534
			$dhcpdconf['dnsserver'][] = $_POST['dns4'];
535
		}
536

    
537
		$dhcpdconf['gateway'] = $_POST['gateway'];
538
		$dhcpdconf['domain'] = $_POST['domain'];
539
		$dhcpdconf['domainsearchlist'] = $_POST['domainsearchlist'];
540
		$dhcpdconf['denyunknown'] = ($_POST['denyunknown']) ? true : false;
541
		$dhcpdconf['ddnsdomain'] = $_POST['ddnsdomain'];
542
		$dhcpdconf['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
543
		$dhcpdconf['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
544
		$dhcpdconf['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
545
		$dhcpdconf['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
546
		$dhcpdconf['mac_allow'] = $_POST['mac_allow'];
547
		$dhcpdconf['mac_deny'] = $_POST['mac_deny'];
548

    
549
		unset($dhcpdconf['ntpserver']);
550
		if ($_POST['ntp1']) {
551
			$dhcpdconf['ntpserver'][] = $_POST['ntp1'];
552
		}
553
		if ($_POST['ntp2']) {
554
			$dhcpdconf['ntpserver'][] = $_POST['ntp2'];
555
		}
556

    
557
		$dhcpdconf['tftp'] = $_POST['tftp'];
558
		$dhcpdconf['ldap'] = $_POST['ldap'];
559
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
560
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
561
		$dhcpdconf['filename'] = $_POST['filename'];
562
		$dhcpdconf['filename32'] = $_POST['filename32'];
563
		$dhcpdconf['filename64'] = $_POST['filename64'];
564
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
565
		unset($dhcpdconf['statsgraph']);
566
		if ($_POST['statsgraph']) {
567
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
568
			enable_rrd_graphing();
569
		}
570

    
571
		// Handle the custom options rowhelper
572
		if (isset($dhcpdconf['numberoptions']['item'])) {
573
			unset($dhcpdconf['numberoptions']['item']);
574
		}
575

    
576
		$dhcpdconf['numberoptions'] = $numberoptions;
577

    
578
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
579
			$a_pools[$pool] = $dhcpdconf;
580
		} elseif ($act == "newpool") {
581
			$a_pools[] = $dhcpdconf;
582
		} else {
583
			$config['dhcpd'][$if] = $dhcpdconf;
584
		}
585

    
586
		write_config();
587
	}
588
}
589

    
590
if ((isset($_POST['submit']) || isset($_POST['apply'])) && (!$input_errors)) {
591
	$retval = 0;
592
	$retvaldhcp = 0;
593
	$retvaldns = 0;
594
	/* dnsmasq_configure calls dhcpd_configure */
595
	/* no need to restart dhcpd twice */
596
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
597
		$retvaldns = services_dnsmasq_configure();
598
		if ($retvaldns == 0) {
599
			clear_subsystem_dirty('hosts');
600
			clear_subsystem_dirty('staticmaps');
601
		}
602
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
603
		$retvaldns = services_unbound_configure();
604
		if ($retvaldns == 0) {
605
			clear_subsystem_dirty('unbound');
606
			clear_subsystem_dirty('hosts');
607
			clear_subsystem_dirty('staticmaps');
608
		}
609
	} else {
610
		$retvaldhcp = services_dhcpd_configure();
611
		if ($retvaldhcp == 0) {
612
			clear_subsystem_dirty('staticmaps');
613
		}
614
	}
615
	if ($dhcpd_enable_changed) {
616
		$retvalfc = filter_configure();
617
	}
618

    
619
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
620
		$retval = 1;
621
	}
622

    
623
	$savemsg = get_std_save_message($retval);
624
}
625

    
626
if ($act == "delpool") {
627
	if ($a_pools[$_GET['id']]) {
628
		unset($a_pools[$_GET['id']]);
629
		write_config();
630
		header("Location: services_dhcp.php?if={$if}");
631
		exit;
632
	}
633
}
634

    
635
if ($act == "del") {
636
	if ($a_maps[$_GET['id']]) {
637
		unset($a_maps[$_GET['id']]);
638
		write_config();
639
		if (isset($config['dhcpd'][$if]['enable'])) {
640
			mark_subsystem_dirty('staticmaps');
641
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
642
				mark_subsystem_dirty('hosts');
643
			}
644
		}
645

    
646
		header("Location: services_dhcp.php?if={$if}");
647
		exit;
648
	}
649
}
650

    
651
// Build an HTML table that can be inserted into a Form_StaticText element
652
function build_pooltable() {
653
	global $a_pools;
654

    
655
	$pooltbl =	'<div class="table-responsive">';
656
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
657
	$pooltbl .=			'<thead>';
658
	$pooltbl .=				'<tr>';
659
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
660
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
661
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
662
	$pooltbl .=					'<th></th>';
663
	$pooltbl .=				'</tr>';
664
	$pooltbl .=			'</thead>';
665
	$pooltbl .=			'<tbody>';
666

    
667
	if (is_array($a_pools)) {
668
		$i = 0;
669
		foreach ($a_pools as $poolent) {
670
			if (!empty($poolent['range']['from']) && !empty($poolent['range']['to'])) {
671
				$pooltbl .= '<tr>';
672
				$pooltbl .= '<td ondblclick="document.location=\'services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '\';">' .
673
							htmlspecialchars($poolent['range']['from']) . '</td>';
674

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

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

    
681
				$pooltbl .= '<td><a class="btn btn-xs btn-info" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&pool=' . $i . '" />' . gettext('Edit') . '</a>';
682

    
683
				$pooltbl .= '<a class="btn btn-xs btn-danger" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" />' . gettext('Delete') . '</a></td>';
684
				$pooltbl .= '</tr>';
685
			}
686
		$i++;
687
		}
688
	}
689

    
690
	$pooltbl .=			'</tbody>';
691
	$pooltbl .=		'</table>';
692
	$pooltbl .= '</div>';
693

    
694
	return($pooltbl);
695
}
696

    
697
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
698
$shortcut_section = "dhcp";
699

    
700
include("head.inc");
701

    
702
if ($input_errors) {
703
	print_input_errors($input_errors);
704
}
705

    
706
if ($savemsg) {
707
	print_info_box($savemsg, 'success');
708
}
709

    
710
if (isset($config['dhcrelay']['enable'])) {
711
	print_info_box(gettext("DHCP Relay is currently enabled. Cannot enable the DHCP Server service while the DHCP Relay is enabled on any interface."));
712
	include("foot.inc");
713
	exit;
714
}
715

    
716
if (is_subsystem_dirty('staticmaps')) {
717
	print_info_box_np(gettext("The static mapping configuration has been changed") . ".<br />" . gettext("You must apply the changes in order for them to take effect."));
718
}
719

    
720
/* active tabs */
721
$tab_array = array();
722
$tabscounter = 0;
723
$i = 0;
724

    
725
foreach ($iflist as $ifent => $ifname) {
726
	$oc = $config['interfaces'][$ifent];
727
	if ((is_array($config['dhcpd'][$ifent]) && !isset($config['dhcpd'][$ifent]['enable']) && (!is_ipaddrv4($oc['ipaddr']))) ||
728
	    (!is_array($config['dhcpd'][$ifent]) && (!is_ipaddrv4($oc['ipaddr'])))) {
729
		continue;
730
	}
731

    
732
	if ($ifent == $if) {
733
		$active = true;
734
	} else {
735
		$active = false;
736
	}
737

    
738
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
739
	$tabscounter++;
740
}
741

    
742
if ($tabscounter == 0) {
743
	print_info_box(gettext("The DHCP Server can only be enabled on interfaces configured with a static IPv4 address. This system has none."));
744
	include("foot.inc");
745
	exit;
746
}
747

    
748
display_top_tabs($tab_array);
749

    
750
// This form uses a non-standard submit button name
751
$form = new Form(new Form_Button(
752
	'submit',
753
	gettext("Save")
754
));
755

    
756
$section = new Form_Section('General Options');
757

    
758
if (!is_numeric($pool) && !($act == "newpool")) {
759
	$section->addInput(new Form_Checkbox(
760
		'enable',
761
		'Enable',
762
		sprintf(gettext("Enable DHCP server on %s interface"), htmlspecialchars($iflist[$if])),
763
		$pconfig['enable']
764
	));
765
} else {
766
	$section->addInput(new Form_StaticText(
767
		null,
768
		'<div class="alert alert-info"> Editing Pool-Specific Options. To return to the Interface, click its tab above. </div>'
769
	));
770
}
771

    
772
$section->addInput(new Form_Checkbox(
773
	'denyunknown',
774
	'Deny unknown clients',
775
	'Only the clients defined below will get DHCP leases from this server.',
776
	$pconfig['denyunknown']
777
));
778

    
779
if (is_numeric($pool) || ($act == "newpool")) {
780
	$section->addInput(new Form_Input(
781
		'descr',
782
		'Pool Description',
783
		'text',
784
		$pconfig['descr']
785
	));
786
}
787

    
788
$section->addInput(new Form_StaticText(
789
	'Subnet',
790
	gen_subnet($ifcfgip, $ifcfgsn)
791
));
792

    
793
$section->addInput(new Form_StaticText(
794
	'Subnet mask',
795
	gen_subnet_mask($ifcfgsn)
796
));
797

    
798
// Compose a string to display the required address ranges
799
$range_from = ip2long(gen_subnetv4($ifcfgip, $ifcfgsn));
800
$range_from++;
801

    
802
$range_to = ip2long(gen_subnetv4_max($ifcfgip, $ifcfgsn));
803
$range_to--;
804

    
805
$rangestr = long2ip32($range_from) . ' - ' . long2ip32($range_to);
806

    
807
if (is_numeric($pool) || ($act == "newpool")) {
808
	$rangestr .= '<br />' . 'In-use DHCP Pool Ranges:';
809
	if (is_array($config['dhcpd'][$if]['range'])) {
810
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
811
	}
812

    
813
	foreach ($a_pools as $p) {
814
		if (is_array($p['range'])) {
815
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
816
		}
817
	}
818
}
819

    
820
$section->addInput(new Form_StaticText(
821
	'Available range',
822
	$rangestr
823
));
824

    
825
if ($is_olsr_enabled) {
826
	$section->addInput(new Form_Select(
827
		'netmask',
828
		'Subnet mask',
829
		$pconfig['netmask'],
830
		array_combine(range(32, 1, -1), range(32, 1, -1))
831
	));
832
}
833

    
834
$group = new Form_Group('Range');
835

    
836
$group->add(new Form_IpAddress(
837
	'range_from',
838
	null,
839
	$pconfig['range_from']
840
))->setHelp('From');
841

    
842
$group->add(new Form_IpAddress(
843
	'range_to',
844
	null,
845
	$pconfig['range_to']
846
))->setHelp('To');
847

    
848
$section->add($group);
849

    
850
$form->add($section);
851

    
852
if (!is_numeric($pool) && !($act == "newpool")) {
853
	$section = new Form_Section('Additional pools');
854

    
855
	$btnaddpool = new Form_Button(
856
		'btnaddpool',
857
		'Add pool',
858
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool'
859
	);
860

    
861
	$section->addInput(new Form_StaticText(
862
		'Add',
863
		$btnaddpool
864
	))->setHelp('If you need additional pools of addresses inside of this subnet outside the above Range, they may be specified here');
865

    
866
	if (is_array($a_pools)) {
867
		$section->addInput(new Form_StaticText(
868
			null,
869
			build_pooltable()
870
		));
871
	}
872

    
873
	$form->add($section);
874
}
875

    
876
$section = new Form_Section('Servers');
877

    
878
$section->addInput(new Form_IpAddress(
879
	'wins1',
880
	'WINS servers',
881
	$pconfig['wins1']
882
))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'WINS Server 1');
883

    
884
$section->addInput(new Form_IpAddress(
885
	'wins2',
886
	null,
887
	$pconfig['wins2']
888
))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'WINS Server 2');
889

    
890
for ($idx=1; $idx<=4; $idx++) {
891
	$section->addInput(new Form_IpAddress(
892
		'dns' . $idx,
893
		($idx == 1) ? 'DNS servers':null,
894
		$pconfig['dns' . $idx]
895
	))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'DNS Server ' . $idx)->setHelp(($idx == 4) ? 'Leave blank to use the system default DNS servers, use this interface\'s IP if DNS Forwarder or Resolver is enabled, otherwise use the servers configured on the General page':'');
896
}
897

    
898
$form->add($section);
899

    
900
$section = new Form_Section('Other options');
901

    
902
$section->addInput(new Form_IpAddress(
903
	'gateway',
904
	'Gateway',
905
	$pconfig['gateway']
906
))->setPattern('[.a-zA-Z0-9_]+')
907
  ->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 your network. Type "none" for no gateway assignment');
908

    
909
$section->addInput(new Form_Input(
910
	'domain',
911
	'Domain name',
912
	'text',
913
	$pconfig['domain']
914
))->setHelp('The default is to use the domain name of this system as the default domain name provided by DHCP. You may specify an alternate domain name here');
915

    
916
$section->addInput(new Form_Input(
917
	'domainsearchlist',
918
	'Domain search list',
919
	'text',
920
	$pconfig['domainsearchlist']
921
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator');
922

    
923
$section->addInput(new Form_Input(
924
	'deftime',
925
	'Default lease time',
926
	'number',
927
	$pconfig['deftime']
928
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds');
929

    
930
$section->addInput(new Form_Input(
931
	'maxtime',
932
	'Maximum lease time',
933
	'number',
934
	$pconfig['maxtime']
935
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds');
936

    
937
if (!is_numeric($pool) && !($act == "newpool")) {
938
	$section->addInput(new Form_IpAddress(
939
		'failover_peerip',
940
		'Failover peer IP',
941
		$pconfig['failover_peerip']
942
	))->setHelp('Leave blank to disable. Enter the interface IP address of the other machine. Machines must be using CARP.' .
943
				'Interface\'s advskew determines whether the DHCPd process is Primary or Secondary. Ensure one machine\'s advskew < 20 (and the other is > 20).');
944
}
945

    
946
if (!is_numeric($pool) && !($act == "newpool")) {
947
	$section->addInput(new Form_Checkbox(
948
		'staticarp',
949
		'Static ARP',
950
		'Enable Static ARP entries',
951
		$pconfig['staticarp']
952
	))->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.');
953

    
954
	$section->addInput(new Form_Checkbox(
955
		'dhcpleaseinlocaltime',
956
		'Time format change',
957
		'Change DHCP display lease time from UTC to local time',
958
		$pconfig['dhcpleaseinlocaltime']
959
	))->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.' .
960
				' This will be used for all DHCP interfaces lease time');
961
	$section->addInput(new Form_Checkbox(
962
		'statsgraph',
963
		'Statistics graphs',
964
		'Enable RRD statistics graphs',
965
		$pconfig['statsgraph']
966
	))->setHelp('Enable this to add DHCP leases statistics to the RRD graphs. Disabled by default.');
967
}
968

    
969
// DDNS
970
$btnadv = new Form_Button(
971
	'btnadvdns',
972
	'Advanced'
973
);
974

    
975
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
976

    
977
$section->addInput(new Form_StaticText(
978
	'Dynamic DNS',
979
	$btnadv
980
));
981

    
982
$section->addInput(new Form_Checkbox(
983
	'ddnsupdate',
984
	null,
985
	'Enable registration of DHCP client names in DNS',
986
	$pconfig['ddnsupdate']
987
));
988

    
989
$section->addInput(new Form_Input(
990
	'ddnsdomain',
991
	'DDNS Domain',
992
	'text',
993
	$pconfig['ddnsdomain']
994
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
995
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
996

    
997
$section->addInput(new Form_IpAddress(
998
	'ddnsdomainprimary',
999
	'Primary DDNS address',
1000
	$pconfig['ddnsdomainprimary']
1001
))->setHelp('Primary domain name server IP address for the dynamic domain name');
1002

    
1003
$section->addInput(new Form_Input(
1004
	'ddnsdomainkeyname',
1005
	'DNS Domain key',
1006
	'text',
1007
	$pconfig['ddnsdomainkeyname']
1008
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server');
1009

    
1010
$section->addInput(new Form_Input(
1011
	'ddnsdomainkey',
1012
	'DNS Domain key secret',
1013
	'text',
1014
	$pconfig['ddnsdomainkey']
1015
))->setHelp('Dynamic DNS domain key secret which will be used to register client names in the DNS server');
1016

    
1017
// Advanced MAC
1018
$btnadv = new Form_Button(
1019
	'btnadvmac',
1020
	'Advanced'
1021
);
1022

    
1023
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1024

    
1025
$section->addInput(new Form_StaticText(
1026
	'MAC address control',
1027
	$btnadv
1028
));
1029

    
1030
$section->addInput(new Form_Input(
1031
	'mac_allow',
1032
	'Allow',
1033
	'text',
1034
	$pconfig['mac_allow']
1035
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1036

    
1037
$section->addInput(new Form_Input(
1038
	'mac_deny',
1039
	'Deny',
1040
	'text',
1041
	$pconfig['mac_deny']
1042
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1043

    
1044
// Advanced NTP
1045
$btnadv = new Form_Button(
1046
	'btnadvntp',
1047
	'Advanced'
1048
);
1049

    
1050
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1051

    
1052
$section->addInput(new Form_StaticText(
1053
	'NTP servers',
1054
	$btnadv
1055
));
1056

    
1057
$section->addInput(new Form_IpAddress(
1058
	'ntp1',
1059
	null,
1060
	$pconfig['ntp1']
1061
))->setAttribute('placeholder', 'NTP Server 1');
1062

    
1063
$section->addInput(new Form_IpAddress(
1064
	'ntp2',
1065
	null,
1066
	$pconfig['ntp2']
1067
))->setAttribute('placeholder', 'NTP Server 2');
1068

    
1069
// Advanced TFTP
1070
$btnadv = new Form_Button(
1071
	'btnadvtftp',
1072
	'Advanced'
1073
);
1074

    
1075
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1076

    
1077
$section->addInput(new Form_StaticText(
1078
	'TFTP server',
1079
	$btnadv
1080
));
1081

    
1082
$section->addInput(new Form_IpAddress(
1083
	'tftp',
1084
	null,
1085
	$pconfig['tftp']
1086
))->setHelp('Leave blank to disable.  Enter a full hostname or IP for the TFTP server')->setPattern('[.a-zA-Z0-9_]+');
1087

    
1088
// Advanced LDAP
1089
$btnadv = new Form_Button(
1090
	'btnadvldap',
1091
	'Advanced'
1092
);
1093

    
1094
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1095

    
1096
$section->addInput(new Form_StaticText(
1097
	'LDAP URI',
1098
	$btnadv
1099
));
1100

    
1101
$section->addInput(new Form_Input(
1102
	'ldap',
1103
	null,
1104
	'text',
1105
	$pconfig['ldap']
1106
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1107

    
1108
// Advanced NETBOOT
1109
$btnadv = new Form_Button(
1110
	'btnadvboot',
1111
	'Advanced'
1112
);
1113

    
1114
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1115

    
1116
$section->addInput(new Form_StaticText(
1117
	'Network booting',
1118
	$btnadv
1119
));
1120

    
1121
$section->addInput(new Form_Checkbox(
1122
	'netboot',
1123
	null,
1124
	'Enables network booting',
1125
	$pconfig['netboot']
1126
));
1127

    
1128
$section->addInput(new Form_IpAddress(
1129
	'nextserver',
1130
	'Next Server',
1131
	$pconfig['nextserver']
1132
))->setHelp('Enter the IP address of the next server');
1133

    
1134
$section->addInput(new Form_Input(
1135
	'filename',
1136
	'Default BIOS file name',
1137
	'text',
1138
	$pconfig['filename']
1139
));
1140

    
1141
$section->addInput(new Form_Input(
1142
	'filename32',
1143
	'UEFI 32 bit file name',
1144
	'text',
1145
	$pconfig['filename32']
1146
));
1147

    
1148
$section->addInput(new Form_Input(
1149
	'filename64',
1150
	'UEFI 64 bit file name',
1151
	'text',
1152
	$pconfig['filename64']
1153
))->setHelp('You need both a filename and a boot server configured for this to work! ' .
1154
			'You will need all three filenames and a boot server configured for UEFI to work! ');
1155

    
1156
$section->addInput(new Form_Input(
1157
	'rootpath',
1158
	'Root path',
1159
	'text',
1160
	$pconfig['rootpath']
1161
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1162

    
1163
// Advanced Additional options
1164
$btnadv = new Form_Button(
1165
	'btnadvopts',
1166
	'Advanced'
1167
);
1168

    
1169
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1170

    
1171
$section->addInput(new Form_StaticText(
1172
	'Additional BOOTP/DHCP Options',
1173
	$btnadv
1174
));
1175

    
1176
$form->add($section);
1177

    
1178
$section = new Form_Section('Additional BOOTP/DHCP Options');
1179
$section->addClass('adnlopts');
1180

    
1181
$section->addInput(new Form_StaticText(
1182
	null,
1183
	'<div class="alert alert-info"> ' . gettext('Enter the DHCP option number and the value for each item you would like to include in the DHCP lease information. ' .
1184
	'For a list of available options please visit this ') . '<a href="http://www.iana.org/assignments/bootp-dhcp-parameters/" target="_blank">' . gettext("URL") . '</a></div>'
1185
));
1186

    
1187
if (!$pconfig['numberoptions']) {
1188
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1189
}
1190

    
1191
$customitemtypes = array(
1192
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1193
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1194
	'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')
1195
);
1196

    
1197
$numrows = count($item) -1;
1198
$counter = 0;
1199

    
1200
$numrows = count($pconfig['numberoptions']['item']) -1;
1201

    
1202
foreach ($pconfig['numberoptions']['item'] as $item) {
1203
	$number = $item['number'];
1204
	$itemtype = $item['type'];
1205
	$value = $item['value'];
1206

    
1207
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1208
	$group->addClass('repeatable');
1209

    
1210
	$group->add(new Form_Input(
1211
		'number' . $counter,
1212
		null,
1213
		'text',
1214
		$number
1215
	))->setHelp($numrows == $counter ? 'Number':null);
1216

    
1217

    
1218
	$group->add(new Form_Select(
1219
		'itemtype' . $counter,
1220
		null,
1221
		$itemtype,
1222
		$customitemtypes
1223
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1224

    
1225
	$group->add(new Form_Input(
1226
		'value' . $counter,
1227
		null,
1228
		'text',
1229
		$value
1230
	))->setHelp($numrows == $counter ? 'Value':null);
1231

    
1232
	$group->add(new Form_Button(
1233
		'deleterow' . $counter,
1234
		'Delete'
1235
	))->removeClass('btn-primary')->addClass('btn-warning');
1236

    
1237
	$section->add($group);
1238

    
1239
	$counter++;
1240
}
1241

    
1242
$section->addInput(new Form_Button(
1243
	'addrow',
1244
	'Add'
1245
))->removeClass('btn-primary')->addClass('btn-success');
1246

    
1247
$form->add($section);
1248

    
1249
if ($act == "newpool") {
1250
	$form->addGlobal(new Form_Input(
1251
		'act',
1252
		null,
1253
		'hidden',
1254
		'newpool'
1255
	));
1256
}
1257

    
1258
if (is_numeric($pool)) {
1259
	$form->addGlobal(new Form_Input(
1260
		'pool',
1261
		null,
1262
		'hidden',
1263
		$pool
1264
	));
1265
}
1266

    
1267
$form->addGlobal(new Form_Input(
1268
	'if',
1269
	null,
1270
	'hidden',
1271
	$if
1272
));
1273

    
1274
print($form);
1275

    
1276
// DHCP Static Mappings table
1277

    
1278
if (!is_numeric($pool) && !($act == "newpool")) {
1279
?>
1280

    
1281
<div class="panel panel-default">
1282
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCP Static Mappings for this interface")?></h2></div>
1283
	<div class="table-responsive">
1284
			<table class="table table-striped table-hover table-condensed">
1285
				<thead>
1286
					<tr>
1287
						<th><?=gettext("Static ARP")?></th>
1288
						<th><?=gettext("MAC address")?></th>
1289
						<th><?=gettext("IP address")?></th>
1290
						<th><?=gettext("Hostname")?></th>
1291
						<th><?=gettext("Description")?></th>
1292
						<th></th>
1293
					</tr>
1294
				</thead>
1295
<?php
1296
	if (is_array($a_maps)) {
1297
		$i = 0;
1298
?>
1299
				<tbody>
1300
<?php
1301
		foreach ($a_maps as $mapent) {
1302
?>
1303
					<tr>
1304
						<td align="center" ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1305
							<?php if (isset($mapent['arp_table_static_entry'])): ?>
1306
								<i class="fa fa-check"></i>
1307
							<?php endif; ?>
1308
						</td>
1309
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1310
							<?=htmlspecialchars($mapent['mac'])?>
1311
						</td>
1312
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1313
							<?=htmlspecialchars($mapent['ipaddr'])?>
1314
						</td>
1315
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1316
							<?=htmlspecialchars($mapent['hostname'])?>
1317
						</td>
1318
						<td ondblclick="document.location='services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>';">
1319
							<?=htmlspecialchars($mapent['descr'])?>
1320
						</td>
1321
						<td>
1322
							<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>"	href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>&amp;id=<?=$i?>"></a>
1323
							<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>"	href="services_dhcp.php?if=<?=htmlspecialchars($if)?>&amp;act=del&amp;id=<?=$i?>"></a>
1324
						</td>
1325
					</tr>
1326
<?php
1327
		$i++;
1328
		}
1329
?>
1330
				</tbody>
1331
<?php
1332
	}
1333
?>
1334
		</table>
1335
	</div>
1336
</div>
1337

    
1338
<nav class="action-buttons">
1339
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1340
		<i class="fa fa-plus icon-embed-btn"></i>
1341
		<?=gettext("Add")?>
1342
	</a>
1343
</nav>
1344
<?php
1345
}
1346
?>
1347

    
1348
<script type="text/javascript">
1349
//<![CDATA[
1350
events.push(function() {
1351

    
1352
	// Show advanced DNS options ======================================================================================
1353
	var showadvdns = false;
1354

    
1355
	function show_advdns() {
1356
<?php
1357
		if (!$pconfig['ddnsupdate'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1358
		    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey'])) {
1359
			$hide = false;
1360
		} else {
1361
			$hide = true;
1362
		}
1363
?>
1364
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1365

    
1366
		hideCheckbox('ddnsupdate', !showadvdns && !hide);
1367
		hideInput('ddnsdomain', !showadvdns && !hide);
1368
		hideInput('ddnsdomainprimary', !showadvdns && !hide);
1369
		hideInput('ddnsdomainkeyname', !showadvdns && !hide);
1370
		hideInput('ddnsdomainkey', !showadvdns && !hide);
1371
		hideInput('btnadvdns', hide);
1372
		showadvdns = !showadvdns;
1373
	}
1374

    
1375
	$('#btnadvdns').prop('type', 'button');
1376

    
1377
	$('#btnadvdns').click(function(event) {
1378
		show_advdns();
1379
	});
1380

    
1381
 // Show advanced MAC options ======================================================================================
1382
	var showadvmac = false;
1383

    
1384
	function show_advmac() {
1385
<?php
1386
		if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny'])) {
1387
			$hide = false;
1388
		} else {
1389
			$hide = true;
1390
		}
1391
?>
1392
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1393

    
1394
		hideInput('mac_allow', !showadvmac && !hide);
1395
		hideInput('mac_deny', !showadvmac && !hide);
1396
		hideInput('btnadvmac', hide);
1397

    
1398
		showadvmac = !showadvmac;
1399
	}
1400

    
1401
	$('#btnadvmac').prop('type', 'button');
1402

    
1403
	$('#btnadvmac').click(function(event) {
1404
		show_advmac();
1405
	});
1406

    
1407
  // Show advanced NTP options ======================================================================================
1408
	var showadvntp = false;
1409

    
1410
	function show_advntp() {
1411
<?php
1412
		if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1413
			$hide = false;
1414
		} else {
1415
			$hide = true;
1416
		}
1417
?>
1418
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1419

    
1420
		hideInput('ntp1', !showadvntp && !hide);
1421
		hideInput('ntp2', !showadvntp && !hide);
1422
		hideInput('btnadvntp', hide);
1423

    
1424
		showadvntp = !showadvntp;
1425
	}
1426

    
1427
	$('#btnadvntp').prop('type', 'button');
1428

    
1429
	$('#btnadvntp').click(function(event) {
1430
		show_advntp();
1431
	});
1432

    
1433
   // Show advanced TFTP options ======================================================================================
1434
	var showadvtftp = false;
1435

    
1436
	function show_advtftp() {
1437
<?php
1438
		if (empty($pconfig['tftp'])) {
1439
			$hide = false;
1440
		} else {
1441
			$hide = true;
1442
		}
1443
?>
1444
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1445

    
1446
		hideInput('tftp', !showadvtftp && !hide);
1447
		hideInput('btnadvtftp', hide);
1448

    
1449
		showadvtftp = !showadvtftp;
1450
	}
1451

    
1452
	$('#btnadvtftp').prop('type', 'button');
1453

    
1454
	$('#btnadvtftp').click(function(event) {
1455
		show_advtftp();
1456
	});
1457

    
1458
   // Show advanced LDAP options ======================================================================================
1459
	var showadvldap = false;
1460

    
1461
	function show_advldap() {
1462
<?php
1463
		if (empty($pconfig['ldap'])) {
1464
			$hide = false;
1465
		} else {
1466
			$hide = true;
1467
		}
1468
?>
1469
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1470

    
1471
		hideInput('ldap', !showadvldap && !hide);
1472
		hideInput('btnadvldap', hide);
1473

    
1474
		showadvldap = !showadvldap;
1475
	}
1476

    
1477
	$('#btnadvldap').prop('type', 'button');
1478

    
1479
	$('#btnadvldap').click(function(event) {
1480
		show_advldap();
1481
	});
1482

    
1483
   // Show advanced NETBOOT options ===================================================================================
1484
	var showadvboot = false;
1485

    
1486
	function show_advboot() {
1487
<?php
1488
		if (!$pconfig['netboot'] && empty($pconfig['nextserver']) && empty($pconfig['filename']) && empty($pconfig['filename32']) &&
1489
		    empty($pconfig['filename64']) && empty($pconfig['rootpath'])) {
1490
			$hide = false;
1491
		} else {
1492
			$hide = true;
1493
		}
1494
?>
1495
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1496

    
1497
		hideCheckbox('netboot', !showadvboot && !hide);
1498
		hideInput('nextserver', !showadvboot && !hide);
1499
		hideInput('filename', !showadvboot && !hide);
1500
		hideInput('filename32', !showadvboot && !hide);
1501
		hideInput('filename64', !showadvboot && !hide);
1502
		hideInput('rootpath', !showadvboot && !hide);
1503
		hideInput('btnadvboot', hide);
1504

    
1505
		showadvboot = !showadvboot;
1506
	}
1507

    
1508
	$('#btnadvboot').prop('type', 'button');
1509

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

    
1514
	// Show advanced additional opts options ===========================================================================
1515
	var showadvopts = false;
1516

    
1517
	function show_advopts() {
1518
<?php
1519
		if (empty($pconfig['numberoptions']) ||
1520
		    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1521
			$hide = false;
1522
		} else {
1523
			$hide = true;
1524
		}
1525
?>
1526
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1527

    
1528
		hideClass('adnlopts', !showadvopts && !hide);
1529
		hideInput('btnadvopts', hide);
1530

    
1531
		showadvopts = !showadvopts;
1532
	}
1533

    
1534
	$('#btnadvopts').prop('type', 'button');
1535

    
1536
	$('#btnadvopts').click(function(event) {
1537
		show_advopts();
1538
	});
1539

    
1540
	// ---------- On initial page load ------------------------------------------------------------
1541

    
1542
	show_advdns();
1543
	show_advmac();
1544
	show_advntp();
1545
	show_advtftp();
1546
	show_advldap();
1547
	show_advboot();
1548
	show_advopts();
1549

    
1550
	// Suppress "Delete row" button if there are fewer than two rows
1551
	checkLastRow();
1552
});
1553
//]]>
1554
</script>
1555

    
1556
<?php include("foot.inc");
(118-118/228)