Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
98
		$realif = get_real_interface($dhcpv6if, "inet6");
99
		if (isset($radvdifs[$realif]))
100
			continue;
101

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
370
	if ($g['booting']) {
371
		/* restore the leases, if we have them */
372
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
373
			$dhcprestore = "";
374
			$dhcpreturn = "";
375
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
376
			$dhcprestore = implode(" ", $dhcprestore);
377
			if($dhcpreturn <> 0) {
378
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
379
			}
380
		}
381
		/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
382
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
383
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
384
		}
385
	}
386

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

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

    
403
	if ($g['booting'])
404
		echo gettext("Starting DHCP service...");
405
	else
406
		sleep(1);
407

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

    
421
	$dhcpdconf = <<<EOD
422

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

    
436
EOD;
437

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

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

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

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

    
461
		interfaces_staticarp_configure($dhcpif);
462

    
463
		if (!isset($dhcpifconf['enable']))
464
			continue;
465

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

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

    
520
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
521

    
522
		$newzone = array();
523
		$ifcfg = $config['interfaces'][$dhcpif];
524

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

    
532
		if (!is_ipaddr($subnet))
533
			continue;
534

    
535
		if($is_olsr_enabled == true)
536
			if($dhcpifconf['netmask'])
537
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
538

    
539
		$all_pools = array();
540
		$all_pools[] = $dhcpifconf;
541
		if (is_array($dhcpifconf['pool'])) {
542
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
543
		}
544

    
545
		$dnscfg = "";
546

    
547
		if ($dhcpifconf['domain']) {
548
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
549
		}
550

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

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

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

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

    
611
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
612

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

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

    
642
			if($poolconf['failover_peerip'] <> "")
643
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
644

    
645
			if (isset($poolconf['denyunknown']))
646
			   $dhcpdconf .= "		deny unknown-clients;\n";
647

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

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

    
655
			$pdnscfg = "";
656

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

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

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

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

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

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

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

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

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

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

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

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

    
730
		$dhcpdconf .= <<<EOD
731
$dnscfg
732

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

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

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

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

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

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

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

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

    
792
		$dhcpdconf .= <<<EOD
793
}
794

    
795
EOD;
796

    
797
		/* add static mappings */
798
		if (is_array($dhcpifconf['staticmap'])) {
799

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

    
804
                if ($sm['mac'])
805
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
806

    
807
                if ($sm['cid'])
808
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
809

    
810
				if ($sm['ipaddr'])
811
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
812

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

    
821
				if ($sm['rootpath'])
822
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
823

    
824
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
825
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
826

    
827
				$smdnscfg = "";
828

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

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

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

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

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

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

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

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

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

    
870
				$dhcpdconf .= "}\n";
871
				$i++;
872
			}
873
		}
874

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

    
886
	if ($need_ddns_updates) {
887
		$dhcpdconf .= "ddns-update-style interim;\n";
888
		$dhcpdconf .= "update-static-leases on;\n";
889

    
890
		$dhcpdconf .= dhcpdkey($dhcpifconf);
891
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
892
	}
893

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

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

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

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

    
916
	if ($g['booting'])
917
		print "done.\n";
918

    
919
	return 0;
920
}
921

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

    
933
	return $dhcpdconf;
934
}
935

    
936
function dhcpdzones($ddns_zones, $dhcpifconf)
937
{
938
	$dhcpdconf = "";
939

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

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

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

    
982
	return $dhcpdconf;
983
}
984

    
985
function services_dhcpdv6_configure($blacklist = array()) {
986
	global $config, $g;
987

    
988
	if($g['services_dhcp_server_enable'] == false)
989
		return;
990

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

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

    
1002
	/* DHCP enabled on any interfaces? */
1003
	if (!is_dhcpv6_server_enabled())
1004
		return 0;
1005

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

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

    
1028

    
1029
	if ($g['booting'])
1030
		echo "Starting DHCPv6 service...";
1031
	else
1032
		sleep(1);
1033

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

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

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

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

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

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

    
1092
	$dhcpdv6conf = <<<EOD
1093

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

    
1106
EOD;
1107

    
1108
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1109
		$dhcpdv6conf .= "authoritative;\n";
1110

    
1111
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1112
		$dhcpdv6conf .= "always-broadcast on\n";
1113

    
1114
	$dhcpdv6ifs = array();
1115

    
1116
	$dhcpv6num = 0;
1117
	$nsupdate = false;
1118

    
1119
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1120

    
1121
		$ddns_zones = array();
1122

    
1123
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1124

    
1125
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
1126
			continue;
1127
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1128
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1129
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1130

    
1131
		if ($is_olsr_enabled == true) {
1132
			if($dhcpv6ifconf['netmask'])
1133
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1134
		}
1135

    
1136
		$dnscfgv6 = "";
1137

    
1138
		if ($dhcpv6ifconf['domain']) {
1139
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1140
		}
1141

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

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

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

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

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

    
1184
		$dhcpdv6conf .= <<<EOD
1185
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1186
$dnscfgv6
1187

    
1188
EOD;
1189

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

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

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

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

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

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

    
1239
		$dhcpdv6conf .= "}\n";
1240

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

    
1250
EOD;
1251
				if ($sm['ipaddrv6'])
1252
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1253

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

    
1262
				if ($sm['rootpath'])
1263
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1264

    
1265
				$dhcpdv6conf .= "}\n";
1266
				$i++;
1267
			}
1268
		}
1269

    
1270
		if ($dhcpv6ifconf['domain'])
1271
		{
1272
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1273
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1274
		}
1275

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

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

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

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

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

    
1321
	/* fire up dhcpd in a chroot */
1322
	if (count($dhcpdv6ifs) > 0) {
1323
		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 " .
1324
			join(" ", $dhcpdv6ifs));
1325
		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");
1326
	}
1327
	if ($g['booting'])
1328
		print gettext("done.") . "\n";
1329

    
1330
	return 0;
1331
}
1332

    
1333
function services_igmpproxy_configure() {
1334
        global $config, $g;
1335

    
1336
        /* kill any running igmpproxy */
1337
        killbyname("igmpproxy");
1338

    
1339
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1340
		return 1;
1341

    
1342
        $iflist = get_configured_interface_list();
1343

    
1344
        $igmpconf = <<<EOD
1345

    
1346
##------------------------------------------------------
1347
## Enable Quickleave mode (Sends Leave instantly)
1348
##------------------------------------------------------
1349
quickleave
1350

    
1351
EOD;
1352

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

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

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

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

    
1388
        return 0;
1389
}
1390

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

    
1400
	/* kill any running dhcrelay */
1401
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1402

    
1403
	$dhcrelaycfg =& $config['dhcrelay'];
1404

    
1405
	/* DHCPRelay enabled on any interfaces? */
1406
	if (!isset($dhcrelaycfg['enable']))
1407
		return 0;
1408

    
1409
	if ($g['booting'])
1410
		echo gettext("Starting DHCP relay service...");
1411
	else
1412
		sleep(1);
1413

    
1414
	$iflist = get_configured_interface_list();
1415

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

    
1422
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1423
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1424
	}
1425

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

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

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

    
1490
		if (!empty($destif))
1491
			$dhcrelayifs[] = $destif;
1492
	}
1493
	$dhcrelayifs = array_unique($dhcrelayifs);
1494

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

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

    
1503
	if (isset($dhcrelaycfg['agentoption']))
1504
		$cmd .=  " -a -m replace";
1505

    
1506
	$cmd .= " " . implode(" ", $srvips);
1507
	mwexec($cmd);
1508
	unset($cmd);
1509

    
1510
	return 0;
1511
}
1512

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

    
1522
	/* kill any running dhcrelay */
1523
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1524

    
1525
	$dhcrelaycfg =& $config['dhcrelay6'];
1526

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

    
1531
	if ($g['booting'])
1532
		echo gettext("Starting DHCPv6 relay service...");
1533
	else
1534
		sleep(1);
1535

    
1536
	$iflist = get_configured_interface_list();
1537

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

    
1544
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1545
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1546
	}
1547
	$dhcrelayifs = array_unique($dhcrelayifs);
1548

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

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

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

    
1608
		if (!empty($destif)) {
1609
			$srvifaces[] = "{$srvip}%{$destif}";
1610
		}
1611
	}
1612

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

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

    
1629
	return 0;
1630
}
1631

    
1632
function services_dyndns_configure_client($conf) {
1633

    
1634
	if (!isset($conf['enable']))
1635
		return;
1636

    
1637
	/* load up the dyndns.class */
1638
	require_once("dyndns.class");
1639

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

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

    
1669
	$dyndnscfg = $config['dyndnses']['dyndns'];
1670
	$gwgroups = return_gateway_groups_array();
1671
	if (is_array($dyndnscfg)) {
1672
		if ($g['booting'])
1673
			echo gettext("Starting DynDNS clients...");
1674

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

    
1685
		if ($g['booting'])
1686
			echo gettext("done.") . "\n";
1687
	}
1688

    
1689
	return 0;
1690
}
1691

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

    
1718
function services_dnsmasq_configure() {
1719
	global $config, $g;
1720
	$return = 0;
1721

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

    
1729

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

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

    
1739
	if (isset($config['dnsmasq']['enable'])) {
1740

    
1741
		if ($g['booting'])
1742
			echo gettext("Starting DNS forwarder...");
1743
		else
1744
			sleep(1);
1745

    
1746
                /* generate hosts file */
1747
                if(system_hosts_generate()!=0)
1748
                        $return = 1;
1749

    
1750
		$args = "";
1751

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

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

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

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

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

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

    
1841
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1842
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1843

    
1844
		if (isset($config['dnsmasq']['strict_order'])) {
1845
			$args .= " --strict-order ";
1846
		}
1847

    
1848
		if (isset($config['dnsmasq']['domain_needed'])) {
1849
			$args .= " --domain-needed ";
1850
		}
1851

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

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

    
1867
        system_dhcpleases_configure();
1868

    
1869
		if ($g['booting'])
1870
			echo gettext("done.") . "\n";
1871
	}
1872

    
1873
	if (!$g['booting']) {
1874
		if(services_dhcpd_configure()!=0)
1875
			$return = 1;
1876
	}
1877

    
1878
	return $return;
1879
}
1880

    
1881
function services_unbound_configure() {
1882
	global $config, $g;
1883
	$return = 0;
1884

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

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

    
1894
	if (isset($config['unbound']['enable'])) {
1895
		if ($g['booting'])
1896
			echo gettext("Starting DNS Resolver...");
1897
		else
1898
			sleep(1);
1899

    
1900
		/* generate hosts file */
1901
		if(system_hosts_generate()!=0)
1902
			$return = 1;
1903

    
1904
		require_once('/etc/inc/unbound.inc');
1905
		sync_unbound_service();
1906
		if ($g['booting'])
1907
			echo gettext("done.") . "\n";
1908

    
1909
        system_dhcpleases_configure();
1910
	}
1911

    
1912
	if (!$g['booting']) {
1913
		if (services_dhcpd_configure()!=0)
1914
			$return = 1;
1915
	}
1916

    
1917
	return $return;
1918
}
1919

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

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

    
1933
	if (isset($config['snmpd']['enable'])) {
1934

    
1935
		if ($g['booting'])
1936
			echo gettext("Starting SNMP daemon... ");
1937

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

    
1945

    
1946
		$snmpdconf = <<<EOD
1947
location := "{$config['snmpd']['syslocation']}"
1948
contact := "{$config['snmpd']['syscontact']}"
1949
read := "{$config['snmpd']['rocommunity']}"
1950

    
1951
EOD;
1952

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

    
1959
EOD;
1960
		}
1961
*/
1962

    
1963

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

    
1971

    
1972
EOD;
1973
		}
1974

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

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

    
1991
EOD;
1992

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

    
1998
EOD;
1999
		}
2000
*/
2001

    
2002

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

    
2009
EOD;
2010
		}
2011

    
2012

    
2013
		$snmpdconf .= <<<EOD
2014
begemotSnmpdCommunityDisable    = 1
2015

    
2016
EOD;
2017

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

    
2033
		if(is_port( $config['snmpd']['pollport'] )) {
2034
		    $snmpdconf .= <<<EOD
2035
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2036

    
2037
EOD;
2038

    
2039
		}
2040

    
2041
		$snmpdconf .= <<<EOD
2042
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2043
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2044

    
2045
# These are bsnmp macros not php vars.
2046
sysContact      = $(contact)
2047
sysLocation     = $(location)
2048
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2049

    
2050
snmpEnableAuthenTraps = 2
2051

    
2052
EOD;
2053

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

    
2059
EOD;
2060
		    }
2061

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

    
2068
EOD;
2069
		    }
2070

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

    
2075
EOD;
2076
		    }
2077

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

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

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

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

    
2101
EOD;
2102
			}
2103
		}
2104

    
2105
		fwrite($fd, $snmpdconf);
2106
		fclose($fd);
2107
		unset($snmpdconf);
2108

    
2109
		if (isset($config['snmpd']['bindlan'])) {
2110
			$bindlan = "";
2111
		}
2112

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

    
2117
		if ($g['booting'])
2118
			echo gettext("done.") . "\n";
2119
	}
2120

    
2121
	return 0;
2122
}
2123

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

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

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

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

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

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

    
2174
EOD;
2175
				fwrite($fd, $privkey);
2176
				fclose($fd);
2177

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

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

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

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

    
2206
				// 25 Days
2207
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2208
				$need_update = false;
2209

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

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

    
2242
				$upinst .= "\n";	/* mind that trailing newline! */
2243

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

    
2262
	return 0;
2263
}
2264

    
2265
/* configure cron service */
2266
function configure_cron() {
2267
	global $g, $config;
2268

    
2269
	conf_mount_rw();
2270
	/* preserve existing crontab entries */
2271
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2272

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

    
2282

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

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

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

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

    
2312
	/* please maintain the newline at the end of file */
2313
	file_put_contents("/etc/crontab", $crontab_contents);
2314
	unset($crontab_contents);
2315

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

    
2319
	conf_mount_ro();
2320
}
2321

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

    
2345
function upnp_start() {
2346
	global $config;
2347

    
2348
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2349
		return;
2350

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

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

    
2362
	$is_installed = false;
2363

    
2364
	if (!is_array($config['cron']))
2365
		$config['cron'] = array();
2366
	if (!is_array($config['cron']['item']))
2367
		$config['cron']['item'] = array();
2368

    
2369
	$x=0;
2370
	foreach($config['cron']['item'] as $item) {
2371
		if(strstr($item['command'], $command)) {
2372
			$is_installed = true;
2373
			break;
2374
		}
2375
		$x++;
2376
	}
2377

    
2378
	if($active) {
2379
		$cron_item = array();
2380
		$cron_item['minute'] = $minute;
2381
		$cron_item['hour'] = $hour;
2382
		$cron_item['mday'] = $monthday;
2383
		$cron_item['month'] = $month;
2384
		$cron_item['wday'] = $weekday;
2385
		$cron_item['who'] = $who;
2386
		$cron_item['command'] = $command;
2387
		if(!$is_installed) {
2388
			$config['cron']['item'][] = $cron_item;
2389
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2390
		} else {
2391
			$config['cron']['item'][$x] = $cron_item;
2392
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2393
		}
2394
	} else {
2395
		if($is_installed == true) {
2396
			unset($config['cron']['item'][$x]);
2397
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2398
		}
2399
	}
2400
	configure_cron();
2401
}
2402

    
2403
?>
(50-50/68)