Project

General

Profile

Download (82.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services.inc
4

    
5
	part of pfSense (https://www.pfsense.org)
6
	Copyright (c) 2004-2016 Electric Sheep Fencing, LLC.
7
	All rights reserved.
8

    
9
	originally part of m0n0wall (http://m0n0.ch/wall)
10
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
	All rights reserved.
12

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

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

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

    
24
	3. All advertising materials mentioning features or use of this software
25
	   must display the following acknowledgment:
26
	   "This product includes software developed by the pfSense Project
27
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
28

    
29
	4. The names "pfSense" and "pfSense Project" must not be used to
30
	   endorse or promote products derived from this software without
31
	   prior written permission. For written permission, please contact
32
	   coreteam@pfsense.org.
33

    
34
	5. Products derived from this software may not be called "pfSense"
35
	   nor may "pfSense" appear in their names without prior written
36
	   permission of the Electric Sheep Fencing, LLC.
37

    
38
	6. Redistributions of any form whatsoever must retain the following
39
	   acknowledgment:
40

    
41
	"This product includes software developed by the pfSense Project
42
	for use in the pfSense software distribution (http://www.pfsense.org/).
43

    
44
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
45
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
48
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55
	OF THE POSSIBILITY OF SUCH DAMAGE.
56
*/
57

    
58
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 spdns spdns-v6 zoneedit');
59
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,SPDNS,SPDNS (v6),ZoneEdit');
60

    
61
/* implement ipv6 route advertising daemon */
62
function services_radvd_configure($blacklist = array()) {
63
	global $config, $g;
64

    
65
	if (isset($config['system']['developerspew'])) {
66
		$mt = microtime();
67
		echo "services_radvd_configure() being called $mt\n";
68
	}
69

    
70
	if (!is_array($config['dhcpdv6'])) {
71
		$config['dhcpdv6'] = array();
72
	}
73

    
74
	$Iflist = get_configured_interface_list();
75
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
76

    
77
	$radvdconf = "# Automatically Generated, do not edit\n";
78

    
79
	/* Process all links which need the router advertise daemon */
80
	$radvdifs = array();
81

    
82
	/* handle manually configured DHCP6 server settings first */
83
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
84
		if (!is_array($config['interfaces'][$dhcpv6if])) {
85
			continue;
86
		}
87
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
88
			continue;
89
		}
90

    
91
		/* Do not put in the config an interface which is down */
92
		if (isset($blacklist[$dhcpv6if])) {
93
			continue;
94
		}
95
		if (!isset($dhcpv6ifconf['ramode'])) {
96
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
97
		}
98

    
99
		/* are router advertisements enabled? */
100
		if ($dhcpv6ifconf['ramode'] == "disabled") {
101
			continue;
102
		}
103

    
104
		if (!isset($dhcpv6ifconf['rapriority'])) {
105
			$dhcpv6ifconf['rapriority'] = "medium";
106
		}
107

    
108
		$realif = get_real_interface($dhcpv6if, "inet6");
109

    
110
		if (isset($radvdifs[$realif])) {
111
			continue;
112
		}
113

    
114
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
115
		if (!is_ipaddrv6($ifcfgipv6)) {
116
			continue;
117
		}
118

    
119
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
120
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
121
		$radvdifs[$realif] = $realif;
122

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

    
186
		if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
187
		  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
188
		} else {
189
		  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
190
		}
191

    
192
		if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
193
		  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
194
		} else {
195
		  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
196
		}
197

    
198
		$radvdconf .= "\t};\n";
199

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

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

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

    
294
		$realif = get_real_interface($if, "inet6");
295

    
296
		/* prevent duplicate entries, manual overrides */
297
		if (isset($radvdifs[$realif])) {
298
			continue;
299
		}
300

    
301
		$ifcfgipv6 = get_interface_ipv6($if);
302
		if (!is_ipaddrv6($ifcfgipv6)) {
303
			$subnetv6 = "::";
304
			$ifcfgsnv6 = "64";
305
		} else {
306
			$ifcfgsnv6 = get_interface_subnetv6($if);
307
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
308
		}
309
		$radvdifs[$realif] = $realif;
310

    
311
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
312

    
313
		if ($g['debug']) {
314
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
315
		}
316

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

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

    
358
	/* write radvd.conf */
359
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
360
		log_error(gettext("Error: cannot open radvd.conf in services_radvd_configure()."));
361
		if (platform_booting()) {
362
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
363
		}
364
	}
365
	unset($radvdconf);
366

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

    
385
function services_dhcpd_configure($family = "all", $blacklist = array()) {
386
	global $config, $g;
387

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

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

    
411
	if ($family == "all" || $family == "inet") {
412
		services_dhcpdv4_configure();
413
	}
414
	if ($family == "all" || $family == "inet6") {
415
		services_dhcpdv6_configure($blacklist);
416
		services_radvd_configure($blacklist);
417
	}
418
}
419

    
420
function services_dhcpdv4_configure() {
421
	global $config, $g;
422
	$need_ddns_updates = false;
423
	$ddns_zones = array();
424

    
425
	if ($g['services_dhcp_server_enable'] == false) {
426
		return;
427
	}
428

    
429
	if (isset($config['system']['developerspew'])) {
430
		$mt = microtime();
431
		echo "services_dhcpdv4_configure($if) being called $mt\n";
432
	}
433

    
434
	/* kill any running dhcpd */
435
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
436
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
437
	}
438

    
439
	/* DHCP enabled on any interfaces? */
440
	if (!is_dhcp_server_enabled()) {
441
		return 0;
442
	}
443

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

    
457
	if (platform_booting()) {
458
		/* restore the leases, if we have them */
459
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
460
			$dhcprestore = "";
461
			$dhcpreturn = "";
462
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
463
			$dhcprestore = implode(" ", $dhcprestore);
464
			if ($dhcpreturn <> 0) {
465
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
466
			}
467
		}
468
		/* 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. */
469
		if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
470
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
471
		}
472
	}
473

    
474
	$syscfg = $config['system'];
475
	if (!is_array($config['dhcpd'])) {
476
		$config['dhcpd'] = array();
477
	}
478
	$dhcpdcfg = $config['dhcpd'];
479
	$Iflist = get_configured_interface_list();
480

    
481
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
482
	$dns_arrv4 = array();
483
	if (is_array($syscfg['dnsserver'])) {
484
		foreach ($syscfg['dnsserver'] as $dnsserver) {
485
			if (is_ipaddrv4($dnsserver)) {
486
				$dns_arrv4[] = $dnsserver;
487
			}
488
		}
489
	}
490

    
491
	if (platform_booting()) {
492
		echo gettext("Starting DHCP service...");
493
	} else {
494
		sleep(1);
495
	}
496

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

    
511
	$dhcpdconf = <<<EOD
512

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

    
526
EOD;
527

    
528
	if (!isset($dhcpifconf['disableauthoritative'])) {
529
		$dhcpdconf .= "authoritative;\n";
530
	}
531

    
532
	if (isset($dhcpifconf['alwaysbroadcast'])) {
533
		$dhcpdconf .= "always-broadcast on\n";
534
	}
535

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

    
548
	/*    loop through and determine if we need to setup
549
	 *    failover peer "bleh" entries
550
	 */
551
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
552

    
553
		if (!isset($config['interfaces'][$dhcpif]['enable'])) {
554
			continue;
555
		}
556

    
557
		interfaces_staticarp_configure($dhcpif);
558

    
559
		if (!isset($dhcpifconf['enable'])) {
560
			continue;
561
		}
562

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

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

    
617
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
618

    
619
		$newzone = array();
620
		$ifcfg = $config['interfaces'][$dhcpif];
621

    
622
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) {
623
			continue;
624
		}
625
		$ifcfgip = get_interface_ip($dhcpif);
626
		$ifcfgsn = get_interface_subnet($dhcpif);
627
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
628
		$subnetmask = gen_subnet_mask($ifcfgsn);
629

    
630
		if (!is_ipaddr($subnet)) {
631
			continue;
632
		}
633

    
634
		if ($is_olsr_enabled == true) {
635
			if ($dhcpifconf['netmask']) {
636
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
637
			}
638
		}
639

    
640
		$all_pools = array();
641
		$all_pools[] = $dhcpifconf;
642
		if (is_array($dhcpifconf['pool'])) {
643
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
644
		}
645

    
646
		$dnscfg = "";
647

    
648
		if ($dhcpifconf['domain']) {
649
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
650
		}
651

    
652
		if ($dhcpifconf['domainsearchlist'] <> "") {
653
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
654
		}
655

    
656
		if (isset($dhcpifconf['ddnsupdate'])) {
657
			$need_ddns_updates = true;
658
			$newzone = array();
659
			if ($dhcpifconf['ddnsdomain'] <> "") {
660
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
661
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
662
			} else {
663
				$newzone['domain-name'] = $config['system']['domain'];
664
			}
665

    
666
			$revsubnet = array_reverse(explode('.',$subnet));
667

    
668
			/* Take care of full classes first */
669
			switch ($ifcfgsn) {
670
				case 8:
671
					$start_octet = 3;
672
					break;
673
				case 16:
674
					$start_octet = 2;
675
					break;
676
				case 24:
677
					$start_octet = 1;
678
					break;
679
				default:
680
					$start_octet = 0;
681
					/* Add subnet bitmask to first octet */
682
					$revsubnet[0] .= '-' . $ifcfgsn;
683
					break;
684

    
685
			}
686

    
687
			$ptr_domain = '';
688
			for ($octet = 0; $octet <= 3; $octet++) {
689
				if ($octet < $start_octet) {
690
					continue;
691
				}
692
				$ptr_domain .= (empty($ptr_domain) ? '' : '.');
693
				$ptr_domain .= $revsubnet[$octet];
694
			}
695
			$ptr_domain .= ".in-addr.arpa";
696
			$newzone['ptr-domain'] = $ptr_domain;
697
			unset($ptr_domain, $revsubnet, $start_octet);
698
		}
699

    
700
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
701
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
702
			if ($newzone['domain-name']) {
703
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
704
			}
705
		} else if (isset($config['dnsmasq']['enable'])) {
706
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
707
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
708
				$newzone['dns-servers'] = $syscfg['dnsserver'];
709
			}
710
		} else if (isset($config['unbound']['enable'])) {
711
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
712
		} else if (!empty($dns_arrv4)) {
713
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
714
			if ($newzone['domain-name']) {
715
				$newzone['dns-servers'] = $dns_arrv4;
716
			}
717
		}
718

    
719
		/* Create classes - These all contain comma separated lists. Join them into one
720
		   big comma separated string then split them all up. */
721
		$all_mac_strings = array();
722
		if (is_array($dhcpifconf['pool'])) {
723
			foreach ($all_pools as $poolconf) {
724
				$all_mac_strings[] = $poolconf['mac_allow'];
725
				$all_mac_strings[] = $poolconf['mac_deny'];
726
			}
727
		}
728
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
729
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
730
		if (!empty($all_mac_strings)) {
731
			$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
732
			foreach ($all_mac_list as $mac) {
733
				if (empty($mac)) {
734
					continue;
735
				}
736
				$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
737
				// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
738
				$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
739
				$dhcpdconf .= '}' . "\n";
740
			}
741
		}
742

    
743
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
744

    
745
		// Setup pool options
746
		foreach ($all_pools as $poolconf) {
747
			if (!(ip_in_subnet($poolconf['range']['from'], "{$subnet}/{$ifcfgsn}") && ip_in_subnet($poolconf['range']['to'], "{$subnet}/{$ifcfgsn}"))) {
748
				// If the user has changed the subnet from the interfaces page and applied,
749
				// but has not updated the DHCP range, then the range to/from of the pool can be outside the subnet.
750
				// This can also happen when implementing the batch of changes when the setup wizard reloads the new settings.
751
				$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);
752
				$do_file_notice = true;
753
				$conf_ipv4_address = $ifcfg['ipaddr'];
754
				$conf_ipv4_subnetmask = $ifcfg['subnet'];
755
				if (is_ipaddrv4($conf_ipv4_address) && is_subnet("{$conf_ipv4_address}/{$conf_ipv4_subnetmask}")) {
756
					$conf_subnet_base = gen_subnet($conf_ipv4_address, $conf_ipv4_subnetmask);
757
					if (ip_in_subnet($poolconf['range']['from'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}") &&
758
					    ip_in_subnet($poolconf['range']['to'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}")) {
759
						// Even though the running interface subnet does not match the pool range,
760
						// the interface subnet in the config file contains the pool range.
761
						// We are somewhere part-way through a settings reload, e.g. after running the setup wizard.
762
						// services_dhcpdv4_configure will be called again later when the new interface settings from
763
						// the config are applied and at that time everything will match up.
764
						// Ignore this pool on this interface for now and just log the error to the system log.
765
						log_error($error_msg);
766
						$do_file_notice = false;
767
					}
768
				}
769
				if ($do_file_notice) {
770
					file_notice("DHCP", $error_msg);
771
				}
772
				continue;
773
			}
774
			$dhcpdconf .= "	pool {\n";
775
			/* is failover dns setup? */
776
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
777
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
778
				if ($poolconf['dnsserver'][1] <> "") {
779
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
780
				}
781
				if ($poolconf['dnsserver'][2] <> "") {
782
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
783
				}
784
				if ($poolconf['dnsserver'][3] <> "") {
785
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
786
				}
787
				$dhcpdconf .= ";\n";
788
			}
789

    
790
			/* allow/deny MACs */
791
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
792
			foreach ($mac_allow_list as $mac) {
793
				if (empty($mac)) {
794
					continue;
795
				}
796
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
797
			}
798
			$deny_action = "deny";
799
			if (isset($poolconf['nonak']) && empty($poolconf['failover_peerip'])) {
800
				$deny_action = "ignore";
801
			}
802
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
803
			foreach ($mac_deny_list as $mac) {
804
				if (empty($mac)) {
805
					continue;
806
				}
807
				$dhcpdconf .= "		$deny_action members of \"" . str_replace(':', '', $mac) . "\";\n";
808
			}
809

    
810
			if ($poolconf['failover_peerip'] <> "") {
811
				$dhcpdconf .= "		$deny_action dynamic bootp clients;\n";
812
			}
813

    
814
			if (isset($poolconf['denyunknown'])) {
815
				$dhcpdconf .= "		$deny_action unknown-clients;\n";
816
			}
817

    
818
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
819
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
820
			}
821

    
822
			if ($dhcpifconf['failover_peerip'] <> "") {
823
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
824
			}
825

    
826
			$pdnscfg = "";
827

    
828
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
829
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
830
			}
831

    
832
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
833
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
834
			}
835

    
836
			if (isset($poolconf['ddnsupdate'])) {
837
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
838
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
839
				}
840
				$pdnscfg .= "		ddns-update-style interim;\n";
841
			}
842

    
843
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
844
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
845
			}
846
			$dhcpdconf .= "{$pdnscfg}";
847

    
848
			// default-lease-time
849
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
850
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
851
			}
852

    
853
			// max-lease-time
854
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
855
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
856
			}
857

    
858
			// netbios-name*
859
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
860
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
861
				$dhcpdconf .= "		option netbios-node-type 8;\n";
862
			}
863

    
864
			// ntp-servers
865
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
866
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
867
			}
868

    
869
			// tftp-server-name
870
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
871
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
872
			}
873

    
874
			// ldap-server
875
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
876
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
877
			}
878

    
879
			// net boot information
880
			if (isset($poolconf['netboot'])) {
881
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
882
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
883
				}
884
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
885
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
886
				}
887
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
888
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
889
				}
890
			}
891
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
892
			$dhcpdconf .= "	}\n\n";
893
		}
894
// End of settings inside pools
895

    
896
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
897
			$routers = $dhcpifconf['gateway'];
898
			$add_routers = true;
899
		} elseif ($dhcpifconf['gateway'] == "none") {
900
			$add_routers = false;
901
		} else {
902
			$add_routers = $enable_add_routers;
903
			$routers = $ifcfgip;
904
		}
905
		if ($add_routers) {
906
			$dhcpdconf .= "	option routers {$routers};\n";
907
		}
908

    
909
		$dhcpdconf .= <<<EOD
910
$dnscfg
911

    
912
EOD;
913
		// default-lease-time
914
		if ($dhcpifconf['defaultleasetime']) {
915
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
916
		}
917

    
918
		// max-lease-time
919
		if ($dhcpifconf['maxleasetime']) {
920
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
921
		}
922

    
923
		// netbios-name*
924
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
925
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
926
			$dhcpdconf .= "	option netbios-node-type 8;\n";
927
		}
928

    
929
		// ntp-servers
930
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0]) {
931
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
932
		}
933

    
934
		// tftp-server-name
935
		if ($dhcpifconf['tftp'] <> "") {
936
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
937
		}
938

    
939
		// Handle option, number rowhelper values
940
		$dhcpdconf .= "\n";
941
		if ($dhcpifconf['numberoptions']['item']) {
942
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
943
				$item_value = base64_decode($item['value']);
944
				if (empty($item['type']) || $item['type'] == "text") {
945
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item_value}\";\n";
946
				} else {
947
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item_value};\n";
948
				}
949
			}
950
		}
951

    
952
		// ldap-server
953
		if ($dhcpifconf['ldap'] <> "") {
954
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
955
		}
956

    
957
		// net boot information
958
		if (isset($dhcpifconf['netboot'])) {
959
			if ($dhcpifconf['nextserver'] <> "") {
960
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
961
			}
962
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
963
				$dhcpdconf .= "	if option arch = 00:06 {\n";
964
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
965
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
966
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
967
				$dhcpdconf .= "	} else if option arch = 00:09 {\n";
968
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
969
				$dhcpdconf .= "	} else {\n";
970
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
971
				$dhcpdconf .= "	}\n\n";
972
			} elseif (!empty($dhcpifconf['filename'])) {
973
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
974
			}
975
			if (!empty($dhcpifconf['rootpath'])) {
976
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
977
			}
978
		}
979

    
980
		$dhcpdconf .= <<<EOD
981
}
982

    
983
EOD;
984

    
985
		/* add static mappings */
986
		if (is_array($dhcpifconf['staticmap'])) {
987

    
988
			$i = 0;
989
			foreach ($dhcpifconf['staticmap'] as $sm) {
990
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
991

    
992
				if ($sm['mac']) {
993
					$dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
994
				}
995

    
996
				if ($sm['cid']) {
997
					$dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
998
				}
999

    
1000
				if ($sm['ipaddr']) {
1001
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
1002
				}
1003

    
1004
				if ($sm['hostname']) {
1005
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1006
					$dhhostname = str_replace(".", "_", $dhhostname);
1007
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
1008
				}
1009
				if ($sm['filename']) {
1010
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
1011
				}
1012

    
1013
				if ($sm['rootpath']) {
1014
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
1015
				}
1016

    
1017
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
1018
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
1019
				}
1020

    
1021
				$smdnscfg = "";
1022

    
1023
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
1024
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
1025
				}
1026

    
1027
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
1028
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
1029
				}
1030

    
1031
				if (isset($sm['ddnsupdate'])) {
1032
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
1033
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
1034
					}
1035
					$pdnscfg .= "		ddns-update-style interim;\n";
1036
				}
1037

    
1038
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
1039
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
1040
				}
1041
				$dhcpdconf .= "{$smdnscfg}";
1042

    
1043
				// default-lease-time
1044
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
1045
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
1046
				}
1047

    
1048
				// max-lease-time
1049
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
1050
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
1051
				}
1052

    
1053
				// netbios-name*
1054
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
1055
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
1056
					$dhcpdconf .= "	option netbios-node-type 8;\n";
1057
				}
1058

    
1059
				// ntp-servers
1060
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
1061
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
1062
				}
1063

    
1064
				// tftp-server-name
1065
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
1066
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
1067
				}
1068

    
1069
				$dhcpdconf .= "}\n";
1070
				$i++;
1071
			}
1072
		}
1073

    
1074
		$dhcpdifs[] = get_real_interface($dhcpif);
1075
		if ($newzone['domain-name']) {
1076
			if ($need_ddns_updates) {
1077
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
1078
				$newzone['ddnsdomainkeyname'] = $dhcpifconf['ddnsdomainkeyname'];
1079
				$newzone['ddnsdomainkey'] = $dhcpifconf['ddnsdomainkey'];
1080
				$dhcpdconf .= dhcpdkey($dhcpifconf);
1081
			}
1082
			$ddns_zones[] = $newzone;
1083
		}
1084
	}
1085

    
1086
	if ($need_ddns_updates) {
1087
		$dhcpdconf .= "ddns-update-style interim;\n";
1088
		$dhcpdconf .= "update-static-leases on;\n";
1089

    
1090
		$dhcpdconf .= dhcpdzones($ddns_zones);
1091
	}
1092

    
1093
	/* write dhcpd.conf */
1094
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
1095
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1096
		unset($dhcpdconf);
1097
		return 1;
1098
	}
1099
	unset($dhcpdconf);
1100

    
1101
	/* create an empty leases database */
1102
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1103
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1104
	}
1105

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

    
1110
	/* fire up dhcpd in a chroot */
1111
	if (count($dhcpdifs) > 0) {
1112
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1113
			join(" ", $dhcpdifs));
1114
	}
1115

    
1116
	if (platform_booting()) {
1117
		print "done.\n";
1118
	}
1119

    
1120
	return 0;
1121
}
1122

    
1123
function dhcpdkey($dhcpifconf) {
1124
	$dhcpdconf = "";
1125
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1126
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1127
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1128
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1129
		$dhcpdconf .= "}\n";
1130
	}
1131

    
1132
	return $dhcpdconf;
1133
}
1134

    
1135
function dhcpdzones($ddns_zones) {
1136
	$dhcpdconf = "";
1137

    
1138
	if (is_array($ddns_zones)) {
1139
		$added_zones = array();
1140
		foreach ($ddns_zones as $zone) {
1141
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1142
				continue;
1143
			}
1144
			$primary = $zone['dns-servers'][0];
1145
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1146

    
1147
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1148
			if (!is_ipaddrv4($primary)) {
1149
				if (is_ipaddrv4($secondary)) {
1150
					$primary = $secondary;
1151
					$secondary = "";
1152
				} else {
1153
					continue;
1154
				}
1155
			}
1156

    
1157
			// We don't need to add zones multiple times.
1158
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1159
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1160
				$dhcpdconf .= "	primary {$primary};\n";
1161
				if (is_ipaddrv4($secondary)) {
1162
					$dhcpdconf .= "	secondary {$secondary};\n";
1163
				}
1164
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1165
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1166
				}
1167
				$dhcpdconf .= "}\n";
1168
				$added_zones[] = $zone['domain-name'];
1169
			}
1170
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1171
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1172
				$dhcpdconf .= "	primary {$primary};\n";
1173
				if (is_ipaddrv4($secondary)) {
1174
					$dhcpdconf .= "	secondary {$secondary};\n";
1175
				}
1176
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1177
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1178
				}
1179
				$dhcpdconf .= "}\n";
1180
				$added_zones[] = $zone['ptr-domain'];
1181
			}
1182
		}
1183
	}
1184

    
1185
	return $dhcpdconf;
1186
}
1187

    
1188
function services_dhcpdv6_configure($blacklist = array()) {
1189
	global $config, $g;
1190

    
1191
	if ($g['services_dhcp_server_enable'] == false) {
1192
		return;
1193
	}
1194

    
1195
	if (isset($config['system']['developerspew'])) {
1196
		$mt = microtime();
1197
		echo "services_dhcpd_configure($if) being called $mt\n";
1198
	}
1199

    
1200
	/* kill any running dhcpd */
1201
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1202
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1203
	}
1204
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1205
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1206
	}
1207

    
1208
	/* DHCP enabled on any interfaces? */
1209
	if (!is_dhcpv6_server_enabled()) {
1210
		return 0;
1211
	}
1212

    
1213
	if (platform_booting()) {
1214
		if ($g['platform'] != $g['product_name']) {
1215
			/* restore the leases, if we have them */
1216
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1217
				$dhcprestore = "";
1218
				$dhcpreturn = "";
1219
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1220
				$dhcprestore = implode(" ", $dhcprestore);
1221
				if ($dhcpreturn <> 0) {
1222
					log_error(sprintf(gettext('DHCP leases v6 restore failed exited with %1$s, the error is: %2$s'), $dhcpreturn, $dhcprestore));
1223
				}
1224
			}
1225
		}
1226
	}
1227

    
1228
	$syscfg = $config['system'];
1229
	if (!is_array($config['dhcpdv6'])) {
1230
		$config['dhcpdv6'] = array();
1231
	}
1232
	$dhcpdv6cfg = $config['dhcpdv6'];
1233
	$Iflist = get_configured_interface_list();
1234
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1235

    
1236

    
1237
	if (platform_booting()) {
1238
		echo "Starting DHCPv6 service...";
1239
	} else {
1240
		sleep(1);
1241
	}
1242

    
1243
	$custoptionsv6 = "";
1244
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1245
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1246
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1247
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1248
			}
1249
		}
1250
	}
1251

    
1252
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1253
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1254
	}
1255

    
1256
	$dhcpdv6conf = <<<EOD
1257

    
1258
option domain-name "{$syscfg['domain']}";
1259
option ldap-server code 95 = text;
1260
option domain-search-list code 119 = text;
1261
{$custoptionsv6}
1262
default-lease-time 7200;
1263
max-lease-time 86400;
1264
log-facility local7;
1265
one-lease-per-client true;
1266
deny duplicates;
1267
ping-check true;
1268
update-conflict-detection false;
1269

    
1270
EOD;
1271

    
1272
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1273
		$dhcpdv6conf .= "authoritative;\n";
1274
	}
1275

    
1276
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1277
		$dhcpdv6conf .= "always-broadcast on\n";
1278
	}
1279

    
1280
	$dhcpdv6ifs = array();
1281

    
1282
	$dhcpv6num = 0;
1283
	$nsupdate = false;
1284

    
1285
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1286

    
1287
		$ddns_zones = array();
1288

    
1289
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1290

    
1291
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1292
			continue;
1293
		}
1294
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1295
		if (!is_ipaddrv6($ifcfgipv6)) {
1296
			continue;
1297
		}
1298
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1299
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1300

    
1301
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1302
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1303
			$trackcfg = $config['interfaces'][$trackifname];
1304
			$pdlen = 64 - $trackcfg['dhcp6-ia-pd-len'];
1305
		}
1306

    
1307
		if ($is_olsr_enabled == true) {
1308
			if ($dhcpv6ifconf['netmask']) {
1309
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1310
			}
1311
		}
1312

    
1313
		$dnscfgv6 = "";
1314

    
1315
		if ($dhcpv6ifconf['domain']) {
1316
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1317
		}
1318

    
1319
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1320
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1321
		}
1322

    
1323
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1324
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1325
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1326
			}
1327
			if (empty($dhcpv6ifconf['ddnsclientupdates'])) {
1328
				$ddnsclientupdates = 'allow';
1329
			} else {
1330
				$ddnsclientupdates = $dhcpv6ifconf['ddnsclientupdates'];
1331
			}
1332
			$dnscfgv6 .= "	{$ddnsclientupdates} client-updates;\n";
1333
			$nsupdate = true;
1334
		} else {
1335
			$dnscfgv6 .= "	do-forward-updates false;\n";
1336
		}
1337

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

    
1354
		if (!is_ipaddrv6($ifcfgipv6)) {
1355
			$ifcfgsnv6 = "64";
1356
			$subnetv6 = gen_subnetv6($dhcpv6ifconf['range']['from'], $ifcfgsnv6);
1357
		}
1358

    
1359
		$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1360

    
1361
		if (isset($dhcpv6ifconf['ddnsupdate']) &&
1362
		    !empty($dhcpv6ifconf['ddnsdomain'])) {
1363
			$newzone = array();
1364
			$newzone['domain-name'] = $dhcpv6ifconf['ddnsdomain'];
1365
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1366
			$newzone['ddnsdomainkeyname'] = $dhcpv6ifconf['ddnsdomainkeyname'];
1367
			$newzone['ddnsdomainkey'] = $dhcpv6ifconf['ddnsdomainkey'];
1368
			$ddns_zones[] = $newzone;
1369
			if (isset($dhcpv6ifconf['ddnsreverse'])) {
1370
				$ptr_zones = get_v6_ptr_zones($subnetv6, $ifcfgsnv6);
1371
				foreach ($ptr_zones as $ptr_zone) {
1372
					$reversezone = array();
1373
					$reversezone['domain-name'] = $ptr_zone;
1374
					$reversezone['dns-servers'][] =
1375
					    $dhcpv6ifconf['ddnsdomainprimary'];
1376
					$ddns_zones[] = $reversezone;
1377
				}
1378
			}
1379
		}
1380

    
1381
		$dhcpdv6conf .= " {\n";
1382

    
1383
		$range_from = $dhcpv6ifconf['range']['from'];
1384
		$range_to = $dhcpv6ifconf['range']['to'];
1385
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1386
			$range_from = merge_ipv6_delegated_prefix($ifcfgipv6, $range_from, $pdlen);
1387
			$range_to = merge_ipv6_delegated_prefix($ifcfgipv6, $range_to, $pdlen);
1388
		}
1389

    
1390
		$dhcpdv6conf .= <<<EOD
1391
	range6 {$range_from} {$range_to};
1392
$dnscfgv6
1393

    
1394
EOD;
1395

    
1396
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1397
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1398
		}
1399
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1400
			$dns6ip = $dhcpv6ifconf['dns6ip'];
1401
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1402
			    Net_IPv6::isInNetmask($dns6ip, '::', $pdlen)) {
1403
				$dns6ip = merge_ipv6_delegated_prefix($ifcfgipv6, $dns6ip, $pdlen);
1404
			}
1405
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dns6ip};\n";
1406
		}
1407
		// default-lease-time
1408
		if ($dhcpv6ifconf['defaultleasetime']) {
1409
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1410
		}
1411

    
1412
		// max-lease-time
1413
		if ($dhcpv6ifconf['maxleasetime']) {
1414
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1415
		}
1416

    
1417
		// ntp-servers
1418
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1419
			$ntpservers = array();
1420
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1421
				if (!is_ipaddrv6($ntpserver)) {
1422
					continue;
1423
				}
1424
				if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1425
				    Net_IPv6::isInNetmask($ntpserver, '::', $pdlen)) {
1426
					$ntpserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ntpserver, $pdlen);
1427
				}
1428
				$ntpservers[] = $ntpserver;
1429
			}
1430
			if (count($ntpservers) > 0) {
1431
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1432
			}
1433
		}
1434
		// tftp-server-name
1435
		/* Needs ISC DHCPD support
1436
		 if ($dhcpv6ifconf['tftp'] <> "") {
1437
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1438
		 }
1439
		*/
1440

    
1441
		// Handle option, number rowhelper values
1442
		$dhcpdv6conf .= "\n";
1443
		if ($dhcpv6ifconf['numberoptions']['item']) {
1444
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1445
				$itemv6_value = base64_decode($itemv6['value']);
1446
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6_value}\";\n";
1447
			}
1448
		}
1449

    
1450
		// ldap-server
1451
		if ($dhcpv6ifconf['ldap'] <> "") {
1452
			$ldapserver = $dhcpv6ifconf['ldap'];
1453
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1454
			    Net_IPv6::isInNetmask($ldapserver, '::', $pdlen)) {
1455
				$ldapserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ldapserver, $pdlen);
1456
			}
1457
			$dhcpdv6conf .= "	option ldap-server \"{$ldapserver}\";\n";
1458
		}
1459

    
1460
		// net boot information
1461
		if (isset($dhcpv6ifconf['netboot'])) {
1462
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1463
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1464
			}
1465
		}
1466

    
1467
		$dhcpdv6conf .= "}\n";
1468

    
1469
		/* add static mappings */
1470
		/* Needs to use DUID */
1471
		if (is_array($dhcpv6ifconf['staticmap'])) {
1472
			$i = 0;
1473
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1474
				$dhcpdv6conf .= <<<EOD
1475
host s_{$dhcpv6if}_{$i} {
1476
	host-identifier option dhcp6.client-id {$sm['duid']};
1477

    
1478
EOD;
1479
				if ($sm['ipaddrv6']) {
1480
					$ipaddrv6 = $sm['ipaddrv6'];
1481
					if ($ifcfgv6['ipaddrv6'] == 'track6') {
1482
						$ipaddrv6 = merge_ipv6_delegated_prefix($ifcfgipv6, $ipaddrv6, $pdlen);
1483
					}
1484
					$dhcpdv6conf .= "	fixed-address6 {$ipaddrv6};\n";
1485
				}
1486

    
1487
				if ($sm['hostname']) {
1488
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1489
					$dhhostname = str_replace(".", "_", $dhhostname);
1490
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1491
				}
1492
				if ($sm['filename']) {
1493
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1494
				}
1495

    
1496
				if ($sm['rootpath']) {
1497
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1498
				}
1499

    
1500
				$dhcpdv6conf .= "}\n";
1501
				$i++;
1502
			}
1503
		}
1504

    
1505
		if ($dhcpv6ifconf['ddnsdomain']) {
1506
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1507
			$dhcpdv6conf .= dhcpdzones($ddns_zones);
1508
		}
1509

    
1510
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1511
			if (preg_match("/poes/si", $dhcpv6if)) {
1512
				/* magic here */
1513
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1514
			} else {
1515
				$realif = get_real_interface($dhcpv6if, "inet6");
1516
				if (stristr("$realif", "bridge")) {
1517
					$mac = get_interface_mac($realif);
1518
					$v6address = generate_ipv6_from_mac($mac);
1519
					/* Create link local address for bridges */
1520
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1521
				}
1522
				$realif = escapeshellcmd($realif);
1523
				$dhcpdv6ifs[] = $realif;
1524
			}
1525
		}
1526
	}
1527

    
1528
	if ($nsupdate) {
1529
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1530
	} else {
1531
		$dhcpdv6conf .= "ddns-update-style none;\n";
1532
	}
1533

    
1534
	/* write dhcpdv6.conf */
1535
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1536
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1537
		if (platform_booting()) {
1538
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1539
		}
1540
		unset($dhcpdv6conf);
1541
		return 1;
1542
	}
1543
	unset($dhcpdv6conf);
1544

    
1545
	/* create an empty leases v6 database */
1546
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1547
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1548
	}
1549

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

    
1554
	/* fire up dhcpd in a chroot */
1555
	if (count($dhcpdv6ifs) > 0) {
1556
		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 " .
1557
			join(" ", $dhcpdv6ifs));
1558
		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");
1559
	}
1560
	if (platform_booting()) {
1561
		print gettext("done.") . "\n";
1562
	}
1563

    
1564
	return 0;
1565
}
1566

    
1567
function services_igmpproxy_configure() {
1568
	global $config, $g;
1569

    
1570
	/* kill any running igmpproxy */
1571
	killbyname("igmpproxy");
1572

    
1573
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1574
		return 1;
1575
	}
1576

    
1577
	$iflist = get_configured_interface_list();
1578

    
1579
	$igmpconf = <<<EOD
1580

    
1581
##------------------------------------------------------
1582
## Enable Quickleave mode (Sends Leave instantly)
1583
##------------------------------------------------------
1584
quickleave
1585

    
1586
EOD;
1587

    
1588
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1589
		unset($iflist[$igmpcf['ifname']]);
1590
		$realif = get_real_interface($igmpcf['ifname']);
1591
		if (empty($igmpcf['threshold'])) {
1592
			$threshld = 1;
1593
		} else {
1594
			$threshld = $igmpcf['threshold'];
1595
		}
1596
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1597

    
1598
		if ($igmpcf['address'] <> "") {
1599
			$item = explode(" ", $igmpcf['address']);
1600
			foreach ($item as $iww) {
1601
				$igmpconf .= "altnet {$iww}\n";
1602
			}
1603
		}
1604
		$igmpconf .= "\n";
1605
	}
1606
	foreach ($iflist as $ifn) {
1607
		$realif = get_real_interface($ifn);
1608
		$igmpconf .= "phyint {$realif} disabled\n";
1609
	}
1610
	$igmpconf .= "\n";
1611

    
1612
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1613
	if (!$igmpfl) {
1614
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1615
		return;
1616
	}
1617
	fwrite($igmpfl, $igmpconf);
1618
	fclose($igmpfl);
1619
	unset($igmpconf);
1620

    
1621
	mwexec_bg("/usr/local/sbin/igmpproxy -v {$g['tmp_path']}/igmpproxy.conf");
1622
	log_error(gettext("Started IGMP proxy service."));
1623

    
1624
	return 0;
1625
}
1626

    
1627
function services_dhcrelay_configure() {
1628
	global $config, $g;
1629

    
1630
	if (isset($config['system']['developerspew'])) {
1631
		$mt = microtime();
1632
		echo "services_dhcrelay_configure() being called $mt\n";
1633
	}
1634

    
1635
	/* kill any running dhcrelay */
1636
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1637

    
1638
	$dhcrelaycfg =& $config['dhcrelay'];
1639

    
1640
	/* DHCPRelay enabled on any interfaces? */
1641
	if (!isset($dhcrelaycfg['enable'])) {
1642
		return 0;
1643
	}
1644

    
1645
	if (platform_booting()) {
1646
		echo gettext("Starting DHCP relay service...");
1647
	} else {
1648
		sleep(1);
1649
	}
1650

    
1651
	$iflist = get_configured_interface_list();
1652

    
1653
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1654
	foreach ($dhcifaces as $dhcrelayif) {
1655
		if (!isset($iflist[$dhcrelayif]) ||
1656
		    link_interface_to_bridge($dhcrelayif)) {
1657
			continue;
1658
		}
1659

    
1660
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1661
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1662
		}
1663
	}
1664

    
1665
	/*
1666
	 * In order for the relay to work, it needs to be active
1667
	 * on the interface in which the destination server sits.
1668
	 */
1669
	$srvips = explode(",", $dhcrelaycfg['server']);
1670
	if (!is_array($srvips)) {
1671
		log_error(gettext("No destination IP has been configured!"));
1672
		return;
1673
	}
1674

    
1675
	foreach ($srvips as $srcidx => $srvip) {
1676
		unset($destif);
1677
		foreach ($iflist as $ifname) {
1678
			$subnet = get_interface_ip($ifname);
1679
			if (!is_ipaddr($subnet)) {
1680
				continue;
1681
			}
1682
			$subnet .= "/" . get_interface_subnet($ifname);
1683
			if (ip_in_subnet($srvip, $subnet)) {
1684
				$destif = get_real_interface($ifname);
1685
				break;
1686
			}
1687
		}
1688
		if (!isset($destif)) {
1689
			foreach (get_staticroutes() as $rtent) {
1690
				if (ip_in_subnet($srvip, $rtent['network'])) {
1691
					$a_gateways = return_gateways_array(true);
1692
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1693
					break;
1694
				}
1695
			}
1696
		}
1697

    
1698
		if (!isset($destif)) {
1699
			/* Create a array from the existing route table */
1700
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1701
			array_shift($route_str);
1702
			array_shift($route_str);
1703
			array_shift($route_str);
1704
			array_shift($route_str);
1705
			$route_arr = array();
1706
			foreach ($route_str as $routeline) {
1707
				$items = preg_split("/[ ]+/i", $routeline);
1708
				if (is_subnetv4($items[0])) {
1709
					$subnet = $items[0];
1710
				} elseif (is_ipaddrv4($items[0])) {
1711
					$subnet = "{$items[0]}/32";
1712
				} else {
1713
					// Not a subnet or IP address, skip to the next line.
1714
					continue;
1715
				}
1716
				if (ip_in_subnet($srvip, $subnet)) {
1717
					$destif = trim($items[6]);
1718
					break;
1719
				}
1720
			}
1721
		}
1722

    
1723
		if (!isset($destif)) {
1724
			if (is_array($config['gateways']['gateway_item'])) {
1725
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1726
					if (isset($gateway['defaultgw'])) {
1727
						$destif = get_real_interface($gateway['interface']);
1728
						break;
1729
					}
1730
				}
1731
			} else {
1732
				$destif = get_real_interface("wan");
1733
			}
1734
		}
1735

    
1736
		if (!empty($destif)) {
1737
			$dhcrelayifs[] = $destif;
1738
		}
1739
	}
1740
	$dhcrelayifs = array_unique($dhcrelayifs);
1741

    
1742
	/* fire up dhcrelay */
1743
	if (empty($dhcrelayifs)) {
1744
		log_error(gettext("No suitable interface found for running dhcrelay!"));
1745
		return; /* XXX */
1746
	}
1747

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

    
1750
	if (isset($dhcrelaycfg['agentoption'])) {
1751
		$cmd .= " -a -m replace";
1752
	}
1753

    
1754
	$cmd .= " " . implode(" ", $srvips);
1755
	mwexec($cmd);
1756
	unset($cmd);
1757

    
1758
	return 0;
1759
}
1760

    
1761
function services_dhcrelay6_configure() {
1762
	global $config, $g;
1763

    
1764
	if (isset($config['system']['developerspew'])) {
1765
		$mt = microtime();
1766
		echo "services_dhcrelay6_configure() being called $mt\n";
1767
	}
1768

    
1769
	/* kill any running dhcrelay */
1770
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1771

    
1772
	$dhcrelaycfg =& $config['dhcrelay6'];
1773

    
1774
	/* DHCPv6 Relay enabled on any interfaces? */
1775
	if (!isset($dhcrelaycfg['enable'])) {
1776
		return 0;
1777
	}
1778

    
1779
	if (platform_booting()) {
1780
		echo gettext("Starting DHCPv6 relay service...");
1781
	} else {
1782
		sleep(1);
1783
	}
1784

    
1785
	$iflist = get_configured_interface_list();
1786

    
1787
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1788
	foreach ($dhcifaces as $dhcrelayif) {
1789
		if (!isset($iflist[$dhcrelayif]) ||
1790
		    link_interface_to_bridge($dhcrelayif)) {
1791
			continue;
1792
		}
1793

    
1794
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1795
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1796
		}
1797
	}
1798
	$dhcrelayifs = array_unique($dhcrelayifs);
1799

    
1800
	/*
1801
	 * In order for the relay to work, it needs to be active
1802
	 * on the interface in which the destination server sits.
1803
	 */
1804
	$srvips = explode(",", $dhcrelaycfg['server']);
1805
	$srvifaces = array();
1806
	foreach ($srvips as $srcidx => $srvip) {
1807
		unset($destif);
1808
		foreach ($iflist as $ifname) {
1809
			$subnet = get_interface_ipv6($ifname);
1810
			if (!is_ipaddrv6($subnet)) {
1811
				continue;
1812
			}
1813
			$subnet .= "/" . get_interface_subnetv6($ifname);
1814
			if (ip_in_subnet($srvip, $subnet)) {
1815
				$destif = get_real_interface($ifname);
1816
				break;
1817
			}
1818
		}
1819
		if (!isset($destif)) {
1820
			if (is_array($config['staticroutes']['route'])) {
1821
				foreach ($config['staticroutes']['route'] as $rtent) {
1822
					if (ip_in_subnet($srvip, $rtent['network'])) {
1823
						$a_gateways = return_gateways_array(true);
1824
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1825
						break;
1826
					}
1827
				}
1828
			}
1829
		}
1830

    
1831
		if (!isset($destif)) {
1832
			/* Create a array from the existing route table */
1833
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1834
			array_shift($route_str);
1835
			array_shift($route_str);
1836
			array_shift($route_str);
1837
			array_shift($route_str);
1838
			$route_arr = array();
1839
			foreach ($route_str as $routeline) {
1840
				$items = preg_split("/[ ]+/i", $routeline);
1841
				if (ip_in_subnet($srvip, $items[0])) {
1842
					$destif = trim($items[6]);
1843
					break;
1844
				}
1845
			}
1846
		}
1847

    
1848
		if (!isset($destif)) {
1849
			if (is_array($config['gateways']['gateway_item'])) {
1850
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1851
					if (isset($gateway['defaultgw'])) {
1852
						$destif = get_real_interface($gateway['interface']);
1853
						break;
1854
					}
1855
				}
1856
			} else {
1857
				$destif = get_real_interface("wan");
1858
			}
1859
		}
1860

    
1861
		if (!empty($destif)) {
1862
			$srvifaces[] = "{$srvip}%{$destif}";
1863
		}
1864
	}
1865

    
1866
	/* fire up dhcrelay */
1867
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1868
		log_error(gettext("No suitable interface found for running dhcrelay -6!"));
1869
		return; /* XXX */
1870
	}
1871

    
1872
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1873
	foreach ($dhcrelayifs as $dhcrelayif) {
1874
		$cmd .= " -l {$dhcrelayif}";
1875
	}
1876
	foreach ($srvifaces as $srviface) {
1877
		$cmd .= " -u \"{$srviface}\"";
1878
	}
1879
	mwexec($cmd);
1880
	unset($cmd);
1881

    
1882
	return 0;
1883
}
1884

    
1885
function services_dyndns_configure_client($conf) {
1886

    
1887
	if (!isset($conf['enable'])) {
1888
		return;
1889
	}
1890

    
1891
	/* load up the dyndns.class */
1892
	require_once("dyndns.class");
1893

    
1894
	$dns = new updatedns($dnsService = $conf['type'],
1895
		$dnsHost = $conf['host'],
1896
		$dnsDomain = $conf['domainname'],
1897
		$dnsUser = $conf['username'],
1898
		$dnsPass = $conf['password'],
1899
		$dnsWildcard = $conf['wildcard'],
1900
		$dnsMX = $conf['mx'],
1901
		$dnsIf = "{$conf['interface']}",
1902
		$dnsBackMX = NULL,
1903
		$dnsServer = NULL,
1904
		$dnsPort = NULL,
1905
		$dnsUpdateURL = "{$conf['updateurl']}",
1906
		$forceUpdate = $conf['force'],
1907
		$dnsZoneID = $conf['zoneid'],
1908
		$dnsTTL = $conf['ttl'],
1909
		$dnsResultMatch = "{$conf['resultmatch']}",
1910
		$dnsRequestIf = "{$conf['requestif']}",
1911
		$dnsID = "{$conf['id']}",
1912
		$dnsVerboseLog = $conf['verboselog'],
1913
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1914
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1915
}
1916

    
1917
function services_dyndns_configure($int = "") {
1918
	global $config, $g;
1919
	if (isset($config['system']['developerspew'])) {
1920
		$mt = microtime();
1921
		echo "services_dyndns_configure() being called $mt\n";
1922
	}
1923

    
1924
	$dyndnscfg = $config['dyndnses']['dyndns'];
1925
	$gwgroups = return_gateway_groups_array();
1926
	if (is_array($dyndnscfg)) {
1927
		if (platform_booting()) {
1928
			echo gettext("Starting DynDNS clients...");
1929
		}
1930

    
1931
		foreach ($dyndnscfg as $dyndns) {
1932
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1933
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1934
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1935
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1936
				services_dyndns_configure_client($dyndns);
1937
				sleep(1);
1938
			}
1939
		}
1940

    
1941
		if (platform_booting()) {
1942
			echo gettext("done.") . "\n";
1943
		}
1944
	}
1945

    
1946
	return 0;
1947
}
1948

    
1949
function dyndnsCheckIP($int) {
1950
	global $config;
1951
	$ip_address = get_interface_ip($int);
1952
	if (is_private_ip($ip_address)) {
1953
		$gateways_status = return_gateways_status(true);
1954
		// If the gateway for this interface is down, then the external check cannot work.
1955
		// Avoid the long wait for the external check to timeout.
1956
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
1957
			return "down";
1958
		}
1959
		$hosttocheck = "http://checkip.dyndns.org";
1960
		$ip_ch = curl_init($hosttocheck);
1961
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1962
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1963
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
1964
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1965
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1966
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1967
		$ip_result_page = curl_exec($ip_ch);
1968
		curl_close($ip_ch);
1969
		$ip_result_decoded = urldecode($ip_result_page);
1970
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1971
		$ip_address = trim($matches[1]);
1972
	}
1973
	return $ip_address;
1974
}
1975

    
1976
function services_dnsmasq_configure($restart_dhcp = true) {
1977
	global $config, $g;
1978
	$return = 0;
1979

    
1980
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1981
	$standard_args = array(
1982
		"dns-forward-max" => "--dns-forward-max=5000",
1983
		"cache-size" => "--cache-size=10000",
1984
		"local-ttl" => "--local-ttl=1"
1985
	);
1986

    
1987

    
1988
	if (isset($config['system']['developerspew'])) {
1989
		$mt = microtime();
1990
		echo "services_dnsmasq_configure() being called $mt\n";
1991
	}
1992

    
1993
	/* kill any running dnsmasq */
1994
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
1995
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1996
	}
1997

    
1998
	if (isset($config['dnsmasq']['enable'])) {
1999

    
2000
		if (platform_booting()) {
2001
			echo gettext("Starting DNS forwarder...");
2002
		} else {
2003
			sleep(1);
2004
		}
2005

    
2006
		/* generate hosts file */
2007
		if (system_hosts_generate() != 0) {
2008
			$return = 1;
2009
		}
2010

    
2011
		$args = "";
2012

    
2013
		if (isset($config['dnsmasq']['regdhcp'])) {
2014
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
2015
		}
2016

    
2017
		/* Setup listen port, if non-default */
2018
		if (is_port($config['dnsmasq']['port'])) {
2019
			$args .= " --port={$config['dnsmasq']['port']} ";
2020
		}
2021

    
2022
		$listen_addresses = "";
2023
		if (isset($config['dnsmasq']['interface'])) {
2024
			$interfaces = explode(",", $config['dnsmasq']['interface']);
2025
			foreach ($interfaces as $interface) {
2026
				$if = get_real_interface($interface);
2027
				if (does_interface_exist($if)) {
2028
					$laddr = get_interface_ip($interface);
2029
					if (is_ipaddrv4($laddr)) {
2030
						$listen_addresses .= " --listen-address={$laddr} ";
2031
					}
2032
					$laddr6 = get_interface_ipv6($interface);
2033
					if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
2034
						/*
2035
						 * XXX: Since dnsmasq does not support link-local address
2036
						 * with scope specified. These checks are being done.
2037
						 */
2038
						if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
2039
							$tmpaddrll6 = explode("%", $laddr6);
2040
							$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2041
						} else {
2042
							$listen_addresses .= " --listen-address={$laddr6} ";
2043
						}
2044
					}
2045
				}
2046
			}
2047
			if (!empty($listen_addresses)) {
2048
				$args .= " {$listen_addresses} ";
2049
				if (isset($config['dnsmasq']['strictbind'])) {
2050
					$args .= " --bind-interfaces ";
2051
				}
2052
			}
2053
		}
2054

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

    
2062
			// Build an array of domain overrides to help in checking for matches.
2063
			$override_a = array();
2064
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2065
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2066
					$override_a[$override['domain']] = "y";
2067
				}
2068
			}
2069

    
2070
			// Build an array of the private reverse lookup domain names
2071
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
2072
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
2073
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
2074
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
2075
			}
2076

    
2077
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
2078
			foreach ($reverse_domain_a as $reverse_domain) {
2079
				if (!isset($override_a[$reverse_domain])) {
2080
					$args .= " --server=/$reverse_domain/ ";
2081
				}
2082
			}
2083
			unset($override_a);
2084
			unset($reverse_domain_a);
2085
		}
2086

    
2087
		/* Setup forwarded domains */
2088
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2089
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2090
				if ($override['ip'] == "!") {
2091
					$override[ip] = "";
2092
				}
2093
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2094
			}
2095
		}
2096

    
2097
		/* Allow DNS Rebind for forwarded domains */
2098
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2099
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2100
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2101
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2102
				}
2103
			}
2104
		}
2105

    
2106
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2107
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2108
		}
2109

    
2110
		if (isset($config['dnsmasq']['strict_order'])) {
2111
			$args .= " --strict-order ";
2112
		}
2113

    
2114
		if (isset($config['dnsmasq']['domain_needed'])) {
2115
			$args .= " --domain-needed ";
2116
		}
2117

    
2118
		if ($config['dnsmasq']['custom_options']) {
2119
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2120
				$args .= " " . escapeshellarg("--{$c}");
2121
				$p = explode('=', $c);
2122
				if (array_key_exists($p[0], $standard_args)) {
2123
					unset($standard_args[$p[0]]);
2124
				}
2125
			}
2126
		}
2127
		$args .= ' ' . implode(' ', array_values($standard_args));
2128

    
2129
		/* run dnsmasq */
2130
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2131
		//log_error("dnsmasq command: {$cmd}");
2132
		mwexec_bg($cmd);
2133
		unset($args);
2134

    
2135
		system_dhcpleases_configure();
2136

    
2137
		if (platform_booting()) {
2138
			echo gettext("done.") . "\n";
2139
		}
2140
	}
2141

    
2142
	if (!platform_booting() && $restart_dhcp) {
2143
		if (services_dhcpd_configure() != 0) {
2144
			$return = 1;
2145
		}
2146
	}
2147

    
2148
	return $return;
2149
}
2150

    
2151
function services_unbound_configure($restart_dhcp = true) {
2152
	global $config, $g;
2153
	$return = 0;
2154

    
2155
	if (isset($config['system']['developerspew'])) {
2156
		$mt = microtime();
2157
		echo "services_unbound_configure() being called $mt\n";
2158
	}
2159

    
2160
	// kill any running Unbound instance
2161
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2162
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2163
	}
2164

    
2165
	if (isset($config['unbound']['enable'])) {
2166
		if (platform_booting()) {
2167
			echo gettext("Starting DNS Resolver...");
2168
		} else {
2169
			sleep(1);
2170
		}
2171

    
2172
		/* generate hosts file */
2173
		if (system_hosts_generate() != 0) {
2174
			$return = 1;
2175
		}
2176

    
2177
		require_once('/etc/inc/unbound.inc');
2178
		sync_unbound_service();
2179
		if (platform_booting()) {
2180
			echo gettext("done.") . "\n";
2181
		}
2182

    
2183
		system_dhcpleases_configure();
2184
	}
2185

    
2186
	if (!platform_booting() && $restart_dhcp) {
2187
		if (services_dhcpd_configure() != 0) {
2188
			$return = 1;
2189
		}
2190
	}
2191

    
2192
	return $return;
2193
}
2194

    
2195
function services_snmpd_configure() {
2196
	global $config, $g;
2197
	if (isset($config['system']['developerspew'])) {
2198
		$mt = microtime();
2199
		echo "services_snmpd_configure() being called $mt\n";
2200
	}
2201

    
2202
	/* kill any running snmpd */
2203
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2204
	sleep(2);
2205
	if (is_process_running("bsnmpd")) {
2206
		mwexec("/usr/bin/killall bsnmpd", true);
2207
	}
2208

    
2209
	if (isset($config['snmpd']['enable'])) {
2210

    
2211
		if (platform_booting()) {
2212
			echo gettext("Starting SNMP daemon... ");
2213
		}
2214

    
2215
		/* generate snmpd.conf */
2216
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2217
		if (!$fd) {
2218
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2219
			return 1;
2220
		}
2221

    
2222

    
2223
		$snmpdconf = <<<EOD
2224
location := "{$config['snmpd']['syslocation']}"
2225
contact := "{$config['snmpd']['syscontact']}"
2226
read := "{$config['snmpd']['rocommunity']}"
2227

    
2228
EOD;
2229

    
2230
/* No docs on what write strings do there so disable for now.
2231
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2232
			$snmpdconf .= <<<EOD
2233
# write string
2234
write := "{$config['snmpd']['rwcommunity']}"
2235

    
2236
EOD;
2237
		}
2238
*/
2239

    
2240

    
2241
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2242
			$snmpdconf .= <<<EOD
2243
# SNMP Trap support.
2244
traphost := {$config['snmpd']['trapserver']}
2245
trapport := {$config['snmpd']['trapserverport']}
2246
trap := "{$config['snmpd']['trapstring']}"
2247

    
2248

    
2249
EOD;
2250
		}
2251

    
2252
		$platform = trim(file_get_contents('/etc/platform'));
2253
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2254
			$platform = $g['product_name'];
2255
		}
2256
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2257
			" {$g['product_version']} {$platform} " . php_uname("s") .
2258
			" " . php_uname("r") . " " . php_uname("m");
2259

    
2260
		$snmpdconf .= <<<EOD
2261
system := 1     # pfSense
2262
%snmpd
2263
sysDescr			= "{$sysDescr}"
2264
begemotSnmpdDebugDumpPdus       = 2
2265
begemotSnmpdDebugSyslogPri      = 7
2266
begemotSnmpdCommunityString.0.1 = $(read)
2267

    
2268
EOD;
2269

    
2270
/* No docs on what write strings do there so disable for now.
2271
		if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2272
			$snmpdconf .= <<<EOD
2273
begemotSnmpdCommunityString.0.2 = $(write)
2274

    
2275
EOD;
2276
		}
2277
*/
2278

    
2279

    
2280
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2281
			$snmpdconf .= <<<EOD
2282
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2283
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2284
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2285

    
2286
EOD;
2287
		}
2288

    
2289

    
2290
		$snmpdconf .= <<<EOD
2291
begemotSnmpdCommunityDisable    = 1
2292

    
2293
EOD;
2294

    
2295
		$bind_to_ip = "0.0.0.0";
2296
		if (isset($config['snmpd']['bindip'])) {
2297
			if (is_ipaddr($config['snmpd']['bindip'])) {
2298
				$bind_to_ip = $config['snmpd']['bindip'];
2299
			} else {
2300
				$if = get_real_interface($config['snmpd']['bindip']);
2301
				if (does_interface_exist($if)) {
2302
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2303
				}
2304
			}
2305
		}
2306

    
2307
		if (is_port($config['snmpd']['pollport'])) {
2308
			$snmpdconf .= <<<EOD
2309
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2310

    
2311
EOD;
2312

    
2313
		}
2314

    
2315
		$snmpdconf .= <<<EOD
2316
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2317
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2318

    
2319
# These are bsnmp macros not php vars.
2320
sysContact      = $(contact)
2321
sysLocation     = $(location)
2322
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2323

    
2324
snmpEnableAuthenTraps = 2
2325

    
2326
EOD;
2327

    
2328
		if (is_array($config['snmpd']['modules'])) {
2329
			if (isset($config['snmpd']['modules']['mibii'])) {
2330
			$snmpdconf .= <<<EOD
2331
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2332

    
2333
EOD;
2334
			}
2335

    
2336
			if (isset($config['snmpd']['modules']['netgraph'])) {
2337
				$snmpdconf .= <<<EOD
2338
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2339
%netgraph
2340
begemotNgControlNodeName = "snmpd"
2341

    
2342
EOD;
2343
			}
2344

    
2345
			if (isset($config['snmpd']['modules']['pf'])) {
2346
				$snmpdconf .= <<<EOD
2347
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2348

    
2349
EOD;
2350
			}
2351

    
2352
			if (isset($config['snmpd']['modules']['hostres'])) {
2353
				$snmpdconf .= <<<EOD
2354
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2355

    
2356
EOD;
2357
			}
2358

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

    
2364
EOD;
2365
			}
2366
			if (isset($config['snmpd']['modules']['ucd'])) {
2367
				$snmpdconf .= <<<EOD
2368
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2369

    
2370
EOD;
2371
			}
2372
			if (isset($config['snmpd']['modules']['regex'])) {
2373
				$snmpdconf .= <<<EOD
2374
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2375

    
2376
EOD;
2377
			}
2378
		}
2379

    
2380
		fwrite($fd, $snmpdconf);
2381
		fclose($fd);
2382
		unset($snmpdconf);
2383

    
2384
		/* run bsnmpd */
2385
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2386
			" -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
		$gwgroups = return_gateway_groups_array();
2407
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2408
			if (!isset($dnsupdate['enable'])) {
2409
				continue;
2410
			}
2411
			if (!empty($int) && ($int != $dnsupdate['interface']) && (!is_array($gwgroups[$dnsupdate['interface']]))) {
2412
				continue;
2413
			}
2414
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2415
				continue;
2416
			}
2417

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2545
	return 0;
2546
}
2547

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

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

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

    
2565

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

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

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

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

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

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

    
2608
	conf_mount_ro();
2609
}
2610

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

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

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

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

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

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

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

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

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

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

    
2705
?>
(49-49/65)