Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
516
	$dhcpdconf = <<<EOD
517

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

    
531
EOD;
532

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

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

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

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

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

    
562
		interfaces_staticarp_configure($dhcpif);
563

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

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

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

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

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

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

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

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

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

    
651
		$dnscfg = "";
652

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

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

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

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

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

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

    
726
		// Setup pool options
727
		foreach ($all_pools as $poolconf) {
728
			$dhcpdconf .= "	pool {\n";
729
			/* is failover dns setup? */
730
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
731
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
732
				if ($poolconf['dnsserver'][1] <> "") {
733
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
734
				}
735
				if ($poolconf['dnsserver'][2] <> "") {
736
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
737
				}
738
				if ($poolconf['dnsserver'][3] <> "") {
739
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
740
				}
741
				$dhcpdconf .= ";\n";
742
			}
743

    
744
			/* allow/deny MACs */
745
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
746
			foreach ($mac_allow_list as $mac) {
747
				if (empty($mac)) {
748
					continue;
749
				}
750
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
751
			}
752
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
753
			foreach ($mac_deny_list as $mac) {
754
				if (empty($mac)) {
755
					continue;
756
				}
757
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
758
			}
759

    
760
			if ($poolconf['failover_peerip'] <> "") {
761
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
762
			}
763

    
764
			if (isset($poolconf['denyunknown'])) {
765
			   $dhcpdconf .= "		deny unknown-clients;\n";
766
			}
767

    
768
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
769
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
770
			}
771

    
772
			if ($dhcpifconf['failover_peerip'] <> "") {
773
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
774
			}
775

    
776
			$pdnscfg = "";
777

    
778
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
779
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
780
			}
781

    
782
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
783
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
784
			}
785

    
786
			if (isset($poolconf['ddnsupdate'])) {
787
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
788
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
789
				}
790
				$pdnscfg .= "		ddns-update-style interim;\n";
791
			}
792

    
793
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
794
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
795
			}
796
			$dhcpdconf .= "{$pdnscfg}";
797

    
798
			// default-lease-time
799
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
800
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
801
			}
802

    
803
			// max-lease-time
804
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
805
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
806
			}
807

    
808
			// netbios-name*
809
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
810
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
811
				$dhcpdconf .= "		option netbios-node-type 8;\n";
812
			}
813

    
814
			// ntp-servers
815
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
816
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
817
			}
818

    
819
			// tftp-server-name
820
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
821
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
822
			}
823

    
824
			// ldap-server
825
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
826
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
827
			}
828

    
829
			// net boot information
830
			if (isset($poolconf['netboot'])) {
831
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
832
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
833
				}
834
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
835
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
836
				}
837
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
838
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
839
				}
840
			}
841
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
842
			$dhcpdconf .= "	}\n\n";
843
		}
844
// End of settings inside pools
845

    
846
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
847
			$routers = $dhcpifconf['gateway'];
848
			$add_routers = true;
849
		} elseif ($dhcpifconf['gateway'] == "none") {
850
			$add_routers = false;
851
		} else {
852
			$add_routers = $enable_add_routers;
853
			$routers = $ifcfgip;
854
		}
855
		if ($add_routers) {
856
			$dhcpdconf .= "	option routers {$routers};\n";
857
		}
858

    
859
		$dhcpdconf .= <<<EOD
860
$dnscfg
861

    
862
EOD;
863
		// default-lease-time
864
		if ($dhcpifconf['defaultleasetime']) {
865
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
866
		}
867

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

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

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

    
884
		// tftp-server-name
885
		if ($dhcpifconf['tftp'] <> "") {
886
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
887
		}
888

    
889
		// Handle option, number rowhelper values
890
		$dhcpdconf .= "\n";
891
		if ($dhcpifconf['numberoptions']['item']) {
892
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
893
				if (empty($item['type']) || $item['type'] == "text") {
894
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
895
				} else {
896
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
897
				}
898
			}
899
		}
900

    
901
		// ldap-server
902
		if ($dhcpifconf['ldap'] <> "") {
903
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
904
		}
905

    
906
		// net boot information
907
		if (isset($dhcpifconf['netboot'])) {
908
			if ($dhcpifconf['nextserver'] <> "") {
909
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
910
			}
911
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
912
				$dhcpdconf .= "	if option arch = 00:06 {\n";
913
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
914
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
915
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
916
				$dhcpdconf .= "	} else {\n";
917
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
918
				$dhcpdconf .= "	}\n\n";
919
			} elseif (!empty($dhcpifconf['filename'])) {
920
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
921
			}
922
			if (!empty($dhcpifconf['rootpath'])) {
923
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
924
			}
925
		}
926

    
927
		$dhcpdconf .= <<<EOD
928
}
929

    
930
EOD;
931

    
932
		/* add static mappings */
933
		if (is_array($dhcpifconf['staticmap'])) {
934

    
935
			$i = 0;
936
			foreach ($dhcpifconf['staticmap'] as $sm) {
937
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
938

    
939
				if ($sm['mac']) {
940
					$dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
941
				}
942

    
943
				if ($sm['cid']) {
944
					$dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
945
				}
946

    
947
				if ($sm['ipaddr']) {
948
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
949
				}
950

    
951
				if ($sm['hostname']) {
952
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
953
					$dhhostname = str_replace(".", "_", $dhhostname);
954
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
955
				}
956
				if ($sm['filename']) {
957
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
958
				}
959

    
960
				if ($sm['rootpath']) {
961
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
962
				}
963

    
964
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
965
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
966
				}
967

    
968
				$smdnscfg = "";
969

    
970
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
971
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
972
				}
973

    
974
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
975
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
976
				}
977

    
978
				if (isset($sm['ddnsupdate'])) {
979
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
980
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
981
					}
982
					$pdnscfg .= "		ddns-update-style interim;\n";
983
				}
984

    
985
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
986
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
987
				}
988
				$dhcpdconf .= "{$smdnscfg}";
989

    
990
				// default-lease-time
991
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
992
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
993
				}
994

    
995
				// max-lease-time
996
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
997
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
998
				}
999

    
1000
				// netbios-name*
1001
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
1002
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
1003
					$dhcpdconf .= "	option netbios-node-type 8;\n";
1004
				}
1005

    
1006
				// ntp-servers
1007
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
1008
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
1009
				}
1010

    
1011
				// tftp-server-name
1012
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
1013
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
1014
				}
1015

    
1016
				$dhcpdconf .= "}\n";
1017
				$i++;
1018
			}
1019
		}
1020

    
1021
		$dhcpdifs[] = get_real_interface($dhcpif);
1022
		if ($newzone['domain-name']) {
1023
			if ($need_ddns_updates) {
1024
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
1025
			}
1026
			$ddns_zones[] = $newzone;
1027
		}
1028
	}
1029

    
1030
	if ($need_ddns_updates) {
1031
		$dhcpdconf .= "ddns-update-style interim;\n";
1032
		$dhcpdconf .= "update-static-leases on;\n";
1033

    
1034
		$dhcpdconf .= dhcpdkey($dhcpifconf);
1035
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
1036
	}
1037

    
1038
	/* write dhcpd.conf */
1039
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
1040
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1041
		unset($dhcpdconf);
1042
		return 1;
1043
	}
1044
	unset($dhcpdconf);
1045

    
1046
	/* create an empty leases database */
1047
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1048
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1049
	}
1050

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

    
1055
	/* fire up dhcpd in a chroot */
1056
	if (count($dhcpdifs) > 0) {
1057
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1058
			join(" ", $dhcpdifs));
1059
	}
1060

    
1061
	if (platform_booting()) {
1062
		print "done.\n";
1063
	}
1064

    
1065
	return 0;
1066
}
1067

    
1068
function dhcpdkey($dhcpifconf) {
1069
	$dhcpdconf = "";
1070
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1071
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1072
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1073
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1074
		$dhcpdconf .= "}\n";
1075
	}
1076

    
1077
	return $dhcpdconf;
1078
}
1079

    
1080
function dhcpdzones($ddns_zones, $dhcpifconf) {
1081
	$dhcpdconf = "";
1082

    
1083
	if (is_array($ddns_zones)) {
1084
		$added_zones = array();
1085
		foreach ($ddns_zones as $zone) {
1086
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1087
				continue;
1088
			}
1089
			$primary = $zone['dns-servers'][0];
1090
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1091

    
1092
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1093
			if (!is_ipaddrv4($primary)) {
1094
				if (is_ipaddrv4($secondary)) {
1095
					$primary = $secondary;
1096
					$secondary = "";
1097
				} else {
1098
					continue;
1099
				}
1100
			}
1101

    
1102
			// We don't need to add zones multiple times.
1103
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1104
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1105
				$dhcpdconf .= "	primary {$primary};\n";
1106
				if (is_ipaddrv4($secondary)) {
1107
					$dhcpdconf .= "	secondary {$secondary};\n";
1108
				}
1109
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1110
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1111
				}
1112
				$dhcpdconf .= "}\n";
1113
				$added_zones[] = $zone['domain-name'];
1114
			}
1115
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1116
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1117
				$dhcpdconf .= "	primary {$primary};\n";
1118
				if (is_ipaddrv4($secondary)) {
1119
					$dhcpdconf .= "	secondary {$secondary};\n";
1120
				}
1121
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1122
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1123
				}
1124
				$dhcpdconf .= "}\n";
1125
				$added_zones[] = $zone['ptr-domain'];
1126
			}
1127
		}
1128
	}
1129

    
1130
	return $dhcpdconf;
1131
}
1132

    
1133
function services_dhcpdv6_configure($blacklist = array()) {
1134
	global $config, $g;
1135

    
1136
	if ($g['services_dhcp_server_enable'] == false) {
1137
		return;
1138
	}
1139

    
1140
	if (isset($config['system']['developerspew'])) {
1141
		$mt = microtime();
1142
		echo "services_dhcpd_configure($if) being called $mt\n";
1143
	}
1144

    
1145
	/* kill any running dhcpd */
1146
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1147
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1148
	}
1149
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1150
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1151
	}
1152

    
1153
	/* DHCP enabled on any interfaces? */
1154
	if (!is_dhcpv6_server_enabled()) {
1155
		return 0;
1156
	}
1157

    
1158
	if (platform_booting()) {
1159
		if ($g['platform'] != "pfSense") {
1160
			/* restore the leases, if we have them */
1161
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1162
				$dhcprestore = "";
1163
				$dhcpreturn = "";
1164
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1165
				$dhcprestore = implode(" ", $dhcprestore);
1166
				if ($dhcpreturn <> 0) {
1167
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1168
				}
1169
			}
1170
		}
1171
	}
1172

    
1173
	$syscfg = $config['system'];
1174
	if (!is_array($config['dhcpdv6'])) {
1175
		$config['dhcpdv6'] = array();
1176
	}
1177
	$dhcpdv6cfg = $config['dhcpdv6'];
1178
	$Iflist = get_configured_interface_list();
1179
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1180

    
1181

    
1182
	if (platform_booting()) {
1183
		echo "Starting DHCPv6 service...";
1184
	} else {
1185
		sleep(1);
1186
	}
1187

    
1188
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1189
	foreach ($Iflist as $ifname) {
1190
		/* Do not put in the config an interface which is down */
1191
		if (isset($blacklist[$ifname])) {
1192
			continue;
1193
		}
1194
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1195
			$realif = get_real_interface($ifname, "inet6");
1196
			$ifcfgipv6 = get_interface_ipv6($ifname);
1197
			if (!is_ipaddrv6($ifcfgipv6)) {
1198
				continue;
1199
			}
1200
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1201
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1202
			$trackcfg = $config['interfaces'][$trackifname];
1203
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1204
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1205
			$dhcpdv6cfg[$ifname] = array();
1206
			$dhcpdv6cfg[$ifname]['enable'] = true;
1207
			/* range */
1208
			$ifcfgipv6arr[7] = "1000";
1209
			$dhcpdv6cfg[$ifname]['range'] = array();
1210
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1211
			$ifcfgipv6arr[7] = "2000";
1212
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1213
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1214
			if ($pdlen > 2) {
1215
				$pdlenmax = $pdlen;
1216
				$pdlenhalf = $pdlenmax -1;
1217
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1218
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1219
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1220

    
1221
				/* set the delegation start to half the current address block */
1222
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1223
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1224

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

    
1229
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1230
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1231
			}
1232
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1233
		}
1234
	}
1235

    
1236
	$custoptionsv6 = "";
1237
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1238
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1239
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1240
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1241
			}
1242
		}
1243
	}
1244

    
1245
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1246
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1247
	}
1248

    
1249
	$dhcpdv6conf = <<<EOD
1250

    
1251
option domain-name "{$syscfg['domain']}";
1252
option ldap-server code 95 = text;
1253
option domain-search-list code 119 = text;
1254
{$custoptionsv6}
1255
default-lease-time 7200;
1256
max-lease-time 86400;
1257
log-facility local7;
1258
one-lease-per-client true;
1259
deny duplicates;
1260
ping-check true;
1261
update-conflict-detection false;
1262

    
1263
EOD;
1264

    
1265
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1266
		$dhcpdv6conf .= "authoritative;\n";
1267
	}
1268

    
1269
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1270
		$dhcpdv6conf .= "always-broadcast on\n";
1271
	}
1272

    
1273
	$dhcpdv6ifs = array();
1274

    
1275
	$dhcpv6num = 0;
1276
	$nsupdate = false;
1277

    
1278
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1279

    
1280
		$ddns_zones = array();
1281

    
1282
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1283

    
1284
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1285
			continue;
1286
		}
1287
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1288
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1289
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1290

    
1291
		if ($is_olsr_enabled == true) {
1292
			if ($dhcpv6ifconf['netmask']) {
1293
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1294
			}
1295
		}
1296

    
1297
		$dnscfgv6 = "";
1298

    
1299
		if ($dhcpv6ifconf['domain']) {
1300
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1301
		}
1302

    
1303
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1304
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1305
		}
1306

    
1307
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1308
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1309
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1310
			}
1311
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1312
			$nsupdate = true;
1313
		}
1314

    
1315
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1316
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1317
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1318
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1319
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1320
			$dns_arrv6 = array();
1321
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1322
				if (is_ipaddrv6($dnsserver)) {
1323
					$dns_arrv6[] = $dnsserver;
1324
				}
1325
			}
1326
			if (!empty($dns_arrv6)) {
1327
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1328
			}
1329
		}
1330

    
1331
		if ($dhcpv6ifconf['domain']) {
1332
			$newzone = array();
1333
			$newzone['domain-name'] = $dhcpv6ifconf['domain'];
1334
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1335
			$ddns_zones[] = $newzone;
1336
		}
1337

    
1338
		if (is_ipaddrv6($ifcfgipv6)) {
1339
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1340
		} else {
1341
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1342
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1343
		}
1344
		$dhcpdv6conf .= " {\n";
1345

    
1346
		$dhcpdv6conf .= <<<EOD
1347
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1348
$dnscfgv6
1349

    
1350
EOD;
1351

    
1352
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1353
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1354
		}
1355
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1356
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1357
		}
1358
		// default-lease-time
1359
		if ($dhcpv6ifconf['defaultleasetime']) {
1360
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1361
		}
1362

    
1363
		// max-lease-time
1364
		if ($dhcpv6ifconf['maxleasetime']) {
1365
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1366
		}
1367

    
1368
		// ntp-servers
1369
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1370
			$ntpservers = array();
1371
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1372
				if (is_ipaddrv6($ntpserver)) {
1373
					$ntpservers[] = $ntpserver;
1374
				}
1375
			}
1376
			if (count($ntpservers) > 0) {
1377
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1378
			}
1379
		}
1380
		// tftp-server-name
1381
		/* Needs ISC DHCPD support
1382
		 if ($dhcpv6ifconf['tftp'] <> "") {
1383
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1384
		 }
1385
		*/
1386

    
1387
		// Handle option, number rowhelper values
1388
		$dhcpdv6conf .= "\n";
1389
		if ($dhcpv6ifconf['numberoptions']['item']) {
1390
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1391
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1392
			}
1393
		}
1394

    
1395
		// ldap-server
1396
		if ($dhcpv6ifconf['ldap'] <> "") {
1397
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1398
		}
1399

    
1400
		// net boot information
1401
		if (isset($dhcpv6ifconf['netboot'])) {
1402
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1403
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1404
			}
1405
		}
1406

    
1407
		$dhcpdv6conf .= "}\n";
1408

    
1409
		/* add static mappings */
1410
		/* Needs to use DUID */
1411
		if (is_array($dhcpv6ifconf['staticmap'])) {
1412
			$i = 0;
1413
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1414
				$dhcpdv6conf .= <<<EOD
1415
host s_{$dhcpv6if}_{$i} {
1416
	host-identifier option dhcp6.client-id {$sm['duid']};
1417

    
1418
EOD;
1419
				if ($sm['ipaddrv6']) {
1420
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1421
				}
1422

    
1423
				if ($sm['hostname']) {
1424
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1425
					$dhhostname = str_replace(".", "_", $dhhostname);
1426
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1427
				}
1428
				if ($sm['filename']) {
1429
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1430
				}
1431

    
1432
				if ($sm['rootpath']) {
1433
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1434
				}
1435

    
1436
				$dhcpdv6conf .= "}\n";
1437
				$i++;
1438
			}
1439
		}
1440

    
1441
		if ($dhcpv6ifconf['domain']) {
1442
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1443
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1444
		}
1445

    
1446
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1447
			if (preg_match("/poes/si", $dhcpv6if)) {
1448
				/* magic here */
1449
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1450
			} else {
1451
				$realif = get_real_interface($dhcpv6if, "inet6");
1452
				if (stristr("$realif", "bridge")) {
1453
					$mac = get_interface_mac($realif);
1454
					$v6address = generate_ipv6_from_mac($mac);
1455
					/* Create link local address for bridges */
1456
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1457
				}
1458
				$realif = escapeshellcmd($realif);
1459
				$dhcpdv6ifs[] = $realif;
1460
			}
1461
		}
1462
	}
1463

    
1464
	if ($nsupdate) {
1465
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1466
	} else {
1467
		$dhcpdv6conf .= "ddns-update-style none;\n";
1468
	}
1469

    
1470
	/* write dhcpdv6.conf */
1471
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1472
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1473
		if (platform_booting()) {
1474
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1475
		}
1476
		unset($dhcpdv6conf);
1477
		return 1;
1478
	}
1479
	unset($dhcpdv6conf);
1480

    
1481
	/* create an empty leases v6 database */
1482
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1483
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1484
	}
1485

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

    
1490
	/* fire up dhcpd in a chroot */
1491
	if (count($dhcpdv6ifs) > 0) {
1492
		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 " .
1493
			join(" ", $dhcpdv6ifs));
1494
		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");
1495
	}
1496
	if (platform_booting()) {
1497
		print gettext("done.") . "\n";
1498
	}
1499

    
1500
	return 0;
1501
}
1502

    
1503
function services_igmpproxy_configure() {
1504
	global $config, $g;
1505

    
1506
	/* kill any running igmpproxy */
1507
	killbyname("igmpproxy");
1508

    
1509
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1510
		return 1;
1511
	}
1512

    
1513
	$iflist = get_configured_interface_list();
1514

    
1515
	$igmpconf = <<<EOD
1516

    
1517
##------------------------------------------------------
1518
## Enable Quickleave mode (Sends Leave instantly)
1519
##------------------------------------------------------
1520
quickleave
1521

    
1522
EOD;
1523

    
1524
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1525
		unset($iflist[$igmpcf['ifname']]);
1526
		$realif = get_real_interface($igmpcf['ifname']);
1527
		if (empty($igmpcf['threshold'])) {
1528
			$threshld = 1;
1529
		} else {
1530
			$threshld = $igmpcf['threshold'];
1531
		}
1532
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1533

    
1534
		if ($igmpcf['address'] <> "") {
1535
			$item = explode(" ", $igmpcf['address']);
1536
			foreach ($item as $iww) {
1537
				$igmpconf .= "altnet {$iww}\n";
1538
			}
1539
		}
1540
		$igmpconf .= "\n";
1541
	}
1542
	foreach ($iflist as $ifn) {
1543
		$realif = get_real_interface($ifn);
1544
		$igmpconf .= "phyint {$realif} disabled\n";
1545
	}
1546
	$igmpconf .= "\n";
1547

    
1548
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1549
	if (!$igmpfl) {
1550
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1551
		return;
1552
	}
1553
	fwrite($igmpfl, $igmpconf);
1554
	fclose($igmpfl);
1555
	unset($igmpconf);
1556

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

    
1561
	return 0;
1562
}
1563

    
1564
function services_dhcrelay_configure() {
1565
	global $config, $g;
1566

    
1567
	if (isset($config['system']['developerspew'])) {
1568
		$mt = microtime();
1569
		echo "services_dhcrelay_configure() being called $mt\n";
1570
	}
1571

    
1572
	/* kill any running dhcrelay */
1573
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1574

    
1575
	$dhcrelaycfg =& $config['dhcrelay'];
1576

    
1577
	/* DHCPRelay enabled on any interfaces? */
1578
	if (!isset($dhcrelaycfg['enable'])) {
1579
		return 0;
1580
	}
1581

    
1582
	if (platform_booting()) {
1583
		echo gettext("Starting DHCP relay service...");
1584
	} else {
1585
		sleep(1);
1586
	}
1587

    
1588
	$iflist = get_configured_interface_list();
1589

    
1590
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1591
	foreach ($dhcifaces as $dhcrelayif) {
1592
		if (!isset($iflist[$dhcrelayif]) ||
1593
		    link_interface_to_bridge($dhcrelayif)) {
1594
			continue;
1595
		}
1596

    
1597
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1598
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1599
		}
1600
	}
1601
	
1602
	$srvips = explode(",", $dhcrelaycfg['server']);	
1603
	if (!is_array($srvips)) {
1604
		log_error("No destination IP has been configured!");
1605
		return;
1606
	}
1607

    
1608
	$dhcrelayifs = array_unique($dhcrelayifs);
1609

    
1610
	/* fire up dhcrelay */
1611
	if (empty($dhcrelayifs)) {
1612
		log_error("No suitable interface found for running dhcrelay!");
1613
		return; /* XXX */
1614
	}
1615

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

    
1618
	if (isset($dhcrelaycfg['agentoption'])) {
1619
		$cmd .= " -a -m replace";
1620
	}
1621

    
1622
	$cmd .= " " . implode(" ", $srvips);
1623
	mwexec($cmd);
1624
	unset($cmd);
1625

    
1626
	return 0;
1627
}
1628

    
1629
function services_dhcrelay6_configure() {
1630
	global $config, $g;
1631

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

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

    
1640
	$dhcrelaycfg =& $config['dhcrelay6'];
1641

    
1642
	/* DHCPv6 Relay enabled on any interfaces? */
1643
	if (!isset($dhcrelaycfg['enable'])) {
1644
		return 0;
1645
	}
1646

    
1647
	if (platform_booting()) {
1648
		echo gettext("Starting DHCPv6 relay service...");
1649
	} else {
1650
		sleep(1);
1651
	}
1652

    
1653
	$iflist = get_configured_interface_list();
1654

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

    
1662
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1663
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1664
		}
1665
	}
1666
	$dhcrelayifs = array_unique($dhcrelayifs);
1667

    
1668
	$srvips = explode(",", $dhcrelaycfg['server']);
1669
	if (!is_array($srvips)) {
1670
		log_error("No destination IP has been configured!");
1671
		return;
1672
	}
1673

    
1674
	/* fire up dhcrelay */
1675
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1676
		log_error("No suitable interface found for running dhcrelay -6!");
1677
		return; /* XXX */
1678
	}
1679

    
1680
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1681
	foreach ($dhcrelayifs as $dhcrelayif) {
1682
		$cmd .= " -l {$dhcrelayif}";
1683
	}
1684
	foreach ($srvifaces as $srviface) {
1685
		$cmd .= " -u \"{$srviface}\"";
1686
	}
1687
	mwexec($cmd);
1688
	unset($cmd);
1689

    
1690
	return 0;
1691
}
1692

    
1693
function services_dyndns_configure_client($conf) {
1694

    
1695
	if (!isset($conf['enable'])) {
1696
		return;
1697
	}
1698

    
1699
	/* load up the dyndns.class */
1700
	require_once("dyndns.class");
1701

    
1702
	$dns = new updatedns($dnsService = $conf['type'],
1703
		$dnsHost = $conf['host'],
1704
		$dnsUser = $conf['username'],
1705
		$dnsPass = $conf['password'],
1706
		$dnsWildcard = $conf['wildcard'],
1707
		$dnsMX = $conf['mx'],
1708
		$dnsIf = "{$conf['interface']}",
1709
		$dnsBackMX = NULL,
1710
		$dnsServer = NULL,
1711
		$dnsPort = NULL,
1712
		$dnsUpdateURL = "{$conf['updateurl']}",
1713
		$forceUpdate = $conf['force'],
1714
		$dnsZoneID = $conf['zoneid'],
1715
		$dnsTTL = $conf['ttl'],
1716
		$dnsResultMatch = "{$conf['resultmatch']}",
1717
		$dnsRequestIf = "{$conf['requestif']}",
1718
		$dnsID = "{$conf['id']}",
1719
		$dnsVerboseLog = $conf['verboselog'],
1720
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1721
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1722
}
1723

    
1724
function services_dyndns_configure($int = "") {
1725
	global $config, $g;
1726
	if (isset($config['system']['developerspew'])) {
1727
		$mt = microtime();
1728
		echo "services_dyndns_configure() being called $mt\n";
1729
	}
1730

    
1731
	$dyndnscfg = $config['dyndnses']['dyndns'];
1732
	$gwgroups = return_gateway_groups_array();
1733
	if (is_array($dyndnscfg)) {
1734
		if (platform_booting()) {
1735
			echo gettext("Starting DynDNS clients...");
1736
		}
1737

    
1738
		foreach ($dyndnscfg as $dyndns) {
1739
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1740
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1741
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1742
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1743
				services_dyndns_configure_client($dyndns);
1744
				sleep(1);
1745
			}
1746
		}
1747

    
1748
		if (platform_booting()) {
1749
			echo gettext("done.") . "\n";
1750
		}
1751
	}
1752

    
1753
	return 0;
1754
}
1755

    
1756
function dyndnsCheckIP($int) {
1757
	global $config;
1758
	$ip_address = get_interface_ip($int);
1759
	if (is_private_ip($ip_address)) {
1760
		$gateways_status = return_gateways_status(true);
1761
		// If the gateway for this interface is down, then the external check cannot work.
1762
		// Avoid the long wait for the external check to timeout.
1763
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
1764
			return "down";
1765
		}
1766
		$hosttocheck = "http://checkip.dyndns.org";
1767
		$ip_ch = curl_init($hosttocheck);
1768
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1769
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1770
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
1771
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1772
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1773
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1774
		$ip_result_page = curl_exec($ip_ch);
1775
		curl_close($ip_ch);
1776
		$ip_result_decoded = urldecode($ip_result_page);
1777
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1778
		$ip_address = trim($matches[1]);
1779
	}
1780
	return $ip_address;
1781
}
1782

    
1783
function services_dnsmasq_configure() {
1784
	global $config, $g;
1785
	$return = 0;
1786

    
1787
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1788
	$standard_args = array(
1789
		"dns-forward-max" => "--dns-forward-max=5000",
1790
		"cache-size" => "--cache-size=10000",
1791
		"local-ttl" => "--local-ttl=1"
1792
	);
1793

    
1794

    
1795
	if (isset($config['system']['developerspew'])) {
1796
		$mt = microtime();
1797
		echo "services_dnsmasq_configure() being called $mt\n";
1798
	}
1799

    
1800
	/* kill any running dnsmasq */
1801
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
1802
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1803
	}
1804

    
1805
	if (isset($config['dnsmasq']['enable'])) {
1806

    
1807
		if (platform_booting()) {
1808
			echo gettext("Starting DNS forwarder...");
1809
		} else {
1810
			sleep(1);
1811
		}
1812

    
1813
		/* generate hosts file */
1814
		if (system_hosts_generate() != 0) {
1815
			$return = 1;
1816
		}
1817

    
1818
		$args = "";
1819

    
1820
		if (isset($config['dnsmasq']['regdhcp'])) {
1821
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1822
		}
1823

    
1824
		/* Setup listen port, if non-default */
1825
		if (is_port($config['dnsmasq']['port'])) {
1826
			$args .= " --port={$config['dnsmasq']['port']} ";
1827
		}
1828

    
1829
		$listen_addresses = "";
1830
		if (isset($config['dnsmasq']['interface'])) {
1831
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1832
			foreach ($interfaces as $interface) {
1833
				if (is_ipaddrv4($interface)) {
1834
					$listen_addresses .= " --listen-address={$interface} ";
1835
				} else if (is_ipaddrv6($interface)) {
1836
					/*
1837
					 * XXX: Since dnsmasq does not support link-local address
1838
					 * with scope specified. These checks are being done.
1839
					 */
1840
					if (is_linklocal($interface) && strstr($interface, "%")) {
1841
						$tmpaddrll6 = explode("%", $interface);
1842
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1843
					} else {
1844
						$listen_addresses .= " --listen-address={$interface} ";
1845
					}
1846
				} else if (strstr($interface, "_vip")) {
1847
					$laddr = get_configured_carp_interface_list($interface);
1848
					if (is_ipaddr($laddr)) {
1849
						$listen_addresses .= " --listen-address={$laddr} ";
1850
					}
1851
				} else {
1852
					$if = get_real_interface($interface);
1853
					if (does_interface_exist($if)) {
1854
						$laddr = get_interface_ip($interface);
1855
						if (is_ipaddrv4($laddr)) {
1856
							$listen_addresses .= " --listen-address={$laddr} ";
1857
						}
1858
						$laddr6 = get_interface_ipv6($interface);
1859
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1860
							/*
1861
							 * XXX: Since dnsmasq does not support link-local address
1862
							 * with scope specified. These checks are being done.
1863
							 */
1864
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1865
								$tmpaddrll6 = explode("%", $laddr6);
1866
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1867
							} else {
1868
								$listen_addresses .= " --listen-address={$laddr6} ";
1869
							}
1870
						}
1871
					}
1872
				}
1873
			}
1874
			if (!empty($listen_addresses)) {
1875
				$args .= " {$listen_addresses} ";
1876
				if (isset($config['dnsmasq']['strictbind'])) {
1877
					$args .= " --bind-interfaces ";
1878
				}
1879
			}
1880
		}
1881

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

    
1889
			// Build an array of domain overrides to help in checking for matches.
1890
			$override_a = array();
1891
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1892
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1893
					$override_a[$override['domain']] = "y";
1894
				}
1895
			}
1896

    
1897
			// Build an array of the private reverse lookup domain names
1898
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
1899
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
1900
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
1901
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
1902
			}
1903

    
1904
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
1905
			foreach ($reverse_domain_a as $reverse_domain) {
1906
				if (!isset($override_a[$reverse_domain])) {
1907
					$args .= " --server=/$reverse_domain/ ";
1908
				}
1909
			}
1910
			unset($override_a);
1911
			unset($reverse_domain_a);
1912
		}
1913

    
1914
		/* Setup forwarded domains */
1915
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1916
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1917
				if ($override['ip'] == "!") {
1918
					$override[ip] = "";
1919
				}
1920
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1921
			}
1922
		}
1923

    
1924
		/* Allow DNS Rebind for forwarded domains */
1925
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1926
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1927
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1928
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1929
				}
1930
			}
1931
		}
1932

    
1933
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1934
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1935
		}
1936

    
1937
		if (isset($config['dnsmasq']['strict_order'])) {
1938
			$args .= " --strict-order ";
1939
		}
1940

    
1941
		if (isset($config['dnsmasq']['domain_needed'])) {
1942
			$args .= " --domain-needed ";
1943
		}
1944

    
1945
		if ($config['dnsmasq']['custom_options']) {
1946
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1947
				$args .= " " . escapeshellarg("--{$c}");
1948
				$p = explode('=', $c);
1949
				if (array_key_exists($p[0], $standard_args)) {
1950
					unset($standard_args[$p[0]]);
1951
				}
1952
			}
1953
		}
1954
		$args .= ' ' . implode(' ', array_values($standard_args));
1955

    
1956
		/* run dnsmasq */
1957
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1958
		//log_error("dnsmasq command: {$cmd}");
1959
		mwexec_bg($cmd);
1960
		unset($args);
1961

    
1962
		system_dhcpleases_configure();
1963

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

    
1969
	if (!platform_booting()) {
1970
		if (services_dhcpd_configure() != 0) {
1971
			$return = 1;
1972
		}
1973
	}
1974

    
1975
	return $return;
1976
}
1977

    
1978
function services_unbound_configure() {
1979
	global $config, $g;
1980
	$return = 0;
1981

    
1982
	if (isset($config['system']['developerspew'])) {
1983
		$mt = microtime();
1984
		echo "services_unbound_configure() being called $mt\n";
1985
	}
1986

    
1987
	// kill any running Unbound instance
1988
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
1989
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1990
	}
1991

    
1992
	if (isset($config['unbound']['enable'])) {
1993
		if (platform_booting()) {
1994
			echo gettext("Starting DNS Resolver...");
1995
		} else {
1996
			sleep(1);
1997
		}
1998

    
1999
		/* generate hosts file */
2000
		if (system_hosts_generate() != 0) {
2001
			$return = 1;
2002
		}
2003

    
2004
		require_once('/etc/inc/unbound.inc');
2005
		sync_unbound_service();
2006
		if (platform_booting()) {
2007
			echo gettext("done.") . "\n";
2008
		}
2009

    
2010
		system_dhcpleases_configure();
2011
	}
2012

    
2013
	if (!platform_booting()) {
2014
		if (services_dhcpd_configure() != 0) {
2015
			$return = 1;
2016
		}
2017
	}
2018

    
2019
	return $return;
2020
}
2021

    
2022
function services_snmpd_configure() {
2023
	global $config, $g;
2024
	if (isset($config['system']['developerspew'])) {
2025
		$mt = microtime();
2026
		echo "services_snmpd_configure() being called $mt\n";
2027
	}
2028

    
2029
	/* kill any running snmpd */
2030
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2031
	sleep(2);
2032
	if (is_process_running("bsnmpd")) {
2033
		mwexec("/usr/bin/killall bsnmpd", true);
2034
	}
2035

    
2036
	if (isset($config['snmpd']['enable'])) {
2037

    
2038
		if (platform_booting()) {
2039
			echo gettext("Starting SNMP daemon... ");
2040
		}
2041

    
2042
		/* generate snmpd.conf */
2043
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2044
		if (!$fd) {
2045
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2046
			return 1;
2047
		}
2048

    
2049

    
2050
		$snmpdconf = <<<EOD
2051
location := "{$config['snmpd']['syslocation']}"
2052
contact := "{$config['snmpd']['syscontact']}"
2053
read := "{$config['snmpd']['rocommunity']}"
2054

    
2055
EOD;
2056

    
2057
/* No docs on what write strings do there for disable for now.
2058
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2059
			$snmpdconf .= <<<EOD
2060
# write string
2061
write := "{$config['snmpd']['rwcommunity']}"
2062

    
2063
EOD;
2064
		}
2065
*/
2066

    
2067

    
2068
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2069
			$snmpdconf .= <<<EOD
2070
# SNMP Trap support.
2071
traphost := {$config['snmpd']['trapserver']}
2072
trapport := {$config['snmpd']['trapserverport']}
2073
trap := "{$config['snmpd']['trapstring']}"
2074

    
2075

    
2076
EOD;
2077
		}
2078

    
2079
		$platform = trim(file_get_contents('/etc/platform'));
2080
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2081
			$platform = $g['product_name'];
2082
		}
2083
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2084
			" {$g['product_version']} {$platform} " . php_uname("s") .
2085
			" " . php_uname("r") . " " . php_uname("m");
2086

    
2087
		$snmpdconf .= <<<EOD
2088
system := 1     # pfSense
2089
%snmpd
2090
sysDescr			= "{$sysDescr}"
2091
begemotSnmpdDebugDumpPdus       = 2
2092
begemotSnmpdDebugSyslogPri      = 7
2093
begemotSnmpdCommunityString.0.1 = $(read)
2094

    
2095
EOD;
2096

    
2097
/* No docs on what write strings do there for disable for now.
2098
		if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2099
			$snmpdconf .= <<<EOD
2100
begemotSnmpdCommunityString.0.2 = $(write)
2101

    
2102
EOD;
2103
		}
2104
*/
2105

    
2106

    
2107
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2108
			$snmpdconf .= <<<EOD
2109
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2110
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2111
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2112

    
2113
EOD;
2114
		}
2115

    
2116

    
2117
		$snmpdconf .= <<<EOD
2118
begemotSnmpdCommunityDisable    = 1
2119

    
2120
EOD;
2121

    
2122
		if (isset($config['snmpd']['bindlan'])) {
2123
			$config['snmpd']['bindip'] = 'lan';
2124
			unset($config['snmpd']['bindlan']);
2125
		}
2126
		$bind_to_ip = "0.0.0.0";
2127
		if (isset($config['snmpd']['bindip'])) {
2128
			if (is_ipaddr($config['snmpd']['bindip'])) {
2129
				$bind_to_ip = $config['snmpd']['bindip'];
2130
			} else {
2131
				$if = get_real_interface($config['snmpd']['bindip']);
2132
				if (does_interface_exist($if)) {
2133
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2134
				}
2135
			}
2136
		}
2137

    
2138
		if (is_port($config['snmpd']['pollport'])) {
2139
			$snmpdconf .= <<<EOD
2140
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2141

    
2142
EOD;
2143

    
2144
		}
2145

    
2146
		$snmpdconf .= <<<EOD
2147
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2148
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2149

    
2150
# These are bsnmp macros not php vars.
2151
sysContact      = $(contact)
2152
sysLocation     = $(location)
2153
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2154

    
2155
snmpEnableAuthenTraps = 2
2156

    
2157
EOD;
2158

    
2159
		if (is_array($config['snmpd']['modules'])) {
2160
			if (isset($config['snmpd']['modules']['mibii'])) {
2161
			$snmpdconf .= <<<EOD
2162
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2163

    
2164
EOD;
2165
			}
2166

    
2167
			if (isset($config['snmpd']['modules']['netgraph'])) {
2168
				$snmpdconf .= <<<EOD
2169
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2170
%netgraph
2171
begemotNgControlNodeName = "snmpd"
2172

    
2173
EOD;
2174
			}
2175

    
2176
			if (isset($config['snmpd']['modules']['pf'])) {
2177
				$snmpdconf .= <<<EOD
2178
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2179

    
2180
EOD;
2181
			}
2182

    
2183
			if (isset($config['snmpd']['modules']['hostres'])) {
2184
				/* XXX: hostres module crashes APU - ticket #4403 */
2185
				$specplatform = system_identify_specific_platform();
2186
				if ($specplatform['name'] == 'APU') {
2187
					log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
2188
				} else {
2189
					$snmpdconf .= <<<EOD
2190
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2191

    
2192
EOD;
2193
				}
2194
				unset($specplatform);
2195
			}
2196

    
2197
			if (isset($config['snmpd']['modules']['bridge'])) {
2198
				$snmpdconf .= <<<EOD
2199
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2200
# config must end with blank line
2201

    
2202
EOD;
2203
			}
2204
			if (isset($config['snmpd']['modules']['ucd'])) {
2205
				$snmpdconf .= <<<EOD
2206
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2207

    
2208
EOD;
2209
			}
2210
			if (isset($config['snmpd']['modules']['regex'])) {
2211
				$snmpdconf .= <<<EOD
2212
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2213

    
2214
EOD;
2215
			}
2216
		}
2217

    
2218
		fwrite($fd, $snmpdconf);
2219
		fclose($fd);
2220
		unset($snmpdconf);
2221

    
2222
		if (isset($config['snmpd']['bindlan'])) {
2223
			$bindlan = "";
2224
		}
2225

    
2226
		/* run bsnmpd */
2227
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2228
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2229

    
2230
		if (platform_booting()) {
2231
			echo gettext("done.") . "\n";
2232
		}
2233
	}
2234

    
2235
	return 0;
2236
}
2237

    
2238
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2239
	global $config, $g;
2240
	if (isset($config['system']['developerspew'])) {
2241
		$mt = microtime();
2242
		echo "services_dnsupdate_process() being called $mt\n";
2243
	}
2244

    
2245
	/* Dynamic DNS updating active? */
2246
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2247
		$notify_text = "";
2248
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2249
			if (!isset($dnsupdate['enable'])) {
2250
				continue;
2251
			}
2252
			if (!empty($int) && $int != $dnsupdate['interface']) {
2253
				continue;
2254
			}
2255
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2256
				continue;
2257
			}
2258

    
2259
			/* determine interface name */
2260
			$if = get_real_interface($dnsupdate['interface']);
2261

    
2262
			if (isset($dnsupdate['usepublicip'])) {
2263
				$wanip = dyndnsCheckIP($dnsupdate['interface']);
2264
			} else {
2265
				$wanip = get_interface_ip($dnsupdate['interface']);
2266
			}
2267

    
2268
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2269
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2270
			$currentTime = time();
2271

    
2272
			if ($wanip || $wanipv6) {
2273
				$keyname = $dnsupdate['keyname'];
2274
				/* trailing dot */
2275
				if (substr($keyname, -1) != ".") {
2276
					$keyname .= ".";
2277
				}
2278

    
2279
				$hostname = $dnsupdate['host'];
2280
				/* trailing dot */
2281
				if (substr($hostname, -1) != ".") {
2282
					$hostname .= ".";
2283
				}
2284

    
2285
				/* write private key file
2286
				   this is dumb - public and private keys are the same for HMAC-MD5,
2287
				   but nsupdate insists on having both */
2288
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2289
				$privkey = <<<EOD
2290
Private-key-format: v1.2
2291
Algorithm: 157 (HMAC)
2292
Key: {$dnsupdate['keydata']}
2293

    
2294
EOD;
2295
				fwrite($fd, $privkey);
2296
				fclose($fd);
2297

    
2298
				/* write public key file */
2299
				if ($dnsupdate['keytype'] == "zone") {
2300
					$flags = 257;
2301
					$proto = 3;
2302
				} else if ($dnsupdate['keytype'] == "host") {
2303
					$flags = 513;
2304
					$proto = 3;
2305
				} else if ($dnsupdate['keytype'] == "user") {
2306
					$flags = 0;
2307
					$proto = 2;
2308
				}
2309

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

    
2314
				/* generate update instructions */
2315
				$upinst = "";
2316
				if (!empty($dnsupdate['server'])) {
2317
					$upinst .= "server {$dnsupdate['server']}\n";
2318
				}
2319

    
2320
				if (file_exists($cacheFile)) {
2321
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2322
				}
2323
				if (file_exists("{$cacheFile}.ipv6")) {
2324
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2325
				}
2326

    
2327
				// 25 Days
2328
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2329
				$need_update = false;
2330

    
2331
				conf_mount_rw();
2332
				/* Update IPv4 if we have it. */
2333
				if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
2334
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2335
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2336
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2337
						$notify_text .= sprintf(gettext("DynDNS updated IP Address (A) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n";
2338
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2339
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2340
						$need_update = true;
2341
					} else {
2342
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2343
					}
2344
				} else {
2345
					@unlink($cacheFile);
2346
				}
2347

    
2348
				/* Update IPv6 if we have it. */
2349
				if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
2350
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2351
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2352
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2353
						$notify_text .= sprintf(gettext("DynDNS updated IPv6 Address (AAAA) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n";
2354
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2355
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2356
						$need_update = true;
2357
					} else {
2358
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2359
					}
2360
				} else {
2361
					@unlink("{$cacheFile}.ipv6");
2362
				}
2363
				conf_mount_ro();
2364

    
2365
				$upinst .= "\n";	/* mind that trailing newline! */
2366

    
2367
				if ($need_update) {
2368
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2369
					unset($upinst);
2370
					/* invoke nsupdate */
2371
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2372
					if (isset($dnsupdate['usetcp'])) {
2373
						$cmd .= " -v";
2374
					}
2375
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2376
					mwexec_bg($cmd);
2377
					unset($cmd);
2378
				}
2379
			}
2380
		}
2381
		if (!empty($notify_text)) {
2382
			notify_all_remote($notify_text);
2383
		}
2384
	}
2385

    
2386
	return 0;
2387
}
2388

    
2389
/* configure cron service */
2390
function configure_cron() {
2391
	global $g, $config;
2392

    
2393
	conf_mount_rw();
2394
	/* preserve existing crontab entries */
2395
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2396

    
2397
	for ($i = 0; $i < count($crontab_contents); $i++) {
2398
		$cron_item =& $crontab_contents[$i];
2399
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2400
			array_splice($crontab_contents, $i - 1);
2401
			break;
2402
		}
2403
	}
2404
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2405

    
2406

    
2407
	if (is_array($config['cron']['item'])) {
2408
		$crontab_contents .= "#\n";
2409
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2410
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2411
		$crontab_contents .= "#\n";
2412

    
2413
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2414
			$http_proxy = $config['system']['proxyurl'];
2415
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2416
				$http_proxy .= ':' . $config['system']['proxyport'];
2417
			}
2418
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2419
		}
2420

    
2421
		foreach ($config['cron']['item'] as $item) {
2422
			$crontab_contents .= "\n{$item['minute']}\t";
2423
			$crontab_contents .= "{$item['hour']}\t";
2424
			$crontab_contents .= "{$item['mday']}\t";
2425
			$crontab_contents .= "{$item['month']}\t";
2426
			$crontab_contents .= "{$item['wday']}\t";
2427
			$crontab_contents .= "{$item['who']}\t";
2428
			$crontab_contents .= "{$item['command']}";
2429
		}
2430

    
2431
		$crontab_contents .= "\n#\n";
2432
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2433
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2434
		$crontab_contents .= "#\n\n";
2435
	}
2436

    
2437
	/* please maintain the newline at the end of file */
2438
	file_put_contents("/etc/crontab", $crontab_contents);
2439
	unset($crontab_contents);
2440

    
2441
	/* make sure that cron is running and start it if it got killed somehow */
2442
	if (!is_process_running("cron")) {
2443
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2444
	} else {
2445
	/* do a HUP kill to force sync changes */
2446
	sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2447
	}
2448

    
2449
	conf_mount_ro();
2450
}
2451

    
2452
function upnp_action ($action) {
2453
	global $g, $config;
2454
	switch ($action) {
2455
		case "start":
2456
			if (file_exists('/var/etc/miniupnpd.conf')) {
2457
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2458
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2459
			}
2460
			break;
2461
		case "stop":
2462
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2463
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2464
				mwexec('killall miniupnpd 2>/dev/null', true);
2465
			}
2466
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2467
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2468
			break;
2469
		case "restart":
2470
			upnp_action('stop');
2471
			upnp_action('start');
2472
			break;
2473
	}
2474
}
2475

    
2476
function upnp_start() {
2477
	global $config;
2478

    
2479
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2480
		return;
2481
	}
2482

    
2483
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2484
		echo gettext("Starting UPnP service... ");
2485
		require_once('/usr/local/pkg/miniupnpd.inc');
2486
		sync_package_miniupnpd();
2487
		echo "done.\n";
2488
	}
2489
}
2490

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

    
2494
	$is_installed = false;
2495
	$cron_changed = true;
2496

    
2497
	if (!is_array($config['cron'])) {
2498
		$config['cron'] = array();
2499
	}
2500
	if (!is_array($config['cron']['item'])) {
2501
		$config['cron']['item'] = array();
2502
	}
2503

    
2504
	$x = 0;
2505
	foreach ($config['cron']['item'] as $item) {
2506
		if (strstr($item['command'], $command)) {
2507
			$is_installed = true;
2508
			break;
2509
		}
2510
		$x++;
2511
	}
2512

    
2513
	if ($active) {
2514
		$cron_item = array();
2515
		$cron_item['minute'] = $minute;
2516
		$cron_item['hour'] = $hour;
2517
		$cron_item['mday'] = $monthday;
2518
		$cron_item['month'] = $month;
2519
		$cron_item['wday'] = $weekday;
2520
		$cron_item['who'] = $who;
2521
		$cron_item['command'] = $command;
2522
		if (!$is_installed) {
2523
			$config['cron']['item'][] = $cron_item;
2524
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2525
		} else {
2526
			if ($config['cron']['item'][$x] == $cron_item) {
2527
				$cron_changed = false;
2528
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2529
			} else {
2530
				$config['cron']['item'][$x] = $cron_item;
2531
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2532
			}
2533
		}
2534
	} else {
2535
		if ($is_installed == true) {
2536
			unset($config['cron']['item'][$x]);
2537
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2538
		}
2539
	}
2540

    
2541
	if ($cron_changed) {
2542
		configure_cron();
2543
	}
2544
}
2545

    
2546
?>
(50-50/68)