Project

General

Profile

Download (83.3 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 freedns-v6 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,freeDNS (v6),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
		$racarpif = false;
109
		/* check if binding to CARP IP */
110
		if (!empty($dhcpv6ifconf['rainterface'])) {
111
			if (strstr($dhcpv6ifconf['rainterface'], "_vip")) {
112
				if (get_carp_interface_status($dhcpv6ifconf['rainterface']) == "MASTER") {
113
					$dhcpv6if = $dhcpv6ifconf['rainterface'];
114
					$racarpif = true;
115
				} else {
116
					continue;
117
				}
118
			}
119
		}
120

    
121
		$realif = get_real_interface($dhcpv6if, "inet6");
122

    
123
		if (isset($radvdifs[$realif])) {
124
			continue;
125
		}
126

    
127
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
128
		if (!is_ipaddrv6($ifcfgipv6)) {
129
			continue;
130
		}
131

    
132
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
133
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
134
		$radvdifs[$realif] = $realif;
135

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

    
202
		if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
203
		  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
204
		} else {
205
		  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
206
		}
207

    
208
		if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
209
		  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
210
		} else {
211
		  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
212
		}
213

    
214
		$radvdconf .= "\t};\n";
215

    
216
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
217
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
218
				if (is_subnetv6($subnet)) {
219
					$radvdconf .= "\tprefix {$subnet} {\n";
220
					$radvdconf .= "\t\tDeprecatePrefix on;\n";
221
					switch ($dhcpv6ifconf['ramode']) {
222
						case "managed":
223
							$radvdconf .= "\t\tAdvOnLink on;\n";
224
							$radvdconf .= "\t\tAdvAutonomous off;\n";
225
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
226
							break;
227
						case "router":
228
							$radvdconf .= "\t\tAdvOnLink off;\n";
229
							$radvdconf .= "\t\tAdvAutonomous off;\n";
230
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
231
							break;
232
						case "assist":
233
							$radvdconf .= "\t\tAdvOnLink on;\n";
234
							$radvdconf .= "\t\tAdvAutonomous on;\n";
235
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
236
							break;
237
						case "unmanaged":
238
							$radvdconf .= "\t\tAdvOnLink on;\n";
239
							$radvdconf .= "\t\tAdvAutonomous on;\n";
240
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
241
							break;
242
					}
243
					$radvdconf .= "\t};\n";
244
				}
245
			}
246
		}
247
		$radvdconf .= "\troute ::/0 {\n";
248
		$radvdconf .= "\t\tRemoveRoute on;\n";
249
		$radvdconf .= "\t};\n";
250

    
251
		/* add DNS servers */
252
		$dnslist = array();
253
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
254
			foreach ($dhcpv6ifconf['dnsserver'] as $server) {
255
				if (is_ipaddrv6($server)) {
256
					$dnslist[] = $server;
257
				}
258
			}
259
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
260
			foreach ($dhcpv6ifconf['radnsserver'] as $server) {
261
				if (is_ipaddrv6($server)) {
262
					$dnslist[] = $server;
263
				}
264
			}
265
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
266
			$dnslist[] = get_interface_ipv6($realif);
267
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
268
			foreach ($config['system']['dnsserver'] as $server) {
269
				if (is_ipaddrv6($server)) {
270
					$dnslist[] = $server;
271
				}
272
			}
273
		}
274
		if (count($dnslist) > 0) {
275
			$dnsstring = implode(" ", $dnslist);
276
			if ($dnsstring <> "") {
277
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
278
			}
279
		}
280
		if (!empty($dhcpv6ifconf['domain'])) {
281
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
282
		} elseif (!empty($config['system']['domain'])) {
283
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
284
		}
285
		$radvdconf .= "};\n";
286
	}
287

    
288
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
289
	foreach ($Iflist as $if => $ifdescr) {
290
		if (!isset($config['interfaces'][$if]['track6-interface']) ||
291
		    !isset($config['interfaces'][$if]['ipaddrv6']) ||
292
		    $config['interfaces'][$if]['ipaddrv6'] != 'track6') {
293
			continue;
294
		}
295
		if (!isset($config['interfaces'][$if]['enable'])) {
296
			continue;
297
		}
298
		if ($config['dhcpdv6'][$if]['ramode'] == "disabled") {
299
			continue;
300
		}
301
		/* Do not put in the config an interface which is down */
302
		if (isset($blacklist[$if])) {
303
			continue;
304
		}
305
		$trackif = $config['interfaces'][$if]['track6-interface'];
306
		if (empty($config['interfaces'][$trackif])) {
307
			continue;
308
		}
309

    
310
		$realif = get_real_interface($if, "inet6");
311

    
312
		/* prevent duplicate entries, manual overrides */
313
		if (isset($radvdifs[$realif])) {
314
			continue;
315
		}
316

    
317
		$ifcfgipv6 = get_interface_ipv6($if);
318
		if (!is_ipaddrv6($ifcfgipv6)) {
319
			$subnetv6 = "::";
320
			$ifcfgsnv6 = "64";
321
		} else {
322
			$ifcfgsnv6 = get_interface_subnetv6($if);
323
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
324
		}
325
		$radvdifs[$realif] = $realif;
326

    
327
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
328

    
329
		if ($g['debug']) {
330
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
331
		}
332

    
333
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
334
		$radvdconf .= "interface {$realif} {\n";
335
		$radvdconf .= "\tAdvSendAdvert on;\n";
336
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
337
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
338
		$mtu = get_interface_mtu($realif);
339
		if (is_numeric($mtu)) {
340
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
341
		} else {
342
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
343
		}
344
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
345
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
346
		$radvdconf .= "\t\tAdvOnLink on;\n";
347
		$radvdconf .= "\t\tAdvAutonomous on;\n";
348
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
349
		$radvdconf .= "\t};\n";
350

    
351
		/* add DNS servers */
352
		$dnslist = array();
353
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
354
			$dnslist[] = $ifcfgipv6;
355
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
356
			foreach ($config['system']['dnsserver'] as $server) {
357
				if (is_ipaddrv6($server)) {
358
					$dnslist[] = $server;
359
				}
360
			}
361
		}
362
		if (count($dnslist) > 0) {
363
			$dnsstring = implode(" ", $dnslist);
364
			if (!empty($dnsstring)) {
365
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
366
			}
367
		}
368
		if (!empty($config['system']['domain'])) {
369
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
370
		}
371
		$radvdconf .= "};\n";
372
	}
373

    
374
	/* write radvd.conf */
375
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
376
		log_error(gettext("Error: cannot open radvd.conf in services_radvd_configure()."));
377
		if (platform_booting()) {
378
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
379
		}
380
	}
381
	unset($radvdconf);
382

    
383
	if (count($radvdifs) > 0) {
384
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
385
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
386
		} else {
387
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
388
		}
389
	} else {
390
		/* we need to shut down the radvd cleanly, it will send out the prefix
391
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
392
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
393
			log_error(gettext("Shutting down Router Advertisment daemon cleanly"));
394
			killbypid("{$g['varrun_path']}/radvd.pid");
395
			@unlink("{$g['varrun_path']}/radvd.pid");
396
		}
397
	}
398
	return 0;
399
}
400

    
401
function services_dhcpd_configure($family = "all", $blacklist = array()) {
402
	global $config, $g;
403

    
404
	/* configure DHCPD chroot once */
405
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh", "w");
406
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
407
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
408
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
409
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
410
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
411
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
412
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
413
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
414
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
415
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
416
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
417
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
418
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
419

    
420
	$status = `/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep "{$g['dhcpd_chroot_path']}/dev"`;
421
	if (!trim($status)) {
422
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
423
	}
424
	fclose($fd);
425
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
426

    
427
	if ($family == "all" || $family == "inet") {
428
		services_dhcpdv4_configure();
429
	}
430
	if ($family == "all" || $family == "inet6") {
431
		services_dhcpdv6_configure($blacklist);
432
		services_radvd_configure($blacklist);
433
	}
434
}
435

    
436
function services_dhcpdv4_configure() {
437
	global $config, $g;
438
	$need_ddns_updates = false;
439
	$ddns_zones = array();
440

    
441
	if ($g['services_dhcp_server_enable'] == false) {
442
		return;
443
	}
444

    
445
	if (isset($config['system']['developerspew'])) {
446
		$mt = microtime();
447
		echo "services_dhcpdv4_configure($if) being called $mt\n";
448
	}
449

    
450
	/* kill any running dhcpd */
451
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
452
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
453
	}
454

    
455
	/* DHCP enabled on any interfaces? */
456
	if (!is_dhcp_server_enabled()) {
457
		return 0;
458
	}
459

    
460
	/* if OLSRD is enabled, allow WAN to house DHCP. */
461
	if (!function_exists('is_package_installed')) {
462
		require_once('pkg-utils.inc');
463
	}
464
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) {
465
		foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
466
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
467
				$is_olsr_enabled = true;
468
				break;
469
			}
470
		}
471
	}
472

    
473
	if (platform_booting()) {
474
		/* restore the leases, if we have them */
475
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
476
			$dhcprestore = "";
477
			$dhcpreturn = "";
478
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
479
			$dhcprestore = implode(" ", $dhcprestore);
480
			if ($dhcpreturn <> 0) {
481
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
482
			}
483
		}
484
		/* 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. */
485
		if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
486
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
487
		}
488
	}
489

    
490
	$syscfg = $config['system'];
491
	if (!is_array($config['dhcpd'])) {
492
		$config['dhcpd'] = array();
493
	}
494
	$dhcpdcfg = $config['dhcpd'];
495
	$Iflist = get_configured_interface_list();
496

    
497
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
498
	$dns_arrv4 = array();
499
	if (is_array($syscfg['dnsserver'])) {
500
		foreach ($syscfg['dnsserver'] as $dnsserver) {
501
			if (is_ipaddrv4($dnsserver)) {
502
				$dns_arrv4[] = $dnsserver;
503
			}
504
		}
505
	}
506

    
507
	if (platform_booting()) {
508
		echo gettext("Starting DHCP service...");
509
	} else {
510
		sleep(1);
511
	}
512

    
513
	$custoptions = "";
514
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
515
		if (is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
516
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
517
				if (!empty($item['type'])) {
518
					$itemtype = $item['type'];
519
				} else {
520
					$itemtype = "text";
521
				}
522
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
523
			}
524
		}
525
	}
526

    
527
	$dhcpdconf = <<<EOD
528

    
529
option domain-name "{$syscfg['domain']}";
530
option ldap-server code 95 = text;
531
option domain-search-list code 119 = text;
532
option arch code 93 = unsigned integer 16; # RFC4578
533
{$custoptions}
534
default-lease-time 7200;
535
max-lease-time 86400;
536
log-facility local7;
537
one-lease-per-client true;
538
deny duplicates;
539
ping-check true;
540
update-conflict-detection false;
541

    
542
EOD;
543

    
544
	if (!isset($dhcpifconf['disableauthoritative'])) {
545
		$dhcpdconf .= "authoritative;\n";
546
	}
547

    
548
	if (isset($dhcpifconf['alwaysbroadcast'])) {
549
		$dhcpdconf .= "always-broadcast on\n";
550
	}
551

    
552
	$dhcpdifs = array();
553
	$enable_add_routers = false;
554
	$gateways_arr = return_gateways_array();
555
	/* only add a routers line if the system has any IPv4 gateway at all */
556
	/* a static route has a gateway, manually overriding this field always works */
557
	foreach ($gateways_arr as $gwitem) {
558
		if ($gwitem['ipprotocol'] == "inet") {
559
			$enable_add_routers = true;
560
			break;
561
		}
562
	}
563

    
564
	/*    loop through and determine if we need to setup
565
	 *    failover peer "bleh" entries
566
	 */
567
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
568

    
569
		if (!isset($config['interfaces'][$dhcpif]['enable'])) {
570
			continue;
571
		}
572

    
573
		interfaces_staticarp_configure($dhcpif);
574

    
575
		if (!isset($dhcpifconf['enable'])) {
576
			continue;
577
		}
578

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

    
614
			if (is_ipaddrv4($intip)) {
615
				$dhcpdconf .= <<<EOPP
616
failover peer "dhcp_{$dhcpif}" {
617
  {$type};
618
  address {$intip};
619
  port {$my_port};
620
  peer address {$dhcpifconf['failover_peerip']};
621
  peer port {$peer_port};
622
  max-response-delay 10;
623
  max-unacked-updates 10;
624
  {$dhcpdconf_pri}
625
  load balance max seconds 3;
626
}
627
\n
628
EOPP;
629
			}
630
		}
631
	}
632

    
633
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
634

    
635
		$newzone = array();
636
		$ifcfg = $config['interfaces'][$dhcpif];
637

    
638
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) {
639
			continue;
640
		}
641
		$ifcfgip = get_interface_ip($dhcpif);
642
		$ifcfgsn = get_interface_subnet($dhcpif);
643
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
644
		$subnetmask = gen_subnet_mask($ifcfgsn);
645

    
646
		if (!is_ipaddr($subnet)) {
647
			continue;
648
		}
649

    
650
		if ($is_olsr_enabled == true) {
651
			if ($dhcpifconf['netmask']) {
652
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
653
			}
654
		}
655

    
656
		$all_pools = array();
657
		$all_pools[] = $dhcpifconf;
658
		if (is_array($dhcpifconf['pool'])) {
659
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
660
		}
661

    
662
		$dnscfg = "";
663

    
664
		if ($dhcpifconf['domain']) {
665
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
666
		}
667

    
668
		if ($dhcpifconf['domainsearchlist'] <> "") {
669
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
670
		}
671

    
672
		if (isset($dhcpifconf['ddnsupdate'])) {
673
			$need_ddns_updates = true;
674
			$newzone = array();
675
			if ($dhcpifconf['ddnsdomain'] <> "") {
676
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
677
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
678
			} else {
679
				$newzone['domain-name'] = $config['system']['domain'];
680
			}
681

    
682
			$revsubnet = array_reverse(explode('.',$subnet));
683

    
684
			/* Take care of full classes first */
685
			switch ($ifcfgsn) {
686
				case 8:
687
					$start_octet = 3;
688
					break;
689
				case 16:
690
					$start_octet = 2;
691
					break;
692
				case 24:
693
					$start_octet = 1;
694
					break;
695
				default:
696
					$start_octet = 0;
697
					/* Add subnet bitmask to first octet */
698
					$revsubnet[0] .= '-' . $ifcfgsn;
699
					break;
700

    
701
			}
702

    
703
			$ptr_domain = '';
704
			for ($octet = 0; $octet <= 3; $octet++) {
705
				if ($octet < $start_octet) {
706
					continue;
707
				}
708
				$ptr_domain .= (empty($ptr_domain) ? '' : '.');
709
				$ptr_domain .= $revsubnet[$octet];
710
			}
711
			$ptr_domain .= ".in-addr.arpa";
712
			$newzone['ptr-domain'] = $ptr_domain;
713
			unset($ptr_domain, $revsubnet, $start_octet);
714
		}
715

    
716
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
717
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
718
			if ($newzone['domain-name']) {
719
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
720
			}
721
		} else if (isset($config['dnsmasq']['enable'])) {
722
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
723
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
724
				$newzone['dns-servers'] = $syscfg['dnsserver'];
725
			}
726
		} else if (isset($config['unbound']['enable'])) {
727
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
728
		} else if (!empty($dns_arrv4)) {
729
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
730
			if ($newzone['domain-name']) {
731
				$newzone['dns-servers'] = $dns_arrv4;
732
			}
733
		}
734

    
735
		/* Create classes - These all contain comma separated lists. Join them into one
736
		   big comma separated string then split them all up. */
737
		$all_mac_strings = array();
738
		if (is_array($dhcpifconf['pool'])) {
739
			foreach ($all_pools as $poolconf) {
740
				$all_mac_strings[] = $poolconf['mac_allow'];
741
				$all_mac_strings[] = $poolconf['mac_deny'];
742
			}
743
		}
744
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
745
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
746
		if (!empty($all_mac_strings)) {
747
			$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
748
			foreach ($all_mac_list as $mac) {
749
				if (empty($mac)) {
750
					continue;
751
				}
752
				$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
753
				// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
754
				$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
755
				$dhcpdconf .= '}' . "\n";
756
			}
757
		}
758

    
759
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
760

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

    
806
			/* allow/deny MACs */
807
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
808
			foreach ($mac_allow_list as $mac) {
809
				if (empty($mac)) {
810
					continue;
811
				}
812
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
813
			}
814
			$deny_action = "deny";
815
			if (isset($poolconf['nonak']) && empty($poolconf['failover_peerip'])) {
816
				$deny_action = "ignore";
817
			}
818
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
819
			foreach ($mac_deny_list as $mac) {
820
				if (empty($mac)) {
821
					continue;
822
				}
823
				$dhcpdconf .= "		$deny_action members of \"" . str_replace(':', '', $mac) . "\";\n";
824
			}
825

    
826
			if ($poolconf['failover_peerip'] <> "") {
827
				$dhcpdconf .= "		$deny_action dynamic bootp clients;\n";
828
			}
829

    
830
			if (isset($poolconf['denyunknown'])) {
831
				$dhcpdconf .= "		$deny_action unknown-clients;\n";
832
			}
833

    
834
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
835
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
836
			}
837

    
838
			if ($dhcpifconf['failover_peerip'] <> "") {
839
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
840
			}
841

    
842
			$pdnscfg = "";
843

    
844
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
845
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
846
			}
847

    
848
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
849
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
850
			}
851

    
852
			if (isset($poolconf['ddnsupdate'])) {
853
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
854
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
855
				}
856
				$pdnscfg .= "		ddns-update-style interim;\n";
857
			}
858

    
859
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
860
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
861
			}
862
			$dhcpdconf .= "{$pdnscfg}";
863

    
864
			// default-lease-time
865
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
866
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
867
			}
868

    
869
			// max-lease-time
870
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
871
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
872
			}
873

    
874
			// netbios-name*
875
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
876
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
877
				$dhcpdconf .= "		option netbios-node-type 8;\n";
878
			}
879

    
880
			// ntp-servers
881
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
882
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
883
			}
884

    
885
			// tftp-server-name
886
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
887
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
888
			}
889

    
890
			// ldap-server
891
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
892
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
893
			}
894

    
895
			// net boot information
896
			if (isset($poolconf['netboot'])) {
897
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
898
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
899
				}
900
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
901
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
902
				}
903
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
904
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
905
				}
906
			}
907
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
908
			$dhcpdconf .= "	}\n\n";
909
		}
910
// End of settings inside pools
911

    
912
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
913
			$routers = $dhcpifconf['gateway'];
914
			$add_routers = true;
915
		} elseif ($dhcpifconf['gateway'] == "none") {
916
			$add_routers = false;
917
		} else {
918
			$add_routers = $enable_add_routers;
919
			$routers = $ifcfgip;
920
		}
921
		if ($add_routers) {
922
			$dhcpdconf .= "	option routers {$routers};\n";
923
		}
924

    
925
		$dhcpdconf .= <<<EOD
926
$dnscfg
927

    
928
EOD;
929
		// default-lease-time
930
		if ($dhcpifconf['defaultleasetime']) {
931
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
932
		}
933

    
934
		// max-lease-time
935
		if ($dhcpifconf['maxleasetime']) {
936
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
937
		}
938

    
939
		// netbios-name*
940
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
941
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
942
			$dhcpdconf .= "	option netbios-node-type 8;\n";
943
		}
944

    
945
		// ntp-servers
946
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0]) {
947
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
948
		}
949

    
950
		// tftp-server-name
951
		if ($dhcpifconf['tftp'] <> "") {
952
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
953
		}
954

    
955
		// Handle option, number rowhelper values
956
		$dhcpdconf .= "\n";
957
		if ($dhcpifconf['numberoptions']['item']) {
958
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
959
				$item_value = base64_decode($item['value']);
960
				if (empty($item['type']) || $item['type'] == "text") {
961
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item_value}\";\n";
962
				} else {
963
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item_value};\n";
964
				}
965
			}
966
		}
967

    
968
		// ldap-server
969
		if ($dhcpifconf['ldap'] <> "") {
970
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
971
		}
972

    
973
		// net boot information
974
		if (isset($dhcpifconf['netboot'])) {
975
			if ($dhcpifconf['nextserver'] <> "") {
976
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
977
			}
978
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
979
				$dhcpdconf .= "	if option arch = 00:06 {\n";
980
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
981
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
982
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
983
				$dhcpdconf .= "	} else if option arch = 00:09 {\n";
984
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
985
				$dhcpdconf .= "	} else {\n";
986
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
987
				$dhcpdconf .= "	}\n\n";
988
			} elseif (!empty($dhcpifconf['filename'])) {
989
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
990
			}
991
			if (!empty($dhcpifconf['rootpath'])) {
992
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
993
			}
994
		}
995

    
996
		$dhcpdconf .= <<<EOD
997
}
998

    
999
EOD;
1000

    
1001
		/* add static mappings */
1002
		if (is_array($dhcpifconf['staticmap'])) {
1003

    
1004
			$i = 0;
1005
			foreach ($dhcpifconf['staticmap'] as $sm) {
1006
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
1007

    
1008
				if ($sm['mac']) {
1009
					$dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
1010
				}
1011

    
1012
				if ($sm['cid']) {
1013
					$dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
1014
				}
1015

    
1016
				if ($sm['ipaddr']) {
1017
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
1018
				}
1019

    
1020
				if ($sm['hostname']) {
1021
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1022
					$dhhostname = str_replace(".", "_", $dhhostname);
1023
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
1024
				}
1025
				if ($sm['filename']) {
1026
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
1027
				}
1028

    
1029
				if ($sm['rootpath']) {
1030
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
1031
				}
1032

    
1033
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
1034
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
1035
				}
1036

    
1037
				$smdnscfg = "";
1038

    
1039
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
1040
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
1041
				}
1042

    
1043
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
1044
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
1045
				}
1046

    
1047
				if (isset($sm['ddnsupdate'])) {
1048
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
1049
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
1050
					}
1051
					$pdnscfg .= "		ddns-update-style interim;\n";
1052
				}
1053

    
1054
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
1055
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
1056
				}
1057
				$dhcpdconf .= "{$smdnscfg}";
1058

    
1059
				// default-lease-time
1060
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
1061
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
1062
				}
1063

    
1064
				// max-lease-time
1065
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
1066
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
1067
				}
1068

    
1069
				// netbios-name*
1070
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
1071
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
1072
					$dhcpdconf .= "	option netbios-node-type 8;\n";
1073
				}
1074

    
1075
				// ntp-servers
1076
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
1077
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
1078
				}
1079

    
1080
				// tftp-server-name
1081
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
1082
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
1083
				}
1084

    
1085
				$dhcpdconf .= "}\n";
1086
				$i++;
1087
			}
1088
		}
1089

    
1090
		$dhcpdifs[] = get_real_interface($dhcpif);
1091
		if ($newzone['domain-name']) {
1092
			if ($need_ddns_updates) {
1093
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
1094
				$newzone['ddnsdomainkeyname'] = $dhcpifconf['ddnsdomainkeyname'];
1095
				$newzone['ddnsdomainkey'] = $dhcpifconf['ddnsdomainkey'];
1096
				$dhcpdconf .= dhcpdkey($dhcpifconf);
1097
			}
1098
			$ddns_zones[] = $newzone;
1099
		}
1100
	}
1101

    
1102
	if ($need_ddns_updates) {
1103
		$dhcpdconf .= "ddns-update-style interim;\n";
1104
		$dhcpdconf .= "update-static-leases on;\n";
1105

    
1106
		$dhcpdconf .= dhcpdzones($ddns_zones);
1107
	}
1108

    
1109
	/* write dhcpd.conf */
1110
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
1111
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1112
		unset($dhcpdconf);
1113
		return 1;
1114
	}
1115
	unset($dhcpdconf);
1116

    
1117
	/* create an empty leases database */
1118
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1119
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1120
	}
1121

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

    
1126
	/* fire up dhcpd in a chroot */
1127
	if (count($dhcpdifs) > 0) {
1128
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1129
			join(" ", $dhcpdifs));
1130
	}
1131

    
1132
	if (platform_booting()) {
1133
		print "done.\n";
1134
	}
1135

    
1136
	return 0;
1137
}
1138

    
1139
function dhcpdkey($dhcpifconf) {
1140
	$dhcpdconf = "";
1141
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1142
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1143
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1144
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1145
		$dhcpdconf .= "}\n";
1146
	}
1147

    
1148
	return $dhcpdconf;
1149
}
1150

    
1151
function dhcpdzones($ddns_zones) {
1152
	$dhcpdconf = "";
1153

    
1154
	if (is_array($ddns_zones)) {
1155
		$added_zones = array();
1156
		foreach ($ddns_zones as $zone) {
1157
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1158
				continue;
1159
			}
1160
			$primary = $zone['dns-servers'][0];
1161
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1162

    
1163
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1164
			if (!is_ipaddrv4($primary)) {
1165
				if (is_ipaddrv4($secondary)) {
1166
					$primary = $secondary;
1167
					$secondary = "";
1168
				} else {
1169
					continue;
1170
				}
1171
			}
1172

    
1173
			// We don't need to add zones multiple times.
1174
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1175
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1176
				$dhcpdconf .= "	primary {$primary};\n";
1177
				if (is_ipaddrv4($secondary)) {
1178
					$dhcpdconf .= "	secondary {$secondary};\n";
1179
				}
1180
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1181
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1182
				}
1183
				$dhcpdconf .= "}\n";
1184
				$added_zones[] = $zone['domain-name'];
1185
			}
1186
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1187
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1188
				$dhcpdconf .= "	primary {$primary};\n";
1189
				if (is_ipaddrv4($secondary)) {
1190
					$dhcpdconf .= "	secondary {$secondary};\n";
1191
				}
1192
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1193
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1194
				}
1195
				$dhcpdconf .= "}\n";
1196
				$added_zones[] = $zone['ptr-domain'];
1197
			}
1198
		}
1199
	}
1200

    
1201
	return $dhcpdconf;
1202
}
1203

    
1204
function services_dhcpdv6_configure($blacklist = array()) {
1205
	global $config, $g;
1206

    
1207
	if ($g['services_dhcp_server_enable'] == false) {
1208
		return;
1209
	}
1210

    
1211
	if (isset($config['system']['developerspew'])) {
1212
		$mt = microtime();
1213
		echo "services_dhcpd_configure($if) being called $mt\n";
1214
	}
1215

    
1216
	/* kill any running dhcpd */
1217
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1218
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1219
	}
1220
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1221
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1222
	}
1223

    
1224
	/* DHCP enabled on any interfaces? */
1225
	if (!is_dhcpv6_server_enabled()) {
1226
		return 0;
1227
	}
1228

    
1229
	if (platform_booting()) {
1230
		if ($g['platform'] != $g['product_name']) {
1231
			/* restore the leases, if we have them */
1232
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1233
				$dhcprestore = "";
1234
				$dhcpreturn = "";
1235
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1236
				$dhcprestore = implode(" ", $dhcprestore);
1237
				if ($dhcpreturn <> 0) {
1238
					log_error(sprintf(gettext('DHCP leases v6 restore failed exited with %1$s, the error is: %2$s'), $dhcpreturn, $dhcprestore));
1239
				}
1240
			}
1241
		}
1242
	}
1243

    
1244
	$syscfg = $config['system'];
1245
	if (!is_array($config['dhcpdv6'])) {
1246
		$config['dhcpdv6'] = array();
1247
	}
1248
	$dhcpdv6cfg = $config['dhcpdv6'];
1249
	$Iflist = get_configured_interface_list();
1250
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1251

    
1252

    
1253
	if (platform_booting()) {
1254
		echo "Starting DHCPv6 service...";
1255
	} else {
1256
		sleep(1);
1257
	}
1258

    
1259
	$custoptionsv6 = "";
1260
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1261
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1262
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1263
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1264
			}
1265
		}
1266
	}
1267

    
1268
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1269
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1270
	}
1271

    
1272
	$dhcpdv6conf = <<<EOD
1273

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

    
1286
EOD;
1287

    
1288
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1289
		$dhcpdv6conf .= "authoritative;\n";
1290
	}
1291

    
1292
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1293
		$dhcpdv6conf .= "always-broadcast on\n";
1294
	}
1295

    
1296
	$dhcpdv6ifs = array();
1297

    
1298
	$dhcpv6num = 0;
1299
	$nsupdate = false;
1300

    
1301
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1302

    
1303
		$ddns_zones = array();
1304

    
1305
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1306

    
1307
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1308
			continue;
1309
		}
1310
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1311
		if (!is_ipaddrv6($ifcfgipv6)) {
1312
			continue;
1313
		}
1314
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1315
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1316

    
1317
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1318
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1319
			$trackcfg = $config['interfaces'][$trackifname];
1320
			$pdlen = 64 - $trackcfg['dhcp6-ia-pd-len'];
1321
		}
1322

    
1323
		if ($is_olsr_enabled == true) {
1324
			if ($dhcpv6ifconf['netmask']) {
1325
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1326
			}
1327
		}
1328

    
1329
		$dnscfgv6 = "";
1330

    
1331
		if ($dhcpv6ifconf['domain']) {
1332
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1333
		}
1334

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

    
1339
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1340
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1341
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1342
			}
1343
			if (empty($dhcpv6ifconf['ddnsclientupdates'])) {
1344
				$ddnsclientupdates = 'allow';
1345
			} else {
1346
				$ddnsclientupdates = $dhcpv6ifconf['ddnsclientupdates'];
1347
			}
1348
			$dnscfgv6 .= "	{$ddnsclientupdates} client-updates;\n";
1349
			$nsupdate = true;
1350
		} else {
1351
			$dnscfgv6 .= "	do-forward-updates false;\n";
1352
		}
1353

    
1354
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1355
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1356
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1357
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1358
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1359
			$dns_arrv6 = array();
1360
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1361
				if (is_ipaddrv6($dnsserver)) {
1362
					$dns_arrv6[] = $dnsserver;
1363
				}
1364
			}
1365
			if (!empty($dns_arrv6)) {
1366
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1367
			}
1368
		}
1369

    
1370
		if (!is_ipaddrv6($ifcfgipv6)) {
1371
			$ifcfgsnv6 = "64";
1372
			$subnetv6 = gen_subnetv6($dhcpv6ifconf['range']['from'], $ifcfgsnv6);
1373
		}
1374

    
1375
		$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1376

    
1377
		if (isset($dhcpv6ifconf['ddnsupdate']) &&
1378
		    !empty($dhcpv6ifconf['ddnsdomain'])) {
1379
			$newzone = array();
1380
			$newzone['domain-name'] = $dhcpv6ifconf['ddnsdomain'];
1381
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1382
			$newzone['ddnsdomainkeyname'] = $dhcpv6ifconf['ddnsdomainkeyname'];
1383
			$newzone['ddnsdomainkey'] = $dhcpv6ifconf['ddnsdomainkey'];
1384
			$ddns_zones[] = $newzone;
1385
			if (isset($dhcpv6ifconf['ddnsreverse'])) {
1386
				$ptr_zones = get_v6_ptr_zones($subnetv6, $ifcfgsnv6);
1387
				foreach ($ptr_zones as $ptr_zone) {
1388
					$reversezone = array();
1389
					$reversezone['domain-name'] = $ptr_zone;
1390
					$reversezone['dns-servers'][] =
1391
					    $dhcpv6ifconf['ddnsdomainprimary'];
1392
					$ddns_zones[] = $reversezone;
1393
				}
1394
			}
1395
		}
1396

    
1397
		$dhcpdv6conf .= " {\n";
1398

    
1399
		$range_from = $dhcpv6ifconf['range']['from'];
1400
		$range_to = $dhcpv6ifconf['range']['to'];
1401
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1402
			$range_from = merge_ipv6_delegated_prefix($ifcfgipv6, $range_from, $pdlen);
1403
			$range_to = merge_ipv6_delegated_prefix($ifcfgipv6, $range_to, $pdlen);
1404
		}
1405

    
1406
		$dhcpdv6conf .= <<<EOD
1407
	range6 {$range_from} {$range_to};
1408
$dnscfgv6
1409

    
1410
EOD;
1411

    
1412
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1413
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1414
		}
1415
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1416
			$dns6ip = $dhcpv6ifconf['dns6ip'];
1417
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1418
			    Net_IPv6::isInNetmask($dns6ip, '::', $pdlen)) {
1419
				$dns6ip = merge_ipv6_delegated_prefix($ifcfgipv6, $dns6ip, $pdlen);
1420
			}
1421
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dns6ip};\n";
1422
		}
1423
		// default-lease-time
1424
		if ($dhcpv6ifconf['defaultleasetime']) {
1425
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1426
		}
1427

    
1428
		// max-lease-time
1429
		if ($dhcpv6ifconf['maxleasetime']) {
1430
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1431
		}
1432

    
1433
		// ntp-servers
1434
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1435
			$ntpservers = array();
1436
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1437
				if (!is_ipaddrv6($ntpserver)) {
1438
					continue;
1439
				}
1440
				if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1441
				    Net_IPv6::isInNetmask($ntpserver, '::', $pdlen)) {
1442
					$ntpserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ntpserver, $pdlen);
1443
				}
1444
				$ntpservers[] = $ntpserver;
1445
			}
1446
			if (count($ntpservers) > 0) {
1447
				$dhcpdv6conf .= "        option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1448
			}
1449
		}
1450
		// tftp-server-name
1451
		/* Needs ISC DHCPD support
1452
		 if ($dhcpv6ifconf['tftp'] <> "") {
1453
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1454
		 }
1455
		*/
1456

    
1457
		// Handle option, number rowhelper values
1458
		$dhcpdv6conf .= "\n";
1459
		if ($dhcpv6ifconf['numberoptions']['item']) {
1460
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1461
				$itemv6_value = base64_decode($itemv6['value']);
1462
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6_value}\";\n";
1463
			}
1464
		}
1465

    
1466
		// ldap-server
1467
		if ($dhcpv6ifconf['ldap'] <> "") {
1468
			$ldapserver = $dhcpv6ifconf['ldap'];
1469
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1470
			    Net_IPv6::isInNetmask($ldapserver, '::', $pdlen)) {
1471
				$ldapserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ldapserver, $pdlen);
1472
			}
1473
			$dhcpdv6conf .= "	option ldap-server \"{$ldapserver}\";\n";
1474
		}
1475

    
1476
		// net boot information
1477
		if (isset($dhcpv6ifconf['netboot'])) {
1478
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1479
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1480
			}
1481
		}
1482

    
1483
		$dhcpdv6conf .= "}\n";
1484

    
1485
		/* add static mappings */
1486
		/* Needs to use DUID */
1487
		if (is_array($dhcpv6ifconf['staticmap'])) {
1488
			$i = 0;
1489
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1490
				$dhcpdv6conf .= <<<EOD
1491
host s_{$dhcpv6if}_{$i} {
1492
	host-identifier option dhcp6.client-id {$sm['duid']};
1493

    
1494
EOD;
1495
				if ($sm['ipaddrv6']) {
1496
					$ipaddrv6 = $sm['ipaddrv6'];
1497
					if ($ifcfgv6['ipaddrv6'] == 'track6') {
1498
						$ipaddrv6 = merge_ipv6_delegated_prefix($ifcfgipv6, $ipaddrv6, $pdlen);
1499
					}
1500
					$dhcpdv6conf .= "	fixed-address6 {$ipaddrv6};\n";
1501
				}
1502

    
1503
				if ($sm['hostname']) {
1504
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1505
					$dhhostname = str_replace(".", "_", $dhhostname);
1506
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1507
				}
1508
				if ($sm['filename']) {
1509
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1510
				}
1511

    
1512
				if ($sm['rootpath']) {
1513
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1514
				}
1515

    
1516
				$dhcpdv6conf .= "}\n";
1517
				$i++;
1518
			}
1519
		}
1520

    
1521
		if ($dhcpv6ifconf['ddnsdomain']) {
1522
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1523
			$dhcpdv6conf .= dhcpdzones($ddns_zones);
1524
		}
1525

    
1526
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1527
			if (preg_match("/poes/si", $dhcpv6if)) {
1528
				/* magic here */
1529
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1530
			} else {
1531
				$realif = get_real_interface($dhcpv6if, "inet6");
1532
				if (stristr("$realif", "bridge")) {
1533
					$mac = get_interface_mac($realif);
1534
					$v6address = generate_ipv6_from_mac($mac);
1535
					/* Create link local address for bridges */
1536
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1537
				}
1538
				$realif = escapeshellcmd($realif);
1539
				$dhcpdv6ifs[] = $realif;
1540
			}
1541
		}
1542
	}
1543

    
1544
	if ($nsupdate) {
1545
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1546
	} else {
1547
		$dhcpdv6conf .= "ddns-update-style none;\n";
1548
	}
1549

    
1550
	/* write dhcpdv6.conf */
1551
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1552
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1553
		if (platform_booting()) {
1554
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1555
		}
1556
		unset($dhcpdv6conf);
1557
		return 1;
1558
	}
1559
	unset($dhcpdv6conf);
1560

    
1561
	/* create an empty leases v6 database */
1562
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1563
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1564
	}
1565

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

    
1570
	/* fire up dhcpd in a chroot */
1571
	if (count($dhcpdv6ifs) > 0) {
1572
		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 " .
1573
			join(" ", $dhcpdv6ifs));
1574
		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");
1575
	}
1576
	if (platform_booting()) {
1577
		print gettext("done.") . "\n";
1578
	}
1579

    
1580
	return 0;
1581
}
1582

    
1583
function services_igmpproxy_configure() {
1584
	global $config, $g;
1585

    
1586
	/* kill any running igmpproxy */
1587
	killbyname("igmpproxy");
1588

    
1589
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1590
		return 1;
1591
	}
1592

    
1593
	$iflist = get_configured_interface_list();
1594

    
1595
	$igmpconf = <<<EOD
1596

    
1597
##------------------------------------------------------
1598
## Enable Quickleave mode (Sends Leave instantly)
1599
##------------------------------------------------------
1600
quickleave
1601

    
1602
EOD;
1603

    
1604
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1605
		unset($iflist[$igmpcf['ifname']]);
1606
		$realif = get_real_interface($igmpcf['ifname']);
1607
		if (empty($igmpcf['threshold'])) {
1608
			$threshld = 1;
1609
		} else {
1610
			$threshld = $igmpcf['threshold'];
1611
		}
1612
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1613

    
1614
		if ($igmpcf['address'] <> "") {
1615
			$item = explode(" ", $igmpcf['address']);
1616
			foreach ($item as $iww) {
1617
				$igmpconf .= "altnet {$iww}\n";
1618
			}
1619
		}
1620
		$igmpconf .= "\n";
1621
	}
1622
	foreach ($iflist as $ifn) {
1623
		$realif = get_real_interface($ifn);
1624
		$igmpconf .= "phyint {$realif} disabled\n";
1625
	}
1626
	$igmpconf .= "\n";
1627

    
1628
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1629
	if (!$igmpfl) {
1630
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1631
		return;
1632
	}
1633
	fwrite($igmpfl, $igmpconf);
1634
	fclose($igmpfl);
1635
	unset($igmpconf);
1636

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

    
1640
	return 0;
1641
}
1642

    
1643
function services_dhcrelay_configure() {
1644
	global $config, $g;
1645

    
1646
	if (isset($config['system']['developerspew'])) {
1647
		$mt = microtime();
1648
		echo "services_dhcrelay_configure() being called $mt\n";
1649
	}
1650

    
1651
	/* kill any running dhcrelay */
1652
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1653

    
1654
	$dhcrelaycfg =& $config['dhcrelay'];
1655

    
1656
	/* DHCPRelay enabled on any interfaces? */
1657
	if (!isset($dhcrelaycfg['enable'])) {
1658
		return 0;
1659
	}
1660

    
1661
	if (platform_booting()) {
1662
		echo gettext("Starting DHCP relay service...");
1663
	} else {
1664
		sleep(1);
1665
	}
1666

    
1667
	$iflist = get_configured_interface_list();
1668

    
1669
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1670
	foreach ($dhcifaces as $dhcrelayif) {
1671
		if (!isset($iflist[$dhcrelayif]) ||
1672
		    link_interface_to_bridge($dhcrelayif)) {
1673
			continue;
1674
		}
1675

    
1676
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1677
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1678
		}
1679
	}
1680

    
1681
	/*
1682
	 * In order for the relay to work, it needs to be active
1683
	 * on the interface in which the destination server sits.
1684
	 */
1685
	$srvips = explode(",", $dhcrelaycfg['server']);
1686
	if (!is_array($srvips)) {
1687
		log_error(gettext("No destination IP has been configured!"));
1688
		return;
1689
	}
1690

    
1691
	foreach ($srvips as $srcidx => $srvip) {
1692
		unset($destif);
1693
		foreach ($iflist as $ifname) {
1694
			$subnet = get_interface_ip($ifname);
1695
			if (!is_ipaddr($subnet)) {
1696
				continue;
1697
			}
1698
			$subnet .= "/" . get_interface_subnet($ifname);
1699
			if (ip_in_subnet($srvip, $subnet)) {
1700
				$destif = get_real_interface($ifname);
1701
				break;
1702
			}
1703
		}
1704
		if (!isset($destif)) {
1705
			foreach (get_staticroutes() as $rtent) {
1706
				if (ip_in_subnet($srvip, $rtent['network'])) {
1707
					$a_gateways = return_gateways_array(true);
1708
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1709
					break;
1710
				}
1711
			}
1712
		}
1713

    
1714
		if (!isset($destif)) {
1715
			/* Create a array from the existing route table */
1716
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1717
			array_shift($route_str);
1718
			array_shift($route_str);
1719
			array_shift($route_str);
1720
			array_shift($route_str);
1721
			$route_arr = array();
1722
			foreach ($route_str as $routeline) {
1723
				$items = preg_split("/[ ]+/i", $routeline);
1724
				if (is_subnetv4($items[0])) {
1725
					$subnet = $items[0];
1726
				} elseif (is_ipaddrv4($items[0])) {
1727
					$subnet = "{$items[0]}/32";
1728
				} else {
1729
					// Not a subnet or IP address, skip to the next line.
1730
					continue;
1731
				}
1732
				if (ip_in_subnet($srvip, $subnet)) {
1733
					$destif = trim($items[6]);
1734
					break;
1735
				}
1736
			}
1737
		}
1738

    
1739
		if (!isset($destif)) {
1740
			if (is_array($config['gateways']['gateway_item'])) {
1741
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1742
					if (isset($gateway['defaultgw'])) {
1743
						$destif = get_real_interface($gateway['interface']);
1744
						break;
1745
					}
1746
				}
1747
			} else {
1748
				$destif = get_real_interface("wan");
1749
			}
1750
		}
1751

    
1752
		if (!empty($destif)) {
1753
			$dhcrelayifs[] = $destif;
1754
		}
1755
	}
1756
	$dhcrelayifs = array_unique($dhcrelayifs);
1757

    
1758
	/* fire up dhcrelay */
1759
	if (empty($dhcrelayifs)) {
1760
		log_error(gettext("No suitable interface found for running dhcrelay!"));
1761
		return; /* XXX */
1762
	}
1763

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

    
1766
	if (isset($dhcrelaycfg['agentoption'])) {
1767
		$cmd .= " -a -m replace";
1768
	}
1769

    
1770
	$cmd .= " " . implode(" ", $srvips);
1771
	mwexec($cmd);
1772
	unset($cmd);
1773

    
1774
	return 0;
1775
}
1776

    
1777
function services_dhcrelay6_configure() {
1778
	global $config, $g;
1779

    
1780
	if (isset($config['system']['developerspew'])) {
1781
		$mt = microtime();
1782
		echo "services_dhcrelay6_configure() being called $mt\n";
1783
	}
1784

    
1785
	/* kill any running dhcrelay */
1786
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1787

    
1788
	$dhcrelaycfg =& $config['dhcrelay6'];
1789

    
1790
	/* DHCPv6 Relay enabled on any interfaces? */
1791
	if (!isset($dhcrelaycfg['enable'])) {
1792
		return 0;
1793
	}
1794

    
1795
	if (platform_booting()) {
1796
		echo gettext("Starting DHCPv6 relay service...");
1797
	} else {
1798
		sleep(1);
1799
	}
1800

    
1801
	$iflist = get_configured_interface_list();
1802

    
1803
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1804
	foreach ($dhcifaces as $dhcrelayif) {
1805
		if (!isset($iflist[$dhcrelayif]) ||
1806
		    link_interface_to_bridge($dhcrelayif)) {
1807
			continue;
1808
		}
1809

    
1810
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1811
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1812
		}
1813
	}
1814
	$dhcrelayifs = array_unique($dhcrelayifs);
1815

    
1816
	/*
1817
	 * In order for the relay to work, it needs to be active
1818
	 * on the interface in which the destination server sits.
1819
	 */
1820
	$srvips = explode(",", $dhcrelaycfg['server']);
1821
	$srvifaces = array();
1822
	foreach ($srvips as $srcidx => $srvip) {
1823
		unset($destif);
1824
		foreach ($iflist as $ifname) {
1825
			$subnet = get_interface_ipv6($ifname);
1826
			if (!is_ipaddrv6($subnet)) {
1827
				continue;
1828
			}
1829
			$subnet .= "/" . get_interface_subnetv6($ifname);
1830
			if (ip_in_subnet($srvip, $subnet)) {
1831
				$destif = get_real_interface($ifname);
1832
				break;
1833
			}
1834
		}
1835
		if (!isset($destif)) {
1836
			if (is_array($config['staticroutes']['route'])) {
1837
				foreach ($config['staticroutes']['route'] as $rtent) {
1838
					if (ip_in_subnet($srvip, $rtent['network'])) {
1839
						$a_gateways = return_gateways_array(true);
1840
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1841
						break;
1842
					}
1843
				}
1844
			}
1845
		}
1846

    
1847
		if (!isset($destif)) {
1848
			/* Create a array from the existing route table */
1849
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1850
			array_shift($route_str);
1851
			array_shift($route_str);
1852
			array_shift($route_str);
1853
			array_shift($route_str);
1854
			$route_arr = array();
1855
			foreach ($route_str as $routeline) {
1856
				$items = preg_split("/[ ]+/i", $routeline);
1857
				if (ip_in_subnet($srvip, $items[0])) {
1858
					$destif = trim($items[6]);
1859
					break;
1860
				}
1861
			}
1862
		}
1863

    
1864
		if (!isset($destif)) {
1865
			if (is_array($config['gateways']['gateway_item'])) {
1866
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1867
					if (isset($gateway['defaultgw'])) {
1868
						$destif = get_real_interface($gateway['interface']);
1869
						break;
1870
					}
1871
				}
1872
			} else {
1873
				$destif = get_real_interface("wan");
1874
			}
1875
		}
1876

    
1877
		if (!empty($destif)) {
1878
			$srvifaces[] = "{$srvip}%{$destif}";
1879
		}
1880
	}
1881

    
1882
	/* fire up dhcrelay */
1883
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1884
		log_error(gettext("No suitable interface found for running dhcrelay -6!"));
1885
		return; /* XXX */
1886
	}
1887

    
1888
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1889
	foreach ($dhcrelayifs as $dhcrelayif) {
1890
		$cmd .= " -l {$dhcrelayif}";
1891
	}
1892
	foreach ($srvifaces as $srviface) {
1893
		$cmd .= " -u \"{$srviface}\"";
1894
	}
1895
	mwexec($cmd);
1896
	unset($cmd);
1897

    
1898
	return 0;
1899
}
1900

    
1901
function services_dyndns_configure_client($conf) {
1902

    
1903
	if (!isset($conf['enable'])) {
1904
		return;
1905
	}
1906

    
1907
	/* load up the dyndns.class */
1908
	require_once("dyndns.class");
1909

    
1910
	$dns = new updatedns($dnsService = $conf['type'],
1911
		$dnsHost = $conf['host'],
1912
		$dnsDomain = $conf['domainname'],
1913
		$dnsUser = $conf['username'],
1914
		$dnsPass = $conf['password'],
1915
		$dnsWildcard = $conf['wildcard'],
1916
		$dnsMX = $conf['mx'],
1917
		$dnsIf = "{$conf['interface']}",
1918
		$dnsBackMX = NULL,
1919
		$dnsServer = NULL,
1920
		$dnsPort = NULL,
1921
		$dnsUpdateURL = "{$conf['updateurl']}",
1922
		$forceUpdate = $conf['force'],
1923
		$dnsZoneID = $conf['zoneid'],
1924
		$dnsTTL = $conf['ttl'],
1925
		$dnsResultMatch = "{$conf['resultmatch']}",
1926
		$dnsRequestIf = "{$conf['requestif']}",
1927
		$dnsID = "{$conf['id']}",
1928
		$dnsVerboseLog = $conf['verboselog'],
1929
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1930
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1931
}
1932

    
1933
function services_dyndns_configure($int = "") {
1934
	global $config, $g;
1935
	if (isset($config['system']['developerspew'])) {
1936
		$mt = microtime();
1937
		echo "services_dyndns_configure() being called $mt\n";
1938
	}
1939

    
1940
	$dyndnscfg = $config['dyndnses']['dyndns'];
1941
	$gwgroups = return_gateway_groups_array();
1942
	if (is_array($dyndnscfg)) {
1943
		if (platform_booting()) {
1944
			echo gettext("Starting DynDNS clients...");
1945
		}
1946

    
1947
		foreach ($dyndnscfg as $dyndns) {
1948
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1949
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1950
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1951
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1952
				services_dyndns_configure_client($dyndns);
1953
				sleep(1);
1954
			}
1955
		}
1956

    
1957
		if (platform_booting()) {
1958
			echo gettext("done.") . "\n";
1959
		}
1960
	}
1961

    
1962
	return 0;
1963
}
1964

    
1965
function dyndnsCheckIP($int) {
1966
	global $config;
1967
	$ip_address = get_interface_ip($int);
1968
	if (is_private_ip($ip_address)) {
1969
		$gateways_status = return_gateways_status(true);
1970
		// If the gateway for this interface is down, then the external check cannot work.
1971
		// Avoid the long wait for the external check to timeout.
1972
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
1973
			return "down";
1974
		}
1975
		$hosttocheck = "http://checkip.dyndns.org";
1976
		$ip_ch = curl_init($hosttocheck);
1977
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1978
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1979
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
1980
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1981
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1982
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1983
		$ip_result_page = curl_exec($ip_ch);
1984
		curl_close($ip_ch);
1985
		$ip_result_decoded = urldecode($ip_result_page);
1986
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1987
		$ip_address = trim($matches[1]);
1988
	}
1989
	return $ip_address;
1990
}
1991

    
1992
function services_dnsmasq_configure($restart_dhcp = true) {
1993
	global $config, $g;
1994
	$return = 0;
1995

    
1996
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1997
	$standard_args = array(
1998
		"dns-forward-max" => "--dns-forward-max=5000",
1999
		"cache-size" => "--cache-size=10000",
2000
		"local-ttl" => "--local-ttl=1"
2001
	);
2002

    
2003

    
2004
	if (isset($config['system']['developerspew'])) {
2005
		$mt = microtime();
2006
		echo "services_dnsmasq_configure() being called $mt\n";
2007
	}
2008

    
2009
	/* kill any running dnsmasq */
2010
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
2011
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
2012
	}
2013

    
2014
	if (isset($config['dnsmasq']['enable'])) {
2015

    
2016
		if (platform_booting()) {
2017
			echo gettext("Starting DNS forwarder...");
2018
		} else {
2019
			sleep(1);
2020
		}
2021

    
2022
		/* generate hosts file */
2023
		if (system_hosts_generate() != 0) {
2024
			$return = 1;
2025
		}
2026

    
2027
		$args = "";
2028

    
2029
		if (isset($config['dnsmasq']['regdhcp'])) {
2030
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
2031
		}
2032

    
2033
		/* Setup listen port, if non-default */
2034
		if (is_port($config['dnsmasq']['port'])) {
2035
			$args .= " --port={$config['dnsmasq']['port']} ";
2036
		}
2037

    
2038
		$listen_addresses = "";
2039
		if (isset($config['dnsmasq']['interface'])) {
2040
			$interfaces = explode(",", $config['dnsmasq']['interface']);
2041
			foreach ($interfaces as $interface) {
2042
				$if = get_real_interface($interface);
2043
				if (does_interface_exist($if)) {
2044
					$laddr = get_interface_ip($interface);
2045
					if (is_ipaddrv4($laddr)) {
2046
						$listen_addresses .= " --listen-address={$laddr} ";
2047
					}
2048
					$laddr6 = get_interface_ipv6($interface);
2049
					if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
2050
						/*
2051
						 * XXX: Since dnsmasq does not support link-local address
2052
						 * with scope specified. These checks are being done.
2053
						 */
2054
						if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
2055
							$tmpaddrll6 = explode("%", $laddr6);
2056
							$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2057
						} else {
2058
							$listen_addresses .= " --listen-address={$laddr6} ";
2059
						}
2060
					}
2061
				}
2062
			}
2063
			if (!empty($listen_addresses)) {
2064
				$args .= " {$listen_addresses} ";
2065
				if (isset($config['dnsmasq']['strictbind'])) {
2066
					$args .= " --bind-interfaces ";
2067
				}
2068
			}
2069
		}
2070

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

    
2078
			// Build an array of domain overrides to help in checking for matches.
2079
			$override_a = array();
2080
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2081
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2082
					$override_a[$override['domain']] = "y";
2083
				}
2084
			}
2085

    
2086
			// Build an array of the private reverse lookup domain names
2087
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
2088
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
2089
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
2090
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
2091
			}
2092

    
2093
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
2094
			foreach ($reverse_domain_a as $reverse_domain) {
2095
				if (!isset($override_a[$reverse_domain])) {
2096
					$args .= " --server=/$reverse_domain/ ";
2097
				}
2098
			}
2099
			unset($override_a);
2100
			unset($reverse_domain_a);
2101
		}
2102

    
2103
		/* Setup forwarded domains */
2104
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2105
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2106
				if ($override['ip'] == "!") {
2107
					$override[ip] = "";
2108
				}
2109
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2110
			}
2111
		}
2112

    
2113
		/* Allow DNS Rebind for forwarded domains */
2114
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2115
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2116
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2117
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2118
				}
2119
			}
2120
		}
2121

    
2122
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2123
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2124
		}
2125

    
2126
		if (isset($config['dnsmasq']['strict_order'])) {
2127
			$args .= " --strict-order ";
2128
		}
2129

    
2130
		if (isset($config['dnsmasq']['domain_needed'])) {
2131
			$args .= " --domain-needed ";
2132
		}
2133

    
2134
		if ($config['dnsmasq']['custom_options']) {
2135
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2136
				$args .= " " . escapeshellarg("--{$c}");
2137
				$p = explode('=', $c);
2138
				if (array_key_exists($p[0], $standard_args)) {
2139
					unset($standard_args[$p[0]]);
2140
				}
2141
			}
2142
		}
2143
		$args .= ' ' . implode(' ', array_values($standard_args));
2144

    
2145
		/* run dnsmasq */
2146
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2147
		//log_error("dnsmasq command: {$cmd}");
2148
		mwexec_bg($cmd);
2149
		unset($args);
2150

    
2151
		system_dhcpleases_configure();
2152

    
2153
		if (platform_booting()) {
2154
			echo gettext("done.") . "\n";
2155
		}
2156
	}
2157

    
2158
	if (!platform_booting() && $restart_dhcp) {
2159
		if (services_dhcpd_configure() != 0) {
2160
			$return = 1;
2161
		}
2162
	}
2163

    
2164
	return $return;
2165
}
2166

    
2167
function services_unbound_configure($restart_dhcp = true) {
2168
	global $config, $g;
2169
	$return = 0;
2170

    
2171
	if (isset($config['system']['developerspew'])) {
2172
		$mt = microtime();
2173
		echo "services_unbound_configure() being called $mt\n";
2174
	}
2175

    
2176
	// kill any running Unbound instance
2177
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2178
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2179
	}
2180

    
2181
	if (isset($config['unbound']['enable'])) {
2182
		if (platform_booting()) {
2183
			echo gettext("Starting DNS Resolver...");
2184
		} else {
2185
			sleep(1);
2186
		}
2187

    
2188
		/* generate hosts file */
2189
		if (system_hosts_generate() != 0) {
2190
			$return = 1;
2191
		}
2192

    
2193
		require_once('/etc/inc/unbound.inc');
2194
		sync_unbound_service();
2195
		if (platform_booting()) {
2196
			echo gettext("done.") . "\n";
2197
		}
2198

    
2199
		system_dhcpleases_configure();
2200
	}
2201

    
2202
	if (!platform_booting() && $restart_dhcp) {
2203
		if (services_dhcpd_configure() != 0) {
2204
			$return = 1;
2205
		}
2206
	}
2207

    
2208
	return $return;
2209
}
2210

    
2211
function services_snmpd_configure() {
2212
	global $config, $g;
2213
	if (isset($config['system']['developerspew'])) {
2214
		$mt = microtime();
2215
		echo "services_snmpd_configure() being called $mt\n";
2216
	}
2217

    
2218
	/* kill any running snmpd */
2219
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2220
	sleep(2);
2221
	if (is_process_running("bsnmpd")) {
2222
		mwexec("/usr/bin/killall bsnmpd", true);
2223
	}
2224

    
2225
	if (isset($config['snmpd']['enable'])) {
2226

    
2227
		if (platform_booting()) {
2228
			echo gettext("Starting SNMP daemon... ");
2229
		}
2230

    
2231
		/* generate snmpd.conf */
2232
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2233
		if (!$fd) {
2234
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2235
			return 1;
2236
		}
2237

    
2238

    
2239
		$snmpdconf = <<<EOD
2240
location := "{$config['snmpd']['syslocation']}"
2241
contact := "{$config['snmpd']['syscontact']}"
2242
read := "{$config['snmpd']['rocommunity']}"
2243

    
2244
EOD;
2245

    
2246
/* No docs on what write strings do there so disable for now.
2247
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2248
			$snmpdconf .= <<<EOD
2249
# write string
2250
write := "{$config['snmpd']['rwcommunity']}"
2251

    
2252
EOD;
2253
		}
2254
*/
2255

    
2256

    
2257
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2258
			$snmpdconf .= <<<EOD
2259
# SNMP Trap support.
2260
traphost := {$config['snmpd']['trapserver']}
2261
trapport := {$config['snmpd']['trapserverport']}
2262
trap := "{$config['snmpd']['trapstring']}"
2263

    
2264

    
2265
EOD;
2266
		}
2267

    
2268
		$platform = trim(file_get_contents('/etc/platform'));
2269
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2270
			$platform = $g['product_name'];
2271
		}
2272
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2273
			" {$g['product_version']} {$platform} " . php_uname("s") .
2274
			" " . php_uname("r") . " " . php_uname("m");
2275

    
2276
		$snmpdconf .= <<<EOD
2277
system := 1     # pfSense
2278
%snmpd
2279
sysDescr			= "{$sysDescr}"
2280
begemotSnmpdDebugDumpPdus       = 2
2281
begemotSnmpdDebugSyslogPri      = 7
2282
begemotSnmpdCommunityString.0.1 = $(read)
2283

    
2284
EOD;
2285

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

    
2291
EOD;
2292
		}
2293
*/
2294

    
2295

    
2296
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2297
			$snmpdconf .= <<<EOD
2298
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2299
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2300
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2301

    
2302
EOD;
2303
		}
2304

    
2305

    
2306
		$snmpdconf .= <<<EOD
2307
begemotSnmpdCommunityDisable    = 1
2308

    
2309
EOD;
2310

    
2311
		$bind_to_ip = "0.0.0.0";
2312
		if (isset($config['snmpd']['bindip'])) {
2313
			if (is_ipaddr($config['snmpd']['bindip'])) {
2314
				$bind_to_ip = $config['snmpd']['bindip'];
2315
			} else {
2316
				$if = get_real_interface($config['snmpd']['bindip']);
2317
				if (does_interface_exist($if)) {
2318
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2319
				}
2320
			}
2321
		}
2322

    
2323
		if (is_port($config['snmpd']['pollport'])) {
2324
			$snmpdconf .= <<<EOD
2325
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2326

    
2327
EOD;
2328

    
2329
		}
2330

    
2331
		$snmpdconf .= <<<EOD
2332
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2333
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2334

    
2335
# These are bsnmp macros not php vars.
2336
sysContact      = $(contact)
2337
sysLocation     = $(location)
2338
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2339

    
2340
snmpEnableAuthenTraps = 2
2341

    
2342
EOD;
2343

    
2344
		if (is_array($config['snmpd']['modules'])) {
2345
			if (isset($config['snmpd']['modules']['mibii'])) {
2346
			$snmpdconf .= <<<EOD
2347
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2348

    
2349
EOD;
2350
			}
2351

    
2352
			if (isset($config['snmpd']['modules']['netgraph'])) {
2353
				$snmpdconf .= <<<EOD
2354
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2355
%netgraph
2356
begemotNgControlNodeName = "snmpd"
2357

    
2358
EOD;
2359
			}
2360

    
2361
			if (isset($config['snmpd']['modules']['pf'])) {
2362
				$snmpdconf .= <<<EOD
2363
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2364

    
2365
EOD;
2366
			}
2367

    
2368
			if (isset($config['snmpd']['modules']['hostres'])) {
2369
				$snmpdconf .= <<<EOD
2370
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2371

    
2372
EOD;
2373
			}
2374

    
2375
			if (isset($config['snmpd']['modules']['bridge'])) {
2376
				$snmpdconf .= <<<EOD
2377
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2378
# config must end with blank line
2379

    
2380
EOD;
2381
			}
2382
			if (isset($config['snmpd']['modules']['ucd'])) {
2383
				$snmpdconf .= <<<EOD
2384
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2385

    
2386
EOD;
2387
			}
2388
			if (isset($config['snmpd']['modules']['regex'])) {
2389
				$snmpdconf .= <<<EOD
2390
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2391

    
2392
EOD;
2393
			}
2394
		}
2395

    
2396
		fwrite($fd, $snmpdconf);
2397
		fclose($fd);
2398
		unset($snmpdconf);
2399

    
2400
		/* run bsnmpd */
2401
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2402
			" -p {$g['varrun_path']}/snmpd.pid");
2403

    
2404
		if (platform_booting()) {
2405
			echo gettext("done.") . "\n";
2406
		}
2407
	}
2408

    
2409
	return 0;
2410
}
2411

    
2412
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2413
	global $config, $g;
2414
	if (isset($config['system']['developerspew'])) {
2415
		$mt = microtime();
2416
		echo "services_dnsupdate_process() being called $mt\n";
2417
	}
2418

    
2419
	/* Dynamic DNS updating active? */
2420
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2421
		$notify_text = "";
2422
		$gwgroups = return_gateway_groups_array();
2423
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2424
			if (!isset($dnsupdate['enable'])) {
2425
				continue;
2426
			}
2427
			if (!empty($int) && ($int != $dnsupdate['interface']) && (!is_array($gwgroups[$dnsupdate['interface']]))) {
2428
				continue;
2429
			}
2430
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2431
				continue;
2432
			}
2433

    
2434
			/* determine interface name */
2435
			$if = get_failover_interface($dnsupdate['interface']);
2436

    
2437
			if (isset($dnsupdate['usepublicip'])) {
2438
				$wanip = dyndnsCheckIP($if);
2439
			} else {
2440
				$wanip = get_interface_ip($if);
2441
			}
2442

    
2443
			$wanipv6 = get_interface_ipv6($if);
2444
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2445
			$currentTime = time();
2446

    
2447
			if ($wanip || $wanipv6) {
2448
				$keyname = $dnsupdate['keyname'];
2449
				/* trailing dot */
2450
				if (substr($keyname, -1) != ".") {
2451
					$keyname .= ".";
2452
				}
2453

    
2454
				$hostname = $dnsupdate['host'];
2455
				/* trailing dot */
2456
				if (substr($hostname, -1) != ".") {
2457
					$hostname .= ".";
2458
				}
2459

    
2460
				/* write private key file
2461
				   this is dumb - public and private keys are the same for HMAC-MD5,
2462
				   but nsupdate insists on having both */
2463
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2464
				$privkey = <<<EOD
2465
Private-key-format: v1.2
2466
Algorithm: 157 (HMAC)
2467
Key: {$dnsupdate['keydata']}
2468

    
2469
EOD;
2470
				fwrite($fd, $privkey);
2471
				fclose($fd);
2472

    
2473
				/* write public key file */
2474
				if ($dnsupdate['keytype'] == "zone") {
2475
					$flags = 257;
2476
					$proto = 3;
2477
				} else if ($dnsupdate['keytype'] == "host") {
2478
					$flags = 513;
2479
					$proto = 3;
2480
				} else if ($dnsupdate['keytype'] == "user") {
2481
					$flags = 0;
2482
					$proto = 2;
2483
				}
2484

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

    
2489
				/* generate update instructions */
2490
				$upinst = "";
2491
				if (!empty($dnsupdate['server'])) {
2492
					$upinst .= "server {$dnsupdate['server']}\n";
2493
				}
2494

    
2495
				if (file_exists($cacheFile)) {
2496
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2497
				}
2498
				if (file_exists("{$cacheFile}.ipv6")) {
2499
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2500
				}
2501

    
2502
				// 25 Days
2503
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2504
				$need_update = false;
2505

    
2506
				conf_mount_rw();
2507
				/* Update IPv4 if we have it. */
2508
				if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
2509
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2510
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2511
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2512
						$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";
2513
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2514
						log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $cacheFile, $wanip));
2515
						$need_update = true;
2516
					} else {
2517
						log_error(sprintf(gettext("phpDynDNS: Not updating %s A record because the IP address has not changed."), $dnsupdate['host']));
2518
					}
2519
				} else {
2520
					@unlink($cacheFile);
2521
				}
2522

    
2523
				/* Update IPv6 if we have it. */
2524
				if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
2525
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2526
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2527
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2528
						$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";
2529
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2530
						log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s.ipv6: %2$s'), $cacheFile, $wanipv6));
2531
						$need_update = true;
2532
					} else {
2533
						log_error(sprintf(gettext("phpDynDNS: Not updating %s AAAA record because the IPv6 address has not changed."), $dnsupdate['host']));
2534
					}
2535
				} else {
2536
					@unlink("{$cacheFile}.ipv6");
2537
				}
2538
				conf_mount_ro();
2539

    
2540
				$upinst .= "\n";	/* mind that trailing newline! */
2541

    
2542
				if ($need_update) {
2543
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2544
					unset($upinst);
2545
					/* invoke nsupdate */
2546
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2547
					if (isset($dnsupdate['usetcp'])) {
2548
						$cmd .= " -v";
2549
					}
2550
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2551
					mwexec_bg($cmd);
2552
					unset($cmd);
2553
				}
2554
			}
2555
		}
2556
		if (!empty($notify_text)) {
2557
			notify_all_remote($notify_text);
2558
		}
2559
	}
2560

    
2561
	return 0;
2562
}
2563

    
2564
/* configure cron service */
2565
function configure_cron() {
2566
	global $g, $config;
2567

    
2568
	conf_mount_rw();
2569
	/* preserve existing crontab entries */
2570
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2571

    
2572
	for ($i = 0; $i < count($crontab_contents); $i++) {
2573
		$cron_item =& $crontab_contents[$i];
2574
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2575
			array_splice($crontab_contents, $i - 1);
2576
			break;
2577
		}
2578
	}
2579
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2580

    
2581

    
2582
	if (is_array($config['cron']['item'])) {
2583
		$crontab_contents .= "#\n";
2584
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2585
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2586
		$crontab_contents .= "#\n";
2587

    
2588
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2589
			$http_proxy = $config['system']['proxyurl'];
2590
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2591
				$http_proxy .= ':' . $config['system']['proxyport'];
2592
			}
2593
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2594
		}
2595

    
2596
		foreach ($config['cron']['item'] as $item) {
2597
			$crontab_contents .= "\n{$item['minute']}\t";
2598
			$crontab_contents .= "{$item['hour']}\t";
2599
			$crontab_contents .= "{$item['mday']}\t";
2600
			$crontab_contents .= "{$item['month']}\t";
2601
			$crontab_contents .= "{$item['wday']}\t";
2602
			$crontab_contents .= "{$item['who']}\t";
2603
			$crontab_contents .= "{$item['command']}";
2604
		}
2605

    
2606
		$crontab_contents .= "\n#\n";
2607
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2608
		$crontab_contents .= "# " . gettext("If done so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2609
		$crontab_contents .= "#\n\n";
2610
	}
2611

    
2612
	/* please maintain the newline at the end of file */
2613
	file_put_contents("/etc/crontab", $crontab_contents);
2614
	unset($crontab_contents);
2615

    
2616
	/* make sure that cron is running and start it if it got killed somehow */
2617
	if (!is_process_running("cron")) {
2618
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2619
	} else {
2620
	/* do a HUP kill to force sync changes */
2621
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2622
	}
2623

    
2624
	conf_mount_ro();
2625
}
2626

    
2627
function upnp_action ($action) {
2628
	global $g, $config;
2629
	switch ($action) {
2630
		case "start":
2631
			if (file_exists('/var/etc/miniupnpd.conf')) {
2632
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2633
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2634
			}
2635
			break;
2636
		case "stop":
2637
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2638
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2639
				mwexec('/usr/bin/killall miniupnpd 2>/dev/null', true);
2640
			}
2641
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2642
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2643
			break;
2644
		case "restart":
2645
			upnp_action('stop');
2646
			upnp_action('start');
2647
			break;
2648
	}
2649
}
2650

    
2651
function upnp_start() {
2652
	global $config;
2653

    
2654
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2655
		return;
2656
	}
2657

    
2658
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2659
		echo gettext("Starting UPnP service... ");
2660
		require_once('/usr/local/pkg/miniupnpd.inc');
2661
		sync_package_miniupnpd();
2662
		echo "done.\n";
2663
	}
2664
}
2665

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

    
2669
	$is_installed = false;
2670
	$cron_changed = true;
2671

    
2672
	if (!is_array($config['cron'])) {
2673
		$config['cron'] = array();
2674
	}
2675
	if (!is_array($config['cron']['item'])) {
2676
		$config['cron']['item'] = array();
2677
	}
2678

    
2679
	$x = 0;
2680
	foreach ($config['cron']['item'] as $item) {
2681
		if (strstr($item['command'], $command)) {
2682
			$is_installed = true;
2683
			break;
2684
		}
2685
		$x++;
2686
	}
2687

    
2688
	if ($active) {
2689
		$cron_item = array();
2690
		$cron_item['minute'] = $minute;
2691
		$cron_item['hour'] = $hour;
2692
		$cron_item['mday'] = $monthday;
2693
		$cron_item['month'] = $month;
2694
		$cron_item['wday'] = $weekday;
2695
		$cron_item['who'] = $who;
2696
		$cron_item['command'] = $command;
2697
		if (!$is_installed) {
2698
			$config['cron']['item'][] = $cron_item;
2699
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2700
		} else {
2701
			if ($config['cron']['item'][$x] == $cron_item) {
2702
				$cron_changed = false;
2703
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2704
			} else {
2705
				$config['cron']['item'][$x] = $cron_item;
2706
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2707
			}
2708
		}
2709
	} else {
2710
		if ($is_installed == true) {
2711
			unset($config['cron']['item'][$x]);
2712
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2713
		}
2714
	}
2715

    
2716
	if ($cron_changed) {
2717
		configure_cron();
2718
	}
2719
}
2720

    
2721
?>
(49-49/65)