Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
511
	$dhcpdconf = <<<EOD
512

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

    
526
EOD;
527

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

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

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

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

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

    
557
		interfaces_staticarp_configure($dhcpif);
558

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

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

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

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

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

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

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

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

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

    
646
		$dnscfg = "";
647

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

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

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

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

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

    
685
			}
686

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

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

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

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

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

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

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

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

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

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

    
826
			$pdnscfg = "";
827

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
983
EOD;
984

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

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

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

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

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

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

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

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

    
1021
				$smdnscfg = "";
1022

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1120
	return 0;
1121
}
1122

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

    
1132
	return $dhcpdconf;
1133
}
1134

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

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

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

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

    
1185
	return $dhcpdconf;
1186
}
1187

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

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

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

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

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

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

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

    
1236

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

    
1243
	/*
1244
	 * We add a fake entry for interfaces that are set to track6
1245
	 * another WAN unless DHCP has been configured
1246
	 */
1247
	foreach ($Iflist as $ifname) {
1248
		/* Do not put in the config an interface which is down */
1249
		if (isset($blacklist[$ifname])) {
1250
			continue;
1251
		}
1252
		if (!empty($config['interfaces'][$ifname]['track6-interface']) && isset($dhcpdv6cfg[$ifname]['enable'])) {
1253
			$realif = get_real_interface($ifname, "inet6");
1254
			$ifcfgipv6 = get_interface_ipv6($ifname);
1255
			if (!is_ipaddrv6($ifcfgipv6)) {
1256
				continue;
1257
			}
1258
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1259
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1260
			$trackcfg = $config['interfaces'][$trackifname];
1261
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1262
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1263
			$dhcpdv6cfg[$ifname] = array();
1264
			$dhcpdv6cfg[$ifname]['enable'] = true;
1265
			/* range */
1266
			$ifcfgipv6arr[7] = "1000";
1267
			$dhcpdv6cfg[$ifname]['range'] = array();
1268
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1269
			$ifcfgipv6arr[7] = "2000";
1270
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1271
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1272
			if ($pdlen > 2) {
1273
				$pdlenmax = $pdlen;
1274
				$pdlenhalf = $pdlenmax -1;
1275
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1276
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1277
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1278

    
1279
				/* set the delegation start to half the current address block */
1280
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1281
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1282

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

    
1287
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1288
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1289
			}
1290
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1291
		}
1292
	}
1293

    
1294
	$custoptionsv6 = "";
1295
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1296
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1297
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1298
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1299
			}
1300
		}
1301
	}
1302

    
1303
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1304
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1305
	}
1306

    
1307
	$dhcpdv6conf = <<<EOD
1308

    
1309
option domain-name "{$syscfg['domain']}";
1310
option ldap-server code 95 = text;
1311
option domain-search-list code 119 = text;
1312
{$custoptionsv6}
1313
default-lease-time 7200;
1314
max-lease-time 86400;
1315
log-facility local7;
1316
one-lease-per-client true;
1317
deny duplicates;
1318
ping-check true;
1319
update-conflict-detection false;
1320

    
1321
EOD;
1322

    
1323
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1324
		$dhcpdv6conf .= "authoritative;\n";
1325
	}
1326

    
1327
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1328
		$dhcpdv6conf .= "always-broadcast on\n";
1329
	}
1330

    
1331
	$dhcpdv6ifs = array();
1332

    
1333
	$dhcpv6num = 0;
1334
	$nsupdate = false;
1335

    
1336
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1337

    
1338
		$ddns_zones = array();
1339

    
1340
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1341

    
1342
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1343
			continue;
1344
		}
1345
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1346
		if (!is_ipaddrv6($ifcfgipv6)) {
1347
			continue;
1348
		}
1349
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1350
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1351

    
1352
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1353
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1354
			$trackcfg = $config['interfaces'][$trackifname];
1355
			$pdlen = 64 - $trackcfg['dhcp6-ia-pd-len'];
1356
		}
1357

    
1358
		if ($is_olsr_enabled == true) {
1359
			if ($dhcpv6ifconf['netmask']) {
1360
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1361
			}
1362
		}
1363

    
1364
		$dnscfgv6 = "";
1365

    
1366
		if ($dhcpv6ifconf['domain']) {
1367
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1368
		}
1369

    
1370
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1371
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1372
		}
1373

    
1374
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1375
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1376
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1377
			}
1378
			if (empty($dhcpv6ifconf['ddnsclientupdates'])) {
1379
				$ddnsclientupdates = 'allow';
1380
			} else {
1381
				$ddnsclientupdates = $dhcpv6ifconf['ddnsclientupdates'];
1382
			}
1383
			$dnscfgv6 .= "	{$ddnsclientupdates} client-updates;\n";
1384
			$nsupdate = true;
1385
		} else {
1386
			$dnscfgv6 .= "	do-forward-updates false;\n";
1387
		}
1388

    
1389
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1390
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1391
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1392
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1393
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1394
			$dns_arrv6 = array();
1395
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1396
				if (is_ipaddrv6($dnsserver)) {
1397
					$dns_arrv6[] = $dnsserver;
1398
				}
1399
			}
1400
			if (!empty($dns_arrv6)) {
1401
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1402
			}
1403
		}
1404

    
1405
		if (!is_ipaddrv6($ifcfgipv6)) {
1406
			$ifcfgsnv6 = "64";
1407
			$subnetv6 = gen_subnetv6($dhcpv6ifconf['range']['from'], $ifcfgsnv6);
1408
		}
1409

    
1410
		$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1411

    
1412
		if (isset($dhcpv6ifconf['ddnsupdate']) &&
1413
		    !empty($dhcpv6ifconf['ddnsdomain'])) {
1414
			$newzone = array();
1415
			$newzone['domain-name'] = $dhcpv6ifconf['ddnsdomain'];
1416
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1417
			$newzone['ddnsdomainkeyname'] = $dhcpv6ifconf['ddnsdomainkeyname'];
1418
			$newzone['ddnsdomainkey'] = $dhcpv6ifconf['ddnsdomainkey'];
1419
			$ddns_zones[] = $newzone;
1420
			if (isset($dhcpv6ifconf['ddnsreverse'])) {
1421
				$ptr_zones = get_v6_ptr_zones($subnetv6, $ifcfgsnv6);
1422
				foreach ($ptr_zones as $ptr_zone) {
1423
					$reversezone = array();
1424
					$reversezone['domain-name'] = $ptr_zone;
1425
					$reversezone['dns-servers'][] =
1426
					    $dhcpv6ifconf['ddnsdomainprimary'];
1427
					$ddns_zones[] = $reversezone;
1428
				}
1429
			}
1430
		}
1431

    
1432
		$dhcpdv6conf .= " {\n";
1433

    
1434
		$range_from = $dhcpv6ifconf['range']['from'];
1435
		$range_to = $dhcpv6ifconf['range']['to'];
1436
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1437
			$range_from = merge_ipv6_delegated_prefix($ifcfgipv6, $range_from, $pdlen);
1438
			$range_to = merge_ipv6_delegated_prefix($ifcfgipv6, $range_to, $pdlen);
1439
		}
1440

    
1441
		$dhcpdv6conf .= <<<EOD
1442
	range6 {$range_from} {$range_to};
1443
$dnscfgv6
1444

    
1445
EOD;
1446

    
1447
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1448
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1449
		}
1450
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1451
			$dns6ip = $dhcpv6ifconf['dns6ip'];
1452
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1453
			    Net_IPv6::isInNetmask($dns6ip, '::', $pdlen)) {
1454
				$dns6ip = merge_ipv6_delegated_prefix($ifcfgipv6, $dns6ip, $pdlen);
1455
			}
1456
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dns6ip};\n";
1457
		}
1458
		// default-lease-time
1459
		if ($dhcpv6ifconf['defaultleasetime']) {
1460
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1461
		}
1462

    
1463
		// max-lease-time
1464
		if ($dhcpv6ifconf['maxleasetime']) {
1465
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1466
		}
1467

    
1468
		// ntp-servers
1469
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1470
			$ntpservers = array();
1471
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1472
				if (!is_ipaddrv6($ntpserver)) {
1473
					continue;
1474
				}
1475
				if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1476
				    Net_IPv6::isInNetmask($ntpserver, '::', $pdlen)) {
1477
					$ntpserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ntpserver, $pdlen);
1478
				}
1479
				$ntpservers[] = $ntpserver;
1480
			}
1481
			if (count($ntpservers) > 0) {
1482
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1483
			}
1484
		}
1485
		// tftp-server-name
1486
		/* Needs ISC DHCPD support
1487
		 if ($dhcpv6ifconf['tftp'] <> "") {
1488
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1489
		 }
1490
		*/
1491

    
1492
		// Handle option, number rowhelper values
1493
		$dhcpdv6conf .= "\n";
1494
		if ($dhcpv6ifconf['numberoptions']['item']) {
1495
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1496
				$itemv6_value = base64_decode($itemv6['value']);
1497
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6_value}\";\n";
1498
			}
1499
		}
1500

    
1501
		// ldap-server
1502
		if ($dhcpv6ifconf['ldap'] <> "") {
1503
			$ldapserver = $dhcpv6ifconf['ldap'];
1504
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1505
			    Net_IPv6::isInNetmask($ldapserver, '::', $pdlen)) {
1506
				$ldapserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ldapserver, $pdlen);
1507
			}
1508
			$dhcpdv6conf .= "	option ldap-server \"{$ldapserver}\";\n";
1509
		}
1510

    
1511
		// net boot information
1512
		if (isset($dhcpv6ifconf['netboot'])) {
1513
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1514
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1515
			}
1516
		}
1517

    
1518
		$dhcpdv6conf .= "}\n";
1519

    
1520
		/* add static mappings */
1521
		/* Needs to use DUID */
1522
		if (is_array($dhcpv6ifconf['staticmap'])) {
1523
			$i = 0;
1524
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1525
				$dhcpdv6conf .= <<<EOD
1526
host s_{$dhcpv6if}_{$i} {
1527
	host-identifier option dhcp6.client-id {$sm['duid']};
1528

    
1529
EOD;
1530
				if ($sm['ipaddrv6']) {
1531
					$ipaddrv6 = $sm['ipaddrv6'];
1532
					if ($ifcfgv6['ipaddrv6'] == 'track6') {
1533
						$ipaddrv6 = merge_ipv6_delegated_prefix($ifcfgipv6, $ipaddrv6, $pdlen);
1534
					}
1535
					$dhcpdv6conf .= "	fixed-address6 {$ipaddrv6};\n";
1536
				}
1537

    
1538
				if ($sm['hostname']) {
1539
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1540
					$dhhostname = str_replace(".", "_", $dhhostname);
1541
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1542
				}
1543
				if ($sm['filename']) {
1544
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1545
				}
1546

    
1547
				if ($sm['rootpath']) {
1548
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1549
				}
1550

    
1551
				$dhcpdv6conf .= "}\n";
1552
				$i++;
1553
			}
1554
		}
1555

    
1556
		if ($dhcpv6ifconf['ddnsdomain']) {
1557
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1558
			$dhcpdv6conf .= dhcpdzones($ddns_zones);
1559
		}
1560

    
1561
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1562
			if (preg_match("/poes/si", $dhcpv6if)) {
1563
				/* magic here */
1564
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1565
			} else {
1566
				$realif = get_real_interface($dhcpv6if, "inet6");
1567
				if (stristr("$realif", "bridge")) {
1568
					$mac = get_interface_mac($realif);
1569
					$v6address = generate_ipv6_from_mac($mac);
1570
					/* Create link local address for bridges */
1571
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1572
				}
1573
				$realif = escapeshellcmd($realif);
1574
				$dhcpdv6ifs[] = $realif;
1575
			}
1576
		}
1577
	}
1578

    
1579
	if ($nsupdate) {
1580
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1581
	} else {
1582
		$dhcpdv6conf .= "ddns-update-style none;\n";
1583
	}
1584

    
1585
	/* write dhcpdv6.conf */
1586
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1587
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1588
		if (platform_booting()) {
1589
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1590
		}
1591
		unset($dhcpdv6conf);
1592
		return 1;
1593
	}
1594
	unset($dhcpdv6conf);
1595

    
1596
	/* create an empty leases v6 database */
1597
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1598
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1599
	}
1600

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

    
1605
	/* fire up dhcpd in a chroot */
1606
	if (count($dhcpdv6ifs) > 0) {
1607
		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 " .
1608
			join(" ", $dhcpdv6ifs));
1609
		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");
1610
	}
1611
	if (platform_booting()) {
1612
		print gettext("done.") . "\n";
1613
	}
1614

    
1615
	return 0;
1616
}
1617

    
1618
function services_igmpproxy_configure() {
1619
	global $config, $g;
1620

    
1621
	/* kill any running igmpproxy */
1622
	killbyname("igmpproxy");
1623

    
1624
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1625
		return 1;
1626
	}
1627

    
1628
	$iflist = get_configured_interface_list();
1629

    
1630
	$igmpconf = <<<EOD
1631

    
1632
##------------------------------------------------------
1633
## Enable Quickleave mode (Sends Leave instantly)
1634
##------------------------------------------------------
1635
quickleave
1636

    
1637
EOD;
1638

    
1639
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1640
		unset($iflist[$igmpcf['ifname']]);
1641
		$realif = get_real_interface($igmpcf['ifname']);
1642
		if (empty($igmpcf['threshold'])) {
1643
			$threshld = 1;
1644
		} else {
1645
			$threshld = $igmpcf['threshold'];
1646
		}
1647
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1648

    
1649
		if ($igmpcf['address'] <> "") {
1650
			$item = explode(" ", $igmpcf['address']);
1651
			foreach ($item as $iww) {
1652
				$igmpconf .= "altnet {$iww}\n";
1653
			}
1654
		}
1655
		$igmpconf .= "\n";
1656
	}
1657
	foreach ($iflist as $ifn) {
1658
		$realif = get_real_interface($ifn);
1659
		$igmpconf .= "phyint {$realif} disabled\n";
1660
	}
1661
	$igmpconf .= "\n";
1662

    
1663
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1664
	if (!$igmpfl) {
1665
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1666
		return;
1667
	}
1668
	fwrite($igmpfl, $igmpconf);
1669
	fclose($igmpfl);
1670
	unset($igmpconf);
1671

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

    
1675
	return 0;
1676
}
1677

    
1678
function services_dhcrelay_configure() {
1679
	global $config, $g;
1680

    
1681
	if (isset($config['system']['developerspew'])) {
1682
		$mt = microtime();
1683
		echo "services_dhcrelay_configure() being called $mt\n";
1684
	}
1685

    
1686
	/* kill any running dhcrelay */
1687
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1688

    
1689
	$dhcrelaycfg =& $config['dhcrelay'];
1690

    
1691
	/* DHCPRelay enabled on any interfaces? */
1692
	if (!isset($dhcrelaycfg['enable'])) {
1693
		return 0;
1694
	}
1695

    
1696
	if (platform_booting()) {
1697
		echo gettext("Starting DHCP relay service...");
1698
	} else {
1699
		sleep(1);
1700
	}
1701

    
1702
	$iflist = get_configured_interface_list();
1703

    
1704
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1705
	foreach ($dhcifaces as $dhcrelayif) {
1706
		if (!isset($iflist[$dhcrelayif]) ||
1707
		    link_interface_to_bridge($dhcrelayif)) {
1708
			continue;
1709
		}
1710

    
1711
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1712
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1713
		}
1714
	}
1715

    
1716
	/*
1717
	 * In order for the relay to work, it needs to be active
1718
	 * on the interface in which the destination server sits.
1719
	 */
1720
	$srvips = explode(",", $dhcrelaycfg['server']);
1721
	if (!is_array($srvips)) {
1722
		log_error(gettext("No destination IP has been configured!"));
1723
		return;
1724
	}
1725

    
1726
	foreach ($srvips as $srcidx => $srvip) {
1727
		unset($destif);
1728
		foreach ($iflist as $ifname) {
1729
			$subnet = get_interface_ip($ifname);
1730
			if (!is_ipaddr($subnet)) {
1731
				continue;
1732
			}
1733
			$subnet .= "/" . get_interface_subnet($ifname);
1734
			if (ip_in_subnet($srvip, $subnet)) {
1735
				$destif = get_real_interface($ifname);
1736
				break;
1737
			}
1738
		}
1739
		if (!isset($destif)) {
1740
			foreach (get_staticroutes() as $rtent) {
1741
				if (ip_in_subnet($srvip, $rtent['network'])) {
1742
					$a_gateways = return_gateways_array(true);
1743
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1744
					break;
1745
				}
1746
			}
1747
		}
1748

    
1749
		if (!isset($destif)) {
1750
			/* Create a array from the existing route table */
1751
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1752
			array_shift($route_str);
1753
			array_shift($route_str);
1754
			array_shift($route_str);
1755
			array_shift($route_str);
1756
			$route_arr = array();
1757
			foreach ($route_str as $routeline) {
1758
				$items = preg_split("/[ ]+/i", $routeline);
1759
				if (is_subnetv4($items[0])) {
1760
					$subnet = $items[0];
1761
				} elseif (is_ipaddrv4($items[0])) {
1762
					$subnet = "{$items[0]}/32";
1763
				} else {
1764
					// Not a subnet or IP address, skip to the next line.
1765
					continue;
1766
				}
1767
				if (ip_in_subnet($srvip, $subnet)) {
1768
					$destif = trim($items[6]);
1769
					break;
1770
				}
1771
			}
1772
		}
1773

    
1774
		if (!isset($destif)) {
1775
			if (is_array($config['gateways']['gateway_item'])) {
1776
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1777
					if (isset($gateway['defaultgw'])) {
1778
						$destif = get_real_interface($gateway['interface']);
1779
						break;
1780
					}
1781
				}
1782
			} else {
1783
				$destif = get_real_interface("wan");
1784
			}
1785
		}
1786

    
1787
		if (!empty($destif)) {
1788
			$dhcrelayifs[] = $destif;
1789
		}
1790
	}
1791
	$dhcrelayifs = array_unique($dhcrelayifs);
1792

    
1793
	/* fire up dhcrelay */
1794
	if (empty($dhcrelayifs)) {
1795
		log_error(gettext("No suitable interface found for running dhcrelay!"));
1796
		return; /* XXX */
1797
	}
1798

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

    
1801
	if (isset($dhcrelaycfg['agentoption'])) {
1802
		$cmd .= " -a -m replace";
1803
	}
1804

    
1805
	$cmd .= " " . implode(" ", $srvips);
1806
	mwexec($cmd);
1807
	unset($cmd);
1808

    
1809
	return 0;
1810
}
1811

    
1812
function services_dhcrelay6_configure() {
1813
	global $config, $g;
1814

    
1815
	if (isset($config['system']['developerspew'])) {
1816
		$mt = microtime();
1817
		echo "services_dhcrelay6_configure() being called $mt\n";
1818
	}
1819

    
1820
	/* kill any running dhcrelay */
1821
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1822

    
1823
	$dhcrelaycfg =& $config['dhcrelay6'];
1824

    
1825
	/* DHCPv6 Relay enabled on any interfaces? */
1826
	if (!isset($dhcrelaycfg['enable'])) {
1827
		return 0;
1828
	}
1829

    
1830
	if (platform_booting()) {
1831
		echo gettext("Starting DHCPv6 relay service...");
1832
	} else {
1833
		sleep(1);
1834
	}
1835

    
1836
	$iflist = get_configured_interface_list();
1837

    
1838
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1839
	foreach ($dhcifaces as $dhcrelayif) {
1840
		if (!isset($iflist[$dhcrelayif]) ||
1841
		    link_interface_to_bridge($dhcrelayif)) {
1842
			continue;
1843
		}
1844

    
1845
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1846
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1847
		}
1848
	}
1849
	$dhcrelayifs = array_unique($dhcrelayifs);
1850

    
1851
	/*
1852
	 * In order for the relay to work, it needs to be active
1853
	 * on the interface in which the destination server sits.
1854
	 */
1855
	$srvips = explode(",", $dhcrelaycfg['server']);
1856
	$srvifaces = array();
1857
	foreach ($srvips as $srcidx => $srvip) {
1858
		unset($destif);
1859
		foreach ($iflist as $ifname) {
1860
			$subnet = get_interface_ipv6($ifname);
1861
			if (!is_ipaddrv6($subnet)) {
1862
				continue;
1863
			}
1864
			$subnet .= "/" . get_interface_subnetv6($ifname);
1865
			if (ip_in_subnet($srvip, $subnet)) {
1866
				$destif = get_real_interface($ifname);
1867
				break;
1868
			}
1869
		}
1870
		if (!isset($destif)) {
1871
			if (is_array($config['staticroutes']['route'])) {
1872
				foreach ($config['staticroutes']['route'] as $rtent) {
1873
					if (ip_in_subnet($srvip, $rtent['network'])) {
1874
						$a_gateways = return_gateways_array(true);
1875
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1876
						break;
1877
					}
1878
				}
1879
			}
1880
		}
1881

    
1882
		if (!isset($destif)) {
1883
			/* Create a array from the existing route table */
1884
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1885
			array_shift($route_str);
1886
			array_shift($route_str);
1887
			array_shift($route_str);
1888
			array_shift($route_str);
1889
			$route_arr = array();
1890
			foreach ($route_str as $routeline) {
1891
				$items = preg_split("/[ ]+/i", $routeline);
1892
				if (ip_in_subnet($srvip, $items[0])) {
1893
					$destif = trim($items[6]);
1894
					break;
1895
				}
1896
			}
1897
		}
1898

    
1899
		if (!isset($destif)) {
1900
			if (is_array($config['gateways']['gateway_item'])) {
1901
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1902
					if (isset($gateway['defaultgw'])) {
1903
						$destif = get_real_interface($gateway['interface']);
1904
						break;
1905
					}
1906
				}
1907
			} else {
1908
				$destif = get_real_interface("wan");
1909
			}
1910
		}
1911

    
1912
		if (!empty($destif)) {
1913
			$srvifaces[] = "{$srvip}%{$destif}";
1914
		}
1915
	}
1916

    
1917
	/* fire up dhcrelay */
1918
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1919
		log_error(gettext("No suitable interface found for running dhcrelay -6!"));
1920
		return; /* XXX */
1921
	}
1922

    
1923
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1924
	foreach ($dhcrelayifs as $dhcrelayif) {
1925
		$cmd .= " -l {$dhcrelayif}";
1926
	}
1927
	foreach ($srvifaces as $srviface) {
1928
		$cmd .= " -u \"{$srviface}\"";
1929
	}
1930
	mwexec($cmd);
1931
	unset($cmd);
1932

    
1933
	return 0;
1934
}
1935

    
1936
function services_dyndns_configure_client($conf) {
1937

    
1938
	if (!isset($conf['enable'])) {
1939
		return;
1940
	}
1941

    
1942
	/* load up the dyndns.class */
1943
	require_once("dyndns.class");
1944

    
1945
	$dns = new updatedns($dnsService = $conf['type'],
1946
		$dnsHost = $conf['host'],
1947
		$dnsDomain = $conf['domainname'],
1948
		$dnsUser = $conf['username'],
1949
		$dnsPass = $conf['password'],
1950
		$dnsWildcard = $conf['wildcard'],
1951
		$dnsMX = $conf['mx'],
1952
		$dnsIf = "{$conf['interface']}",
1953
		$dnsBackMX = NULL,
1954
		$dnsServer = NULL,
1955
		$dnsPort = NULL,
1956
		$dnsUpdateURL = "{$conf['updateurl']}",
1957
		$forceUpdate = $conf['force'],
1958
		$dnsZoneID = $conf['zoneid'],
1959
		$dnsTTL = $conf['ttl'],
1960
		$dnsResultMatch = "{$conf['resultmatch']}",
1961
		$dnsRequestIf = "{$conf['requestif']}",
1962
		$dnsID = "{$conf['id']}",
1963
		$dnsVerboseLog = $conf['verboselog'],
1964
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1965
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1966
}
1967

    
1968
function services_dyndns_configure($int = "") {
1969
	global $config, $g;
1970
	if (isset($config['system']['developerspew'])) {
1971
		$mt = microtime();
1972
		echo "services_dyndns_configure() being called $mt\n";
1973
	}
1974

    
1975
	$dyndnscfg = $config['dyndnses']['dyndns'];
1976
	$gwgroups = return_gateway_groups_array();
1977
	if (is_array($dyndnscfg)) {
1978
		if (platform_booting()) {
1979
			echo gettext("Starting DynDNS clients...");
1980
		}
1981

    
1982
		foreach ($dyndnscfg as $dyndns) {
1983
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1984
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1985
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1986
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1987
				services_dyndns_configure_client($dyndns);
1988
				sleep(1);
1989
			}
1990
		}
1991

    
1992
		if (platform_booting()) {
1993
			echo gettext("done.") . "\n";
1994
		}
1995
	}
1996

    
1997
	return 0;
1998
}
1999

    
2000
function dyndnsCheckIP($int) {
2001
	global $config;
2002
	$ip_address = get_interface_ip($int);
2003
	if (is_private_ip($ip_address)) {
2004
		$gateways_status = return_gateways_status(true);
2005
		// If the gateway for this interface is down, then the external check cannot work.
2006
		// Avoid the long wait for the external check to timeout.
2007
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
2008
			return "down";
2009
		}
2010
		$hosttocheck = "http://checkip.dyndns.org";
2011
		$ip_ch = curl_init($hosttocheck);
2012
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
2013
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
2014
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
2015
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
2016
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
2017
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
2018
		$ip_result_page = curl_exec($ip_ch);
2019
		curl_close($ip_ch);
2020
		$ip_result_decoded = urldecode($ip_result_page);
2021
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
2022
		$ip_address = trim($matches[1]);
2023
	}
2024
	return $ip_address;
2025
}
2026

    
2027
function services_dnsmasq_configure($restart_dhcp = true) {
2028
	global $config, $g;
2029
	$return = 0;
2030

    
2031
	// hard coded args: will be removed to avoid duplication if specified in custom_options
2032
	$standard_args = array(
2033
		"dns-forward-max" => "--dns-forward-max=5000",
2034
		"cache-size" => "--cache-size=10000",
2035
		"local-ttl" => "--local-ttl=1"
2036
	);
2037

    
2038

    
2039
	if (isset($config['system']['developerspew'])) {
2040
		$mt = microtime();
2041
		echo "services_dnsmasq_configure() being called $mt\n";
2042
	}
2043

    
2044
	/* kill any running dnsmasq */
2045
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
2046
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
2047
	}
2048

    
2049
	if (isset($config['dnsmasq']['enable'])) {
2050

    
2051
		if (platform_booting()) {
2052
			echo gettext("Starting DNS forwarder...");
2053
		} else {
2054
			sleep(1);
2055
		}
2056

    
2057
		/* generate hosts file */
2058
		if (system_hosts_generate() != 0) {
2059
			$return = 1;
2060
		}
2061

    
2062
		$args = "";
2063

    
2064
		if (isset($config['dnsmasq']['regdhcp'])) {
2065
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
2066
		}
2067

    
2068
		/* Setup listen port, if non-default */
2069
		if (is_port($config['dnsmasq']['port'])) {
2070
			$args .= " --port={$config['dnsmasq']['port']} ";
2071
		}
2072

    
2073
		$listen_addresses = "";
2074
		if (isset($config['dnsmasq']['interface'])) {
2075
			$interfaces = explode(",", $config['dnsmasq']['interface']);
2076
			foreach ($interfaces as $interface) {
2077
				$if = get_real_interface($interface);
2078
				if (does_interface_exist($if)) {
2079
					$laddr = get_interface_ip($interface);
2080
					if (is_ipaddrv4($laddr)) {
2081
						$listen_addresses .= " --listen-address={$laddr} ";
2082
					}
2083
					$laddr6 = get_interface_ipv6($interface);
2084
					if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
2085
						/*
2086
						 * XXX: Since dnsmasq does not support link-local address
2087
						 * with scope specified. These checks are being done.
2088
						 */
2089
						if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
2090
							$tmpaddrll6 = explode("%", $laddr6);
2091
							$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2092
						} else {
2093
							$listen_addresses .= " --listen-address={$laddr6} ";
2094
						}
2095
					}
2096
				}
2097
			}
2098
			if (!empty($listen_addresses)) {
2099
				$args .= " {$listen_addresses} ";
2100
				if (isset($config['dnsmasq']['strictbind'])) {
2101
					$args .= " --bind-interfaces ";
2102
				}
2103
			}
2104
		}
2105

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

    
2113
			// Build an array of domain overrides to help in checking for matches.
2114
			$override_a = array();
2115
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2116
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2117
					$override_a[$override['domain']] = "y";
2118
				}
2119
			}
2120

    
2121
			// Build an array of the private reverse lookup domain names
2122
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
2123
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
2124
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
2125
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
2126
			}
2127

    
2128
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
2129
			foreach ($reverse_domain_a as $reverse_domain) {
2130
				if (!isset($override_a[$reverse_domain])) {
2131
					$args .= " --server=/$reverse_domain/ ";
2132
				}
2133
			}
2134
			unset($override_a);
2135
			unset($reverse_domain_a);
2136
		}
2137

    
2138
		/* Setup forwarded domains */
2139
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2140
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2141
				if ($override['ip'] == "!") {
2142
					$override[ip] = "";
2143
				}
2144
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2145
			}
2146
		}
2147

    
2148
		/* Allow DNS Rebind for forwarded domains */
2149
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2150
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2151
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2152
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2153
				}
2154
			}
2155
		}
2156

    
2157
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2158
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2159
		}
2160

    
2161
		if (isset($config['dnsmasq']['strict_order'])) {
2162
			$args .= " --strict-order ";
2163
		}
2164

    
2165
		if (isset($config['dnsmasq']['domain_needed'])) {
2166
			$args .= " --domain-needed ";
2167
		}
2168

    
2169
		if ($config['dnsmasq']['custom_options']) {
2170
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2171
				$args .= " " . escapeshellarg("--{$c}");
2172
				$p = explode('=', $c);
2173
				if (array_key_exists($p[0], $standard_args)) {
2174
					unset($standard_args[$p[0]]);
2175
				}
2176
			}
2177
		}
2178
		$args .= ' ' . implode(' ', array_values($standard_args));
2179

    
2180
		/* run dnsmasq */
2181
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2182
		//log_error("dnsmasq command: {$cmd}");
2183
		mwexec_bg($cmd);
2184
		unset($args);
2185

    
2186
		system_dhcpleases_configure();
2187

    
2188
		if (platform_booting()) {
2189
			echo gettext("done.") . "\n";
2190
		}
2191
	}
2192

    
2193
	if (!platform_booting() && $restart_dhcp) {
2194
		if (services_dhcpd_configure() != 0) {
2195
			$return = 1;
2196
		}
2197
	}
2198

    
2199
	return $return;
2200
}
2201

    
2202
function services_unbound_configure($restart_dhcp = true) {
2203
	global $config, $g;
2204
	$return = 0;
2205

    
2206
	if (isset($config['system']['developerspew'])) {
2207
		$mt = microtime();
2208
		echo "services_unbound_configure() being called $mt\n";
2209
	}
2210

    
2211
	// kill any running Unbound instance
2212
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2213
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2214
	}
2215

    
2216
	if (isset($config['unbound']['enable'])) {
2217
		if (platform_booting()) {
2218
			echo gettext("Starting DNS Resolver...");
2219
		} else {
2220
			sleep(1);
2221
		}
2222

    
2223
		/* generate hosts file */
2224
		if (system_hosts_generate() != 0) {
2225
			$return = 1;
2226
		}
2227

    
2228
		require_once('/etc/inc/unbound.inc');
2229
		sync_unbound_service();
2230
		if (platform_booting()) {
2231
			echo gettext("done.") . "\n";
2232
		}
2233

    
2234
		system_dhcpleases_configure();
2235
	}
2236

    
2237
	if (!platform_booting() && $restart_dhcp) {
2238
		if (services_dhcpd_configure() != 0) {
2239
			$return = 1;
2240
		}
2241
	}
2242

    
2243
	return $return;
2244
}
2245

    
2246
function services_snmpd_configure() {
2247
	global $config, $g;
2248
	if (isset($config['system']['developerspew'])) {
2249
		$mt = microtime();
2250
		echo "services_snmpd_configure() being called $mt\n";
2251
	}
2252

    
2253
	/* kill any running snmpd */
2254
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2255
	sleep(2);
2256
	if (is_process_running("bsnmpd")) {
2257
		mwexec("/usr/bin/killall bsnmpd", true);
2258
	}
2259

    
2260
	if (isset($config['snmpd']['enable'])) {
2261

    
2262
		if (platform_booting()) {
2263
			echo gettext("Starting SNMP daemon... ");
2264
		}
2265

    
2266
		/* generate snmpd.conf */
2267
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2268
		if (!$fd) {
2269
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2270
			return 1;
2271
		}
2272

    
2273

    
2274
		$snmpdconf = <<<EOD
2275
location := "{$config['snmpd']['syslocation']}"
2276
contact := "{$config['snmpd']['syscontact']}"
2277
read := "{$config['snmpd']['rocommunity']}"
2278

    
2279
EOD;
2280

    
2281
/* No docs on what write strings do there so disable for now.
2282
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2283
			$snmpdconf .= <<<EOD
2284
# write string
2285
write := "{$config['snmpd']['rwcommunity']}"
2286

    
2287
EOD;
2288
		}
2289
*/
2290

    
2291

    
2292
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2293
			$snmpdconf .= <<<EOD
2294
# SNMP Trap support.
2295
traphost := {$config['snmpd']['trapserver']}
2296
trapport := {$config['snmpd']['trapserverport']}
2297
trap := "{$config['snmpd']['trapstring']}"
2298

    
2299

    
2300
EOD;
2301
		}
2302

    
2303
		$platform = trim(file_get_contents('/etc/platform'));
2304
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2305
			$platform = $g['product_name'];
2306
		}
2307
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2308
			" {$g['product_version']} {$platform} " . php_uname("s") .
2309
			" " . php_uname("r") . " " . php_uname("m");
2310

    
2311
		$snmpdconf .= <<<EOD
2312
system := 1     # pfSense
2313
%snmpd
2314
sysDescr			= "{$sysDescr}"
2315
begemotSnmpdDebugDumpPdus       = 2
2316
begemotSnmpdDebugSyslogPri      = 7
2317
begemotSnmpdCommunityString.0.1 = $(read)
2318

    
2319
EOD;
2320

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

    
2326
EOD;
2327
		}
2328
*/
2329

    
2330

    
2331
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2332
			$snmpdconf .= <<<EOD
2333
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2334
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2335
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2336

    
2337
EOD;
2338
		}
2339

    
2340

    
2341
		$snmpdconf .= <<<EOD
2342
begemotSnmpdCommunityDisable    = 1
2343

    
2344
EOD;
2345

    
2346
		$bind_to_ip = "0.0.0.0";
2347
		if (isset($config['snmpd']['bindip'])) {
2348
			if (is_ipaddr($config['snmpd']['bindip'])) {
2349
				$bind_to_ip = $config['snmpd']['bindip'];
2350
			} else {
2351
				$if = get_real_interface($config['snmpd']['bindip']);
2352
				if (does_interface_exist($if)) {
2353
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2354
				}
2355
			}
2356
		}
2357

    
2358
		if (is_port($config['snmpd']['pollport'])) {
2359
			$snmpdconf .= <<<EOD
2360
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2361

    
2362
EOD;
2363

    
2364
		}
2365

    
2366
		$snmpdconf .= <<<EOD
2367
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2368
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2369

    
2370
# These are bsnmp macros not php vars.
2371
sysContact      = $(contact)
2372
sysLocation     = $(location)
2373
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2374

    
2375
snmpEnableAuthenTraps = 2
2376

    
2377
EOD;
2378

    
2379
		if (is_array($config['snmpd']['modules'])) {
2380
			if (isset($config['snmpd']['modules']['mibii'])) {
2381
			$snmpdconf .= <<<EOD
2382
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2383

    
2384
EOD;
2385
			}
2386

    
2387
			if (isset($config['snmpd']['modules']['netgraph'])) {
2388
				$snmpdconf .= <<<EOD
2389
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2390
%netgraph
2391
begemotNgControlNodeName = "snmpd"
2392

    
2393
EOD;
2394
			}
2395

    
2396
			if (isset($config['snmpd']['modules']['pf'])) {
2397
				$snmpdconf .= <<<EOD
2398
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2399

    
2400
EOD;
2401
			}
2402

    
2403
			if (isset($config['snmpd']['modules']['hostres'])) {
2404
				$snmpdconf .= <<<EOD
2405
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2406

    
2407
EOD;
2408
			}
2409

    
2410
			if (isset($config['snmpd']['modules']['bridge'])) {
2411
				$snmpdconf .= <<<EOD
2412
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2413
# config must end with blank line
2414

    
2415
EOD;
2416
			}
2417
			if (isset($config['snmpd']['modules']['ucd'])) {
2418
				$snmpdconf .= <<<EOD
2419
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2420

    
2421
EOD;
2422
			}
2423
			if (isset($config['snmpd']['modules']['regex'])) {
2424
				$snmpdconf .= <<<EOD
2425
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2426

    
2427
EOD;
2428
			}
2429
		}
2430

    
2431
		fwrite($fd, $snmpdconf);
2432
		fclose($fd);
2433
		unset($snmpdconf);
2434

    
2435
		/* run bsnmpd */
2436
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2437
			" -p {$g['varrun_path']}/snmpd.pid");
2438

    
2439
		if (platform_booting()) {
2440
			echo gettext("done.") . "\n";
2441
		}
2442
	}
2443

    
2444
	return 0;
2445
}
2446

    
2447
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2448
	global $config, $g;
2449
	if (isset($config['system']['developerspew'])) {
2450
		$mt = microtime();
2451
		echo "services_dnsupdate_process() being called $mt\n";
2452
	}
2453

    
2454
	/* Dynamic DNS updating active? */
2455
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2456
		$notify_text = "";
2457
		$gwgroups = return_gateway_groups_array();
2458
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2459
			if (!isset($dnsupdate['enable'])) {
2460
				continue;
2461
			}
2462
			if (!empty($int) && ($int != $dnsupdate['interface']) && (!is_array($gwgroups[$dnsupdate['interface']]))) {
2463
				continue;
2464
			}
2465
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2466
				continue;
2467
			}
2468

    
2469
			/* determine interface name */
2470
			$if = get_failover_interface($dnsupdate['interface']);
2471

    
2472
			if (isset($dnsupdate['usepublicip'])) {
2473
				$wanip = dyndnsCheckIP($if);
2474
			} else {
2475
				$wanip = get_interface_ip($if);
2476
			}
2477

    
2478
			$wanipv6 = get_interface_ipv6($if);
2479
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2480
			$currentTime = time();
2481

    
2482
			if ($wanip || $wanipv6) {
2483
				$keyname = $dnsupdate['keyname'];
2484
				/* trailing dot */
2485
				if (substr($keyname, -1) != ".") {
2486
					$keyname .= ".";
2487
				}
2488

    
2489
				$hostname = $dnsupdate['host'];
2490
				/* trailing dot */
2491
				if (substr($hostname, -1) != ".") {
2492
					$hostname .= ".";
2493
				}
2494

    
2495
				/* write private key file
2496
				   this is dumb - public and private keys are the same for HMAC-MD5,
2497
				   but nsupdate insists on having both */
2498
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2499
				$privkey = <<<EOD
2500
Private-key-format: v1.2
2501
Algorithm: 157 (HMAC)
2502
Key: {$dnsupdate['keydata']}
2503

    
2504
EOD;
2505
				fwrite($fd, $privkey);
2506
				fclose($fd);
2507

    
2508
				/* write public key file */
2509
				if ($dnsupdate['keytype'] == "zone") {
2510
					$flags = 257;
2511
					$proto = 3;
2512
				} else if ($dnsupdate['keytype'] == "host") {
2513
					$flags = 513;
2514
					$proto = 3;
2515
				} else if ($dnsupdate['keytype'] == "user") {
2516
					$flags = 0;
2517
					$proto = 2;
2518
				}
2519

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

    
2524
				/* generate update instructions */
2525
				$upinst = "";
2526
				if (!empty($dnsupdate['server'])) {
2527
					$upinst .= "server {$dnsupdate['server']}\n";
2528
				}
2529

    
2530
				if (file_exists($cacheFile)) {
2531
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2532
				}
2533
				if (file_exists("{$cacheFile}.ipv6")) {
2534
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2535
				}
2536

    
2537
				// 25 Days
2538
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2539
				$need_update = false;
2540

    
2541
				conf_mount_rw();
2542
				/* Update IPv4 if we have it. */
2543
				if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
2544
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2545
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2546
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2547
						$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";
2548
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2549
						log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $cacheFile, $wanip));
2550
						$need_update = true;
2551
					} else {
2552
						log_error(sprintf(gettext("phpDynDNS: Not updating %s A record because the IP address has not changed."), $dnsupdate['host']));
2553
					}
2554
				} else {
2555
					@unlink($cacheFile);
2556
				}
2557

    
2558
				/* Update IPv6 if we have it. */
2559
				if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
2560
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2561
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2562
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2563
						$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";
2564
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2565
						log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s.ipv6: %2$s'), $cacheFile, $wanipv6));
2566
						$need_update = true;
2567
					} else {
2568
						log_error(sprintf(gettext("phpDynDNS: Not updating %s AAAA record because the IPv6 address has not changed."), $dnsupdate['host']));
2569
					}
2570
				} else {
2571
					@unlink("{$cacheFile}.ipv6");
2572
				}
2573
				conf_mount_ro();
2574

    
2575
				$upinst .= "\n";	/* mind that trailing newline! */
2576

    
2577
				if ($need_update) {
2578
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2579
					unset($upinst);
2580
					/* invoke nsupdate */
2581
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2582
					if (isset($dnsupdate['usetcp'])) {
2583
						$cmd .= " -v";
2584
					}
2585
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2586
					mwexec_bg($cmd);
2587
					unset($cmd);
2588
				}
2589
			}
2590
		}
2591
		if (!empty($notify_text)) {
2592
			notify_all_remote($notify_text);
2593
		}
2594
	}
2595

    
2596
	return 0;
2597
}
2598

    
2599
/* configure cron service */
2600
function configure_cron() {
2601
	global $g, $config;
2602

    
2603
	conf_mount_rw();
2604
	/* preserve existing crontab entries */
2605
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2606

    
2607
	for ($i = 0; $i < count($crontab_contents); $i++) {
2608
		$cron_item =& $crontab_contents[$i];
2609
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2610
			array_splice($crontab_contents, $i - 1);
2611
			break;
2612
		}
2613
	}
2614
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2615

    
2616

    
2617
	if (is_array($config['cron']['item'])) {
2618
		$crontab_contents .= "#\n";
2619
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2620
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2621
		$crontab_contents .= "#\n";
2622

    
2623
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2624
			$http_proxy = $config['system']['proxyurl'];
2625
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2626
				$http_proxy .= ':' . $config['system']['proxyport'];
2627
			}
2628
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2629
		}
2630

    
2631
		foreach ($config['cron']['item'] as $item) {
2632
			$crontab_contents .= "\n{$item['minute']}\t";
2633
			$crontab_contents .= "{$item['hour']}\t";
2634
			$crontab_contents .= "{$item['mday']}\t";
2635
			$crontab_contents .= "{$item['month']}\t";
2636
			$crontab_contents .= "{$item['wday']}\t";
2637
			$crontab_contents .= "{$item['who']}\t";
2638
			$crontab_contents .= "{$item['command']}";
2639
		}
2640

    
2641
		$crontab_contents .= "\n#\n";
2642
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2643
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2644
		$crontab_contents .= "#\n\n";
2645
	}
2646

    
2647
	/* please maintain the newline at the end of file */
2648
	file_put_contents("/etc/crontab", $crontab_contents);
2649
	unset($crontab_contents);
2650

    
2651
	/* make sure that cron is running and start it if it got killed somehow */
2652
	if (!is_process_running("cron")) {
2653
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2654
	} else {
2655
	/* do a HUP kill to force sync changes */
2656
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2657
	}
2658

    
2659
	conf_mount_ro();
2660
}
2661

    
2662
function upnp_action ($action) {
2663
	global $g, $config;
2664
	switch ($action) {
2665
		case "start":
2666
			if (file_exists('/var/etc/miniupnpd.conf')) {
2667
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2668
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2669
			}
2670
			break;
2671
		case "stop":
2672
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2673
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2674
				mwexec('/usr/bin/killall miniupnpd 2>/dev/null', true);
2675
			}
2676
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2677
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2678
			break;
2679
		case "restart":
2680
			upnp_action('stop');
2681
			upnp_action('start');
2682
			break;
2683
	}
2684
}
2685

    
2686
function upnp_start() {
2687
	global $config;
2688

    
2689
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2690
		return;
2691
	}
2692

    
2693
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2694
		echo gettext("Starting UPnP service... ");
2695
		require_once('/usr/local/pkg/miniupnpd.inc');
2696
		sync_package_miniupnpd();
2697
		echo "done.\n";
2698
	}
2699
}
2700

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

    
2704
	$is_installed = false;
2705
	$cron_changed = true;
2706

    
2707
	if (!is_array($config['cron'])) {
2708
		$config['cron'] = array();
2709
	}
2710
	if (!is_array($config['cron']['item'])) {
2711
		$config['cron']['item'] = array();
2712
	}
2713

    
2714
	$x = 0;
2715
	foreach ($config['cron']['item'] as $item) {
2716
		if (strstr($item['command'], $command)) {
2717
			$is_installed = true;
2718
			break;
2719
		}
2720
		$x++;
2721
	}
2722

    
2723
	if ($active) {
2724
		$cron_item = array();
2725
		$cron_item['minute'] = $minute;
2726
		$cron_item['hour'] = $hour;
2727
		$cron_item['mday'] = $monthday;
2728
		$cron_item['month'] = $month;
2729
		$cron_item['wday'] = $weekday;
2730
		$cron_item['who'] = $who;
2731
		$cron_item['command'] = $command;
2732
		if (!$is_installed) {
2733
			$config['cron']['item'][] = $cron_item;
2734
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2735
		} else {
2736
			if ($config['cron']['item'][$x] == $cron_item) {
2737
				$cron_changed = false;
2738
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2739
			} else {
2740
				$config['cron']['item'][$x] = $cron_item;
2741
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2742
			}
2743
		}
2744
	} else {
2745
		if ($is_installed == true) {
2746
			unset($config['cron']['item'][$x]);
2747
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2748
		}
2749
	}
2750

    
2751
	if ($cron_changed) {
2752
		configure_cron();
2753
	}
2754
}
2755

    
2756
?>
(49-49/65)