Project

General

Profile

Download (76 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', 'dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip noip-free ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-v6 he-net-tunnelbroker selfhost route53 cloudflare custom custom-v6 eurodns gratisdns ovh-dynhost citynetwork');
42
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'DNS-O-Matic,DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,No-IP (free),ODS.org,ZoneEdit,Loopia,freeDNS,DNSexit,OpenDNS,Namecheap,HE.net,HE.net (v6),HE.net Tunnelbroker,SelfHost,Route 53,CloudFlare,Custom,Custom (v6),Euro Dns,GratisDNS,OVH DynHOST,City Network');
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 (!empty($dns_arrv4)) {
583
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
584
			if ($newzone['domain-name'])
585
				$newzone['dns-servers'] = $dns_arrv4;
586
		}
587

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

    
609
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
610

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

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

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

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

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

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

    
653
			$pdnscfg = "";
654

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

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

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

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

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

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

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

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

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

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

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

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

    
728
		$dhcpdconf .= <<<EOD
729
$dnscfg
730

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

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

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

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

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

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

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

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

    
790
		$dhcpdconf .= <<<EOD
791
}
792

    
793
EOD;
794

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

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

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

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

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

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

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

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

    
825
				$smdnscfg = "";
826

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

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

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

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

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

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

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

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

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

    
868
				$dhcpdconf .= "}\n";
869
				$i++;
870
			}
871
		}
872

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

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

    
888
		$dhcpdconf .= dhcpdkey($dhcpifconf);
889
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
890
	}
891

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

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

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

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

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

    
917
	return 0;
918
}
919

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

    
931
	return $dhcpdconf;
932
}
933

    
934
function dhcpdzones($ddns_zones, $dhcpifconf)
935
{
936
	$dhcpdconf = "";
937

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

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

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

    
980
	return $dhcpdconf;
981
}
982

    
983
function services_dhcpdv6_configure($blacklist = array()) {
984
	global $config, $g;
985

    
986
	if($g['services_dhcp_server_enable'] == false)
987
		return;
988

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

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

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

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

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

    
1026

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

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

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

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

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

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

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

    
1090
	$dhcpdv6conf = <<<EOD
1091

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

    
1104
EOD;
1105

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

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

    
1112
	$dhcpdv6ifs = array();
1113

    
1114
	$dhcpv6num = 0;
1115
	$nsupdate = false;
1116

    
1117
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1118

    
1119
		$ddns_zones = array();
1120

    
1121
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1122

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

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

    
1134
		$dnscfgv6 = "";
1135

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

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

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

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

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

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

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

    
1186
EOD;
1187

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

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

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

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

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

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

    
1237
		$dhcpdv6conf .= "}\n";
1238

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

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

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

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

    
1263
				$dhcpdv6conf .= "}\n";
1264
				$i++;
1265
			}
1266
		}
1267

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

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

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

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

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

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

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

    
1328
	return 0;
1329
}
1330

    
1331
function services_igmpproxy_configure() {
1332
        global $config, $g;
1333

    
1334
        /* kill any running igmpproxy */
1335
        killbyname("igmpproxy");
1336

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

    
1340
        $iflist = get_configured_interface_list();
1341

    
1342
        $igmpconf = <<<EOD
1343

    
1344
##------------------------------------------------------
1345
## Enable Quickleave mode (Sends Leave instantly)
1346
##------------------------------------------------------
1347
quickleave
1348

    
1349
EOD;
1350

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

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

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

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

    
1386
        return 0;
1387
}
1388

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

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

    
1401
	$dhcrelaycfg =& $config['dhcrelay'];
1402

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

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

    
1412
	$iflist = get_configured_interface_list();
1413

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

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

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

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

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

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

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

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

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

    
1504
	$cmd .= " " . implode(" ", $srvips);
1505
	mwexec($cmd);
1506
	unset($cmd);
1507

    
1508
	return 0;
1509
}
1510

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

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

    
1523
	$dhcrelaycfg =& $config['dhcrelay6'];
1524

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

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

    
1534
	$iflist = get_configured_interface_list();
1535

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

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

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

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

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

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

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

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

    
1627
	return 0;
1628
}
1629

    
1630
function services_dyndns_configure_client($conf) {
1631

    
1632
	if (!isset($conf['enable']))
1633
		return;
1634

    
1635
	/* load up the dyndns.class */
1636
	require_once("dyndns.class");
1637

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

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

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

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

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

    
1687
	return 0;
1688
}
1689

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

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

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

    
1727

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

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

    
1737
	if (isset($config['dnsmasq']['enable'])) {
1738

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

    
1744
		$args = "";
1745

    
1746
		if (isset($config['dnsmasq']['regdhcp'])) {
1747
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1748
		}
1749

    
1750
		/* Setup listen port, if non-default */
1751
		if (is_port($config['dnsmasq']['port']))
1752
			$args .= " --port={$config['dnsmasq']['port']} ";
1753

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

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

    
1813
		/* Setup forwarded domains */
1814
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1815
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1816
				if ($override['ip'] == "!")
1817
					$override[ip] = "";
1818
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1819
			}
1820
		}
1821

    
1822
		/* Allow DNS Rebind for forwarded domains */
1823
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1824
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1825
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1826
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1827
				}
1828
			}
1829
		}
1830

    
1831
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1832
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1833

    
1834
		if (isset($config['dnsmasq']['strict_order'])) {
1835
			$args .= " --strict-order ";
1836
		}
1837

    
1838
		if (isset($config['dnsmasq']['domain_needed'])) {
1839
			$args .= " --domain-needed ";
1840
		}
1841

    
1842
		if ($config['dnsmasq']['custom_options'])
1843
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1844
				$args .= " " . escapeshellarg("--{$c}");
1845
				$p = explode('=', $c);
1846
				if (array_key_exists($p[0], $standard_args))
1847
					unset($standard_args[$p[0]]);
1848
			}
1849
		$args .= ' ' . implode(' ', array_values($standard_args));
1850

    
1851
		/* run dnsmasq */
1852
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1853
		//log_error("dnsmasq command: {$cmd}");
1854
		mwexec_bg($cmd);
1855
		unset($args);
1856

    
1857
		if ($g['booting'])
1858
			echo gettext("done.") . "\n";
1859
	}
1860

    
1861
	if (!$g['booting']) {
1862
		if(services_dhcpd_configure()!=0)
1863
			$return = 1;
1864
	}
1865

    
1866
	return $return;
1867
}
1868

    
1869
function services_unbound_configure() {
1870
	global $config, $g;
1871
	$return = 0;
1872

    
1873
	if (isset($config['system']['developerspew'])) {
1874
		$mt = microtime();
1875
		echo "services_unbound_configure() being called $mt\n";
1876
	}
1877

    
1878
	// kill any running Unbound instance
1879
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1880
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1881

    
1882
	if (isset($config['unbound']['enable'])) {
1883
		if ($g['booting'])
1884
			echo gettext("Starting DNS Resolver...");
1885
		else
1886
			sleep(1);
1887

    
1888
		require_once('/etc/inc/unbound.inc');
1889
		sync_unbound_service();
1890
		if ($g['booting'])
1891
			echo gettext("done.") . "\n";
1892
	}
1893

    
1894
	if (!$g['booting']) {
1895
		if (services_dhcpd_configure()!=0)
1896
			$return = 1;
1897
	}
1898

    
1899
	return $return;
1900
}
1901

    
1902
function services_snmpd_configure() {
1903
	global $config, $g;
1904
	if(isset($config['system']['developerspew'])) {
1905
		$mt = microtime();
1906
		echo "services_snmpd_configure() being called $mt\n";
1907
	}
1908

    
1909
	/* kill any running snmpd */
1910
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1911
	sleep(2);
1912
	if(is_process_running("bsnmpd"))
1913
		mwexec("/usr/bin/killall bsnmpd", true);
1914

    
1915
	if (isset($config['snmpd']['enable'])) {
1916

    
1917
		if ($g['booting'])
1918
			echo gettext("Starting SNMP daemon... ");
1919

    
1920
		/* generate snmpd.conf */
1921
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1922
		if (!$fd) {
1923
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1924
			return 1;
1925
		}
1926

    
1927

    
1928
		$snmpdconf = <<<EOD
1929
location := "{$config['snmpd']['syslocation']}"
1930
contact := "{$config['snmpd']['syscontact']}"
1931
read := "{$config['snmpd']['rocommunity']}"
1932

    
1933
EOD;
1934

    
1935
/* No docs on what write strings do there for disable for now.
1936
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1937
		    $snmpdconf .= <<<EOD
1938
# write string
1939
write := "{$config['snmpd']['rwcommunity']}"
1940

    
1941
EOD;
1942
		}
1943
*/
1944

    
1945

    
1946
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1947
		    $snmpdconf .= <<<EOD
1948
# SNMP Trap support.
1949
traphost := {$config['snmpd']['trapserver']}
1950
trapport := {$config['snmpd']['trapserverport']}
1951
trap := "{$config['snmpd']['trapstring']}"
1952

    
1953

    
1954
EOD;
1955
		}
1956

    
1957
		$version = trim(file_get_contents('/etc/version'));
1958
		$platform = trim(file_get_contents('/etc/platform'));
1959
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1960
			$platform = $g['product_name'];
1961
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1962
			" {$version} {$platform} " . php_uname("s") .
1963
			" " . php_uname("r") . " " . php_uname("m");
1964

    
1965
		$snmpdconf .= <<<EOD
1966
system := 1     # pfSense
1967
%snmpd
1968
sysDescr			= "{$sysDescr}"
1969
begemotSnmpdDebugDumpPdus       = 2
1970
begemotSnmpdDebugSyslogPri      = 7
1971
begemotSnmpdCommunityString.0.1 = $(read)
1972

    
1973
EOD;
1974

    
1975
/* No docs on what write strings do there for disable for now.
1976
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1977
		    $snmpdconf .= <<<EOD
1978
begemotSnmpdCommunityString.0.2 = $(write)
1979

    
1980
EOD;
1981
		}
1982
*/
1983

    
1984

    
1985
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1986
		    $snmpdconf .= <<<EOD
1987
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1988
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1989
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1990

    
1991
EOD;
1992
		}
1993

    
1994

    
1995
		$snmpdconf .= <<<EOD
1996
begemotSnmpdCommunityDisable    = 1
1997

    
1998
EOD;
1999

    
2000
		if (isset($config['snmpd']['bindlan'])) {
2001
			$config['snmpd']['bindip'] = 'lan';
2002
			unset($config['snmpd']['bindlan']);
2003
		}
2004
		$bind_to_ip = "0.0.0.0";
2005
		if(isset($config['snmpd']['bindip'])) {
2006
			if (is_ipaddr($config['snmpd']['bindip'])) {
2007
				$bind_to_ip = $config['snmpd']['bindip'];
2008
			} else {
2009
				$if = get_real_interface($config['snmpd']['bindip']);
2010
				if (does_interface_exist($if))
2011
					$bind_to_ip = find_interface_ip($if);
2012
			}
2013
		}
2014

    
2015
		if(is_port( $config['snmpd']['pollport'] )) {
2016
		    $snmpdconf .= <<<EOD
2017
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2018

    
2019
EOD;
2020

    
2021
		}
2022

    
2023
		$snmpdconf .= <<<EOD
2024
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2025
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2026

    
2027
# These are bsnmp macros not php vars.
2028
sysContact      = $(contact)
2029
sysLocation     = $(location)
2030
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2031

    
2032
snmpEnableAuthenTraps = 2
2033

    
2034
EOD;
2035

    
2036
		if (is_array( $config['snmpd']['modules'] )) {
2037
		    if(isset($config['snmpd']['modules']['mibii'])) {
2038
			$snmpdconf .= <<<EOD
2039
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2040

    
2041
EOD;
2042
		    }
2043

    
2044
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2045
			$snmpdconf .= <<<EOD
2046
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2047
%netgraph
2048
begemotNgControlNodeName = "snmpd"
2049

    
2050
EOD;
2051
		    }
2052

    
2053
		    if(isset($config['snmpd']['modules']['pf'])) {
2054
			$snmpdconf .= <<<EOD
2055
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2056

    
2057
EOD;
2058
		    }
2059

    
2060
		    if(isset($config['snmpd']['modules']['hostres'])) {
2061
			$snmpdconf .= <<<EOD
2062
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2063

    
2064
EOD;
2065
		    }
2066
		    if(isset($config['snmpd']['modules']['bridge'])) {
2067
			$snmpdconf .= <<<EOD
2068
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2069
# config must end with blank line
2070

    
2071
EOD;
2072
		    }
2073
			if(isset($config['snmpd']['modules']['ucd'])) {
2074
				$snmpdconf .= <<<EOD
2075
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2076

    
2077
EOD;
2078
			}
2079
			if(isset($config['snmpd']['modules']['regex'])) {
2080
				$snmpdconf .= <<<EOD
2081
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2082

    
2083
EOD;
2084
			}
2085
		}
2086

    
2087
		fwrite($fd, $snmpdconf);
2088
		fclose($fd);
2089
		unset($snmpdconf);
2090

    
2091
		if (isset($config['snmpd']['bindlan'])) {
2092
			$bindlan = "";
2093
		}
2094

    
2095
		/* run bsnmpd */
2096
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2097
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2098

    
2099
		if ($g['booting'])
2100
			echo gettext("done.") . "\n";
2101
	}
2102

    
2103
	return 0;
2104
}
2105

    
2106
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2107
	global $config, $g;
2108
	if(isset($config['system']['developerspew'])) {
2109
		$mt = microtime();
2110
		echo "services_dnsupdate_process() being called $mt\n";
2111
	}
2112

    
2113
	/* Dynamic DNS updating active? */
2114
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2115
		$notify_text = "";
2116
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2117
			if (!isset($dnsupdate['enable']))
2118
				continue;
2119
			if (!empty($int) && $int != $dnsupdate['interface'])
2120
				continue;
2121
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2122
				continue;
2123

    
2124
			/* determine interface name */
2125
			$if = get_real_interface($dnsupdate['interface']);
2126
			
2127
			if (isset($dnsupdate['usepublicip']))
2128
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2129
                        else
2130
                                $wanip = get_interface_ip($dnsupdate['interface']);
2131
			
2132
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2133
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2134
			$currentTime = time();
2135

    
2136
			if ($wanip || $wanipv6) {
2137
				$keyname = $dnsupdate['keyname'];
2138
				/* trailing dot */
2139
				if (substr($keyname, -1) != ".")
2140
					$keyname .= ".";
2141

    
2142
				$hostname = $dnsupdate['host'];
2143
				/* trailing dot */
2144
				if (substr($hostname, -1) != ".")
2145
					$hostname .= ".";
2146

    
2147
				/* write private key file
2148
				   this is dumb - public and private keys are the same for HMAC-MD5,
2149
				   but nsupdate insists on having both */
2150
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2151
				$privkey = <<<EOD
2152
Private-key-format: v1.2
2153
Algorithm: 157 (HMAC)
2154
Key: {$dnsupdate['keydata']}
2155

    
2156
EOD;
2157
				fwrite($fd, $privkey);
2158
				fclose($fd);
2159

    
2160
				/* write public key file */
2161
				if ($dnsupdate['keytype'] == "zone") {
2162
					$flags = 257;
2163
					$proto = 3;
2164
				} else if ($dnsupdate['keytype'] == "host") {
2165
					$flags = 513;
2166
					$proto = 3;
2167
				} else if ($dnsupdate['keytype'] == "user") {
2168
					$flags = 0;
2169
					$proto = 2;
2170
				}
2171

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

    
2176
				/* generate update instructions */
2177
				$upinst = "";
2178
				if (!empty($dnsupdate['server']))
2179
					$upinst .= "server {$dnsupdate['server']}\n";
2180

    
2181
				if (file_exists($cacheFile)) {
2182
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2183
				}
2184
				if (file_exists("{$cacheFile}.ipv6")) {
2185
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2186
				}
2187

    
2188
				// 25 Days
2189
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2190
				$need_update = false;
2191

    
2192
				conf_mount_rw();
2193
				/* Update IPv4 if we have it. */
2194
				if (is_ipaddrv4($wanip)) {
2195
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2196
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2197
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2198
						$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";
2199
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2200
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2201
						$need_update = true;
2202
					} else {
2203
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2204
					}
2205
				} else
2206
					@unlink($cacheFile);
2207

    
2208
				/* Update IPv6 if we have it. */
2209
				if (is_ipaddrv6($wanipv6)) {
2210
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2211
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2212
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2213
						$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";
2214
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2215
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2216
						$need_update = true;
2217
					} else {
2218
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2219
					}
2220
				} else
2221
					@unlink("{$cacheFile}.ipv6");
2222
				conf_mount_ro();
2223

    
2224
				$upinst .= "\n";	/* mind that trailing newline! */
2225

    
2226
				if ($need_update) {
2227
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2228
					unset($upinst);
2229
					/* invoke nsupdate */
2230
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2231
					if (isset($dnsupdate['usetcp']))
2232
						$cmd .= " -v";
2233
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2234
					mwexec_bg($cmd);
2235
					unset($cmd);
2236
				}
2237
			}
2238
		}
2239
		if (!empty($notify_text)) {
2240
			notify_all_remote($notify_text);
2241
		}
2242
	}
2243

    
2244
	return 0;
2245
}
2246

    
2247
/* configure cron service */
2248
function configure_cron() {
2249
	global $g, $config;
2250

    
2251
	conf_mount_rw();
2252
	/* preserve existing crontab entries */
2253
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2254

    
2255
	for ($i = 0; $i < count($crontab_contents); $i++) {
2256
		$cron_item =& $crontab_contents[$i];
2257
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2258
			array_splice($crontab_contents, $i - 1);
2259
			break;
2260
		}
2261
	}
2262
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2263

    
2264

    
2265
	if (is_array($config['cron']['item'])) {
2266
		$crontab_contents .= "#\n";
2267
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2268
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2269
		$crontab_contents .= "#\n";
2270

    
2271
		foreach ($config['cron']['item'] as $item) {
2272
			$crontab_contents .= "\n{$item['minute']}\t";
2273
			$crontab_contents .= "{$item['hour']}\t";
2274
			$crontab_contents .= "{$item['mday']}\t";
2275
			$crontab_contents .= "{$item['month']}\t";
2276
			$crontab_contents .= "{$item['wday']}\t";
2277
			$crontab_contents .= "{$item['who']}\t";
2278
			$crontab_contents .= "{$item['command']}";
2279
		}
2280

    
2281
		$crontab_contents .= "\n#\n";
2282
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2283
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2284
		$crontab_contents .= "#\n\n";
2285
	}
2286

    
2287
	/* please maintain the newline at the end of file */
2288
	file_put_contents("/etc/crontab", $crontab_contents);
2289
	unset($crontab_contents);
2290

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

    
2294
	conf_mount_ro();
2295
}
2296

    
2297
function upnp_action ($action) {
2298
	global $g, $config;
2299
	switch($action) {
2300
		case "start":
2301
			if (file_exists('/var/etc/miniupnpd.conf')) {
2302
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2303
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2304
			}
2305
			break;
2306
		case "stop":
2307
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2308
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2309
				mwexec('killall miniupnpd 2>/dev/null', true);
2310
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2311
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2312
			break;
2313
		case "restart":
2314
			upnp_action('stop');
2315
			upnp_action('start');
2316
			break;
2317
	}
2318
}
2319

    
2320
function upnp_start() {
2321
	global $config;
2322

    
2323
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2324
		return;
2325

    
2326
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2327
		echo gettext("Starting UPnP service... ");
2328
		require_once('/usr/local/pkg/miniupnpd.inc');
2329
		sync_package_miniupnpd();
2330
		echo "done.\n";
2331
	}
2332
}
2333

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

    
2337
	$is_installed = false;
2338

    
2339
	if (!is_array($config['cron']))
2340
		$config['cron'] = array();
2341
	if (!is_array($config['cron']['item']))
2342
		$config['cron']['item'] = array();
2343

    
2344
	$x=0;
2345
	foreach($config['cron']['item'] as $item) {
2346
		if(strstr($item['command'], $command)) {
2347
			$is_installed = true;
2348
			break;
2349
		}
2350
		$x++;
2351
	}
2352

    
2353
	if($active) {
2354
		$cron_item = array();
2355
		$cron_item['minute'] = $minute;
2356
		$cron_item['hour'] = $hour;
2357
		$cron_item['mday'] = $monthday;
2358
		$cron_item['month'] = $month;
2359
		$cron_item['wday'] = $weekday;
2360
		$cron_item['who'] = $who;
2361
		$cron_item['command'] = $command;
2362
		if(!$is_installed) {
2363
			$config['cron']['item'][] = $cron_item;
2364
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2365
		} else {
2366
			$config['cron']['item'][$x] = $cron_item;
2367
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2368
		}
2369
	} else {
2370
		if($is_installed == true) {
2371
			unset($config['cron']['item'][$x]);
2372
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2373
		}
2374
	}
2375
	configure_cron();
2376
}
2377

    
2378
?>
(50-50/68)