Project

General

Profile

Download (48.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	services_dhcp.php
5
*/
6
/* ====================================================================
7
 *	Copyright (c)  2004-2015  Electric Sheep Fencing, LLC. All rights reserved.
8
 *	Copyright (c)  2004, 2005 Scott Ullrich
9
 *	Copyright (c)  2003-2004 Manuel Kasper <mk@neon1.net>
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
	pfSense_BUILDER_BINARIES:	/bin/rm
60
	pfSense_MODULE: interfaces
61
*/
62

    
63
##|+PRIV
64
##|*IDENT=page-services-dhcpserver
65
##|*NAME=Services: DHCP server page
66
##|*DESCR=Allow access to the 'Services: DHCP server' page.
67
##|*MATCH=services_dhcp.php*
68
##|-PRIV
69

    
70
require("guiconfig.inc");
71
require_once("filter.inc");
72

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

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

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

    
93
$iflist = get_configured_interface_with_descr();
94

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

    
104
		$if = $ifent;
105
		break;
106
	}
107
}
108

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

    
114
$a_pools = array();
115

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

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

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

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

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

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

    
160
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
161

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

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

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

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

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

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

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

    
219
	return true;
220
}
221

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

    
224
	unset($input_errors);
225

    
226
	$pconfig = $_POST;
227

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
372
		if ($_POST['staticarp'] && $noip) {
373
			$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.";
374
		}
375

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

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

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

    
412
			if (ip2ulong($_POST['range_from']) > ip2ulong($_POST['range_to'])) {
413
				$input_errors[] = gettext("The range is invalid (first element higher than second element).");
414
			}
415

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

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

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

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

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

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

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

    
482
		$dhcpd_enable_changed = false;
483

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

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

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

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

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

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

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

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

    
559
		$dhcpdconf['tftp'] = $_POST['tftp'];
560
		$dhcpdconf['ldap'] = $_POST['ldap'];
561
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
562
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
563
		$dhcpdconf['filename'] = $_POST['filename'];
564
		$dhcpdconf['filename32'] = $_POST['filename32'];
565
		$dhcpdconf['filename64'] = $_POST['filename64'];
566
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
567

    
568
		// Handle the custom options rowhelper
569
		if (isset($dhcpdconf['numberoptions']['item'])) {
570
			unset($dhcpdconf['numberoptions']['item']);
571
		}
572

    
573
		$dhcpdconf['numberoptions'] = $numberoptions;
574

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

    
583
		write_config();
584
	}
585
}
586

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

    
616
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
617
		$retval = 1;
618
	}
619

    
620
	$savemsg = get_std_save_message($retval);
621
}
622

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

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

    
643
		header("Location: services_dhcp.php?if={$if}");
644
		exit;
645
	}
646
}
647

    
648
// Build an HTML table that can be inseted into a Form_StaticText element
649
function build_pooltable() {
650
	global $a_pools;
651

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

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

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

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

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

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

    
687
	$pooltbl .=			'</tbody>';
688
	$pooltbl .=		'</table>';
689
	$pooltbl .= '</div>';
690

    
691
	return($pooltbl);
692
}
693

    
694
$closehead = false;
695
$pgtitle = array(gettext("Services"), gettext("DHCP server"));
696
$shortcut_section = "dhcp";
697

    
698
include("head.inc");
699

    
700
if ($input_errors)
701
	print_input_errors($input_errors);
702

    
703
if ($savemsg)
704
	print_info_box($savemsg, 'success');
705

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

    
712
if (is_subsystem_dirty('staticmaps'))
713
	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."));
714

    
715
/* active tabs */
716
$tab_array = array();
717
$tabscounter = 0;
718
$i = 0;
719

    
720
foreach ($iflist as $ifent => $ifname) {
721
	$oc = $config['interfaces'][$ifent];
722
	if ((is_array($config['dhcpd'][$ifent]) && !isset($config['dhcpd'][$ifent]['enable']) && (!is_ipaddrv4($oc['ipaddr']))) ||
723
		(!is_array($config['dhcpd'][$ifent]) && (!is_ipaddrv4($oc['ipaddr'])))) {
724
		continue;
725
	}
726

    
727
	if ($ifent == $if) {
728
		$active = true;
729
	} else {
730
		$active = false;
731
	}
732

    
733
	$tab_array[] = array($ifname, $active, "services_dhcp.php?if={$ifent}");
734
	$tabscounter++;
735
}
736

    
737
if ($tabscounter == 0) {
738
	print_info_box(gettext("The DHCP Server can only be enabled on interfaces configured with a static IPv4 address. This system has none."));
739
	include("foot.inc");
740
	exit;
741
}
742

    
743
display_top_tabs($tab_array);
744

    
745
require_once('classes/Form.class.php');
746

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

    
753
$section = new Form_Section('General Options');
754

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

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

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

    
785
$section->addInput(new Form_StaticText(
786
	'Subnet',
787
	gen_subnet($ifcfgip, $ifcfgsn)
788
));
789

    
790
$section->addInput(new Form_StaticText(
791
	'Subnet mask',
792
	gen_subnet_mask($ifcfgsn)
793
));
794

    
795
// Compose a string to display the required address ranges
796
$range_from = ip2long(long2ip32(ip2long($ifcfgip) & gen_subnet_mask_long($ifcfgsn)));
797
$range_from++;
798

    
799
$range_to = ip2long(long2ip32(ip2long($ifcfgip) | (~gen_subnet_mask_long($ifcfgsn))));
800
$range_to--;
801

    
802
$rangestr = long2ip32($range_from) . ' - ' . long2ip32($range_to);
803

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

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

    
817
$section->addInput(new Form_StaticText(
818
	'Available range',
819
	$rangestr
820
));
821

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

    
831
$group = new Form_Group('Range');
832

    
833
$group->add(new Form_IpAddress(
834
	'range_from',
835
	null,
836
	$pconfig['range_from']
837
))->setHelp('From');
838

    
839
$group->add(new Form_IpAddress(
840
	'range_to',
841
	null,
842
	$pconfig['range_to']
843
))->setHelp('To');
844

    
845
$section->add($group);
846

    
847
$form->add($section);
848

    
849
if (!is_numeric($pool) && !($act == "newpool")) {
850
	$section = new Form_Section('Additional pools');
851

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

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

    
863
	if (is_array($a_pools)) {
864
		$section->addInput(new Form_StaticText(
865
			null,
866
			build_pooltable()
867
		));
868
	}
869

    
870
	$form->add($section);
871
}
872

    
873
$section = new Form_Section('Servers');
874

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

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

    
887
for($idx=1; $idx<=4; $idx++) {
888
	$section->addInput(new Form_IpAddress(
889
		'dns' . $idx,
890
		($idx == 1) ? 'DNS servers':null,
891
		$pconfig['dns' . $idx]
892
	))->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':'');
893
}
894

    
895
$form->add($section);
896

    
897
$section = new Form_Section('Other options');
898

    
899
$section->addInput(new Form_IpAddress(
900
	'gateway',
901
	'Gateway',
902
	$pconfig['gateway']
903
))->setPattern('[.a-zA-Z0-9_]+')
904
  ->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');
905

    
906
$section->addInput(new Form_Input(
907
	'domain',
908
	'Domain name',
909
	'text',
910
	$pconfig['domain']
911
))->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');
912

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

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

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

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

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

    
951
	$section->addInput(new Form_Checkbox(
952
		'dhcpleaseinlocaltime',
953
		'Time format change',
954
		'Change DHCP display lease time from UTC to local time',
955
		$pconfig['dhcpleaseinlocaltime']
956
	))->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.' .
957
				' This will be used for all DHCP interfaces lease time');
958
}
959

    
960
// DDNS
961
$btnadv = new Form_Button(
962
	'btnadvdns',
963
	'Advanced'
964
);
965

    
966
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
967

    
968
$section->addInput(new Form_StaticText(
969
	'Dynamic DNS',
970
	$btnadv
971
));
972

    
973
$section->addInput(new Form_Checkbox(
974
	'ddnsupdate',
975
	null,
976
	'Enable registration of DHCP client names in DNS',
977
	$pconfig['ddnsupdate']
978
));
979

    
980
$section->addInput(new Form_Input(
981
	'ddnsdomain',
982
	'DDNS Domain',
983
	'number',
984
	$pconfig['ddnsdomain']
985
))->setHelp('Leave blank to disable dynamic DNS registration.' . '<br />' .
986
			'Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
987

    
988
$section->addInput(new Form_IpAddress(
989
	'ddnsdomainprimary',
990
	'Primary DDNS address',
991
	$pconfig['ddnsdomainprimary']
992
))->setHelp('Primary domain name server IP address for the dynamic domain name');
993

    
994
$section->addInput(new Form_Input(
995
	'ddnsdomainkeyname',
996
	'DNS Domain key',
997
	'text',
998
	$pconfig['ddnsdomainkeyname']
999
))->setHelp('Dynamic DNS domain key name which will be used to register client names in the DNS server');
1000

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

    
1008
// Advanced MAC
1009
$btnadv = new Form_Button(
1010
	'btnadvmac',
1011
	'Advanced'
1012
);
1013

    
1014
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1015

    
1016
$section->addInput(new Form_StaticText(
1017
	'MAC address control',
1018
	$btnadv
1019
));
1020

    
1021
$section->addInput(new Form_Input(
1022
	'mac_allow',
1023
	'Allow',
1024
	'text',
1025
	$pconfig['mac_allow']
1026
))->setHelp('List of partial MAC addresses to allow, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1027

    
1028
$section->addInput(new Form_Input(
1029
	'mac_deny',
1030
	'Deny',
1031
	'text',
1032
	$pconfig['mac_deny']
1033
))->setHelp('List of partial MAC addresses to deny access, comma separated, no spaces, e.g.: 00:00:00,01:E5:FF');
1034

    
1035
// Advanced NTP
1036
$btnadv = new Form_Button(
1037
	'btnadvntp',
1038
	'Advanced'
1039
);
1040

    
1041
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1042

    
1043
$section->addInput(new Form_StaticText(
1044
	'NTP servers',
1045
	$btnadv
1046
));
1047

    
1048
$section->addInput(new Form_IpAddress(
1049
	'ntp1',
1050
	'Allow',
1051
	$pconfig['ntp1']
1052
));
1053

    
1054
$section->addInput(new Form_IpAddress(
1055
	'ntp2',
1056
	'Deny',
1057
	$pconfig['ntp2']
1058
));
1059

    
1060
// Advanced TFTP
1061
$btnadv = new Form_Button(
1062
	'btnadvtftp',
1063
	'Advanced'
1064
);
1065

    
1066
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1067

    
1068
$section->addInput(new Form_StaticText(
1069
	'TFTP server',
1070
	$btnadv
1071
));
1072

    
1073
$section->addInput(new Form_IpAddress(
1074
	'tftp',
1075
	'Allow',
1076
	$pconfig['tftp']
1077
))->setHelp('Leave blank to disable.  Enter a full hostname or IP for the TFTP server')->setPattern('[.a-zA-Z0-9_]+');
1078

    
1079
// Advanced LDAP
1080
$btnadv = new Form_Button(
1081
	'btnadvldap',
1082
	'Advanced'
1083
);
1084

    
1085
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1086

    
1087
$section->addInput(new Form_StaticText(
1088
	'LDAP URI',
1089
	$btnadv
1090
));
1091

    
1092
$section->addInput(new Form_Input(
1093
	'ldap',
1094
	null,
1095
	'text',
1096
	$pconfig['ldap']
1097
))->setHelp('Leave blank to disable. Enter a full URI for the LDAP server in the form ldap://ldap.example.com/dc=example,dc=com ');
1098

    
1099
// Advanced NETBOOT
1100
$btnadv = new Form_Button(
1101
	'btnadvboot',
1102
	'Advanced'
1103
);
1104

    
1105
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1106

    
1107
$section->addInput(new Form_StaticText(
1108
	'Network booting',
1109
	$btnadv
1110
));
1111

    
1112
$section->addInput(new Form_Checkbox(
1113
	'netboot',
1114
	null,
1115
	'Enables network booting',
1116
	$pconfig['netboot']
1117
));
1118

    
1119
$section->addInput(new Form_IpAddress(
1120
	'nextserver',
1121
	'Next Server',
1122
	$pconfig['nextserver']
1123
))->setHelp('Enter the IP address of the next server');
1124

    
1125
$section->addInput(new Form_Input(
1126
	'filename',
1127
	'Default BIOS file name',
1128
	'text',
1129
	$pconfig['filename']
1130
));
1131

    
1132
$section->addInput(new Form_Input(
1133
	'filename32',
1134
	'UEFI 32 bit file name',
1135
	'text',
1136
	$pconfig['filename32']
1137
));
1138

    
1139
$section->addInput(new Form_Input(
1140
	'filename64',
1141
	'UEFI 64 bit file name',
1142
	'text',
1143
	$pconfig['filename64']
1144
))->setHelp('You need both a filename and a boot server configured for this to work! ' .
1145
			'You will need all three filenames and a boot server configured for UEFI to work! ');
1146

    
1147
$section->addInput(new Form_Input(
1148
	'rootpath',
1149
	'Root path',
1150
	'text',
1151
	$pconfig['rootpath']
1152
))->setHelp('string-format: iscsi:(servername):(protocol):(port):(LUN):targetname ');
1153

    
1154
// Advanced Additional options
1155
$btnadv = new Form_Button(
1156
	'btnadvopts',
1157
	'Advanced'
1158
);
1159

    
1160
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1161

    
1162
$section->addInput(new Form_StaticText(
1163
	'Additional BOOTP/DHCP Options',
1164
	$btnadv
1165
));
1166

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

    
1169
$section = new Form_Section('Additional BOOTP/DHCP Options');
1170
$section->addClass('adnlopts');
1171

    
1172
$section->addInput(new Form_StaticText(
1173
	null,
1174
	'<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. ' .
1175
	'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>'
1176
));
1177

    
1178
if(!$pconfig['numberoptions']) {
1179
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1180
}
1181

    
1182
$customitemtypes = array(
1183
	'text' => gettext('Text'), 'string' => gettext('String'), 'boolean' => gettext('Boolean'),
1184
	'unsigned integer 8' => gettext('Unsigned 8-bit integer'), 'unsigned integer 16' => gettext('Unsigned 16-bit integer'), 'unsigned integer 32' => gettext('Unsigned 32-bit integer'),
1185
	'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')
1186
);
1187

    
1188
$numrows = count($item) -1;
1189
$counter = 0;
1190

    
1191
$numrows = count($pconfig['numberoptions']['item']) -1;
1192

    
1193
foreach ($pconfig['numberoptions']['item'] as $item) {
1194
	$number = $item['number'];
1195
	$itemtype = $item['type'];
1196
	$value = $item['value'];
1197

    
1198
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1199
	$group->addClass('repeatable');
1200

    
1201
	$group->add(new Form_Input(
1202
		'number' . $counter,
1203
		null,
1204
		'text',
1205
		$number
1206
	))->setHelp($numrows == $counter ? 'Number':null);
1207

    
1208

    
1209
	$group->add(new Form_Select(
1210
		'itemtype' . $counter,
1211
		null,
1212
		$itemtype,
1213
		$customitemtypes
1214
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1215

    
1216
	$group->add(new Form_Input(
1217
		'value' . $counter,
1218
		null,
1219
		'text',
1220
		$value
1221
	))->setHelp($numrows == $counter ? 'Value':null);
1222

    
1223
	$group->add(new Form_Button(
1224
		'deleterow' . $counter,
1225
		'Delete'
1226
	))->removeClass('btn-primary')->addClass('btn-warning');
1227

    
1228
	$section->add($group);
1229

    
1230
	$counter++;
1231
}
1232

    
1233
$section->addInput(new Form_Button(
1234
	'addrow',
1235
	'Add'
1236
))->removeClass('btn-primary')->addClass('btn-success');
1237

    
1238
$form->add($section);
1239

    
1240
if ($act == "newpool") {
1241
	$form->addGlobal(new Form_Input(
1242
		'act',
1243
		null,
1244
		'hidden',
1245
		'newpool'
1246
	));
1247
}
1248

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

    
1258
$form->addGlobal(new Form_Input(
1259
	'if',
1260
	null,
1261
	'hidden',
1262
	$if
1263
));
1264

    
1265
print($form);
1266

    
1267
// DHCP Static Mappings table
1268

    
1269
if (!is_numeric($pool) && !($act == "newpool")) {
1270
?>
1271

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

    
1328
	<nav class="action-buttons">
1329
		<br />
1330
		<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success"><?=gettext("Add")?></a>
1331
	</nav>
1332
</div>
1333
<?php
1334
}
1335
?>
1336

    
1337
<script>
1338
//<![CDATA[
1339
events.push(function(){
1340

    
1341
	// Show advanced DNS options ======================================================================================
1342
	var showadvdns = false;
1343

    
1344
	function show_advdns() {
1345
<?php
1346
		if (!$pconfig['ddnsupdate'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1347
		    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey']))
1348
			$hide = false;
1349
		else
1350
			$hide = true;
1351
?>
1352
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1353

    
1354
		hideCheckbox('ddnsupdate', !showadvdns && !hide);
1355
		hideInput('ddnsdomain', !showadvdns && !hide);
1356
		hideInput('ddnsdomainprimary', !showadvdns && !hide);
1357
		hideInput('ddnsdomainkeyname', !showadvdns && !hide);
1358
		hideInput('ddnsdomainkey', !showadvdns && !hide);
1359
		hideInput('btnadvdns', hide);
1360
		showadvdns = !showadvdns;
1361
	}
1362

    
1363
	$('#btnadvdns').prop('type', 'button');
1364

    
1365
	$('#btnadvdns').click(function(event) {
1366
		show_advdns();
1367
	});
1368

    
1369
 // Show advanced MAC options ======================================================================================
1370
	var showadvmac = false;
1371

    
1372
	function show_advmac() {
1373
<?php
1374
		if (empty($pconfig['mac_allow']) && empty($pconfig['mac_deny']))
1375
			$hide = false;
1376
		else
1377
			$hide = true;
1378
?>
1379
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1380

    
1381
		hideInput('mac_allow', !showadvmac && !hide);
1382
		hideInput('mac_deny', !showadvmac && !hide);
1383
		hideInput('btnadvmac', hide);
1384

    
1385
		showadvmac = !showadvmac;
1386
	}
1387

    
1388
	$('#btnadvmac').prop('type', 'button');
1389

    
1390
	$('#btnadvmac').click(function(event) {
1391
		show_advmac();
1392
	});
1393

    
1394
  // Show advanced NTP options ======================================================================================
1395
	var showadvntp = false;
1396

    
1397
	function show_advntp() {
1398
<?php
1399
		if (empty($pconfig['ntp1']) && empty($pconfig['ntp2']))
1400
			$hide = false;
1401
		else
1402
			$hide = true;
1403
?>
1404
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1405

    
1406
		hideInput('ntp1', !showadvntp && !hide);
1407
		hideInput('ntp2', !showadvntp && !hide);
1408
		hideInput('btnadvntp', hide);
1409

    
1410
		showadvntp = !showadvntp;
1411
	}
1412

    
1413
	$('#btnadvntp').prop('type', 'button');
1414

    
1415
	$('#btnadvntp').click(function(event) {
1416
		show_advntp();
1417
	});
1418

    
1419
   // Show advanced TFTP options ======================================================================================
1420
	var showadvtftp = false;
1421

    
1422
	function show_advtftp() {
1423
<?php
1424
		if (empty($pconfig['tftp']))
1425
			$hide = false;
1426
		else
1427
			$hide = true;
1428
?>
1429
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1430

    
1431
		hideInput('tftp', !showadvtftp && !hide);
1432
		hideInput('btnadvtftp', hide);
1433

    
1434
		showadvtftp = !showadvtftp;
1435
	}
1436

    
1437
	$('#btnadvtftp').prop('type', 'button');
1438

    
1439
	$('#btnadvtftp').click(function(event) {
1440
		show_advtftp();
1441
	});
1442

    
1443
   // Show advanced LDAP options ======================================================================================
1444
	var showadvldap = false;
1445

    
1446
	function show_advldap() {
1447
<?php
1448
		if (empty($pconfig['ldap']))
1449
			$hide = false;
1450
		else
1451
			$hide = true;
1452
?>
1453
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1454

    
1455
		hideInput('ldap', !showadvldap && !hide);
1456
		hideInput('btnadvldap', hide);
1457

    
1458
		showadvldap = !showadvldap;
1459
	}
1460

    
1461
	$('#btnadvldap').prop('type', 'button');
1462

    
1463
	$('#btnadvldap').click(function(event) {
1464
		show_advldap();
1465
	});
1466

    
1467
   // Show advanced NETBOOT options ===================================================================================
1468
	var showadvboot = false;
1469

    
1470
	function show_advboot() {
1471
<?php
1472
		if (!$pconfig['netboot'] && empty($pconfig['nextserver']) && empty($pconfig['filename']) && empty($pconfig['filename32']) &&
1473
		    empty($pconfig['filename64']) && empty($pconfig['rootpath']))
1474
			$hide = false;
1475
		else
1476
			$hide = true;
1477
?>
1478
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1479

    
1480
		hideCheckbox('netboot', !showadvboot && !hide);
1481
		hideInput('nextserver', !showadvboot && !hide);
1482
		hideInput('filename', !showadvboot && !hide);
1483
		hideInput('filename32', !showadvboot && !hide);
1484
		hideInput('filename64', !showadvboot && !hide);
1485
		hideInput('rootpath', !showadvboot && !hide);
1486
		hideInput('btnadvboot', hide);
1487

    
1488
		showadvboot = !showadvboot;
1489
	}
1490

    
1491
	$('#btnadvboot').prop('type', 'button');
1492

    
1493
	$('#btnadvboot').click(function(event) {
1494
		show_advboot();
1495
	});
1496

    
1497
	// Show advanced additional opts options ===========================================================================
1498
	var showadvopts = false;
1499

    
1500
	function show_advopts() {
1501
<?php
1502
		if ( empty($pconfig['numberoptions']) ||
1503
		    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value']))))
1504
			$hide = false;
1505
		else
1506
			$hide = true;
1507
?>
1508
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1509

    
1510
		hideClass('adnlopts', !showadvopts && !hide);
1511
		hideInput('btnadvopts', hide);
1512

    
1513
		showadvopts = !showadvopts;
1514
	}
1515

    
1516
	$('#btnadvopts').prop('type', 'button');
1517

    
1518
	$('#btnadvopts').click(function(event) {
1519
		show_advopts();
1520
	});
1521

    
1522
	// ---------- On initial page load ------------------------------------------------------------
1523

    
1524
	show_advdns();
1525
	show_advmac();
1526
	show_advntp();
1527
	show_advtftp();
1528
	show_advldap();
1529
	show_advboot();
1530
	show_advopts();
1531
});
1532
//]]>
1533
</script>
1534

    
1535
<?php include("foot.inc");
(133-133/235)