Project

General

Profile

Download (83.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services.inc
4
	part of the pfSense project (https://www.pfsense.org)
5

    
6
	originally part of m0n0wall (http://m0n0.ch/wall)
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
8
	Copyright (C) 2010	Ermal Luçi
9
	All rights reserved.
10

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

    
17
	2. Redistributions in binary form must reproduce the above copyright
18
	   notice, this list of conditions and the following disclaimer in the
19
	   documentation and/or other materials provided with the distribution.
20

    
21
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
	POSSIBILITY OF SUCH DAMAGE.
31
*/
32

    
33
/*
34
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/bin/pgrep	/bin/sh	/usr/local/sbin/dhcpd	/usr/local/sbin/igmpproxy
35
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig		/usr/local/sbin/dnsmasq
36
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/miniupnpd	/usr/sbin/radvd
37
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcleases6	/usr/sbin/bsnmpd
38
	pfSense_MODULE:	utils
39
*/
40

    
41
define('DYNDNS_PROVIDER_VALUES', 'citynetwork cloudflare custom custom-v6 dnsexit dnsimple dnsmadeeasy dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns glesys googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost zoneedit');
42
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'City Network,CloudFlare,Custom,Custom (v6),DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,GleSYS,Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,ZoneEdit');
43

    
44
/* implement ipv6 route advertising daemon */
45
function services_radvd_configure($blacklist = array()) {
46
	global $config, $g;
47

    
48
	if (isset($config['system']['developerspew'])) {
49
		$mt = microtime();
50
		echo "services_radvd_configure() being called $mt\n";
51
	}
52

    
53
	if (!is_array($config['dhcpdv6'])) {
54
		$config['dhcpdv6'] = array();
55
	}
56

    
57
	$Iflist = get_configured_interface_list();
58
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
59
	$carplist = get_configured_carp_interface_list();
60

    
61
	$radvdconf = "# Automatically Generated, do not edit\n";
62

    
63
	/* Process all links which need the router advertise daemon */
64
	$radvdifs = array();
65

    
66
	/* handle manually configured DHCP6 server settings first */
67
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
68
		if (!is_array($config['interfaces'][$dhcpv6if])) {
69
			continue;
70
		}
71
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
72
			continue;
73
		}
74

    
75
		/* Do not put in the config an interface which is down */
76
		if (isset($blacklist[$dhcpv6if])) {
77
			continue;
78
		}
79
		if (!isset($dhcpv6ifconf['ramode'])) {
80
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
81
		}
82

    
83
		/* are router advertisements enabled? */
84
		if ($dhcpv6ifconf['ramode'] == "disabled") {
85
			continue;
86
		}
87

    
88
		if (!isset($dhcpv6ifconf['rapriority'])) {
89
			$dhcpv6ifconf['rapriority'] = "medium";
90
		}
91

    
92
		/* always start with the real parent, we override with the carp if later */
93
		$carpif = false;
94
		/* check if we need to listen on a CARP interface */
95
		if (!empty($dhcpv6ifconf['rainterface'])) {
96
			if (!empty($carplist[$dhcpv6ifconf['rainterface']])) {
97
				$dhcpv6if = $dhcpv6ifconf['rainterface'];
98
				$carpif = true;
99
			}
100
		}
101

    
102
		if (strstr($dhcpv6if, "_vip")) {
103
			// CARP IP, check if it's enabled and find parent
104
			if (!get_carp_status() || get_carp_interface_status($dhcpv6if) != "MASTER") {
105
				continue;
106
			}
107
			$ifparent = link_carp_interface_to_parent($dhcpv6if);
108
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
109
		} else {
110
			$realif = get_real_interface($dhcpv6if, "inet6");
111
		}
112

    
113
		if (isset($radvdifs[$realif])) {
114
			continue;
115
		}
116

    
117
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
118
		if (!is_ipaddrv6($ifcfgipv6)) {
119
			continue;
120
		}
121

    
122
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
123
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
124
		$radvdifs[$realif] = $realif;
125

    
126
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
127
		$radvdconf .= "interface {$realif} {\n";
128
		if (strstr($realif, "ovpn")) {
129
			$radvdconf .= "\tUnicastOnly on;\n";
130
		}
131
		$radvdconf .= "\tAdvSendAdvert on;\n";
132
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
133
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
134
		$mtu = get_interface_mtu($realif);
135
		if (is_numeric($mtu)) {
136
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
137
		} else {
138
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
139
		}
140
		// $radvdconf .= "\tDeprecatePrefix on;\n";
141
		switch ($dhcpv6ifconf['rapriority']) {
142
			case "low":
143
				$radvdconf .= "\tAdvDefaultPreference low;\n";
144
				break;
145
			case "high":
146
				$radvdconf .= "\tAdvDefaultPreference high;\n";
147
				break;
148
			default:
149
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
150
				break;
151
		}
152
		switch ($dhcpv6ifconf['ramode']) {
153
			case "managed":
154
			case "assist":
155
				$radvdconf .= "\tAdvManagedFlag on;\n";
156
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
157
				break;
158
			case "stateless_dhcp":
159
				$radvdconf .= "\tAdvManagedFlag off;\n";
160
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
161
				break;
162
		}
163
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
164
		if ($carpif == true) {
165
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
166
		} else {
167
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
168
		}
169
		switch ($dhcpv6ifconf['ramode']) {
170
			case "managed":
171
				$radvdconf .= "\t\tAdvOnLink on;\n";
172
				$radvdconf .= "\t\tAdvAutonomous off;\n";
173
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
174
				break;
175
			case "router":
176
				$radvdconf .= "\t\tAdvOnLink off;\n";
177
				$radvdconf .= "\t\tAdvAutonomous off;\n";
178
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
179
				break;
180
			case "stateless_dhcp":
181
			case "assist":
182
				$radvdconf .= "\t\tAdvOnLink on;\n";
183
				$radvdconf .= "\t\tAdvAutonomous on;\n";
184
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
185
				break;
186
			case "unmanaged":
187
				$radvdconf .= "\t\tAdvOnLink on;\n";
188
				$radvdconf .= "\t\tAdvAutonomous on;\n";
189
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
190
				break;
191
		}
192
		$radvdconf .= "\t};\n";
193

    
194
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
195
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
196
				if (is_subnetv6($subnet)) {
197
					$radvdconf .= "\tprefix {$subnet} {\n";
198
					if ($carpif == true) {
199
						$radvdconf .= "\t\tDeprecatePrefix off;\n";
200
					} else {
201
						$radvdconf .= "\t\tDeprecatePrefix on;\n";
202
					}
203
					switch ($dhcpv6ifconf['ramode']) {
204
						case "managed":
205
							$radvdconf .= "\t\tAdvOnLink on;\n";
206
							$radvdconf .= "\t\tAdvAutonomous off;\n";
207
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
208
							break;
209
						case "router":
210
							$radvdconf .= "\t\tAdvOnLink off;\n";
211
							$radvdconf .= "\t\tAdvAutonomous off;\n";
212
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
213
							break;
214
						case "assist":
215
							$radvdconf .= "\t\tAdvOnLink on;\n";
216
							$radvdconf .= "\t\tAdvAutonomous on;\n";
217
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
218
							break;
219
						case "unmanaged":
220
							$radvdconf .= "\t\tAdvOnLink on;\n";
221
							$radvdconf .= "\t\tAdvAutonomous on;\n";
222
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
223
							break;
224
					}
225
					$radvdconf .= "\t};\n";
226
				}
227
			}
228
		}
229
		if ($carpif === true) {
230
			$radvdconf .= "\troute ::/0 {\n";
231
			$radvdconf .= "\t\tRemoveRoute off;\n";
232
			$radvdconf .= "\t};\n";
233
		} else {
234
			$radvdconf .= "\troute ::/0 {\n";
235
			$radvdconf .= "\t\tRemoveRoute on;\n";
236
			$radvdconf .= "\t};\n";
237
		}
238

    
239
		/* add DNS servers */
240
		$dnslist = array();
241
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
242
			foreach ($dhcpv6ifconf['dnsserver'] as $server) {
243
				if (is_ipaddrv6($server)) {
244
					$dnslist[] = $server;
245
				}
246
			}
247
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
248
			foreach ($dhcpv6ifconf['radnsserver'] as $server) {
249
				if (is_ipaddrv6($server)) {
250
					$dnslist[] = $server;
251
				}
252
			}
253
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
254
			$dnslist[] = get_interface_ipv6($realif);
255
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
256
			foreach ($config['system']['dnsserver'] as $server) {
257
				if (is_ipaddrv6($server)) {
258
					$dnslist[] = $server;
259
				}
260
			}
261
		}
262
		if (count($dnslist) > 0) {
263
			$dnsstring = implode(" ", $dnslist);
264
			if ($dnsstring <> "") {
265
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
266
			}
267
		}
268
		if (!empty($dhcpv6ifconf['domain'])) {
269
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
270
		} elseif (!empty($config['system']['domain'])) {
271
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
272
		}
273
		$radvdconf .= "};\n";
274
	}
275

    
276
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
277
	foreach ($Iflist as $if => $ifdescr) {
278
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
279
			continue;
280
		}
281
		if (!isset($config['interfaces'][$if]['enable'])) {
282
			continue;
283
		}
284
		/* Do not put in the config an interface which is down */
285
		if (isset($blacklist[$if])) {
286
			continue;
287
		}
288
		$trackif = $config['interfaces'][$if]['track6-interface'];
289
		if (empty($config['interfaces'][$trackif])) {
290
			continue;
291
		}
292

    
293
		if (strstr($if, "_vip")) {
294
			// CARP IP, find parent
295
			$ifparent = link_carp_interface_to_parent($if);
296
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
297
		} else {
298
			$realif = get_real_interface($if, "inet6");
299
		}
300

    
301
		/* prevent duplicate entries, manual overrides */
302
		if (isset($radvdifs[$realif])) {
303
			continue;
304
		}
305

    
306
		$ifcfgipv6 = get_interface_ipv6($if);
307
		if (!is_ipaddrv6($ifcfgipv6)) {
308
			$subnetv6 = "::";
309
			$ifcfgsnv6 = "64";
310
		} else {
311
			$ifcfgsnv6 = get_interface_subnetv6($if);
312
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
313
		}
314
		$radvdifs[$realif] = $realif;
315

    
316
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
317

    
318
		if ($g['debug']) {
319
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
320
		}
321

    
322
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
323
		$radvdconf .= "interface {$realif} {\n";
324
		$radvdconf .= "\tAdvSendAdvert on;\n";
325
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
326
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
327
		$mtu = get_interface_mtu($realif);
328
		if (is_numeric($mtu)) {
329
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
330
		} else {
331
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
332
		}
333
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
334
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
335
		$radvdconf .= "\t\tAdvOnLink on;\n";
336
		$radvdconf .= "\t\tAdvAutonomous on;\n";
337
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
338
		$radvdconf .= "\t};\n";
339

    
340
		/* add DNS servers */
341
		$dnslist = array();
342
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
343
			$dnslist[] = $ifcfgipv6;
344
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
345
			foreach ($config['system']['dnsserver'] as $server) {
346
				if (is_ipaddrv6($server)) {
347
					$dnslist[] = $server;
348
				}
349
			}
350
		}
351
		if (count($dnslist) > 0) {
352
			$dnsstring = implode(" ", $dnslist);
353
			if (!empty($dnsstring)) {
354
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
355
			}
356
		}
357
		if (!empty($config['system']['domain'])) {
358
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
359
		}
360
		$radvdconf .= "};\n";
361
	}
362

    
363
	/* write radvd.conf */
364
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
365
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
366
		if (platform_booting()) {
367
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
368
		}
369
	}
370
	unset($radvdconf);
371

    
372
	if (count($radvdifs) > 0) {
373
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
374
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
375
		} else {
376
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
377
		}
378
	} else {
379
		/* we need to shut down the radvd cleanly, it will send out the prefix
380
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
381
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
382
			log_error("Shutting down Router Advertisment daemon cleanly");
383
			killbypid("{$g['varrun_path']}/radvd.pid");
384
			@unlink("{$g['varrun_path']}/radvd.pid");
385
		}
386
	}
387
	return 0;
388
}
389

    
390
function services_dhcpd_configure($family = "all", $blacklist = array()) {
391
	global $config, $g;
392

    
393
	/* configure DHCPD chroot once */
394
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh", "w");
395
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
396
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
397
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
398
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
399
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
400
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
401
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
402
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
403
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
404
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
405
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
406
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
407
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
408

    
409
	$status = `/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep "{$g['dhcpd_chroot_path']}/dev"`;
410
	if (!trim($status)) {
411
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
412
	}
413
	fclose($fd);
414
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
415

    
416
	if ($family == "all" || $family == "inet") {
417
		services_dhcpdv4_configure();
418
	}
419
	if ($family == "all" || $family == "inet6") {
420
		services_dhcpdv6_configure($blacklist);
421
		services_radvd_configure($blacklist);
422
	}
423
}
424

    
425
function services_dhcpdv4_configure() {
426
	global $config, $g;
427
	$need_ddns_updates = false;
428
	$ddns_zones = array();
429

    
430
	if ($g['services_dhcp_server_enable'] == false) {
431
		return;
432
	}
433

    
434
	if (isset($config['system']['developerspew'])) {
435
		$mt = microtime();
436
		echo "services_dhcpdv4_configure($if) being called $mt\n";
437
	}
438

    
439
	/* kill any running dhcpd */
440
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
441
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
442
	}
443

    
444
	/* DHCP enabled on any interfaces? */
445
	if (!is_dhcp_server_enabled()) {
446
		return 0;
447
	}
448

    
449
	/* if OLSRD is enabled, allow WAN to house DHCP. */
450
	if (!function_exists('is_package_installed')) {
451
		require_once('pkg-utils.inc');
452
	}
453
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) {
454
		foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
455
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
456
				$is_olsr_enabled = true;
457
				break;
458
			}
459
		}
460
	}
461

    
462
	if (platform_booting()) {
463
		/* restore the leases, if we have them */
464
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
465
			$dhcprestore = "";
466
			$dhcpreturn = "";
467
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
468
			$dhcprestore = implode(" ", $dhcprestore);
469
			if ($dhcpreturn <> 0) {
470
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
471
			}
472
		}
473
		/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
474
		if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
475
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
476
		}
477
	}
478

    
479
	$syscfg = $config['system'];
480
	if (!is_array($config['dhcpd'])) {
481
		$config['dhcpd'] = array();
482
	}
483
	$dhcpdcfg = $config['dhcpd'];
484
	$Iflist = get_configured_interface_list();
485

    
486
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
487
	$dns_arrv4 = array();
488
	if (is_array($syscfg['dnsserver'])) {
489
		foreach ($syscfg['dnsserver'] as $dnsserver) {
490
			if (is_ipaddrv4($dnsserver)) {
491
				$dns_arrv4[] = $dnsserver;
492
			}
493
		}
494
	}
495

    
496
	if (platform_booting()) {
497
		echo gettext("Starting DHCP service...");
498
	} else {
499
		sleep(1);
500
	}
501

    
502
	$custoptions = "";
503
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
504
		if (is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
505
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
506
				if (!empty($item['type'])) {
507
					$itemtype = $item['type'];
508
				} else {
509
					$itemtype = "text";
510
				}
511
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
512
			}
513
		}
514
	}
515

    
516
	$dhcpdconf = <<<EOD
517

    
518
option domain-name "{$syscfg['domain']}";
519
option ldap-server code 95 = text;
520
option domain-search-list code 119 = text;
521
option arch code 93 = unsigned integer 16; # RFC4578
522
{$custoptions}
523
default-lease-time 7200;
524
max-lease-time 86400;
525
log-facility local7;
526
one-lease-per-client true;
527
deny duplicates;
528
ping-check true;
529
update-conflict-detection false;
530

    
531
EOD;
532

    
533
	if (!isset($dhcpifconf['disableauthoritative'])) {
534
		$dhcpdconf .= "authoritative;\n";
535
	}
536

    
537
	if (isset($dhcpifconf['alwaysbroadcast'])) {
538
		$dhcpdconf .= "always-broadcast on\n";
539
	}
540

    
541
	$dhcpdifs = array();
542
	$enable_add_routers = false;
543
	$gateways_arr = return_gateways_array();
544
	/* only add a routers line if the system has any IPv4 gateway at all */
545
	/* a static route has a gateway, manually overriding this field always works */
546
	foreach ($gateways_arr as $gwitem) {
547
		if ($gwitem['ipprotocol'] == "inet") {
548
			$enable_add_routers = true;
549
			break;
550
		}
551
	}
552

    
553
	/*    loop through and determine if we need to setup
554
	 *    failover peer "bleh" entries
555
	 */
556
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
557

    
558
		if (!isset($config['interfaces'][$dhcpif]['enable'])) {
559
			continue;
560
		}
561

    
562
		interfaces_staticarp_configure($dhcpif);
563

    
564
		if (!isset($dhcpifconf['enable'])) {
565
			continue;
566
		}
567

    
568
		if ($dhcpifconf['failover_peerip'] <> "") {
569
			$intip = get_interface_ip($dhcpif);
570
			/*
571
			 *    yep, failover peer is defined.
572
			 *    does it match up to a defined vip?
573
			 */
574
			$skew = 110;
575
			if (is_array($config['virtualip']['vip'])) {
576
				foreach ($config['virtualip']['vip'] as $vipent) {
577
					if ($vipent['interface'] == $dhcpif) {
578
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
579
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
580
							/* this is the interface! */
581
							if (is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
582
								$skew = 0;
583
								break;
584
							}
585
						}
586
					}
587
				}
588
			} else {
589
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
590
			}
591
			if ($skew > 10) {
592
				$type = "secondary";
593
				$my_port = "520";
594
				$peer_port = "519";
595
			} else {
596
				$my_port = "519";
597
				$peer_port = "520";
598
				$type = "primary";
599
				$dhcpdconf_pri = "split 128;\n";
600
				$dhcpdconf_pri .= "  mclt 600;\n";
601
			}
602

    
603
			if (is_ipaddrv4($intip)) {
604
				$dhcpdconf .= <<<EOPP
605
failover peer "dhcp_{$dhcpif}" {
606
  {$type};
607
  address {$intip};
608
  port {$my_port};
609
  peer address {$dhcpifconf['failover_peerip']};
610
  peer port {$peer_port};
611
  max-response-delay 10;
612
  max-unacked-updates 10;
613
  {$dhcpdconf_pri}
614
  load balance max seconds 3;
615
}
616
\n
617
EOPP;
618
			}
619
		}
620
	}
621

    
622
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
623

    
624
		$newzone = array();
625
		$ifcfg = $config['interfaces'][$dhcpif];
626

    
627
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) {
628
			continue;
629
		}
630
		$ifcfgip = get_interface_ip($dhcpif);
631
		$ifcfgsn = get_interface_subnet($dhcpif);
632
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
633
		$subnetmask = gen_subnet_mask($ifcfgsn);
634

    
635
		if (!is_ipaddr($subnet)) {
636
			continue;
637
		}
638

    
639
		if ($is_olsr_enabled == true) {
640
			if ($dhcpifconf['netmask']) {
641
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
642
			}
643
		}
644

    
645
		$all_pools = array();
646
		$all_pools[] = $dhcpifconf;
647
		if (is_array($dhcpifconf['pool'])) {
648
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
649
		}
650

    
651
		$dnscfg = "";
652

    
653
		if ($dhcpifconf['domain']) {
654
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
655
		}
656

    
657
		if ($dhcpifconf['domainsearchlist'] <> "") {
658
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
659
		}
660

    
661
		if (isset($dhcpifconf['ddnsupdate'])) {
662
			$need_ddns_updates = true;
663
			$newzone = array();
664
			if ($dhcpifconf['ddnsdomain'] <> "") {
665
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
666
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
667
			} else {
668
				$newzone['domain-name'] = $config['system']['domain'];
669
			}
670
			$revsubnet = explode(".", $subnet);
671
			$revsubnet = array_reverse($revsubnet);
672
			foreach ($revsubnet as $octet) {
673
				if ($octet != "0") {
674
					break;
675
				}
676
				array_shift($revsubnet);
677
			}
678
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
679
		}
680

    
681
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
682
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
683
			if ($newzone['domain-name']) {
684
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
685
			}
686
		} else if (isset($config['dnsmasq']['enable'])) {
687
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
688
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
689
				$newzone['dns-servers'] = $syscfg['dnsserver'];
690
			}
691
		} else if (isset($config['unbound']['enable'])) {
692
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
693
		} else if (!empty($dns_arrv4)) {
694
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
695
			if ($newzone['domain-name']) {
696
				$newzone['dns-servers'] = $dns_arrv4;
697
			}
698
		}
699

    
700
		/* Create classes - These all contain comma separated lists. Join them into one
701
		   big comma separated string then split them all up. */
702
		$all_mac_strings = array();
703
		if (is_array($dhcpifconf['pool'])) {
704
			foreach ($all_pools as $poolconf) {
705
				$all_mac_strings[] = $poolconf['mac_allow'];
706
				$all_mac_strings[] = $poolconf['mac_deny'];
707
			}
708
		}
709
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
710
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
711
		if (!empty($all_mac_strings)) {
712
			$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
713
			foreach ($all_mac_list as $mac) {
714
				if (empty($mac)) {
715
					continue;
716
				}
717
				$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
718
				// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
719
				$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
720
				$dhcpdconf .= '}' . "\n";
721
			}
722
		}
723

    
724
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
725

    
726
		// Setup pool options
727
		foreach ($all_pools as $poolconf) {
728
			if (!(ip_in_subnet($poolconf['range']['from'], "{$subnet}/{$ifcfgsn}") && ip_in_subnet($poolconf['range']['to'], "{$subnet}/{$ifcfgsn}"))) {
729
				// If the user has changed the subnet from the interfaces page and applied,
730
				// but has not updated the DHCP range, then the range to/from of the pool can be outside the subnet.
731
				// This can also happen when implementing the batch of changes when the setup wizard reloads the new settings.
732
				$error_msg = sprintf(gettext("Invalid DHCP pool %s - %s for %s subnet %s/%s detected. Please correct the settings in Services, DHCP Server"), $poolconf['range']['from'], $poolconf['range']['to'], convert_real_interface_to_friendly_descr($dhcpif), $subnet, $ifcfgsn);
733
				$do_file_notice = true;
734
				$conf_ipv4_address = $ifcfg['ipaddr'];
735
				$conf_ipv4_subnetmask = $ifcfg['subnet'];
736
				if (is_ipaddrv4($conf_ipv4_address) && is_subnet("{$conf_ipv4_address}/{$conf_ipv4_subnetmask}")) {
737
					$conf_subnet_base = gen_subnet($conf_ipv4_address, $conf_ipv4_subnetmask);
738
					if (ip_in_subnet($poolconf['range']['from'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}") &&
739
					    ip_in_subnet($poolconf['range']['to'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}")) {
740
						// Even though the running interface subnet does not match the pool range,
741
						// the interface subnet in the config file contains the pool range.
742
						// We are somewhere part-way through a settings reload, e.g. after running the setup wizard.
743
						// services_dhcpdv4_configure will be called again later when the new interface settings from
744
						// the config are applied and at that time everything will match up.
745
						// Ignore this pool on this interface for now and just log the error to the system log.
746
						log_error($error_msg);
747
						$do_file_notice = false;
748
					}
749
				}
750
				if ($do_file_notice) {
751
					file_notice("DHCP", $error_msg);
752
				}
753
				continue;
754
			}
755
			$dhcpdconf .= "	pool {\n";
756
			/* is failover dns setup? */
757
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
758
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
759
				if ($poolconf['dnsserver'][1] <> "") {
760
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
761
				}
762
				if ($poolconf['dnsserver'][2] <> "") {
763
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
764
				}
765
				if ($poolconf['dnsserver'][3] <> "") {
766
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
767
				}
768
				$dhcpdconf .= ";\n";
769
			}
770

    
771
			/* allow/deny MACs */
772
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
773
			foreach ($mac_allow_list as $mac) {
774
				if (empty($mac)) {
775
					continue;
776
				}
777
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
778
			}
779
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
780
			foreach ($mac_deny_list as $mac) {
781
				if (empty($mac)) {
782
					continue;
783
				}
784
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
785
			}
786

    
787
			if ($poolconf['failover_peerip'] <> "") {
788
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
789
			}
790

    
791
			if (isset($poolconf['denyunknown'])) {
792
			   $dhcpdconf .= "		deny unknown-clients;\n";
793
			}
794

    
795
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
796
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
797
			}
798

    
799
			if ($dhcpifconf['failover_peerip'] <> "") {
800
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
801
			}
802

    
803
			$pdnscfg = "";
804

    
805
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
806
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
807
			}
808

    
809
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
810
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
811
			}
812

    
813
			if (isset($poolconf['ddnsupdate'])) {
814
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
815
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
816
				}
817
				$pdnscfg .= "		ddns-update-style interim;\n";
818
			}
819

    
820
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
821
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
822
			}
823
			$dhcpdconf .= "{$pdnscfg}";
824

    
825
			// default-lease-time
826
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
827
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
828
			}
829

    
830
			// max-lease-time
831
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
832
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
833
			}
834

    
835
			// netbios-name*
836
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
837
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
838
				$dhcpdconf .= "		option netbios-node-type 8;\n";
839
			}
840

    
841
			// ntp-servers
842
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
843
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
844
			}
845

    
846
			// tftp-server-name
847
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
848
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
849
			}
850

    
851
			// ldap-server
852
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
853
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
854
			}
855

    
856
			// net boot information
857
			if (isset($poolconf['netboot'])) {
858
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
859
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
860
				}
861
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
862
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
863
				}
864
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
865
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
866
				}
867
			}
868
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
869
			$dhcpdconf .= "	}\n\n";
870
		}
871
// End of settings inside pools
872

    
873
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
874
			$routers = $dhcpifconf['gateway'];
875
			$add_routers = true;
876
		} elseif ($dhcpifconf['gateway'] == "none") {
877
			$add_routers = false;
878
		} else {
879
			$add_routers = $enable_add_routers;
880
			$routers = $ifcfgip;
881
		}
882
		if ($add_routers) {
883
			$dhcpdconf .= "	option routers {$routers};\n";
884
		}
885

    
886
		$dhcpdconf .= <<<EOD
887
$dnscfg
888

    
889
EOD;
890
		// default-lease-time
891
		if ($dhcpifconf['defaultleasetime']) {
892
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
893
		}
894

    
895
		// max-lease-time
896
		if ($dhcpifconf['maxleasetime']) {
897
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
898
		}
899

    
900
		// netbios-name*
901
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
902
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
903
			$dhcpdconf .= "	option netbios-node-type 8;\n";
904
		}
905

    
906
		// ntp-servers
907
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0]) {
908
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
909
		}
910

    
911
		// tftp-server-name
912
		if ($dhcpifconf['tftp'] <> "") {
913
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
914
		}
915

    
916
		// Handle option, number rowhelper values
917
		$dhcpdconf .= "\n";
918
		if ($dhcpifconf['numberoptions']['item']) {
919
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
920
				if (empty($item['type']) || $item['type'] == "text") {
921
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
922
				} else {
923
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
924
				}
925
			}
926
		}
927

    
928
		// ldap-server
929
		if ($dhcpifconf['ldap'] <> "") {
930
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
931
		}
932

    
933
		// net boot information
934
		if (isset($dhcpifconf['netboot'])) {
935
			if ($dhcpifconf['nextserver'] <> "") {
936
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
937
			}
938
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
939
				$dhcpdconf .= "	if option arch = 00:06 {\n";
940
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
941
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
942
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
943
				$dhcpdconf .= "	} else if option arch = 00:09 {\n";
944
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
945
				$dhcpdconf .= "	} else {\n";
946
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
947
				$dhcpdconf .= "	}\n\n";
948
			} elseif (!empty($dhcpifconf['filename'])) {
949
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
950
			}
951
			if (!empty($dhcpifconf['rootpath'])) {
952
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
953
			}
954
		}
955

    
956
		$dhcpdconf .= <<<EOD
957
}
958

    
959
EOD;
960

    
961
		/* add static mappings */
962
		if (is_array($dhcpifconf['staticmap'])) {
963

    
964
			$i = 0;
965
			foreach ($dhcpifconf['staticmap'] as $sm) {
966
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
967

    
968
				if ($sm['mac']) {
969
					$dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
970
				}
971

    
972
				if ($sm['cid']) {
973
					$dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
974
				}
975

    
976
				if ($sm['ipaddr']) {
977
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
978
				}
979

    
980
				if ($sm['hostname']) {
981
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
982
					$dhhostname = str_replace(".", "_", $dhhostname);
983
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
984
				}
985
				if ($sm['filename']) {
986
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
987
				}
988

    
989
				if ($sm['rootpath']) {
990
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
991
				}
992

    
993
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
994
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
995
				}
996

    
997
				$smdnscfg = "";
998

    
999
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
1000
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
1001
				}
1002

    
1003
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
1004
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
1005
				}
1006

    
1007
				if (isset($sm['ddnsupdate'])) {
1008
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
1009
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
1010
					}
1011
					$pdnscfg .= "		ddns-update-style interim;\n";
1012
				}
1013

    
1014
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
1015
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
1016
				}
1017
				$dhcpdconf .= "{$smdnscfg}";
1018

    
1019
				// default-lease-time
1020
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
1021
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
1022
				}
1023

    
1024
				// max-lease-time
1025
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
1026
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
1027
				}
1028

    
1029
				// netbios-name*
1030
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
1031
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
1032
					$dhcpdconf .= "	option netbios-node-type 8;\n";
1033
				}
1034

    
1035
				// ntp-servers
1036
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
1037
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
1038
				}
1039

    
1040
				// tftp-server-name
1041
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
1042
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
1043
				}
1044

    
1045
				$dhcpdconf .= "}\n";
1046
				$i++;
1047
			}
1048
		}
1049

    
1050
		$dhcpdifs[] = get_real_interface($dhcpif);
1051
		if ($newzone['domain-name']) {
1052
			if ($need_ddns_updates) {
1053
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
1054
			}
1055
			$ddns_zones[] = $newzone;
1056
		}
1057
	}
1058

    
1059
	if ($need_ddns_updates) {
1060
		$dhcpdconf .= "ddns-update-style interim;\n";
1061
		$dhcpdconf .= "update-static-leases on;\n";
1062

    
1063
		$dhcpdconf .= dhcpdkey($dhcpifconf);
1064
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
1065
	}
1066

    
1067
	/* write dhcpd.conf */
1068
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
1069
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1070
		unset($dhcpdconf);
1071
		return 1;
1072
	}
1073
	unset($dhcpdconf);
1074

    
1075
	/* create an empty leases database */
1076
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1077
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1078
	}
1079

    
1080
	/* make sure there isn't a stale dhcpd.pid file, which can make dhcpd fail to start.   */
1081
	/* if we get here, dhcpd has been killed and is not started yet                        */
1082
	unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
1083

    
1084
	/* fire up dhcpd in a chroot */
1085
	if (count($dhcpdifs) > 0) {
1086
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1087
			join(" ", $dhcpdifs));
1088
	}
1089

    
1090
	if (platform_booting()) {
1091
		print "done.\n";
1092
	}
1093

    
1094
	return 0;
1095
}
1096

    
1097
function dhcpdkey($dhcpifconf) {
1098
	$dhcpdconf = "";
1099
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1100
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1101
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1102
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1103
		$dhcpdconf .= "}\n";
1104
	}
1105

    
1106
	return $dhcpdconf;
1107
}
1108

    
1109
function dhcpdzones($ddns_zones, $dhcpifconf) {
1110
	$dhcpdconf = "";
1111

    
1112
	if (is_array($ddns_zones)) {
1113
		$added_zones = array();
1114
		foreach ($ddns_zones as $zone) {
1115
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1116
				continue;
1117
			}
1118
			$primary = $zone['dns-servers'][0];
1119
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1120

    
1121
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1122
			if (!is_ipaddrv4($primary)) {
1123
				if (is_ipaddrv4($secondary)) {
1124
					$primary = $secondary;
1125
					$secondary = "";
1126
				} else {
1127
					continue;
1128
				}
1129
			}
1130

    
1131
			// We don't need to add zones multiple times.
1132
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1133
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1134
				$dhcpdconf .= "	primary {$primary};\n";
1135
				if (is_ipaddrv4($secondary)) {
1136
					$dhcpdconf .= "	secondary {$secondary};\n";
1137
				}
1138
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1139
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1140
				}
1141
				$dhcpdconf .= "}\n";
1142
				$added_zones[] = $zone['domain-name'];
1143
			}
1144
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1145
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1146
				$dhcpdconf .= "	primary {$primary};\n";
1147
				if (is_ipaddrv4($secondary)) {
1148
					$dhcpdconf .= "	secondary {$secondary};\n";
1149
				}
1150
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1151
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1152
				}
1153
				$dhcpdconf .= "}\n";
1154
				$added_zones[] = $zone['ptr-domain'];
1155
			}
1156
		}
1157
	}
1158

    
1159
	return $dhcpdconf;
1160
}
1161

    
1162
function services_dhcpdv6_configure($blacklist = array()) {
1163
	global $config, $g;
1164

    
1165
	if ($g['services_dhcp_server_enable'] == false) {
1166
		return;
1167
	}
1168

    
1169
	if (isset($config['system']['developerspew'])) {
1170
		$mt = microtime();
1171
		echo "services_dhcpd_configure($if) being called $mt\n";
1172
	}
1173

    
1174
	/* kill any running dhcpd */
1175
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1176
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1177
	}
1178
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1179
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1180
	}
1181

    
1182
	/* DHCP enabled on any interfaces? */
1183
	if (!is_dhcpv6_server_enabled()) {
1184
		return 0;
1185
	}
1186

    
1187
	if (platform_booting()) {
1188
		if ($g['platform'] != $g['product_name']) {
1189
			/* restore the leases, if we have them */
1190
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1191
				$dhcprestore = "";
1192
				$dhcpreturn = "";
1193
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1194
				$dhcprestore = implode(" ", $dhcprestore);
1195
				if ($dhcpreturn <> 0) {
1196
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1197
				}
1198
			}
1199
		}
1200
	}
1201

    
1202
	$syscfg = $config['system'];
1203
	if (!is_array($config['dhcpdv6'])) {
1204
		$config['dhcpdv6'] = array();
1205
	}
1206
	$dhcpdv6cfg = $config['dhcpdv6'];
1207
	$Iflist = get_configured_interface_list();
1208
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1209

    
1210

    
1211
	if (platform_booting()) {
1212
		echo "Starting DHCPv6 service...";
1213
	} else {
1214
		sleep(1);
1215
	}
1216

    
1217
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1218
	foreach ($Iflist as $ifname) {
1219
		/* Do not put in the config an interface which is down */
1220
		if (isset($blacklist[$ifname])) {
1221
			continue;
1222
		}
1223
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1224
			$realif = get_real_interface($ifname, "inet6");
1225
			$ifcfgipv6 = get_interface_ipv6($ifname);
1226
			if (!is_ipaddrv6($ifcfgipv6)) {
1227
				continue;
1228
			}
1229
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1230
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1231
			$trackcfg = $config['interfaces'][$trackifname];
1232
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1233
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1234
			$dhcpdv6cfg[$ifname] = array();
1235
			$dhcpdv6cfg[$ifname]['enable'] = true;
1236
			/* range */
1237
			$ifcfgipv6arr[7] = "1000";
1238
			$dhcpdv6cfg[$ifname]['range'] = array();
1239
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1240
			$ifcfgipv6arr[7] = "2000";
1241
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1242
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1243
			if ($pdlen > 2) {
1244
				$pdlenmax = $pdlen;
1245
				$pdlenhalf = $pdlenmax -1;
1246
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1247
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1248
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1249

    
1250
				/* set the delegation start to half the current address block */
1251
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1252
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1253

    
1254
				/* set the end range to a multiple of the prefix delegation size, required by dhcpd */
1255
				$range = Net_IPv6::parseAddress($range['end'], (64 - $pdlenhalf));
1256
				$range['end'] = Net_IPv6::getNetmask($range['end'], (64 - round($pdlen / 2)));
1257

    
1258
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1259
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1260
			}
1261
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1262
		}
1263
	}
1264

    
1265
	$custoptionsv6 = "";
1266
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1267
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1268
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1269
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1270
			}
1271
		}
1272
	}
1273

    
1274
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1275
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1276
	}
1277

    
1278
	$dhcpdv6conf = <<<EOD
1279

    
1280
option domain-name "{$syscfg['domain']}";
1281
option ldap-server code 95 = text;
1282
option domain-search-list code 119 = text;
1283
{$custoptionsv6}
1284
default-lease-time 7200;
1285
max-lease-time 86400;
1286
log-facility local7;
1287
one-lease-per-client true;
1288
deny duplicates;
1289
ping-check true;
1290
update-conflict-detection false;
1291

    
1292
EOD;
1293

    
1294
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1295
		$dhcpdv6conf .= "authoritative;\n";
1296
	}
1297

    
1298
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1299
		$dhcpdv6conf .= "always-broadcast on\n";
1300
	}
1301

    
1302
	$dhcpdv6ifs = array();
1303

    
1304
	$dhcpv6num = 0;
1305
	$nsupdate = false;
1306

    
1307
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1308

    
1309
		$ddns_zones = array();
1310

    
1311
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1312

    
1313
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1314
			continue;
1315
		}
1316
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1317
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1318
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1319

    
1320
		if ($is_olsr_enabled == true) {
1321
			if ($dhcpv6ifconf['netmask']) {
1322
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1323
			}
1324
		}
1325

    
1326
		$dnscfgv6 = "";
1327

    
1328
		if ($dhcpv6ifconf['domain']) {
1329
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1330
		}
1331

    
1332
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1333
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1334
		}
1335

    
1336
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1337
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1338
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1339
			}
1340
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1341
			$nsupdate = true;
1342
		}
1343

    
1344
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1345
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1346
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1347
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1348
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1349
			$dns_arrv6 = array();
1350
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1351
				if (is_ipaddrv6($dnsserver)) {
1352
					$dns_arrv6[] = $dnsserver;
1353
				}
1354
			}
1355
			if (!empty($dns_arrv6)) {
1356
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1357
			}
1358
		}
1359

    
1360
		if ($dhcpv6ifconf['domain']) {
1361
			$newzone = array();
1362
			$newzone['domain-name'] = $dhcpv6ifconf['domain'];
1363
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1364
			$ddns_zones[] = $newzone;
1365
		}
1366

    
1367
		if (is_ipaddrv6($ifcfgipv6)) {
1368
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1369
		} else {
1370
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1371
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1372
		}
1373
		$dhcpdv6conf .= " {\n";
1374

    
1375
		$dhcpdv6conf .= <<<EOD
1376
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1377
$dnscfgv6
1378

    
1379
EOD;
1380

    
1381
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1382
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1383
		}
1384
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1385
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1386
		}
1387
		// default-lease-time
1388
		if ($dhcpv6ifconf['defaultleasetime']) {
1389
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1390
		}
1391

    
1392
		// max-lease-time
1393
		if ($dhcpv6ifconf['maxleasetime']) {
1394
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1395
		}
1396

    
1397
		// ntp-servers
1398
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1399
			$ntpservers = array();
1400
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1401
				if (is_ipaddrv6($ntpserver)) {
1402
					$ntpservers[] = $ntpserver;
1403
				}
1404
			}
1405
			if (count($ntpservers) > 0) {
1406
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1407
			}
1408
		}
1409
		// tftp-server-name
1410
		/* Needs ISC DHCPD support
1411
		 if ($dhcpv6ifconf['tftp'] <> "") {
1412
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1413
		 }
1414
		*/
1415

    
1416
		// Handle option, number rowhelper values
1417
		$dhcpdv6conf .= "\n";
1418
		if ($dhcpv6ifconf['numberoptions']['item']) {
1419
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1420
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1421
			}
1422
		}
1423

    
1424
		// ldap-server
1425
		if ($dhcpv6ifconf['ldap'] <> "") {
1426
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1427
		}
1428

    
1429
		// net boot information
1430
		if (isset($dhcpv6ifconf['netboot'])) {
1431
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1432
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1433
			}
1434
		}
1435

    
1436
		$dhcpdv6conf .= "}\n";
1437

    
1438
		/* add static mappings */
1439
		/* Needs to use DUID */
1440
		if (is_array($dhcpv6ifconf['staticmap'])) {
1441
			$i = 0;
1442
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1443
				$dhcpdv6conf .= <<<EOD
1444
host s_{$dhcpv6if}_{$i} {
1445
	host-identifier option dhcp6.client-id {$sm['duid']};
1446

    
1447
EOD;
1448
				if ($sm['ipaddrv6']) {
1449
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1450
				}
1451

    
1452
				if ($sm['hostname']) {
1453
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1454
					$dhhostname = str_replace(".", "_", $dhhostname);
1455
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1456
				}
1457
				if ($sm['filename']) {
1458
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1459
				}
1460

    
1461
				if ($sm['rootpath']) {
1462
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1463
				}
1464

    
1465
				$dhcpdv6conf .= "}\n";
1466
				$i++;
1467
			}
1468
		}
1469

    
1470
		if ($dhcpv6ifconf['domain']) {
1471
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1472
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1473
		}
1474

    
1475
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1476
			if (preg_match("/poes/si", $dhcpv6if)) {
1477
				/* magic here */
1478
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1479
			} else {
1480
				$realif = get_real_interface($dhcpv6if, "inet6");
1481
				if (stristr("$realif", "bridge")) {
1482
					$mac = get_interface_mac($realif);
1483
					$v6address = generate_ipv6_from_mac($mac);
1484
					/* Create link local address for bridges */
1485
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1486
				}
1487
				$realif = escapeshellcmd($realif);
1488
				$dhcpdv6ifs[] = $realif;
1489
			}
1490
		}
1491
	}
1492

    
1493
	if ($nsupdate) {
1494
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1495
	} else {
1496
		$dhcpdv6conf .= "ddns-update-style none;\n";
1497
	}
1498

    
1499
	/* write dhcpdv6.conf */
1500
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1501
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1502
		if (platform_booting()) {
1503
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1504
		}
1505
		unset($dhcpdv6conf);
1506
		return 1;
1507
	}
1508
	unset($dhcpdv6conf);
1509

    
1510
	/* create an empty leases v6 database */
1511
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1512
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1513
	}
1514

    
1515
	/* make sure there isn't a stale dhcpdv6.pid file, which may make dhcpdv6 fail to start.  */
1516
	/* if we get here, dhcpdv6 has been killed and is not started yet                         */
1517
	unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1518

    
1519
	/* fire up dhcpd in a chroot */
1520
	if (count($dhcpdv6ifs) > 0) {
1521
		mwexec("/usr/local/sbin/dhcpd -6 -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpdv6.conf -pf {$g['varrun_path']}/dhcpdv6.pid " .
1522
			join(" ", $dhcpdv6ifs));
1523
		mwexec("/usr/local/sbin/dhcpleases6 -c \"/usr/local/bin/php-cgi -f /usr/local/sbin/prefixes.php|/bin/sh\" -l {$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1524
	}
1525
	if (platform_booting()) {
1526
		print gettext("done.") . "\n";
1527
	}
1528

    
1529
	return 0;
1530
}
1531

    
1532
function services_igmpproxy_configure() {
1533
	global $config, $g;
1534

    
1535
	/* kill any running igmpproxy */
1536
	killbyname("igmpproxy");
1537

    
1538
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1539
		return 1;
1540
	}
1541

    
1542
	$iflist = get_configured_interface_list();
1543

    
1544
	$igmpconf = <<<EOD
1545

    
1546
##------------------------------------------------------
1547
## Enable Quickleave mode (Sends Leave instantly)
1548
##------------------------------------------------------
1549
quickleave
1550

    
1551
EOD;
1552

    
1553
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1554
		unset($iflist[$igmpcf['ifname']]);
1555
		$realif = get_real_interface($igmpcf['ifname']);
1556
		if (empty($igmpcf['threshold'])) {
1557
			$threshld = 1;
1558
		} else {
1559
			$threshld = $igmpcf['threshold'];
1560
		}
1561
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1562

    
1563
		if ($igmpcf['address'] <> "") {
1564
			$item = explode(" ", $igmpcf['address']);
1565
			foreach ($item as $iww) {
1566
				$igmpconf .= "altnet {$iww}\n";
1567
			}
1568
		}
1569
		$igmpconf .= "\n";
1570
	}
1571
	foreach ($iflist as $ifn) {
1572
		$realif = get_real_interface($ifn);
1573
		$igmpconf .= "phyint {$realif} disabled\n";
1574
	}
1575
	$igmpconf .= "\n";
1576

    
1577
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1578
	if (!$igmpfl) {
1579
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1580
		return;
1581
	}
1582
	fwrite($igmpfl, $igmpconf);
1583
	fclose($igmpfl);
1584
	unset($igmpconf);
1585

    
1586
	/* NOTE: -d4 means everything LOG_WARNING and smaller */
1587
	mwexec("/usr/local/sbin/igmpproxy -d4 -c {$g['tmp_path']}/igmpproxy.conf");
1588
	log_error(gettext("Started IGMP proxy service."));
1589

    
1590
	return 0;
1591
}
1592

    
1593
function services_dhcrelay_configure() {
1594
	global $config, $g;
1595

    
1596
	if (isset($config['system']['developerspew'])) {
1597
		$mt = microtime();
1598
		echo "services_dhcrelay_configure() being called $mt\n";
1599
	}
1600

    
1601
	/* kill any running dhcrelay */
1602
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1603

    
1604
	$dhcrelaycfg =& $config['dhcrelay'];
1605

    
1606
	/* DHCPRelay enabled on any interfaces? */
1607
	if (!isset($dhcrelaycfg['enable'])) {
1608
		return 0;
1609
	}
1610

    
1611
	if (platform_booting()) {
1612
		echo gettext("Starting DHCP relay service...");
1613
	} else {
1614
		sleep(1);
1615
	}
1616

    
1617
	$iflist = get_configured_interface_list();
1618

    
1619
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1620
	foreach ($dhcifaces as $dhcrelayif) {
1621
		if (!isset($iflist[$dhcrelayif]) ||
1622
		    link_interface_to_bridge($dhcrelayif)) {
1623
			continue;
1624
		}
1625

    
1626
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1627
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1628
		}
1629
	}
1630

    
1631
	/*
1632
	 * In order for the relay to work, it needs to be active
1633
	 * on the interface in which the destination server sits.
1634
	 */
1635
	$srvips = explode(",", $dhcrelaycfg['server']);
1636
	if (!is_array($srvips)) {
1637
		log_error("No destination IP has been configured!");
1638
		return;
1639
	}
1640

    
1641
	foreach ($srvips as $srcidx => $srvip) {
1642
		unset($destif);
1643
		foreach ($iflist as $ifname) {
1644
			$subnet = get_interface_ip($ifname);
1645
			if (!is_ipaddr($subnet)) {
1646
				continue;
1647
			}
1648
			$subnet .= "/" . get_interface_subnet($ifname);
1649
			if (ip_in_subnet($srvip, $subnet)) {
1650
				$destif = get_real_interface($ifname);
1651
				break;
1652
			}
1653
		}
1654
		if (!isset($destif)) {
1655
			foreach (get_staticroutes() as $rtent) {
1656
				if (ip_in_subnet($srvip, $rtent['network'])) {
1657
					$a_gateways = return_gateways_array(true);
1658
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1659
					break;
1660
				}
1661
			}
1662
		}
1663

    
1664
		if (!isset($destif)) {
1665
			/* Create a array from the existing route table */
1666
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1667
			array_shift($route_str);
1668
			array_shift($route_str);
1669
			array_shift($route_str);
1670
			array_shift($route_str);
1671
			$route_arr = array();
1672
			foreach ($route_str as $routeline) {
1673
				$items = preg_split("/[ ]+/i", $routeline);
1674
				if (is_subnetv4($items[0])) {
1675
					$subnet = $items[0];
1676
				} elseif (is_ipaddrv4($items[0])) {
1677
					$subnet = "{$items[0]}/32";
1678
				} else {
1679
					// Not a subnet or IP address, skip to the next line.
1680
					continue;
1681
				}
1682
				if (ip_in_subnet($srvip, $subnet)) {
1683
					$destif = trim($items[6]);
1684
					break;
1685
				}
1686
			}
1687
		}
1688

    
1689
		if (!isset($destif)) {
1690
			if (is_array($config['gateways']['gateway_item'])) {
1691
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1692
					if (isset($gateway['defaultgw'])) {
1693
						$destif = get_real_interface($gateway['interface']);
1694
						break;
1695
					}
1696
				}
1697
			} else {
1698
				$destif = get_real_interface("wan");
1699
			}
1700
		}
1701

    
1702
		if (!empty($destif)) {
1703
			$dhcrelayifs[] = $destif;
1704
		}
1705
	}
1706
	$dhcrelayifs = array_unique($dhcrelayifs);
1707

    
1708
	/* fire up dhcrelay */
1709
	if (empty($dhcrelayifs)) {
1710
		log_error("No suitable interface found for running dhcrelay!");
1711
		return; /* XXX */
1712
	}
1713

    
1714
	$cmd = "/usr/local/sbin/dhcrelay -i " . implode(" -i ", $dhcrelayifs);
1715

    
1716
	if (isset($dhcrelaycfg['agentoption'])) {
1717
		$cmd .= " -a -m replace";
1718
	}
1719

    
1720
	$cmd .= " " . implode(" ", $srvips);
1721
	mwexec($cmd);
1722
	unset($cmd);
1723

    
1724
	return 0;
1725
}
1726

    
1727
function services_dhcrelay6_configure() {
1728
	global $config, $g;
1729

    
1730
	if (isset($config['system']['developerspew'])) {
1731
		$mt = microtime();
1732
		echo "services_dhcrelay6_configure() being called $mt\n";
1733
	}
1734

    
1735
	/* kill any running dhcrelay */
1736
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1737

    
1738
	$dhcrelaycfg =& $config['dhcrelay6'];
1739

    
1740
	/* DHCPv6 Relay enabled on any interfaces? */
1741
	if (!isset($dhcrelaycfg['enable'])) {
1742
		return 0;
1743
	}
1744

    
1745
	if (platform_booting()) {
1746
		echo gettext("Starting DHCPv6 relay service...");
1747
	} else {
1748
		sleep(1);
1749
	}
1750

    
1751
	$iflist = get_configured_interface_list();
1752

    
1753
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1754
	foreach ($dhcifaces as $dhcrelayif) {
1755
		if (!isset($iflist[$dhcrelayif]) ||
1756
		    link_interface_to_bridge($dhcrelayif)) {
1757
			continue;
1758
		}
1759

    
1760
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1761
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1762
		}
1763
	}
1764
	$dhcrelayifs = array_unique($dhcrelayifs);
1765

    
1766
	/*
1767
	 * In order for the relay to work, it needs to be active
1768
	 * on the interface in which the destination server sits.
1769
	 */
1770
	$srvips = explode(",", $dhcrelaycfg['server']);
1771
	$srvifaces = array();
1772
	foreach ($srvips as $srcidx => $srvip) {
1773
		unset($destif);
1774
		foreach ($iflist as $ifname) {
1775
			$subnet = get_interface_ipv6($ifname);
1776
			if (!is_ipaddrv6($subnet)) {
1777
				continue;
1778
			}
1779
			$subnet .= "/" . get_interface_subnetv6($ifname);
1780
			if (ip_in_subnet($srvip, $subnet)) {
1781
				$destif = get_real_interface($ifname);
1782
				break;
1783
			}
1784
		}
1785
		if (!isset($destif)) {
1786
			if (is_array($config['staticroutes']['route'])) {
1787
				foreach ($config['staticroutes']['route'] as $rtent) {
1788
					if (ip_in_subnet($srvip, $rtent['network'])) {
1789
						$a_gateways = return_gateways_array(true);
1790
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1791
						break;
1792
					}
1793
				}
1794
			}
1795
		}
1796

    
1797
		if (!isset($destif)) {
1798
			/* Create a array from the existing route table */
1799
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1800
			array_shift($route_str);
1801
			array_shift($route_str);
1802
			array_shift($route_str);
1803
			array_shift($route_str);
1804
			$route_arr = array();
1805
			foreach ($route_str as $routeline) {
1806
				$items = preg_split("/[ ]+/i", $routeline);
1807
				if (ip_in_subnet($srvip, $items[0])) {
1808
					$destif = trim($items[6]);
1809
					break;
1810
				}
1811
			}
1812
		}
1813

    
1814
		if (!isset($destif)) {
1815
			if (is_array($config['gateways']['gateway_item'])) {
1816
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1817
					if (isset($gateway['defaultgw'])) {
1818
						$destif = get_real_interface($gateway['interface']);
1819
						break;
1820
					}
1821
				}
1822
			} else {
1823
				$destif = get_real_interface("wan");
1824
			}
1825
		}
1826

    
1827
		if (!empty($destif)) {
1828
			$srvifaces[] = "{$srvip}%{$destif}";
1829
		}
1830
	}
1831

    
1832
	/* fire up dhcrelay */
1833
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1834
		log_error("No suitable interface found for running dhcrelay -6!");
1835
		return; /* XXX */
1836
	}
1837

    
1838
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1839
	foreach ($dhcrelayifs as $dhcrelayif) {
1840
		$cmd .= " -l {$dhcrelayif}";
1841
	}
1842
	foreach ($srvifaces as $srviface) {
1843
		$cmd .= " -u \"{$srviface}\"";
1844
	}
1845
	mwexec($cmd);
1846
	unset($cmd);
1847

    
1848
	return 0;
1849
}
1850

    
1851
function services_dyndns_configure_client($conf) {
1852

    
1853
	if (!isset($conf['enable'])) {
1854
		return;
1855
	}
1856

    
1857
	/* load up the dyndns.class */
1858
	require_once("dyndns.class");
1859

    
1860
	$dns = new updatedns($dnsService = $conf['type'],
1861
		$dnsHost = $conf['host'],
1862
		$dnsUser = $conf['username'],
1863
		$dnsPass = $conf['password'],
1864
		$dnsWildcard = $conf['wildcard'],
1865
		$dnsMX = $conf['mx'],
1866
		$dnsIf = "{$conf['interface']}",
1867
		$dnsBackMX = NULL,
1868
		$dnsServer = NULL,
1869
		$dnsPort = NULL,
1870
		$dnsUpdateURL = "{$conf['updateurl']}",
1871
		$forceUpdate = $conf['force'],
1872
		$dnsZoneID = $conf['zoneid'],
1873
		$dnsTTL = $conf['ttl'],
1874
		$dnsResultMatch = "{$conf['resultmatch']}",
1875
		$dnsRequestIf = "{$conf['requestif']}",
1876
		$dnsID = "{$conf['id']}",
1877
		$dnsVerboseLog = $conf['verboselog'],
1878
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1879
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1880
}
1881

    
1882
function services_dyndns_configure($int = "") {
1883
	global $config, $g;
1884
	if (isset($config['system']['developerspew'])) {
1885
		$mt = microtime();
1886
		echo "services_dyndns_configure() being called $mt\n";
1887
	}
1888

    
1889
	$dyndnscfg = $config['dyndnses']['dyndns'];
1890
	$gwgroups = return_gateway_groups_array();
1891
	if (is_array($dyndnscfg)) {
1892
		if (platform_booting()) {
1893
			echo gettext("Starting DynDNS clients...");
1894
		}
1895

    
1896
		foreach ($dyndnscfg as $dyndns) {
1897
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1898
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1899
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1900
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1901
				services_dyndns_configure_client($dyndns);
1902
				sleep(1);
1903
			}
1904
		}
1905

    
1906
		if (platform_booting()) {
1907
			echo gettext("done.") . "\n";
1908
		}
1909
	}
1910

    
1911
	return 0;
1912
}
1913

    
1914
function dyndnsCheckIP($int) {
1915
	global $config;
1916
	$ip_address = get_interface_ip($int);
1917
	if (is_private_ip($ip_address)) {
1918
		$gateways_status = return_gateways_status(true);
1919
		// If the gateway for this interface is down, then the external check cannot work.
1920
		// Avoid the long wait for the external check to timeout.
1921
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
1922
			return "down";
1923
		}
1924
		$hosttocheck = "http://checkip.dyndns.org";
1925
		$ip_ch = curl_init($hosttocheck);
1926
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1927
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1928
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
1929
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1930
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1931
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1932
		$ip_result_page = curl_exec($ip_ch);
1933
		curl_close($ip_ch);
1934
		$ip_result_decoded = urldecode($ip_result_page);
1935
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1936
		$ip_address = trim($matches[1]);
1937
	}
1938
	return $ip_address;
1939
}
1940

    
1941
function services_dnsmasq_configure() {
1942
	global $config, $g;
1943
	$return = 0;
1944

    
1945
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1946
	$standard_args = array(
1947
		"dns-forward-max" => "--dns-forward-max=5000",
1948
		"cache-size" => "--cache-size=10000",
1949
		"local-ttl" => "--local-ttl=1"
1950
	);
1951

    
1952

    
1953
	if (isset($config['system']['developerspew'])) {
1954
		$mt = microtime();
1955
		echo "services_dnsmasq_configure() being called $mt\n";
1956
	}
1957

    
1958
	/* kill any running dnsmasq */
1959
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
1960
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1961
	}
1962

    
1963
	if (isset($config['dnsmasq']['enable'])) {
1964

    
1965
		if (platform_booting()) {
1966
			echo gettext("Starting DNS forwarder...");
1967
		} else {
1968
			sleep(1);
1969
		}
1970

    
1971
		/* generate hosts file */
1972
		if (system_hosts_generate() != 0) {
1973
			$return = 1;
1974
		}
1975

    
1976
		$args = "";
1977

    
1978
		if (isset($config['dnsmasq']['regdhcp'])) {
1979
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1980
		}
1981

    
1982
		/* Setup listen port, if non-default */
1983
		if (is_port($config['dnsmasq']['port'])) {
1984
			$args .= " --port={$config['dnsmasq']['port']} ";
1985
		}
1986

    
1987
		$listen_addresses = "";
1988
		if (isset($config['dnsmasq']['interface'])) {
1989
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1990
			foreach ($interfaces as $interface) {
1991
				if (is_ipaddrv4($interface)) {
1992
					$listen_addresses .= " --listen-address={$interface} ";
1993
				} else if (is_ipaddrv6($interface)) {
1994
					/*
1995
					 * XXX: Since dnsmasq does not support link-local address
1996
					 * with scope specified. These checks are being done.
1997
					 */
1998
					if (is_linklocal($interface) && strstr($interface, "%")) {
1999
						$tmpaddrll6 = explode("%", $interface);
2000
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2001
					} else {
2002
						$listen_addresses .= " --listen-address={$interface} ";
2003
					}
2004
				} else if (strstr($interface, "_vip")) {
2005
					$laddr = get_configured_carp_interface_list($interface);
2006
					if (is_ipaddr($laddr)) {
2007
						$listen_addresses .= " --listen-address={$laddr} ";
2008
					}
2009
				} else {
2010
					$if = get_real_interface($interface);
2011
					if (does_interface_exist($if)) {
2012
						$laddr = get_interface_ip($interface);
2013
						if (is_ipaddrv4($laddr)) {
2014
							$listen_addresses .= " --listen-address={$laddr} ";
2015
						}
2016
						$laddr6 = get_interface_ipv6($interface);
2017
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
2018
							/*
2019
							 * XXX: Since dnsmasq does not support link-local address
2020
							 * with scope specified. These checks are being done.
2021
							 */
2022
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
2023
								$tmpaddrll6 = explode("%", $laddr6);
2024
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2025
							} else {
2026
								$listen_addresses .= " --listen-address={$laddr6} ";
2027
							}
2028
						}
2029
					}
2030
				}
2031
			}
2032
			if (!empty($listen_addresses)) {
2033
				$args .= " {$listen_addresses} ";
2034
				if (isset($config['dnsmasq']['strictbind'])) {
2035
					$args .= " --bind-interfaces ";
2036
				}
2037
			}
2038
		}
2039

    
2040
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
2041
		/* Only make entries for reverse domains that do not have a matching domain override. */
2042
		if (isset($config['dnsmasq']['no_private_reverse'])) {
2043
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
2044
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
2045
			/* Just the pfSense WAN might get a CGN address from an ISP. */
2046

    
2047
			// Build an array of domain overrides to help in checking for matches.
2048
			$override_a = array();
2049
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2050
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2051
					$override_a[$override['domain']] = "y";
2052
				}
2053
			}
2054

    
2055
			// Build an array of the private reverse lookup domain names
2056
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
2057
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
2058
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
2059
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
2060
			}
2061

    
2062
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
2063
			foreach ($reverse_domain_a as $reverse_domain) {
2064
				if (!isset($override_a[$reverse_domain])) {
2065
					$args .= " --server=/$reverse_domain/ ";
2066
				}
2067
			}
2068
			unset($override_a);
2069
			unset($reverse_domain_a);
2070
		}
2071

    
2072
		/* Setup forwarded domains */
2073
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2074
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2075
				if ($override['ip'] == "!") {
2076
					$override[ip] = "";
2077
				}
2078
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2079
			}
2080
		}
2081

    
2082
		/* Allow DNS Rebind for forwarded domains */
2083
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2084
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2085
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2086
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2087
				}
2088
			}
2089
		}
2090

    
2091
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2092
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2093
		}
2094

    
2095
		if (isset($config['dnsmasq']['strict_order'])) {
2096
			$args .= " --strict-order ";
2097
		}
2098

    
2099
		if (isset($config['dnsmasq']['domain_needed'])) {
2100
			$args .= " --domain-needed ";
2101
		}
2102

    
2103
		if ($config['dnsmasq']['custom_options']) {
2104
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2105
				$args .= " " . escapeshellarg("--{$c}");
2106
				$p = explode('=', $c);
2107
				if (array_key_exists($p[0], $standard_args)) {
2108
					unset($standard_args[$p[0]]);
2109
				}
2110
			}
2111
		}
2112
		$args .= ' ' . implode(' ', array_values($standard_args));
2113

    
2114
		/* run dnsmasq */
2115
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2116
		//log_error("dnsmasq command: {$cmd}");
2117
		mwexec_bg($cmd);
2118
		unset($args);
2119

    
2120
		system_dhcpleases_configure();
2121

    
2122
		if (platform_booting()) {
2123
			echo gettext("done.") . "\n";
2124
		}
2125
	}
2126

    
2127
	if (!platform_booting()) {
2128
		if (services_dhcpd_configure() != 0) {
2129
			$return = 1;
2130
		}
2131
	}
2132

    
2133
	return $return;
2134
}
2135

    
2136
function services_unbound_configure() {
2137
	global $config, $g;
2138
	$return = 0;
2139

    
2140
	if (isset($config['system']['developerspew'])) {
2141
		$mt = microtime();
2142
		echo "services_unbound_configure() being called $mt\n";
2143
	}
2144

    
2145
	// kill any running Unbound instance
2146
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2147
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2148
	}
2149

    
2150
	if (isset($config['unbound']['enable'])) {
2151
		if (platform_booting()) {
2152
			echo gettext("Starting DNS Resolver...");
2153
		} else {
2154
			sleep(1);
2155
		}
2156

    
2157
		/* generate hosts file */
2158
		if (system_hosts_generate() != 0) {
2159
			$return = 1;
2160
		}
2161

    
2162
		require_once('/etc/inc/unbound.inc');
2163
		sync_unbound_service();
2164
		if (platform_booting()) {
2165
			echo gettext("done.") . "\n";
2166
		}
2167

    
2168
		system_dhcpleases_configure();
2169
	}
2170

    
2171
	if (!platform_booting()) {
2172
		if (services_dhcpd_configure() != 0) {
2173
			$return = 1;
2174
		}
2175
	}
2176

    
2177
	return $return;
2178
}
2179

    
2180
function services_snmpd_configure() {
2181
	global $config, $g;
2182
	if (isset($config['system']['developerspew'])) {
2183
		$mt = microtime();
2184
		echo "services_snmpd_configure() being called $mt\n";
2185
	}
2186

    
2187
	/* kill any running snmpd */
2188
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2189
	sleep(2);
2190
	if (is_process_running("bsnmpd")) {
2191
		mwexec("/usr/bin/killall bsnmpd", true);
2192
	}
2193

    
2194
	if (isset($config['snmpd']['enable'])) {
2195

    
2196
		if (platform_booting()) {
2197
			echo gettext("Starting SNMP daemon... ");
2198
		}
2199

    
2200
		/* generate snmpd.conf */
2201
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2202
		if (!$fd) {
2203
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2204
			return 1;
2205
		}
2206

    
2207

    
2208
		$snmpdconf = <<<EOD
2209
location := "{$config['snmpd']['syslocation']}"
2210
contact := "{$config['snmpd']['syscontact']}"
2211
read := "{$config['snmpd']['rocommunity']}"
2212

    
2213
EOD;
2214

    
2215
/* No docs on what write strings do there for disable for now.
2216
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2217
			$snmpdconf .= <<<EOD
2218
# write string
2219
write := "{$config['snmpd']['rwcommunity']}"
2220

    
2221
EOD;
2222
		}
2223
*/
2224

    
2225

    
2226
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2227
			$snmpdconf .= <<<EOD
2228
# SNMP Trap support.
2229
traphost := {$config['snmpd']['trapserver']}
2230
trapport := {$config['snmpd']['trapserverport']}
2231
trap := "{$config['snmpd']['trapstring']}"
2232

    
2233

    
2234
EOD;
2235
		}
2236

    
2237
		$platform = trim(file_get_contents('/etc/platform'));
2238
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2239
			$platform = $g['product_name'];
2240
		}
2241
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2242
			" {$g['product_version']} {$platform} " . php_uname("s") .
2243
			" " . php_uname("r") . " " . php_uname("m");
2244

    
2245
		$snmpdconf .= <<<EOD
2246
system := 1     # pfSense
2247
%snmpd
2248
sysDescr			= "{$sysDescr}"
2249
begemotSnmpdDebugDumpPdus       = 2
2250
begemotSnmpdDebugSyslogPri      = 7
2251
begemotSnmpdCommunityString.0.1 = $(read)
2252

    
2253
EOD;
2254

    
2255
/* No docs on what write strings do there for disable for now.
2256
		if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2257
			$snmpdconf .= <<<EOD
2258
begemotSnmpdCommunityString.0.2 = $(write)
2259

    
2260
EOD;
2261
		}
2262
*/
2263

    
2264

    
2265
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2266
			$snmpdconf .= <<<EOD
2267
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2268
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2269
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2270

    
2271
EOD;
2272
		}
2273

    
2274

    
2275
		$snmpdconf .= <<<EOD
2276
begemotSnmpdCommunityDisable    = 1
2277

    
2278
EOD;
2279

    
2280
		if (isset($config['snmpd']['bindlan'])) {
2281
			$config['snmpd']['bindip'] = 'lan';
2282
			unset($config['snmpd']['bindlan']);
2283
		}
2284
		$bind_to_ip = "0.0.0.0";
2285
		if (isset($config['snmpd']['bindip'])) {
2286
			if (is_ipaddr($config['snmpd']['bindip'])) {
2287
				$bind_to_ip = $config['snmpd']['bindip'];
2288
			} else {
2289
				$if = get_real_interface($config['snmpd']['bindip']);
2290
				if (does_interface_exist($if)) {
2291
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2292
				}
2293
			}
2294
		}
2295

    
2296
		if (is_port($config['snmpd']['pollport'])) {
2297
			$snmpdconf .= <<<EOD
2298
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2299

    
2300
EOD;
2301

    
2302
		}
2303

    
2304
		$snmpdconf .= <<<EOD
2305
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2306
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2307

    
2308
# These are bsnmp macros not php vars.
2309
sysContact      = $(contact)
2310
sysLocation     = $(location)
2311
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2312

    
2313
snmpEnableAuthenTraps = 2
2314

    
2315
EOD;
2316

    
2317
		if (is_array($config['snmpd']['modules'])) {
2318
			if (isset($config['snmpd']['modules']['mibii'])) {
2319
			$snmpdconf .= <<<EOD
2320
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2321

    
2322
EOD;
2323
			}
2324

    
2325
			if (isset($config['snmpd']['modules']['netgraph'])) {
2326
				$snmpdconf .= <<<EOD
2327
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2328
%netgraph
2329
begemotNgControlNodeName = "snmpd"
2330

    
2331
EOD;
2332
			}
2333

    
2334
			if (isset($config['snmpd']['modules']['pf'])) {
2335
				$snmpdconf .= <<<EOD
2336
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2337

    
2338
EOD;
2339
			}
2340

    
2341
			if (isset($config['snmpd']['modules']['hostres'])) {
2342
				/* XXX: hostres module crashes APU - ticket #4403 */
2343
				$specplatform = system_identify_specific_platform();
2344
				if ($specplatform['name'] == 'APU') {
2345
					log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
2346
				} else {
2347
					$snmpdconf .= <<<EOD
2348
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2349

    
2350
EOD;
2351
				}
2352
				unset($specplatform);
2353
			}
2354

    
2355
			if (isset($config['snmpd']['modules']['bridge'])) {
2356
				$snmpdconf .= <<<EOD
2357
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2358
# config must end with blank line
2359

    
2360
EOD;
2361
			}
2362
			if (isset($config['snmpd']['modules']['ucd'])) {
2363
				$snmpdconf .= <<<EOD
2364
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2365

    
2366
EOD;
2367
			}
2368
			if (isset($config['snmpd']['modules']['regex'])) {
2369
				$snmpdconf .= <<<EOD
2370
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2371

    
2372
EOD;
2373
			}
2374
		}
2375

    
2376
		fwrite($fd, $snmpdconf);
2377
		fclose($fd);
2378
		unset($snmpdconf);
2379

    
2380
		if (isset($config['snmpd']['bindlan'])) {
2381
			$bindlan = "";
2382
		}
2383

    
2384
		/* run bsnmpd */
2385
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2386
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2387

    
2388
		if (platform_booting()) {
2389
			echo gettext("done.") . "\n";
2390
		}
2391
	}
2392

    
2393
	return 0;
2394
}
2395

    
2396
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2397
	global $config, $g;
2398
	if (isset($config['system']['developerspew'])) {
2399
		$mt = microtime();
2400
		echo "services_dnsupdate_process() being called $mt\n";
2401
	}
2402

    
2403
	/* Dynamic DNS updating active? */
2404
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2405
		$notify_text = "";
2406
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2407
			if (!isset($dnsupdate['enable'])) {
2408
				continue;
2409
			}
2410
			if (!empty($int) && $int != $dnsupdate['interface']) {
2411
				continue;
2412
			}
2413
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2414
				continue;
2415
			}
2416

    
2417
			/* determine interface name */
2418
			$if = get_real_interface($dnsupdate['interface']);
2419

    
2420
			if (isset($dnsupdate['usepublicip'])) {
2421
				$wanip = dyndnsCheckIP($dnsupdate['interface']);
2422
			} else {
2423
				$wanip = get_interface_ip($dnsupdate['interface']);
2424
			}
2425

    
2426
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2427
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2428
			$currentTime = time();
2429

    
2430
			if ($wanip || $wanipv6) {
2431
				$keyname = $dnsupdate['keyname'];
2432
				/* trailing dot */
2433
				if (substr($keyname, -1) != ".") {
2434
					$keyname .= ".";
2435
				}
2436

    
2437
				$hostname = $dnsupdate['host'];
2438
				/* trailing dot */
2439
				if (substr($hostname, -1) != ".") {
2440
					$hostname .= ".";
2441
				}
2442

    
2443
				/* write private key file
2444
				   this is dumb - public and private keys are the same for HMAC-MD5,
2445
				   but nsupdate insists on having both */
2446
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2447
				$privkey = <<<EOD
2448
Private-key-format: v1.2
2449
Algorithm: 157 (HMAC)
2450
Key: {$dnsupdate['keydata']}
2451

    
2452
EOD;
2453
				fwrite($fd, $privkey);
2454
				fclose($fd);
2455

    
2456
				/* write public key file */
2457
				if ($dnsupdate['keytype'] == "zone") {
2458
					$flags = 257;
2459
					$proto = 3;
2460
				} else if ($dnsupdate['keytype'] == "host") {
2461
					$flags = 513;
2462
					$proto = 3;
2463
				} else if ($dnsupdate['keytype'] == "user") {
2464
					$flags = 0;
2465
					$proto = 2;
2466
				}
2467

    
2468
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.key", "w");
2469
				fwrite($fd, "{$keyname} IN KEY {$flags} {$proto} 157 {$dnsupdate['keydata']}\n");
2470
				fclose($fd);
2471

    
2472
				/* generate update instructions */
2473
				$upinst = "";
2474
				if (!empty($dnsupdate['server'])) {
2475
					$upinst .= "server {$dnsupdate['server']}\n";
2476
				}
2477

    
2478
				if (file_exists($cacheFile)) {
2479
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2480
				}
2481
				if (file_exists("{$cacheFile}.ipv6")) {
2482
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2483
				}
2484

    
2485
				// 25 Days
2486
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2487
				$need_update = false;
2488

    
2489
				conf_mount_rw();
2490
				/* Update IPv4 if we have it. */
2491
				if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
2492
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2493
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2494
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2495
						$notify_text .= sprintf(gettext("DynDNS updated IP Address (A) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n";
2496
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2497
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2498
						$need_update = true;
2499
					} else {
2500
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2501
					}
2502
				} else {
2503
					@unlink($cacheFile);
2504
				}
2505

    
2506
				/* Update IPv6 if we have it. */
2507
				if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
2508
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2509
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2510
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2511
						$notify_text .= sprintf(gettext("DynDNS updated IPv6 Address (AAAA) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n";
2512
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2513
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2514
						$need_update = true;
2515
					} else {
2516
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2517
					}
2518
				} else {
2519
					@unlink("{$cacheFile}.ipv6");
2520
				}
2521
				conf_mount_ro();
2522

    
2523
				$upinst .= "\n";	/* mind that trailing newline! */
2524

    
2525
				if ($need_update) {
2526
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2527
					unset($upinst);
2528
					/* invoke nsupdate */
2529
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2530
					if (isset($dnsupdate['usetcp'])) {
2531
						$cmd .= " -v";
2532
					}
2533
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2534
					mwexec_bg($cmd);
2535
					unset($cmd);
2536
				}
2537
			}
2538
		}
2539
		if (!empty($notify_text)) {
2540
			notify_all_remote($notify_text);
2541
		}
2542
	}
2543

    
2544
	return 0;
2545
}
2546

    
2547
/* configure cron service */
2548
function configure_cron() {
2549
	global $g, $config;
2550

    
2551
	conf_mount_rw();
2552
	/* preserve existing crontab entries */
2553
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2554

    
2555
	for ($i = 0; $i < count($crontab_contents); $i++) {
2556
		$cron_item =& $crontab_contents[$i];
2557
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2558
			array_splice($crontab_contents, $i - 1);
2559
			break;
2560
		}
2561
	}
2562
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2563

    
2564

    
2565
	if (is_array($config['cron']['item'])) {
2566
		$crontab_contents .= "#\n";
2567
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2568
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2569
		$crontab_contents .= "#\n";
2570

    
2571
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2572
			$http_proxy = $config['system']['proxyurl'];
2573
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2574
				$http_proxy .= ':' . $config['system']['proxyport'];
2575
			}
2576
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2577
		}
2578

    
2579
		foreach ($config['cron']['item'] as $item) {
2580
			$crontab_contents .= "\n{$item['minute']}\t";
2581
			$crontab_contents .= "{$item['hour']}\t";
2582
			$crontab_contents .= "{$item['mday']}\t";
2583
			$crontab_contents .= "{$item['month']}\t";
2584
			$crontab_contents .= "{$item['wday']}\t";
2585
			$crontab_contents .= "{$item['who']}\t";
2586
			$crontab_contents .= "{$item['command']}";
2587
		}
2588

    
2589
		$crontab_contents .= "\n#\n";
2590
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2591
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2592
		$crontab_contents .= "#\n\n";
2593
	}
2594

    
2595
	/* please maintain the newline at the end of file */
2596
	file_put_contents("/etc/crontab", $crontab_contents);
2597
	unset($crontab_contents);
2598

    
2599
	/* make sure that cron is running and start it if it got killed somehow */
2600
	if (!is_process_running("cron")) {
2601
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2602
	} else {
2603
	/* do a HUP kill to force sync changes */
2604
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2605
	}
2606

    
2607
	conf_mount_ro();
2608
}
2609

    
2610
function upnp_action ($action) {
2611
	global $g, $config;
2612
	switch ($action) {
2613
		case "start":
2614
			if (file_exists('/var/etc/miniupnpd.conf')) {
2615
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2616
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2617
			}
2618
			break;
2619
		case "stop":
2620
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2621
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2622
				mwexec('killall miniupnpd 2>/dev/null', true);
2623
			}
2624
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2625
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2626
			break;
2627
		case "restart":
2628
			upnp_action('stop');
2629
			upnp_action('start');
2630
			break;
2631
	}
2632
}
2633

    
2634
function upnp_start() {
2635
	global $config;
2636

    
2637
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2638
		return;
2639
	}
2640

    
2641
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2642
		echo gettext("Starting UPnP service... ");
2643
		require_once('/usr/local/pkg/miniupnpd.inc');
2644
		sync_package_miniupnpd();
2645
		echo "done.\n";
2646
	}
2647
}
2648

    
2649
function install_cron_job($command, $active = false, $minute = "0", $hour = "*", $monthday = "*", $month = "*", $weekday = "*", $who = "root") {
2650
	global $config, $g;
2651

    
2652
	$is_installed = false;
2653
	$cron_changed = true;
2654

    
2655
	if (!is_array($config['cron'])) {
2656
		$config['cron'] = array();
2657
	}
2658
	if (!is_array($config['cron']['item'])) {
2659
		$config['cron']['item'] = array();
2660
	}
2661

    
2662
	$x = 0;
2663
	foreach ($config['cron']['item'] as $item) {
2664
		if (strstr($item['command'], $command)) {
2665
			$is_installed = true;
2666
			break;
2667
		}
2668
		$x++;
2669
	}
2670

    
2671
	if ($active) {
2672
		$cron_item = array();
2673
		$cron_item['minute'] = $minute;
2674
		$cron_item['hour'] = $hour;
2675
		$cron_item['mday'] = $monthday;
2676
		$cron_item['month'] = $month;
2677
		$cron_item['wday'] = $weekday;
2678
		$cron_item['who'] = $who;
2679
		$cron_item['command'] = $command;
2680
		if (!$is_installed) {
2681
			$config['cron']['item'][] = $cron_item;
2682
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2683
		} else {
2684
			if ($config['cron']['item'][$x] == $cron_item) {
2685
				$cron_changed = false;
2686
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2687
			} else {
2688
				$config['cron']['item'][$x] = $cron_item;
2689
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2690
			}
2691
		}
2692
	} else {
2693
		if ($is_installed == true) {
2694
			unset($config['cron']['item'][$x]);
2695
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2696
		}
2697
	}
2698

    
2699
	if ($cron_changed) {
2700
		configure_cron();
2701
	}
2702
}
2703

    
2704
?>
(50-50/67)