Project

General

Profile

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

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

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

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

    
95
$iflist = get_configured_interface_with_descr();
96

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

    
106
		$if = $ifent;
107
		break;
108
	}
109
}
110

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

    
116
$a_pools = array();
117

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

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

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

    
134
	$a_pools = &$config['dhcpd'][$if]['pool'];
135

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

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

    
162
		$pconfig['dhcpleaseinlocaltime'] = $dhcpleaseinlocaltime;
163

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

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

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

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

    
209
$ifcfgip = $config['interfaces'][$if]['ipaddr'];
210
$ifcfgsn = $config['interfaces'][$if]['subnet'];
211

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

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

    
222
	return true;
223
}
224

    
225
if (isset($_POST['submit'])) {
226

    
227
	unset($input_errors);
228

    
229
	$pconfig = $_POST;
230

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

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

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

    
250
		do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors);
251

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
485
		$dhcpd_enable_changed = false;
486

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

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

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

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

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

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

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

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

    
562
		$dhcpdconf['tftp'] = $_POST['tftp'];
563
		$dhcpdconf['ldap'] = $_POST['ldap'];
564
		$dhcpdconf['netboot'] = ($_POST['netboot']) ? true : false;
565
		$dhcpdconf['nextserver'] = $_POST['nextserver'];
566
		$dhcpdconf['filename'] = $_POST['filename'];
567
		$dhcpdconf['filename32'] = $_POST['filename32'];
568
		$dhcpdconf['filename64'] = $_POST['filename64'];
569
		$dhcpdconf['rootpath'] = $_POST['rootpath'];
570
		unset($dhcpdconf['statsgraph']);
571
		if ($_POST['statsgraph']) {
572
			$dhcpdconf['statsgraph'] = $_POST['statsgraph'];
573
			enable_rrd_graphing();
574
		}
575

    
576
		// Handle the custom options rowhelper
577
		if (isset($dhcpdconf['numberoptions']['item'])) {
578
			unset($dhcpdconf['numberoptions']['item']);
579
		}
580

    
581
		$dhcpdconf['numberoptions'] = $numberoptions;
582

    
583
		if (is_numeric($pool) && is_array($a_pools[$pool])) {
584
			$a_pools[$pool] = $dhcpdconf;
585
		} elseif ($act == "newpool") {
586
			$a_pools[] = $dhcpdconf;
587
		} else {
588
			$config['dhcpd'][$if] = $dhcpdconf;
589
		}
590

    
591
		write_config();
592
	}
593
}
594

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

    
624
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
625
		$retval = 1;
626
	}
627

    
628
	$savemsg = get_std_save_message($retval);
629
}
630

    
631
if ($act == "delpool") {
632
	if ($a_pools[$_GET['id']]) {
633
		unset($a_pools[$_GET['id']]);
634
		write_config();
635
		header("Location: services_dhcp.php?if={$if}");
636
		exit;
637
	}
638
}
639

    
640
if ($act == "del") {
641
	if ($a_maps[$_GET['id']]) {
642
		unset($a_maps[$_GET['id']]);
643
		write_config();
644
		if (isset($config['dhcpd'][$if]['enable'])) {
645
			mark_subsystem_dirty('staticmaps');
646
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic'])) {
647
				mark_subsystem_dirty('hosts');
648
			}
649
		}
650

    
651
		header("Location: services_dhcp.php?if={$if}");
652
		exit;
653
	}
654
}
655

    
656
// Build an HTML table that can be inserted into a Form_StaticText element
657
function build_pooltable() {
658
	global $a_pools;
659

    
660
	$pooltbl =	'<div class="table-responsive">';
661
	$pooltbl .=		'<table class="table table-striped table-hover table-condensed">';
662
	$pooltbl .=			'<thead>';
663
	$pooltbl .=				'<tr>';
664
	$pooltbl .=					'<th>' . gettext("Pool Start") . '</th>';
665
	$pooltbl .=					'<th>' . gettext("Pool End") . '</th>';
666
	$pooltbl .=					'<th>' . gettext("Description") . '</th>';
667
	$pooltbl .=					'<th></th>';
668
	$pooltbl .=				'</tr>';
669
	$pooltbl .=			'</thead>';
670
	$pooltbl .=			'<tbody>';
671

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

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

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

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

    
688
				$pooltbl .= '<a class="btn btn-xs btn-danger" href="services_dhcp.php?if=' . htmlspecialchars($if) . '&act=delpool&id=' . $i . '" />' . gettext('Delete') . '</a></td>';
689
				$pooltbl .= '</tr>';
690
			}
691
		$i++;
692
		}
693
	}
694

    
695
	$pooltbl .=			'</tbody>';
696
	$pooltbl .=		'</table>';
697
	$pooltbl .= '</div>';
698

    
699
	return($pooltbl);
700
}
701

    
702
$closehead = false;
703
$pgtitle = array(gettext("Services"), gettext("DHCP Server"));
704
$shortcut_section = "dhcp";
705

    
706
include("head.inc");
707

    
708
if ($input_errors)
709
	print_input_errors($input_errors);
710

    
711
if ($savemsg)
712
	print_info_box($savemsg, 'success');
713

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

    
720
if (is_subsystem_dirty('staticmaps'))
721
	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."));
722

    
723
/* active tabs */
724
$tab_array = array();
725
$tabscounter = 0;
726
$i = 0;
727

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

    
735
	if ($ifent == $if) {
736
		$active = true;
737
	} else {
738
		$active = false;
739
	}
740

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

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

    
751
display_top_tabs($tab_array);
752

    
753
require_once('classes/Form.class.php');
754

    
755
// This form uses a non-standard submit button name
756
$form = new Form(new Form_Button(
757
	'submit',
758
	gettext("Save")
759
));
760

    
761
$section = new Form_Section('General Options');
762

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

    
777
$section->addInput(new Form_Checkbox(
778
	'denyunknown',
779
	'Deny unknown clients',
780
	'Only the clients defined below will get DHCP leases from this server.',
781
	$pconfig['denyunknown']
782
));
783

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

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

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

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

    
807
$range_to = ip2long(long2ip32(ip2long($ifcfgip) | (~gen_subnet_mask_long($ifcfgsn))));
808
$range_to--;
809

    
810
$rangestr = long2ip32($range_from) . ' - ' . long2ip32($range_to);
811

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

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

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

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

    
839
$group = new Form_Group('Range');
840

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

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

    
853
$section->add($group);
854

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

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

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

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

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

    
878
	$form->add($section);
879
}
880

    
881
$section = new Form_Section('Servers');
882

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

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

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

    
903
$form->add($section);
904

    
905
$section = new Form_Section('Other options');
906

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

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

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

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

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

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

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

    
959
	$section->addInput(new Form_Checkbox(
960
		'dhcpleaseinlocaltime',
961
		'Time format change',
962
		'Change DHCP display lease time from UTC to local time',
963
		$pconfig['dhcpleaseinlocaltime']
964
	))->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.' .
965
				' This will be used for all DHCP interfaces lease time');
966
	$section->addInput(new Form_Checkbox(
967
		'statsgraph',
968
		'RRD graphs',
969
		'Enable RRD graphs',
970
		$pconfig['statsgraph']
971
	))->setHelp('By default RRD graphs are disabled.');
972
}
973

    
974
// DDNS
975
$btnadv = new Form_Button(
976
	'btnadvdns',
977
	'Advanced'
978
);
979

    
980
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
981

    
982
$section->addInput(new Form_StaticText(
983
	'Dynamic DNS',
984
	$btnadv
985
));
986

    
987
$section->addInput(new Form_Checkbox(
988
	'ddnsupdate',
989
	null,
990
	'Enable registration of DHCP client names in DNS',
991
	$pconfig['ddnsupdate']
992
));
993

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

    
1002
$section->addInput(new Form_IpAddress(
1003
	'ddnsdomainprimary',
1004
	'Primary DDNS address',
1005
	$pconfig['ddnsdomainprimary']
1006
))->setHelp('Primary domain name server IP address for the dynamic domain name');
1007

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

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

    
1022
// Advanced MAC
1023
$btnadv = new Form_Button(
1024
	'btnadvmac',
1025
	'Advanced'
1026
);
1027

    
1028
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1029

    
1030
$section->addInput(new Form_StaticText(
1031
	'MAC address control',
1032
	$btnadv
1033
));
1034

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

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

    
1049
// Advanced NTP
1050
$btnadv = new Form_Button(
1051
	'btnadvntp',
1052
	'Advanced'
1053
);
1054

    
1055
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1056

    
1057
$section->addInput(new Form_StaticText(
1058
	'NTP servers',
1059
	$btnadv
1060
));
1061

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

    
1068
$section->addInput(new Form_IpAddress(
1069
	'ntp2',
1070
	null,
1071
	$pconfig['ntp2']
1072
))->setAttribute('placeholder', 'NTP Server 2');
1073

    
1074
// Advanced TFTP
1075
$btnadv = new Form_Button(
1076
	'btnadvtftp',
1077
	'Advanced'
1078
);
1079

    
1080
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1081

    
1082
$section->addInput(new Form_StaticText(
1083
	'TFTP server',
1084
	$btnadv
1085
));
1086

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

    
1093
// Advanced LDAP
1094
$btnadv = new Form_Button(
1095
	'btnadvldap',
1096
	'Advanced'
1097
);
1098

    
1099
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1100

    
1101
$section->addInput(new Form_StaticText(
1102
	'LDAP URI',
1103
	$btnadv
1104
));
1105

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

    
1113
// Advanced NETBOOT
1114
$btnadv = new Form_Button(
1115
	'btnadvboot',
1116
	'Advanced'
1117
);
1118

    
1119
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1120

    
1121
$section->addInput(new Form_StaticText(
1122
	'Network booting',
1123
	$btnadv
1124
));
1125

    
1126
$section->addInput(new Form_Checkbox(
1127
	'netboot',
1128
	null,
1129
	'Enables network booting',
1130
	$pconfig['netboot']
1131
));
1132

    
1133
$section->addInput(new Form_IpAddress(
1134
	'nextserver',
1135
	'Next Server',
1136
	$pconfig['nextserver']
1137
))->setHelp('Enter the IP address of the next server');
1138

    
1139
$section->addInput(new Form_Input(
1140
	'filename',
1141
	'Default BIOS file name',
1142
	'text',
1143
	$pconfig['filename']
1144
));
1145

    
1146
$section->addInput(new Form_Input(
1147
	'filename32',
1148
	'UEFI 32 bit file name',
1149
	'text',
1150
	$pconfig['filename32']
1151
));
1152

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

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

    
1168
// Advanced Additional options
1169
$btnadv = new Form_Button(
1170
	'btnadvopts',
1171
	'Advanced'
1172
);
1173

    
1174
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1175

    
1176
$section->addInput(new Form_StaticText(
1177
	'Additional BOOTP/DHCP Options',
1178
	$btnadv
1179
));
1180

    
1181
$form->add($section);
1182

    
1183
$section = new Form_Section('Additional BOOTP/DHCP Options');
1184
$section->addClass('adnlopts');
1185

    
1186
$section->addInput(new Form_StaticText(
1187
	null,
1188
	'<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. ' .
1189
	'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>'
1190
));
1191

    
1192
if(!$pconfig['numberoptions']) {
1193
	$pconfig['numberoptions']['item']  = array(array('number' => '', 'type' => 'text', 'value' => ''));
1194
}
1195

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

    
1202
$numrows = count($item) -1;
1203
$counter = 0;
1204

    
1205
$numrows = count($pconfig['numberoptions']['item']) -1;
1206

    
1207
foreach ($pconfig['numberoptions']['item'] as $item) {
1208
	$number = $item['number'];
1209
	$itemtype = $item['type'];
1210
	$value = $item['value'];
1211

    
1212
	$group = new Form_Group(($counter == 0) ? 'Option':null);
1213
	$group->addClass('repeatable');
1214

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

    
1222

    
1223
	$group->add(new Form_Select(
1224
		'itemtype' . $counter,
1225
		null,
1226
		$itemtype,
1227
		$customitemtypes
1228
	))->setWidth(3)->setHelp($numrows == $counter ? 'Type':null);
1229

    
1230
	$group->add(new Form_Input(
1231
		'value' . $counter,
1232
		null,
1233
		'text',
1234
		$value
1235
	))->setHelp($numrows == $counter ? 'Value':null);
1236

    
1237
	$group->add(new Form_Button(
1238
		'deleterow' . $counter,
1239
		'Delete'
1240
	))->removeClass('btn-primary')->addClass('btn-warning');
1241

    
1242
	$section->add($group);
1243

    
1244
	$counter++;
1245
}
1246

    
1247
$section->addInput(new Form_Button(
1248
	'addrow',
1249
	'Add'
1250
))->removeClass('btn-primary')->addClass('btn-success');
1251

    
1252
$form->add($section);
1253

    
1254
if ($act == "newpool") {
1255
	$form->addGlobal(new Form_Input(
1256
		'act',
1257
		null,
1258
		'hidden',
1259
		'newpool'
1260
	));
1261
}
1262

    
1263
if (is_numeric($pool)) {
1264
	$form->addGlobal(new Form_Input(
1265
		'pool',
1266
		null,
1267
		'hidden',
1268
		$pool
1269
	));
1270
}
1271

    
1272
$form->addGlobal(new Form_Input(
1273
	'if',
1274
	null,
1275
	'hidden',
1276
	$if
1277
));
1278

    
1279
print($form);
1280

    
1281
// DHCP Static Mappings table
1282

    
1283
if (!is_numeric($pool) && !($act == "newpool")) {
1284
?>
1285

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

    
1343
<nav class="action-buttons">
1344
	<a href="services_dhcp_edit.php?if=<?=htmlspecialchars($if)?>" class="btn btn-sm btn-success">
1345
		<i class="fa fa-plus icon-embed-btn"></i>
1346
		<?=gettext("Add")?>
1347
	</a>
1348
</nav>
1349
<?php
1350
}
1351
?>
1352

    
1353
<script>
1354
//<![CDATA[
1355
events.push(function(){
1356

    
1357
	// Show advanced DNS options ======================================================================================
1358
	var showadvdns = false;
1359

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

    
1370
		hideCheckbox('ddnsupdate', !showadvdns && !hide);
1371
		hideInput('ddnsdomain', !showadvdns && !hide);
1372
		hideInput('ddnsdomainprimary', !showadvdns && !hide);
1373
		hideInput('ddnsdomainkeyname', !showadvdns && !hide);
1374
		hideInput('ddnsdomainkey', !showadvdns && !hide);
1375
		hideInput('btnadvdns', hide);
1376
		showadvdns = !showadvdns;
1377
	}
1378

    
1379
	$('#btnadvdns').prop('type', 'button');
1380

    
1381
	$('#btnadvdns').click(function(event) {
1382
		show_advdns();
1383
	});
1384

    
1385
 // Show advanced MAC options ======================================================================================
1386
	var showadvmac = false;
1387

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

    
1397
		hideInput('mac_allow', !showadvmac && !hide);
1398
		hideInput('mac_deny', !showadvmac && !hide);
1399
		hideInput('btnadvmac', hide);
1400

    
1401
		showadvmac = !showadvmac;
1402
	}
1403

    
1404
	$('#btnadvmac').prop('type', 'button');
1405

    
1406
	$('#btnadvmac').click(function(event) {
1407
		show_advmac();
1408
	});
1409

    
1410
  // Show advanced NTP options ======================================================================================
1411
	var showadvntp = false;
1412

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

    
1422
		hideInput('ntp1', !showadvntp && !hide);
1423
		hideInput('ntp2', !showadvntp && !hide);
1424
		hideInput('btnadvntp', hide);
1425

    
1426
		showadvntp = !showadvntp;
1427
	}
1428

    
1429
	$('#btnadvntp').prop('type', 'button');
1430

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

    
1435
   // Show advanced TFTP options ======================================================================================
1436
	var showadvtftp = false;
1437

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

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

    
1450
		showadvtftp = !showadvtftp;
1451
	}
1452

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

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

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

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

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

    
1474
		showadvldap = !showadvldap;
1475
	}
1476

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

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

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

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

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

    
1504
		showadvboot = !showadvboot;
1505
	}
1506

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

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

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

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

    
1526
		hideClass('adnlopts', !showadvopts && !hide);
1527
		hideInput('btnadvopts', hide);
1528

    
1529
		showadvopts = !showadvopts;
1530
	}
1531

    
1532
	$('#btnadvopts').prop('type', 'button');
1533

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

    
1538
	// ---------- On initial page load ------------------------------------------------------------
1539

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

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

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