Project

General

Profile

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

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

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

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

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

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

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

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

    
44
/* implement ipv6 route advertising daemon */
45
function services_radvd_configure($blacklist = array()) {
46
	global $config, $g;
47
	
48
	if ($g['platform'] == 'jail') 
49
		return;
50

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
178
		if($carpif === true) {
179
			$radvdconf .= "\troute ::/0 {\n";
180
			$radvdconf .= "\t\tRemoveRoute off;\n";
181
			$radvdconf .= "\t};\n";
182
		} else {
183
			$radvdconf .= "\troute ::/0 {\n";
184
			$radvdconf .= "\t\tRemoveRoute on;\n";
185
			$radvdconf .= "\t};\n";
186
		}
187

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

    
219
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
220
	foreach ($Iflist as $if => $ifdescr) {
221
		if(!isset($config['interfaces'][$if]['track6-interface']))
222
			continue;
223
		if(!isset($config['interfaces'][$if]['enable']))
224
			continue;
225
		/* Do not put in the config an interface which is down */
226
		if (isset($blacklist[$if]))
227
			continue;
228
		$trackif = $config['interfaces'][$if]['track6-interface'];
229
		if (empty($config['interfaces'][$trackif]))
230
			continue;
231

    
232
		if (strstr($if, "_vip")) {
233
			// CARP IP, find parent
234
			$ifparent = link_carp_interface_to_parent($if);
235
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
236
		} else {
237
			$realif = get_real_interface($if, "inet6");
238
		}
239
		
240
		/* prevent duplicate entries, manual overrides */
241
		if (isset($radvdifs[$realif]))
242
			continue;
243

    
244
		$ifcfgipv6 = get_interface_ipv6($if);
245
		if(!is_ipaddrv6($ifcfgipv6)) {
246
			$subnetv6 = "::";
247
			$ifcfgsnv6 = "64";
248
		} else {
249
			$ifcfgsnv6 = get_interface_subnetv6($if);
250
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
251
		}
252
		$radvdifs[$realif] = $realif;
253

    
254
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
255
	
256
		if ($g['debug'])
257
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
258

    
259
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
260
		$radvdconf .= "interface {$realif} {\n";
261
		$radvdconf .= "\tAdvSendAdvert on;\n";
262
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
263
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
264
		$mtu = get_interface_mtu($realif);
265
		if (is_numeric($mtu))
266
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
267
		else
268
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
269
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
270
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
271
		$radvdconf .= "\t\tAdvOnLink on;\n";
272
		$radvdconf .= "\t\tAdvAutonomous on;\n";
273
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
274
		$radvdconf .= "\t};\n";
275

    
276
		/* add DNS servers */
277
		$dnslist = array();
278
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
279
			$dnslist[] = $ifcfgipv6;
280
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
281
			foreach($config['system']['dnsserver'] as $server) {
282
				if(is_ipaddrv6($server))
283
					$dnslist[] = $server;
284
			}
285
		}
286
		if (count($dnslist) > 0) {
287
			$dnsstring = implode(" ", $dnslist);
288
			if (!empty($dnsstring))
289
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
290
		}
291
		if (!empty($config['system']['domain'])) {
292
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
293
		}
294
		$radvdconf .= "};\n";
295
	}
296

    
297
	/* write radvd.conf */
298
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
299
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
300
		if (platform_booting())
301
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
302
	}
303
	unset($radvdconf);
304

    
305
	if (count($radvdifs) > 0) {
306
		if (isvalidpid("{$g['varrun_path']}/radvd.pid"))
307
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
308
		else
309
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
310
	} else {
311
		/* we need to shut down the radvd cleanly, it will send out the prefix
312
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
313
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
314
			log_error("Shutting down Router Advertisment daemon cleanly");
315
			killbypid("{$g['varrun_path']}/radvd.pid");
316
			@unlink("{$g['varrun_path']}/radvd.pid");
317
		}
318
	}
319
	return 0;
320
}
321

    
322
function services_dhcpd_configure($family = "all", $blacklist = array()) {
323
	global $config, $g;
324

    
325
	/* configure DHCPD chroot once */
326
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
327
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
328
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
329
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
330
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
331
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
332
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
333
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
334
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
335
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
336
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
337
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
338
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
339
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
340

    
341
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
342
	if (!trim($status))
343
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
344
	fclose($fd);
345
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
346

    
347
	if ($family == "all" || $family == "inet")
348
		services_dhcpdv4_configure();
349
	if ($family == "all" || $family == "inet6") {
350
		services_dhcpdv6_configure($blacklist);
351
		services_radvd_configure($blacklist);
352
	}
353
}
354

    
355
function services_dhcpdv4_configure() {
356
	global $config, $g;
357
	$need_ddns_updates = false;
358
	$ddns_zones = array();
359

    
360
	if($g['services_dhcp_server_enable'] == false)
361
		return;
362

    
363
	if(isset($config['system']['developerspew'])) {
364
		$mt = microtime();
365
		echo "services_dhcpdv4_configure($if) being called $mt\n";
366
	}
367

    
368
	/* kill any running dhcpd */
369
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
370
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
371

    
372
	/* DHCP enabled on any interfaces? */
373
	if (!is_dhcp_server_enabled())
374
		return 0;
375

    
376
	/* if OLSRD is enabled, allow WAN to house DHCP. */
377
	if (!function_exists('is_package_installed'))
378
		require_once('pkg-utils.inc');
379
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd']))
380
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
381
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
382
				$is_olsr_enabled = true;
383
				break;
384
			}
385

    
386
	if (platform_booting()) {
387
		/* restore the leases, if we have them */
388
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
389
			$dhcprestore = "";
390
			$dhcpreturn = "";
391
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
392
			$dhcprestore = implode(" ", $dhcprestore);
393
			if($dhcpreturn <> 0) {
394
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
395
			}
396
		}
397
		/* 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. */
398
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
399
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
400
		}
401
	}
402

    
403
	$syscfg = $config['system'];
404
	if (!is_array($config['dhcpd']))
405
		$config['dhcpd'] = array();
406
	$dhcpdcfg = $config['dhcpd'];
407
	$Iflist = get_configured_interface_list();
408

    
409
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
410
	$dns_arrv4 = array();
411
	if (is_array($syscfg['dnsserver'])) {
412
		foreach($syscfg['dnsserver'] as $dnsserver) {
413
			if (is_ipaddrv4($dnsserver)) {
414
				$dns_arrv4[] = $dnsserver;
415
			}
416
		}
417
	}
418

    
419
	if (platform_booting())
420
		echo gettext("Starting DHCP service...");
421
	else
422
		sleep(1);
423

    
424
	$custoptions = "";
425
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
426
		if(is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
427
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
428
				if(!empty($item['type']))
429
					$itemtype = $item['type'];
430
				else
431
					$itemtype = "text";
432
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
433
			}
434
		}
435
	}
436

    
437
	$dhcpdconf = <<<EOD
438

    
439
option domain-name "{$syscfg['domain']}";
440
option ldap-server code 95 = text;
441
option domain-search-list code 119 = text;
442
option arch code 93 = unsigned integer 16; # RFC4578
443
{$custoptions}
444
default-lease-time 7200;
445
max-lease-time 86400;
446
log-facility local7;
447
one-lease-per-client true;
448
deny duplicates;
449
ping-check true;
450
update-conflict-detection false;
451

    
452
EOD;
453

    
454
	if(!isset($dhcpifconf['disableauthoritative']))
455
		$dhcpdconf .= "authoritative;\n";
456

    
457
	if(isset($dhcpifconf['alwaysbroadcast']))
458
		$dhcpdconf .= "always-broadcast on\n";
459

    
460
	$dhcpdifs = array();
461
	$enable_add_routers = false;
462
	$gateways_arr = return_gateways_array();
463
	/* only add a routers line if the system has any IPv4 gateway at all */
464
	/* a static route has a gateway, manually overriding this field always works */
465
	foreach($gateways_arr as $gwitem) {
466
		if($gwitem['ipprotocol'] == "inet") {
467
			$enable_add_routers = true;
468
			break;
469
		}
470
	}
471

    
472
	/*    loop through and determine if we need to setup
473
	 *    failover peer "bleh" entries
474
	 */
475
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
476

    
477
		if (!isset($config['interfaces'][$dhcpif]['enable']))
478
			continue;
479

    
480
		interfaces_staticarp_configure($dhcpif);
481

    
482
		if (!isset($dhcpifconf['enable']))
483
			continue;
484

    
485
		if($dhcpifconf['failover_peerip'] <> "") {
486
			$intip = get_interface_ip($dhcpif);
487
			/*
488
			 *    yep, failover peer is defined.
489
			 *    does it match up to a defined vip?
490
			 */
491
			$skew = 110;
492
			if(is_array($config['virtualip']['vip'])) {
493
				foreach ($config['virtualip']['vip'] as $vipent) {
494
					if($vipent['interface'] == $dhcpif) {
495
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
496
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
497
							/* this is the interface! */
498
							if(is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
499
								$skew = 0;
500
								break;
501
							}
502
						}
503
					}
504
				}
505
			} else {
506
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
507
			}
508
			if($skew > 10) {
509
				$type = "secondary";
510
				$my_port = "520";
511
				$peer_port = "519";
512
			} else {
513
				$my_port = "519";
514
				$peer_port = "520";
515
				$type = "primary";
516
				$dhcpdconf_pri  = "split 128;\n";
517
				$dhcpdconf_pri .= "  mclt 600;\n";
518
			}
519

    
520
			if (is_ipaddrv4($intip)) {
521
			$dhcpdconf .= <<<EOPP
522
failover peer "dhcp_{$dhcpif}" {
523
  {$type};
524
  address {$intip};
525
  port {$my_port};
526
  peer address {$dhcpifconf['failover_peerip']};
527
  peer port {$peer_port};
528
  max-response-delay 10;
529
  max-unacked-updates 10;
530
  {$dhcpdconf_pri}
531
  load balance max seconds 3;
532
}
533
\n
534
EOPP;
535
			}
536
		}
537
	}
538

    
539
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
540

    
541
		$newzone = array();
542
		$ifcfg = $config['interfaces'][$dhcpif];
543

    
544
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
545
			continue;
546
		$ifcfgip = get_interface_ip($dhcpif);
547
		$ifcfgsn = get_interface_subnet($dhcpif);
548
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
549
		$subnetmask = gen_subnet_mask($ifcfgsn);
550

    
551
		if (!is_ipaddr($subnet))
552
			continue;
553

    
554
		if($is_olsr_enabled == true)
555
			if($dhcpifconf['netmask'])
556
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
557

    
558
		$all_pools = array();
559
		$all_pools[] = $dhcpifconf;
560
		if (is_array($dhcpifconf['pool'])) {
561
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
562
		}
563

    
564
		$dnscfg = "";
565

    
566
		if ($dhcpifconf['domain']) {
567
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
568
		}
569

    
570
		if($dhcpifconf['domainsearchlist'] <> "") {
571
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
572
		}
573

    
574
		if (isset($dhcpifconf['ddnsupdate'])) {
575
			$need_ddns_updates = true;
576
			$newzone = array();
577
			if($dhcpifconf['ddnsdomain'] <> "") {
578
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
579
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
580
			} else {
581
				$newzone['domain-name'] = $config['system']['domain'];
582
			}
583
			$revsubnet = explode(".", $subnet);
584
			$revsubnet = array_reverse($revsubnet);
585
			foreach ($revsubnet as $octet) {
586
				if ($octet != "0")
587
					break;
588
				array_shift($revsubnet);
589
			}
590
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
591
		}
592

    
593
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
594
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
595
			if ($newzone['domain-name'])
596
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
597
		} else if (isset($config['dnsmasq']['enable'])) {
598
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
599
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
600
				$newzone['dns-servers'] = $syscfg['dnsserver'];
601
		} else if (isset($config['unbound']['enable'])) {
602
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
603
		} else if (!empty($dns_arrv4)) {
604
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
605
			if ($newzone['domain-name'])
606
				$newzone['dns-servers'] = $dns_arrv4;
607
		}
608

    
609
		/* Create classes - These all contain comma separated lists. Join them into one 
610
		   big comma separated string then split them all up. */
611
		$all_mac_strings = array();
612
		if (is_array($dhcpifconf['pool'])) {
613
			foreach($all_pools as $poolconf) {
614
				$all_mac_strings[] = $poolconf['mac_allow'];
615
				$all_mac_strings[] = $poolconf['mac_deny'];
616
			}
617
		}
618
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
619
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
620
		$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
621
		foreach ($all_mac_list as $mac) {
622
			if (empty($mac))
623
				continue;
624
			$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
625
			// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
626
			$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
627
			$dhcpdconf .= '}' . "\n";
628
		}
629

    
630
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
631

    
632
// Setup pool options
633
		foreach($all_pools as $poolconf) {
634
			$dhcpdconf .= "	pool {\n";
635
			/* is failover dns setup? */
636
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
637
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
638
				if($poolconf['dnsserver'][1] <> "")
639
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
640
				if($poolconf['dnsserver'][2] <> "")
641
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
642
				if($poolconf['dnsserver'][3] <> "")
643
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
644
				$dhcpdconf .= ";\n";
645
			}
646

    
647
			/* allow/deny MACs */
648
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
649
			foreach ($mac_allow_list as $mac) {
650
				if (empty($mac))
651
					continue;
652
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
653
			}
654
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
655
			foreach ($mac_deny_list as $mac) {
656
				if (empty($mac))
657
					continue;
658
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
659
			}
660

    
661
			if($poolconf['failover_peerip'] <> "")
662
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
663

    
664
			if (isset($poolconf['denyunknown']))
665
			   $dhcpdconf .= "		deny unknown-clients;\n";
666

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

    
670
			if($dhcpifconf['failover_peerip'] <> "") {
671
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
672
			}
673

    
674
			$pdnscfg = "";
675

    
676
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
677
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
678
			}
679

    
680
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
681
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
682
			}
683

    
684
			if (isset($poolconf['ddnsupdate'])) {
685
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
686
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
687
				$pdnscfg .= "		ddns-update-style interim;\n";
688
			}
689

    
690
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
691
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
692
			}
693
			$dhcpdconf .= "{$pdnscfg}";
694

    
695
			// default-lease-time
696
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
697
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
698

    
699
			// max-lease-time
700
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
701
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
702

    
703
			// netbios-name*
704
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
705
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
706
				$dhcpdconf .= "		option netbios-node-type 8;\n";
707
			}
708

    
709
			// ntp-servers
710
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
711
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
712

    
713
			// tftp-server-name
714
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
715
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
716

    
717
			// ldap-server
718
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
719
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
720

    
721
			// net boot information
722
			if(isset($poolconf['netboot'])) {
723
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
724
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
725
				}
726
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
727
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
728
				}
729
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
730
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
731
				}
732
			}
733
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
734
			$dhcpdconf .= "	}\n\n";
735
		}
736
// End of settings inside pools
737

    
738
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
739
			$routers = $dhcpifconf['gateway'];
740
			$add_routers = true;
741
		} elseif ($dhcpifconf['gateway'] == "none") {
742
			$add_routers = false;
743
		} else {
744
			$add_routers = $enable_add_routers;
745
			$routers = $ifcfgip;
746
		}
747
		if($add_routers)
748
			$dhcpdconf .= "	option routers {$routers};\n";
749

    
750
		$dhcpdconf .= <<<EOD
751
$dnscfg
752

    
753
EOD;
754
    		// default-lease-time
755
		if ($dhcpifconf['defaultleasetime'])
756
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
757

    
758
		// max-lease-time
759
		if ($dhcpifconf['maxleasetime'])
760
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
761

    
762
		// netbios-name*
763
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
764
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
765
			$dhcpdconf .= "	option netbios-node-type 8;\n";
766
		}
767

    
768
		// ntp-servers
769
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
770
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
771

    
772
		// tftp-server-name
773
		if ($dhcpifconf['tftp'] <> "")
774
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
775

    
776
		// Handle option, number rowhelper values
777
		$dhcpdconf .= "\n";
778
		if($dhcpifconf['numberoptions']['item']) {
779
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
780
				if(empty($item['type']) || $item['type'] == "text")
781
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
782
				else
783
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
784
			}
785
		}
786

    
787
		// ldap-server
788
		if ($dhcpifconf['ldap'] <> "")
789
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
790

    
791
		// net boot information
792
		if(isset($dhcpifconf['netboot'])) {
793
			if ($dhcpifconf['nextserver'] <> "") {
794
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
795
			}
796
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
797
				$dhcpdconf .= "	if option arch = 00:06 {\n";
798
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
799
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
800
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
801
				$dhcpdconf .= "	} else {\n";
802
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
803
				$dhcpdconf .= "	}\n\n";
804
			} elseif (!empty($dhcpifconf['filename'])) {
805
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
806
			}
807
			if (!empty($dhcpifconf['rootpath'])) {
808
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
809
			}
810
		}
811

    
812
		$dhcpdconf .= <<<EOD
813
}
814

    
815
EOD;
816

    
817
		/* add static mappings */
818
		if (is_array($dhcpifconf['staticmap'])) {
819

    
820
			$i = 0;
821
			foreach ($dhcpifconf['staticmap'] as $sm) {
822
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
823

    
824
                if ($sm['mac'])
825
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
826

    
827
                if ($sm['cid'])
828
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
829

    
830
				if ($sm['ipaddr'])
831
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
832

    
833
				if ($sm['hostname']) {
834
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
835
					$dhhostname = str_replace(".", "_", $dhhostname);
836
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
837
				}
838
				if ($sm['filename'])
839
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
840

    
841
				if ($sm['rootpath'])
842
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
843

    
844
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
845
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
846

    
847
				$smdnscfg = "";
848

    
849
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
850
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
851
				}
852

    
853
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
854
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
855
				}
856

    
857
				if (isset($sm['ddnsupdate'])) {
858
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
859
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
860
					$pdnscfg .= "		ddns-update-style interim;\n";
861
				}
862

    
863
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
864
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
865
				}
866
				$dhcpdconf .= "{$smdnscfg}";
867

    
868
				// default-lease-time
869
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
870
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
871

    
872
				// max-lease-time
873
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
874
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
875

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

    
882
				// ntp-servers
883
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
884
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
885

    
886
				// tftp-server-name
887
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
888
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
889

    
890
				$dhcpdconf .= "}\n";
891
				$i++;
892
			}
893
		}
894

    
895
		$dhcpdifs[] = get_real_interface($dhcpif);
896
		if ($newzone['domain-name'])
897
		{
898
			if ($need_ddns_updates)
899
			{
900
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
901
			}
902
			$ddns_zones[] = $newzone;
903
		}
904
	}
905

    
906
	if ($need_ddns_updates) {
907
		$dhcpdconf .= "ddns-update-style interim;\n";
908
		$dhcpdconf .= "update-static-leases on;\n";
909

    
910
		$dhcpdconf .= dhcpdkey($dhcpifconf);
911
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
912
	}
913

    
914
	/* write dhcpd.conf */
915
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
916
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
917
		unset($dhcpdconf);
918
		return 1;
919
	}
920
	unset($dhcpdconf);
921

    
922
	/* create an empty leases database */
923
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
924
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
925

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

    
930
	/* fire up dhcpd in a chroot */
931
	if (count($dhcpdifs) > 0) {
932
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
933
			join(" ", $dhcpdifs));
934
	}
935

    
936
	if (platform_booting())
937
		print "done.\n";
938

    
939
	return 0;
940
}
941

    
942
function dhcpdkey($dhcpifconf)
943
{
944
	$dhcpdconf = "";
945
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
946
	{
947
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
948
		$dhcpdconf .= "	algorithm hmac-md5;\n";
949
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
950
		$dhcpdconf .= "}\n";
951
	}
952

    
953
	return $dhcpdconf;
954
}
955

    
956
function dhcpdzones($ddns_zones, $dhcpifconf)
957
{
958
	$dhcpdconf = "";
959

    
960
	if (is_array($ddns_zones)) {
961
		$added_zones = array();
962
		foreach ($ddns_zones as $zone) {
963
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
964
				continue;
965
			$primary = $zone['dns-servers'][0];
966
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
967

    
968
			// Make sure we aren't using any invalid or IPv6 DNS servers.
969
			if (!is_ipaddrv4($primary)) {
970
				if (is_ipaddrv4($secondary)) {
971
					$primary = $secondary;
972
					$secondary = "";
973
				} else {
974
					continue;
975
				}
976
			}
977

    
978
			// We don't need to add zones multiple times.
979
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
980
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
981
				$dhcpdconf .= "	primary {$primary};\n";
982
				if (is_ipaddrv4($secondary))
983
					$dhcpdconf .= "	secondary {$secondary};\n";
984
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
985
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
986
				$dhcpdconf .= "}\n";
987
				$added_zones[] = $zone['domain-name'];
988
			}
989
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
990
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
991
				$dhcpdconf .= "	primary {$primary};\n";
992
				if (is_ipaddrv4($secondary))
993
					$dhcpdconf .= "	secondary {$secondary};\n";
994
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
995
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
996
				$dhcpdconf .= "}\n";
997
				$added_zones[] = $zone['ptr-domain'];
998
			}
999
		}
1000
	}
1001

    
1002
	return $dhcpdconf;
1003
}
1004

    
1005
function services_dhcpdv6_configure($blacklist = array()) {
1006
	global $config, $g;
1007

    
1008
	if($g['services_dhcp_server_enable'] == false)
1009
		return;
1010

    
1011
	if(isset($config['system']['developerspew'])) {
1012
		$mt = microtime();
1013
		echo "services_dhcpd_configure($if) being called $mt\n";
1014
	}
1015

    
1016
	/* kill any running dhcpd */
1017
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
1018
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1019
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
1020
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1021

    
1022
	/* DHCP enabled on any interfaces? */
1023
	if (!is_dhcpv6_server_enabled())
1024
		return 0;
1025

    
1026
	if (platform_booting()) {
1027
		if ($g['platform'] != "pfSense") {
1028
			/* restore the leases, if we have them */
1029
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1030
				$dhcprestore = "";
1031
				$dhcpreturn = "";
1032
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1033
				$dhcprestore = implode(" ", $dhcprestore);
1034
				if($dhcpreturn <> 0) {
1035
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1036
				}
1037
			}
1038
		}
1039
	}
1040

    
1041
	$syscfg = $config['system'];
1042
	if (!is_array($config['dhcpdv6']))
1043
		$config['dhcpdv6'] = array();
1044
	$dhcpdv6cfg = $config['dhcpdv6'];
1045
	$Iflist = get_configured_interface_list();
1046
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1047

    
1048

    
1049
	if (platform_booting())
1050
		echo "Starting DHCPv6 service...";
1051
	else
1052
		sleep(1);
1053

    
1054
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1055
	foreach ($Iflist as $ifname) {
1056
		/* Do not put in the config an interface which is down */
1057
		if (isset($blacklist[$ifname]))
1058
			continue;
1059
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1060
			$realif = get_real_interface($ifname, "inet6");
1061
			$ifcfgipv6 = get_interface_ipv6($ifname);
1062
			if(!is_ipaddrv6($ifcfgipv6))
1063
				continue;
1064
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1065
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1066
			$trackcfg = $config['interfaces'][$trackifname];
1067
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1068
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1069
			$dhcpdv6cfg[$ifname] = array();
1070
			$dhcpdv6cfg[$ifname]['enable'] = true;
1071
			/* range */
1072
			$ifcfgipv6arr[7] = "1000";
1073
			$dhcpdv6cfg[$ifname]['range'] = array();
1074
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1075
			$ifcfgipv6arr[7] = "2000";
1076
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1077
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1078
			if($pdlen > 2) {
1079
				$pdlenmax = $pdlen;
1080
				$pdlenhalf = $pdlenmax -1;
1081
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1082
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1083
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1084

    
1085
				/* set the delegation start to half the current address block */
1086
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1087
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1088

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

    
1093
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1094
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1095
			}
1096
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1097
		}
1098
	}
1099

    
1100
	$custoptionsv6 = "";
1101
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1102
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1103
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1104
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1105
			}
1106
		}
1107
	}
1108

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

    
1112
	$dhcpdv6conf = <<<EOD
1113

    
1114
option domain-name "{$syscfg['domain']}";
1115
option ldap-server code 95 = text;
1116
option domain-search-list code 119 = text;
1117
{$custoptionsv6}
1118
default-lease-time 7200;
1119
max-lease-time 86400;
1120
log-facility local7;
1121
one-lease-per-client true;
1122
deny duplicates;
1123
ping-check true;
1124
update-conflict-detection false;
1125

    
1126
EOD;
1127

    
1128
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1129
		$dhcpdv6conf .= "authoritative;\n";
1130

    
1131
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1132
		$dhcpdv6conf .= "always-broadcast on\n";
1133

    
1134
	$dhcpdv6ifs = array();
1135

    
1136
	$dhcpv6num = 0;
1137
	$nsupdate = false;
1138

    
1139
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1140

    
1141
		$ddns_zones = array();
1142

    
1143
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1144

    
1145
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable']))
1146
			continue;
1147
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1148
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1149
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1150

    
1151
		if ($is_olsr_enabled == true) {
1152
			if($dhcpv6ifconf['netmask'])
1153
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1154
		}
1155

    
1156
		$dnscfgv6 = "";
1157

    
1158
		if ($dhcpv6ifconf['domain']) {
1159
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1160
		}
1161

    
1162
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1163
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1164
    	}
1165

    
1166
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1167
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1168
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1169
			}
1170
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1171
			$nsupdate = true;
1172
		}
1173

    
1174
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1175
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1176
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1177
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1178
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1179
			$dns_arrv6 = array();
1180
			foreach($syscfg['dnsserver'] as $dnsserver) {
1181
				if (is_ipaddrv6($dnsserver)) {
1182
					$dns_arrv6[] = $dnsserver;
1183
				}
1184
			}
1185
			if(!empty($dns_arrv6))
1186
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1187
		}
1188

    
1189
		if ($dhcpv6ifconf['domain']) {
1190
			$newzone = array();
1191
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1192
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1193
			$ddns_zones[] = $newzone;
1194
		}
1195

    
1196
		if (is_ipaddrv6($ifcfgipv6)) {
1197
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1198
		} else {
1199
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1200
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1201
		}
1202
		$dhcpdv6conf .= " {\n";
1203

    
1204
		$dhcpdv6conf .= <<<EOD
1205
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1206
$dnscfgv6
1207

    
1208
EOD;
1209

    
1210
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1211
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1212
		}
1213
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1214
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1215
		}
1216
    		// default-lease-time
1217
		if ($dhcpv6ifconf['defaultleasetime'])
1218
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1219

    
1220
		// max-lease-time
1221
		if ($dhcpv6ifconf['maxleasetime'])
1222
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1223

    
1224
		// ntp-servers
1225
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1226
			$ntpservers = array();
1227
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1228
				if(is_ipaddrv6($ntpserver))
1229
					$ntpservers[] = $ntpserver;
1230
			}
1231
			if(count($ntpservers) > 0 )
1232
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1233
		}
1234
		// tftp-server-name
1235
		/* Needs ISC DHCPD support
1236
		 if ($dhcpv6ifconf['tftp'] <> "")
1237
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1238
		*/
1239

    
1240
		// Handle option, number rowhelper values
1241
		$dhcpdv6conf .= "\n";
1242
		if ($dhcpv6ifconf['numberoptions']['item']) {
1243
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1244
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1245
			}
1246
		}
1247

    
1248
		// ldap-server
1249
		if ($dhcpv6ifconf['ldap'] <> "")
1250
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1251

    
1252
		// net boot information
1253
		if(isset($dhcpv6ifconf['netboot'])) {
1254
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1255
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1256
			}
1257
		}
1258

    
1259
		$dhcpdv6conf .= "}\n";
1260

    
1261
		/* add static mappings */
1262
		/* Needs to use DUID */
1263
		if (is_array($dhcpv6ifconf['staticmap'])) {
1264
			$i = 0;
1265
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1266
				$dhcpdv6conf .= <<<EOD
1267
host s_{$dhcpv6if}_{$i} {
1268
	host-identifier option dhcp6.client-id {$sm['duid']};
1269

    
1270
EOD;
1271
				if ($sm['ipaddrv6'])
1272
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1273

    
1274
				if ($sm['hostname']) {
1275
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1276
					$dhhostname = str_replace(".", "_", $dhhostname);
1277
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1278
				}
1279
				if ($sm['filename'])
1280
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1281

    
1282
				if ($sm['rootpath'])
1283
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1284

    
1285
				$dhcpdv6conf .= "}\n";
1286
				$i++;
1287
			}
1288
		}
1289

    
1290
		if ($dhcpv6ifconf['domain'])
1291
		{
1292
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1293
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1294
		}
1295

    
1296
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1297
			if(preg_match("/poes/si", $dhcpv6if)) {
1298
				/* magic here */
1299
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1300
			} else {
1301
				$realif = get_real_interface($dhcpv6if, "inet6");
1302
				if (stristr("$realif", "bridge")) {
1303
					$mac = get_interface_mac($realif);
1304
					$v6address = generate_ipv6_from_mac($mac);
1305
					/* Create link local address for bridges */
1306
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1307
				}
1308
				$realif = escapeshellcmd($realif);
1309
				$dhcpdv6ifs[] = $realif;
1310
			}
1311
		}
1312
	}
1313

    
1314
	if ($nsupdate)
1315
	{
1316
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1317
	}
1318
	else
1319
	{
1320
		$dhcpdv6conf .= "ddns-update-style none;\n";
1321
	}
1322

    
1323
	/* write dhcpdv6.conf */
1324
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1325
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1326
		if (platform_booting())
1327
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1328
		unset($dhcpdv6conf);
1329
		return 1;
1330
	}
1331
	unset($dhcpdv6conf);
1332

    
1333
	/* create an empty leases v6 database */
1334
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1335
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1336

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

    
1341
	/* fire up dhcpd in a chroot */
1342
	if (count($dhcpdv6ifs) > 0) {
1343
		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 " .
1344
			join(" ", $dhcpdv6ifs));
1345
		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");
1346
	}
1347
	if (platform_booting())
1348
		print gettext("done.") . "\n";
1349

    
1350
	return 0;
1351
}
1352

    
1353
function services_igmpproxy_configure() {
1354
        global $config, $g;
1355

    
1356
        /* kill any running igmpproxy */
1357
        killbyname("igmpproxy");
1358

    
1359
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1360
		return 1;
1361

    
1362
        $iflist = get_configured_interface_list();
1363

    
1364
        $igmpconf = <<<EOD
1365

    
1366
##------------------------------------------------------
1367
## Enable Quickleave mode (Sends Leave instantly)
1368
##------------------------------------------------------
1369
quickleave
1370

    
1371
EOD;
1372

    
1373
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1374
                unset($iflist[$igmpcf['ifname']]);
1375
                $realif = get_real_interface($igmpcf['ifname']);
1376
                if (empty($igmpcf['threshold']))
1377
                        $threshld = 1;
1378
                else
1379
                        $threshld = $igmpcf['threshold'];
1380
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1381

    
1382
                if ($igmpcf['address'] <> "") {
1383
                        $item = explode(" ", $igmpcf['address']);
1384
                        foreach($item as $iww)
1385
                                $igmpconf .= "altnet {$iww}\n";
1386
                }
1387
                $igmpconf .= "\n";
1388
        }
1389
        foreach ($iflist as $ifn) {
1390
                $realif = get_real_interface($ifn);
1391
                $igmpconf .= "phyint {$realif} disabled\n";
1392
        }
1393
	$igmpconf .= "\n";
1394

    
1395
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1396
        if (!$igmpfl) {
1397
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1398
                return;
1399
        }
1400
        fwrite($igmpfl, $igmpconf);
1401
        fclose($igmpfl);
1402
	unset($igmpconf);
1403

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

    
1408
        return 0;
1409
}
1410

    
1411
function services_dhcrelay_configure() {
1412
	global $config, $g;
1413
	if ($g['platform'] == 'jail')
1414
		return;
1415
	if(isset($config['system']['developerspew'])) {
1416
		$mt = microtime();
1417
		echo "services_dhcrelay_configure() being called $mt\n";
1418
	}
1419

    
1420
	/* kill any running dhcrelay */
1421
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1422

    
1423
	$dhcrelaycfg =& $config['dhcrelay'];
1424

    
1425
	/* DHCPRelay enabled on any interfaces? */
1426
	if (!isset($dhcrelaycfg['enable']))
1427
		return 0;
1428

    
1429
	if (platform_booting())
1430
		echo gettext("Starting DHCP relay service...");
1431
	else
1432
		sleep(1);
1433

    
1434
	$iflist = get_configured_interface_list();
1435

    
1436
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1437
	foreach ($dhcifaces as $dhcrelayif) {
1438
		if (!isset($iflist[$dhcrelayif]) ||
1439
			link_interface_to_bridge($dhcrelayif))
1440
			continue;
1441

    
1442
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1443
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1444
	}
1445

    
1446
	/*
1447
	 * In order for the relay to work, it needs to be active
1448
	 * on the interface in which the destination server sits.
1449
	 */
1450
	$srvips = explode(",", $dhcrelaycfg['server']);
1451
	foreach ($srvips as $srcidx => $srvip) {
1452
		unset($destif);
1453
		foreach ($iflist as $ifname) {
1454
			$subnet = get_interface_ip($ifname);
1455
			if (!is_ipaddr($subnet))
1456
				continue;
1457
			$subnet .=  "/" . get_interface_subnet($ifname);
1458
			if (ip_in_subnet($srvip, $subnet)) {
1459
				$destif = get_real_interface($ifname);
1460
				break;
1461
			}
1462
		}
1463
		if (!isset($destif)) {
1464
			foreach (get_staticroutes() as $rtent) {
1465
				if (ip_in_subnet($srvip, $rtent['network'])) {
1466
					$a_gateways = return_gateways_array(true);
1467
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1468
					break;
1469
				}
1470
			}
1471
		}
1472

    
1473
		if (!isset($destif)) {
1474
			/* Create a array from the existing route table */
1475
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1476
        		array_shift($route_str);
1477
        		array_shift($route_str);
1478
        		array_shift($route_str);
1479
        		array_shift($route_str);
1480
        		$route_arr = array();
1481
        		foreach($route_str as $routeline) {
1482
				$items = preg_split("/[ ]+/i", $routeline);
1483
				if (is_subnetv4($items[0])) {
1484
					$subnet = $items[0];
1485
				} elseif (is_ipaddrv4($items[0])) {
1486
					$subnet = "{$items[0]}/32";
1487
				} else {
1488
					// Not a subnet or IP address, skip to the next line.
1489
					continue;
1490
				}
1491
				if (ip_in_subnet($srvip, $subnet)) {
1492
					$destif = trim($items[6]);
1493
					break;
1494
				}
1495
			}
1496
		}
1497

    
1498
		if (!isset($destif)) {
1499
			if (is_array($config['gateways']['gateway_item'])) {
1500
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1501
					if (isset($gateway['defaultgw'])) {
1502
						$destif = get_real_interface($gateway['interface']);
1503
						break;
1504
					}
1505
				}
1506
			} else
1507
				$destif = get_real_interface("wan");
1508
		}
1509

    
1510
		if (!empty($destif))
1511
			$dhcrelayifs[] = $destif;
1512
	}
1513
	$dhcrelayifs = array_unique($dhcrelayifs);
1514

    
1515
	/* fire up dhcrelay */
1516
	if (empty($dhcrelayifs)) {
1517
		log_error("No suitable interface found for running dhcrelay!");
1518
		return; /* XXX */
1519
	}
1520

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

    
1523
	if (isset($dhcrelaycfg['agentoption']))
1524
		$cmd .=  " -a -m replace";
1525

    
1526
	$cmd .= " " . implode(" ", $srvips);
1527
	mwexec($cmd);
1528
	unset($cmd);
1529

    
1530
	return 0;
1531
}
1532

    
1533
function services_dhcrelay6_configure() {
1534
	global $config, $g;
1535
	if ($g['platform'] == 'jail')
1536
		return;
1537
	if(isset($config['system']['developerspew'])) {
1538
		$mt = microtime();
1539
		echo "services_dhcrelay6_configure() being called $mt\n";
1540
	}
1541

    
1542
	/* kill any running dhcrelay */
1543
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1544

    
1545
	$dhcrelaycfg =& $config['dhcrelay6'];
1546

    
1547
	/* DHCPv6 Relay enabled on any interfaces? */
1548
	if (!isset($dhcrelaycfg['enable']))
1549
		return 0;
1550

    
1551
	if (platform_booting())
1552
		echo gettext("Starting DHCPv6 relay service...");
1553
	else
1554
		sleep(1);
1555

    
1556
	$iflist = get_configured_interface_list();
1557

    
1558
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1559
	foreach ($dhcifaces as $dhcrelayif) {
1560
		if (!isset($iflist[$dhcrelayif]) ||
1561
			link_interface_to_bridge($dhcrelayif))
1562
			continue;
1563

    
1564
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1565
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1566
	}
1567
	$dhcrelayifs = array_unique($dhcrelayifs);
1568

    
1569
	/*
1570
	 * In order for the relay to work, it needs to be active
1571
	 * on the interface in which the destination server sits.
1572
	 */
1573
	$srvips = explode(",", $dhcrelaycfg['server']);
1574
        $srvifaces = array();
1575
	foreach ($srvips as $srcidx => $srvip) {
1576
		unset($destif);
1577
		foreach ($iflist as $ifname) {
1578
			$subnet = get_interface_ipv6($ifname);
1579
			if (!is_ipaddrv6($subnet))
1580
				continue;
1581
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1582
			if (ip_in_subnet($srvip, $subnet)) {
1583
				$destif = get_real_interface($ifname);
1584
				break;
1585
			}
1586
		}
1587
		if (!isset($destif)) {
1588
			if (is_array($config['staticroutes']['route'])) {
1589
				foreach ($config['staticroutes']['route'] as $rtent) {
1590
					if (ip_in_subnet($srvip, $rtent['network'])) {
1591
						$a_gateways = return_gateways_array(true);
1592
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1593
						break;
1594
					}
1595
				}
1596
			}
1597
		}
1598

    
1599
		if (!isset($destif)) {
1600
			/* Create a array from the existing route table */
1601
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1602
        		array_shift($route_str);
1603
        		array_shift($route_str);
1604
        		array_shift($route_str);
1605
        		array_shift($route_str);
1606
        		$route_arr = array();
1607
        		foreach($route_str as $routeline) {
1608
                		$items = preg_split("/[ ]+/i", $routeline);
1609
				if (ip_in_subnet($srvip, $items[0])) {
1610
					$destif = trim($items[6]);
1611
					break;
1612
				}
1613
        		}
1614
		}
1615

    
1616
		if (!isset($destif)) {
1617
			if (is_array($config['gateways']['gateway_item'])) {
1618
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1619
					if (isset($gateway['defaultgw'])) {
1620
						$destif = $gateway['interface'];
1621
						break;
1622
					}
1623
				}
1624
			} else
1625
				$destif = get_real_interface("wan");
1626
		}
1627

    
1628
		if (!empty($destif)) {
1629
			$srvifaces[] = "{$srvip}%{$destif}";
1630
		}
1631
	}
1632

    
1633
	/* fire up dhcrelay */
1634
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1635
		log_error("No suitable interface found for running dhcrelay -6!");
1636
		return; /* XXX */
1637
	}
1638

    
1639
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1640
	foreach ($dhcrelayifs as $dhcrelayif) {
1641
		$cmd .= " -l {$dhcrelayif}";
1642
	}
1643
	foreach ($srvifaces as $srviface) {
1644
		$cmd .= " -u \"{$srviface}\"";
1645
	}
1646
	mwexec($cmd);
1647
	unset($cmd);
1648

    
1649
	return 0;
1650
}
1651

    
1652
function services_dyndns_configure_client($conf) {
1653

    
1654
	if (!isset($conf['enable']))
1655
		return;
1656

    
1657
	/* load up the dyndns.class */
1658
	require_once("dyndns.class");
1659

    
1660
	$dns = new updatedns($dnsService = $conf['type'],
1661
		$dnsHost = $conf['host'],
1662
		$dnsUser = $conf['username'],
1663
		$dnsPass = $conf['password'],
1664
		$dnsWildcard = $conf['wildcard'],
1665
		$dnsMX = $conf['mx'],
1666
		$dnsIf = "{$conf['interface']}",
1667
		$dnsBackMX = NULL,
1668
		$dnsServer = NULL,
1669
		$dnsPort = NULL,
1670
		$dnsUpdateURL = "{$conf['updateurl']}",
1671
		$forceUpdate = $conf['force'],
1672
		$dnsZoneID=$conf['zoneid'],
1673
		$dnsTTL=$conf['ttl'],
1674
		$dnsResultMatch = "{$conf['resultmatch']}",
1675
		$dnsRequestIf = "{$conf['requestif']}",
1676
		$dnsID = "{$conf['id']}",
1677
		$dnsVerboseLog = $conf['verboselog'],
1678
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1679
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1680
}
1681

    
1682
function services_dyndns_configure($int = "") {
1683
	global $config, $g;
1684
	if(isset($config['system']['developerspew'])) {
1685
		$mt = microtime();
1686
		echo "services_dyndns_configure() being called $mt\n";
1687
	}
1688

    
1689
	$dyndnscfg = $config['dyndnses']['dyndns'];
1690
	$gwgroups = return_gateway_groups_array();
1691
	if (is_array($dyndnscfg)) {
1692
		if (platform_booting())
1693
			echo gettext("Starting DynDNS clients...");
1694

    
1695
		foreach ($dyndnscfg as $dyndns) {
1696
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1697
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1698
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1699
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1700
				services_dyndns_configure_client($dyndns);
1701
				sleep(1);
1702
			}
1703
		}
1704

    
1705
		if (platform_booting())
1706
			echo gettext("done.") . "\n";
1707
	}
1708

    
1709
	return 0;
1710
}
1711

    
1712
function dyndnsCheckIP($int) {
1713
	global $config;
1714
	$ip_address = get_interface_ip($int);
1715
	if (is_private_ip($ip_address)) {
1716
		$gateways_status = return_gateways_status(true);
1717
		// If the gateway for this interface is down, then the external check cannot work.
1718
		// Avoid the long wait for the external check to timeout.
1719
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1720
			return "down";
1721
		$hosttocheck = "http://checkip.dyndns.org";
1722
		$ip_ch = curl_init($hosttocheck);
1723
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1724
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1725
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1726
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1727
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1728
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1729
		$ip_result_page = curl_exec($ip_ch);
1730
		curl_close($ip_ch);
1731
		$ip_result_decoded = urldecode($ip_result_page);
1732
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1733
		$ip_address = trim($matches[1]);
1734
	}
1735
	return $ip_address;
1736
}
1737

    
1738
function services_dnsmasq_configure() {
1739
	global $config, $g;
1740
	$return = 0;
1741

    
1742
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1743
	$standard_args = array(
1744
		"dns-forward-max" => "--dns-forward-max=5000",
1745
		"cache-size" => "--cache-size=10000",
1746
		"local-ttl" => "--local-ttl=1"
1747
	);
1748

    
1749

    
1750
	if(isset($config['system']['developerspew'])) {
1751
		$mt = microtime();
1752
		echo "services_dnsmasq_configure() being called $mt\n";
1753
	}
1754

    
1755
	/* kill any running dnsmasq */
1756
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1757
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1758

    
1759
	if (isset($config['dnsmasq']['enable'])) {
1760

    
1761
		if (platform_booting())
1762
			echo gettext("Starting DNS forwarder...");
1763
		else
1764
			sleep(1);
1765

    
1766
                /* generate hosts file */
1767
                if(system_hosts_generate()!=0)
1768
                        $return = 1;
1769

    
1770
		$args = "";
1771

    
1772
		if (isset($config['dnsmasq']['regdhcp'])) {
1773
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1774
		}
1775

    
1776
		/* Setup listen port, if non-default */
1777
		if (is_port($config['dnsmasq']['port']))
1778
			$args .= " --port={$config['dnsmasq']['port']} ";
1779

    
1780
		$listen_addresses = "";
1781
		if(isset($config['dnsmasq']['interface'])) {
1782
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1783
			foreach ($interfaces as $interface) {
1784
				if (is_ipaddrv4($interface)) {
1785
					$listen_addresses .= " --listen-address={$interface} ";
1786
				} else if (is_ipaddrv6($interface)) {
1787
					/*
1788
					 * XXX: Since dnsmasq does not support link-local address
1789
					 * with scope specified. These checks are being done.
1790
					 */
1791
					if (is_linklocal($interface) && strstr($interface, "%")) {
1792
						$tmpaddrll6 = explode("%", $interface);
1793
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1794
					} else 
1795
						$listen_addresses .= " --listen-address={$interface} ";
1796
				} else if (strstr($interface, "_vip")) {
1797
					$laddr = get_configured_carp_interface_list($interface);
1798
					if (is_ipaddr($laddr)) 
1799
						$listen_addresses .= " --listen-address={$laddr} ";
1800
				} else {
1801
					$if = get_real_interface($interface);
1802
					if (does_interface_exist($if)) {
1803
						$laddr = find_interface_ip($if);
1804
						if (is_ipaddrv4($laddr))
1805
							$listen_addresses .= " --listen-address={$laddr} ";
1806
						$laddr6 = find_interface_ipv6($if);
1807
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1808
							/*
1809
							 * XXX: Since dnsmasq does not support link-local address
1810
							 * with scope specified. These checks are being done.
1811
							 */
1812
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1813
								$tmpaddrll6 = explode("%", $laddr6);
1814
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1815
							} else
1816
								$listen_addresses .= " --listen-address={$laddr6} ";
1817
						}
1818
					}
1819
				}
1820
			}
1821
			if (!empty($listen_addresses)) {
1822
				$args .= " {$listen_addresses} ";
1823
				if (isset($config['dnsmasq']['strictbind']))
1824
					$args .= " --bind-interfaces ";
1825
			}
1826
		}
1827

    
1828
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1829
		/* If any of these are duplicated by a user-specified domain override (e.g. 10.in-addr.arpa) then */
1830
		/* the user-specified entry made later on the command line below will be the one that is effective. */
1831
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1832
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1833
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1834
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1835
			$args .= " --server=/10.in-addr.arpa/ ";
1836
			$args .= " --server=/168.192.in-addr.arpa/ ";
1837
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1838
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1839
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1840
			}
1841
		}
1842

    
1843
		/* Setup forwarded domains */
1844
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1845
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1846
				if ($override['ip'] == "!")
1847
					$override[ip] = "";
1848
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1849
			}
1850
		}
1851

    
1852
		/* Allow DNS Rebind for forwarded domains */
1853
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1854
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1855
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1856
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1857
				}
1858
			}
1859
		}
1860

    
1861
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1862
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1863

    
1864
		if (isset($config['dnsmasq']['strict_order'])) {
1865
			$args .= " --strict-order ";
1866
		}
1867

    
1868
		if (isset($config['dnsmasq']['domain_needed'])) {
1869
			$args .= " --domain-needed ";
1870
		}
1871

    
1872
		if ($config['dnsmasq']['custom_options'])
1873
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1874
				$args .= " " . escapeshellarg("--{$c}");
1875
				$p = explode('=', $c);
1876
				if (array_key_exists($p[0], $standard_args))
1877
					unset($standard_args[$p[0]]);
1878
			}
1879
		$args .= ' ' . implode(' ', array_values($standard_args));
1880

    
1881
		/* run dnsmasq */
1882
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1883
		//log_error("dnsmasq command: {$cmd}");
1884
		mwexec_bg($cmd);
1885
		unset($args);
1886

    
1887
        system_dhcpleases_configure();
1888

    
1889
		if (platform_booting())
1890
			echo gettext("done.") . "\n";
1891
	}
1892

    
1893
	if (!platform_booting()) {
1894
		if(services_dhcpd_configure()!=0)
1895
			$return = 1;
1896
	}
1897

    
1898
	return $return;
1899
}
1900

    
1901
function services_unbound_configure() {
1902
	global $config, $g;
1903
	$return = 0;
1904

    
1905
	if (isset($config['system']['developerspew'])) {
1906
		$mt = microtime();
1907
		echo "services_unbound_configure() being called $mt\n";
1908
	}
1909

    
1910
	// kill any running Unbound instance
1911
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1912
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1913

    
1914
	if (isset($config['unbound']['enable'])) {
1915
		if (platform_booting())
1916
			echo gettext("Starting DNS Resolver...");
1917
		else
1918
			sleep(1);
1919

    
1920
		/* generate hosts file */
1921
		if(system_hosts_generate()!=0)
1922
			$return = 1;
1923

    
1924
		require_once('/etc/inc/unbound.inc');
1925
		sync_unbound_service();
1926
		if (platform_booting())
1927
			echo gettext("done.") . "\n";
1928

    
1929
        system_dhcpleases_configure();
1930
	}
1931

    
1932
	if (!platform_booting()) {
1933
		if (services_dhcpd_configure()!=0)
1934
			$return = 1;
1935
	}
1936

    
1937
	return $return;
1938
}
1939

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

    
1947
	/* kill any running snmpd */
1948
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1949
	sleep(2);
1950
	if(is_process_running("bsnmpd"))
1951
		mwexec("/usr/bin/killall bsnmpd", true);
1952

    
1953
	if (isset($config['snmpd']['enable'])) {
1954

    
1955
		if (platform_booting())
1956
			echo gettext("Starting SNMP daemon... ");
1957

    
1958
		/* generate snmpd.conf */
1959
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1960
		if (!$fd) {
1961
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1962
			return 1;
1963
		}
1964

    
1965

    
1966
		$snmpdconf = <<<EOD
1967
location := "{$config['snmpd']['syslocation']}"
1968
contact := "{$config['snmpd']['syscontact']}"
1969
read := "{$config['snmpd']['rocommunity']}"
1970

    
1971
EOD;
1972

    
1973
/* No docs on what write strings do there for disable for now.
1974
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1975
		    $snmpdconf .= <<<EOD
1976
# write string
1977
write := "{$config['snmpd']['rwcommunity']}"
1978

    
1979
EOD;
1980
		}
1981
*/
1982

    
1983

    
1984
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1985
		    $snmpdconf .= <<<EOD
1986
# SNMP Trap support.
1987
traphost := {$config['snmpd']['trapserver']}
1988
trapport := {$config['snmpd']['trapserverport']}
1989
trap := "{$config['snmpd']['trapstring']}"
1990

    
1991

    
1992
EOD;
1993
		}
1994

    
1995
		$version = trim(file_get_contents('/etc/version'));
1996
		$platform = trim(file_get_contents('/etc/platform'));
1997
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1998
			$platform = $g['product_name'];
1999
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2000
			" {$version} {$platform} " . php_uname("s") .
2001
			" " . php_uname("r") . " " . php_uname("m");
2002

    
2003
		$snmpdconf .= <<<EOD
2004
system := 1     # pfSense
2005
%snmpd
2006
sysDescr			= "{$sysDescr}"
2007
begemotSnmpdDebugDumpPdus       = 2
2008
begemotSnmpdDebugSyslogPri      = 7
2009
begemotSnmpdCommunityString.0.1 = $(read)
2010

    
2011
EOD;
2012

    
2013
/* No docs on what write strings do there for disable for now.
2014
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
2015
		    $snmpdconf .= <<<EOD
2016
begemotSnmpdCommunityString.0.2 = $(write)
2017

    
2018
EOD;
2019
		}
2020
*/
2021

    
2022

    
2023
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2024
		    $snmpdconf .= <<<EOD
2025
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2026
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2027
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2028

    
2029
EOD;
2030
		}
2031

    
2032

    
2033
		$snmpdconf .= <<<EOD
2034
begemotSnmpdCommunityDisable    = 1
2035

    
2036
EOD;
2037

    
2038
		if (isset($config['snmpd']['bindlan'])) {
2039
			$config['snmpd']['bindip'] = 'lan';
2040
			unset($config['snmpd']['bindlan']);
2041
		}
2042
		$bind_to_ip = "0.0.0.0";
2043
		if(isset($config['snmpd']['bindip'])) {
2044
			if (is_ipaddr($config['snmpd']['bindip'])) {
2045
				$bind_to_ip = $config['snmpd']['bindip'];
2046
			} else {
2047
				$if = get_real_interface($config['snmpd']['bindip']);
2048
				if (does_interface_exist($if))
2049
					$bind_to_ip = find_interface_ip($if);
2050
			}
2051
		}
2052

    
2053
		if(is_port( $config['snmpd']['pollport'] )) {
2054
		    $snmpdconf .= <<<EOD
2055
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2056

    
2057
EOD;
2058

    
2059
		}
2060

    
2061
		$snmpdconf .= <<<EOD
2062
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2063
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2064

    
2065
# These are bsnmp macros not php vars.
2066
sysContact      = $(contact)
2067
sysLocation     = $(location)
2068
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2069

    
2070
snmpEnableAuthenTraps = 2
2071

    
2072
EOD;
2073

    
2074
		if (is_array( $config['snmpd']['modules'] )) {
2075
		    if(isset($config['snmpd']['modules']['mibii'])) {
2076
			$snmpdconf .= <<<EOD
2077
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2078

    
2079
EOD;
2080
		    }
2081

    
2082
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2083
			$snmpdconf .= <<<EOD
2084
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2085
%netgraph
2086
begemotNgControlNodeName = "snmpd"
2087

    
2088
EOD;
2089
		    }
2090

    
2091
		    if(isset($config['snmpd']['modules']['pf'])) {
2092
			$snmpdconf .= <<<EOD
2093
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2094

    
2095
EOD;
2096
		    }
2097

    
2098
		    if(isset($config['snmpd']['modules']['hostres'])) {
2099
			$snmpdconf .= <<<EOD
2100
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2101

    
2102
EOD;
2103
		    }
2104
		    if(isset($config['snmpd']['modules']['bridge'])) {
2105
			$snmpdconf .= <<<EOD
2106
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2107
# config must end with blank line
2108

    
2109
EOD;
2110
		    }
2111
			if(isset($config['snmpd']['modules']['ucd'])) {
2112
				$snmpdconf .= <<<EOD
2113
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2114

    
2115
EOD;
2116
			}
2117
			if(isset($config['snmpd']['modules']['regex'])) {
2118
				$snmpdconf .= <<<EOD
2119
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2120

    
2121
EOD;
2122
			}
2123
		}
2124

    
2125
		fwrite($fd, $snmpdconf);
2126
		fclose($fd);
2127
		unset($snmpdconf);
2128

    
2129
		if (isset($config['snmpd']['bindlan'])) {
2130
			$bindlan = "";
2131
		}
2132

    
2133
		/* run bsnmpd */
2134
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2135
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2136

    
2137
		if (platform_booting())
2138
			echo gettext("done.") . "\n";
2139
	}
2140

    
2141
	return 0;
2142
}
2143

    
2144
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2145
	global $config, $g;
2146
	if(isset($config['system']['developerspew'])) {
2147
		$mt = microtime();
2148
		echo "services_dnsupdate_process() being called $mt\n";
2149
	}
2150

    
2151
	/* Dynamic DNS updating active? */
2152
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2153
		$notify_text = "";
2154
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2155
			if (!isset($dnsupdate['enable']))
2156
				continue;
2157
			if (!empty($int) && $int != $dnsupdate['interface'])
2158
				continue;
2159
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2160
				continue;
2161

    
2162
			/* determine interface name */
2163
			$if = get_real_interface($dnsupdate['interface']);
2164
			
2165
			if (isset($dnsupdate['usepublicip']))
2166
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2167
                        else
2168
                                $wanip = get_interface_ip($dnsupdate['interface']);
2169
			
2170
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2171
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2172
			$currentTime = time();
2173

    
2174
			if ($wanip || $wanipv6) {
2175
				$keyname = $dnsupdate['keyname'];
2176
				/* trailing dot */
2177
				if (substr($keyname, -1) != ".")
2178
					$keyname .= ".";
2179

    
2180
				$hostname = $dnsupdate['host'];
2181
				/* trailing dot */
2182
				if (substr($hostname, -1) != ".")
2183
					$hostname .= ".";
2184

    
2185
				/* write private key file
2186
				   this is dumb - public and private keys are the same for HMAC-MD5,
2187
				   but nsupdate insists on having both */
2188
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2189
				$privkey = <<<EOD
2190
Private-key-format: v1.2
2191
Algorithm: 157 (HMAC)
2192
Key: {$dnsupdate['keydata']}
2193

    
2194
EOD;
2195
				fwrite($fd, $privkey);
2196
				fclose($fd);
2197

    
2198
				/* write public key file */
2199
				if ($dnsupdate['keytype'] == "zone") {
2200
					$flags = 257;
2201
					$proto = 3;
2202
				} else if ($dnsupdate['keytype'] == "host") {
2203
					$flags = 513;
2204
					$proto = 3;
2205
				} else if ($dnsupdate['keytype'] == "user") {
2206
					$flags = 0;
2207
					$proto = 2;
2208
				}
2209

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

    
2214
				/* generate update instructions */
2215
				$upinst = "";
2216
				if (!empty($dnsupdate['server']))
2217
					$upinst .= "server {$dnsupdate['server']}\n";
2218

    
2219
				if (file_exists($cacheFile)) {
2220
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2221
				}
2222
				if (file_exists("{$cacheFile}.ipv6")) {
2223
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2224
				}
2225

    
2226
				// 25 Days
2227
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2228
				$need_update = false;
2229

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

    
2246
				/* Update IPv6 if we have it. */
2247
				if (is_ipaddrv6($wanipv6)) {
2248
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2249
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2250
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2251
						$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";
2252
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2253
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2254
						$need_update = true;
2255
					} else {
2256
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2257
					}
2258
				} else
2259
					@unlink("{$cacheFile}.ipv6");
2260
				conf_mount_ro();
2261

    
2262
				$upinst .= "\n";	/* mind that trailing newline! */
2263

    
2264
				if ($need_update) {
2265
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2266
					unset($upinst);
2267
					/* invoke nsupdate */
2268
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2269
					if (isset($dnsupdate['usetcp']))
2270
						$cmd .= " -v";
2271
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2272
					mwexec_bg($cmd);
2273
					unset($cmd);
2274
				}
2275
			}
2276
		}
2277
		if (!empty($notify_text)) {
2278
			notify_all_remote($notify_text);
2279
		}
2280
	}
2281

    
2282
	return 0;
2283
}
2284

    
2285
/* configure cron service */
2286
function configure_cron() {
2287
	global $g, $config;
2288

    
2289
	conf_mount_rw();
2290
	/* preserve existing crontab entries */
2291
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2292

    
2293
	for ($i = 0; $i < count($crontab_contents); $i++) {
2294
		$cron_item =& $crontab_contents[$i];
2295
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2296
			array_splice($crontab_contents, $i - 1);
2297
			break;
2298
		}
2299
	}
2300
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2301

    
2302

    
2303
	if (is_array($config['cron']['item'])) {
2304
		$crontab_contents .= "#\n";
2305
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2306
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2307
		$crontab_contents .= "#\n";
2308

    
2309
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2310
			$http_proxy = $config['system']['proxyurl'];
2311
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2312
				$http_proxy .= ':' . $config['system']['proxyport'];
2313
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2314
		}
2315

    
2316
		foreach ($config['cron']['item'] as $item) {
2317
			$crontab_contents .= "\n{$item['minute']}\t";
2318
			$crontab_contents .= "{$item['hour']}\t";
2319
			$crontab_contents .= "{$item['mday']}\t";
2320
			$crontab_contents .= "{$item['month']}\t";
2321
			$crontab_contents .= "{$item['wday']}\t";
2322
			$crontab_contents .= "{$item['who']}\t";
2323
			$crontab_contents .= "{$item['command']}";
2324
		}
2325

    
2326
		$crontab_contents .= "\n#\n";
2327
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2328
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2329
		$crontab_contents .= "#\n\n";
2330
	}
2331

    
2332
	/* please maintain the newline at the end of file */
2333
	file_put_contents("/etc/crontab", $crontab_contents);
2334
	unset($crontab_contents);
2335

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

    
2339
	conf_mount_ro();
2340
}
2341

    
2342
function upnp_action ($action) {
2343
	global $g, $config;
2344
	switch($action) {
2345
		case "start":
2346
			if (file_exists('/var/etc/miniupnpd.conf')) {
2347
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2348
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2349
			}
2350
			break;
2351
		case "stop":
2352
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2353
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2354
				mwexec('killall miniupnpd 2>/dev/null', true);
2355
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2356
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2357
			break;
2358
		case "restart":
2359
			upnp_action('stop');
2360
			upnp_action('start');
2361
			break;
2362
	}
2363
}
2364

    
2365
function upnp_start() {
2366
	global $config;
2367

    
2368
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2369
		return;
2370

    
2371
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2372
		echo gettext("Starting UPnP service... ");
2373
		require_once('/usr/local/pkg/miniupnpd.inc');
2374
		sync_package_miniupnpd();
2375
		echo "done.\n";
2376
	}
2377
}
2378

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

    
2382
	$is_installed = false;
2383
	$cron_changed = true;
2384

    
2385
	if (!is_array($config['cron']))
2386
		$config['cron'] = array();
2387
	if (!is_array($config['cron']['item']))
2388
		$config['cron']['item'] = array();
2389

    
2390
	$x=0;
2391
	foreach($config['cron']['item'] as $item) {
2392
		if(strstr($item['command'], $command)) {
2393
			$is_installed = true;
2394
			break;
2395
		}
2396
		$x++;
2397
	}
2398

    
2399
	if($active) {
2400
		$cron_item = array();
2401
		$cron_item['minute'] = $minute;
2402
		$cron_item['hour'] = $hour;
2403
		$cron_item['mday'] = $monthday;
2404
		$cron_item['month'] = $month;
2405
		$cron_item['wday'] = $weekday;
2406
		$cron_item['who'] = $who;
2407
		$cron_item['command'] = $command;
2408
		if(!$is_installed) {
2409
			$config['cron']['item'][] = $cron_item;
2410
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2411
		} else {
2412
			if ($config['cron']['item'][$x] == $cron_item) {
2413
				$cron_changed = false;
2414
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2415
			} else {
2416
				$config['cron']['item'][$x] = $cron_item;
2417
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2418
			}
2419
		}
2420
	} else {
2421
		if($is_installed == true) {
2422
			unset($config['cron']['item'][$x]);
2423
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2424
		}
2425
	}
2426

    
2427
	if ($cron_changed)
2428
		configure_cron();
2429
}
2430

    
2431
?>
(50-50/68)