Project

General

Profile

Download (40.2 KB) Statistics
| Branch: | Tag: | Revision:
1 99caa67c Seth Mos
<?php
2
/*
3 c5d81585 Renato Botelho
 * services_dhcpv6.php
4 df6cb8fe Stephen Beaver
 *
5 c5d81585 Renato Botelho
 * part of pfSense (https://www.pfsense.org)
6 38809d47 Renato Botelho do Couto
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8 0284d79e jim-p
 * Copyright (c) 2014-2020 Rubicon Communications, LLC (Netgate)
9 c5d81585 Renato Botelho
 * Copyright (c) 2010 Seth Mos <seth.mos@dds.nl>
10
 * All rights reserved.
11 191cb31d Stephen Beaver
 *
12 c5d81585 Renato Botelho
 * originally based on m0n0wall (http://m0n0.ch/wall)
13
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
14
 * All rights reserved.
15 df6cb8fe Stephen Beaver
 *
16 b12ea3fb Renato Botelho
 * 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 df6cb8fe Stephen Beaver
 *
20 b12ea3fb Renato Botelho
 * http://www.apache.org/licenses/LICENSE-2.0
21 df6cb8fe Stephen Beaver
 *
22 b12ea3fb Renato Botelho
 * 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 df6cb8fe Stephen Beaver
 */
28 99caa67c Seth Mos
29
##|+PRIV
30
##|*IDENT=page-services-dhcpv6server
31 48157a04 Phil Davis
##|*NAME=Services: DHCPv6 Server
32
##|*DESCR=Allow access to the 'Services: DHCPv6 Server' page.
33 99caa67c Seth Mos
##|*MATCH=services_dhcpv6.php*
34
##|-PRIV
35
36 c81ef6e2 Phil Davis
require_once("guiconfig.inc");
37 472ad9a0 Renato Botelho
require_once("filter.inc");
38 99caa67c Seth Mos
39 8f36f87a jim-p
function dhcpv6_apply_changes($dhcpdv6_enable_changed) {
40
	$retval = 0;
41
	$retvaldhcp = 0;
42
	$retvaldns = 0;
43
	/* Stop DHCPv6 so we can cleanup leases */
44
	killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
45
	// dhcp_clean_leases();
46
	/* dnsmasq_configure calls dhcpd_configure */
47
	/* no need to restart dhcpd twice */
48
	if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstatic']))	{
49 44c42356 Phil Davis
		$retvaldns |= services_dnsmasq_configure();
50 8f36f87a jim-p
		if ($retvaldns == 0) {
51
			clear_subsystem_dirty('hosts');
52
			clear_subsystem_dirty('staticmaps');
53
		}
54
	} else if (isset($config['unbound']['enable']) && isset($config['unbound']['regdhcpstatic'])) {
55 44c42356 Phil Davis
		$retvaldns |= services_unbound_configure();
56 8f36f87a jim-p
		if ($retvaldns == 0) {
57
			clear_subsystem_dirty('unbound');
58
			clear_subsystem_dirty('staticmaps');
59
		}
60
	} else {
61 44c42356 Phil Davis
		$retvaldhcp |= services_dhcpd_configure();
62 8f36f87a jim-p
		if ($retvaldhcp == 0) {
63
			clear_subsystem_dirty('staticmaps');
64
		}
65
	}
66 c3fb0119 doktornotor
	/* BIND package - Bug #3710 */
67
	if (!function_exists('is_package_installed')) {
68
		require_once('pkg-utils.inc');
69
	}
70
	if (is_package_installed('pfSense-pkg-bind') && isset($config['installedpackages']['bind']['config'][0]['enable_bind'])) {
71
		$reloadbind = false;
72
		if (is_array($config['installedpackages']['bindzone'])) {
73
			$bindzone = $config['installedpackages']['bindzone']['config'];
74
		} else {
75
			$bindzone = array();
76
		}
77
		for ($x = 0; $x < sizeof($bindzone); $x++) {
78 6cc58ae8 doktornotor
			$zone = $bindzone[$x];
79 c3fb0119 doktornotor
			if ($zone['regdhcpstatic'] == 'on') {
80
				$reloadbind = true;
81
				break;
82
			}
83
		}
84
		if ($reloadbind === true) {
85
			if (file_exists("/usr/local/pkg/bind.inc")) {
86
				require_once("/usr/local/pkg/bind.inc");
87
				bind_sync();
88
			}
89
		}
90
	}
91 8f36f87a jim-p
	if ($dhcpdv6_enable_changed) {
92 44c42356 Phil Davis
		$retvalfc |= filter_configure();
93 8f36f87a jim-p
	}
94
	if ($retvaldhcp == 1 || $retvaldns == 1 || $retvalfc == 1) {
95
		$retval = 1;
96
	}
97 44c42356 Phil Davis
	return $retval;
98 8f36f87a jim-p
}
99
100 8f8682f7 Phil Davis
if (!$g['services_dhcp_server_enable']) {
101 6f3d2063 Renato Botelho
	header("Location: /");
102 99caa67c Seth Mos
	exit;
103
}
104
105 c946d721 Steve Beaver
$if = $_REQUEST['if'];
106 99caa67c Seth Mos
$iflist = get_configured_interface_with_descr();
107 16d9ad13 smos
$iflist = array_merge($iflist, get_configured_pppoe_server_interfaces());
108 99caa67c Seth Mos
109
/* set the starting interface */
110
if (!$if || !isset($iflist[$if])) {
111
	foreach ($iflist as $ifent => $ifname) {
112
		$oc = $config['interfaces'][$ifent];
113 2bf455ca Renato Botelho
		$valid_if_ipaddrv6 = (bool) ($oc['ipaddrv6'] == 'track6' ||
114
		    (is_ipaddrv6($oc['ipaddrv6']) &&
115
		    !is_linklocal($oc['ipaddrv6'])));
116 c80e6a6a Stephen Beaver
117 48602774 Renato Botelho
		if ((!is_array($config['dhcpdv6'][$ifent]) ||
118
		    !isset($config['dhcpdv6'][$ifent]['enable'])) &&
119
		    !$valid_if_ipaddrv6) {
120 99caa67c Seth Mos
			continue;
121 8f8682f7 Phil Davis
		}
122 99caa67c Seth Mos
		$if = $ifent;
123
		break;
124
	}
125
}
126
127 8f8682f7 Phil Davis
if (is_array($config['dhcpdv6'][$if])) {
128 fe838158 smos
	/* DHCPv6 */
129 99caa67c Seth Mos
	if (is_array($config['dhcpdv6'][$if]['range'])) {
130
		$pconfig['range_from'] = $config['dhcpdv6'][$if]['range']['from'];
131
		$pconfig['range_to'] = $config['dhcpdv6'][$if]['range']['to'];
132
	}
133 bfb3e717 Seth Mos
	if (is_array($config['dhcpdv6'][$if]['prefixrange'])) {
134
		$pconfig['prefixrange_from'] = $config['dhcpdv6'][$if]['prefixrange']['from'];
135
		$pconfig['prefixrange_to'] = $config['dhcpdv6'][$if]['prefixrange']['to'];
136
		$pconfig['prefixrange_length'] = $config['dhcpdv6'][$if]['prefixrange']['prefixlength'];
137
	}
138 99caa67c Seth Mos
	$pconfig['deftime'] = $config['dhcpdv6'][$if]['defaultleasetime'];
139
	$pconfig['maxtime'] = $config['dhcpdv6'][$if]['maxleasetime'];
140
	$pconfig['domain'] = $config['dhcpdv6'][$if]['domain'];
141
	$pconfig['domainsearchlist'] = $config['dhcpdv6'][$if]['domainsearchlist'];
142 8f8682f7 Phil Davis
	list($pconfig['wins1'], $pconfig['wins2']) = $config['dhcpdv6'][$if]['winsserver'];
143
	list($pconfig['dns1'], $pconfig['dns2'], $pconfig['dns3'], $pconfig['dns4']) = $config['dhcpdv6'][$if]['dnsserver'];
144 c58e56fb luckman212
	$pconfig['dhcp6c-dns'] = ($config['dhcpdv6'][$if]['dhcp6c-dns'] != 'disabled') ? "enabled" : "disabled";
145 99caa67c Seth Mos
	$pconfig['enable'] = isset($config['dhcpdv6'][$if]['enable']);
146
	$pconfig['ddnsdomain'] = $config['dhcpdv6'][$if]['ddnsdomain'];
147 87019fc4 Andres Petralli
	$pconfig['ddnsdomainprimary'] = $config['dhcpdv6'][$if]['ddnsdomainprimary'];
148 9fbd8f71 Viktor Gurov
	$pconfig['ddnsdomainsecondary'] = $config['dhcpdv6'][$if]['ddnsdomainsecondary'];
149 87019fc4 Andres Petralli
	$pconfig['ddnsdomainkeyname'] = $config['dhcpdv6'][$if]['ddnsdomainkeyname'];
150 534d7d69 Joeri Capens
	$pconfig['ddnsdomainkeyalgorithm'] = $config['dhcpdv6'][$if]['ddnsdomainkeyalgorithm'];
151 87019fc4 Andres Petralli
	$pconfig['ddnsdomainkey'] = $config['dhcpdv6'][$if]['ddnsdomainkey'];
152 99caa67c Seth Mos
	$pconfig['ddnsupdate'] = isset($config['dhcpdv6'][$if]['ddnsupdate']);
153 1a6bda5b Ross Williams
	$pconfig['ddnsforcehostname'] = isset($config['dhcpdv6'][$if]['ddnsforcehostname']);
154 391d63da Renato Botelho
	$pconfig['ddnsreverse'] = isset($config['dhcpdv6'][$if]['ddnsreverse']);
155
	$pconfig['ddnsclientupdates'] = $config['dhcpdv6'][$if]['ddnsclientupdates'];
156 5c52a260 kiokoman
	list($pconfig['ntp1'], $pconfig['ntp2'], $pconfig['ntp3'] ) = $config['dhcpdv6'][$if]['ntpserver'];
157 99caa67c Seth Mos
	$pconfig['tftp'] = $config['dhcpdv6'][$if]['tftp'];
158
	$pconfig['ldap'] = $config['dhcpdv6'][$if]['ldap'];
159
	$pconfig['netboot'] = isset($config['dhcpdv6'][$if]['netboot']);
160 bd942860 Renato Botelho
	$pconfig['bootfile_url'] = $config['dhcpdv6'][$if]['bootfile_url'];
161 99caa67c Seth Mos
	$pconfig['netmask'] = $config['dhcpdv6'][$if]['netmask'];
162
	$pconfig['numberoptions'] = $config['dhcpdv6'][$if]['numberoptions'];
163 138208bf Joecowboy
	$pconfig['dhcpv6leaseinlocaltime'] = $config['dhcpdv6'][$if]['dhcpv6leaseinlocaltime'];
164 8f8682f7 Phil Davis
	if (!is_array($config['dhcpdv6'][$if]['staticmap'])) {
165 99caa67c Seth Mos
		$config['dhcpdv6'][$if]['staticmap'] = array();
166 8f8682f7 Phil Davis
	}
167 c6c398c6 jim-p
	init_config_arr(array('dhcpdv6', $if, 'staticmap'));
168 99caa67c Seth Mos
	$a_maps = &$config['dhcpdv6'][$if]['staticmap'];
169
}
170
171 2bf455ca Renato Botelho
if ($config['interfaces'][$if]['ipaddrv6'] == 'track6') {
172 6c8beed3 Renato Botelho
	$trackifname = $config['interfaces'][$if]['track6-interface'];
173
	$trackcfg = $config['interfaces'][$trackifname];
174 a5776226 Chris Buechler
	$ifcfgsn = "64";
175 2bf455ca Renato Botelho
	$ifcfgip = '::';
176 6c8beed3 Renato Botelho
177
	$str_help_mask = dhcpv6_pd_str_help($ifcfgsn);
178 2bf455ca Renato Botelho
} else {
179
	$ifcfgip = get_interface_ipv6($if);
180
	$ifcfgsn = get_interface_subnetv6($if);
181
}
182 99caa67c Seth Mos
183 cd2c7940 sbeaver
/*	 set the enabled flag which will tell us if DHCP relay is enabled
184
 *	 on any interface. We will use this to disable DHCP server since
185
 *	 the two are not compatible with each other.
186 99caa67c Seth Mos
 */
187
188
$dhcrelay_enabled = false;
189 80c88a68 smos
$dhcrelaycfg = $config['dhcrelay6'];
190 99caa67c Seth Mos
191 9c06758b k-paulius
if (is_array($dhcrelaycfg) && isset($dhcrelaycfg['enable']) && isset($dhcrelaycfg['interface']) && !empty($dhcrelaycfg['interface'])) {
192
	$dhcrelayifs = explode(",", $dhcrelaycfg['interface']);
193
194
	foreach ($dhcrelayifs as $dhcrelayif) {
195
196
		if (isset($iflist[$dhcrelayif]) && (!link_interface_to_bridge($dhcrelayif))) {
197 99caa67c Seth Mos
			$dhcrelay_enabled = true;
198 9c06758b k-paulius
			break;
199 8f8682f7 Phil Davis
		}
200 99caa67c Seth Mos
	}
201
}
202
203 306cbbc8 Phil Davis
if (isset($_POST['apply'])) {
204 44c42356 Phil Davis
	$changes_applied = true;
205
	$retval = dhcpv6_apply_changes(false);
206 306cbbc8 Phil Davis
} elseif (isset($_POST['save'])) {
207 99caa67c Seth Mos
	unset($input_errors);
208
209 472ad9a0 Renato Botelho
	$old_dhcpdv6_enable = ($pconfig['enable'] == true);
210
	$new_dhcpdv6_enable = ($_POST['enable'] ? true : false);
211
	$dhcpdv6_enable_changed = ($old_dhcpdv6_enable != $new_dhcpdv6_enable);
212
213 99caa67c Seth Mos
	$pconfig = $_POST;
214
215
	$numberoptions = array();
216 6c07db48 Phil Davis
	for ($x = 0; $x < 99; $x++) {
217 8f8682f7 Phil Davis
		if (isset($_POST["number{$x}"]) && ctype_digit($_POST["number{$x}"])) {
218 99caa67c Seth Mos
			$numbervalue = array();
219
			$numbervalue['number'] = htmlspecialchars($_POST["number{$x}"]);
220 65cce9d7 Renato Botelho
			$numbervalue['value'] = base64_encode($_POST["value{$x}"]);
221 99caa67c Seth Mos
			$numberoptions['item'][] = $numbervalue;
222
		}
223
	}
224 756da4bd Phil Davis
	// Reload the new pconfig variable that the form uses.
225 99caa67c Seth Mos
	$pconfig['numberoptions'] = $numberoptions;
226
227
	/* input validation */
228 756da4bd Phil Davis
229
	// Note: if DHCPv6 Server is not enabled, then it is OK to adjust other parameters without specifying range from-to.
230 99caa67c Seth Mos
	if ($_POST['enable']) {
231 5c533d72 Viktor G
		if ((empty($_POST['range_from']) || empty($_POST['range_to'])) &&
232
		    ($config['dhcpdv6'][$if]['ramode'] != 'stateless_dhcp')) {
233
			$input_errors[] = gettext("A valid range must be specified for any mode except Stateless DHCP.");
234
		}
235 756da4bd Phil Davis
	}
236 99caa67c Seth Mos
237 756da4bd Phil Davis
	if (($_POST['prefixrange_from'] && !is_ipaddrv6($_POST['prefixrange_from']))) {
238
		$input_errors[] = gettext("A valid prefix range must be specified.");
239
	}
240
	if (($_POST['prefixrange_to'] && !is_ipaddrv6($_POST['prefixrange_to']))) {
241
		$input_errors[] = gettext("A valid prefix range must be specified.");
242
	}
243 bcc2b417 Renato Botelho
244 756da4bd Phil Davis
	if ($_POST['prefixrange_from'] && $_POST['prefixrange_to'] &&
245
		$_POST['prefixrange_length']) {
246
		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_from'],
247
			$_POST['prefixrange_length']);
248 587995fb Phil Davis
		$netmask = text_to_compressed_ip6($netmask);
249 756da4bd Phil Davis
250 587995fb Phil Davis
		if ($netmask != text_to_compressed_ip6(strtolower(
251 756da4bd Phil Davis
			$_POST['prefixrange_from']))) {
252
			$input_errors[] = sprintf(gettext(
253
				"Prefix Delegation From address is not a valid IPv6 Netmask for %s"),
254
				$netmask . '/' . $_POST['prefixrange_length']);
255
		}
256 bcc2b417 Renato Botelho
257 756da4bd Phil Davis
		$netmask = Net_IPv6::getNetmask($_POST['prefixrange_to'],
258
			$_POST['prefixrange_length']);
259 587995fb Phil Davis
		$netmask = text_to_compressed_ip6($netmask);
260 bcc2b417 Renato Botelho
261 587995fb Phil Davis
		if ($netmask != text_to_compressed_ip6(strtolower(
262 756da4bd Phil Davis
			$_POST['prefixrange_to']))) {
263
			$input_errors[] = sprintf(gettext(
264
				"Prefix Delegation To address is not a valid IPv6 Netmask for %s"),
265
				$netmask . '/' . $_POST['prefixrange_length']);
266 bcc2b417 Renato Botelho
		}
267 756da4bd Phil Davis
	}
268 bcc2b417 Renato Botelho
269 756da4bd Phil Davis
	$range_from_to_ok = true;
270
271
	if ($_POST['range_from']) {
272
		if (!is_ipaddrv6($_POST['range_from'])) {
273
			$input_errors[] = gettext("A valid range must be specified.");
274
			$range_from_to_ok = false;
275
		} elseif ($config['interfaces'][$if]['ipaddrv6'] == 'track6' &&
276
			!Net_IPv6::isInNetmask($_POST['range_from'], '::', $ifcfgsn)) {
277
			$input_errors[] = sprintf(gettext(
278 702fa4d0 Phil Davis
				'The prefix (upper %1$s bits) must be zero.  Use the form %2$s'),
279 756da4bd Phil Davis
				$ifcfgsn, $str_help_mask);
280
			$range_from_to_ok = false;
281 8f8682f7 Phil Davis
		}
282 756da4bd Phil Davis
	}
283
	if ($_POST['range_to']) {
284
		if (!is_ipaddrv6($_POST['range_to'])) {
285
			$input_errors[] = gettext("A valid range must be specified.");
286
			$range_from_to_ok = false;
287
		} elseif ($config['interfaces'][$if]['ipaddrv6'] == 'track6' &&
288
			!Net_IPv6::isInNetmask($_POST['range_to'], '::', $ifcfgsn)) {
289
			$input_errors[] = sprintf(gettext(
290 702fa4d0 Phil Davis
				'The prefix (upper %1$s bits) must be zero.  Use the form %2$s'),
291 756da4bd Phil Davis
				$ifcfgsn, $str_help_mask);
292
			$range_from_to_ok = false;
293 8f8682f7 Phil Davis
		}
294 756da4bd Phil Davis
	}
295
	if (($_POST['range_from'] && !$_POST['range_to']) || ($_POST['range_to'] && !$_POST['range_from'])) {
296
		$input_errors[] = gettext("Range From and Range To must both be entered.");
297
	}
298
	if (($_POST['gateway'] && !is_ipaddrv6($_POST['gateway']))) {
299
		$input_errors[] = gettext("A valid IPv6 address must be specified for the gateway.");
300
	}
301
	if (($_POST['dns1'] && !is_ipaddrv6($_POST['dns1'])) ||
302
		($_POST['dns2'] && !is_ipaddrv6($_POST['dns2'])) ||
303
		($_POST['dns3'] && !is_ipaddrv6($_POST['dns3'])) ||
304
		($_POST['dns4'] && !is_ipaddrv6($_POST['dns4']))) {
305
		$input_errors[] = gettext("A valid IPv6 address must be specified for each of the DNS servers.");
306
	}
307 99caa67c Seth Mos
308 756da4bd Phil Davis
	if ($_POST['deftime'] && (!is_numeric($_POST['deftime']) || ($_POST['deftime'] < 60))) {
309
		$input_errors[] = gettext("The default lease time must be at least 60 seconds.");
310
	}
311
	if ($_POST['maxtime'] && (!is_numeric($_POST['maxtime']) || ($_POST['maxtime'] < 60) || ($_POST['maxtime'] <= $_POST['deftime']))) {
312
		$input_errors[] = gettext("The maximum lease time must be at least 60 seconds and higher than the default lease time.");
313
	}
314 9fbd8f71 Viktor Gurov
	if ($_POST['ddnsupdate']) {
315
		if (!is_domain($_POST['ddnsdomain'])) {
316
			$input_errors[] = gettext("A valid domain name must be specified for the dynamic DNS registration.");
317
		}
318
		if (!is_ipaddr($_POST['ddnsdomainprimary'])) {
319
			$input_errors[] = gettext("A valid primary domain name server IP address must be specified for the dynamic domain name.");
320
		}
321
		if (!empty($_POST['ddnsdomainsecondary']) && !is_ipaddr($_POST['ddnsdomainsecondary'])) {
322
			$input_errors[] = gettext("A valid secondary domain name server IP address must be specified for the dynamic domain name.");
323
		}
324
		if (!$_POST['ddnsdomainkeyname'] || !$_POST['ddnsdomainkeyalgorithm'] || !$_POST['ddnsdomainkey']) {
325
			$input_errors[] = gettext("A valid domain key name, algorithm and secret must be specified.");
326
		}
327
		if (preg_match('/[^A-Za-z0-9\-_]/', $_POST['ddnsdomainkeyname'])) {
328
			$input_errors[] = gettext("The domain key name may only contain the characters a-z, A-Z, 0-9, '-' and '_'");
329
		}
330
		if ($_POST['ddnsdomainkey'] && !base64_decode($_POST['ddnsdomainkey'], true)) {
331
			$input_errors[] = gettext("The domain key secret must be a Base64 encoded value.");
332
		}
333 756da4bd Phil Davis
	}
334
	if ($_POST['domainsearchlist']) {
335 534d7d69 Joeri Capens
		$domain_array = preg_split("/[ ;]+/", $_POST['domainsearchlist']);
336 756da4bd Phil Davis
		foreach ($domain_array as $curdomain) {
337
			if (!is_domain($curdomain)) {
338
				$input_errors[] = gettext("A valid domain search list must be specified.");
339
				break;
340 a3de8b9e Pierre POMES
			}
341
		}
342 756da4bd Phil Davis
	}
343 a3de8b9e Pierre POMES
344 5c52a260 kiokoman
	if (($_POST['ntp1'] && !is_ipaddrv6($_POST['ntp1'])) ||
345
	    ($_POST['ntp2'] && !is_ipaddrv6($_POST['ntp2'])) ||
346
	    ($_POST['ntp3'] && !is_ipaddrv6($_POST['ntp3']))) {
347 756da4bd Phil Davis
		$input_errors[] = gettext("A valid IPv6 address must be specified for the primary/secondary NTP servers.");
348
	}
349
	if (($_POST['domain'] && !is_domain($_POST['domain']))) {
350
		$input_errors[] = gettext("A valid domain name must be specified for the DNS domain.");
351
	}
352
	if ($_POST['tftp'] && !is_ipaddr($_POST['tftp']) && !is_domain($_POST['tftp']) && !is_URL($_POST['tftp'])) {
353
		$input_errors[] = gettext("A valid IPv6 address or hostname must be specified for the TFTP server.");
354
	}
355
	if (($_POST['bootfile_url'] && !is_URL($_POST['bootfile_url']))) {
356
		$input_errors[] = gettext("A valid URL must be specified for the network bootfile.");
357
	}
358 99caa67c Seth Mos
359 756da4bd Phil Davis
	// Disallow a range that includes the virtualip
360
	if ($range_from_to_ok && is_array($config['virtualip']['vip'])) {
361
		foreach ($config['virtualip']['vip'] as $vip) {
362
			if ($vip['interface'] == $if) {
363
				if ($vip['subnetv6'] && is_inrange_v6($vip['subnetv6'], $_POST['range_from'], $_POST['range_to'])) {
364
					$input_errors[] = sprintf(gettext("The subnet range cannot overlap with virtual IPv6 address %s."), $vip['subnetv6']);
365 8f8682f7 Phil Davis
				}
366 99caa67c Seth Mos
			}
367
		}
368 756da4bd Phil Davis
	}
369 99caa67c Seth Mos
370 756da4bd Phil Davis
	$noip = false;
371
	if (is_array($a_maps)) {
372
		foreach ($a_maps as $map) {
373
			if (empty($map['ipaddrv6'])) {
374
				$noip = true;
375 cd2c7940 sbeaver
			}
376
		}
377 756da4bd Phil Davis
	}
378
379
	/* make sure that the DHCP Relay isn't enabled on this interface */
380
	if ($_POST['enable'] && $dhcrelay_enabled) {
381
		$input_errors[] = sprintf(gettext("The DHCP relay on the %s interface must be disabled before enabling the DHCP server."), $iflist[$if]);
382
	}
383
384
	// 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.
385
	if (!$input_errors && $_POST['range_from'] && $_POST['range_to']) {
386
		/* make sure the range lies within the current subnet */
387
		$subnet_start = gen_subnetv6($ifcfgip, $ifcfgsn);
388
		$subnet_end = gen_subnetv6_max($ifcfgip, $ifcfgsn);
389 99caa67c Seth Mos
390 756da4bd Phil Davis
		if (is_ipaddrv6($ifcfgip)) {
391
			if ((!is_inrange_v6($_POST['range_from'], $subnet_start, $subnet_end)) ||
392
				(!is_inrange_v6($_POST['range_to'], $subnet_start, $subnet_end))) {
393
				$input_errors[] = gettext("The specified range lies outside of the current subnet.");
394 8f8682f7 Phil Davis
			}
395 756da4bd Phil Davis
		}
396
		/* "from" cannot be higher than "to" */
397
		if (inet_pton($_POST['range_from']) > inet_pton($_POST['range_to'])) {
398
			$input_errors[] = gettext("The range is invalid (first element higher than second element).");
399
		}
400 99caa67c Seth Mos
401 756da4bd Phil Davis
		/* Verify static mappings do not overlap:
402
		   - available DHCP range
403
		   - prefix delegation range (FIXME: still need to be completed) */
404
		$dynsubnet_start = inet_pton($_POST['range_from']);
405
		$dynsubnet_end = inet_pton($_POST['range_to']);
406 731de711 Pierre POMES
407 756da4bd Phil Davis
		if (is_array($a_maps)) {
408
			foreach ($a_maps as $map) {
409
				if (empty($map['ipaddrv6'])) {
410
					continue;
411
				}
412
				if ((inet_pton($map['ipaddrv6']) > $dynsubnet_start) &&
413
					(inet_pton($map['ipaddrv6']) < $dynsubnet_end)) {
414
					$input_errors[] = sprintf(gettext("The DHCP range cannot overlap any static DHCP mappings."));
415
					break;
416 99caa67c Seth Mos
				}
417
			}
418
		}
419
	}
420
421
	if (!$input_errors) {
422 5fa2a4a2 Stephen Jones
		if (!is_array($config['dhcpdv6'])) {
423
			$config['dhcpdv6'] = array();
424
		}
425 8f8682f7 Phil Davis
		if (!is_array($config['dhcpdv6'][$if])) {
426 99caa67c Seth Mos
			$config['dhcpdv6'][$if] = array();
427 8f8682f7 Phil Davis
		}
428
		if (!is_array($config['dhcpdv6'][$if]['range'])) {
429 99caa67c Seth Mos
			$config['dhcpdv6'][$if]['range'] = array();
430 8f8682f7 Phil Davis
		}
431
		if (!is_array($config['dhcpdv6'][$if]['prefixrange'])) {
432 bfb3e717 Seth Mos
			$config['dhcpdv6'][$if]['prefixrange'] = array();
433 8f8682f7 Phil Davis
		}
434 99caa67c Seth Mos
435
		$config['dhcpdv6'][$if]['range']['from'] = $_POST['range_from'];
436
		$config['dhcpdv6'][$if]['range']['to'] = $_POST['range_to'];
437 bfb3e717 Seth Mos
		$config['dhcpdv6'][$if]['prefixrange']['from'] = $_POST['prefixrange_from'];
438
		$config['dhcpdv6'][$if]['prefixrange']['to'] = $_POST['prefixrange_to'];
439
		$config['dhcpdv6'][$if]['prefixrange']['prefixlength'] = $_POST['prefixrange_length'];
440 99caa67c Seth Mos
		$config['dhcpdv6'][$if]['defaultleasetime'] = $_POST['deftime'];
441
		$config['dhcpdv6'][$if]['maxleasetime'] = $_POST['maxtime'];
442
		$config['dhcpdv6'][$if]['netmask'] = $_POST['netmask'];
443
444
		unset($config['dhcpdv6'][$if]['winsserver']);
445
446
		unset($config['dhcpdv6'][$if]['dnsserver']);
447 8f8682f7 Phil Davis
		if ($_POST['dns1']) {
448 99caa67c Seth Mos
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns1'];
449 8f8682f7 Phil Davis
		}
450
		if ($_POST['dns2']) {
451 99caa67c Seth Mos
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns2'];
452 8f8682f7 Phil Davis
		}
453
		if ($_POST['dns3']) {
454 3d88ea11 Phil Davis
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns3'];
455 8f8682f7 Phil Davis
		}
456
		if ($_POST['dns4']) {
457 3d88ea11 Phil Davis
			$config['dhcpdv6'][$if]['dnsserver'][] = $_POST['dns4'];
458 8f8682f7 Phil Davis
		}
459 c58e56fb luckman212
		$config['dhcpdv6'][$if]['dhcp6c-dns'] = ($_POST['dhcp6c-dns']) ? "enabled" : "disabled";
460 99caa67c Seth Mos
		$config['dhcpdv6'][$if]['domain'] = $_POST['domain'];
461
		$config['dhcpdv6'][$if]['domainsearchlist'] = $_POST['domainsearchlist'];
462
		$config['dhcpdv6'][$if]['enable'] = ($_POST['enable']) ? true : false;
463
		$config['dhcpdv6'][$if]['ddnsdomain'] = $_POST['ddnsdomain'];
464 87019fc4 Andres Petralli
		$config['dhcpdv6'][$if]['ddnsdomainprimary'] = $_POST['ddnsdomainprimary'];
465 9fbd8f71 Viktor Gurov
		$config['dhcpdv6'][$if]['ddnsdomainsecondary'] = (!empty($_POST['ddnsdomainsecondary'])) ? $_POST['ddnsdomainsecondary'] : ''; 
466 87019fc4 Andres Petralli
		$config['dhcpdv6'][$if]['ddnsdomainkeyname'] = $_POST['ddnsdomainkeyname'];
467 534d7d69 Joeri Capens
		$config['dhcpdv6'][$if]['ddnsdomainkeyalgorithm'] = $_POST['ddnsdomainkeyalgorithm'];
468 87019fc4 Andres Petralli
		$config['dhcpdv6'][$if]['ddnsdomainkey'] = $_POST['ddnsdomainkey'];
469 99caa67c Seth Mos
		$config['dhcpdv6'][$if]['ddnsupdate'] = ($_POST['ddnsupdate']) ? true : false;
470 1a6bda5b Ross Williams
		$config['dhcpdv6'][$if]['ddnsforcehostname'] = ($_POST['ddnsforcehostname']) ? true : false;
471 391d63da Renato Botelho
		$config['dhcpdv6'][$if]['ddnsreverse'] = ($_POST['ddnsreverse']) ? true : false;
472
		$config['dhcpdv6'][$if]['ddnsclientupdates'] = $_POST['ddnsclientupdates'];
473 99caa67c Seth Mos
474
		unset($config['dhcpdv6'][$if]['ntpserver']);
475 8f8682f7 Phil Davis
		if ($_POST['ntp1']) {
476 99caa67c Seth Mos
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp1'];
477 8f8682f7 Phil Davis
		}
478
		if ($_POST['ntp2']) {
479 99caa67c Seth Mos
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp2'];
480 8f8682f7 Phil Davis
		}
481 5c52a260 kiokoman
		if ($_POST['ntp3']) {
482
			$config['dhcpdv6'][$if]['ntpserver'][] = $_POST['ntp3'];
483
		}
484 99caa67c Seth Mos
485
		$config['dhcpdv6'][$if]['tftp'] = $_POST['tftp'];
486
		$config['dhcpdv6'][$if]['ldap'] = $_POST['ldap'];
487
		$config['dhcpdv6'][$if]['netboot'] = ($_POST['netboot']) ? true : false;
488 bd942860 Renato Botelho
		$config['dhcpdv6'][$if]['bootfile_url'] = $_POST['bootfile_url'];
489 138208bf Joecowboy
		$config['dhcpdv6'][$if]['dhcpv6leaseinlocaltime'] = $_POST['dhcpv6leaseinlocaltime'];
490 99caa67c Seth Mos
491
		// Handle the custom options rowhelper
492 8f8682f7 Phil Davis
		if (isset($config['dhcpdv6'][$if]['numberoptions']['item'])) {
493 99caa67c Seth Mos
			unset($config['dhcpdv6'][$if]['numberoptions']['item']);
494 8f8682f7 Phil Davis
		}
495 99caa67c Seth Mos
496
		$config['dhcpdv6'][$if]['numberoptions'] = $numberoptions;
497
498
		write_config();
499
500 44c42356 Phil Davis
		$changes_applied = true;
501
		$retval = dhcpv6_apply_changes($dhcpdv6_enable_changed);
502 99caa67c Seth Mos
	}
503
}
504
505 c946d721 Steve Beaver
if ($_POST['act'] == "del") {
506
	if ($a_maps[$_POST['id']]) {
507
		unset($a_maps[$_POST['id']]);
508 99caa67c Seth Mos
		write_config();
509 8f8682f7 Phil Davis
		if (isset($config['dhcpdv6'][$if]['enable'])) {
510 99caa67c Seth Mos
			mark_subsystem_dirty('staticmapsv6');
511 8f8682f7 Phil Davis
			if (isset($config['dnsmasq']['enable']) && isset($config['dnsmasq']['regdhcpstaticv6'])) {
512 99caa67c Seth Mos
				mark_subsystem_dirty('hosts');
513 8f8682f7 Phil Davis
			}
514 99caa67c Seth Mos
		}
515
		header("Location: services_dhcpv6.php?if={$if}");
516
		exit;
517
	}
518
}
519
520 46b7214c k-paulius
$pgtitle = array(gettext("Services"), htmlspecialchars(gettext("DHCPv6 Server & RA")));
521 edcd7535 Phil Davis
$pglinks = array("", "services_dhcpv6.php");
522 253fa019 k-paulius
523 75173246 Chris Buechler
if (!empty($if) && isset($iflist[$if])) {
524 253fa019 k-paulius
	$pgtitle[] = $iflist[$if];
525 edcd7535 Phil Davis
	$pglinks[] = "@self";
526 9c06758b k-paulius
	$pgtitle[] = gettext("DHCPv6 Server");
527 edcd7535 Phil Davis
	$pglinks[] = "@self";
528 253fa019 k-paulius
}
529 b32dd0a6 jim-p
$shortcut_section = "dhcp6";
530 99caa67c Seth Mos
531
include("head.inc");
532
533 6e3488e9 Phil Davis
if ($input_errors) {
534 cd2c7940 sbeaver
	print_input_errors($input_errors);
535 6e3488e9 Phil Davis
}
536 99caa67c Seth Mos
537 44c42356 Phil Davis
if ($changes_applied) {
538
	print_apply_result_box($retval);
539 6e3488e9 Phil Davis
}
540 99caa67c Seth Mos
541 6e3488e9 Phil Davis
if (is_subsystem_dirty('staticmaps')) {
542 5daef710 NOYB
	print_apply_box(gettext('The static mapping configuration has been changed.') . '<br />' . gettext('The changes must be applied for them to take effect.'));
543 6e3488e9 Phil Davis
}
544 99caa67c Seth Mos
545 cd2c7940 sbeaver
/* active tabs */
546
$tab_array = array();
547
$tabscounter = 0;
548
$i = 0;
549 c80e6a6a Stephen Beaver
550 cd2c7940 sbeaver
foreach ($iflist as $ifent => $ifname) {
551
	$oc = $config['interfaces'][$ifent];
552 2bf455ca Renato Botelho
	$valid_if_ipaddrv6 = (bool) ($oc['ipaddrv6'] == 'track6' ||
553
	    (is_ipaddrv6($oc['ipaddrv6']) &&
554
	    !is_linklocal($oc['ipaddrv6'])));
555 c80e6a6a Stephen Beaver
556 8f928dc3 Renato Botelho
	if ((!is_array($config['dhcpdv6'][$ifent]) ||
557
	    !isset($config['dhcpdv6'][$ifent]['enable'])) &&
558
	    !$valid_if_ipaddrv6) {
559 cd2c7940 sbeaver
		continue;
560 6e3488e9 Phil Davis
	}
561 cd2c7940 sbeaver
562 6e3488e9 Phil Davis
	if ($ifent == $if) {
563 cd2c7940 sbeaver
		$active = true;
564 6e3488e9 Phil Davis
	} else {
565 cd2c7940 sbeaver
		$active = false;
566 6e3488e9 Phil Davis
	}
567 cd2c7940 sbeaver
568
	$tab_array[] = array($ifname, $active, "services_dhcpv6.php?if={$ifent}");
569
	$tabscounter++;
570
}
571 c80e6a6a Stephen Beaver
572 cd2c7940 sbeaver
/* tack on PPPoE or PPtP servers here */
573
/* pppoe server */
574
if (is_array($config['pppoes']['pppoe'])) {
575 6e3488e9 Phil Davis
	foreach ($config['pppoes']['pppoe'] as $pppoe) {
576 cd2c7940 sbeaver
		if ($pppoe['mode'] == "server") {
577
			$ifent = "poes". $pppoe['pppoeid'];
578
			$ifname = strtoupper($ifent);
579
580 6e3488e9 Phil Davis
			if ($ifent == $if) {
581 cd2c7940 sbeaver
				$active = true;
582 6e3488e9 Phil Davis
			} else {
583 cd2c7940 sbeaver
				$active = false;
584 6e3488e9 Phil Davis
			}
585 cd2c7940 sbeaver
586
			$tab_array[] = array($ifname, $active, "services_dhcpv6.php?if={$ifent}");
587
			$tabscounter++;
588
		}
589 99caa67c Seth Mos
	}
590 cd2c7940 sbeaver
}
591 99caa67c Seth Mos
592 c80e6a6a Stephen Beaver
if ($tabscounter == 0) {
593 cd2c7940 sbeaver
	print_info_box(gettext("The DHCPv6 Server can only be enabled on interfaces configured with a static IPv6 address. This system has none."), 'danger');
594
	include("foot.inc");
595
	exit;
596
}
597 99caa67c Seth Mos
598 9b54ac32 Stephen Beaver
display_top_tabs($tab_array);
599
600 cd2c7940 sbeaver
$tab_array = array();
601
$tab_array[] = array(gettext("DHCPv6 Server"),		 true,	"services_dhcpv6.php?if={$if}");
602
$tab_array[] = array(gettext("Router Advertisements"), false, "services_router_advertisements.php?if={$if}");
603 6e3488e9 Phil Davis
display_top_tabs($tab_array, false, 'nav nav-tabs');
604 99caa67c Seth Mos
605 8f58b51b jim-p
$form = new Form();
606 cd2c7940 sbeaver
607
$section = new Form_Section('DHCPv6 Options');
608
609 756da4bd Phil Davis
if ($dhcrelay_enabled) {
610
	$section->addInput(new Form_Checkbox(
611
		'enable',
612
		'DHCPv6 Server',
613
		gettext("DHCPv6 Relay is currently enabled. DHCPv6 Server canot be enabled while the DHCPv6 Relay is enabled on any interface."),
614
		$pconfig['enable']
615
	))->setAttribute('disabled', true);
616
} else {
617
	$section->addInput(new Form_Checkbox(
618
		'enable',
619
		'DHCPv6 Server',
620
		'Enable DHCPv6 server on interface ' . $iflist[$if],
621
		$pconfig['enable']
622
	));
623
}
624 cd2c7940 sbeaver
625 6e3488e9 Phil Davis
if (is_ipaddrv6($ifcfgip)) {
626 cd2c7940 sbeaver
627 e1953efa Chris Buechler
	if ($ifcfgip == "::") {
628
		$sntext = "Prefix Delegation";
629
	} else {
630
		$sntext = gen_subnetv6($ifcfgip, $ifcfgsn);
631
	}
632 cd2c7940 sbeaver
	$section->addInput(new Form_StaticText(
633
		'Subnet',
634 e1953efa Chris Buechler
		$sntext
635 cd2c7940 sbeaver
		));
636
637
	$section->addInput(new Form_StaticText(
638
		'Subnet Mask',
639
		$ifcfgsn . ' bits'
640
		));
641
642
	$section->addInput(new Form_StaticText(
643
		'Available Range',
644
		$range_from = gen_subnetv6($ifcfgip, $ifcfgsn) . ' to ' . gen_subnetv6_max($ifcfgip, $ifcfgsn)
645 e1953efa Chris Buechler
		))->setHelp($trackifname ? 'Prefix Delegation subnet will be appended to the beginning of the defined range':'');
646 cd2c7940 sbeaver
}
647
648
$f1 = new Form_Input(
649
	'range_from',
650
	null,
651
	'text',
652
	$pconfig['range_from']
653 218600a2 Renato Botelho
);
654
655
$f1->setHelp('From');
656 cd2c7940 sbeaver
657
$f2 = new Form_Input(
658
	'range_to',
659
	null,
660
	'text',
661
	$pconfig['range_to']
662 218600a2 Renato Botelho
);
663
664
$f2->setHelp('To');
665 cd2c7940 sbeaver
666 24b82516 Phil Davis
$group = new Form_Group('*Range');
667 cd2c7940 sbeaver
668
$group->add($f1);
669
$group->add($f2);
670
671
$section->add($group);
672
673
$f1 = new Form_Input(
674 70f17067 Stephen Beaver
	'prefixrange_from',
675 cd2c7940 sbeaver
	null,
676
	'text',
677 70f17067 Stephen Beaver
	$pconfig['prefixrange_from']
678 218600a2 Renato Botelho
);
679
680
$f1->setHelp('From');
681 cd2c7940 sbeaver
682
$f2 = new Form_Input(
683 70f17067 Stephen Beaver
	'prefixrange_to',
684 cd2c7940 sbeaver
	null,
685
	'text',
686 70f17067 Stephen Beaver
	$pconfig['prefixrange_to']
687 218600a2 Renato Botelho
);
688
689
$f2->setHelp('To');
690 cd2c7940 sbeaver
691
$group = new Form_Group('Prefix Delegation Range');
692
693
$group->add($f1);
694
$group->add($f2);
695
696
$section->add($group);
697
698
$section->addInput(new Form_Select(
699
	'prefixrange_length',
700
	'Prefix Delegation Size',
701
	$pconfig['prefixrange_length'],
702
	array(
703
		'48' => '48',
704
		'52' => '52',
705
		'56' => '56',
706 19d905bc PiBa-NL
		'59' => '59',
707 cd2c7940 sbeaver
		'60' => '60',
708 19d905bc PiBa-NL
		'61' => '61',
709 cd2c7940 sbeaver
		'62' => '62',
710
		'63' => '63',
711
		'64' => '64'
712
		)
713 5daef710 NOYB
))->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.');
714 cd2c7940 sbeaver
715
$group = new Form_Group('DNS Servers');
716
717 6e3488e9 Phil Davis
for ($i=1;$i<=4; $i++) {
718 cd2c7940 sbeaver
	$group->add(new Form_input(
719
		'dns' . $i,
720
		null,
721
		'text',
722 e32f02a5 Phil Davis
		$pconfig['dns' . $i],
723
		['placeholder' => 'DNS ' . $i]
724
	));
725 cd2c7940 sbeaver
}
726
727 6e3488e9 Phil Davis
$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.');
728 cd2c7940 sbeaver
$section->add($group);
729 9f6432f0 luckman212
730 e26ad76e luckman212
$section->addInput(new Form_Checkbox(
731 c58e56fb luckman212
	'dhcp6c-dns',
732 e26ad76e luckman212
	null,
733 9f6432f0 luckman212
	'Provide DNS servers to DHCPv6 clients',
734 c58e56fb luckman212
	($pconfig['dhcp6c-dns'] == "enabled")
735 b9f3dfd2 jim-p
))->setHelp('Unchecking this box disables the dhcp6.name-servers option. ' .
736
			'Use with caution, as the resulting behavior may violate RFCs and lead to unintended client behavior.');
737 cd2c7940 sbeaver
738
$section->addInput(new Form_Input(
739
	'domain',
740 cb6c20a9 NewEraCracker
	'Domain name',
741 cd2c7940 sbeaver
	'text',
742 ea6649f7 sbeaver
	$pconfig['domain']
743 5daef710 NOYB
))->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. ');
744 cd2c7940 sbeaver
745
$section->addInput(new Form_Input(
746
	'domainsearchlist',
747
	'Domain search list',
748
	'text',
749 ea6649f7 sbeaver
	$pconfig['domainsearchlist']
750 e4c7d45f NewEraCracker
))->setHelp('The DHCP server can optionally provide a domain search list. Use the semicolon character as separator.');
751 cd2c7940 sbeaver
752
$section->addInput(new Form_Input(
753
	'deftime',
754
	'Default lease time',
755
	'text',
756 ea6649f7 sbeaver
	$pconfig['deftime']
757 3fd41815 Phil Davis
))->setHelp('Lease time in seconds. Used for clients that do not ask for a specific expiration time. %1$s' .
758
			'The default is 7200 seconds.', '<br />');
759 cd2c7940 sbeaver
760
$section->addInput(new Form_Input(
761
	'maxtime',
762
	'Max lease time',
763
	'text',
764 ea6649f7 sbeaver
	$pconfig['maxtime']
765 3fd41815 Phil Davis
))->setHelp('Maximum lease time for clients that ask for a specific expiration time. %1$s' .
766
			'The default is 86400 seconds.', '<br />');
767 cd2c7940 sbeaver
768
$section->addInput(new Form_Checkbox(
769
	'dhcpv6leaseinlocaltime',
770
	'Time Format Change',
771
	'Change DHCPv6 display lease time from UTC to local time',
772
	$pconfig['dhcpv6leaseinlocaltime']
773
))->setHelp('By default DHCPv6 leases are displayed in UTC time. ' .
774
			'By checking this box DHCPv6 lease time will be displayed in local time and set to time zone selected. ' .
775
			'This will be used for all DHCPv6 interfaces lease time.');
776
777 4aa42b06 Phil Davis
$btnadv = new Form_Button(
778
	'btnadvdns',
779
	'Display Advanced',
780 3314e626 jim-p
	null,
781
	'fa-cog'
782 cd2c7940 sbeaver
);
783
784 347c0214 Phil Davis
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
785 cd2c7940 sbeaver
786
$section->addInput(new Form_StaticText(
787
	'Dynamic DNS',
788 4aa42b06 Phil Davis
	$btnadv
789 cd2c7940 sbeaver
));
790
791
$section->addInput(new Form_Checkbox(
792
	'ddnsupdate',
793
	'DHCP Registration',
794
	'Enable registration of DHCP client names in DNS.',
795
	$pconfig['ddnsupdate']
796
));
797
798
$section->addInput(new Form_Input(
799
	'ddnsdomain',
800
	'DDNS Domain',
801
	'text',
802 ea6649f7 sbeaver
	$pconfig['ddnsdomain']
803 e5c4b4fc Joeri Capens
))->setHelp('Enter the dynamic DNS domain which will be used to register client names in the DNS server.');
804 cd2c7940 sbeaver
805 1a6bda5b Ross Williams
$section->addInput(new Form_Checkbox(
806
	'ddnsforcehostname',
807 cfc10a33 Ross Williams
	'DDNS Hostnames',
808 1a6bda5b Ross Williams
	'Force dynamic DNS hostname to be the same as configured hostname for Static Mappings',
809
	$pconfig['ddnsforcehostname']
810 9ca5d4ab Ross Williams
))->setHelp('Default registers host name option supplied by DHCP client.');
811 1a6bda5b Ross Williams
812 cd2c7940 sbeaver
$section->addInput(new Form_IpAddress(
813
	'ddnsdomainprimary',
814 9fbd8f71 Viktor Gurov
	'Primary DDNS address',
815 ff3d11c8 Phil Davis
	$pconfig['ddnsdomainprimary'],
816 9fbd8f71 Viktor Gurov
	'BOTH'
817
))->setHelp('Enter the primary domain name server IP address for the dynamic domain name.');
818
819
$section->addInput(new Form_IpAddress(
820
	'ddnsdomainsecondary',
821
	'Secondary DDNS address',
822
	$pconfig['ddnsdomainsecondary'],
823
	'BOTH'
824
))->setHelp('Enter the secondary domain name server IP address for the dynamic domain name.');
825 cd2c7940 sbeaver
826
$section->addInput(new Form_Input(
827
	'ddnsdomainkeyname',
828
	'DDNS Domain Key name',
829
	'text',
830 ea6649f7 sbeaver
	$pconfig['ddnsdomainkeyname']
831 cd2c7940 sbeaver
))->setHelp('Enter the dynamic DNS domain key name which will be used to register client names in the DNS server.');
832
833 534d7d69 Joeri Capens
$section->addInput(new Form_Select(
834
	'ddnsdomainkeyalgorithm',
835
	'Key algorithm',
836
	$pconfig['ddnsdomainkeyalgorithm'],
837
	array(
838
		'hmac-md5' => 'HMAC-MD5 (legacy default)',
839
		'hmac-sha1' => 'HMAC-SHA1',
840
		'hmac-sha224' => 'HMAC-SHA224',
841
		'hmac-sha256' => 'HMAC-SHA256 (current bind9 default)',
842
		'hmac-sha384' => 'HMAC-SHA384',
843
		'hmac-sha512' => 'HMAC-SHA512 (most secure)',
844
	)
845
));
846
847 cd2c7940 sbeaver
$section->addInput(new Form_Input(
848
	'ddnsdomainkey',
849
	'DDNS Domain Key secret',
850
	'text',
851 ea6649f7 sbeaver
	$pconfig['ddnsdomainkey']
852 9fbd8f71 Viktor Gurov
))->setAttribute('placeholder', 'Base64 encoded string')
853
->setHelp('Enter the dynamic DNS domain key secret which will be used to register client names in the DNS server.');
854 cd2c7940 sbeaver
855 391d63da Renato Botelho
$section->addInput(new Form_Select(
856
	'ddnsclientupdates',
857
	'DDNS Client Updates',
858
	$pconfig['ddnsclientupdates'],
859
	array(
860
	    'allow' => gettext('Allow'),
861
	    'deny' => gettext('Deny'),
862
	    'ignore' => gettext('Ignore'))
863
))->setHelp('How Forward entries are handled when client indicates they wish to update DNS.  ' .
864
	    'Allow prevents DHCP from updating Forward entries, Deny indicates that DHCP will ' .
865
	    'do the updates and the client should not, Ignore specifies that DHCP will do the ' .
866
	    'update and the client can also attempt the update usually using a different domain name.');
867
868
$section->addInput(new Form_Checkbox(
869
	'ddnsreverse',
870
	'DDNS Reverse',
871
	'Add reverse dynamic DNS entries.',
872
	$pconfig['ddnsreverse']
873
));
874
875 4aa42b06 Phil Davis
$btnadv = new Form_Button(
876
	'btnadvntp',
877
	'Display Advanced',
878 3314e626 jim-p
	null,
879
	'fa-cog'
880 cd2c7940 sbeaver
);
881
882 347c0214 Phil Davis
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
883 cd2c7940 sbeaver
884
$section->addInput(new Form_StaticText(
885
	'NTP servers',
886 4aa42b06 Phil Davis
	$btnadv
887 cd2c7940 sbeaver
));
888
889
$group = new Form_Group('NTP Servers');
890
891
$group->add(new Form_Input(
892
	'ntp1',
893
	'NTP Server 1',
894
	'text',
895 ea6649f7 sbeaver
	$pconfig['ntp1'],
896 cd2c7940 sbeaver
	['placeholder' => 'NTP 1']
897
));
898
899
$group->add(new Form_Input(
900
	'ntp2',
901 e32f02a5 Phil Davis
	'NTP Server 2',
902 cd2c7940 sbeaver
	'text',
903 ea6649f7 sbeaver
	$pconfig['ntp2'],
904 cd2c7940 sbeaver
	['placeholder' => 'NTP 2']
905
));
906
907 5c52a260 kiokoman
$group->add(new Form_Input(
908
	'ntp3',
909
	'NTP Server 3',
910
	'text',
911
	$pconfig['ntp3'],
912
	['placeholder' => 'NTP 3']
913
));
914
915 cd2c7940 sbeaver
$group->addClass('ntpclass');
916
917
$section->add($group);
918
919 4aa42b06 Phil Davis
$btnadv = new Form_Button(
920
	'btnadvldap',
921
	'Display Advanced',
922 3314e626 jim-p
	null,
923
	'fa-cog'
924 cd2c7940 sbeaver
);
925
926 347c0214 Phil Davis
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
927 cd2c7940 sbeaver
928
$section->addInput(new Form_StaticText(
929
	'LDAP',
930 4aa42b06 Phil Davis
	$btnadv
931 cd2c7940 sbeaver
));
932
933
$section->addInput(new Form_Input(
934
	'ldap',
935
	'LDAP URI',
936
	'text',
937 ea6649f7 sbeaver
	$pconfig['ldap']
938 cd2c7940 sbeaver
));
939
940 4aa42b06 Phil Davis
$btnadv = new Form_Button(
941
	'btnadvnetboot',
942
	'Display Advanced',
943 3314e626 jim-p
	null,
944
	'fa-cog'
945 cd2c7940 sbeaver
);
946
947 347c0214 Phil Davis
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
948 cd2c7940 sbeaver
949
$section->addInput(new Form_StaticText(
950
	'Network booting',
951 4aa42b06 Phil Davis
	$btnadv
952 cd2c7940 sbeaver
));
953
954
$section->addInput(new Form_Checkbox(
955 e46ea2c6 Stephen Jones
	'netboot',
956 cd2c7940 sbeaver
	'Network booting',
957
	'Enable Network Booting',
958 e46ea2c6 Stephen Jones
	$pconfig['netboot']
959 cd2c7940 sbeaver
));
960
961
$section->addInput(new Form_Input(
962
	'bootfile_url',
963
	'Bootfile URL',
964
	'text',
965 ea6649f7 sbeaver
	$pconfig['bootfile_url']
966 cd2c7940 sbeaver
));
967
968 4aa42b06 Phil Davis
$btnadv = new Form_Button(
969
	'btnadvopts',
970
	'Display Advanced',
971 3314e626 jim-p
	null,
972
	'fa-cog'
973 cd2c7940 sbeaver
);
974
975 347c0214 Phil Davis
$btnadv->setAttribute('type','button')->addClass('btn-info btn-sm');
976 cd2c7940 sbeaver
977
$section->addInput(new Form_StaticText(
978
	'Additional BOOTP/DHCP Options',
979 4aa42b06 Phil Davis
	$btnadv
980 cd2c7940 sbeaver
));
981
982
$form->add($section);
983
984
$title = 'Show Additional BOOTP/DHCP Options';
985
986 b090a0d9 Stephen Beaver
if (!$pconfig['numberoptions']) {
987 0716b616 Stephen Beaver
	$noopts = true;
988 d4cebe1f Steve Beaver
	$pconfig['numberoptions'] = array();
989 b090a0d9 Stephen Beaver
	$pconfig['numberoptions']['item'] = array(0 => array('number' => "", 'value' => ""));
990 0716b616 Stephen Beaver
} else {
991
	$noopts = false;
992 b090a0d9 Stephen Beaver
}
993
994
$counter = 0;
995 a2a60a07 Stephen Jones
if (!is_array($pconfig['numberoptions'])) {
996
	$pconfig['numberoptions'] = array();
997
}
998
if (!is_array($pconfig['numberoptions']['item'])) {
999
	$pconfig['numberoptions']['item'] = array();
1000
}
1001 b090a0d9 Stephen Beaver
$last = count($pconfig['numberoptions']['item']) - 1;
1002
1003
foreach ($pconfig['numberoptions']['item'] as $item) {
1004
	$group = new Form_Group(null);
1005
	$group->addClass('repeatable');
1006 0716b616 Stephen Beaver
	$group->addClass('adnloptions');
1007 b090a0d9 Stephen Beaver
1008
	$group->add(new Form_Input(
1009
		'number' . $counter,
1010
		null,
1011
		'text',
1012
		$item['number']
1013
	))->setHelp($counter == $last ? 'Number':null);
1014
1015
	$group->add(new Form_Input(
1016
		'value' . $counter,
1017
		null,
1018
		'text',
1019
		base64_decode($item['value'])
1020
	))->setHelp($counter == $last ? 'Value':null);
1021
1022
	$btn = new Form_Button(
1023
		'deleterow' . $counter,
1024 faab522f Renato Botelho
		'Delete',
1025 cd7ddae6 jim-p
		null,
1026
		'fa-trash'
1027 b090a0d9 Stephen Beaver
	);
1028
1029 cd7ddae6 jim-p
	$btn->addClass('btn-warning');
1030 b090a0d9 Stephen Beaver
	$group->add($btn);
1031
	$section->add($group);
1032
	$counter++;
1033 cd2c7940 sbeaver
}
1034
1035 b090a0d9 Stephen Beaver
1036 cd2c7940 sbeaver
$btnaddopt = new Form_Button(
1037 9eeb91dd Stephen Beaver
	'addrow',
1038 faab522f Renato Botelho
	'Add Option',
1039 cd7ddae6 jim-p
	null,
1040
	'fa-plus'
1041 cd2c7940 sbeaver
);
1042
1043 9eeb91dd Stephen Beaver
$btnaddopt->removeClass('btn-primary')->addClass('btn-success btn-sm');
1044 cd2c7940 sbeaver
1045
$section->addInput($btnaddopt);
1046
1047 ee12dd78 Peter Feichtinger
$form->addGlobal(new Form_Input(
1048 cd2c7940 sbeaver
	'if',
1049
	null,
1050
	'hidden',
1051
	$if
1052
));
1053
1054
print($form);
1055 b090a0d9 Stephen Beaver
1056 f78bbe16 Phil Davis
?>
1057 c95dabdd Stephen Beaver
<div class="infoblock blockopen">
1058 f78bbe16 Phil Davis
<?php
1059 0a8a90f7 Phil Davis
print_info_box(
1060
	sprintf(
1061 e4c7d45f NewEraCracker
		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.'),
1062 0a8a90f7 Phil Davis
		'<a href="system.php">',
1063
		'<a href="services_dnsmasq.php"/>',
1064 9eeb91dd Stephen Beaver
		'</a>') .
1065 0a8a90f7 Phil Davis
	'<br />' .
1066
	sprintf(
1067
		gettext('The DHCP lease table can be viewed on the %1$sStatus: DHCPv6 leases%2$s page.'),
1068
		'<a href="status_dhcpv6_leases.php">',
1069
		'</a>'),
1070
	'info',
1071
	false);
1072 99caa67c Seth Mos
?>
1073 f78bbe16 Phil Davis
</div>
1074 cd2c7940 sbeaver
<div class="panel panel-default">
1075 544af3fe k-paulius
	<div class="panel-heading"><h2 class="panel-title"><?=gettext("DHCPv6 Static Mappings for this Interface");?></h2></div>
1076 cd2c7940 sbeaver
	<div class="panel-body table-responsive">
1077
		<table class="table table-striped table-hover table-condensed">
1078
			<thead>
1079
				<tr>
1080
					<th><?=gettext("DUID")?></th>
1081
					<th><?=gettext("IPv6 address")?></th>
1082
					<th><?=gettext("Hostname")?></th>
1083
					<th><?=gettext("Description")?></th>
1084
					<th><!-- Buttons --></th>
1085
				</tr>
1086
			</thead>
1087
			<tbody>
1088 99caa67c Seth Mos
<?php
1089 6e3488e9 Phil Davis
if (is_array($a_maps)):
1090 99caa67c Seth Mos
	$i = 0;
1091 cd2c7940 sbeaver
	foreach ($a_maps as $mapent):
1092 6e3488e9 Phil Davis
		if ($mapent['duid'] != "" or $mapent['ipaddrv6'] != ""):
1093 99caa67c Seth Mos
?>
1094 cd2c7940 sbeaver
				<tr>
1095 7d0ad4ec Joecowboy
					<td>
1096 cd2c7940 sbeaver
						<?=htmlspecialchars($mapent['duid'])?>
1097 7d0ad4ec Joecowboy
					</td>
1098
					<td>
1099 cd2c7940 sbeaver
						<?=htmlspecialchars($mapent['ipaddrv6'])?>
1100 7d0ad4ec Joecowboy
					</td>
1101
					<td>
1102 cd2c7940 sbeaver
						<?=htmlspecialchars($mapent['hostname'])?>
1103
					</td>
1104
					<td>
1105
						<?=htmlspecialchars($mapent['descr'])?>
1106
					</td>
1107
					<td>
1108 33f0b0d5 Stephen Beaver
						<a class="fa fa-pencil"	title="<?=gettext('Edit static mapping')?>" href="services_dhcpv6_edit.php?if=<?=$if?>&amp;id=<?=$i?>"></a>
1109 c946d721 Steve Beaver
						<a class="fa fa-trash"	title="<?=gettext('Delete static mapping')?>" href="services_dhcpv6.php?if=<?=$if?>&amp;act=del&amp;id=<?=$i?>" usepost></a>
1110 7d0ad4ec Joecowboy
					</td>
1111 99caa67c Seth Mos
				</tr>
1112 cd2c7940 sbeaver
<?php
1113
		endif;
1114
	$i++;
1115
	endforeach;
1116
endif;
1117
?>
1118
			</tbody>
1119 99caa67c Seth Mos
		</table>
1120
	</div>
1121 cd2c7940 sbeaver
</div>
1122
1123 c10cb196 Stephen Beaver
<nav class="action-buttons">
1124 c9679d8c Stephen Beaver
	<a href="services_dhcpv6_edit.php?if=<?=$if?>" class="btn btn-sm btn-success"/>
1125 9d5a20cf heper
		<i class="fa fa-plus icon-embed-btn"></i>
1126 c9679d8c Stephen Beaver
		<?=gettext("Add")?>
1127
	</a>
1128 cd2c7940 sbeaver
</nav>
1129
1130 8fd9052f Colin Fleming
<script type="text/javascript">
1131 ee9530e1 Colin Fleming
//<![CDATA[
1132 6e3488e9 Phil Davis
events.push(function() {
1133 cd2c7940 sbeaver
1134 4aa42b06 Phil Davis
	// Show advanced DNS options ======================================================================================
1135
	var showadvdns = false;
1136
1137
	function show_advdns(ispageload) {
1138
		var text;
1139
		// On page load decide the initial state based on the data.
1140
		if (ispageload) {
1141
<?php
1142
			if (!$pconfig['ddnsupdate'] &&
1143 1a6bda5b Ross Williams
			    !$pconfig['ddnsforcehostname'] &&
1144 4aa42b06 Phil Davis
			    empty($pconfig['ddnsdomain']) &&
1145
			    empty($pconfig['ddnsdomainprimary']) &&
1146 9fbd8f71 Viktor Gurov
			    empty($pconfig['ddnsdomainsecondary']) &&
1147 4aa42b06 Phil Davis
			    empty($pconfig['ddnsdomainkeyname']) &&
1148 7ba6788b jim-p
			    (empty($pconfig['ddnsdomainkeyalgorithm'])  || ($pconfig['ddnsdomainkeyalgorithm'] == "hmac-md5")) &&
1149 4aa42b06 Phil Davis
			    empty($pconfig['ddnsdomainkey']) &&
1150
			    (empty($pconfig['ddnsclientupdates']) || ($pconfig['ddnsclientupdates'] == "allow")) &&
1151
			    !$pconfig['ddnsreverse']) {
1152
				$showadv = false;
1153
			} else {
1154
				$showadv = true;
1155
			}
1156
?>
1157
			showadvdns = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1158
		} else {
1159
			// It was a click, swap the state.
1160
			showadvdns = !showadvdns;
1161
		}
1162
1163
		hideCheckbox('ddnsupdate', !showadvdns);
1164
		hideInput('ddnsdomain', !showadvdns);
1165 1a6bda5b Ross Williams
		hideCheckbox('ddnsforcehostname', !showadvdns);
1166 4aa42b06 Phil Davis
		hideInput('ddnsdomainprimary', !showadvdns);
1167 9fbd8f71 Viktor Gurov
		hideInput('ddnsdomainsecondary', !showadvdns);
1168 4aa42b06 Phil Davis
		hideInput('ddnsdomainkeyname', !showadvdns);
1169 534d7d69 Joeri Capens
		hideInput('ddnsdomainkeyalgorithm', !showadvdns);
1170 4aa42b06 Phil Davis
		hideInput('ddnsdomainkey', !showadvdns);
1171
		hideInput('ddnsclientupdates', !showadvdns);
1172
		hideCheckbox('ddnsreverse', !showadvdns);
1173
1174
		if (showadvdns) {
1175
			text = "<?=gettext('Hide Advanced');?>";
1176
		} else {
1177
			text = "<?=gettext('Display Advanced');?>";
1178
		}
1179
		$('#btnadvdns').html('<i class="fa fa-cog"></i> ' + text);
1180 cd2c7940 sbeaver
	}
1181
1182 4aa42b06 Phil Davis
	$('#btnadvdns').click(function(event) {
1183
		show_advdns();
1184 cd2c7940 sbeaver
	});
1185
1186 4aa42b06 Phil Davis
	// Show advanced NTP options ======================================================================================
1187
	var showadvntp = false;
1188 cd2c7940 sbeaver
1189 4aa42b06 Phil Davis
	function show_advntp(ispageload) {
1190
		var text;
1191
		// On page load decide the initial state based on the data.
1192
		if (ispageload) {
1193
<?php
1194 5c52a260 kiokoman
			if (empty($pconfig['ntp1']) && empty($pconfig['ntp2']) && empty($pconfig['ntp3'])) {
1195 4aa42b06 Phil Davis
				$showadv = false;
1196
			} else {
1197
				$showadv = true;
1198
			}
1199
?>
1200
			showadvntp = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1201
		} else {
1202
			// It was a click, swap the state.
1203
			showadvntp = !showadvntp;
1204
		}
1205 cd2c7940 sbeaver
1206 4aa42b06 Phil Davis
		hideInput('ntp1', !showadvntp);
1207
		hideInput('ntp2', !showadvntp);
1208 5c52a260 kiokoman
		hideInput('ntp3', !showadvntp);
1209 cd2c7940 sbeaver
1210 4aa42b06 Phil Davis
		if (showadvntp) {
1211
			text = "<?=gettext('Hide Advanced');?>";
1212
		} else {
1213
			text = "<?=gettext('Display Advanced');?>";
1214
		}
1215
		$('#btnadvntp').html('<i class="fa fa-cog"></i> ' + text);
1216
	}
1217 cd2c7940 sbeaver
1218 4aa42b06 Phil Davis
	$('#btnadvntp').click(function(event) {
1219
		show_advntp();
1220 cd2c7940 sbeaver
	});
1221
1222 4aa42b06 Phil Davis
	// Show advanced LDAP options ======================================================================================
1223
	var showadvldap = false;
1224 cd2c7940 sbeaver
1225 4aa42b06 Phil Davis
	function show_advldap(ispageload) {
1226
		var text;
1227
		// On page load decide the initial state based on the data.
1228
		if (ispageload) {
1229
<?php
1230
			if (empty($pconfig['ldap'])) {
1231
				$showadv = false;
1232
			} else {
1233
				$showadv = true;
1234
			}
1235
?>
1236
			showadvldap = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1237
		} else {
1238
			// It was a click, swap the state.
1239
			showadvldap = !showadvldap;
1240
		}
1241
1242
		hideInput('ldap', !showadvldap);
1243
1244
		if (showadvldap) {
1245
			text = "<?=gettext('Hide Advanced');?>";
1246
		} else {
1247
			text = "<?=gettext('Display Advanced');?>";
1248
		}
1249
		$('#btnadvldap').html('<i class="fa fa-cog"></i> ' + text);
1250
	}
1251
1252
	$('#btnadvldap').click(function(event) {
1253
		show_advldap();
1254 cd2c7940 sbeaver
	});
1255
1256 4aa42b06 Phil Davis
	// Show advanced Netboot options ======================================================================================
1257
	var showadvnetboot = false;
1258
1259
	function show_advnetboot(ispageload) {
1260
		var text;
1261
		// On page load decide the initial state based on the data.
1262
		if (ispageload) {
1263
<?php
1264 e46ea2c6 Stephen Jones
			if (!$pconfig['netboot'] && empty($pconfig['bootfile_url'])) {
1265 4aa42b06 Phil Davis
				$showadv = false;
1266
			} else {
1267
				$showadv = true;
1268
			}
1269
?>
1270
			showadvnetboot = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1271
		} else {
1272
			// It was a click, swap the state.
1273
			showadvnetboot = !showadvnetboot;
1274
		}
1275
1276 e46ea2c6 Stephen Jones
		hideCheckbox('netboot', !showadvnetboot);
1277 4aa42b06 Phil Davis
		hideInput('bootfile_url', !showadvnetboot);
1278
1279
		if (showadvnetboot) {
1280
			text = "<?=gettext('Hide Advanced');?>";
1281
		} else {
1282
			text = "<?=gettext('Display Advanced');?>";
1283
		}
1284
		$('#btnadvnetboot').html('<i class="fa fa-cog"></i> ' + text);
1285
	}
1286
1287
	$('#btnadvnetboot').click(function(event) {
1288
		show_advnetboot();
1289 cd2c7940 sbeaver
	});
1290
1291 4aa42b06 Phil Davis
	// Show advanced additional opts options ===========================================================================
1292
	var showadvopts = false;
1293
1294
	function show_advopts(ispageload) {
1295
		var text;
1296
		// On page load decide the initial state based on the data.
1297
		if (ispageload) {
1298
<?php
1299
			if (empty($pconfig['numberoptions']) ||
1300
			    (empty($pconfig['numberoptions']['item'][0]['number']) && (empty($pconfig['numberoptions']['item'][0]['value'])))) {
1301
				$showadv = false;
1302
			} else {
1303
				$showadv = true;
1304
			}
1305
?>
1306
			showadvopts = <?php if ($showadv) {echo 'true';} else {echo 'false';} ?>;
1307
		} else {
1308
			// It was a click, swap the state.
1309
			showadvopts = !showadvopts;
1310
		}
1311
1312
		hideClass('adnloptions', !showadvopts);
1313
		hideInput('addrow', !showadvopts);
1314
1315
		if (showadvopts) {
1316
			text = "<?=gettext('Hide Advanced');?>";
1317
		} else {
1318
			text = "<?=gettext('Display Advanced');?>";
1319
		}
1320
		$('#btnadvopts').html('<i class="fa fa-cog"></i> ' + text);
1321
	}
1322
1323
	$('#btnadvopts').click(function(event) {
1324
		show_advopts();
1325 9eeb91dd Stephen Beaver
		checkLastRow();
1326 cd2c7940 sbeaver
	});
1327
1328
	// On initial load
1329 4aa42b06 Phil Davis
	show_advdns(true);
1330
	show_advntp(true);
1331
	show_advldap(true);
1332
	show_advnetboot(true);
1333
	show_advopts(true);
1334 611cc5ca Renato Botelho
	if ($('#enable').prop('checked')) {
1335
		hideClass('adnloptions', <?php echo json_encode($noopts); ?>);
1336
		hideInput('addrow', <?php echo json_encode($noopts); ?>);
1337
	} else {
1338
		hideClass('adnloptions', true);
1339
		hideInput('addrow', true);
1340
	}
1341 9eeb91dd Stephen Beaver
1342 cd2c7940 sbeaver
});
1343 ee9530e1 Colin Fleming
//]]>
1344 99caa67c Seth Mos
</script>
1345 cd2c7940 sbeaver
1346 2f5dafed heper
<?php include('foot.inc');