Project

General

Profile

Download (77.9 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 deamon */
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
		$realif = get_real_interface($dhcpv6if, "inet6");
99
		if (isset($radvdifs[$realif]))
100
			continue;
101

    
102
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
103
		if (!is_ipaddrv6($ifcfgipv6))
104
			continue;
105

    
106
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
107
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
108
		$radvdifs[$realif] = $realif;
109

    
110
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
111
		$radvdconf .= "interface {$realif} {\n";
112
		$radvdconf .= "\tAdvSendAdvert on;\n";
113
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
114
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
115
		$mtu = get_interface_mtu($realif);
116
		if (is_numeric($mtu))
117
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
118
		else
119
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
120
		// $radvdconf .= "\tDeprecatePrefix on;\n";
121
		switch($dhcpv6ifconf['rapriority']) {
122
			case "low":
123
				$radvdconf .= "\tAdvDefaultPreference low;\n";
124
				break;
125
			case "high":
126
				$radvdconf .= "\tAdvDefaultPreference high;\n";
127
				break;
128
			default:
129
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
130
				break;
131
		}
132
		switch($dhcpv6ifconf['ramode']) {
133
			case "managed":
134
			case "assist":
135
				$radvdconf .= "\tAdvManagedFlag on;\n";
136
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
137
				break;
138
		}
139
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
140
		if($carpif == true) {
141
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
142
		} else {
143
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
144
		}
145
		switch($dhcpv6ifconf['ramode']) {
146
			case "managed":
147
				$radvdconf .= "\t\tAdvOnLink on;\n";
148
				$radvdconf .= "\t\tAdvAutonomous off;\n";
149
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
150
				break;
151
			case "router":
152
				$radvdconf .= "\t\tAdvOnLink off;\n";
153
				$radvdconf .= "\t\tAdvAutonomous off;\n";
154
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
155
				break;
156
			case "assist":
157
				$radvdconf .= "\t\tAdvOnLink on;\n";
158
				$radvdconf .= "\t\tAdvAutonomous on;\n";
159
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
160
				break;
161
			case "unmanaged":
162
				$radvdconf .= "\t\tAdvOnLink on;\n";
163
				$radvdconf .= "\t\tAdvAutonomous on;\n";
164
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
165
				break;				
166
		}
167
		$radvdconf .= "\t};\n";
168

    
169
		if($carpif === true) {
170
			$radvdconf .= "\troute ::/0 {\n";
171
			$radvdconf .= "\t\tRemoveRoute off;\n";
172
			$radvdconf .= "\t};\n";
173
		} else {
174
			$radvdconf .= "\troute ::/0 {\n";
175
			$radvdconf .= "\t\tRemoveRoute on;\n";
176
			$radvdconf .= "\t};\n";
177
		}
178

    
179
		/* add DNS servers */
180
		$dnslist = array();
181
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
182
			foreach($dhcpv6ifconf['dnsserver'] as $server)
183
				if (is_ipaddrv6($server))
184
					$dnslist[] = $server;
185
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
186
			foreach($dhcpv6ifconf['radnsserver'] as $server)
187
				if (is_ipaddrv6($server))
188
					$dnslist[] = $server;
189
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
190
			$dnslist[] = get_interface_ipv6($realif);
191
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
192
			foreach($config['system']['dnsserver'] as $server) {
193
				if (is_ipaddrv6($server))
194
					$dnslist[] = $server;
195
			}
196
		}
197
		if (count($dnslist) > 0) {
198
			$dnsstring = implode(" ", $dnslist);
199
			if ($dnsstring <> "")
200
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
201
		}
202
		if (!empty($dhcpv6ifconf['domain'])) {
203
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
204
		} elseif (!empty($config['system']['domain'])) {
205
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
206
		}
207
		$radvdconf .= "};\n";
208
	}
209

    
210
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
211
	foreach ($Iflist as $if => $ifdescr) {
212
		if(!isset($config['interfaces'][$if]['track6-interface']))
213
			continue;
214
		if(!isset($config['interfaces'][$if]['enable']))
215
			continue;
216
		/* Do not put in the config an interface which is down */
217
		if (isset($blacklist[$if]))
218
			continue;
219
		$trackif = $config['interfaces'][$if]['track6-interface'];
220
		if (empty($config['interfaces'][$trackif]))
221
			continue;
222

    
223
		$realif = get_real_interface($if, "inet6");
224
		/* prevent duplicate entries, manual overrides */
225
		if (isset($radvdifs[$realif]))
226
			continue;
227

    
228
		$ifcfgipv6 = get_interface_ipv6($if);
229
		if(!is_ipaddrv6($ifcfgipv6)) {
230
			$subnetv6 = "::";
231
			$ifcfgsnv6 = "64";
232
		} else {
233
			$ifcfgsnv6 = get_interface_subnetv6($if);
234
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
235
		}
236
		$radvdifs[$realif] = $realif;
237

    
238
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
239
	
240
		if ($g['debug'])
241
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
242

    
243
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
244
		$radvdconf .= "interface {$realif} {\n";
245
		$radvdconf .= "\tAdvSendAdvert on;\n";
246
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
247
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
248
		$mtu = get_interface_mtu($realif);
249
		if (is_numeric($mtu))
250
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
251
		else
252
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
253
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
254
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
255
		$radvdconf .= "\t\tAdvOnLink on;\n";
256
		$radvdconf .= "\t\tAdvAutonomous on;\n";
257
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
258
		$radvdconf .= "\t};\n";
259

    
260
		/* add DNS servers */
261
		$dnslist = array();
262
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
263
			$dnslist[] = $ifcfgipv6;
264
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
265
			foreach($config['system']['dnsserver'] as $server) {
266
				if(is_ipaddrv6($server))
267
					$dnslist[] = $server;
268
			}
269
		}
270
		if (count($dnslist) > 0) {
271
			$dnsstring = implode(" ", $dnslist);
272
			if (!empty($dnsstring))
273
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
274
		}
275
		if (!empty($config['system']['domain'])) {
276
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
277
		}
278
		$radvdconf .= "};\n";
279
	}
280

    
281
	/* write radvd.conf */
282
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
283
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
284
		if (platform_booting())
285
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
286
	}
287
	unset($radvdconf);
288

    
289
	if (count($radvdifs) > 0) {
290
		if (isvalidpid("{$g['varrun_path']}/radvd.pid"))
291
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
292
		else
293
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
294
	} else {
295
		/* we need to shut down the radvd cleanly, it will send out the prefix
296
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
297
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
298
			log_error("Shutting down Router Advertisment daemon cleanly");
299
			killbypid("{$g['varrun_path']}/radvd.pid");
300
			@unlink("{$g['varrun_path']}/radvd.pid");
301
		}
302
	}
303
	return 0;
304
}
305

    
306
function services_dhcpd_configure($family = "all", $blacklist = array()) {
307
	global $config, $g;
308

    
309
	/* configure DHCPD chroot once */
310
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
311
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
312
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
313
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
314
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
315
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
316
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
317
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
318
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
319
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
320
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
321
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
322
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
323
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
324

    
325
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
326
	if (!trim($status))
327
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
328
	fclose($fd);
329
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
330

    
331
	if ($family == "all" || $family == "inet")
332
		services_dhcpdv4_configure();
333
	if ($family == "all" || $family == "inet6") {
334
		services_dhcpdv6_configure($blacklist);
335
		services_radvd_configure($blacklist);
336
	}
337
}
338

    
339
function services_dhcpdv4_configure() {
340
	global $config, $g;
341
	$need_ddns_updates = false;
342
	$ddns_zones = array();
343

    
344
	if($g['services_dhcp_server_enable'] == false)
345
		return;
346

    
347
	if(isset($config['system']['developerspew'])) {
348
		$mt = microtime();
349
		echo "services_dhcpdv4_configure($if) being called $mt\n";
350
	}
351

    
352
	/* kill any running dhcpd */
353
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
354
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
355

    
356
	/* DHCP enabled on any interfaces? */
357
	if (!is_dhcp_server_enabled())
358
		return 0;
359

    
360
	/* if OLSRD is enabled, allow WAN to house DHCP. */
361
	if (!function_exists('is_package_installed'))
362
		require_once('pkg-utils.inc');
363
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd']))
364
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
365
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
366
				$is_olsr_enabled = true;
367
				break;
368
			}
369

    
370
	if (platform_booting()) {
371
		/* restore the leases, if we have them */
372
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
373
			$dhcprestore = "";
374
			$dhcpreturn = "";
375
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
376
			$dhcprestore = implode(" ", $dhcprestore);
377
			if($dhcpreturn <> 0) {
378
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
379
			}
380
		}
381
		/* 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. */
382
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
383
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
384
		}
385
	}
386

    
387
	$syscfg = $config['system'];
388
	if (!is_array($config['dhcpd']))
389
		$config['dhcpd'] = array();
390
	$dhcpdcfg = $config['dhcpd'];
391
	$Iflist = get_configured_interface_list();
392

    
393
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
394
	$dns_arrv4 = array();
395
	if (is_array($syscfg['dnsserver'])) {
396
		foreach($syscfg['dnsserver'] as $dnsserver) {
397
			if (is_ipaddrv4($dnsserver)) {
398
				$dns_arrv4[] = $dnsserver;
399
			}
400
		}
401
	}
402

    
403
	if (platform_booting())
404
		echo gettext("Starting DHCP service...");
405
	else
406
		sleep(1);
407

    
408
	$custoptions = "";
409
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
410
		if(is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
411
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
412
				if(!empty($item['type']))
413
					$itemtype = $item['type'];
414
				else
415
					$itemtype = "text";
416
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
417
			}
418
		}
419
	}
420

    
421
	$dhcpdconf = <<<EOD
422

    
423
option domain-name "{$syscfg['domain']}";
424
option ldap-server code 95 = text;
425
option domain-search-list code 119 = text;
426
option arch code 93 = unsigned integer 16; # RFC4578
427
{$custoptions}
428
default-lease-time 7200;
429
max-lease-time 86400;
430
log-facility local7;
431
one-lease-per-client true;
432
deny duplicates;
433
ping-check true;
434
update-conflict-detection false;
435

    
436
EOD;
437

    
438
	if(!isset($dhcpifconf['disableauthoritative']))
439
		$dhcpdconf .= "authoritative;\n";
440

    
441
	if(isset($dhcpifconf['alwaysbroadcast']))
442
		$dhcpdconf .= "always-broadcast on\n";
443

    
444
	$dhcpdifs = array();
445
	$add_routers = false;
446
	$gateways_arr = return_gateways_array();
447
	/* only add a routers line if the system has any IPv4 gateway at all */
448
	/* a static route has a gateway, manually overriding this field always works */
449
	foreach($gateways_arr as $gwitem) {
450
		if($gwitem['ipprotocol'] == "inet") {
451
			$add_routers = true;
452
			break;
453
		}
454
	}
455

    
456
	/*    loop through and determine if we need to setup
457
	 *    failover peer "bleh" entries
458
	 */
459
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
460

    
461
		if (!isset($config['interfaces'][$dhcpif]['enable']))
462
			continue;
463

    
464
		interfaces_staticarp_configure($dhcpif);
465

    
466
		if (!isset($dhcpifconf['enable']))
467
			continue;
468

    
469
		if($dhcpifconf['failover_peerip'] <> "") {
470
			$intip = get_interface_ip($dhcpif);
471
			/*
472
			 *    yep, failover peer is defined.
473
			 *    does it match up to a defined vip?
474
			 */
475
			$skew = 110;
476
			if(is_array($config['virtualip']['vip'])) {
477
				foreach ($config['virtualip']['vip'] as $vipent) {
478
					if($vipent['interface'] == $dhcpif) {
479
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
480
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
481
							/* this is the interface! */
482
							if(is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
483
								$skew = 0;
484
								break;
485
							}
486
						}
487
					}
488
				}
489
			} else {
490
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
491
			}
492
			if($skew > 10) {
493
				$type = "secondary";
494
				$my_port = "520";
495
				$peer_port = "519";
496
			} else {
497
				$my_port = "519";
498
				$peer_port = "520";
499
				$type = "primary";
500
				$dhcpdconf_pri  = "split 128;\n";
501
				$dhcpdconf_pri .= "  mclt 600;\n";
502
			}
503

    
504
			if (is_ipaddrv4($intip)) {
505
			$dhcpdconf .= <<<EOPP
506
failover peer "dhcp_{$dhcpif}" {
507
  {$type};
508
  address {$intip};
509
  port {$my_port};
510
  peer address {$dhcpifconf['failover_peerip']};
511
  peer port {$peer_port};
512
  max-response-delay 10;
513
  max-unacked-updates 10;
514
  {$dhcpdconf_pri}
515
  load balance max seconds 3;
516
}
517
\n
518
EOPP;
519
			}
520
		}
521
	}
522

    
523
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
524

    
525
		$newzone = array();
526
		$ifcfg = $config['interfaces'][$dhcpif];
527

    
528
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
529
			continue;
530
		$ifcfgip = get_interface_ip($dhcpif);
531
		$ifcfgsn = get_interface_subnet($dhcpif);
532
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
533
		$subnetmask = gen_subnet_mask($ifcfgsn);
534

    
535
		if (!is_ipaddr($subnet))
536
			continue;
537

    
538
		if($is_olsr_enabled == true)
539
			if($dhcpifconf['netmask'])
540
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
541

    
542
		$all_pools = array();
543
		$all_pools[] = $dhcpifconf;
544
		if (is_array($dhcpifconf['pool'])) {
545
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
546
		}
547

    
548
		$dnscfg = "";
549

    
550
		if ($dhcpifconf['domain']) {
551
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
552
		}
553

    
554
		if($dhcpifconf['domainsearchlist'] <> "") {
555
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
556
		}
557

    
558
		if (isset($dhcpifconf['ddnsupdate'])) {
559
			$need_ddns_updates = true;
560
			$newzone = array();
561
			if($dhcpifconf['ddnsdomain'] <> "") {
562
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
563
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
564
			} else {
565
				$newzone['domain-name'] = $config['system']['domain'];
566
			}
567
			$revsubnet = explode(".", $subnet);
568
			$revsubnet = array_reverse($revsubnet);
569
			foreach ($revsubnet as $octet) {
570
				if ($octet != "0")
571
					break;
572
				array_shift($revsubnet);
573
			}
574
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
575
		}
576

    
577
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
578
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
579
			if ($newzone['domain-name'])
580
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
581
		} else if (isset($config['dnsmasq']['enable'])) {
582
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
583
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
584
				$newzone['dns-servers'] = $syscfg['dnsserver'];
585
		} else if (isset($config['unbound']['enable'])) {
586
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
587
		} else if (!empty($dns_arrv4)) {
588
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
589
			if ($newzone['domain-name'])
590
				$newzone['dns-servers'] = $dns_arrv4;
591
		}
592

    
593
		/* Create classes - These all contain comma separated lists. Join them into one 
594
		   big comma separated string then split them all up. */
595
		$all_mac_strings = array();
596
		if (is_array($dhcpifconf['pool'])) {
597
			foreach($all_pools as $poolconf) {
598
				$all_mac_strings[] = $poolconf['mac_allow'];
599
				$all_mac_strings[] = $poolconf['mac_deny'];
600
			}
601
		}
602
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
603
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
604
		$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
605
		foreach ($all_mac_list as $mac) {
606
			if (empty($mac))
607
				continue;
608
			$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
609
			// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
610
			$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
611
			$dhcpdconf .= '}' . "\n";
612
		}
613

    
614
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
615

    
616
// Setup pool options
617
		foreach($all_pools as $poolconf) {
618
			$dhcpdconf .= "	pool {\n";
619
			/* is failover dns setup? */
620
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
621
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
622
				if($poolconf['dnsserver'][1] <> "")
623
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
624
				if($poolconf['dnsserver'][2] <> "")
625
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
626
				if($poolconf['dnsserver'][3] <> "")
627
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
628
				$dhcpdconf .= ";\n";
629
			}
630

    
631
			/* allow/deny MACs */
632
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
633
			foreach ($mac_allow_list as $mac) {
634
				if (empty($mac))
635
					continue;
636
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
637
			}
638
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
639
			foreach ($mac_deny_list as $mac) {
640
				if (empty($mac))
641
					continue;
642
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
643
			}
644

    
645
			if($poolconf['failover_peerip'] <> "")
646
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
647

    
648
			if (isset($poolconf['denyunknown']))
649
			   $dhcpdconf .= "		deny unknown-clients;\n";
650

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

    
654
			if($dhcpifconf['failover_peerip'] <> "") {
655
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
656
			}
657

    
658
			$pdnscfg = "";
659

    
660
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
661
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
662
			}
663

    
664
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
665
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
666
			}
667

    
668
			if (isset($poolconf['ddnsupdate'])) {
669
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
670
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
671
				$pdnscfg .= "		ddns-update-style interim;\n";
672
			}
673

    
674
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
675
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
676
			}
677
			$dhcpdconf .= "{$pdnscfg}";
678

    
679
			// default-lease-time
680
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
681
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
682

    
683
			// max-lease-time
684
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
685
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
686

    
687
			// netbios-name*
688
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
689
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
690
				$dhcpdconf .= "		option netbios-node-type 8;\n";
691
			}
692

    
693
			// ntp-servers
694
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
695
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
696

    
697
			// tftp-server-name
698
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
699
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
700

    
701
			// ldap-server
702
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
703
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
704

    
705
			// net boot information
706
			if(isset($poolconf['netboot'])) {
707
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
708
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
709
				}
710
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
711
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
712
				}
713
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
714
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
715
				}
716
			}
717
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
718
			$dhcpdconf .= "	}\n\n";
719
		}
720
// End of settings inside pools
721

    
722
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
723
			$routers = $dhcpifconf['gateway'];
724
			$add_routers = true;
725
		} elseif ($dhcpifconf['gateway'] == "none") {
726
			$add_routers = false;
727
		} else {
728
			$routers = $ifcfgip;
729
		}
730
		if($add_routers)
731
			$dhcpdconf .= "	option routers {$routers};\n";
732

    
733
		$dhcpdconf .= <<<EOD
734
$dnscfg
735

    
736
EOD;
737
    		// default-lease-time
738
		if ($dhcpifconf['defaultleasetime'])
739
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
740

    
741
		// max-lease-time
742
		if ($dhcpifconf['maxleasetime'])
743
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
744

    
745
		// netbios-name*
746
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
747
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
748
			$dhcpdconf .= "	option netbios-node-type 8;\n";
749
		}
750

    
751
		// ntp-servers
752
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
753
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
754

    
755
		// tftp-server-name
756
		if ($dhcpifconf['tftp'] <> "")
757
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
758

    
759
		// Handle option, number rowhelper values
760
		$dhcpdconf .= "\n";
761
		if($dhcpifconf['numberoptions']['item']) {
762
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
763
				if(empty($item['type']) || $item['type'] == "text")
764
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
765
				else
766
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
767
			}
768
		}
769

    
770
		// ldap-server
771
		if ($dhcpifconf['ldap'] <> "")
772
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
773

    
774
		// net boot information
775
		if(isset($dhcpifconf['netboot'])) {
776
			if ($dhcpifconf['nextserver'] <> "") {
777
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
778
			}
779
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
780
				$dhcpdconf .= "	if option arch = 00:06 {\n";
781
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
782
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
783
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
784
				$dhcpdconf .= "	} else {\n";
785
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
786
				$dhcpdconf .= "	}\n\n";
787
			} elseif (!empty($dhcpifconf['filename'])) {
788
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
789
			}
790
			if (!empty($dhcpifconf['rootpath'])) {
791
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
792
			}
793
		}
794

    
795
		$dhcpdconf .= <<<EOD
796
}
797

    
798
EOD;
799

    
800
		/* add static mappings */
801
		if (is_array($dhcpifconf['staticmap'])) {
802

    
803
			$i = 0;
804
			foreach ($dhcpifconf['staticmap'] as $sm) {
805
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
806

    
807
                if ($sm['mac'])
808
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
809

    
810
                if ($sm['cid'])
811
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
812

    
813
				if ($sm['ipaddr'])
814
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
815

    
816
				if ($sm['hostname']) {
817
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
818
					$dhhostname = str_replace(".", "_", $dhhostname);
819
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
820
				}
821
				if ($sm['filename'])
822
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
823

    
824
				if ($sm['rootpath'])
825
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
826

    
827
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
828
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
829

    
830
				$smdnscfg = "";
831

    
832
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
833
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
834
				}
835

    
836
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
837
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
838
				}
839

    
840
				if (isset($sm['ddnsupdate'])) {
841
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
842
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
843
					$pdnscfg .= "		ddns-update-style interim;\n";
844
				}
845

    
846
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
847
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
848
				}
849
				$dhcpdconf .= "{$smdnscfg}";
850

    
851
				// default-lease-time
852
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
853
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
854

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

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

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

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

    
873
				$dhcpdconf .= "}\n";
874
				$i++;
875
			}
876
		}
877

    
878
		$dhcpdifs[] = get_real_interface($dhcpif);
879
		if ($newzone['domain-name'])
880
		{
881
			if ($need_ddns_updates)
882
			{
883
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
884
			}
885
			$ddns_zones[] = $newzone;
886
		}
887
	}
888

    
889
	if ($need_ddns_updates) {
890
		$dhcpdconf .= "ddns-update-style interim;\n";
891
		$dhcpdconf .= "update-static-leases on;\n";
892

    
893
		$dhcpdconf .= dhcpdkey($dhcpifconf);
894
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
895
	}
896

    
897
	/* write dhcpd.conf */
898
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
899
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
900
		unset($dhcpdconf);
901
		return 1;
902
	}
903
	unset($dhcpdconf);
904

    
905
	/* create an empty leases database */
906
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
907
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
908

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

    
913
	/* fire up dhcpd in a chroot */
914
	if (count($dhcpdifs) > 0) {
915
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
916
			join(" ", $dhcpdifs));
917
	}
918

    
919
	if (platform_booting())
920
		print "done.\n";
921

    
922
	return 0;
923
}
924

    
925
function dhcpdkey($dhcpifconf)
926
{
927
	$dhcpdconf = "";
928
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
929
	{
930
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
931
		$dhcpdconf .= "	algorithm hmac-md5;\n";
932
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
933
		$dhcpdconf .= "}\n";
934
	}
935

    
936
	return $dhcpdconf;
937
}
938

    
939
function dhcpdzones($ddns_zones, $dhcpifconf)
940
{
941
	$dhcpdconf = "";
942

    
943
	if (is_array($ddns_zones)) {
944
		$added_zones = array();
945
		foreach ($ddns_zones as $zone) {
946
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
947
				continue;
948
			$primary = $zone['dns-servers'][0];
949
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
950

    
951
			// Make sure we aren't using any invalid or IPv6 DNS servers.
952
			if (!is_ipaddrv4($primary)) {
953
				if (is_ipaddrv4($secondary)) {
954
					$primary = $secondary;
955
					$secondary = "";
956
				} else {
957
					continue;
958
				}
959
			}
960

    
961
			// We don't need to add zones multiple times.
962
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
963
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
964
				$dhcpdconf .= "	primary {$primary};\n";
965
				if (is_ipaddrv4($secondary))
966
					$dhcpdconf .= "	secondary {$secondary};\n";
967
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
968
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
969
				$dhcpdconf .= "}\n";
970
				$added_zones[] = $zone['domain-name'];
971
			}
972
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
973
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
974
				$dhcpdconf .= "	primary {$primary};\n";
975
				if (is_ipaddrv4($secondary))
976
					$dhcpdconf .= "	secondary {$secondary};\n";
977
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
978
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
979
				$dhcpdconf .= "}\n";
980
				$added_zones[] = $zone['ptr-domain'];
981
			}
982
		}
983
	}
984

    
985
	return $dhcpdconf;
986
}
987

    
988
function services_dhcpdv6_configure($blacklist = array()) {
989
	global $config, $g;
990

    
991
	if($g['services_dhcp_server_enable'] == false)
992
		return;
993

    
994
	if(isset($config['system']['developerspew'])) {
995
		$mt = microtime();
996
		echo "services_dhcpd_configure($if) being called $mt\n";
997
	}
998

    
999
	/* kill any running dhcpd */
1000
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
1001
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1002
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
1003
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1004

    
1005
	/* DHCP enabled on any interfaces? */
1006
	if (!is_dhcpv6_server_enabled())
1007
		return 0;
1008

    
1009
	if (platform_booting()) {
1010
		if ($g['platform'] != "pfSense") {
1011
			/* restore the leases, if we have them */
1012
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1013
				$dhcprestore = "";
1014
				$dhcpreturn = "";
1015
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1016
				$dhcprestore = implode(" ", $dhcprestore);
1017
				if($dhcpreturn <> 0) {
1018
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1019
				}
1020
			}
1021
		}
1022
	}
1023

    
1024
	$syscfg = $config['system'];
1025
	if (!is_array($config['dhcpdv6']))
1026
		$config['dhcpdv6'] = array();
1027
	$dhcpdv6cfg = $config['dhcpdv6'];
1028
	$Iflist = get_configured_interface_list();
1029
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1030

    
1031

    
1032
	if (platform_booting())
1033
		echo "Starting DHCPv6 service...";
1034
	else
1035
		sleep(1);
1036

    
1037
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1038
	foreach ($Iflist as $ifname) {
1039
		/* Do not put in the config an interface which is down */
1040
		if (isset($blacklist[$ifname]))
1041
			continue;
1042
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1043
			$realif = get_real_interface($ifname, "inet6");
1044
			$ifcfgipv6 = get_interface_ipv6($ifname);
1045
			if(!is_ipaddrv6($ifcfgipv6))
1046
				continue;
1047
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1048
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1049
			$trackcfg = $config['interfaces'][$trackifname];
1050
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1051
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1052
			$dhcpdv6cfg[$ifname] = array();
1053
			$dhcpdv6cfg[$ifname]['enable'] = true;
1054
			/* range */
1055
			$ifcfgipv6arr[7] = "1000";
1056
			$dhcpdv6cfg[$ifname]['range'] = array();
1057
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1058
			$ifcfgipv6arr[7] = "2000";
1059
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1060
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1061
			if($pdlen > 2) {
1062
				$pdlenmax = $pdlen;
1063
				$pdlenhalf = $pdlenmax -1;
1064
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1065
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1066
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1067

    
1068
				/* set the delegation start to half the current address block */
1069
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1070
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1071

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

    
1076
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1077
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1078
				$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1079
			}
1080
		}
1081
	}
1082

    
1083
	$custoptionsv6 = "";
1084
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1085
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1086
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1087
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1088
			}
1089
		}
1090
	}
1091

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

    
1095
	$dhcpdv6conf = <<<EOD
1096

    
1097
option domain-name "{$syscfg['domain']}";
1098
option ldap-server code 95 = text;
1099
option domain-search-list code 119 = text;
1100
{$custoptionsv6}
1101
default-lease-time 7200;
1102
max-lease-time 86400;
1103
log-facility local7;
1104
one-lease-per-client true;
1105
deny duplicates;
1106
ping-check true;
1107
update-conflict-detection false;
1108

    
1109
EOD;
1110

    
1111
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1112
		$dhcpdv6conf .= "authoritative;\n";
1113

    
1114
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1115
		$dhcpdv6conf .= "always-broadcast on\n";
1116

    
1117
	$dhcpdv6ifs = array();
1118

    
1119
	$dhcpv6num = 0;
1120
	$nsupdate = false;
1121

    
1122
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1123

    
1124
		$ddns_zones = array();
1125

    
1126
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1127

    
1128
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable']))
1129
			continue;
1130
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1131
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1132
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1133

    
1134
		if ($is_olsr_enabled == true) {
1135
			if($dhcpv6ifconf['netmask'])
1136
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1137
		}
1138

    
1139
		$dnscfgv6 = "";
1140

    
1141
		if ($dhcpv6ifconf['domain']) {
1142
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1143
		}
1144

    
1145
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1146
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1147
    	}
1148

    
1149
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1150
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1151
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1152
			}
1153
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1154
			$nsupdate = true;
1155
		}
1156

    
1157
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1158
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1159
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1160
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1161
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1162
			$dns_arrv6 = array();
1163
			foreach($syscfg['dnsserver'] as $dnsserver) {
1164
				if (is_ipaddrv6($dnsserver)) {
1165
					$dns_arrv6[] = $dnsserver;
1166
				}
1167
			}
1168
			if(!empty($dns_arrv6))
1169
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1170
		}
1171

    
1172
		if ($dhcpv6ifconf['domain']) {
1173
			$newzone = array();
1174
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1175
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1176
			$ddns_zones[] = $newzone;
1177
		}
1178

    
1179
		if (is_ipaddrv6($ifcfgipv6)) {
1180
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1181
		} else {
1182
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1183
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1184
		}
1185
		$dhcpdv6conf .= " {\n";
1186

    
1187
		$dhcpdv6conf .= <<<EOD
1188
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1189
$dnscfgv6
1190

    
1191
EOD;
1192

    
1193
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1194
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1195
		}
1196
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1197
			$dhcpdv6conf .= "       option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1198
		}
1199
    		// default-lease-time
1200
		if ($dhcpv6ifconf['defaultleasetime'])
1201
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1202

    
1203
		// max-lease-time
1204
		if ($dhcpv6ifconf['maxleasetime'])
1205
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1206

    
1207
		// ntp-servers
1208
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1209
			$ntpservers = array();
1210
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1211
				if(is_ipaddrv6($ntpserver))
1212
					$ntpservers[] = $ntpserver;
1213
			}
1214
			if(count($ntpservers) > 0 )
1215
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1216
		}
1217
		// tftp-server-name
1218
		/* Needs ISC DHCPD support
1219
		 if ($dhcpv6ifconf['tftp'] <> "")
1220
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1221
		*/
1222

    
1223
		// Handle option, number rowhelper values
1224
		$dhcpdv6conf .= "\n";
1225
		if ($dhcpv6ifconf['numberoptions']['item']) {
1226
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1227
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1228
			}
1229
		}
1230

    
1231
		// ldap-server
1232
		if ($dhcpv6ifconf['ldap'] <> "")
1233
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1234

    
1235
		// net boot information
1236
		if(isset($dhcpv6ifconf['netboot'])) {
1237
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1238
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1239
			}
1240
		}
1241

    
1242
		$dhcpdv6conf .= "}\n";
1243

    
1244
		/* add static mappings */
1245
		/* Needs to use DUID */
1246
		if (is_array($dhcpv6ifconf['staticmap'])) {
1247
			$i = 0;
1248
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1249
				$dhcpdv6conf .= <<<EOD
1250
host s_{$dhcpv6if}_{$i} {
1251
	host-identifier option dhcp6.client-id {$sm['duid']};
1252

    
1253
EOD;
1254
				if ($sm['ipaddrv6'])
1255
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1256

    
1257
				if ($sm['hostname']) {
1258
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1259
					$dhhostname = str_replace(".", "_", $dhhostname);
1260
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1261
				}
1262
				if ($sm['filename'])
1263
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1264

    
1265
				if ($sm['rootpath'])
1266
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1267

    
1268
				$dhcpdv6conf .= "}\n";
1269
				$i++;
1270
			}
1271
		}
1272

    
1273
		if ($dhcpv6ifconf['domain'])
1274
		{
1275
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1276
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1277
		}
1278

    
1279
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1280
			if(preg_match("/poes/si", $dhcpv6if)) {
1281
				/* magic here */
1282
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1283
			} else {
1284
				$realif = get_real_interface($dhcpv6if, "inet6");
1285
				if (stristr("$realif", "bridge")) {
1286
					$mac = get_interface_mac($realif);
1287
					$v6address = generate_ipv6_from_mac($mac);
1288
					/* Create link local address for bridges */
1289
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1290
				}
1291
				$realif = escapeshellcmd($realif);
1292
				$dhcpdv6ifs[] = $realif;
1293
			}
1294
		}
1295
	}
1296

    
1297
	if ($nsupdate)
1298
	{
1299
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1300
	}
1301
	else
1302
	{
1303
		$dhcpdv6conf .= "ddns-update-style none;\n";
1304
	}
1305

    
1306
	/* write dhcpdv6.conf */
1307
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1308
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1309
		if (platform_booting())
1310
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1311
		unset($dhcpdv6conf);
1312
		return 1;
1313
	}
1314
	unset($dhcpdv6conf);
1315

    
1316
	/* create an empty leases v6 database */
1317
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1318
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1319

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

    
1324
	/* fire up dhcpd in a chroot */
1325
	if (count($dhcpdv6ifs) > 0) {
1326
		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 " .
1327
			join(" ", $dhcpdv6ifs));
1328
		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");
1329
	}
1330
	if (platform_booting())
1331
		print gettext("done.") . "\n";
1332

    
1333
	return 0;
1334
}
1335

    
1336
function services_igmpproxy_configure() {
1337
        global $config, $g;
1338

    
1339
        /* kill any running igmpproxy */
1340
        killbyname("igmpproxy");
1341

    
1342
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1343
		return 1;
1344

    
1345
        $iflist = get_configured_interface_list();
1346

    
1347
        $igmpconf = <<<EOD
1348

    
1349
##------------------------------------------------------
1350
## Enable Quickleave mode (Sends Leave instantly)
1351
##------------------------------------------------------
1352
quickleave
1353

    
1354
EOD;
1355

    
1356
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1357
                unset($iflist[$igmpcf['ifname']]);
1358
                $realif = get_real_interface($igmpcf['ifname']);
1359
                if (empty($igmpcf['threshold']))
1360
                        $threshld = 1;
1361
                else
1362
                        $threshld = $igmpcf['threshold'];
1363
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1364

    
1365
                if ($igmpcf['address'] <> "") {
1366
                        $item = explode(" ", $igmpcf['address']);
1367
                        foreach($item as $iww)
1368
                                $igmpconf .= "altnet {$iww}\n";
1369
                }
1370
                $igmpconf .= "\n";
1371
        }
1372
        foreach ($iflist as $ifn) {
1373
                $realif = get_real_interface($ifn);
1374
                $igmpconf .= "phyint {$realif} disabled\n";
1375
        }
1376
	$igmpconf .= "\n";
1377

    
1378
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1379
        if (!$igmpfl) {
1380
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1381
                return;
1382
        }
1383
        fwrite($igmpfl, $igmpconf);
1384
        fclose($igmpfl);
1385
	unset($igmpconf);
1386

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

    
1391
        return 0;
1392
}
1393

    
1394
function services_dhcrelay_configure() {
1395
	global $config, $g;
1396
	if ($g['platform'] == 'jail')
1397
		return;
1398
	if(isset($config['system']['developerspew'])) {
1399
		$mt = microtime();
1400
		echo "services_dhcrelay_configure() being called $mt\n";
1401
	}
1402

    
1403
	/* kill any running dhcrelay */
1404
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1405

    
1406
	$dhcrelaycfg =& $config['dhcrelay'];
1407

    
1408
	/* DHCPRelay enabled on any interfaces? */
1409
	if (!isset($dhcrelaycfg['enable']))
1410
		return 0;
1411

    
1412
	if (platform_booting())
1413
		echo gettext("Starting DHCP relay service...");
1414
	else
1415
		sleep(1);
1416

    
1417
	$iflist = get_configured_interface_list();
1418

    
1419
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1420
	foreach ($dhcifaces as $dhcrelayif) {
1421
		if (!isset($iflist[$dhcrelayif]) ||
1422
			link_interface_to_bridge($dhcrelayif))
1423
			continue;
1424

    
1425
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1426
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1427
	}
1428

    
1429
	/*
1430
	 * In order for the relay to work, it needs to be active
1431
	 * on the interface in which the destination server sits.
1432
	 */
1433
	$srvips = explode(",", $dhcrelaycfg['server']);
1434
	foreach ($srvips as $srcidx => $srvip) {
1435
		unset($destif);
1436
		foreach ($iflist as $ifname) {
1437
			$subnet = get_interface_ip($ifname);
1438
			if (!is_ipaddr($subnet))
1439
				continue;
1440
			$subnet .=  "/" . get_interface_subnet($ifname);
1441
			if (ip_in_subnet($srvip, $subnet)) {
1442
				$destif = get_real_interface($ifname);
1443
				break;
1444
			}
1445
		}
1446
		if (!isset($destif)) {
1447
			foreach (get_staticroutes() as $rtent) {
1448
				if (ip_in_subnet($srvip, $rtent['network'])) {
1449
					$a_gateways = return_gateways_array(true);
1450
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1451
					break;
1452
				}
1453
			}
1454
		}
1455

    
1456
		if (!isset($destif)) {
1457
			/* Create a array from the existing route table */
1458
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1459
        		array_shift($route_str);
1460
        		array_shift($route_str);
1461
        		array_shift($route_str);
1462
        		array_shift($route_str);
1463
        		$route_arr = array();
1464
        		foreach($route_str as $routeline) {
1465
				$items = preg_split("/[ ]+/i", $routeline);
1466
				if (is_subnetv4($items[0])) {
1467
					$subnet = $items[0];
1468
				} elseif (is_ipaddrv4($items[0])) {
1469
					$subnet = "{$items[0]}/32";
1470
				} else {
1471
					// Not a subnet or IP address, skip to the next line.
1472
					continue;
1473
				}
1474
				if (ip_in_subnet($srvip, $subnet)) {
1475
					$destif = trim($items[6]);
1476
					break;
1477
				}
1478
			}
1479
		}
1480

    
1481
		if (!isset($destif)) {
1482
			if (is_array($config['gateways']['gateway_item'])) {
1483
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1484
					if (isset($gateway['defaultgw'])) {
1485
						$destif = get_real_interface($gateway['interface']);
1486
						break;
1487
					}
1488
				}
1489
			} else
1490
				$destif = get_real_interface("wan");
1491
		}
1492

    
1493
		if (!empty($destif))
1494
			$dhcrelayifs[] = $destif;
1495
	}
1496
	$dhcrelayifs = array_unique($dhcrelayifs);
1497

    
1498
	/* fire up dhcrelay */
1499
	if (empty($dhcrelayifs)) {
1500
		log_error("No suitable interface found for running dhcrelay!");
1501
		return; /* XXX */
1502
	}
1503

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

    
1506
	if (isset($dhcrelaycfg['agentoption']))
1507
		$cmd .=  " -a -m replace";
1508

    
1509
	$cmd .= " " . implode(" ", $srvips);
1510
	mwexec($cmd);
1511
	unset($cmd);
1512

    
1513
	return 0;
1514
}
1515

    
1516
function services_dhcrelay6_configure() {
1517
	global $config, $g;
1518
	if ($g['platform'] == 'jail')
1519
		return;
1520
	if(isset($config['system']['developerspew'])) {
1521
		$mt = microtime();
1522
		echo "services_dhcrelay6_configure() being called $mt\n";
1523
	}
1524

    
1525
	/* kill any running dhcrelay */
1526
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1527

    
1528
	$dhcrelaycfg =& $config['dhcrelay6'];
1529

    
1530
	/* DHCPv6 Relay enabled on any interfaces? */
1531
	if (!isset($dhcrelaycfg['enable']))
1532
		return 0;
1533

    
1534
	if (platform_booting())
1535
		echo gettext("Starting DHCPv6 relay service...");
1536
	else
1537
		sleep(1);
1538

    
1539
	$iflist = get_configured_interface_list();
1540

    
1541
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1542
	foreach ($dhcifaces as $dhcrelayif) {
1543
		if (!isset($iflist[$dhcrelayif]) ||
1544
			link_interface_to_bridge($dhcrelayif))
1545
			continue;
1546

    
1547
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1548
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1549
	}
1550
	$dhcrelayifs = array_unique($dhcrelayifs);
1551

    
1552
	/*
1553
	 * In order for the relay to work, it needs to be active
1554
	 * on the interface in which the destination server sits.
1555
	 */
1556
	$srvips = explode(",", $dhcrelaycfg['server']);
1557
        $srvifaces = array();
1558
	foreach ($srvips as $srcidx => $srvip) {
1559
		unset($destif);
1560
		foreach ($iflist as $ifname) {
1561
			$subnet = get_interface_ipv6($ifname);
1562
			if (!is_ipaddrv6($subnet))
1563
				continue;
1564
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1565
			if (ip_in_subnet($srvip, $subnet)) {
1566
				$destif = get_real_interface($ifname);
1567
				break;
1568
			}
1569
		}
1570
		if (!isset($destif)) {
1571
			if (is_array($config['staticroutes']['route'])) {
1572
				foreach ($config['staticroutes']['route'] as $rtent) {
1573
					if (ip_in_subnet($srvip, $rtent['network'])) {
1574
						$a_gateways = return_gateways_array(true);
1575
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1576
						break;
1577
					}
1578
				}
1579
			}
1580
		}
1581

    
1582
		if (!isset($destif)) {
1583
			/* Create a array from the existing route table */
1584
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1585
        		array_shift($route_str);
1586
        		array_shift($route_str);
1587
        		array_shift($route_str);
1588
        		array_shift($route_str);
1589
        		$route_arr = array();
1590
        		foreach($route_str as $routeline) {
1591
                		$items = preg_split("/[ ]+/i", $routeline);
1592
				if (ip_in_subnet($srvip, $items[0])) {
1593
					$destif = trim($items[6]);
1594
					break;
1595
				}
1596
        		}
1597
		}
1598

    
1599
		if (!isset($destif)) {
1600
			if (is_array($config['gateways']['gateway_item'])) {
1601
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1602
					if (isset($gateway['defaultgw'])) {
1603
						$destif = $gateway['interface'];
1604
						break;
1605
					}
1606
				}
1607
			} else
1608
				$destif = get_real_interface("wan");
1609
		}
1610

    
1611
		if (!empty($destif)) {
1612
			$srvifaces[] = "{$srvip}%{$destif}";
1613
		}
1614
	}
1615

    
1616
	/* fire up dhcrelay */
1617
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1618
		log_error("No suitable interface found for running dhcrelay -6!");
1619
		return; /* XXX */
1620
	}
1621

    
1622
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1623
	foreach ($dhcrelayifs as $dhcrelayif) {
1624
		$cmd .= " -l {$dhcrelayif}";
1625
	}
1626
	foreach ($srvifaces as $srviface) {
1627
		$cmd .= " -u \"{$srviface}\"";
1628
	}
1629
	mwexec($cmd);
1630
	unset($cmd);
1631

    
1632
	return 0;
1633
}
1634

    
1635
function services_dyndns_configure_client($conf) {
1636

    
1637
	if (!isset($conf['enable']))
1638
		return;
1639

    
1640
	/* load up the dyndns.class */
1641
	require_once("dyndns.class");
1642

    
1643
	$dns = new updatedns($dnsService = $conf['type'],
1644
		$dnsHost = $conf['host'],
1645
		$dnsUser = $conf['username'],
1646
		$dnsPass = $conf['password'],
1647
		$dnsWilcard = $conf['wildcard'],
1648
		$dnsMX = $conf['mx'],
1649
		$dnsIf = "{$conf['interface']}",
1650
		$dnsBackMX = NULL,
1651
		$dnsServer = NULL,
1652
		$dnsPort = NULL,
1653
		$dnsUpdateURL = "{$conf['updateurl']}",
1654
		$forceUpdate = $conf['force'],
1655
		$dnsZoneID=$conf['zoneid'],
1656
		$dnsTTL=$conf['ttl'],
1657
		$dnsResultMatch = "{$conf['resultmatch']}",
1658
		$dnsRequestIf = "{$conf['requestif']}",
1659
		$dnsID = "{$conf['id']}",
1660
		$dnsVerboseLog = $conf['verboselog'],
1661
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1662
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1663
}
1664

    
1665
function services_dyndns_configure($int = "") {
1666
	global $config, $g;
1667
	if(isset($config['system']['developerspew'])) {
1668
		$mt = microtime();
1669
		echo "services_dyndns_configure() being called $mt\n";
1670
	}
1671

    
1672
	$dyndnscfg = $config['dyndnses']['dyndns'];
1673
	$gwgroups = return_gateway_groups_array();
1674
	if (is_array($dyndnscfg)) {
1675
		if (platform_booting())
1676
			echo gettext("Starting DynDNS clients...");
1677

    
1678
		foreach ($dyndnscfg as $dyndns) {
1679
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1680
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1681
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1682
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1683
				services_dyndns_configure_client($dyndns);
1684
				sleep(1);
1685
			}
1686
		}
1687

    
1688
		if (platform_booting())
1689
			echo gettext("done.") . "\n";
1690
	}
1691

    
1692
	return 0;
1693
}
1694

    
1695
function dyndnsCheckIP($int) {
1696
	global $config;
1697
	$ip_address = get_interface_ip($int);
1698
	if (is_private_ip($ip_address)) {
1699
		$gateways_status = return_gateways_status(true);
1700
		// If the gateway for this interface is down, then the external check cannot work.
1701
		// Avoid the long wait for the external check to timeout.
1702
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1703
			return "down";
1704
		$hosttocheck = "http://checkip.dyndns.org";
1705
		$ip_ch = curl_init($hosttocheck);
1706
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1707
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1708
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1709
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1710
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1711
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1712
		$ip_result_page = curl_exec($ip_ch);
1713
		curl_close($ip_ch);
1714
		$ip_result_decoded = urldecode($ip_result_page);
1715
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1716
		$ip_address = trim($matches[1]);
1717
	}
1718
	return $ip_address;
1719
}
1720

    
1721
function services_dnsmasq_configure() {
1722
	global $config, $g;
1723
	$return = 0;
1724

    
1725
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1726
	$standard_args = array(
1727
		"dns-forward-max" => "--dns-forward-max=5000",
1728
		"cache-size" => "--cache-size=10000",
1729
		"local-ttl" => "--local-ttl=1"
1730
	);
1731

    
1732

    
1733
	if(isset($config['system']['developerspew'])) {
1734
		$mt = microtime();
1735
		echo "services_dnsmasq_configure() being called $mt\n";
1736
	}
1737

    
1738
	/* kill any running dnsmasq */
1739
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1740
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1741

    
1742
	if (isset($config['dnsmasq']['enable'])) {
1743

    
1744
		if (platform_booting())
1745
			echo gettext("Starting DNS forwarder...");
1746
		else
1747
			sleep(1);
1748

    
1749
                /* generate hosts file */
1750
                if(system_hosts_generate()!=0)
1751
                        $return = 1;
1752

    
1753
		$args = "";
1754

    
1755
		if (isset($config['dnsmasq']['regdhcp'])) {
1756
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1757
		}
1758

    
1759
		/* Setup listen port, if non-default */
1760
		if (is_port($config['dnsmasq']['port']))
1761
			$args .= " --port={$config['dnsmasq']['port']} ";
1762

    
1763
		$listen_addresses = "";
1764
		if(isset($config['dnsmasq']['interface'])) {
1765
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1766
			foreach ($interfaces as $interface) {
1767
				if (is_ipaddrv4($interface)) {
1768
					$listen_addresses .= " --listen-address={$interface} ";
1769
				} else if (is_ipaddrv6($interface)) {
1770
					/*
1771
					 * XXX: Since dnsmasq does not support link-local address
1772
					 * with scope specified. These checks are being done.
1773
					 */
1774
					if (is_linklocal($interface) && strstr($interface, "%")) {
1775
						$tmpaddrll6 = explode("%", $interface);
1776
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1777
					} else 
1778
						$listen_addresses .= " --listen-address={$interface} ";
1779
				} else if (strstr($interface, "_vip")) {
1780
					$laddr = get_configured_carp_interface_list($interface);
1781
					if (is_ipaddr($laddr)) 
1782
						$listen_addresses .= " --listen-address={$laddr} ";
1783
				} else {
1784
					$if = get_real_interface($interface);
1785
					if (does_interface_exist($if)) {
1786
						$laddr = find_interface_ip($if);
1787
						if (is_ipaddrv4($laddr))
1788
							$listen_addresses .= " --listen-address={$laddr} ";
1789
						$laddr6 = find_interface_ipv6($if);
1790
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1791
							/*
1792
							 * XXX: Since dnsmasq does not support link-local address
1793
							 * with scope specified. These checks are being done.
1794
							 */
1795
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1796
								$tmpaddrll6 = explode("%", $laddr6);
1797
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1798
							} else
1799
								$listen_addresses .= " --listen-address={$laddr6} ";
1800
						}
1801
					}
1802
				}
1803
			}
1804
			if (!empty($listen_addresses)) {
1805
				$args .= " {$listen_addresses} ";
1806
				if (isset($config['dnsmasq']['strictbind']))
1807
					$args .= " --bind-interfaces ";
1808
			}
1809
		}
1810

    
1811
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1812
		/* If any of these are duplicated by a user-specified domain override (e.g. 10.in-addr.arpa) then */
1813
		/* the user-specified entry made later on the command line below will be the one that is effective. */
1814
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1815
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1816
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1817
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1818
			$args .= " --server=/10.in-addr.arpa/ ";
1819
			$args .= " --server=/168.192.in-addr.arpa/ ";
1820
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1821
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1822
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1823
			}
1824
		}
1825

    
1826
		/* Setup forwarded domains */
1827
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1828
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1829
				if ($override['ip'] == "!")
1830
					$override[ip] = "";
1831
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1832
			}
1833
		}
1834

    
1835
		/* Allow DNS Rebind for forwarded domains */
1836
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1837
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1838
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1839
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1840
				}
1841
			}
1842
		}
1843

    
1844
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1845
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1846

    
1847
		if (isset($config['dnsmasq']['strict_order'])) {
1848
			$args .= " --strict-order ";
1849
		}
1850

    
1851
		if (isset($config['dnsmasq']['domain_needed'])) {
1852
			$args .= " --domain-needed ";
1853
		}
1854

    
1855
		if ($config['dnsmasq']['custom_options'])
1856
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1857
				$args .= " " . escapeshellarg("--{$c}");
1858
				$p = explode('=', $c);
1859
				if (array_key_exists($p[0], $standard_args))
1860
					unset($standard_args[$p[0]]);
1861
			}
1862
		$args .= ' ' . implode(' ', array_values($standard_args));
1863

    
1864
		/* run dnsmasq */
1865
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1866
		//log_error("dnsmasq command: {$cmd}");
1867
		mwexec_bg($cmd);
1868
		unset($args);
1869

    
1870
        system_dhcpleases_configure();
1871

    
1872
		if (platform_booting())
1873
			echo gettext("done.") . "\n";
1874
	}
1875

    
1876
	if (!platform_booting()) {
1877
		if(services_dhcpd_configure()!=0)
1878
			$return = 1;
1879
	}
1880

    
1881
	return $return;
1882
}
1883

    
1884
function services_unbound_configure() {
1885
	global $config, $g;
1886
	$return = 0;
1887

    
1888
	if (isset($config['system']['developerspew'])) {
1889
		$mt = microtime();
1890
		echo "services_unbound_configure() being called $mt\n";
1891
	}
1892

    
1893
	// kill any running Unbound instance
1894
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1895
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1896

    
1897
	if (isset($config['unbound']['enable'])) {
1898
		if (platform_booting())
1899
			echo gettext("Starting DNS Resolver...");
1900
		else
1901
			sleep(1);
1902

    
1903
		/* generate hosts file */
1904
		if(system_hosts_generate()!=0)
1905
			$return = 1;
1906

    
1907
		require_once('/etc/inc/unbound.inc');
1908
		sync_unbound_service();
1909
		if (platform_booting())
1910
			echo gettext("done.") . "\n";
1911

    
1912
        system_dhcpleases_configure();
1913
	}
1914

    
1915
	if (!platform_booting()) {
1916
		if (services_dhcpd_configure()!=0)
1917
			$return = 1;
1918
	}
1919

    
1920
	return $return;
1921
}
1922

    
1923
function services_snmpd_configure() {
1924
	global $config, $g;
1925
	if(isset($config['system']['developerspew'])) {
1926
		$mt = microtime();
1927
		echo "services_snmpd_configure() being called $mt\n";
1928
	}
1929

    
1930
	/* kill any running snmpd */
1931
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1932
	sleep(2);
1933
	if(is_process_running("bsnmpd"))
1934
		mwexec("/usr/bin/killall bsnmpd", true);
1935

    
1936
	if (isset($config['snmpd']['enable'])) {
1937

    
1938
		if (platform_booting())
1939
			echo gettext("Starting SNMP daemon... ");
1940

    
1941
		/* generate snmpd.conf */
1942
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1943
		if (!$fd) {
1944
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1945
			return 1;
1946
		}
1947

    
1948

    
1949
		$snmpdconf = <<<EOD
1950
location := "{$config['snmpd']['syslocation']}"
1951
contact := "{$config['snmpd']['syscontact']}"
1952
read := "{$config['snmpd']['rocommunity']}"
1953

    
1954
EOD;
1955

    
1956
/* No docs on what write strings do there for disable for now.
1957
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1958
		    $snmpdconf .= <<<EOD
1959
# write string
1960
write := "{$config['snmpd']['rwcommunity']}"
1961

    
1962
EOD;
1963
		}
1964
*/
1965

    
1966

    
1967
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1968
		    $snmpdconf .= <<<EOD
1969
# SNMP Trap support.
1970
traphost := {$config['snmpd']['trapserver']}
1971
trapport := {$config['snmpd']['trapserverport']}
1972
trap := "{$config['snmpd']['trapstring']}"
1973

    
1974

    
1975
EOD;
1976
		}
1977

    
1978
		$version = trim(file_get_contents('/etc/version'));
1979
		$platform = trim(file_get_contents('/etc/platform'));
1980
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1981
			$platform = $g['product_name'];
1982
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1983
			" {$version} {$platform} " . php_uname("s") .
1984
			" " . php_uname("r") . " " . php_uname("m");
1985

    
1986
		$snmpdconf .= <<<EOD
1987
system := 1     # pfSense
1988
%snmpd
1989
sysDescr			= "{$sysDescr}"
1990
begemotSnmpdDebugDumpPdus       = 2
1991
begemotSnmpdDebugSyslogPri      = 7
1992
begemotSnmpdCommunityString.0.1 = $(read)
1993

    
1994
EOD;
1995

    
1996
/* No docs on what write strings do there for disable for now.
1997
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1998
		    $snmpdconf .= <<<EOD
1999
begemotSnmpdCommunityString.0.2 = $(write)
2000

    
2001
EOD;
2002
		}
2003
*/
2004

    
2005

    
2006
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2007
		    $snmpdconf .= <<<EOD
2008
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2009
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2010
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2011

    
2012
EOD;
2013
		}
2014

    
2015

    
2016
		$snmpdconf .= <<<EOD
2017
begemotSnmpdCommunityDisable    = 1
2018

    
2019
EOD;
2020

    
2021
		if (isset($config['snmpd']['bindlan'])) {
2022
			$config['snmpd']['bindip'] = 'lan';
2023
			unset($config['snmpd']['bindlan']);
2024
		}
2025
		$bind_to_ip = "0.0.0.0";
2026
		if(isset($config['snmpd']['bindip'])) {
2027
			if (is_ipaddr($config['snmpd']['bindip'])) {
2028
				$bind_to_ip = $config['snmpd']['bindip'];
2029
			} else {
2030
				$if = get_real_interface($config['snmpd']['bindip']);
2031
				if (does_interface_exist($if))
2032
					$bind_to_ip = find_interface_ip($if);
2033
			}
2034
		}
2035

    
2036
		if(is_port( $config['snmpd']['pollport'] )) {
2037
		    $snmpdconf .= <<<EOD
2038
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2039

    
2040
EOD;
2041

    
2042
		}
2043

    
2044
		$snmpdconf .= <<<EOD
2045
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2046
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2047

    
2048
# These are bsnmp macros not php vars.
2049
sysContact      = $(contact)
2050
sysLocation     = $(location)
2051
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2052

    
2053
snmpEnableAuthenTraps = 2
2054

    
2055
EOD;
2056

    
2057
		if (is_array( $config['snmpd']['modules'] )) {
2058
		    if(isset($config['snmpd']['modules']['mibii'])) {
2059
			$snmpdconf .= <<<EOD
2060
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2061

    
2062
EOD;
2063
		    }
2064

    
2065
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2066
			$snmpdconf .= <<<EOD
2067
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2068
%netgraph
2069
begemotNgControlNodeName = "snmpd"
2070

    
2071
EOD;
2072
		    }
2073

    
2074
		    if(isset($config['snmpd']['modules']['pf'])) {
2075
			$snmpdconf .= <<<EOD
2076
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2077

    
2078
EOD;
2079
		    }
2080

    
2081
		    if(isset($config['snmpd']['modules']['hostres'])) {
2082
			$snmpdconf .= <<<EOD
2083
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2084

    
2085
EOD;
2086
		    }
2087
		    if(isset($config['snmpd']['modules']['bridge'])) {
2088
			$snmpdconf .= <<<EOD
2089
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2090
# config must end with blank line
2091

    
2092
EOD;
2093
		    }
2094
			if(isset($config['snmpd']['modules']['ucd'])) {
2095
				$snmpdconf .= <<<EOD
2096
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2097

    
2098
EOD;
2099
			}
2100
			if(isset($config['snmpd']['modules']['regex'])) {
2101
				$snmpdconf .= <<<EOD
2102
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2103

    
2104
EOD;
2105
			}
2106
		}
2107

    
2108
		fwrite($fd, $snmpdconf);
2109
		fclose($fd);
2110
		unset($snmpdconf);
2111

    
2112
		if (isset($config['snmpd']['bindlan'])) {
2113
			$bindlan = "";
2114
		}
2115

    
2116
		/* run bsnmpd */
2117
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2118
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2119

    
2120
		if (platform_booting())
2121
			echo gettext("done.") . "\n";
2122
	}
2123

    
2124
	return 0;
2125
}
2126

    
2127
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2128
	global $config, $g;
2129
	if(isset($config['system']['developerspew'])) {
2130
		$mt = microtime();
2131
		echo "services_dnsupdate_process() being called $mt\n";
2132
	}
2133

    
2134
	/* Dynamic DNS updating active? */
2135
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2136
		$notify_text = "";
2137
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2138
			if (!isset($dnsupdate['enable']))
2139
				continue;
2140
			if (!empty($int) && $int != $dnsupdate['interface'])
2141
				continue;
2142
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2143
				continue;
2144

    
2145
			/* determine interface name */
2146
			$if = get_real_interface($dnsupdate['interface']);
2147
			
2148
			if (isset($dnsupdate['usepublicip']))
2149
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2150
                        else
2151
                                $wanip = get_interface_ip($dnsupdate['interface']);
2152
			
2153
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2154
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2155
			$currentTime = time();
2156

    
2157
			if ($wanip || $wanipv6) {
2158
				$keyname = $dnsupdate['keyname'];
2159
				/* trailing dot */
2160
				if (substr($keyname, -1) != ".")
2161
					$keyname .= ".";
2162

    
2163
				$hostname = $dnsupdate['host'];
2164
				/* trailing dot */
2165
				if (substr($hostname, -1) != ".")
2166
					$hostname .= ".";
2167

    
2168
				/* write private key file
2169
				   this is dumb - public and private keys are the same for HMAC-MD5,
2170
				   but nsupdate insists on having both */
2171
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2172
				$privkey = <<<EOD
2173
Private-key-format: v1.2
2174
Algorithm: 157 (HMAC)
2175
Key: {$dnsupdate['keydata']}
2176

    
2177
EOD;
2178
				fwrite($fd, $privkey);
2179
				fclose($fd);
2180

    
2181
				/* write public key file */
2182
				if ($dnsupdate['keytype'] == "zone") {
2183
					$flags = 257;
2184
					$proto = 3;
2185
				} else if ($dnsupdate['keytype'] == "host") {
2186
					$flags = 513;
2187
					$proto = 3;
2188
				} else if ($dnsupdate['keytype'] == "user") {
2189
					$flags = 0;
2190
					$proto = 2;
2191
				}
2192

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

    
2197
				/* generate update instructions */
2198
				$upinst = "";
2199
				if (!empty($dnsupdate['server']))
2200
					$upinst .= "server {$dnsupdate['server']}\n";
2201

    
2202
				if (file_exists($cacheFile)) {
2203
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2204
				}
2205
				if (file_exists("{$cacheFile}.ipv6")) {
2206
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2207
				}
2208

    
2209
				// 25 Days
2210
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2211
				$need_update = false;
2212

    
2213
				conf_mount_rw();
2214
				/* Update IPv4 if we have it. */
2215
				if (is_ipaddrv4($wanip)) {
2216
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2217
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2218
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2219
						$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";
2220
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2221
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2222
						$need_update = true;
2223
					} else {
2224
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2225
					}
2226
				} else
2227
					@unlink($cacheFile);
2228

    
2229
				/* Update IPv6 if we have it. */
2230
				if (is_ipaddrv6($wanipv6)) {
2231
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2232
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2233
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2234
						$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";
2235
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2236
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2237
						$need_update = true;
2238
					} else {
2239
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2240
					}
2241
				} else
2242
					@unlink("{$cacheFile}.ipv6");
2243
				conf_mount_ro();
2244

    
2245
				$upinst .= "\n";	/* mind that trailing newline! */
2246

    
2247
				if ($need_update) {
2248
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2249
					unset($upinst);
2250
					/* invoke nsupdate */
2251
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2252
					if (isset($dnsupdate['usetcp']))
2253
						$cmd .= " -v";
2254
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2255
					mwexec_bg($cmd);
2256
					unset($cmd);
2257
				}
2258
			}
2259
		}
2260
		if (!empty($notify_text)) {
2261
			notify_all_remote($notify_text);
2262
		}
2263
	}
2264

    
2265
	return 0;
2266
}
2267

    
2268
/* configure cron service */
2269
function configure_cron() {
2270
	global $g, $config;
2271

    
2272
	conf_mount_rw();
2273
	/* preserve existing crontab entries */
2274
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2275

    
2276
	for ($i = 0; $i < count($crontab_contents); $i++) {
2277
		$cron_item =& $crontab_contents[$i];
2278
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2279
			array_splice($crontab_contents, $i - 1);
2280
			break;
2281
		}
2282
	}
2283
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2284

    
2285

    
2286
	if (is_array($config['cron']['item'])) {
2287
		$crontab_contents .= "#\n";
2288
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2289
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2290
		$crontab_contents .= "#\n";
2291

    
2292
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2293
			$http_proxy = $config['system']['proxyurl'];
2294
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2295
				$http_proxy .= ':' . $config['system']['proxyport'];
2296
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2297
		}
2298

    
2299
		foreach ($config['cron']['item'] as $item) {
2300
			$crontab_contents .= "\n{$item['minute']}\t";
2301
			$crontab_contents .= "{$item['hour']}\t";
2302
			$crontab_contents .= "{$item['mday']}\t";
2303
			$crontab_contents .= "{$item['month']}\t";
2304
			$crontab_contents .= "{$item['wday']}\t";
2305
			$crontab_contents .= "{$item['who']}\t";
2306
			$crontab_contents .= "{$item['command']}";
2307
		}
2308

    
2309
		$crontab_contents .= "\n#\n";
2310
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2311
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2312
		$crontab_contents .= "#\n\n";
2313
	}
2314

    
2315
	/* please maintain the newline at the end of file */
2316
	file_put_contents("/etc/crontab", $crontab_contents);
2317
	unset($crontab_contents);
2318

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

    
2322
	conf_mount_ro();
2323
}
2324

    
2325
function upnp_action ($action) {
2326
	global $g, $config;
2327
	switch($action) {
2328
		case "start":
2329
			if (file_exists('/var/etc/miniupnpd.conf')) {
2330
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2331
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2332
			}
2333
			break;
2334
		case "stop":
2335
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2336
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2337
				mwexec('killall miniupnpd 2>/dev/null', true);
2338
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2339
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2340
			break;
2341
		case "restart":
2342
			upnp_action('stop');
2343
			upnp_action('start');
2344
			break;
2345
	}
2346
}
2347

    
2348
function upnp_start() {
2349
	global $config;
2350

    
2351
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2352
		return;
2353

    
2354
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2355
		echo gettext("Starting UPnP service... ");
2356
		require_once('/usr/local/pkg/miniupnpd.inc');
2357
		sync_package_miniupnpd();
2358
		echo "done.\n";
2359
	}
2360
}
2361

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

    
2365
	$is_installed = false;
2366
	$cron_changed = true;
2367

    
2368
	if (!is_array($config['cron']))
2369
		$config['cron'] = array();
2370
	if (!is_array($config['cron']['item']))
2371
		$config['cron']['item'] = array();
2372

    
2373
	$x=0;
2374
	foreach($config['cron']['item'] as $item) {
2375
		if(strstr($item['command'], $command)) {
2376
			$is_installed = true;
2377
			break;
2378
		}
2379
		$x++;
2380
	}
2381

    
2382
	if($active) {
2383
		$cron_item = array();
2384
		$cron_item['minute'] = $minute;
2385
		$cron_item['hour'] = $hour;
2386
		$cron_item['mday'] = $monthday;
2387
		$cron_item['month'] = $month;
2388
		$cron_item['wday'] = $weekday;
2389
		$cron_item['who'] = $who;
2390
		$cron_item['command'] = $command;
2391
		if(!$is_installed) {
2392
			$config['cron']['item'][] = $cron_item;
2393
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2394
		} else {
2395
			if (($config['cron']['item'][$x]['minute'] == $cron_item['minute']) && 
2396
			    ($config['cron']['item'][$x]['hour'] == $cron_item['hour']) && 
2397
			    ($config['cron']['item'][$x]['mday'] == $cron_item['mday']) && 
2398
			    ($config['cron']['item'][$x]['month'] == $cron_item['month']) && 
2399
			    ($config['cron']['item'][$x]['wday'] == $cron_item['wday']) && 
2400
			    ($config['cron']['item'][$x]['who'] == $cron_item['who']) && 
2401
			    ($config['cron']['item'][$x]['command'] == $cron_item['command'])) {
2402
				$cron_changed = false;
2403
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2404
			} else {
2405
				$config['cron']['item'][$x] = $cron_item;
2406
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2407
			}
2408
		}
2409
	} else {
2410
		if($is_installed == true) {
2411
			unset($config['cron']['item'][$x]);
2412
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2413
		}
2414
	}
2415

    
2416
	if ($cron_changed)
2417
		configure_cron();
2418
}
2419

    
2420
?>
(50-50/68)