Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
325
function services_dhcpd_configure($family = "all", $blacklist = array()) {
326
	global $config, $g;
327

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

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

    
350
	if ($family == "all" || $family == "inet")
351
		services_dhcpdv4_configure();
352
	if ($family == "all" || $family == "inet6") {
353
		services_dhcpdv6_configure($blacklist);
354
		services_radvd_configure($blacklist);
355
	}
356
}
357

    
358
function services_dhcpdv4_configure() {
359
	global $config, $g;
360
	$need_ddns_updates = false;
361
	$ddns_zones = array();
362

    
363
	if($g['services_dhcp_server_enable'] == false)
364
		return;
365

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

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

    
375
	/* DHCP enabled on any interfaces? */
376
	if (!is_dhcp_server_enabled())
377
		return 0;
378

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

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

    
406
	$syscfg = $config['system'];
407
	if (!is_array($config['dhcpd']))
408
		$config['dhcpd'] = array();
409
	$dhcpdcfg = $config['dhcpd'];
410
	$Iflist = get_configured_interface_list();
411

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

    
422
	if (platform_booting())
423
		echo gettext("Starting DHCP service...");
424
	else
425
		sleep(1);
426

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

    
440
	$dhcpdconf = <<<EOD
441

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

    
455
EOD;
456

    
457
	if(!isset($dhcpifconf['disableauthoritative']))
458
		$dhcpdconf .= "authoritative;\n";
459

    
460
	if(isset($dhcpifconf['alwaysbroadcast']))
461
		$dhcpdconf .= "always-broadcast on\n";
462

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

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

    
480
		if (!isset($config['interfaces'][$dhcpif]['enable']))
481
			continue;
482

    
483
		interfaces_staticarp_configure($dhcpif);
484

    
485
		if (!isset($dhcpifconf['enable']))
486
			continue;
487

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

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

    
542
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
543

    
544
		$newzone = array();
545
		$ifcfg = $config['interfaces'][$dhcpif];
546

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

    
554
		if (!is_ipaddr($subnet))
555
			continue;
556

    
557
		if($is_olsr_enabled == true)
558
			if($dhcpifconf['netmask'])
559
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
560

    
561
		$all_pools = array();
562
		$all_pools[] = $dhcpifconf;
563
		if (is_array($dhcpifconf['pool'])) {
564
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
565
		}
566

    
567
		$dnscfg = "";
568

    
569
		if ($dhcpifconf['domain']) {
570
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
571
		}
572

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

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

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

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

    
633
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
634

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

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

    
664
			if($poolconf['failover_peerip'] <> "")
665
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
666

    
667
			if (isset($poolconf['denyunknown']))
668
			   $dhcpdconf .= "		deny unknown-clients;\n";
669

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

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

    
677
			$pdnscfg = "";
678

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

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

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

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

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

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

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

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

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

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

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

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

    
753
		$dhcpdconf .= <<<EOD
754
$dnscfg
755

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

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

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

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

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

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

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

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

    
815
		$dhcpdconf .= <<<EOD
816
}
817

    
818
EOD;
819

    
820
		/* add static mappings */
821
		if (is_array($dhcpifconf['staticmap'])) {
822

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

    
827
                if ($sm['mac'])
828
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
829

    
830
                if ($sm['cid'])
831
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
832

    
833
				if ($sm['ipaddr'])
834
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
835

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

    
844
				if ($sm['rootpath'])
845
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
846

    
847
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
848
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
849

    
850
				$smdnscfg = "";
851

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

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

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

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

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

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

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

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

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

    
893
				$dhcpdconf .= "}\n";
894
				$i++;
895
			}
896
		}
897

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

    
909
	if ($need_ddns_updates) {
910
		$dhcpdconf .= "ddns-update-style interim;\n";
911
		$dhcpdconf .= "update-static-leases on;\n";
912

    
913
		$dhcpdconf .= dhcpdkey($dhcpifconf);
914
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
915
	}
916

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

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

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

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

    
939
	if (platform_booting())
940
		print "done.\n";
941

    
942
	return 0;
943
}
944

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

    
956
	return $dhcpdconf;
957
}
958

    
959
function dhcpdzones($ddns_zones, $dhcpifconf)
960
{
961
	$dhcpdconf = "";
962

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

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

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

    
1005
	return $dhcpdconf;
1006
}
1007

    
1008
function services_dhcpdv6_configure($blacklist = array()) {
1009
	global $config, $g;
1010

    
1011
	if($g['services_dhcp_server_enable'] == false)
1012
		return;
1013

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

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

    
1025
	/* DHCP enabled on any interfaces? */
1026
	if (!is_dhcpv6_server_enabled())
1027
		return 0;
1028

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

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

    
1051

    
1052
	if (platform_booting())
1053
		echo "Starting DHCPv6 service...";
1054
	else
1055
		sleep(1);
1056

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

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

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

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

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

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

    
1115
	$dhcpdv6conf = <<<EOD
1116

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

    
1129
EOD;
1130

    
1131
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1132
		$dhcpdv6conf .= "authoritative;\n";
1133

    
1134
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1135
		$dhcpdv6conf .= "always-broadcast on\n";
1136

    
1137
	$dhcpdv6ifs = array();
1138

    
1139
	$dhcpv6num = 0;
1140
	$nsupdate = false;
1141

    
1142
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1143

    
1144
		$ddns_zones = array();
1145

    
1146
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1147

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

    
1154
		if ($is_olsr_enabled == true) {
1155
			if($dhcpv6ifconf['netmask'])
1156
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1157
		}
1158

    
1159
		$dnscfgv6 = "";
1160

    
1161
		if ($dhcpv6ifconf['domain']) {
1162
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1163
		}
1164

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

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

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

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

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

    
1207
		$dhcpdv6conf .= <<<EOD
1208
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1209
$dnscfgv6
1210

    
1211
EOD;
1212

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

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

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

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

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

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

    
1262
		$dhcpdv6conf .= "}\n";
1263

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

    
1273
EOD;
1274
				if ($sm['ipaddrv6'])
1275
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1276

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

    
1285
				if ($sm['rootpath'])
1286
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1287

    
1288
				$dhcpdv6conf .= "}\n";
1289
				$i++;
1290
			}
1291
		}
1292

    
1293
		if ($dhcpv6ifconf['domain'])
1294
		{
1295
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1296
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1297
		}
1298

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

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

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

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

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

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

    
1353
	return 0;
1354
}
1355

    
1356
function services_igmpproxy_configure() {
1357
        global $config, $g;
1358

    
1359
        /* kill any running igmpproxy */
1360
        killbyname("igmpproxy");
1361

    
1362
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1363
		return 1;
1364

    
1365
        $iflist = get_configured_interface_list();
1366

    
1367
        $igmpconf = <<<EOD
1368

    
1369
##------------------------------------------------------
1370
## Enable Quickleave mode (Sends Leave instantly)
1371
##------------------------------------------------------
1372
quickleave
1373

    
1374
EOD;
1375

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

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

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

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

    
1411
        return 0;
1412
}
1413

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

    
1423
	/* kill any running dhcrelay */
1424
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1425

    
1426
	$dhcrelaycfg =& $config['dhcrelay'];
1427

    
1428
	/* DHCPRelay enabled on any interfaces? */
1429
	if (!isset($dhcrelaycfg['enable']))
1430
		return 0;
1431

    
1432
	if (platform_booting())
1433
		echo gettext("Starting DHCP relay service...");
1434
	else
1435
		sleep(1);
1436

    
1437
	$iflist = get_configured_interface_list();
1438

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

    
1445
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1446
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1447
	}
1448

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

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

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

    
1513
		if (!empty($destif))
1514
			$dhcrelayifs[] = $destif;
1515
	}
1516
	$dhcrelayifs = array_unique($dhcrelayifs);
1517

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

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

    
1526
	if (isset($dhcrelaycfg['agentoption']))
1527
		$cmd .=  " -a -m replace";
1528

    
1529
	$cmd .= " " . implode(" ", $srvips);
1530
	mwexec($cmd);
1531
	unset($cmd);
1532

    
1533
	return 0;
1534
}
1535

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

    
1545
	/* kill any running dhcrelay */
1546
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1547

    
1548
	$dhcrelaycfg =& $config['dhcrelay6'];
1549

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

    
1554
	if (platform_booting())
1555
		echo gettext("Starting DHCPv6 relay service...");
1556
	else
1557
		sleep(1);
1558

    
1559
	$iflist = get_configured_interface_list();
1560

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

    
1567
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1568
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1569
	}
1570
	$dhcrelayifs = array_unique($dhcrelayifs);
1571

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

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

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

    
1631
		if (!empty($destif)) {
1632
			$srvifaces[] = "{$srvip}%{$destif}";
1633
		}
1634
	}
1635

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

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

    
1652
	return 0;
1653
}
1654

    
1655
function services_dyndns_configure_client($conf) {
1656

    
1657
	if (!isset($conf['enable']))
1658
		return;
1659

    
1660
	/* load up the dyndns.class */
1661
	require_once("dyndns.class");
1662

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

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

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

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

    
1708
		if (platform_booting())
1709
			echo gettext("done.") . "\n";
1710
	}
1711

    
1712
	return 0;
1713
}
1714

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

    
1741
function services_dnsmasq_configure() {
1742
	global $config, $g;
1743
	$return = 0;
1744

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

    
1752

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

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

    
1762
	if (isset($config['dnsmasq']['enable'])) {
1763

    
1764
		if (platform_booting())
1765
			echo gettext("Starting DNS forwarder...");
1766
		else
1767
			sleep(1);
1768

    
1769
                /* generate hosts file */
1770
                if(system_hosts_generate()!=0)
1771
                        $return = 1;
1772

    
1773
		$args = "";
1774

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

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

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

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

    
1838
			// Build an array of domain overrides to help in checking for matches.
1839
			$override_a = array();
1840
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1841
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1842
					$override_a[$override['domain']] = "y";
1843
				}
1844
			}
1845

    
1846
			// Build an array of the private reverse lookup domain names
1847
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
1848
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
1849
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1850
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
1851
			}
1852

    
1853
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
1854
			foreach ($reverse_domain_a as $reverse_domain) { 
1855
				if (!isset($override_a[$reverse_domain]))
1856
					$args .= " --server=/$reverse_domain/ ";
1857
			}
1858
			unset($override_a);
1859
			unset($reverse_domain_a);
1860
		}
1861

    
1862
		/* Setup forwarded domains */
1863
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1864
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1865
				if ($override['ip'] == "!")
1866
					$override[ip] = "";
1867
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1868
			}
1869
		}
1870

    
1871
		/* Allow DNS Rebind for forwarded domains */
1872
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1873
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1874
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1875
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1876
				}
1877
			}
1878
		}
1879

    
1880
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1881
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1882

    
1883
		if (isset($config['dnsmasq']['strict_order'])) {
1884
			$args .= " --strict-order ";
1885
		}
1886

    
1887
		if (isset($config['dnsmasq']['domain_needed'])) {
1888
			$args .= " --domain-needed ";
1889
		}
1890

    
1891
		if ($config['dnsmasq']['custom_options'])
1892
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1893
				$args .= " " . escapeshellarg("--{$c}");
1894
				$p = explode('=', $c);
1895
				if (array_key_exists($p[0], $standard_args))
1896
					unset($standard_args[$p[0]]);
1897
			}
1898
		$args .= ' ' . implode(' ', array_values($standard_args));
1899

    
1900
		/* run dnsmasq */
1901
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1902
		//log_error("dnsmasq command: {$cmd}");
1903
		mwexec_bg($cmd);
1904
		unset($args);
1905

    
1906
        system_dhcpleases_configure();
1907

    
1908
		if (platform_booting())
1909
			echo gettext("done.") . "\n";
1910
	}
1911

    
1912
	if (!platform_booting()) {
1913
		if(services_dhcpd_configure()!=0)
1914
			$return = 1;
1915
	}
1916

    
1917
	return $return;
1918
}
1919

    
1920
function services_unbound_configure() {
1921
	global $config, $g;
1922
	$return = 0;
1923

    
1924
	if (isset($config['system']['developerspew'])) {
1925
		$mt = microtime();
1926
		echo "services_unbound_configure() being called $mt\n";
1927
	}
1928

    
1929
	// kill any running Unbound instance
1930
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1931
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1932

    
1933
	if (isset($config['unbound']['enable'])) {
1934
		if (platform_booting())
1935
			echo gettext("Starting DNS Resolver...");
1936
		else
1937
			sleep(1);
1938

    
1939
		/* generate hosts file */
1940
		if(system_hosts_generate()!=0)
1941
			$return = 1;
1942

    
1943
		require_once('/etc/inc/unbound.inc');
1944
		sync_unbound_service();
1945
		if (platform_booting())
1946
			echo gettext("done.") . "\n";
1947

    
1948
        system_dhcpleases_configure();
1949
	}
1950

    
1951
	if (!platform_booting()) {
1952
		if (services_dhcpd_configure()!=0)
1953
			$return = 1;
1954
	}
1955

    
1956
	return $return;
1957
}
1958

    
1959
function services_snmpd_configure() {
1960
	global $config, $g;
1961
	if(isset($config['system']['developerspew'])) {
1962
		$mt = microtime();
1963
		echo "services_snmpd_configure() being called $mt\n";
1964
	}
1965

    
1966
	/* kill any running snmpd */
1967
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1968
	sleep(2);
1969
	if(is_process_running("bsnmpd"))
1970
		mwexec("/usr/bin/killall bsnmpd", true);
1971

    
1972
	if (isset($config['snmpd']['enable'])) {
1973

    
1974
		if (platform_booting())
1975
			echo gettext("Starting SNMP daemon... ");
1976

    
1977
		/* generate snmpd.conf */
1978
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1979
		if (!$fd) {
1980
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1981
			return 1;
1982
		}
1983

    
1984

    
1985
		$snmpdconf = <<<EOD
1986
location := "{$config['snmpd']['syslocation']}"
1987
contact := "{$config['snmpd']['syscontact']}"
1988
read := "{$config['snmpd']['rocommunity']}"
1989

    
1990
EOD;
1991

    
1992
/* No docs on what write strings do there for disable for now.
1993
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1994
		    $snmpdconf .= <<<EOD
1995
# write string
1996
write := "{$config['snmpd']['rwcommunity']}"
1997

    
1998
EOD;
1999
		}
2000
*/
2001

    
2002

    
2003
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2004
		    $snmpdconf .= <<<EOD
2005
# SNMP Trap support.
2006
traphost := {$config['snmpd']['trapserver']}
2007
trapport := {$config['snmpd']['trapserverport']}
2008
trap := "{$config['snmpd']['trapstring']}"
2009

    
2010

    
2011
EOD;
2012
		}
2013

    
2014
		$version = trim(file_get_contents('/etc/version'));
2015
		$platform = trim(file_get_contents('/etc/platform'));
2016
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
2017
			$platform = $g['product_name'];
2018
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2019
			" {$version} {$platform} " . php_uname("s") .
2020
			" " . php_uname("r") . " " . php_uname("m");
2021

    
2022
		$snmpdconf .= <<<EOD
2023
system := 1     # pfSense
2024
%snmpd
2025
sysDescr			= "{$sysDescr}"
2026
begemotSnmpdDebugDumpPdus       = 2
2027
begemotSnmpdDebugSyslogPri      = 7
2028
begemotSnmpdCommunityString.0.1 = $(read)
2029

    
2030
EOD;
2031

    
2032
/* No docs on what write strings do there for disable for now.
2033
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
2034
		    $snmpdconf .= <<<EOD
2035
begemotSnmpdCommunityString.0.2 = $(write)
2036

    
2037
EOD;
2038
		}
2039
*/
2040

    
2041

    
2042
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
2043
		    $snmpdconf .= <<<EOD
2044
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2045
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2046
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2047

    
2048
EOD;
2049
		}
2050

    
2051

    
2052
		$snmpdconf .= <<<EOD
2053
begemotSnmpdCommunityDisable    = 1
2054

    
2055
EOD;
2056

    
2057
		if (isset($config['snmpd']['bindlan'])) {
2058
			$config['snmpd']['bindip'] = 'lan';
2059
			unset($config['snmpd']['bindlan']);
2060
		}
2061
		$bind_to_ip = "0.0.0.0";
2062
		if(isset($config['snmpd']['bindip'])) {
2063
			if (is_ipaddr($config['snmpd']['bindip'])) {
2064
				$bind_to_ip = $config['snmpd']['bindip'];
2065
			} else {
2066
				$if = get_real_interface($config['snmpd']['bindip']);
2067
				if (does_interface_exist($if))
2068
					$bind_to_ip = find_interface_ip($if);
2069
			}
2070
		}
2071

    
2072
		if(is_port( $config['snmpd']['pollport'] )) {
2073
		    $snmpdconf .= <<<EOD
2074
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2075

    
2076
EOD;
2077

    
2078
		}
2079

    
2080
		$snmpdconf .= <<<EOD
2081
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2082
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2083

    
2084
# These are bsnmp macros not php vars.
2085
sysContact      = $(contact)
2086
sysLocation     = $(location)
2087
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2088

    
2089
snmpEnableAuthenTraps = 2
2090

    
2091
EOD;
2092

    
2093
		if (is_array( $config['snmpd']['modules'] )) {
2094
		    if(isset($config['snmpd']['modules']['mibii'])) {
2095
			$snmpdconf .= <<<EOD
2096
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2097

    
2098
EOD;
2099
		    }
2100

    
2101
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2102
			$snmpdconf .= <<<EOD
2103
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2104
%netgraph
2105
begemotNgControlNodeName = "snmpd"
2106

    
2107
EOD;
2108
		    }
2109

    
2110
		    if(isset($config['snmpd']['modules']['pf'])) {
2111
			$snmpdconf .= <<<EOD
2112
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2113

    
2114
EOD;
2115
		    }
2116

    
2117
		    if(isset($config['snmpd']['modules']['hostres'])) {
2118
			/* XXX: hostres module crashes APU - ticket #4403 */
2119
			$specplatform = system_identify_specific_platform();
2120
			if ($specplatform['name'] == 'APU') {
2121
				log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
2122
			} else {
2123
				$snmpdconf .= <<<EOD
2124
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2125

    
2126
EOD;
2127
			}
2128
			unset($specplatform);
2129
		    }
2130

    
2131
		    if(isset($config['snmpd']['modules']['bridge'])) {
2132
			$snmpdconf .= <<<EOD
2133
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2134
# config must end with blank line
2135

    
2136
EOD;
2137
		    }
2138
			if(isset($config['snmpd']['modules']['ucd'])) {
2139
				$snmpdconf .= <<<EOD
2140
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2141

    
2142
EOD;
2143
			}
2144
			if(isset($config['snmpd']['modules']['regex'])) {
2145
				$snmpdconf .= <<<EOD
2146
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2147

    
2148
EOD;
2149
			}
2150
		}
2151

    
2152
		fwrite($fd, $snmpdconf);
2153
		fclose($fd);
2154
		unset($snmpdconf);
2155

    
2156
		if (isset($config['snmpd']['bindlan'])) {
2157
			$bindlan = "";
2158
		}
2159

    
2160
		/* run bsnmpd */
2161
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2162
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2163

    
2164
		if (platform_booting())
2165
			echo gettext("done.") . "\n";
2166
	}
2167

    
2168
	return 0;
2169
}
2170

    
2171
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2172
	global $config, $g;
2173
	if(isset($config['system']['developerspew'])) {
2174
		$mt = microtime();
2175
		echo "services_dnsupdate_process() being called $mt\n";
2176
	}
2177

    
2178
	/* Dynamic DNS updating active? */
2179
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2180
		$notify_text = "";
2181
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2182
			if (!isset($dnsupdate['enable']))
2183
				continue;
2184
			if (!empty($int) && $int != $dnsupdate['interface'])
2185
				continue;
2186
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2187
				continue;
2188

    
2189
			/* determine interface name */
2190
			$if = get_real_interface($dnsupdate['interface']);
2191
			
2192
			if (isset($dnsupdate['usepublicip']))
2193
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2194
                        else
2195
                                $wanip = get_interface_ip($dnsupdate['interface']);
2196
			
2197
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2198
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2199
			$currentTime = time();
2200

    
2201
			if ($wanip || $wanipv6) {
2202
				$keyname = $dnsupdate['keyname'];
2203
				/* trailing dot */
2204
				if (substr($keyname, -1) != ".")
2205
					$keyname .= ".";
2206

    
2207
				$hostname = $dnsupdate['host'];
2208
				/* trailing dot */
2209
				if (substr($hostname, -1) != ".")
2210
					$hostname .= ".";
2211

    
2212
				/* write private key file
2213
				   this is dumb - public and private keys are the same for HMAC-MD5,
2214
				   but nsupdate insists on having both */
2215
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2216
				$privkey = <<<EOD
2217
Private-key-format: v1.2
2218
Algorithm: 157 (HMAC)
2219
Key: {$dnsupdate['keydata']}
2220

    
2221
EOD;
2222
				fwrite($fd, $privkey);
2223
				fclose($fd);
2224

    
2225
				/* write public key file */
2226
				if ($dnsupdate['keytype'] == "zone") {
2227
					$flags = 257;
2228
					$proto = 3;
2229
				} else if ($dnsupdate['keytype'] == "host") {
2230
					$flags = 513;
2231
					$proto = 3;
2232
				} else if ($dnsupdate['keytype'] == "user") {
2233
					$flags = 0;
2234
					$proto = 2;
2235
				}
2236

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

    
2241
				/* generate update instructions */
2242
				$upinst = "";
2243
				if (!empty($dnsupdate['server']))
2244
					$upinst .= "server {$dnsupdate['server']}\n";
2245

    
2246
				if (file_exists($cacheFile)) {
2247
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2248
				}
2249
				if (file_exists("{$cacheFile}.ipv6")) {
2250
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2251
				}
2252

    
2253
				// 25 Days
2254
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2255
				$need_update = false;
2256

    
2257
				conf_mount_rw();
2258
				/* Update IPv4 if we have it. */
2259
				if (is_ipaddrv4($wanip)) {
2260
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2261
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2262
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2263
						$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";
2264
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2265
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2266
						$need_update = true;
2267
					} else {
2268
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2269
					}
2270
				} else
2271
					@unlink($cacheFile);
2272

    
2273
				/* Update IPv6 if we have it. */
2274
				if (is_ipaddrv6($wanipv6)) {
2275
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2276
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2277
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2278
						$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";
2279
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2280
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2281
						$need_update = true;
2282
					} else {
2283
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2284
					}
2285
				} else
2286
					@unlink("{$cacheFile}.ipv6");
2287
				conf_mount_ro();
2288

    
2289
				$upinst .= "\n";	/* mind that trailing newline! */
2290

    
2291
				if ($need_update) {
2292
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2293
					unset($upinst);
2294
					/* invoke nsupdate */
2295
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2296
					if (isset($dnsupdate['usetcp']))
2297
						$cmd .= " -v";
2298
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2299
					mwexec_bg($cmd);
2300
					unset($cmd);
2301
				}
2302
			}
2303
		}
2304
		if (!empty($notify_text)) {
2305
			notify_all_remote($notify_text);
2306
		}
2307
	}
2308

    
2309
	return 0;
2310
}
2311

    
2312
/* configure cron service */
2313
function configure_cron() {
2314
	global $g, $config;
2315

    
2316
	conf_mount_rw();
2317
	/* preserve existing crontab entries */
2318
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2319

    
2320
	for ($i = 0; $i < count($crontab_contents); $i++) {
2321
		$cron_item =& $crontab_contents[$i];
2322
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2323
			array_splice($crontab_contents, $i - 1);
2324
			break;
2325
		}
2326
	}
2327
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2328

    
2329

    
2330
	if (is_array($config['cron']['item'])) {
2331
		$crontab_contents .= "#\n";
2332
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2333
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2334
		$crontab_contents .= "#\n";
2335

    
2336
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2337
			$http_proxy = $config['system']['proxyurl'];
2338
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2339
				$http_proxy .= ':' . $config['system']['proxyport'];
2340
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2341
		}
2342

    
2343
		foreach ($config['cron']['item'] as $item) {
2344
			$crontab_contents .= "\n{$item['minute']}\t";
2345
			$crontab_contents .= "{$item['hour']}\t";
2346
			$crontab_contents .= "{$item['mday']}\t";
2347
			$crontab_contents .= "{$item['month']}\t";
2348
			$crontab_contents .= "{$item['wday']}\t";
2349
			$crontab_contents .= "{$item['who']}\t";
2350
			$crontab_contents .= "{$item['command']}";
2351
		}
2352

    
2353
		$crontab_contents .= "\n#\n";
2354
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2355
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2356
		$crontab_contents .= "#\n\n";
2357
	}
2358

    
2359
	/* please maintain the newline at the end of file */
2360
	file_put_contents("/etc/crontab", $crontab_contents);
2361
	unset($crontab_contents);
2362

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

    
2366
	conf_mount_ro();
2367
}
2368

    
2369
function upnp_action ($action) {
2370
	global $g, $config;
2371
	switch($action) {
2372
		case "start":
2373
			if (file_exists('/var/etc/miniupnpd.conf')) {
2374
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2375
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2376
			}
2377
			break;
2378
		case "stop":
2379
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2380
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2381
				mwexec('killall miniupnpd 2>/dev/null', true);
2382
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2383
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2384
			break;
2385
		case "restart":
2386
			upnp_action('stop');
2387
			upnp_action('start');
2388
			break;
2389
	}
2390
}
2391

    
2392
function upnp_start() {
2393
	global $config;
2394

    
2395
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2396
		return;
2397

    
2398
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2399
		echo gettext("Starting UPnP service... ");
2400
		require_once('/usr/local/pkg/miniupnpd.inc');
2401
		sync_package_miniupnpd();
2402
		echo "done.\n";
2403
	}
2404
}
2405

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

    
2409
	$is_installed = false;
2410
	$cron_changed = true;
2411

    
2412
	if (!is_array($config['cron']))
2413
		$config['cron'] = array();
2414
	if (!is_array($config['cron']['item']))
2415
		$config['cron']['item'] = array();
2416

    
2417
	$x=0;
2418
	foreach($config['cron']['item'] as $item) {
2419
		if(strstr($item['command'], $command)) {
2420
			$is_installed = true;
2421
			break;
2422
		}
2423
		$x++;
2424
	}
2425

    
2426
	if($active) {
2427
		$cron_item = array();
2428
		$cron_item['minute'] = $minute;
2429
		$cron_item['hour'] = $hour;
2430
		$cron_item['mday'] = $monthday;
2431
		$cron_item['month'] = $month;
2432
		$cron_item['wday'] = $weekday;
2433
		$cron_item['who'] = $who;
2434
		$cron_item['command'] = $command;
2435
		if(!$is_installed) {
2436
			$config['cron']['item'][] = $cron_item;
2437
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2438
		} else {
2439
			if ($config['cron']['item'][$x] == $cron_item) {
2440
				$cron_changed = false;
2441
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2442
			} else {
2443
				$config['cron']['item'][$x] = $cron_item;
2444
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2445
			}
2446
		}
2447
	} else {
2448
		if($is_installed == true) {
2449
			unset($config['cron']['item'][$x]);
2450
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2451
		}
2452
	}
2453

    
2454
	if ($cron_changed)
2455
		configure_cron();
2456
}
2457

    
2458
?>
(50-50/68)