Project

General

Profile

Download (80.1 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 Luci
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 dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns 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,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,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 ($g['platform'] == 'jail') 
49
		return;
50

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

    
56
	if (!is_array($config['dhcpdv6']))
57
		$config['dhcpdv6'] = array();
58

    
59
	$Iflist = get_configured_interface_list();
60
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
61
	$carplist = get_configured_carp_interface_list();
62

    
63
	$radvdconf = "# Automatically Generated, do not edit\n";
64

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

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

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

    
81
		/* are router advertisements enabled? */
82
		if ($dhcpv6ifconf['ramode'] == "disabled")
83
			continue;
84

    
85
		if (!isset($dhcpv6ifconf['rapriority']))
86
			$dhcpv6ifconf['rapriority'] = "medium";
87

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

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

    
111
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
112
		if (!is_ipaddrv6($ifcfgipv6))
113
			continue;
114

    
115
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
116
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
117
		$radvdifs[$realif] = $realif;
118

    
119
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
120
		$radvdconf .= "interface {$realif} {\n";
121
		if (strstr($realif, "ovpn")) {
122
			$radvdconf .= "\tUnicastOnly on;\n";
123
		}
124
		$radvdconf .= "\tAdvSendAdvert on;\n";
125
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
126
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
127
		$mtu = get_interface_mtu($realif);
128
		if (is_numeric($mtu))
129
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
130
		else
131
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
132

    
133
		switch($dhcpv6ifconf['rapriority']) {
134
			case "low":
135
				$radvdconf .= "\tAdvDefaultPreference low;\n";
136
				break;
137
			case "high":
138
				$radvdconf .= "\tAdvDefaultPreference high;\n";
139
				break;
140
			default:
141
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
142
				break;
143
		}
144
		switch($dhcpv6ifconf['ramode']) {
145
			case "managed":
146
			case "assist":
147
				$radvdconf .= "\tAdvManagedFlag on;\n";
148
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
149
				break;
150
		}
151
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
152
		if($carpif == true) {
153
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
154
		} else {
155
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
156
		}
157
		switch($dhcpv6ifconf['ramode']) {
158
			case "managed":
159
				$radvdconf .= "\t\tAdvOnLink on;\n";
160
				$radvdconf .= "\t\tAdvAutonomous off;\n";
161
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
162
				break;
163
			case "router":
164
				$radvdconf .= "\t\tAdvOnLink off;\n";
165
				$radvdconf .= "\t\tAdvAutonomous off;\n";
166
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
167
				break;
168
			case "assist":
169
				$radvdconf .= "\t\tAdvOnLink on;\n";
170
				$radvdconf .= "\t\tAdvAutonomous on;\n";
171
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
172
				break;
173
			case "unmanaged":
174
				$radvdconf .= "\t\tAdvOnLink on;\n";
175
				$radvdconf .= "\t\tAdvAutonomous on;\n";
176
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
177
				break;				
178
		}
179
		$radvdconf .= "\t};\n";
180

    
181
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
182
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
183
				if (is_subnetv6($subnet)) {
184
					$radvdconf .= "\tprefix {$subnet} {\n";
185
					if($carpif == true) {
186
						$radvdconf .= "\t\tDeprecatePrefix off;\n";
187
					} else {
188
						$radvdconf .= "\t\tDeprecatePrefix on;\n";
189
					}
190
					switch($dhcpv6ifconf['ramode']) {
191
						case "managed":
192
							$radvdconf .= "\t\tAdvOnLink on;\n";
193
							$radvdconf .= "\t\tAdvAutonomous off;\n";
194
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
195
							break;
196
						case "router":
197
							$radvdconf .= "\t\tAdvOnLink off;\n";
198
							$radvdconf .= "\t\tAdvAutonomous off;\n";
199
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
200
							break;
201
						case "assist":
202
							$radvdconf .= "\t\tAdvOnLink on;\n";
203
							$radvdconf .= "\t\tAdvAutonomous on;\n";
204
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
205
							break;
206
						case "unmanaged":
207
							$radvdconf .= "\t\tAdvOnLink on;\n";
208
							$radvdconf .= "\t\tAdvAutonomous on;\n";
209
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
210
							break;				
211
					}
212
					$radvdconf .= "\t};\n";
213
				}
214
			}
215
		}
216
		if($carpif === true) {
217
			$radvdconf .= "\troute ::/0 {\n";
218
			$radvdconf .= "\t\tRemoveRoute off;\n";
219
			$radvdconf .= "\t};\n";
220
		} else {
221
			$radvdconf .= "\troute ::/0 {\n";
222
			$radvdconf .= "\t\tRemoveRoute on;\n";
223
			$radvdconf .= "\t};\n";
224
		}
225

    
226
		/* add DNS servers */
227
		$dnslist = array();
228
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
229
			foreach($dhcpv6ifconf['dnsserver'] as $server)
230
				if (is_ipaddrv6($server))
231
					$dnslist[] = $server;
232
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
233
			foreach($dhcpv6ifconf['radnsserver'] as $server)
234
				if (is_ipaddrv6($server))
235
					$dnslist[] = $server;
236
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
237
			$dnslist[] = get_interface_ipv6($realif);
238
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
239
			foreach($config['system']['dnsserver'] as $server) {
240
				if (is_ipaddrv6($server))
241
					$dnslist[] = $server;
242
			}
243
		}
244
		if (count($dnslist) > 0) {
245
			$dnsstring = implode(" ", $dnslist);
246
			if ($dnsstring <> "")
247
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
248
		}
249
		if (!empty($dhcpv6ifconf['domain'])) {
250
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
251
		} elseif (!empty($config['system']['domain'])) {
252
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
253
		}
254
		$radvdconf .= "};\n";
255
	}
256

    
257
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
258
	foreach ($Iflist as $if => $ifdescr) {
259
		if(!isset($config['interfaces'][$if]['track6-interface']))
260
			continue;
261
		if(!isset($config['interfaces'][$if]['enable']))
262
			continue;
263
		/* Do not put in the config an interface which is down */
264
		if (isset($blacklist[$if]))
265
			continue;
266
		$trackif = $config['interfaces'][$if]['track6-interface'];
267
		if (empty($config['interfaces'][$trackif]))
268
			continue;
269

    
270
		if (strstr($if, "_vip")) {
271
			// CARP IP, find parent
272
			$ifparent = link_carp_interface_to_parent($if);
273
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
274
		} else {
275
			$realif = get_real_interface($if, "inet6");
276
		}
277
		
278
		/* prevent duplicate entries, manual overrides */
279
		if (isset($radvdifs[$realif]))
280
			continue;
281

    
282
		$ifcfgipv6 = get_interface_ipv6($if);
283
		if(!is_ipaddrv6($ifcfgipv6)) {
284
			$subnetv6 = "::";
285
			$ifcfgsnv6 = "64";
286
		} else {
287
			$ifcfgsnv6 = get_interface_subnetv6($if);
288
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
289
		}
290
		$radvdifs[$realif] = $realif;
291

    
292
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
293
	
294
		if ($g['debug'])
295
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
296

    
297
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
298
		$radvdconf .= "interface {$realif} {\n";
299
		$radvdconf .= "\tAdvSendAdvert on;\n";
300
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
301
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
302
		$mtu = get_interface_mtu($realif);
303
		if (is_numeric($mtu))
304
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
305
		else
306
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
307
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
308
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
309
		$radvdconf .= "\t\tAdvOnLink on;\n";
310
		$radvdconf .= "\t\tAdvAutonomous on;\n";
311
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
312
		$radvdconf .= "\t};\n";
313

    
314
		/* add DNS servers */
315
		$dnslist = array();
316
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
317
			$dnslist[] = $ifcfgipv6;
318
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
319
			foreach($config['system']['dnsserver'] as $server) {
320
				if(is_ipaddrv6($server))
321
					$dnslist[] = $server;
322
			}
323
		}
324
		if (count($dnslist) > 0) {
325
			$dnsstring = implode(" ", $dnslist);
326
			if (!empty($dnsstring))
327
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
328
		}
329
		if (!empty($config['system']['domain'])) {
330
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
331
		}
332
		$radvdconf .= "};\n";
333
	}
334

    
335
	/* write radvd.conf */
336
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
337
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
338
		if (platform_booting())
339
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
340
	}
341
	unset($radvdconf);
342

    
343
	if (count($radvdifs) > 0) {
344
		if (isvalidpid("{$g['varrun_path']}/radvd.pid"))
345
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
346
		else
347
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
348
	} else {
349
		/* we need to shut down the radvd cleanly, it will send out the prefix
350
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
351
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
352
			log_error("Shutting down Router Advertisment daemon cleanly");
353
			killbypid("{$g['varrun_path']}/radvd.pid");
354
			@unlink("{$g['varrun_path']}/radvd.pid");
355
		}
356
	}
357
	return 0;
358
}
359

    
360
function services_dhcpd_configure($family = "all", $blacklist = array()) {
361
	global $config, $g;
362

    
363
	/* configure DHCPD chroot once */
364
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
365
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
366
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
367
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
368
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
369
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
370
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
371
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
372
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
373
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
374
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
375
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
376
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
377
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
378

    
379
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
380
	if (!trim($status))
381
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
382
	fclose($fd);
383
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
384

    
385
	if ($family == "all" || $family == "inet")
386
		services_dhcpdv4_configure();
387
	if ($family == "all" || $family == "inet6") {
388
		services_dhcpdv6_configure($blacklist);
389
		services_radvd_configure($blacklist);
390
	}
391
}
392

    
393
function services_dhcpdv4_configure() {
394
	global $config, $g;
395
	$need_ddns_updates = false;
396
	$ddns_zones = array();
397

    
398
	if($g['services_dhcp_server_enable'] == false)
399
		return;
400

    
401
	if(isset($config['system']['developerspew'])) {
402
		$mt = microtime();
403
		echo "services_dhcpdv4_configure($if) being called $mt\n";
404
	}
405

    
406
	/* kill any running dhcpd */
407
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
408
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
409

    
410
	/* DHCP enabled on any interfaces? */
411
	if (!is_dhcp_server_enabled())
412
		return 0;
413

    
414
	/* if OLSRD is enabled, allow WAN to house DHCP. */
415
	if (!function_exists('is_package_installed'))
416
		require_once('pkg-utils.inc');
417
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd']))
418
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
419
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
420
				$is_olsr_enabled = true;
421
				break;
422
			}
423

    
424
	if (platform_booting()) {
425
		/* restore the leases, if we have them */
426
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
427
			$dhcprestore = "";
428
			$dhcpreturn = "";
429
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
430
			$dhcprestore = implode(" ", $dhcprestore);
431
			if($dhcpreturn <> 0) {
432
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
433
			}
434
		}
435
		/* 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. */
436
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
437
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
438
		}
439
	}
440

    
441
	$syscfg = $config['system'];
442
	if (!is_array($config['dhcpd']))
443
		$config['dhcpd'] = array();
444
	$dhcpdcfg = $config['dhcpd'];
445
	$Iflist = get_configured_interface_list();
446

    
447
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
448
	$dns_arrv4 = array();
449
	if (is_array($syscfg['dnsserver'])) {
450
		foreach($syscfg['dnsserver'] as $dnsserver) {
451
			if (is_ipaddrv4($dnsserver)) {
452
				$dns_arrv4[] = $dnsserver;
453
			}
454
		}
455
	}
456

    
457
	if (platform_booting())
458
		echo gettext("Starting DHCP service...");
459
	else
460
		sleep(1);
461

    
462
	$custoptions = "";
463
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
464
		if(is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
465
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
466
				if(!empty($item['type']))
467
					$itemtype = $item['type'];
468
				else
469
					$itemtype = "text";
470
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
471
			}
472
		}
473
	}
474

    
475
	$dhcpdconf = <<<EOD
476

    
477
option domain-name "{$syscfg['domain']}";
478
option ldap-server code 95 = text;
479
option domain-search-list code 119 = text;
480
option arch code 93 = unsigned integer 16; # RFC4578
481
{$custoptions}
482
default-lease-time 7200;
483
max-lease-time 86400;
484
log-facility local7;
485
one-lease-per-client true;
486
deny duplicates;
487
ping-check true;
488
update-conflict-detection false;
489

    
490
EOD;
491

    
492
	if(!isset($dhcpifconf['disableauthoritative']))
493
		$dhcpdconf .= "authoritative;\n";
494

    
495
	if(isset($dhcpifconf['alwaysbroadcast']))
496
		$dhcpdconf .= "always-broadcast on\n";
497

    
498
	$dhcpdifs = array();
499
	$enable_add_routers = false;
500
	$gateways_arr = return_gateways_array();
501
	/* only add a routers line if the system has any IPv4 gateway at all */
502
	/* a static route has a gateway, manually overriding this field always works */
503
	foreach($gateways_arr as $gwitem) {
504
		if($gwitem['ipprotocol'] == "inet") {
505
			$enable_add_routers = true;
506
			break;
507
		}
508
	}
509

    
510
	/*    loop through and determine if we need to setup
511
	 *    failover peer "bleh" entries
512
	 */
513
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
514

    
515
		if (!isset($config['interfaces'][$dhcpif]['enable']))
516
			continue;
517

    
518
		interfaces_staticarp_configure($dhcpif);
519

    
520
		if (!isset($dhcpifconf['enable']))
521
			continue;
522

    
523
		if($dhcpifconf['failover_peerip'] <> "") {
524
			$intip = get_interface_ip($dhcpif);
525
			/*
526
			 *    yep, failover peer is defined.
527
			 *    does it match up to a defined vip?
528
			 */
529
			$skew = 110;
530
			if(is_array($config['virtualip']['vip'])) {
531
				foreach ($config['virtualip']['vip'] as $vipent) {
532
					if($vipent['interface'] == $dhcpif) {
533
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
534
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
535
							/* this is the interface! */
536
							if(is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
537
								$skew = 0;
538
								break;
539
							}
540
						}
541
					}
542
				}
543
			} else {
544
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
545
			}
546
			if($skew > 10) {
547
				$type = "secondary";
548
				$my_port = "520";
549
				$peer_port = "519";
550
			} else {
551
				$my_port = "519";
552
				$peer_port = "520";
553
				$type = "primary";
554
				$dhcpdconf_pri  = "split 128;\n";
555
				$dhcpdconf_pri .= "  mclt 600;\n";
556
			}
557

    
558
			if (is_ipaddrv4($intip)) {
559
			$dhcpdconf .= <<<EOPP
560
failover peer "dhcp_{$dhcpif}" {
561
  {$type};
562
  address {$intip};
563
  port {$my_port};
564
  peer address {$dhcpifconf['failover_peerip']};
565
  peer port {$peer_port};
566
  max-response-delay 10;
567
  max-unacked-updates 10;
568
  {$dhcpdconf_pri}
569
  load balance max seconds 3;
570
}
571
\n
572
EOPP;
573
			}
574
		}
575
	}
576

    
577
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
578

    
579
		$newzone = array();
580
		$ifcfg = $config['interfaces'][$dhcpif];
581

    
582
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
583
			continue;
584
		$ifcfgip = get_interface_ip($dhcpif);
585
		$ifcfgsn = get_interface_subnet($dhcpif);
586
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
587
		$subnetmask = gen_subnet_mask($ifcfgsn);
588

    
589
		if (!is_ipaddr($subnet))
590
			continue;
591

    
592
		if($is_olsr_enabled == true)
593
			if($dhcpifconf['netmask'])
594
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
595

    
596
		$all_pools = array();
597
		$all_pools[] = $dhcpifconf;
598
		if (is_array($dhcpifconf['pool'])) {
599
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
600
		}
601

    
602
		$dnscfg = "";
603

    
604
		if ($dhcpifconf['domain']) {
605
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
606
		}
607

    
608
		if($dhcpifconf['domainsearchlist'] <> "") {
609
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
610
		}
611

    
612
		if (isset($dhcpifconf['ddnsupdate'])) {
613
			$need_ddns_updates = true;
614
			$newzone = array();
615
			if($dhcpifconf['ddnsdomain'] <> "") {
616
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
617
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
618
			} else {
619
				$newzone['domain-name'] = $config['system']['domain'];
620
			}
621
			$revsubnet = explode(".", $subnet);
622
			$revsubnet = array_reverse($revsubnet);
623
			foreach ($revsubnet as $octet) {
624
				if ($octet != "0")
625
					break;
626
				array_shift($revsubnet);
627
			}
628
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
629
		}
630

    
631
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
632
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
633
			if ($newzone['domain-name'])
634
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
635
		} else if (isset($config['dnsmasq']['enable'])) {
636
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
637
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
638
				$newzone['dns-servers'] = $syscfg['dnsserver'];
639
		} else if (isset($config['unbound']['enable'])) {
640
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
641
		} else if (!empty($dns_arrv4)) {
642
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
643
			if ($newzone['domain-name'])
644
				$newzone['dns-servers'] = $dns_arrv4;
645
		}
646

    
647
		/* Create classes - These all contain comma separated lists. Join them into one 
648
		   big comma separated string then split them all up. */
649
		$all_mac_strings = array();
650
		if (is_array($dhcpifconf['pool'])) {
651
			foreach($all_pools as $poolconf) {
652
				$all_mac_strings[] = $poolconf['mac_allow'];
653
				$all_mac_strings[] = $poolconf['mac_deny'];
654
			}
655
		}
656
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
657
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
658
		$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
659
		foreach ($all_mac_list as $mac) {
660
			if (empty($mac))
661
				continue;
662
			$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
663
			// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
664
			$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
665
			$dhcpdconf .= '}' . "\n";
666
		}
667

    
668
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
669

    
670
// Setup pool options
671
		foreach($all_pools as $poolconf) {
672
			$dhcpdconf .= "	pool {\n";
673
			/* is failover dns setup? */
674
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
675
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
676
				if($poolconf['dnsserver'][1] <> "")
677
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
678
				if($poolconf['dnsserver'][2] <> "")
679
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
680
				if($poolconf['dnsserver'][3] <> "")
681
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
682
				$dhcpdconf .= ";\n";
683
			}
684

    
685
			/* allow/deny MACs */
686
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
687
			foreach ($mac_allow_list as $mac) {
688
				if (empty($mac))
689
					continue;
690
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
691
			}
692
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
693
			foreach ($mac_deny_list as $mac) {
694
				if (empty($mac))
695
					continue;
696
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
697
			}
698

    
699
			if($poolconf['failover_peerip'] <> "")
700
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
701

    
702
			if (isset($poolconf['denyunknown']))
703
			   $dhcpdconf .= "		deny unknown-clients;\n";
704

    
705
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway']))
706
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
707

    
708
			if($dhcpifconf['failover_peerip'] <> "") {
709
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
710
			}
711

    
712
			$pdnscfg = "";
713

    
714
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
715
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
716
			}
717

    
718
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
719
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
720
			}
721

    
722
			if (isset($poolconf['ddnsupdate'])) {
723
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
724
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
725
				$pdnscfg .= "		ddns-update-style interim;\n";
726
			}
727

    
728
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
729
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
730
			}
731
			$dhcpdconf .= "{$pdnscfg}";
732

    
733
			// default-lease-time
734
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
735
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
736

    
737
			// max-lease-time
738
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
739
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
740

    
741
			// netbios-name*
742
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
743
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
744
				$dhcpdconf .= "		option netbios-node-type 8;\n";
745
			}
746

    
747
			// ntp-servers
748
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
749
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
750

    
751
			// tftp-server-name
752
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
753
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
754

    
755
			// ldap-server
756
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
757
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
758

    
759
			// net boot information
760
			if(isset($poolconf['netboot'])) {
761
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
762
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
763
				}
764
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
765
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
766
				}
767
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
768
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
769
				}
770
			}
771
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
772
			$dhcpdconf .= "	}\n\n";
773
		}
774
// End of settings inside pools
775

    
776
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
777
			$routers = $dhcpifconf['gateway'];
778
			$add_routers = true;
779
		} elseif ($dhcpifconf['gateway'] == "none") {
780
			$add_routers = false;
781
		} else {
782
			$add_routers = $enable_add_routers;
783
			$routers = $ifcfgip;
784
		}
785
		if($add_routers)
786
			$dhcpdconf .= "	option routers {$routers};\n";
787

    
788
		$dhcpdconf .= <<<EOD
789
$dnscfg
790

    
791
EOD;
792
    		// default-lease-time
793
		if ($dhcpifconf['defaultleasetime'])
794
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
795

    
796
		// max-lease-time
797
		if ($dhcpifconf['maxleasetime'])
798
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
799

    
800
		// netbios-name*
801
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
802
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
803
			$dhcpdconf .= "	option netbios-node-type 8;\n";
804
		}
805

    
806
		// ntp-servers
807
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
808
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
809

    
810
		// tftp-server-name
811
		if ($dhcpifconf['tftp'] <> "")
812
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
813

    
814
		// Handle option, number rowhelper values
815
		$dhcpdconf .= "\n";
816
		if($dhcpifconf['numberoptions']['item']) {
817
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
818
				if(empty($item['type']) || $item['type'] == "text")
819
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
820
				else
821
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
822
			}
823
		}
824

    
825
		// ldap-server
826
		if ($dhcpifconf['ldap'] <> "")
827
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
828

    
829
		// net boot information
830
		if(isset($dhcpifconf['netboot'])) {
831
			if ($dhcpifconf['nextserver'] <> "") {
832
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
833
			}
834
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
835
				$dhcpdconf .= "	if option arch = 00:06 {\n";
836
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
837
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
838
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
839
				$dhcpdconf .= "	} else {\n";
840
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
841
				$dhcpdconf .= "	}\n\n";
842
			} elseif (!empty($dhcpifconf['filename'])) {
843
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
844
			}
845
			if (!empty($dhcpifconf['rootpath'])) {
846
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
847
			}
848
		}
849

    
850
		$dhcpdconf .= <<<EOD
851
}
852

    
853
EOD;
854

    
855
		/* add static mappings */
856
		if (is_array($dhcpifconf['staticmap'])) {
857

    
858
			$i = 0;
859
			foreach ($dhcpifconf['staticmap'] as $sm) {
860
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
861

    
862
                if ($sm['mac'])
863
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
864

    
865
                if ($sm['cid'])
866
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
867

    
868
				if ($sm['ipaddr'])
869
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
870

    
871
				if ($sm['hostname']) {
872
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
873
					$dhhostname = str_replace(".", "_", $dhhostname);
874
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
875
				}
876
				if ($sm['filename'])
877
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
878

    
879
				if ($sm['rootpath'])
880
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
881

    
882
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
883
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
884

    
885
				$smdnscfg = "";
886

    
887
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
888
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
889
				}
890

    
891
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
892
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
893
				}
894

    
895
				if (isset($sm['ddnsupdate'])) {
896
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
897
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
898
					$pdnscfg .= "		ddns-update-style interim;\n";
899
				}
900

    
901
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
902
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
903
				}
904
				$dhcpdconf .= "{$smdnscfg}";
905

    
906
				// default-lease-time
907
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
908
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
909

    
910
				// max-lease-time
911
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
912
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
913

    
914
				// netbios-name*
915
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
916
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
917
					$dhcpdconf .= "	option netbios-node-type 8;\n";
918
				}
919

    
920
				// ntp-servers
921
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
922
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
923

    
924
				// tftp-server-name
925
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
926
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
927

    
928
				$dhcpdconf .= "}\n";
929
				$i++;
930
			}
931
		}
932

    
933
		$dhcpdifs[] = get_real_interface($dhcpif);
934
		if ($newzone['domain-name'])
935
		{
936
			if ($need_ddns_updates)
937
			{
938
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
939
			}
940
			$ddns_zones[] = $newzone;
941
		}
942
	}
943

    
944
	if ($need_ddns_updates) {
945
		$dhcpdconf .= "ddns-update-style interim;\n";
946
		$dhcpdconf .= "update-static-leases on;\n";
947

    
948
		$dhcpdconf .= dhcpdkey($dhcpifconf);
949
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
950
	}
951

    
952
	/* write dhcpd.conf */
953
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
954
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
955
		unset($dhcpdconf);
956
		return 1;
957
	}
958
	unset($dhcpdconf);
959

    
960
	/* create an empty leases database */
961
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
962
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
963

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

    
968
	/* fire up dhcpd in a chroot */
969
	if (count($dhcpdifs) > 0) {
970
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
971
			join(" ", $dhcpdifs));
972
	}
973

    
974
	if (platform_booting())
975
		print "done.\n";
976

    
977
	return 0;
978
}
979

    
980
function dhcpdkey($dhcpifconf)
981
{
982
	$dhcpdconf = "";
983
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
984
	{
985
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
986
		$dhcpdconf .= "	algorithm hmac-md5;\n";
987
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
988
		$dhcpdconf .= "}\n";
989
	}
990

    
991
	return $dhcpdconf;
992
}
993

    
994
function dhcpdzones($ddns_zones, $dhcpifconf)
995
{
996
	$dhcpdconf = "";
997

    
998
	if (is_array($ddns_zones)) {
999
		$added_zones = array();
1000
		foreach ($ddns_zones as $zone) {
1001
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
1002
				continue;
1003
			$primary = $zone['dns-servers'][0];
1004
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1005

    
1006
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1007
			if (!is_ipaddrv4($primary)) {
1008
				if (is_ipaddrv4($secondary)) {
1009
					$primary = $secondary;
1010
					$secondary = "";
1011
				} else {
1012
					continue;
1013
				}
1014
			}
1015

    
1016
			// We don't need to add zones multiple times.
1017
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1018
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1019
				$dhcpdconf .= "	primary {$primary};\n";
1020
				if (is_ipaddrv4($secondary))
1021
					$dhcpdconf .= "	secondary {$secondary};\n";
1022
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
1023
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1024
				$dhcpdconf .= "}\n";
1025
				$added_zones[] = $zone['domain-name'];
1026
			}
1027
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1028
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1029
				$dhcpdconf .= "	primary {$primary};\n";
1030
				if (is_ipaddrv4($secondary))
1031
					$dhcpdconf .= "	secondary {$secondary};\n";
1032
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
1033
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1034
				$dhcpdconf .= "}\n";
1035
				$added_zones[] = $zone['ptr-domain'];
1036
			}
1037
		}
1038
	}
1039

    
1040
	return $dhcpdconf;
1041
}
1042

    
1043
function services_dhcpdv6_configure($blacklist = array()) {
1044
	global $config, $g;
1045

    
1046
	if($g['services_dhcp_server_enable'] == false)
1047
		return;
1048

    
1049
	if(isset($config['system']['developerspew'])) {
1050
		$mt = microtime();
1051
		echo "services_dhcpd_configure($if) being called $mt\n";
1052
	}
1053

    
1054
	/* kill any running dhcpd */
1055
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
1056
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1057
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
1058
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1059

    
1060
	/* DHCP enabled on any interfaces? */
1061
	if (!is_dhcpv6_server_enabled())
1062
		return 0;
1063

    
1064
	if (platform_booting()) {
1065
		if ($g['platform'] != "pfSense") {
1066
			/* restore the leases, if we have them */
1067
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1068
				$dhcprestore = "";
1069
				$dhcpreturn = "";
1070
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1071
				$dhcprestore = implode(" ", $dhcprestore);
1072
				if($dhcpreturn <> 0) {
1073
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1074
				}
1075
			}
1076
		}
1077
	}
1078

    
1079
	$syscfg = $config['system'];
1080
	if (!is_array($config['dhcpdv6']))
1081
		$config['dhcpdv6'] = array();
1082
	$dhcpdv6cfg = $config['dhcpdv6'];
1083
	$Iflist = get_configured_interface_list();
1084
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1085

    
1086

    
1087
	if (platform_booting())
1088
		echo "Starting DHCPv6 service...";
1089
	else
1090
		sleep(1);
1091

    
1092
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1093
	foreach ($Iflist as $ifname) {
1094
		/* Do not put in the config an interface which is down */
1095
		if (isset($blacklist[$ifname]))
1096
			continue;
1097
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1098
			$realif = get_real_interface($ifname, "inet6");
1099
			$ifcfgipv6 = get_interface_ipv6($ifname);
1100
			if(!is_ipaddrv6($ifcfgipv6))
1101
				continue;
1102
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1103
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1104
			$trackcfg = $config['interfaces'][$trackifname];
1105
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1106
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1107
			$dhcpdv6cfg[$ifname] = array();
1108
			$dhcpdv6cfg[$ifname]['enable'] = true;
1109
			/* range */
1110
			$ifcfgipv6arr[7] = "1000";
1111
			$dhcpdv6cfg[$ifname]['range'] = array();
1112
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1113
			$ifcfgipv6arr[7] = "2000";
1114
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1115
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1116
			if($pdlen > 2) {
1117
				$pdlenmax = $pdlen;
1118
				$pdlenhalf = $pdlenmax -1;
1119
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1120
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1121
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1122

    
1123
				/* set the delegation start to half the current address block */
1124
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1125
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1126

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

    
1131
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1132
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1133
			}
1134
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1135
		}
1136
	}
1137

    
1138
	$custoptionsv6 = "";
1139
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1140
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1141
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1142
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1143
			}
1144
		}
1145
	}
1146

    
1147
	if(isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url']))
1148
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1149

    
1150
	$dhcpdv6conf = <<<EOD
1151

    
1152
option domain-name "{$syscfg['domain']}";
1153
option ldap-server code 95 = text;
1154
option domain-search-list code 119 = text;
1155
{$custoptionsv6}
1156
default-lease-time 7200;
1157
max-lease-time 86400;
1158
log-facility local7;
1159
one-lease-per-client true;
1160
deny duplicates;
1161
ping-check true;
1162
update-conflict-detection false;
1163

    
1164
EOD;
1165

    
1166
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1167
		$dhcpdv6conf .= "authoritative;\n";
1168

    
1169
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1170
		$dhcpdv6conf .= "always-broadcast on\n";
1171

    
1172
	$dhcpdv6ifs = array();
1173

    
1174
	$dhcpv6num = 0;
1175
	$nsupdate = false;
1176

    
1177
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1178

    
1179
		$ddns_zones = array();
1180

    
1181
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1182

    
1183
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable']))
1184
			continue;
1185
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1186
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1187
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1188

    
1189
		if ($is_olsr_enabled == true) {
1190
			if($dhcpv6ifconf['netmask'])
1191
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1192
		}
1193

    
1194
		$dnscfgv6 = "";
1195

    
1196
		if ($dhcpv6ifconf['domain']) {
1197
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1198
		}
1199

    
1200
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1201
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1202
    	}
1203

    
1204
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1205
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1206
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1207
			}
1208
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1209
			$nsupdate = true;
1210
		}
1211

    
1212
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1213
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1214
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1215
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1216
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1217
			$dns_arrv6 = array();
1218
			foreach($syscfg['dnsserver'] as $dnsserver) {
1219
				if (is_ipaddrv6($dnsserver)) {
1220
					$dns_arrv6[] = $dnsserver;
1221
				}
1222
			}
1223
			if(!empty($dns_arrv6))
1224
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1225
		}
1226

    
1227
		if ($dhcpv6ifconf['domain']) {
1228
			$newzone = array();
1229
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1230
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1231
			$ddns_zones[] = $newzone;
1232
		}
1233

    
1234
		if (is_ipaddrv6($ifcfgipv6)) {
1235
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1236
		} else {
1237
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1238
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1239
		}
1240
		$dhcpdv6conf .= " {\n";
1241

    
1242
		$dhcpdv6conf .= <<<EOD
1243
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1244
$dnscfgv6
1245

    
1246
EOD;
1247

    
1248
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1249
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1250
		}
1251
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1252
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1253
		}
1254
    		// default-lease-time
1255
		if ($dhcpv6ifconf['defaultleasetime'])
1256
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1257

    
1258
		// max-lease-time
1259
		if ($dhcpv6ifconf['maxleasetime'])
1260
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1261

    
1262
		// ntp-servers
1263
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1264
			$ntpservers = array();
1265
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1266
				if(is_ipaddrv6($ntpserver))
1267
					$ntpservers[] = $ntpserver;
1268
			}
1269
			if(count($ntpservers) > 0 )
1270
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1271
		}
1272
		// tftp-server-name
1273
		/* Needs ISC DHCPD support
1274
		 if ($dhcpv6ifconf['tftp'] <> "")
1275
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1276
		*/
1277

    
1278
		// Handle option, number rowhelper values
1279
		$dhcpdv6conf .= "\n";
1280
		if ($dhcpv6ifconf['numberoptions']['item']) {
1281
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1282
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1283
			}
1284
		}
1285

    
1286
		// ldap-server
1287
		if ($dhcpv6ifconf['ldap'] <> "")
1288
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1289

    
1290
		// net boot information
1291
		if(isset($dhcpv6ifconf['netboot'])) {
1292
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1293
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1294
			}
1295
		}
1296

    
1297
		$dhcpdv6conf .= "}\n";
1298

    
1299
		/* add static mappings */
1300
		/* Needs to use DUID */
1301
		if (is_array($dhcpv6ifconf['staticmap'])) {
1302
			$i = 0;
1303
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1304
				$dhcpdv6conf .= <<<EOD
1305
host s_{$dhcpv6if}_{$i} {
1306
	host-identifier option dhcp6.client-id {$sm['duid']};
1307

    
1308
EOD;
1309
				if ($sm['ipaddrv6'])
1310
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1311

    
1312
				if ($sm['hostname']) {
1313
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1314
					$dhhostname = str_replace(".", "_", $dhhostname);
1315
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1316
				}
1317
				if ($sm['filename'])
1318
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1319

    
1320
				if ($sm['rootpath'])
1321
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1322

    
1323
				$dhcpdv6conf .= "}\n";
1324
				$i++;
1325
			}
1326
		}
1327

    
1328
		if ($dhcpv6ifconf['domain'])
1329
		{
1330
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1331
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1332
		}
1333

    
1334
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1335
			if(preg_match("/poes/si", $dhcpv6if)) {
1336
				/* magic here */
1337
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1338
			} else {
1339
				$realif = get_real_interface($dhcpv6if, "inet6");
1340
				if (stristr("$realif", "bridge")) {
1341
					$mac = get_interface_mac($realif);
1342
					$v6address = generate_ipv6_from_mac($mac);
1343
					/* Create link local address for bridges */
1344
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1345
				}
1346
				$realif = escapeshellcmd($realif);
1347
				$dhcpdv6ifs[] = $realif;
1348
			}
1349
		}
1350
	}
1351

    
1352
	if ($nsupdate)
1353
	{
1354
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1355
	}
1356
	else
1357
	{
1358
		$dhcpdv6conf .= "ddns-update-style none;\n";
1359
	}
1360

    
1361
	/* write dhcpdv6.conf */
1362
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1363
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1364
		if (platform_booting())
1365
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1366
		unset($dhcpdv6conf);
1367
		return 1;
1368
	}
1369
	unset($dhcpdv6conf);
1370

    
1371
	/* create an empty leases v6 database */
1372
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1373
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1374

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

    
1379
	/* fire up dhcpd in a chroot */
1380
	if (count($dhcpdv6ifs) > 0) {
1381
		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 " .
1382
			join(" ", $dhcpdv6ifs));
1383
		mwexec("/usr/local/sbin/dhcpleases6 -c \"/usr/local/bin/php -f /usr/local/sbin/prefixes.php|/bin/sh\" -l {$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1384
	}
1385
	if (platform_booting())
1386
		print gettext("done.") . "\n";
1387

    
1388
	return 0;
1389
}
1390

    
1391
function services_igmpproxy_configure() {
1392
        global $config, $g;
1393

    
1394
        /* kill any running igmpproxy */
1395
        killbyname("igmpproxy");
1396

    
1397
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1398
		return 1;
1399

    
1400
        $iflist = get_configured_interface_list();
1401

    
1402
        $igmpconf = <<<EOD
1403

    
1404
##------------------------------------------------------
1405
## Enable Quickleave mode (Sends Leave instantly)
1406
##------------------------------------------------------
1407
quickleave
1408

    
1409
EOD;
1410

    
1411
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1412
                unset($iflist[$igmpcf['ifname']]);
1413
                $realif = get_real_interface($igmpcf['ifname']);
1414
                if (empty($igmpcf['threshold']))
1415
                        $threshld = 1;
1416
                else
1417
                        $threshld = $igmpcf['threshold'];
1418
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1419

    
1420
                if ($igmpcf['address'] <> "") {
1421
                        $item = explode(" ", $igmpcf['address']);
1422
                        foreach($item as $iww)
1423
                                $igmpconf .= "altnet {$iww}\n";
1424
                }
1425
                $igmpconf .= "\n";
1426
        }
1427
        foreach ($iflist as $ifn) {
1428
                $realif = get_real_interface($ifn);
1429
                $igmpconf .= "phyint {$realif} disabled\n";
1430
        }
1431
	$igmpconf .= "\n";
1432

    
1433
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1434
        if (!$igmpfl) {
1435
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1436
                return;
1437
        }
1438
        fwrite($igmpfl, $igmpconf);
1439
        fclose($igmpfl);
1440
	unset($igmpconf);
1441

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

    
1446
        return 0;
1447
}
1448

    
1449
function services_dhcrelay_configure() {
1450
	global $config, $g;
1451
	if ($g['platform'] == 'jail')
1452
		return;
1453
	if(isset($config['system']['developerspew'])) {
1454
		$mt = microtime();
1455
		echo "services_dhcrelay_configure() being called $mt\n";
1456
	}
1457

    
1458
	/* kill any running dhcrelay */
1459
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1460

    
1461
	$dhcrelaycfg =& $config['dhcrelay'];
1462

    
1463
	/* DHCPRelay enabled on any interfaces? */
1464
	if (!isset($dhcrelaycfg['enable']))
1465
		return 0;
1466

    
1467
	if (platform_booting())
1468
		echo gettext("Starting DHCP relay service...");
1469
	else
1470
		sleep(1);
1471

    
1472
	$iflist = get_configured_interface_list();
1473

    
1474
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1475
	foreach ($dhcifaces as $dhcrelayif) {
1476
		if (!isset($iflist[$dhcrelayif]) ||
1477
			link_interface_to_bridge($dhcrelayif))
1478
			continue;
1479

    
1480
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1481
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1482
	}
1483

    
1484
	/*
1485
	 * In order for the relay to work, it needs to be active
1486
	 * on the interface in which the destination server sits.
1487
	 */
1488
	$srvips = explode(",", $dhcrelaycfg['server']);
1489
	foreach ($srvips as $srcidx => $srvip) {
1490
		unset($destif);
1491
		foreach ($iflist as $ifname) {
1492
			$subnet = get_interface_ip($ifname);
1493
			if (!is_ipaddr($subnet))
1494
				continue;
1495
			$subnet .=  "/" . get_interface_subnet($ifname);
1496
			if (ip_in_subnet($srvip, $subnet)) {
1497
				$destif = get_real_interface($ifname);
1498
				break;
1499
			}
1500
		}
1501
		if (!isset($destif)) {
1502
			foreach (get_staticroutes() as $rtent) {
1503
				if (ip_in_subnet($srvip, $rtent['network'])) {
1504
					$a_gateways = return_gateways_array(true);
1505
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1506
					break;
1507
				}
1508
			}
1509
		}
1510

    
1511
		if (!isset($destif)) {
1512
			/* Create a array from the existing route table */
1513
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1514
        		array_shift($route_str);
1515
        		array_shift($route_str);
1516
        		array_shift($route_str);
1517
        		array_shift($route_str);
1518
        		$route_arr = array();
1519
        		foreach($route_str as $routeline) {
1520
				$items = preg_split("/[ ]+/i", $routeline);
1521
				if (is_subnetv4($items[0])) {
1522
					$subnet = $items[0];
1523
				} elseif (is_ipaddrv4($items[0])) {
1524
					$subnet = "{$items[0]}/32";
1525
				} else {
1526
					// Not a subnet or IP address, skip to the next line.
1527
					continue;
1528
				}
1529
				if (ip_in_subnet($srvip, $subnet)) {
1530
					$destif = trim($items[6]);
1531
					break;
1532
				}
1533
			}
1534
		}
1535

    
1536
		if (!isset($destif)) {
1537
			if (is_array($config['gateways']['gateway_item'])) {
1538
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1539
					if (isset($gateway['defaultgw'])) {
1540
						$destif = get_real_interface($gateway['interface']);
1541
						break;
1542
					}
1543
				}
1544
			} else
1545
				$destif = get_real_interface("wan");
1546
		}
1547

    
1548
		if (!empty($destif))
1549
			$dhcrelayifs[] = $destif;
1550
	}
1551
	$dhcrelayifs = array_unique($dhcrelayifs);
1552

    
1553
	/* fire up dhcrelay */
1554
	if (empty($dhcrelayifs)) {
1555
		log_error("No suitable interface found for running dhcrelay!");
1556
		return; /* XXX */
1557
	}
1558

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

    
1561
	if (isset($dhcrelaycfg['agentoption']))
1562
		$cmd .=  " -a -m replace";
1563

    
1564
	$cmd .= " " . implode(" ", $srvips);
1565
	mwexec($cmd);
1566
	unset($cmd);
1567

    
1568
	return 0;
1569
}
1570

    
1571
function services_dhcrelay6_configure() {
1572
	global $config, $g;
1573
	if ($g['platform'] == 'jail')
1574
		return;
1575
	if(isset($config['system']['developerspew'])) {
1576
		$mt = microtime();
1577
		echo "services_dhcrelay6_configure() being called $mt\n";
1578
	}
1579

    
1580
	/* kill any running dhcrelay */
1581
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1582

    
1583
	$dhcrelaycfg =& $config['dhcrelay6'];
1584

    
1585
	/* DHCPv6 Relay enabled on any interfaces? */
1586
	if (!isset($dhcrelaycfg['enable']))
1587
		return 0;
1588

    
1589
	if (platform_booting())
1590
		echo gettext("Starting DHCPv6 relay service...");
1591
	else
1592
		sleep(1);
1593

    
1594
	$iflist = get_configured_interface_list();
1595

    
1596
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1597
	foreach ($dhcifaces as $dhcrelayif) {
1598
		if (!isset($iflist[$dhcrelayif]) ||
1599
			link_interface_to_bridge($dhcrelayif))
1600
			continue;
1601

    
1602
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1603
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1604
	}
1605
	$dhcrelayifs = array_unique($dhcrelayifs);
1606

    
1607
	/*
1608
	 * In order for the relay to work, it needs to be active
1609
	 * on the interface in which the destination server sits.
1610
	 */
1611
	$srvips = explode(",", $dhcrelaycfg['server']);
1612
        $srvifaces = array();
1613
	foreach ($srvips as $srcidx => $srvip) {
1614
		unset($destif);
1615
		foreach ($iflist as $ifname) {
1616
			$subnet = get_interface_ipv6($ifname);
1617
			if (!is_ipaddrv6($subnet))
1618
				continue;
1619
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1620
			if (ip_in_subnet($srvip, $subnet)) {
1621
				$destif = get_real_interface($ifname);
1622
				break;
1623
			}
1624
		}
1625
		if (!isset($destif)) {
1626
			if (is_array($config['staticroutes']['route'])) {
1627
				foreach ($config['staticroutes']['route'] as $rtent) {
1628
					if (ip_in_subnet($srvip, $rtent['network'])) {
1629
						$a_gateways = return_gateways_array(true);
1630
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1631
						break;
1632
					}
1633
				}
1634
			}
1635
		}
1636

    
1637
		if (!isset($destif)) {
1638
			/* Create a array from the existing route table */
1639
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1640
        		array_shift($route_str);
1641
        		array_shift($route_str);
1642
        		array_shift($route_str);
1643
        		array_shift($route_str);
1644
        		$route_arr = array();
1645
        		foreach($route_str as $routeline) {
1646
                		$items = preg_split("/[ ]+/i", $routeline);
1647
				if (ip_in_subnet($srvip, $items[0])) {
1648
					$destif = trim($items[6]);
1649
					break;
1650
				}
1651
        		}
1652
		}
1653

    
1654
		if (!isset($destif)) {
1655
			if (is_array($config['gateways']['gateway_item'])) {
1656
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1657
					if (isset($gateway['defaultgw'])) {
1658
						$destif = get_real_interface($gateway['interface']);
1659
						break;
1660
					}
1661
				}
1662
			} else
1663
				$destif = get_real_interface("wan");
1664
		}
1665

    
1666
		if (!empty($destif)) {
1667
			$srvifaces[] = "{$srvip}%{$destif}";
1668
		}
1669
	}
1670

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

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

    
1687
	return 0;
1688
}
1689

    
1690
function services_dyndns_configure_client($conf) {
1691

    
1692
	if (!isset($conf['enable']))
1693
		return;
1694

    
1695
	/* load up the dyndns.class */
1696
	require_once("dyndns.class");
1697

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

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

    
1727
	$dyndnscfg = $config['dyndnses']['dyndns'];
1728
	$gwgroups = return_gateway_groups_array();
1729
	if (is_array($dyndnscfg)) {
1730
		if (platform_booting())
1731
			echo gettext("Starting DynDNS clients...");
1732

    
1733
		foreach ($dyndnscfg as $dyndns) {
1734
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1735
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1736
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1737
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1738
				services_dyndns_configure_client($dyndns);
1739
				sleep(1);
1740
			}
1741
		}
1742

    
1743
		if (platform_booting())
1744
			echo gettext("done.") . "\n";
1745
	}
1746

    
1747
	return 0;
1748
}
1749

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

    
1776
function services_dnsmasq_configure() {
1777
	global $config, $g;
1778
	$return = 0;
1779

    
1780
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1781
	$standard_args = array(
1782
		"dns-forward-max" => "--dns-forward-max=5000",
1783
		"cache-size" => "--cache-size=10000",
1784
		"local-ttl" => "--local-ttl=1"
1785
	);
1786

    
1787

    
1788
	if(isset($config['system']['developerspew'])) {
1789
		$mt = microtime();
1790
		echo "services_dnsmasq_configure() being called $mt\n";
1791
	}
1792

    
1793
	/* kill any running dnsmasq */
1794
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1795
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1796

    
1797
	if (isset($config['dnsmasq']['enable'])) {
1798

    
1799
		if (platform_booting())
1800
			echo gettext("Starting DNS forwarder...");
1801
		else
1802
			sleep(1);
1803

    
1804
                /* generate hosts file */
1805
                if(system_hosts_generate()!=0)
1806
                        $return = 1;
1807

    
1808
		$args = "";
1809

    
1810
		if (isset($config['dnsmasq']['regdhcp'])) {
1811
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1812
		}
1813

    
1814
		/* Setup listen port, if non-default */
1815
		if (is_port($config['dnsmasq']['port']))
1816
			$args .= " --port={$config['dnsmasq']['port']} ";
1817

    
1818
		$listen_addresses = "";
1819
		if(isset($config['dnsmasq']['interface'])) {
1820
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1821
			foreach ($interfaces as $interface) {
1822
				if (is_ipaddrv4($interface)) {
1823
					$listen_addresses .= " --listen-address={$interface} ";
1824
				} else if (is_ipaddrv6($interface)) {
1825
					/*
1826
					 * XXX: Since dnsmasq does not support link-local address
1827
					 * with scope specified. These checks are being done.
1828
					 */
1829
					if (is_linklocal($interface) && strstr($interface, "%")) {
1830
						$tmpaddrll6 = explode("%", $interface);
1831
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1832
					} else 
1833
						$listen_addresses .= " --listen-address={$interface} ";
1834
				} else if (strstr($interface, "_vip")) {
1835
					$laddr = get_configured_carp_interface_list($interface);
1836
					if (is_ipaddr($laddr)) 
1837
						$listen_addresses .= " --listen-address={$laddr} ";
1838
				} else {
1839
					$if = get_real_interface($interface);
1840
					if (does_interface_exist($if)) {
1841
						$laddr = find_interface_ip($if);
1842
						if (is_ipaddrv4($laddr))
1843
							$listen_addresses .= " --listen-address={$laddr} ";
1844
						$laddr6 = find_interface_ipv6($if);
1845
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1846
							/*
1847
							 * XXX: Since dnsmasq does not support link-local address
1848
							 * with scope specified. These checks are being done.
1849
							 */
1850
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1851
								$tmpaddrll6 = explode("%", $laddr6);
1852
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1853
							} else
1854
								$listen_addresses .= " --listen-address={$laddr6} ";
1855
						}
1856
					}
1857
				}
1858
			}
1859
			if (!empty($listen_addresses)) {
1860
				$args .= " {$listen_addresses} ";
1861
				if (isset($config['dnsmasq']['strictbind']))
1862
					$args .= " --bind-interfaces ";
1863
			}
1864
		}
1865

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

    
1873
			// Build an array of domain overrides to help in checking for matches.
1874
			$override_a = array();
1875
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1876
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1877
					$override_a[$override['domain']] = "y";
1878
				}
1879
			}
1880

    
1881
			// Build an array of the private reverse lookup domain names
1882
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
1883
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
1884
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1885
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
1886
			}
1887

    
1888
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
1889
			foreach ($reverse_domain_a as $reverse_domain) { 
1890
				if (!isset($override_a[$reverse_domain]))
1891
					$args .= " --server=/$reverse_domain/ ";
1892
			}
1893
			unset($override_a);
1894
			unset($reverse_domain_a);
1895
		}
1896

    
1897
		/* Setup forwarded domains */
1898
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1899
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1900
				if ($override['ip'] == "!")
1901
					$override[ip] = "";
1902
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1903
			}
1904
		}
1905

    
1906
		/* Allow DNS Rebind for forwarded domains */
1907
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1908
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1909
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1910
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1911
				}
1912
			}
1913
		}
1914

    
1915
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1916
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1917

    
1918
		if (isset($config['dnsmasq']['strict_order'])) {
1919
			$args .= " --strict-order ";
1920
		}
1921

    
1922
		if (isset($config['dnsmasq']['domain_needed'])) {
1923
			$args .= " --domain-needed ";
1924
		}
1925

    
1926
		if ($config['dnsmasq']['custom_options'])
1927
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1928
				$args .= " " . escapeshellarg("--{$c}");
1929
				$p = explode('=', $c);
1930
				if (array_key_exists($p[0], $standard_args))
1931
					unset($standard_args[$p[0]]);
1932
			}
1933
		$args .= ' ' . implode(' ', array_values($standard_args));
1934

    
1935
		/* run dnsmasq */
1936
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1937
		//log_error("dnsmasq command: {$cmd}");
1938
		mwexec_bg($cmd);
1939
		unset($args);
1940

    
1941
        system_dhcpleases_configure();
1942

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

    
1947
	if (!platform_booting()) {
1948
		if(services_dhcpd_configure()!=0)
1949
			$return = 1;
1950
	}
1951

    
1952
	return $return;
1953
}
1954

    
1955
function services_unbound_configure() {
1956
	global $config, $g;
1957
	$return = 0;
1958

    
1959
	if (isset($config['system']['developerspew'])) {
1960
		$mt = microtime();
1961
		echo "services_unbound_configure() being called $mt\n";
1962
	}
1963

    
1964
	// kill any running Unbound instance
1965
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1966
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1967

    
1968
	if (isset($config['unbound']['enable'])) {
1969
		if (platform_booting())
1970
			echo gettext("Starting DNS Resolver...");
1971
		else
1972
			sleep(1);
1973

    
1974
		/* generate hosts file */
1975
		if(system_hosts_generate()!=0)
1976
			$return = 1;
1977

    
1978
		require_once('/etc/inc/unbound.inc');
1979
		sync_unbound_service();
1980
		if (platform_booting())
1981
			echo gettext("done.") . "\n";
1982

    
1983
        system_dhcpleases_configure();
1984
	}
1985

    
1986
	if (!platform_booting()) {
1987
		if (services_dhcpd_configure()!=0)
1988
			$return = 1;
1989
	}
1990

    
1991
	return $return;
1992
}
1993

    
1994
function services_snmpd_configure() {
1995
	global $config, $g;
1996
	if(isset($config['system']['developerspew'])) {
1997
		$mt = microtime();
1998
		echo "services_snmpd_configure() being called $mt\n";
1999
	}
2000

    
2001
	/* kill any running snmpd */
2002
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2003
	sleep(2);
2004
	if(is_process_running("bsnmpd"))
2005
		mwexec("/usr/bin/killall bsnmpd", true);
2006

    
2007
	if (isset($config['snmpd']['enable'])) {
2008

    
2009
		if (platform_booting())
2010
			echo gettext("Starting SNMP daemon... ");
2011

    
2012
		/* generate snmpd.conf */
2013
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2014
		if (!$fd) {
2015
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
2016
			return 1;
2017
		}
2018

    
2019

    
2020
		$snmpdconf = <<<EOD
2021
location := "{$config['snmpd']['syslocation']}"
2022
contact := "{$config['snmpd']['syscontact']}"
2023
read := "{$config['snmpd']['rocommunity']}"
2024

    
2025
EOD;
2026

    
2027
/* No docs on what write strings do there for disable for now.
2028
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
2029
		    $snmpdconf .= <<<EOD
2030
# write string
2031
write := "{$config['snmpd']['rwcommunity']}"
2032

    
2033
EOD;
2034
		}
2035
*/
2036

    
2037

    
2038
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2039
		    $snmpdconf .= <<<EOD
2040
# SNMP Trap support.
2041
traphost := {$config['snmpd']['trapserver']}
2042
trapport := {$config['snmpd']['trapserverport']}
2043
trap := "{$config['snmpd']['trapstring']}"
2044

    
2045

    
2046
EOD;
2047
		}
2048

    
2049
		$version = trim(file_get_contents('/etc/version'));
2050
		$platform = trim(file_get_contents('/etc/platform'));
2051
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
2052
			$platform = $g['product_name'];
2053
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2054
			" {$version} {$platform} " . php_uname("s") .
2055
			" " . php_uname("r") . " " . php_uname("m");
2056

    
2057
		$snmpdconf .= <<<EOD
2058
system := 1     # pfSense
2059
%snmpd
2060
sysDescr			= "{$sysDescr}"
2061
begemotSnmpdDebugDumpPdus       = 2
2062
begemotSnmpdDebugSyslogPri      = 7
2063
begemotSnmpdCommunityString.0.1 = $(read)
2064

    
2065
EOD;
2066

    
2067
/* No docs on what write strings do there for disable for now.
2068
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
2069
		    $snmpdconf .= <<<EOD
2070
begemotSnmpdCommunityString.0.2 = $(write)
2071

    
2072
EOD;
2073
		}
2074
*/
2075

    
2076

    
2077
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2078
		    $snmpdconf .= <<<EOD
2079
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2080
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2081
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2082

    
2083
EOD;
2084
		}
2085

    
2086

    
2087
		$snmpdconf .= <<<EOD
2088
begemotSnmpdCommunityDisable    = 1
2089

    
2090
EOD;
2091

    
2092
		if (isset($config['snmpd']['bindlan'])) {
2093
			$config['snmpd']['bindip'] = 'lan';
2094
			unset($config['snmpd']['bindlan']);
2095
		}
2096
		$bind_to_ip = "0.0.0.0";
2097
		if(isset($config['snmpd']['bindip'])) {
2098
			if (is_ipaddr($config['snmpd']['bindip'])) {
2099
				$bind_to_ip = $config['snmpd']['bindip'];
2100
			} else {
2101
				$if = get_real_interface($config['snmpd']['bindip']);
2102
				if (does_interface_exist($if))
2103
					$bind_to_ip = find_interface_ip($if);
2104
			}
2105
		}
2106

    
2107
		if(is_port( $config['snmpd']['pollport'] )) {
2108
		    $snmpdconf .= <<<EOD
2109
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2110

    
2111
EOD;
2112

    
2113
		}
2114

    
2115
		$snmpdconf .= <<<EOD
2116
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2117
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2118

    
2119
# These are bsnmp macros not php vars.
2120
sysContact      = $(contact)
2121
sysLocation     = $(location)
2122
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2123

    
2124
snmpEnableAuthenTraps = 2
2125

    
2126
EOD;
2127

    
2128
		if (is_array( $config['snmpd']['modules'] )) {
2129
		    if(isset($config['snmpd']['modules']['mibii'])) {
2130
			$snmpdconf .= <<<EOD
2131
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2132

    
2133
EOD;
2134
		    }
2135

    
2136
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2137
			$snmpdconf .= <<<EOD
2138
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2139
%netgraph
2140
begemotNgControlNodeName = "snmpd"
2141

    
2142
EOD;
2143
		    }
2144

    
2145
		    if(isset($config['snmpd']['modules']['pf'])) {
2146
			$snmpdconf .= <<<EOD
2147
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2148

    
2149
EOD;
2150
		    }
2151

    
2152
		    if(isset($config['snmpd']['modules']['hostres'])) {
2153
			/* XXX: hostres module crashes APU - ticket #4403 */
2154
			$specplatform = system_identify_specific_platform();
2155
			if ($specplatform['name'] == 'APU') {
2156
				log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
2157
			} else {
2158
				$snmpdconf .= <<<EOD
2159
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2160

    
2161
EOD;
2162
			}
2163
			unset($specplatform);
2164
		    }
2165

    
2166
		    if(isset($config['snmpd']['modules']['bridge'])) {
2167
			$snmpdconf .= <<<EOD
2168
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2169
# config must end with blank line
2170

    
2171
EOD;
2172
		    }
2173
			if(isset($config['snmpd']['modules']['ucd'])) {
2174
				$snmpdconf .= <<<EOD
2175
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2176

    
2177
EOD;
2178
			}
2179
			if(isset($config['snmpd']['modules']['regex'])) {
2180
				$snmpdconf .= <<<EOD
2181
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2182

    
2183
EOD;
2184
			}
2185
		}
2186

    
2187
		fwrite($fd, $snmpdconf);
2188
		fclose($fd);
2189
		unset($snmpdconf);
2190

    
2191
		if (isset($config['snmpd']['bindlan'])) {
2192
			$bindlan = "";
2193
		}
2194

    
2195
		/* run bsnmpd */
2196
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2197
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2198

    
2199
		if (platform_booting())
2200
			echo gettext("done.") . "\n";
2201
	}
2202

    
2203
	return 0;
2204
}
2205

    
2206
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2207
	global $config, $g;
2208
	if(isset($config['system']['developerspew'])) {
2209
		$mt = microtime();
2210
		echo "services_dnsupdate_process() being called $mt\n";
2211
	}
2212

    
2213
	/* Dynamic DNS updating active? */
2214
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2215
		$notify_text = "";
2216
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2217
			if (!isset($dnsupdate['enable']))
2218
				continue;
2219
			if (!empty($int) && $int != $dnsupdate['interface'])
2220
				continue;
2221
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2222
				continue;
2223

    
2224
			/* determine interface name */
2225
			$if = get_real_interface($dnsupdate['interface']);
2226
			
2227
			if (isset($dnsupdate['usepublicip']))
2228
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2229
                        else
2230
                                $wanip = get_interface_ip($dnsupdate['interface']);
2231
			
2232
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2233
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2234
			$currentTime = time();
2235

    
2236
			if ($wanip || $wanipv6) {
2237
				$keyname = $dnsupdate['keyname'];
2238
				/* trailing dot */
2239
				if (substr($keyname, -1) != ".")
2240
					$keyname .= ".";
2241

    
2242
				$hostname = $dnsupdate['host'];
2243
				/* trailing dot */
2244
				if (substr($hostname, -1) != ".")
2245
					$hostname .= ".";
2246

    
2247
				/* write private key file
2248
				   this is dumb - public and private keys are the same for HMAC-MD5,
2249
				   but nsupdate insists on having both */
2250
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2251
				$privkey = <<<EOD
2252
Private-key-format: v1.2
2253
Algorithm: 157 (HMAC)
2254
Key: {$dnsupdate['keydata']}
2255

    
2256
EOD;
2257
				fwrite($fd, $privkey);
2258
				fclose($fd);
2259

    
2260
				/* write public key file */
2261
				if ($dnsupdate['keytype'] == "zone") {
2262
					$flags = 257;
2263
					$proto = 3;
2264
				} else if ($dnsupdate['keytype'] == "host") {
2265
					$flags = 513;
2266
					$proto = 3;
2267
				} else if ($dnsupdate['keytype'] == "user") {
2268
					$flags = 0;
2269
					$proto = 2;
2270
				}
2271

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

    
2276
				/* generate update instructions */
2277
				$upinst = "";
2278
				if (!empty($dnsupdate['server']))
2279
					$upinst .= "server {$dnsupdate['server']}\n";
2280

    
2281
				if (file_exists($cacheFile)) {
2282
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2283
				}
2284
				if (file_exists("{$cacheFile}.ipv6")) {
2285
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2286
				}
2287

    
2288
				// 25 Days
2289
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2290
				$need_update = false;
2291

    
2292
				conf_mount_rw();
2293
				/* Update IPv4 if we have it. */
2294
				if (is_ipaddrv4($wanip)) {
2295
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2296
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2297
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2298
						$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";
2299
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2300
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2301
						$need_update = true;
2302
					} else {
2303
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2304
					}
2305
				} else
2306
					@unlink($cacheFile);
2307

    
2308
				/* Update IPv6 if we have it. */
2309
				if (is_ipaddrv6($wanipv6)) {
2310
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2311
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2312
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2313
						$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";
2314
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2315
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2316
						$need_update = true;
2317
					} else {
2318
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2319
					}
2320
				} else
2321
					@unlink("{$cacheFile}.ipv6");
2322
				conf_mount_ro();
2323

    
2324
				$upinst .= "\n";	/* mind that trailing newline! */
2325

    
2326
				if ($need_update) {
2327
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2328
					unset($upinst);
2329
					/* invoke nsupdate */
2330
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2331
					if (isset($dnsupdate['usetcp']))
2332
						$cmd .= " -v";
2333
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2334
					mwexec_bg($cmd);
2335
					unset($cmd);
2336
				}
2337
			}
2338
		}
2339
		if (!empty($notify_text)) {
2340
			notify_all_remote($notify_text);
2341
		}
2342
	}
2343

    
2344
	return 0;
2345
}
2346

    
2347
/* configure cron service */
2348
function configure_cron() {
2349
	global $g, $config;
2350

    
2351
	conf_mount_rw();
2352
	/* preserve existing crontab entries */
2353
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2354

    
2355
	for ($i = 0; $i < count($crontab_contents); $i++) {
2356
		$cron_item =& $crontab_contents[$i];
2357
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2358
			array_splice($crontab_contents, $i - 1);
2359
			break;
2360
		}
2361
	}
2362
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2363

    
2364

    
2365
	if (is_array($config['cron']['item'])) {
2366
		$crontab_contents .= "#\n";
2367
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2368
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2369
		$crontab_contents .= "#\n";
2370

    
2371
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2372
			$http_proxy = $config['system']['proxyurl'];
2373
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2374
				$http_proxy .= ':' . $config['system']['proxyport'];
2375
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2376
		}
2377

    
2378
		foreach ($config['cron']['item'] as $item) {
2379
			$crontab_contents .= "\n{$item['minute']}\t";
2380
			$crontab_contents .= "{$item['hour']}\t";
2381
			$crontab_contents .= "{$item['mday']}\t";
2382
			$crontab_contents .= "{$item['month']}\t";
2383
			$crontab_contents .= "{$item['wday']}\t";
2384
			$crontab_contents .= "{$item['who']}\t";
2385
			$crontab_contents .= "{$item['command']}";
2386
		}
2387

    
2388
		$crontab_contents .= "\n#\n";
2389
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2390
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2391
		$crontab_contents .= "#\n\n";
2392
	}
2393

    
2394
	/* please maintain the newline at the end of file */
2395
	file_put_contents("/etc/crontab", $crontab_contents);
2396
	unset($crontab_contents);
2397

    
2398
	/* do a HUP kill to force sync changes */
2399
	sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2400

    
2401
	conf_mount_ro();
2402
}
2403

    
2404
function upnp_action ($action) {
2405
	global $g, $config;
2406
	switch($action) {
2407
		case "start":
2408
			if (file_exists('/var/etc/miniupnpd.conf')) {
2409
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2410
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2411
			}
2412
			break;
2413
		case "stop":
2414
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2415
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2416
				mwexec('killall miniupnpd 2>/dev/null', true);
2417
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2418
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2419
			break;
2420
		case "restart":
2421
			upnp_action('stop');
2422
			upnp_action('start');
2423
			break;
2424
	}
2425
}
2426

    
2427
function upnp_start() {
2428
	global $config;
2429

    
2430
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2431
		return;
2432

    
2433
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2434
		echo gettext("Starting UPnP service... ");
2435
		require_once('/usr/local/pkg/miniupnpd.inc');
2436
		sync_package_miniupnpd();
2437
		echo "done.\n";
2438
	}
2439
}
2440

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

    
2444
	$is_installed = false;
2445
	$cron_changed = true;
2446

    
2447
	if (!is_array($config['cron']))
2448
		$config['cron'] = array();
2449
	if (!is_array($config['cron']['item']))
2450
		$config['cron']['item'] = array();
2451

    
2452
	$x=0;
2453
	foreach($config['cron']['item'] as $item) {
2454
		if(strstr($item['command'], $command)) {
2455
			$is_installed = true;
2456
			break;
2457
		}
2458
		$x++;
2459
	}
2460

    
2461
	if($active) {
2462
		$cron_item = array();
2463
		$cron_item['minute'] = $minute;
2464
		$cron_item['hour'] = $hour;
2465
		$cron_item['mday'] = $monthday;
2466
		$cron_item['month'] = $month;
2467
		$cron_item['wday'] = $weekday;
2468
		$cron_item['who'] = $who;
2469
		$cron_item['command'] = $command;
2470
		if(!$is_installed) {
2471
			$config['cron']['item'][] = $cron_item;
2472
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2473
		} else {
2474
			if ($config['cron']['item'][$x] == $cron_item) {
2475
				$cron_changed = false;
2476
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2477
			} else {
2478
				$config['cron']['item'][$x] = $cron_item;
2479
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2480
			}
2481
		}
2482
	} else {
2483
		if($is_installed == true) {
2484
			unset($config['cron']['item'][$x]);
2485
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2486
		}
2487
	}
2488

    
2489
	if ($cron_changed)
2490
		configure_cron();
2491
}
2492

    
2493
?>
(49-49/67)