Project

General

Profile

Download (48.7 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['nonak'] = isset($dhcpdconf['nonak']);
187
	$pconfig['ddnsdomain'] = $dhcpdconf['ddnsdomain'];
188
	$pconfig['ddnsdomainprimary'] = $dhcpdconf['ddnsdomainprimary'];
189
	$pconfig['ddnsdomainkeyname'] = $dhcpdconf['ddnsdomainkeyname'];
190
	$pconfig['ddnsdomainkey'] = $dhcpdconf['ddnsdomainkey'];
191
	$pconfig['ddnsupdate'] = isset($dhcpdconf['ddnsupdate']);
192
	$pconfig['mac_allow'] = $dhcpdconf['mac_allow'];
193
	$pconfig['mac_deny'] = $dhcpdconf['mac_deny'];
194
	list($pconfig['ntp1'], $pconfig['ntp2']) = $dhcpdconf['ntpserver'];
195
	$pconfig['tftp'] = $dhcpdconf['tftp'];
196
	$pconfig['ldap'] = $dhcpdconf['ldap'];
197
	$pconfig['netboot'] = isset($dhcpdconf['netboot']);
198
	$pconfig['nextserver'] = $dhcpdconf['nextserver'];
199
	$pconfig['filename'] = $dhcpdconf['filename'];
200
	$pconfig['filename32'] = $dhcpdconf['filename32'];
201
	$pconfig['filename64'] = $dhcpdconf['filename64'];
202
	$pconfig['rootpath'] = $dhcpdconf['rootpath'];
203
	$pconfig['netmask'] = $dhcpdconf['netmask'];
204
	$pconfig['numberoptions'] = $dhcpdconf['numberoptions'];
205
}
206

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

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

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

    
220
	return true;
221
}
222

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

    
225
	unset($input_errors);
226

    
227
	$pconfig = $_POST;
228

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
483
		$dhcpd_enable_changed = false;
484

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

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

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

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

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

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

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

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

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

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

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

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

    
585
		write_config();
586
	}
587
}
588

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
693
	return($pooltbl);
694
}
695

    
696
$closehead = false;
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
if ($savemsg)
706
	print_info_box($savemsg, 'success');
707

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

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

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

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

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

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

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

    
745
display_top_tabs($tab_array);
746

    
747
require_once('classes/Form.class.php');
748

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

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

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

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

    
778
$section->addInput(new Form_Checkbox(
779
	'nonak',
780
	'Ignore denied clients',
781
	'Denied clients will be ignored rather than rejected.',
782
	$pconfig['nonak']
783
));
784

    
785

    
786
if (is_numeric($pool) || ($act == "newpool")) {
787
	$section->addInput(new Form_Input(
788
		'descr',
789
		'Pool Description',
790
		'text',
791
		$pconfig['descr']
792
	));
793
}
794

    
795
$section->addInput(new Form_StaticText(
796
	'Subnet',
797
	gen_subnet($ifcfgip, $ifcfgsn)
798
));
799

    
800
$section->addInput(new Form_StaticText(
801
	'Subnet mask',
802
	gen_subnet_mask($ifcfgsn)
803
));
804

    
805
// Compose a string to display the required address ranges
806
$range_from = ip2long(long2ip32(ip2long($ifcfgip) & gen_subnet_mask_long($ifcfgsn)));
807
$range_from++;
808

    
809
$range_to = ip2long(long2ip32(ip2long($ifcfgip) | (~gen_subnet_mask_long($ifcfgsn))));
810
$range_to--;
811

    
812
$rangestr = long2ip32($range_from) . ' - ' . long2ip32($range_to);
813

    
814
if (is_numeric($pool) || ($act == "newpool")) {
815
	$rangestr .= '<br />' . 'In-use DHCP Pool Ranges:';
816
	if (is_array($config['dhcpd'][$if]['range'])) {
817
		$rangestr .= '<br />' . $config['dhcpd'][$if]['range']['from'] . ' - ' . $config['dhcpd'][$if]['range']['to'];
818
	}
819

    
820
	foreach ($a_pools as $p) {
821
		if (is_array($p['range'])) {
822
			$rangestr .= '<br />' . $p['range']['from'] . ' - ' . $p['range']['to'];
823
		}
824
	}
825
}
826

    
827
$section->addInput(new Form_StaticText(
828
	'Available range',
829
	$rangestr
830
));
831

    
832
if ($is_olsr_enabled) {
833
	$section->addInput(new Form_Select(
834
		'netmask',
835
		'Subnet mask',
836
		$pconfig['netmask'],
837
		array_combine(range(32, 1, -1), range(32, 1, -1))
838
	));
839
}
840

    
841
$group = new Form_Group('Range');
842

    
843
$group->add(new Form_IpAddress(
844
	'range_from',
845
	null,
846
	$pconfig['range_from']
847
))->setHelp('From');
848

    
849
$group->add(new Form_IpAddress(
850
	'range_to',
851
	null,
852
	$pconfig['range_to']
853
))->setHelp('To');
854

    
855
$section->add($group);
856

    
857
$form->add($section);
858

    
859
if (!is_numeric($pool) && !($act == "newpool")) {
860
	$section = new Form_Section('Additional pools');
861

    
862
	$btnaddpool = new Form_Button(
863
		'btnaddpool',
864
		'Add pool',
865
		'services_dhcp.php?if=' . htmlspecialchars($if) . '&act=newpool'
866
	);
867

    
868
	$section->addInput(new Form_StaticText(
869
		'Add',
870
		$btnaddpool
871
	))->setHelp('If you need additional pools of addresses inside of this subnet outside the above Range, they may be specified here');
872

    
873
	if (is_array($a_pools)) {
874
		$section->addInput(new Form_StaticText(
875
			null,
876
			build_pooltable()
877
		));
878
	}
879

    
880
	$form->add($section);
881
}
882

    
883
$section = new Form_Section('Servers');
884

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

    
891
$section->addInput(new Form_IpAddress(
892
	'wins2',
893
	null,
894
	$pconfig['wins2']
895
))->setPattern('[.a-zA-Z0-9_]+')->setAttribute('placeholder', 'WINS Server 2');
896

    
897
for($idx=1; $idx<=4; $idx++) {
898
	$section->addInput(new Form_IpAddress(
899
		'dns' . $idx,
900
		($idx == 1) ? 'DNS servers':null,
901
		$pconfig['dns' . $idx]
902
	))->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':'');
903
}
904

    
905
$form->add($section);
906

    
907
$section = new Form_Section('Other options');
908

    
909
$section->addInput(new Form_IpAddress(
910
	'gateway',
911
	'Gateway',
912
	$pconfig['gateway']
913
))->setPattern('[.a-zA-Z0-9_]+')
914
  ->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');
915

    
916
$section->addInput(new Form_Input(
917
	'domain',
918
	'Domain name',
919
	'text',
920
	$pconfig['domain']
921
))->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');
922

    
923
$section->addInput(new Form_Input(
924
	'domainsearchlist',
925
	'Domain search list',
926
	'text',
927
	$pconfig['domainsearchlist']
928
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator');
929

    
930
$section->addInput(new Form_Input(
931
	'deftime',
932
	'Default lease time',
933
	'number',
934
	$pconfig['deftime']
935
))->setHelp('This is used for clients that do not ask for a specific expiration time. The default is 7200 seconds');
936

    
937
$section->addInput(new Form_Input(
938
	'maxtime',
939
	'Maximum lease time',
940
	'number',
941
	$pconfig['maxtime']
942
))->setHelp('This is the maximum lease time for clients that ask for a specific expiration time. The default is 86400 seconds');
943

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

    
953
if (!is_numeric($pool) && !($act == "newpool")) {
954
	$section->addInput(new Form_Checkbox(
955
		'staticarp',
956
		'Static ARP',
957
		'Enable Static ARP entries',
958
		$pconfig['staticarp']
959
	))->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.');
960

    
961
	$section->addInput(new Form_Checkbox(
962
		'dhcpleaseinlocaltime',
963
		'Time format change',
964
		'Change DHCP display lease time from UTC to local time',
965
		$pconfig['dhcpleaseinlocaltime']
966
	))->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.' .
967
				' This will be used for all DHCP interfaces lease time');
968
}
969

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1058
$section->addInput(new Form_IpAddress(
1059
	'ntp1',
1060
	'Allow',
1061
	$pconfig['ntp1']
1062
));
1063

    
1064
$section->addInput(new Form_IpAddress(
1065
	'ntp2',
1066
	'Deny',
1067
	$pconfig['ntp2']
1068
));
1069

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1182
$section->addInput(new Form_StaticText(
1183
	null,
1184
	'<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. ' .
1185
	'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>'
1186
));
1187

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

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

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

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

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

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

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

    
1218

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

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

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

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

    
1240
	$counter++;
1241
}
1242

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

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

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

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

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

    
1275
print($form);
1276

    
1277
// DHCP Static Mappings table
1278

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

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

    
1339
<nav class="action-buttons" style="margin-top: 10px;">
1340
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1341
		<i class="fa fa-plus" style="font-size:15px; vertical-align: middle; margin-right: 6px;"></i>
1342
		<?=gettext("Add")?>
1343
	</a>
1344
</nav>
1345
<?php
1346
}
1347
?>
1348

    
1349
<script>
1350
//<![CDATA[
1351
events.push(function(){
1352

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

    
1356
	function show_advdns() {
1357
<?php
1358
		if (!$pconfig['ddnsupdate'] && empty($pconfig['ddnsdomain']) && empty($pconfig['ddnsdomainprimary']) &&
1359
		    empty($pconfig['ddnsdomainkeyname']) && empty($pconfig['ddnsdomainkey']))
1360
			$hide = false;
1361
		else
1362
			$hide = true;
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
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1392

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

    
1397
		showadvmac = !showadvmac;
1398
	}
1399

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

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

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

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

    
1418
		hideInput('ntp1', !showadvntp && !hide);
1419
		hideInput('ntp2', !showadvntp && !hide);
1420
		hideInput('btnadvntp', hide);
1421

    
1422
		showadvntp = !showadvntp;
1423
	}
1424

    
1425
	$('#btnadvntp').prop('type', 'button');
1426

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

    
1431
   // Show advanced TFTP options ======================================================================================
1432
	var showadvtftp = false;
1433

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

    
1443
		hideInput('tftp', !showadvtftp && !hide);
1444
		hideInput('btnadvtftp', hide);
1445

    
1446
		showadvtftp = !showadvtftp;
1447
	}
1448

    
1449
	$('#btnadvtftp').prop('type', 'button');
1450

    
1451
	$('#btnadvtftp').click(function(event) {
1452
		show_advtftp();
1453
	});
1454

    
1455
   // Show advanced LDAP options ======================================================================================
1456
	var showadvldap = false;
1457

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

    
1467
		hideInput('ldap', !showadvldap && !hide);
1468
		hideInput('btnadvldap', hide);
1469

    
1470
		showadvldap = !showadvldap;
1471
	}
1472

    
1473
	$('#btnadvldap').prop('type', 'button');
1474

    
1475
	$('#btnadvldap').click(function(event) {
1476
		show_advldap();
1477
	});
1478

    
1479
   // Show advanced NETBOOT options ===================================================================================
1480
	var showadvboot = false;
1481

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

    
1492
		hideCheckbox('netboot', !showadvboot && !hide);
1493
		hideInput('nextserver', !showadvboot && !hide);
1494
		hideInput('filename', !showadvboot && !hide);
1495
		hideInput('filename32', !showadvboot && !hide);
1496
		hideInput('filename64', !showadvboot && !hide);
1497
		hideInput('rootpath', !showadvboot && !hide);
1498
		hideInput('btnadvboot', hide);
1499

    
1500
		showadvboot = !showadvboot;
1501
	}
1502

    
1503
	$('#btnadvboot').prop('type', 'button');
1504

    
1505
	$('#btnadvboot').click(function(event) {
1506
		show_advboot();
1507
	});
1508

    
1509
	// Show advanced additional opts options ===========================================================================
1510
	var showadvopts = false;
1511

    
1512
	function show_advopts() {
1513
<?php
1514
		if ( empty($pconfig['numberoptions']) ||
1515
		    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value']))))
1516
			$hide = false;
1517
		else
1518
			$hide = true;
1519
?>
1520
		var hide = <?php if($hide) {echo 'true';} else {echo 'false';} ?>;
1521

    
1522
		hideClass('adnlopts', !showadvopts && !hide);
1523
		hideInput('btnadvopts', hide);
1524

    
1525
		showadvopts = !showadvopts;
1526
	}
1527

    
1528
	$('#btnadvopts').prop('type', 'button');
1529

    
1530
	$('#btnadvopts').click(function(event) {
1531
		show_advopts();
1532
	});
1533

    
1534
	// ---------- On initial page load ------------------------------------------------------------
1535

    
1536
	show_advdns();
1537
	show_advmac();
1538
	show_advntp();
1539
	show_advtftp();
1540
	show_advldap();
1541
	show_advboot();
1542
	show_advopts();
1543

    
1544
	// Suppress "Delete row" button if there are fewer than two rows
1545
	checkLastRow();
1546
});
1547
//]]>
1548
</script>
1549

    
1550
<?php include("foot.inc");
(132-132/234)