Project

General

Profile

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

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

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

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

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

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

    
91
$iflist = get_configured_interface_with_descr();
92

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

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

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

    
112
$a_pools = array();
113

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

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

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

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

    
132
	if (is_numeric($pool) && $a_pools[$pool]) {
133
		$dhcpdconf = &$a_pools[$pool];
134
	} elseif ($act == "newpool") {
135
		$dhcpdconf = array();
136
	} else {
137
		$dhcpdconf = &$config['dhcpd'][$if];
138
	}
139

    
140
	if (!is_array($config['dhcpd'][$if]['staticmap'])) {
141
		$dhcpdconf['staticmap'] = array();
142
	}
143

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

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

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

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

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

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

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

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

    
218
	return true;
219
}
220

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

    
223
	unset($input_errors);
224

    
225
	$pconfig = $_POST;
226

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

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

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

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

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

    
268
		if (($_POST['dns1'] && !is_ipaddrv4($_POST['dns1'])) || ($_POST['dns2'] && !is_ipaddrv4($_POST['dns2'])) || ($_POST['dns3'] && !is_ipaddrv4($_POST['dns3'])) || ($_POST['dns4'] && !is_ipaddrv4($_POST['dns4']))) {
269
			$input_errors[] = gettext("A valid IP address must be specified for each of the DNS servers.");
270
		}
271

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
414
			if (is_numeric($pool) || ($act == "newpool")) {
415
				if (!((ip2ulong($_POST['range_from']) > ip2ulong($config['dhcpd'][$if]['range']['to'])) ||
416
				      (ip2ulong($_POST['range_to']) < ip2ulong($config['dhcpd'][$if]['range']['from'])))) {
417
					$input_errors[] = gettext("The specified range must not be within the DHCP range for this interface.");
418
				}
419
			}
420

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

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

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

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

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

    
478
		$dhcpd_enable_changed = false;
479

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

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

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

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

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

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

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

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

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

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

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

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

    
584
		write_config();
585
	}
586
}
587

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
692
	return($pooltbl);
693
}
694

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

    
698
include("head.inc");
699

    
700
if ($input_errors) {
701
	print_input_errors($input_errors);
702
}
703

    
704
if ($savemsg) {
705
	print_info_box($savemsg, 'success');
706
}
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

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

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

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

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

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

    
746
display_top_tabs($tab_array);
747

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

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

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

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

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

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

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

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

    
800
$range_to = ip2long(gen_subnetv4_max($ifcfgip, $ifcfgsn));
801
$range_to--;
802

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
944
if (!is_numeric($pool) && !($act == "newpool")) {
945
	$section->addInput(new Form_Checkbox(
946
		'staticarp',
947
		'Static ARP',
948
		'Enable Static ARP entries',
949
		$pconfig['staticarp']
950
	))->setHelp('This option persists even if DHCP server is disabled. Only the machines listed below will be able to communicate with the firewall on this interface.');
951

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

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

    
973
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
974

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

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

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

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

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

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

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

    
1021
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1022

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

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

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

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

    
1048
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1049

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

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

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

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

    
1073
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1074

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

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

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

    
1092
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1093

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

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

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

    
1112
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1113

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

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

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

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

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

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

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

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

    
1167
$btnadv->removeClass('btn-primary')->addClass('btn-default btn-sm');
1168

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

    
1174
$form->add($section);
1175

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

    
1179
$section->addInput(new Form_StaticText(
1180
	null,
1181
	'<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. ' .
1182
	'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>'
1183
));
1184

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

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

    
1195
$numrows = count($item) -1;
1196
$counter = 0;
1197

    
1198
$numrows = count($pconfig['numberoptions']['item']) -1;
1199

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

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

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

    
1215

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

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

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

    
1235
	$section->add($group);
1236

    
1237
	$counter++;
1238
}
1239

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

    
1245
$form->add($section);
1246

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

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

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

    
1272
print($form);
1273

    
1274
// DHCP Static Mappings table
1275

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

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

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

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

    
1350
	// Show advanced DNS options ======================================================================================
1351
	var showadvdns = false;
1352

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

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

    
1373
	$('#btnadvdns').prop('type', 'button');
1374

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

    
1379
 // Show advanced MAC options ======================================================================================
1380
	var showadvmac = false;
1381

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

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

    
1396
		showadvmac = !showadvmac;
1397
	}
1398

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

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

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

    
1408
	function show_advntp() {
1409
<?php
1410
		if (empty($pconfig['ntp1']) && empty($pconfig['ntp2'])) {
1411
			$hide = false;
1412
		} else {
1413
			$hide = true;
1414
		}
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
?>
1442
		var hide = <?php if ($hide) {echo 'true';} else {echo 'false';} ?>;
1443

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

    
1447
		showadvtftp = !showadvtftp;
1448
	}
1449

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

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

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

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

    
1469
		hideInput('ldap', !showadvldap && !hide);
1470
		hideInput('btnadvldap', hide);
1471

    
1472
		showadvldap = !showadvldap;
1473
	}
1474

    
1475
	$('#btnadvldap').prop('type', 'button');
1476

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

    
1481
   // Show advanced NETBOOT options ===================================================================================
1482
	var showadvboot = false;
1483

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

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

    
1503
		showadvboot = !showadvboot;
1504
	}
1505

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

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

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

    
1515
	function show_advopts() {
1516
<?php
1517
		if (empty($pconfig['numberoptions']) ||
1518
		    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1519
			$hide = false;
1520
		} else {
1521
			$hide = true;
1522
		}
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");
(118-118/229)