Project

General

Profile

Download (40.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services_dhcpv6.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2021 Rubicon Communications, LLC (Netgate)
9
 * Copyright (c) 2010 Seth Mos <seth.mos@dds.nl>
10
 * All rights reserved.
11
 *
12
 * originally based on m0n0wall (http://m0n0.ch/wall)
13
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
 * All rights reserved.
15
 *
16
 * Licensed under the Apache License, Version 2.0 (the "License");
17
 * you may not use this file except in compliance with the License.
18
 * You may obtain a copy of the License at
19
 *
20
 * http://www.apache.org/licenses/LICENSE-2.0
21
 *
22
 * Unless required by applicable law or agreed to in writing, software
23
 * distributed under the License is distributed on an "AS IS" BASIS,
24
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25
 * See the License for the specific language governing permissions and
26
 * limitations under the License.
27
 */
28

    
29
##|+PRIV
30
##|*IDENT=page-services-dhcpv6server
31
##|*NAME=Services: DHCPv6 Server
32
##|*DESCR=Allow access to the 'Services: DHCPv6 Server' page.
33
##|*MATCH=services_dhcpv6.php*
34
##|-PRIV
35

    
36
require_once("guiconfig.inc");
37
require_once("filter.inc");
38

    
39
function dhcpv6_apply_changes($dhcpdv6_enable_changed) {
40
	global $config, $g;
41

    
42
	$retval = 0;
43
	$retvaldhcp = 0;
44
	$retvaldns = 0;
45
	/* Stop DHCPv6 so we can cleanup leases */
46
	killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
47
	// dhcp_clean_leases();
48
	/* dnsmasq_configure calls dhcpd_configure */
49
	/* no need to restart dhcpd twice */
50
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
51
		$retvaldns |= services_dnsmasq_configure();
52
		if ($retvaldns == 0) {
53
			clear_subsystem_dirty('hosts');
54
			clear_subsystem_dirty('staticmaps');
55
		}
56
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
57
		$retvaldns |= services_unbound_configure();
58
		if ($retvaldns == 0) {
59
			clear_subsystem_dirty('unbound');
60
			clear_subsystem_dirty('staticmaps');
61
		}
62
	} else {
63
		$retvaldhcp |= services_dhcpd_configure();
64
		if ($retvaldhcp == 0) {
65
			clear_subsystem_dirty('staticmaps');
66
		}
67
	}
68
	/* BIND package - Bug #3710 */
69
	if (!function_exists('is_package_installed')) {
70
		require_once('pkg-utils.inc');
71
	}
72
	if (is_package_installed('pfSense-pkg-bind') && isset($config['installedpackages']['bind']['config'][0]['enable_bind'])) {
73
		$reloadbind = false;
74
		if (is_array($config['installedpackages']['bindzone'])) {
75
			$bindzone = $config['installedpackages']['bindzone']['config'];
76
		} else {
77
			$bindzone = array();
78
		}
79
		for ($x = 0; $x < sizeof($bindzone); $x++) {
80
			$zone = $bindzone[$x];
81
			if ($zone['regdhcpstatic'] == 'on') {
82
				$reloadbind = true;
83
				break;
84
			}
85
		}
86
		if ($reloadbind === true) {
87
			if (file_exists("/usr/local/pkg/bind.inc")) {
88
				require_once("/usr/local/pkg/bind.inc");
89
				bind_sync();
90
			}
91
		}
92
	}
93
	if ($dhcpdv6_enable_changed) {
94
		$retvalfc |= filter_configure();
95
	}
96
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
97
		$retval = 1;
98
	}
99
	return $retval;
100
}
101

    
102
if (!$g['services_dhcp_server_enable']) {
103
	header("Location: /");
104
	exit;
105
}
106

    
107
$if = $_REQUEST['if'];
108
$iflist = get_configured_interface_with_descr();
109
$iflist = array_merge($iflist, get_configured_pppoe_server_interfaces());
110

    
111
/* set the starting interface */
112
if (!$if || !isset($iflist[$if])) {
113
	foreach ($iflist as $ifent => $ifname) {
114
		$oc = $config['interfaces'][$ifent];
115
		$valid_if_ipaddrv6 = (bool) ($oc['ipaddrv6'] == 'track6' ||
116
		    (is_ipaddrv6($oc['ipaddrv6']) &&
117
		    !is_linklocal($oc['ipaddrv6'])));
118

    
119
		if ((!is_array($config['dhcpdv6'][$ifent]) ||
120
		    !isset($config['dhcpdv6'][$ifent]['enable'])) &&
121
		    !$valid_if_ipaddrv6) {
122
			continue;
123
		}
124
		$if = $ifent;
125
		break;
126
	}
127
}
128

    
129
if (is_array($config['dhcpdv6'][$if])) {
130
	/* DHCPv6 */
131
	if (is_array($config['dhcpdv6'][$if]['range'])) {
132
		$pconfig['range_from'] = $config['dhcpdv6'][$if]['range']['from'];
133
		$pconfig['range_to'] = $config['dhcpdv6'][$if]['range']['to'];
134
	}
135
	if (is_array($config['dhcpdv6'][$if]['prefixrange'])) {
136
		$pconfig['prefixrange_from'] = $config['dhcpdv6'][$if]['prefixrange']['from'];
137
		$pconfig['prefixrange_to'] = $config['dhcpdv6'][$if]['prefixrange']['to'];
138
		$pconfig['prefixrange_length'] = $config['dhcpdv6'][$if]['prefixrange']['prefixlength'];
139
	}
140
	$pconfig['deftime'] = $config['dhcpdv6'][$if]['defaultleasetime'];
141
	$pconfig['maxtime'] = $config['dhcpdv6'][$if]['maxleasetime'];
142
	$pconfig['domain'] = $config['dhcpdv6'][$if]['domain'];
143
	$pconfig['domainsearchlist'] = $config['dhcpdv6'][$if]['domainsearchlist'];
144
	list($pconfig['wins1'], $pconfig['wins2']) = $config['dhcpdv6'][$if]['winsserver'];
145
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $config['dhcpdv6'][$if]['dnsserver'];
146
	$pconfig['dhcp6c-dns'] = ($config['dhcpdv6'][$if]['dhcp6c-dns'] != 'disabled') ? "enabled" : "disabled";
147
	$pconfig['enable'] = isset($config['dhcpdv6'][$if]['enable']);
148
	$pconfig['ddnsdomain'] = $config['dhcpdv6'][$if]['ddnsdomain'];
149
	$pconfig['ddnsdomainprimary'] = $config['dhcpdv6'][$if]['ddnsdomainprimary'];
150
	$pconfig['ddnsdomainsecondary'] = $config['dhcpdv6'][$if]['ddnsdomainsecondary'];
151
	$pconfig['ddnsdomainkeyname'] = $config['dhcpdv6'][$if]['ddnsdomainkeyname'];
152
	$pconfig['ddnsdomainkeyalgorithm'] = $config['dhcpdv6'][$if]['ddnsdomainkeyalgorithm'];
153
	$pconfig['ddnsdomainkey'] = $config['dhcpdv6'][$if]['ddnsdomainkey'];
154
	$pconfig['ddnsupdate'] = isset($config['dhcpdv6'][$if]['ddnsupdate']);
155
	$pconfig['ddnsforcehostname'] = isset($config['dhcpdv6'][$if]['ddnsforcehostname']);
156
	$pconfig['ddnsreverse'] = isset($config['dhcpdv6'][$if]['ddnsreverse']);
157
	$pconfig['ddnsclientupdates'] = $config['dhcpdv6'][$if]['ddnsclientupdates'];
158
	list($pconfig['ntp1'], $pconfig['ntp2'], $pconfig['ntp3'] ) = $config['dhcpdv6'][$if]['ntpserver'];
159
	$pconfig['tftp'] = $config['dhcpdv6'][$if]['tftp'];
160
	$pconfig['ldap'] = $config['dhcpdv6'][$if]['ldap'];
161
	$pconfig['netboot'] = isset($config['dhcpdv6'][$if]['netboot']);
162
	$pconfig['bootfile_url'] = $config['dhcpdv6'][$if]['bootfile_url'];
163
	$pconfig['netmask'] = $config['dhcpdv6'][$if]['netmask'];
164
	$pconfig['numberoptions'] = $config['dhcpdv6'][$if]['numberoptions'];
165
	$pconfig['dhcpv6leaseinlocaltime'] = $config['dhcpdv6'][$if]['dhcpv6leaseinlocaltime'];
166
	if (!is_array($config['dhcpdv6'][$if]['staticmap'])) {
167
		$config['dhcpdv6'][$if]['staticmap'] = array();
168
	}
169
	init_config_arr(array('dhcpdv6', $if, 'staticmap'));
170
	$a_maps = &$config['dhcpdv6'][$if]['staticmap'];
171
}
172

    
173
if ($config['interfaces'][$if]['ipaddrv6'] == 'track6') {
174
	$trackifname = $config['interfaces'][$if]['track6-interface'];
175
	$trackcfg = $config['interfaces'][$trackifname];
176
	$ifcfgsn = "64";
177
	$ifcfgip = '::';
178

    
179
	$str_help_mask = dhcpv6_pd_str_help($ifcfgsn);
180
} else {
181
	$ifcfgip = get_interface_ipv6($if);
182
	$ifcfgsn = get_interface_subnetv6($if);
183
}
184

    
185
/*	 set the enabled flag which will tell us if DHCP relay is enabled
186
 *	 on any interface. We will use this to disable DHCP server since
187
 *	 the two are not compatible with each other.
188
 */
189

    
190
$dhcrelay_enabled = false;
191
$dhcrelaycfg = $config['dhcrelay6'];
192

    
193
if (is_array($dhcrelaycfg) && isset($dhcrelaycfg['enable']) && isset($dhcrelaycfg['interface']) && !empty($dhcrelaycfg['interface'])) {
194
	$dhcrelayifs = explode(",", $dhcrelaycfg['interface']);
195

    
196
	foreach ($dhcrelayifs as $dhcrelayif) {
197

    
198
		if (isset($iflist[$dhcrelayif]) && (!link_interface_to_bridge($dhcrelayif))) {
199
			$dhcrelay_enabled = true;
200
			break;
201
		}
202
	}
203
}
204

    
205
if (isset($_POST['apply'])) {
206
	$changes_applied = true;
207
	$retval = dhcpv6_apply_changes(false);
208
} elseif (isset($_POST['save'])) {
209
	unset($input_errors);
210

    
211
	$old_dhcpdv6_enable = ($pconfig['enable'] == true);
212
	$new_dhcpdv6_enable = ($_POST['enable'] ? true : false);
213
	$dhcpdv6_enable_changed = ($old_dhcpdv6_enable != $new_dhcpdv6_enable);
214

    
215
	$pconfig = $_POST;
216

    
217
	$numberoptions = array();
218
	for ($x = 0; $x < 99; $x++) {
219
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
220
			$numbervalue = array();
221
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
222
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
223
			$numberoptions['item'][] = $numbervalue;
224
		}
225
	}
226
	// Reload the new pconfig variable that the form uses.
227
	$pconfig['numberoptions'] = $numberoptions;
228

    
229
	/* input validation */
230

    
231
	// Note: if DHCPv6 Server is not enabled, then it is OK to adjust other parameters without specifying range from-to.
232
	if ($_POST['enable']) {
233
		if ((empty($_POST['range_from']) || empty($_POST['range_to'])) &&
234
		    ($config['dhcpdv6'][$if]['ramode'] != 'stateless_dhcp')) {
235
			$input_errors[] = gettext("A valid range must be specified for any mode except Stateless DHCP.");
236
		}
237
	}
238

    
239
	if (($_POST['prefixrange_from'] && !is_ipaddrv6($_POST['prefixrange_from']))) {
240
		$input_errors[] = gettext("A valid prefix range must be specified.");
241
	}
242
	if (($_POST['prefixrange_to'] && !is_ipaddrv6($_POST['prefixrange_to']))) {
243
		$input_errors[] = gettext("A valid prefix range must be specified.");
244
	}
245

    
246
	if ($_POST['prefixrange_from'] && $_POST['prefixrange_to'] &&
247
		$_POST['prefixrange_length']) {
248
		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_from'],
249
			$_POST['prefixrange_length']);
250
		$netmask = text_to_compressed_ip6($netmask);
251

    
252
		if ($netmask != text_to_compressed_ip6(strtolower(
253
			$_POST['prefixrange_from']))) {
254
			$input_errors[] = sprintf(gettext(
255
				"Prefix Delegation From address is not a valid IPv6 Netmask for %s"),
256
				$netmask . '/' . $_POST['prefixrange_length']);
257
		}
258

    
259
		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_to'],
260
			$_POST['prefixrange_length']);
261
		$netmask = text_to_compressed_ip6($netmask);
262

    
263
		if ($netmask != text_to_compressed_ip6(strtolower(
264
			$_POST['prefixrange_to']))) {
265
			$input_errors[] = sprintf(gettext(
266
				"Prefix Delegation To address is not a valid IPv6 Netmask for %s"),
267
				$netmask . '/' . $_POST['prefixrange_length']);
268
		}
269
	}
270

    
271
	$range_from_to_ok = true;
272

    
273
	if ($_POST['range_from']) {
274
		if (!is_ipaddrv6($_POST['range_from'])) {
275
			$input_errors[] = gettext("A valid range must be specified.");
276
			$range_from_to_ok = false;
277
		} elseif ($config['interfaces'][$if]['ipaddrv6'] == 'track6' &&
278
			!Net_IPv6::isInNetmask($_POST['range_from'], '::', $ifcfgsn)) {
279
			$input_errors[] = sprintf(gettext(
280
				'The prefix (upper %1$s bits) must be zero.  Use the form %2$s'),
281
				$ifcfgsn, $str_help_mask);
282
			$range_from_to_ok = false;
283
		}
284
	}
285
	if ($_POST['range_to']) {
286
		if (!is_ipaddrv6($_POST['range_to'])) {
287
			$input_errors[] = gettext("A valid range must be specified.");
288
			$range_from_to_ok = false;
289
		} elseif ($config['interfaces'][$if]['ipaddrv6'] == 'track6' &&
290
			!Net_IPv6::isInNetmask($_POST['range_to'], '::', $ifcfgsn)) {
291
			$input_errors[] = sprintf(gettext(
292
				'The prefix (upper %1$s bits) must be zero.  Use the form %2$s'),
293
				$ifcfgsn, $str_help_mask);
294
			$range_from_to_ok = false;
295
		}
296
	}
297
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
298
		$input_errors[] = gettext("Range From and Range To must both be entered.");
299
	}
300
	if (($_POST['gateway'] && !is_ipaddrv6($_POST['gateway']))) {
301
		$input_errors[] = gettext("A valid IPv6 address must be specified for the gateway.");
302
	}
303
	if (($_POST['dns1'] && !is_ipaddrv6($_POST['dns1'])) ||
304
		($_POST['dns2'] && !is_ipaddrv6($_POST['dns2'])) ||
305
		($_POST['dns3'] && !is_ipaddrv6($_POST['dns3'])) ||
306
		($_POST['dns4'] && !is_ipaddrv6($_POST['dns4']))) {
307
		$input_errors[] = gettext("A valid IPv6 address must be specified for each of the DNS servers.");
308
	}
309

    
310
	if ($_POST['deftime'] && (!is_numeric($_POST['deftime']) || ($_POST['deftime'] < 60))) {
311
		$input_errors[] = gettext("The default lease time must be at least 60 seconds.");
312
	}
313
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
314
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
315
	}
316
	if ($_POST['ddnsupdate']) {
317
		if (!is_domain($_POST['ddnsdomain'])) {
318
			$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
319
		}
320
		if (!is_ipaddr($_POST['ddnsdomainprimary'])) {
321
			$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
322
		}
323
		if (!empty($_POST['ddnsdomainsecondary']) && !is_ipaddr($_POST['ddnsdomainsecondary'])) {
324
			$input_errors[] = gettext("A valid secondary domain name server IP address must be specified for the dynamic domain name.");
325
		}
326
		if (!$_POST['ddnsdomainkeyname'] || !$_POST['ddnsdomainkeyalgorithm'] || !$_POST['ddnsdomainkey']) {
327
			$input_errors[] = gettext("A valid domain key name, algorithm and secret must be specified.");
328
		}
329
		if (preg_match('/[^A-Za-z0-9\.\-\_]/', $_POST['ddnsdomainkeyname'])) {
330
			$input_errors[] = gettext("The domain key name may only contain the characters a-z, A-Z, 0-9, '-', '_' and '.'");
331
		}
332
		if ($_POST['ddnsdomainkey'] && !base64_decode($_POST['ddnsdomainkey'], true)) {
333
			$input_errors[] = gettext("The domain key secret must be a Base64 encoded value.");
334
		}
335
	}
336
	if ($_POST['domainsearchlist']) {
337
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
338
		foreach ($domain_array as $curdomain) {
339
			if (!is_domain($curdomain)) {
340
				$input_errors[] = gettext("A valid domain search list must be specified.");
341
				break;
342
			}
343
		}
344
	}
345

    
346
	if (($_POST['ntp1'] && !is_ipaddrv6($_POST['ntp1'])) ||
347
	    ($_POST['ntp2'] && !is_ipaddrv6($_POST['ntp2'])) ||
348
	    ($_POST['ntp3'] && !is_ipaddrv6($_POST['ntp3']))) {
349
		$input_errors[] = gettext("A valid IPv6 address must be specified for the primary/secondary NTP servers.");
350
	}
351
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
352
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
353
	}
354
	if ($_POST['tftp'] && !is_ipaddr($_POST['tftp']) && !is_domain($_POST['tftp']) && !is_URL($_POST['tftp'])) {
355
		$input_errors[] = gettext("A valid IPv6 address or hostname must be specified for the TFTP server.");
356
	}
357
	if (($_POST['bootfile_url'] && !is_URL($_POST['bootfile_url']))) {
358
		$input_errors[] = gettext("A valid URL must be specified for the network bootfile.");
359
	}
360

    
361
	// Disallow a range that includes the virtualip
362
	if ($range_from_to_ok && is_array($config['virtualip']['vip'])) {
363
		foreach ($config['virtualip']['vip'] as $vip) {
364
			if ($vip['interface'] == $if) {
365
				if ($vip['subnetv6'] && is_inrange_v6($vip['subnetv6'], $_POST['range_from'], $_POST['range_to'])) {
366
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IPv6 address %s."), $vip['subnetv6']);
367
				}
368
			}
369
		}
370
	}
371

    
372
	$noip = false;
373
	if (is_array($a_maps)) {
374
		foreach ($a_maps as $map) {
375
			if (empty($map['ipaddrv6'])) {
376
				$noip = true;
377
			}
378
		}
379
	}
380

    
381
	/* make sure that the DHCP Relay isn't enabled on this interface */
382
	if ($_POST['enable'] && $dhcrelay_enabled) {
383
		$input_errors[] = sprintf(gettext("The DHCP relay on the %s interface must be disabled before enabling the DHCP server."), $iflist[$if]);
384
	}
385

    
386
	// If nothing is wrong so far, and we have range from and to, then check conditions related to the values of range from and to.
387
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
388
		/* make sure the range lies within the current subnet */
389
		$subnet_start = gen_subnetv6($ifcfgip, $ifcfgsn);
390
		$subnet_end = gen_subnetv6_max($ifcfgip, $ifcfgsn);
391

    
392
		if (is_ipaddrv6($ifcfgip)) {
393
			if ((!is_inrange_v6($_POST['range_from'], $subnet_start, $subnet_end)) ||
394
				(!is_inrange_v6($_POST['range_to'], $subnet_start, $subnet_end))) {
395
				$input_errors[] = gettext("The specified range lies outside of the current subnet.");
396
			}
397
		}
398
		/* "from" cannot be higher than "to" */
399
		if (inet_pton($_POST['range_from']) > inet_pton($_POST['range_to'])) {
400
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
401
		}
402

    
403
		/* Verify static mappings do not overlap:
404
		   - available DHCP range
405
		   - prefix delegation range (FIXME: still need to be completed) */
406
		$dynsubnet_start = inet_pton($_POST['range_from']);
407
		$dynsubnet_end = inet_pton($_POST['range_to']);
408

    
409
		if (is_array($a_maps)) {
410
			foreach ($a_maps as $map) {
411
				if (empty($map['ipaddrv6'])) {
412
					continue;
413
				}
414
				if ((inet_pton($map['ipaddrv6']) > $dynsubnet_start) &&
415
					(inet_pton($map['ipaddrv6']) < $dynsubnet_end)) {
416
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
417
					break;
418
				}
419
			}
420
		}
421
	}
422

    
423
	if (!$input_errors) {
424
		if (!is_array($config['dhcpdv6'])) {
425
			$config['dhcpdv6'] = array();
426
		}
427
		if (!is_array($config['dhcpdv6'][$if])) {
428
			$config['dhcpdv6'][$if] = array();
429
		}
430
		if (!is_array($config['dhcpdv6'][$if]['range'])) {
431
			$config['dhcpdv6'][$if]['range'] = array();
432
		}
433
		if (!is_array($config['dhcpdv6'][$if]['prefixrange'])) {
434
			$config['dhcpdv6'][$if]['prefixrange'] = array();
435
		}
436

    
437
		$config['dhcpdv6'][$if]['range']['from'] = $_POST['range_from'];
438
		$config['dhcpdv6'][$if]['range']['to'] = $_POST['range_to'];
439
		$config['dhcpdv6'][$if]['prefixrange']['from'] = $_POST['prefixrange_from'];
440
		$config['dhcpdv6'][$if]['prefixrange']['to'] = $_POST['prefixrange_to'];
441
		$config['dhcpdv6'][$if]['prefixrange']['prefixlength'] = $_POST['prefixrange_length'];
442
		$config['dhcpdv6'][$if]['defaultleasetime'] = $_POST['deftime'];
443
		$config['dhcpdv6'][$if]['maxleasetime'] = $_POST['maxtime'];
444
		$config['dhcpdv6'][$if]['netmask'] = $_POST['netmask'];
445

    
446
		unset($config['dhcpdv6'][$if]['winsserver']);
447

    
448
		unset($config['dhcpdv6'][$if]['dnsserver']);
449
		if ($_POST['dns1']) {
450
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns1'];
451
		}
452
		if ($_POST['dns2']) {
453
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns2'];
454
		}
455
		if ($_POST['dns3']) {
456
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns3'];
457
		}
458
		if ($_POST['dns4']) {
459
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns4'];
460
		}
461
		$config['dhcpdv6'][$if]['dhcp6c-dns'] = ($_POST['dhcp6c-dns']) ? "enabled" : "disabled";
462
		$config['dhcpdv6'][$if]['domain'] = $_POST['domain'];
463
		$config['dhcpdv6'][$if]['domainsearchlist'] = $_POST['domainsearchlist'];
464
		$config['dhcpdv6'][$if]['enable'] = ($_POST['enable']) ? true : false;
465
		$config['dhcpdv6'][$if]['ddnsdomain'] = $_POST['ddnsdomain'];
466
		$config['dhcpdv6'][$if]['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
467
		$config['dhcpdv6'][$if]['ddnsdomainsecondary'] = (!empty($_POST['ddnsdomainsecondary'])) ? $_POST['ddnsdomainsecondary'] : ''; 
468
		$config['dhcpdv6'][$if]['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
469
		$config['dhcpdv6'][$if]['ddnsdomainkeyalgorithm'] = $_POST['ddnsdomainkeyalgorithm'];
470
		$config['dhcpdv6'][$if]['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
471
		$config['dhcpdv6'][$if]['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
472
		$config['dhcpdv6'][$if]['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
473
		$config['dhcpdv6'][$if]['ddnsreverse'] = ($_POST['ddnsreverse']) ? true : false;
474
		$config['dhcpdv6'][$if]['ddnsclientupdates'] = $_POST['ddnsclientupdates'];
475

    
476
		unset($config['dhcpdv6'][$if]['ntpserver']);
477
		if ($_POST['ntp1']) {
478
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp1'];
479
		}
480
		if ($_POST['ntp2']) {
481
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp2'];
482
		}
483
		if ($_POST['ntp3']) {
484
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp3'];
485
		}
486

    
487
		$config['dhcpdv6'][$if]['tftp'] = $_POST['tftp'];
488
		$config['dhcpdv6'][$if]['ldap'] = $_POST['ldap'];
489
		$config['dhcpdv6'][$if]['netboot'] = ($_POST['netboot']) ? true : false;
490
		$config['dhcpdv6'][$if]['bootfile_url'] = $_POST['bootfile_url'];
491
		$config['dhcpdv6'][$if]['dhcpv6leaseinlocaltime'] = $_POST['dhcpv6leaseinlocaltime'];
492

    
493
		// Handle the custom options rowhelper
494
		if (isset($config['dhcpdv6'][$if]['numberoptions']['item'])) {
495
			unset($config['dhcpdv6'][$if]['numberoptions']['item']);
496
		}
497

    
498
		$config['dhcpdv6'][$if]['numberoptions'] = $numberoptions;
499

    
500
		write_config("DHCPv6 server settings saved");
501

    
502
		$changes_applied = true;
503
		$retval = dhcpv6_apply_changes($dhcpdv6_enable_changed);
504
	}
505
}
506

    
507
if ($_POST['act'] == "del") {
508
	if ($a_maps[$_POST['id']]) {
509
		unset($a_maps[$_POST['id']]);
510
		write_config("DHCPv6 server static map deleted");
511
		if (isset($config['dhcpdv6'][$if]['enable'])) {
512
			mark_subsystem_dirty('staticmapsv6');
513
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstaticv6'])) {
514
				mark_subsystem_dirty('hosts');
515
			}
516
		}
517
		header("Location: services_dhcpv6.php?if={$if}");
518
		exit;
519
	}
520
}
521

    
522
$pgtitle = array(gettext("Services"), htmlspecialchars(gettext("DHCPv6 Server & RA")));
523
$pglinks = array("", "services_dhcpv6.php");
524

    
525
if (!empty($if) && isset($iflist[$if])) {
526
	$pgtitle[] = $iflist[$if];
527
	$pglinks[] = "@self";
528
	$pgtitle[] = gettext("DHCPv6 Server");
529
	$pglinks[] = "@self";
530
}
531
$shortcut_section = "dhcp6";
532

    
533
include("head.inc");
534

    
535
if ($input_errors) {
536
	print_input_errors($input_errors);
537
}
538

    
539
if ($changes_applied) {
540
	print_apply_result_box($retval);
541
}
542

    
543
if (is_subsystem_dirty('staticmaps')) {
544
	print_apply_box(gettext('The static mapping configuration has been changed.') . '<br />' . gettext('The changes must be applied for them to take effect.'));
545
}
546

    
547
/* active tabs */
548
$tab_array = array();
549
$tabscounter = 0;
550
$i = 0;
551

    
552
foreach ($iflist as $ifent => $ifname) {
553
	$oc = $config['interfaces'][$ifent];
554
	$valid_if_ipaddrv6 = (bool) ($oc['ipaddrv6'] == 'track6' ||
555
	    (is_ipaddrv6($oc['ipaddrv6']) &&
556
	    !is_linklocal($oc['ipaddrv6'])));
557

    
558
	if ((!is_array($config['dhcpdv6'][$ifent]) ||
559
	    !isset($config['dhcpdv6'][$ifent]['enable']) ||
560
	    preg_match('/poes/', $ifent)) &&
561
	    !$valid_if_ipaddrv6) {
562
		continue;
563
	}
564

    
565
	if ($ifent == $if) {
566
		$active = true;
567
	} else {
568
		$active = false;
569
	}
570

    
571
	$tab_array[] = array($ifname, $active, "services_dhcpv6.php?if={$ifent}");
572
	$tabscounter++;
573
}
574

    
575
/* tack on PPPoE or PPtP servers here */
576
/* pppoe server */
577
if (is_array($config['pppoes']['pppoe'])) {
578
	foreach ($config['pppoes']['pppoe'] as $pppoe) {
579
		if ($pppoe['mode'] == "server") {
580
			$ifent = "poes". $pppoe['pppoeid'];
581
			$ifname = strtoupper($ifent);
582

    
583
			if ($ifent == $if) {
584
				$active = true;
585
			} else {
586
				$active = false;
587
			}
588

    
589
			$tab_array[] = array($ifname, $active, "services_dhcpv6.php?if={$ifent}");
590
			$tabscounter++;
591
		}
592
	}
593
}
594

    
595
if ($tabscounter == 0) {
596
	print_info_box(gettext("The DHCPv6 Server can only be enabled on interfaces configured with a static IPv6 address. This system has none."), 'danger');
597
	include("foot.inc");
598
	exit;
599
}
600

    
601
display_top_tabs($tab_array);
602

    
603
$tab_array = array();
604
$tab_array[] = array(gettext("DHCPv6 Server"),		 true,	"services_dhcpv6.php?if={$if}");
605
$tab_array[] = array(gettext("Router Advertisements"), false, "services_router_advertisements.php?if={$if}");
606
display_top_tabs($tab_array, false, 'nav nav-tabs');
607

    
608
$form = new Form();
609

    
610
$section = new Form_Section('DHCPv6 Options');
611

    
612
if ($dhcrelay_enabled) {
613
	$section->addInput(new Form_Checkbox(
614
		'enable',
615
		'DHCPv6 Server',
616
		gettext("DHCPv6 Relay is currently enabled. DHCPv6 Server canot be enabled while the DHCPv6 Relay is enabled on any interface."),
617
		$pconfig['enable']
618
	))->setAttribute('disabled', true);
619
} else {
620
	$section->addInput(new Form_Checkbox(
621
		'enable',
622
		'DHCPv6 Server',
623
		'Enable DHCPv6 server on interface ' . $iflist[$if],
624
		$pconfig['enable']
625
	));
626
}
627

    
628
if (is_ipaddrv6($ifcfgip)) {
629

    
630
	if ($ifcfgip == "::") {
631
		$sntext = "Prefix Delegation";
632
		if (get_interface_track6ip($if)) {
633
			$track6ip = get_interface_track6ip($if);
634
			$pdsubnet = gen_subnetv6($track6ip[0], $track6ip[1]);
635
			$sntext .= " ({$pdsubnet}/{$track6ip[1]})";
636
		}
637
	} else {
638
		$sntext = gen_subnetv6($ifcfgip, $ifcfgsn);
639
	}
640
	$section->addInput(new Form_StaticText(
641
		'Subnet',
642
		$sntext
643
		));
644

    
645
	$section->addInput(new Form_StaticText(
646
		'Subnet Mask',
647
		$ifcfgsn . ' bits'
648
		));
649

    
650
	$section->addInput(new Form_StaticText(
651
		'Available Range',
652
		$range_from = gen_subnetv6($ifcfgip, $ifcfgsn) . ' to ' . gen_subnetv6_max($ifcfgip, $ifcfgsn)
653
		))->setHelp($trackifname ? 'Prefix Delegation subnet will be appended to the beginning of the defined range':'');
654
}
655

    
656
$f1 = new Form_Input(
657
	'range_from',
658
	null,
659
	'text',
660
	$pconfig['range_from']
661
);
662

    
663
$f1->setHelp('From');
664

    
665
$f2 = new Form_Input(
666
	'range_to',
667
	null,
668
	'text',
669
	$pconfig['range_to']
670
);
671

    
672
$f2->setHelp('To');
673

    
674
$group = new Form_Group('*Range');
675

    
676
$group->add($f1);
677
$group->add($f2);
678

    
679
$section->add($group);
680

    
681
$f1 = new Form_Input(
682
	'prefixrange_from',
683
	null,
684
	'text',
685
	$pconfig['prefixrange_from']
686
);
687

    
688
$f1->setHelp('From');
689

    
690
$f2 = new Form_Input(
691
	'prefixrange_to',
692
	null,
693
	'text',
694
	$pconfig['prefixrange_to']
695
);
696

    
697
$f2->setHelp('To');
698

    
699
$group = new Form_Group('Prefix Delegation Range');
700

    
701
$group->add($f1);
702
$group->add($f2);
703

    
704
$section->add($group);
705

    
706
$section->addInput(new Form_Select(
707
	'prefixrange_length',
708
	'Prefix Delegation Size',
709
	$pconfig['prefixrange_length'],
710
	array(
711
		'48' => '48',
712
		'52' => '52',
713
		'56' => '56',
714
		'59' => '59',
715
		'60' => '60',
716
		'61' => '61',
717
		'62' => '62',
718
		'63' => '63',
719
		'64' => '64'
720
		)
721
))->setHelp('A Prefix range can be defined here for DHCP Prefix Delegation. This allows for assigning networks to subrouters. The start and end of the range must end on boundaries of the prefix delegation size.');
722

    
723
$group = new Form_Group('DNS Servers');
724

    
725
for ($i=1;$i<=4; $i++) {
726
	$group->add(new Form_input(
727
		'dns' . $i,
728
		null,
729
		'text',
730
		$pconfig['dns' . $i],
731
		['placeholder' => 'DNS ' . $i]
732
	));
733
}
734

    
735
$group->setHelp('Leave blank to use the system default DNS servers, this interface\'s IP if DNS forwarder is enabled, or the servers configured on the "General" page.');
736
$section->add($group);
737

    
738
$section->addInput(new Form_Checkbox(
739
	'dhcp6c-dns',
740
	null,
741
	'Provide DNS servers to DHCPv6 clients',
742
	($pconfig['dhcp6c-dns'] == "enabled")
743
))->setHelp('Unchecking this box disables the dhcp6.name-servers option. ' .
744
			'Use with caution, as the resulting behavior may violate RFCs and lead to unintended client behavior.');
745

    
746
$section->addInput(new Form_Input(
747
	'domain',
748
	'Domain name',
749
	'text',
750
	$pconfig['domain']
751
))->setHelp('The default is to use the domain name of this system as the default domain name provided by DHCP. An alternate domain name may be specified here. ');
752

    
753
$section->addInput(new Form_Input(
754
	'domainsearchlist',
755
	'Domain search list',
756
	'text',
757
	$pconfig['domainsearchlist']
758
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
759

    
760
$section->addInput(new Form_Input(
761
	'deftime',
762
	'Default lease time',
763
	'text',
764
	$pconfig['deftime']
765
))->setHelp('Lease time in seconds. Used for clients that do not ask for a specific expiration time. %1$s' .
766
			'The default is 7200 seconds.', '<br />');
767

    
768
$section->addInput(new Form_Input(
769
	'maxtime',
770
	'Max lease time',
771
	'text',
772
	$pconfig['maxtime']
773
))->setHelp('Maximum lease time for clients that ask for a specific expiration time. %1$s' .
774
			'The default is 86400 seconds.', '<br />');
775

    
776
$section->addInput(new Form_Checkbox(
777
	'dhcpv6leaseinlocaltime',
778
	'Time Format Change',
779
	'Change DHCPv6 display lease time from UTC to local time',
780
	$pconfig['dhcpv6leaseinlocaltime']
781
))->setHelp('By default DHCPv6 leases are displayed in UTC time. ' .
782
			'By checking this box DHCPv6 lease time will be displayed in local time and set to time zone selected. ' .
783
			'This will be used for all DHCPv6 interfaces lease time.');
784

    
785
$btnadv = new Form_Button(
786
	'btnadvdns',
787
	'Display Advanced',
788
	null,
789
	'fa-cog'
790
);
791

    
792
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
793

    
794
$section->addInput(new Form_StaticText(
795
	'Dynamic DNS',
796
	$btnadv
797
));
798

    
799
$section->addInput(new Form_Checkbox(
800
	'ddnsupdate',
801
	'DHCP Registration',
802
	'Enable registration of DHCP client names in DNS.',
803
	$pconfig['ddnsupdate']
804
));
805

    
806
$section->addInput(new Form_Input(
807
	'ddnsdomain',
808
	'DDNS Domain',
809
	'text',
810
	$pconfig['ddnsdomain']
811
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
812

    
813
$section->addInput(new Form_Checkbox(
814
	'ddnsforcehostname',
815
	'DDNS Hostnames',
816
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
817
	$pconfig['ddnsforcehostname']
818
))->setHelp('Default registers host name option supplied by DHCP client.');
819

    
820
$section->addInput(new Form_IpAddress(
821
	'ddnsdomainprimary',
822
	'Primary DDNS address',
823
	$pconfig['ddnsdomainprimary'],
824
	'BOTH'
825
))->setHelp('Enter the primary domain name server IP address for the dynamic domain name.');
826

    
827
$section->addInput(new Form_IpAddress(
828
	'ddnsdomainsecondary',
829
	'Secondary DDNS address',
830
	$pconfig['ddnsdomainsecondary'],
831
	'BOTH'
832
))->setHelp('Enter the secondary domain name server IP address for the dynamic domain name.');
833

    
834
$section->addInput(new Form_Input(
835
	'ddnsdomainkeyname',
836
	'DDNS Domain Key name',
837
	'text',
838
	$pconfig['ddnsdomainkeyname']
839
))->setHelp('Enter the dynamic DNS domain key name which will be used to register client names in the DNS server.');
840

    
841
$section->addInput(new Form_Select(
842
	'ddnsdomainkeyalgorithm',
843
	'Key algorithm',
844
	$pconfig['ddnsdomainkeyalgorithm'],
845
	array(
846
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
847
		'hmac-sha1' => 'HMAC-SHA1',
848
		'hmac-sha224' => 'HMAC-SHA224',
849
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
850
		'hmac-sha384' => 'HMAC-SHA384',
851
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
852
	)
853
));
854

    
855
$section->addInput(new Form_Input(
856
	'ddnsdomainkey',
857
	'DDNS Domain Key secret',
858
	'text',
859
	$pconfig['ddnsdomainkey']
860
))->setAttribute('placeholder', 'Base64 encoded string')
861
->setHelp('Enter the dynamic DNS domain key secret which will be used to register client names in the DNS server.');
862

    
863
$section->addInput(new Form_Select(
864
	'ddnsclientupdates',
865
	'DDNS Client Updates',
866
	$pconfig['ddnsclientupdates'],
867
	array(
868
	    'allow' => gettext('Allow'),
869
	    'deny' => gettext('Deny'),
870
	    'ignore' => gettext('Ignore'))
871
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
872
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
873
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
874
	    'update and the client can also attempt the update usually using a different domain name.');
875

    
876
$section->addInput(new Form_Checkbox(
877
	'ddnsreverse',
878
	'DDNS Reverse',
879
	'Add reverse dynamic DNS entries.',
880
	$pconfig['ddnsreverse']
881
));
882

    
883
$btnadv = new Form_Button(
884
	'btnadvntp',
885
	'Display Advanced',
886
	null,
887
	'fa-cog'
888
);
889

    
890
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
891

    
892
$section->addInput(new Form_StaticText(
893
	'NTP servers',
894
	$btnadv
895
));
896

    
897
$group = new Form_Group('NTP Servers');
898

    
899
$group->add(new Form_Input(
900
	'ntp1',
901
	'NTP Server 1',
902
	'text',
903
	$pconfig['ntp1'],
904
	['placeholder' => 'NTP 1']
905
));
906

    
907
$group->add(new Form_Input(
908
	'ntp2',
909
	'NTP Server 2',
910
	'text',
911
	$pconfig['ntp2'],
912
	['placeholder' => 'NTP 2']
913
));
914

    
915
$group->add(new Form_Input(
916
	'ntp3',
917
	'NTP Server 3',
918
	'text',
919
	$pconfig['ntp3'],
920
	['placeholder' => 'NTP 3']
921
));
922

    
923
$group->addClass('ntpclass');
924

    
925
$section->add($group);
926

    
927
$btnadv = new Form_Button(
928
	'btnadvldap',
929
	'Display Advanced',
930
	null,
931
	'fa-cog'
932
);
933

    
934
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
935

    
936
$section->addInput(new Form_StaticText(
937
	'LDAP',
938
	$btnadv
939
));
940

    
941
$section->addInput(new Form_Input(
942
	'ldap',
943
	'LDAP URI',
944
	'text',
945
	$pconfig['ldap']
946
));
947

    
948
$btnadv = new Form_Button(
949
	'btnadvnetboot',
950
	'Display Advanced',
951
	null,
952
	'fa-cog'
953
);
954

    
955
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
956

    
957
$section->addInput(new Form_StaticText(
958
	'Network booting',
959
	$btnadv
960
));
961

    
962
$section->addInput(new Form_Checkbox(
963
	'netboot',
964
	'Network booting',
965
	'Enable Network Booting',
966
	$pconfig['netboot']
967
));
968

    
969
$section->addInput(new Form_Input(
970
	'bootfile_url',
971
	'Bootfile URL',
972
	'text',
973
	$pconfig['bootfile_url']
974
));
975

    
976
$btnadv = new Form_Button(
977
	'btnadvopts',
978
	'Display Advanced',
979
	null,
980
	'fa-cog'
981
);
982

    
983
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
984

    
985
$section->addInput(new Form_StaticText(
986
	'Additional BOOTP/DHCP Options',
987
	$btnadv
988
));
989

    
990
$form->add($section);
991

    
992
$title = 'Show Additional BOOTP/DHCP Options';
993

    
994
if (!$pconfig['numberoptions']) {
995
	$noopts = true;
996
	$pconfig['numberoptions'] = array();
997
	$pconfig['numberoptions']['item'] = array(0 => array('number' => "", 'value' => ""));
998
} else {
999
	$noopts = false;
1000
}
1001

    
1002
$counter = 0;
1003
if (!is_array($pconfig['numberoptions'])) {
1004
	$pconfig['numberoptions'] = array();
1005
}
1006
if (!is_array($pconfig['numberoptions']['item'])) {
1007
	$pconfig['numberoptions']['item'] = array();
1008
}
1009
$last = count($pconfig['numberoptions']['item']) - 1;
1010

    
1011
foreach ($pconfig['numberoptions']['item'] as $item) {
1012
	$group = new Form_Group(null);
1013
	$group->addClass('repeatable');
1014
	$group->addClass('adnloptions');
1015

    
1016
	$group->add(new Form_Input(
1017
		'number' . $counter,
1018
		null,
1019
		'text',
1020
		$item['number']
1021
	))->setHelp($counter == $last ? 'Number':null);
1022

    
1023
	$group->add(new Form_Input(
1024
		'value' . $counter,
1025
		null,
1026
		'text',
1027
		base64_decode($item['value'])
1028
	))->setHelp($counter == $last ? 'Value':null);
1029

    
1030
	$btn = new Form_Button(
1031
		'deleterow' . $counter,
1032
		'Delete',
1033
		null,
1034
		'fa-trash'
1035
	);
1036

    
1037
	$btn->addClass('btn-warning');
1038
	$group->add($btn);
1039
	$section->add($group);
1040
	$counter++;
1041
}
1042

    
1043

    
1044
$btnaddopt = new Form_Button(
1045
	'addrow',
1046
	'Add Option',
1047
	null,
1048
	'fa-plus'
1049
);
1050

    
1051
$btnaddopt->removeClass('btn-primary')->addClass('btn-success btn-sm');
1052

    
1053
$section->addInput($btnaddopt);
1054

    
1055
$form->addGlobal(new Form_Input(
1056
	'if',
1057
	null,
1058
	'hidden',
1059
	$if
1060
));
1061

    
1062
print($form);
1063

    
1064
?>
1065
<div class="infoblock blockopen">
1066
<?php
1067
print_info_box(
1068
	sprintf(
1069
		gettext('The DNS servers entered in %1$sSystem: General Setup%3$s (or the %2$sDNS forwarder%3$s if enabled) will be assigned to clients by the DHCP server.'),
1070
		'<a href="system.php">',
1071
		'<a href="services_dnsmasq.php"/>',
1072
		'</a>') .
1073
	'<br />' .
1074
	sprintf(
1075
		gettext('The DHCP lease table can be viewed on the %1$sStatus: DHCPv6 leases%2$s page.'),
1076
		'<a href="status_dhcpv6_leases.php">',
1077
		'</a>'),
1078
	'info',
1079
	false);
1080
?>
1081
</div>
1082
<div class="panel panel-default">
1083
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCPv6 Static Mappings for this Interface");?></h2></div>
1084
	<div class="panel-body table-responsive">
1085
		<table class="table table-striped table-hover table-condensed">
1086
			<thead>
1087
				<tr>
1088
					<th><?=gettext("DUID")?></th>
1089
					<th><?=gettext("IPv6 address")?></th>
1090
					<th><?=gettext("Hostname")?></th>
1091
					<th><?=gettext("Description")?></th>
1092
					<th><!-- Buttons --></th>
1093
				</tr>
1094
			</thead>
1095
			<tbody>
1096
<?php
1097
if (is_array($a_maps)):
1098
	$i = 0;
1099
	foreach ($a_maps as $mapent):
1100
		if ($mapent['duid'] != "" or $mapent['ipaddrv6'] != ""):
1101
?>
1102
				<tr>
1103
					<td>
1104
						<?=htmlspecialchars($mapent['duid'])?>
1105
					</td>
1106
					<td>
1107
						<?=htmlspecialchars($mapent['ipaddrv6'])?>
1108
					</td>
1109
					<td>
1110
						<?=htmlspecialchars($mapent['hostname'])?>
1111
					</td>
1112
					<td>
1113
						<?=htmlspecialchars($mapent['descr'])?>
1114
					</td>
1115
					<td>
1116
						<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>" href="services_dhcpv6_edit.php?if=<?=$if?>&amp;id=<?=$i?>"></a>
1117
						<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>" href="services_dhcpv6.php?if=<?=$if?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
1118
					</td>
1119
				</tr>
1120
<?php
1121
		endif;
1122
	$i++;
1123
	endforeach;
1124
endif;
1125
?>
1126
			</tbody>
1127
		</table>
1128
	</div>
1129
</div>
1130

    
1131
<nav class="action-buttons">
1132
	<a href="services_dhcpv6_edit.php?if=<?=$if?>" class="btn btn-sm btn-success"/>
1133
		<i class="fa fa-plus icon-embed-btn"></i>
1134
		<?=gettext("Add")?>
1135
	</a>
1136
</nav>
1137

    
1138
<script type="text/javascript">
1139
//<![CDATA[
1140
events.push(function() {
1141

    
1142
	// Show advanced DNS options ======================================================================================
1143
	var showadvdns = false;
1144

    
1145
	function show_advdns(ispageload) {
1146
		var text;
1147
		// On page load decide the initial state based on the data.
1148
		if (ispageload) {
1149
<?php
1150
			if (!$pconfig['ddnsupdate'] &&
1151
			    !$pconfig['ddnsforcehostname'] &&
1152
			    empty($pconfig['ddnsdomain']) &&
1153
			    empty($pconfig['ddnsdomainprimary']) &&
1154
			    empty($pconfig['ddnsdomainsecondary']) &&
1155
			    empty($pconfig['ddnsdomainkeyname']) &&
1156
			    (empty($pconfig['ddnsdomainkeyalgorithm'])  || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1157
			    empty($pconfig['ddnsdomainkey']) &&
1158
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1159
			    !$pconfig['ddnsreverse']) {
1160
				$showadv = false;
1161
			} else {
1162
				$showadv = true;
1163
			}
1164
?>
1165
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1166
		} else {
1167
			// It was a click, swap the state.
1168
			showadvdns = !showadvdns;
1169
		}
1170

    
1171
		hideCheckbox('ddnsupdate', !showadvdns);
1172
		hideInput('ddnsdomain', !showadvdns);
1173
		hideCheckbox('ddnsforcehostname', !showadvdns);
1174
		hideInput('ddnsdomainprimary', !showadvdns);
1175
		hideInput('ddnsdomainsecondary', !showadvdns);
1176
		hideInput('ddnsdomainkeyname', !showadvdns);
1177
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1178
		hideInput('ddnsdomainkey', !showadvdns);
1179
		hideInput('ddnsclientupdates', !showadvdns);
1180
		hideCheckbox('ddnsreverse', !showadvdns);
1181

    
1182
		if (showadvdns) {
1183
			text = "<?=gettext('Hide Advanced');?>";
1184
		} else {
1185
			text = "<?=gettext('Display Advanced');?>";
1186
		}
1187
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1188
	}
1189

    
1190
	$('#btnadvdns').click(function(event) {
1191
		show_advdns();
1192
	});
1193

    
1194
	// Show advanced NTP options ======================================================================================
1195
	var showadvntp = false;
1196

    
1197
	function show_advntp(ispageload) {
1198
		var text;
1199
		// On page load decide the initial state based on the data.
1200
		if (ispageload) {
1201
<?php
1202
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2']) && empty($pconfig['ntp3'])) {
1203
				$showadv = false;
1204
			} else {
1205
				$showadv = true;
1206
			}
1207
?>
1208
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1209
		} else {
1210
			// It was a click, swap the state.
1211
			showadvntp = !showadvntp;
1212
		}
1213

    
1214
		hideInput('ntp1', !showadvntp);
1215
		hideInput('ntp2', !showadvntp);
1216
		hideInput('ntp3', !showadvntp);
1217

    
1218
		if (showadvntp) {
1219
			text = "<?=gettext('Hide Advanced');?>";
1220
		} else {
1221
			text = "<?=gettext('Display Advanced');?>";
1222
		}
1223
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1224
	}
1225

    
1226
	$('#btnadvntp').click(function(event) {
1227
		show_advntp();
1228
	});
1229

    
1230
	// Show advanced LDAP options ======================================================================================
1231
	var showadvldap = false;
1232

    
1233
	function show_advldap(ispageload) {
1234
		var text;
1235
		// On page load decide the initial state based on the data.
1236
		if (ispageload) {
1237
<?php
1238
			if (empty($pconfig['ldap'])) {
1239
				$showadv = false;
1240
			} else {
1241
				$showadv = true;
1242
			}
1243
?>
1244
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1245
		} else {
1246
			// It was a click, swap the state.
1247
			showadvldap = !showadvldap;
1248
		}
1249

    
1250
		hideInput('ldap', !showadvldap);
1251

    
1252
		if (showadvldap) {
1253
			text = "<?=gettext('Hide Advanced');?>";
1254
		} else {
1255
			text = "<?=gettext('Display Advanced');?>";
1256
		}
1257
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1258
	}
1259

    
1260
	$('#btnadvldap').click(function(event) {
1261
		show_advldap();
1262
	});
1263

    
1264
	// Show advanced Netboot options ======================================================================================
1265
	var showadvnetboot = false;
1266

    
1267
	function show_advnetboot(ispageload) {
1268
		var text;
1269
		// On page load decide the initial state based on the data.
1270
		if (ispageload) {
1271
<?php
1272
			if (!$pconfig['netboot'] && empty($pconfig['bootfile_url'])) {
1273
				$showadv = false;
1274
			} else {
1275
				$showadv = true;
1276
			}
1277
?>
1278
			showadvnetboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1279
		} else {
1280
			// It was a click, swap the state.
1281
			showadvnetboot = !showadvnetboot;
1282
		}
1283

    
1284
		hideCheckbox('netboot', !showadvnetboot);
1285
		hideInput('bootfile_url', !showadvnetboot);
1286

    
1287
		if (showadvnetboot) {
1288
			text = "<?=gettext('Hide Advanced');?>";
1289
		} else {
1290
			text = "<?=gettext('Display Advanced');?>";
1291
		}
1292
		$('#btnadvnetboot').html('<i class="fa fa-cog"></i> ' + text);
1293
	}
1294

    
1295
	$('#btnadvnetboot').click(function(event) {
1296
		show_advnetboot();
1297
	});
1298

    
1299
	// Show advanced additional opts options ===========================================================================
1300
	var showadvopts = false;
1301

    
1302
	function show_advopts(ispageload) {
1303
		var text;
1304
		// On page load decide the initial state based on the data.
1305
		if (ispageload) {
1306
<?php
1307
			if (empty($pconfig['numberoptions']) ||
1308
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1309
				$showadv = false;
1310
			} else {
1311
				$showadv = true;
1312
			}
1313
?>
1314
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1315
		} else {
1316
			// It was a click, swap the state.
1317
			showadvopts = !showadvopts;
1318
		}
1319

    
1320
		hideClass('adnloptions', !showadvopts);
1321
		hideInput('addrow', !showadvopts);
1322

    
1323
		if (showadvopts) {
1324
			text = "<?=gettext('Hide Advanced');?>";
1325
		} else {
1326
			text = "<?=gettext('Display Advanced');?>";
1327
		}
1328
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1329
	}
1330

    
1331
	$('#btnadvopts').click(function(event) {
1332
		show_advopts();
1333
		checkLastRow();
1334
	});
1335

    
1336
	// On initial load
1337
	show_advdns(true);
1338
	show_advntp(true);
1339
	show_advldap(true);
1340
	show_advnetboot(true);
1341
	show_advopts(true);
1342
	if ($('#enable').prop('checked')) {
1343
		hideClass('adnloptions', <?php echo json_encode($noopts); ?>);
1344
		hideInput('addrow', <?php echo json_encode($noopts); ?>);
1345
	} else {
1346
		hideClass('adnloptions', true);
1347
		hideInput('addrow', true);
1348
	}
1349

    
1350
});
1351
//]]>
1352
</script>
1353

    
1354
<?php include('foot.inc');
(121-121/227)