Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
108
		$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) && $ptr_domain !== "0") ? '' : '.');
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
	if (isset($config['syslog']['igmpxverbose'])) {
1638
		mwexec_bg("/usr/local/sbin/igmpproxy -v {$g['tmp_path']}/igmpproxy.conf");
1639
	} else {
1640
		mwexec_bg("/usr/local/sbin/igmpproxy {$g['tmp_path']}/igmpproxy.conf");
1641
	}
1642

    
1643
	log_error(gettext("Started IGMP proxy service."));
1644

    
1645
	return 0;
1646
}
1647

    
1648
function services_dhcrelay_configure() {
1649
	global $config, $g;
1650

    
1651
	if (isset($config['system']['developerspew'])) {
1652
		$mt = microtime();
1653
		echo "services_dhcrelay_configure() being called $mt\n";
1654
	}
1655

    
1656
	/* kill any running dhcrelay */
1657
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1658

    
1659
	$dhcrelaycfg =& $config['dhcrelay'];
1660

    
1661
	/* DHCPRelay enabled on any interfaces? */
1662
	if (!isset($dhcrelaycfg['enable'])) {
1663
		return 0;
1664
	}
1665

    
1666
	if (platform_booting()) {
1667
		echo gettext("Starting DHCP relay service...");
1668
	} else {
1669
		sleep(1);
1670
	}
1671

    
1672
	$iflist = get_configured_interface_list();
1673

    
1674
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1675
	foreach ($dhcifaces as $dhcrelayif) {
1676
		if (!isset($iflist[$dhcrelayif]) ||
1677
		    link_interface_to_bridge($dhcrelayif)) {
1678
			continue;
1679
		}
1680

    
1681
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1682
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1683
		}
1684
	}
1685

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

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

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

    
1744
		if (!isset($destif)) {
1745
			if (is_array($config['gateways']['gateway_item'])) {
1746
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1747
					if (isset($gateway['defaultgw'])) {
1748
						$destif = get_real_interface($gateway['interface']);
1749
						break;
1750
					}
1751
				}
1752
			} else {
1753
				$destif = get_real_interface("wan");
1754
			}
1755
		}
1756

    
1757
		if (!empty($destif)) {
1758
			$dhcrelayifs[] = $destif;
1759
		}
1760
	}
1761
	$dhcrelayifs = array_unique($dhcrelayifs);
1762

    
1763
	/* fire up dhcrelay */
1764
	if (empty($dhcrelayifs)) {
1765
		log_error(gettext("No suitable interface found for running dhcrelay!"));
1766
		return; /* XXX */
1767
	}
1768

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

    
1771
	if (isset($dhcrelaycfg['agentoption'])) {
1772
		$cmd .= " -a -m replace";
1773
	}
1774

    
1775
	$cmd .= " " . implode(" ", $srvips);
1776
	mwexec($cmd);
1777
	unset($cmd);
1778

    
1779
	return 0;
1780
}
1781

    
1782
function services_dhcrelay6_configure() {
1783
	global $config, $g;
1784

    
1785
	if (isset($config['system']['developerspew'])) {
1786
		$mt = microtime();
1787
		echo "services_dhcrelay6_configure() being called $mt\n";
1788
	}
1789

    
1790
	/* kill any running dhcrelay */
1791
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1792

    
1793
	$dhcrelaycfg =& $config['dhcrelay6'];
1794

    
1795
	/* DHCPv6 Relay enabled on any interfaces? */
1796
	if (!isset($dhcrelaycfg['enable'])) {
1797
		return 0;
1798
	}
1799

    
1800
	if (platform_booting()) {
1801
		echo gettext("Starting DHCPv6 relay service...");
1802
	} else {
1803
		sleep(1);
1804
	}
1805

    
1806
	$iflist = get_configured_interface_list();
1807

    
1808
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1809
	foreach ($dhcifaces as $dhcrelayif) {
1810
		if (!isset($iflist[$dhcrelayif]) ||
1811
		    link_interface_to_bridge($dhcrelayif)) {
1812
			continue;
1813
		}
1814

    
1815
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1816
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1817
		}
1818
	}
1819
	$dhcrelayifs = array_unique($dhcrelayifs);
1820

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

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

    
1869
		if (!isset($destif)) {
1870
			if (is_array($config['gateways']['gateway_item'])) {
1871
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1872
					if (isset($gateway['defaultgw'])) {
1873
						$destif = get_real_interface($gateway['interface']);
1874
						break;
1875
					}
1876
				}
1877
			} else {
1878
				$destif = get_real_interface("wan");
1879
			}
1880
		}
1881

    
1882
		if (!empty($destif)) {
1883
			$srvifaces[] = "{$srvip}%{$destif}";
1884
		}
1885
	}
1886

    
1887
	/* fire up dhcrelay */
1888
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1889
		log_error(gettext("No suitable interface found for running dhcrelay -6!"));
1890
		return; /* XXX */
1891
	}
1892

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

    
1903
	return 0;
1904
}
1905

    
1906
function services_dyndns_configure_client($conf) {
1907

    
1908
	if (!isset($conf['enable'])) {
1909
		return;
1910
	}
1911

    
1912
	/* load up the dyndns.class */
1913
	require_once("dyndns.class");
1914

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

    
1938
function services_dyndns_configure($int = "") {
1939
	global $config, $g;
1940
	if (isset($config['system']['developerspew'])) {
1941
		$mt = microtime();
1942
		echo "services_dyndns_configure() being called $mt\n";
1943
	}
1944

    
1945
	$dyndnscfg = $config['dyndnses']['dyndns'];
1946
	$gwgroups = return_gateway_groups_array();
1947
	if (is_array($dyndnscfg)) {
1948
		if (platform_booting()) {
1949
			echo gettext("Starting DynDNS clients...");
1950
		}
1951

    
1952
		foreach ($dyndnscfg as $dyndns) {
1953
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1954
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1955
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1956
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1957
				services_dyndns_configure_client($dyndns);
1958
				sleep(1);
1959
			}
1960
		}
1961

    
1962
		if (platform_booting()) {
1963
			echo gettext("done.") . "\n";
1964
		}
1965
	}
1966

    
1967
	return 0;
1968
}
1969

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

    
1997
function services_dnsmasq_configure($restart_dhcp = true) {
1998
	global $config, $g;
1999
	$return = 0;
2000

    
2001
	// hard coded args: will be removed to avoid duplication if specified in custom_options
2002
	$standard_args = array(
2003
		"dns-forward-max" => "--dns-forward-max=5000",
2004
		"cache-size" => "--cache-size=10000",
2005
		"local-ttl" => "--local-ttl=1"
2006
	);
2007

    
2008

    
2009
	if (isset($config['system']['developerspew'])) {
2010
		$mt = microtime();
2011
		echo "services_dnsmasq_configure() being called $mt\n";
2012
	}
2013

    
2014
	/* kill any running dnsmasq */
2015
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
2016
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
2017
	}
2018

    
2019
	if (isset($config['dnsmasq']['enable'])) {
2020

    
2021
		if (platform_booting()) {
2022
			echo gettext("Starting DNS forwarder...");
2023
		} else {
2024
			sleep(1);
2025
		}
2026

    
2027
		/* generate hosts file */
2028
		if (system_hosts_generate() != 0) {
2029
			$return = 1;
2030
		}
2031

    
2032
		$args = "";
2033

    
2034
		if (isset($config['dnsmasq']['regdhcp'])) {
2035
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
2036
		}
2037

    
2038
		/* Setup listen port, if non-default */
2039
		if (is_port($config['dnsmasq']['port'])) {
2040
			$args .= " --port={$config['dnsmasq']['port']} ";
2041
		}
2042

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

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

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

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

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

    
2108
		/* Setup forwarded domains */
2109
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2110
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2111
				if ($override['ip'] == "!") {
2112
					$override[ip] = "";
2113
				}
2114
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2115
			}
2116
		}
2117

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

    
2127
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2128
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2129
		}
2130

    
2131
		if (isset($config['dnsmasq']['strict_order'])) {
2132
			$args .= " --strict-order ";
2133
		}
2134

    
2135
		if (isset($config['dnsmasq']['domain_needed'])) {
2136
			$args .= " --domain-needed ";
2137
		}
2138

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

    
2150
		/* run dnsmasq */
2151
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2152
		//log_error("dnsmasq command: {$cmd}");
2153
		mwexec_bg($cmd);
2154
		unset($args);
2155

    
2156
		system_dhcpleases_configure();
2157

    
2158
		if (platform_booting()) {
2159
			echo gettext("done.") . "\n";
2160
		}
2161
	}
2162

    
2163
	if (!platform_booting() && $restart_dhcp) {
2164
		if (services_dhcpd_configure() != 0) {
2165
			$return = 1;
2166
		}
2167
	}
2168

    
2169
	return $return;
2170
}
2171

    
2172
function services_unbound_configure($restart_dhcp = true) {
2173
	global $config, $g;
2174
	$return = 0;
2175

    
2176
	if (isset($config['system']['developerspew'])) {
2177
		$mt = microtime();
2178
		echo "services_unbound_configure() being called $mt\n";
2179
	}
2180

    
2181
	// kill any running Unbound instance
2182
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2183
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2184
	}
2185

    
2186
	if (isset($config['unbound']['enable'])) {
2187
		if (platform_booting()) {
2188
			echo gettext("Starting DNS Resolver...");
2189
		} else {
2190
			sleep(1);
2191
		}
2192

    
2193
		/* generate hosts file */
2194
		if (system_hosts_generate() != 0) {
2195
			$return = 1;
2196
		}
2197

    
2198
		require_once('/etc/inc/unbound.inc');
2199
		sync_unbound_service();
2200
		if (platform_booting()) {
2201
			echo gettext("done.") . "\n";
2202
		}
2203

    
2204
		system_dhcpleases_configure();
2205
	}
2206

    
2207
	if (!platform_booting() && $restart_dhcp) {
2208
		if (services_dhcpd_configure() != 0) {
2209
			$return = 1;
2210
		}
2211
	}
2212

    
2213
	return $return;
2214
}
2215

    
2216
function services_snmpd_configure() {
2217
	global $config, $g;
2218
	if (isset($config['system']['developerspew'])) {
2219
		$mt = microtime();
2220
		echo "services_snmpd_configure() being called $mt\n";
2221
	}
2222

    
2223
	/* kill any running snmpd */
2224
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2225
	sleep(2);
2226
	if (is_process_running("bsnmpd")) {
2227
		mwexec("/usr/bin/killall bsnmpd", true);
2228
	}
2229

    
2230
	if (isset($config['snmpd']['enable'])) {
2231

    
2232
		if (platform_booting()) {
2233
			echo gettext("Starting SNMP daemon... ");
2234
		}
2235

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

    
2243

    
2244
		$snmpdconf = <<<EOD
2245
location := "{$config['snmpd']['syslocation']}"
2246
contact := "{$config['snmpd']['syscontact']}"
2247
read := "{$config['snmpd']['rocommunity']}"
2248

    
2249
EOD;
2250

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

    
2257
EOD;
2258
		}
2259
*/
2260

    
2261

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

    
2269

    
2270
EOD;
2271
		}
2272

    
2273
		$platform = trim(file_get_contents('/etc/platform'));
2274
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2275
			$platform = $g['product_name'];
2276
		}
2277
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2278
			" {$g['product_version']} {$platform} " . php_uname("s") .
2279
			" " . php_uname("r") . " " . php_uname("m");
2280

    
2281
		$snmpdconf .= <<<EOD
2282
system := 1     # pfSense
2283
%snmpd
2284
sysDescr			= "{$sysDescr}"
2285
begemotSnmpdDebugDumpPdus       = 2
2286
begemotSnmpdDebugSyslogPri      = 7
2287
begemotSnmpdCommunityString.0.1 = $(read)
2288

    
2289
EOD;
2290

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

    
2296
EOD;
2297
		}
2298
*/
2299

    
2300

    
2301
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2302
			$snmpdconf .= <<<EOD
2303
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2304
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2305
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2306

    
2307
EOD;
2308
		}
2309

    
2310

    
2311
		$snmpdconf .= <<<EOD
2312
begemotSnmpdCommunityDisable    = 1
2313

    
2314
EOD;
2315

    
2316
		$bind_to_ip = "0.0.0.0";
2317
		if (isset($config['snmpd']['bindip'])) {
2318
			if (is_ipaddr($config['snmpd']['bindip'])) {
2319
				$bind_to_ip = $config['snmpd']['bindip'];
2320
			} else {
2321
				$if = get_real_interface($config['snmpd']['bindip']);
2322
				if (does_interface_exist($if)) {
2323
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2324
				}
2325
			}
2326
		}
2327

    
2328
		if (is_port($config['snmpd']['pollport'])) {
2329
			$snmpdconf .= <<<EOD
2330
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2331

    
2332
EOD;
2333

    
2334
		}
2335

    
2336
		$snmpdconf .= <<<EOD
2337
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2338
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2339

    
2340
# These are bsnmp macros not php vars.
2341
sysContact      = $(contact)
2342
sysLocation     = $(location)
2343
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2344

    
2345
snmpEnableAuthenTraps = 2
2346

    
2347
EOD;
2348

    
2349
		if (is_array($config['snmpd']['modules'])) {
2350
			if (isset($config['snmpd']['modules']['mibii'])) {
2351
			$snmpdconf .= <<<EOD
2352
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2353

    
2354
EOD;
2355
			}
2356

    
2357
			if (isset($config['snmpd']['modules']['netgraph'])) {
2358
				$snmpdconf .= <<<EOD
2359
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2360
%netgraph
2361
begemotNgControlNodeName = "snmpd"
2362

    
2363
EOD;
2364
			}
2365

    
2366
			if (isset($config['snmpd']['modules']['pf'])) {
2367
				$snmpdconf .= <<<EOD
2368
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2369

    
2370
EOD;
2371
			}
2372

    
2373
			if (isset($config['snmpd']['modules']['hostres'])) {
2374
				$snmpdconf .= <<<EOD
2375
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2376

    
2377
EOD;
2378
			}
2379

    
2380
			if (isset($config['snmpd']['modules']['bridge'])) {
2381
				$snmpdconf .= <<<EOD
2382
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2383
# config must end with blank line
2384

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

    
2391
EOD;
2392
			}
2393
			if (isset($config['snmpd']['modules']['regex'])) {
2394
				$snmpdconf .= <<<EOD
2395
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2396

    
2397
EOD;
2398
			}
2399
		}
2400

    
2401
		fwrite($fd, $snmpdconf);
2402
		fclose($fd);
2403
		unset($snmpdconf);
2404

    
2405
		/* run bsnmpd */
2406
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2407
			" -p {$g['varrun_path']}/snmpd.pid");
2408

    
2409
		if (platform_booting()) {
2410
			echo gettext("done.") . "\n";
2411
		}
2412
	}
2413

    
2414
	return 0;
2415
}
2416

    
2417
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2418
	global $config, $g;
2419
	if (isset($config['system']['developerspew'])) {
2420
		$mt = microtime();
2421
		echo "services_dnsupdate_process() being called $mt\n";
2422
	}
2423

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

    
2439
			/* determine interface name */
2440
			$if = get_failover_interface($dnsupdate['interface']);
2441

    
2442
			if (isset($dnsupdate['usepublicip'])) {
2443
				$wanip = dyndnsCheckIP($if);
2444
			} else {
2445
				$wanip = get_interface_ip($if);
2446
			}
2447

    
2448
			$wanipv6 = get_interface_ipv6($if);
2449
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2450
			$currentTime = time();
2451

    
2452
			if ($wanip || $wanipv6) {
2453
				$keyname = $dnsupdate['keyname'];
2454
				/* trailing dot */
2455
				if (substr($keyname, -1) != ".") {
2456
					$keyname .= ".";
2457
				}
2458

    
2459
				$hostname = $dnsupdate['host'];
2460
				/* trailing dot */
2461
				if (substr($hostname, -1) != ".") {
2462
					$hostname .= ".";
2463
				}
2464

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

    
2474
EOD;
2475
				fwrite($fd, $privkey);
2476
				fclose($fd);
2477

    
2478
				/* write public key file */
2479
				if ($dnsupdate['keytype'] == "zone") {
2480
					$flags = 257;
2481
					$proto = 3;
2482
				} else if ($dnsupdate['keytype'] == "host") {
2483
					$flags = 513;
2484
					$proto = 3;
2485
				} else if ($dnsupdate['keytype'] == "user") {
2486
					$flags = 0;
2487
					$proto = 2;
2488
				}
2489

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

    
2494
				/* generate update instructions */
2495
				$upinst = "";
2496
				if (!empty($dnsupdate['server'])) {
2497
					$upinst .= "server {$dnsupdate['server']}\n";
2498
				}
2499

    
2500
				if (file_exists($cacheFile)) {
2501
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2502
				}
2503
				if (file_exists("{$cacheFile}.ipv6")) {
2504
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2505
				}
2506

    
2507
				// 25 Days
2508
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2509
				$need_update = false;
2510

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

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

    
2545
				$upinst .= "\n";	/* mind that trailing newline! */
2546

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

    
2566
	return 0;
2567
}
2568

    
2569
/* configure cron service */
2570
function configure_cron() {
2571
	global $g, $config;
2572

    
2573
	conf_mount_rw();
2574
	/* preserve existing crontab entries */
2575
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2576

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

    
2586

    
2587
	if (is_array($config['cron']['item'])) {
2588
		$crontab_contents .= "#\n";
2589
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2590
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2591
		$crontab_contents .= "#\n";
2592

    
2593
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2594
			$http_proxy = $config['system']['proxyurl'];
2595
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2596
				$http_proxy .= ':' . $config['system']['proxyport'];
2597
			}
2598
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2599
		}
2600

    
2601
		foreach ($config['cron']['item'] as $item) {
2602
			$crontab_contents .= "\n{$item['minute']}\t";
2603
			$crontab_contents .= "{$item['hour']}\t";
2604
			$crontab_contents .= "{$item['mday']}\t";
2605
			$crontab_contents .= "{$item['month']}\t";
2606
			$crontab_contents .= "{$item['wday']}\t";
2607
			$crontab_contents .= "{$item['who']}\t";
2608
			$crontab_contents .= "{$item['command']}";
2609
		}
2610

    
2611
		$crontab_contents .= "\n#\n";
2612
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2613
		$crontab_contents .= "# " . gettext("If done so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2614
		$crontab_contents .= "#\n\n";
2615
	}
2616

    
2617
	/* please maintain the newline at the end of file */
2618
	file_put_contents("/etc/crontab", $crontab_contents);
2619
	unset($crontab_contents);
2620

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

    
2629
	conf_mount_ro();
2630
}
2631

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

    
2656
function upnp_start() {
2657
	global $config;
2658

    
2659
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2660
		return;
2661
	}
2662

    
2663
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2664
		echo gettext("Starting UPnP service... ");
2665
		require_once('/usr/local/pkg/miniupnpd.inc');
2666
		sync_package_miniupnpd();
2667
		echo "done.\n";
2668
	}
2669
}
2670

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

    
2674
	$is_installed = false;
2675
	$cron_changed = true;
2676

    
2677
	if (!is_array($config['cron'])) {
2678
		$config['cron'] = array();
2679
	}
2680
	if (!is_array($config['cron']['item'])) {
2681
		$config['cron']['item'] = array();
2682
	}
2683

    
2684
	$x = 0;
2685
	foreach ($config['cron']['item'] as $item) {
2686
		if (strstr($item['command'], $command)) {
2687
			$is_installed = true;
2688
			break;
2689
		}
2690
		$x++;
2691
	}
2692

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

    
2721
	if ($cron_changed) {
2722
		configure_cron();
2723
	}
2724
}
2725

    
2726
?>
(49-49/65)