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 deamon */
45
function services_radvd_configure($blacklist = array()) {
46
	global $config, $g;
47
	
48
	if ($g['platform'] == 'jail') 
49
		return;
50

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

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

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

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

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

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

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

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

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

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

    
98
		if (strstr($dhcpv6if, "_vip")) {
99
			// CARP IP, find parent
100
			if (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
	$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
			$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
			$routers = $ifcfgip;
745
		}
746
		if($add_routers)
747
			$dhcpdconf .= "	option routers {$routers};\n";
748

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

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

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

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

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

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

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

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

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

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

    
814
EOD;
815

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

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

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

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

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

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

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

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

    
846
				$smdnscfg = "";
847

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
938
	return 0;
939
}
940

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

    
952
	return $dhcpdconf;
953
}
954

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

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

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

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

    
1001
	return $dhcpdconf;
1002
}
1003

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

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

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

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

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

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

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

    
1047

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

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

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

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

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

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

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

    
1111
	$dhcpdv6conf = <<<EOD
1112

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

    
1125
EOD;
1126

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

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

    
1133
	$dhcpdv6ifs = array();
1134

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

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

    
1140
		$ddns_zones = array();
1141

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

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

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

    
1155
		$dnscfgv6 = "";
1156

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

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

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

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

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

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

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

    
1207
EOD;
1208

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1349
	return 0;
1350
}
1351

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

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

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

    
1361
        $iflist = get_configured_interface_list();
1362

    
1363
        $igmpconf = <<<EOD
1364

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

    
1370
EOD;
1371

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

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

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

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

    
1407
        return 0;
1408
}
1409

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

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

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

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

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

    
1433
	$iflist = get_configured_interface_list();
1434

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

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

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

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

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

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

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

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

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

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

    
1529
	return 0;
1530
}
1531

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

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

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

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

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

    
1555
	$iflist = get_configured_interface_list();
1556

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

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

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

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

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

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

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

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

    
1648
	return 0;
1649
}
1650

    
1651
function services_dyndns_configure_client($conf) {
1652

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

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

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

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

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

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

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

    
1708
	return 0;
1709
}
1710

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

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

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

    
1748

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

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

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

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

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

    
1769
		$args = "";
1770

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

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

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

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

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

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

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

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

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

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

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

    
1886
        system_dhcpleases_configure();
1887

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

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

    
1897
	return $return;
1898
}
1899

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

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

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

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

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

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

    
1928
        system_dhcpleases_configure();
1929
	}
1930

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

    
1936
	return $return;
1937
}
1938

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

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

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

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

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

    
1964

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

    
1970
EOD;
1971

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

    
1978
EOD;
1979
		}
1980
*/
1981

    
1982

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

    
1990

    
1991
EOD;
1992
		}
1993

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

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

    
2010
EOD;
2011

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

    
2017
EOD;
2018
		}
2019
*/
2020

    
2021

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

    
2028
EOD;
2029
		}
2030

    
2031

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

    
2035
EOD;
2036

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

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

    
2056
EOD;
2057

    
2058
		}
2059

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

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

    
2069
snmpEnableAuthenTraps = 2
2070

    
2071
EOD;
2072

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

    
2078
EOD;
2079
		    }
2080

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

    
2087
EOD;
2088
		    }
2089

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

    
2094
EOD;
2095
		    }
2096

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

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

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

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

    
2120
EOD;
2121
			}
2122
		}
2123

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

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

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

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

    
2140
	return 0;
2141
}
2142

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2281
	return 0;
2282
}
2283

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

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

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

    
2301

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

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

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

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

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

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

    
2338
	conf_mount_ro();
2339
}
2340

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

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

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

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

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

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

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

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

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

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

    
2430
?>
(50-50/68)