Project

General

Profile

Download (76.8 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
		if ($g['booting'])
1868
			echo gettext("done.") . "\n";
1869
	}
1870

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

    
1876
	return $return;
1877
}
1878

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

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

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

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

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

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

    
1908
	if (!$g['booting']) {
1909
		if (services_dhcpd_configure()!=0)
1910
			$return = 1;
1911
	}
1912

    
1913
	return $return;
1914
}
1915

    
1916
function services_snmpd_configure() {
1917
	global $config, $g;
1918
	if(isset($config['system']['developerspew'])) {
1919
		$mt = microtime();
1920
		echo "services_snmpd_configure() being called $mt\n";
1921
	}
1922

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

    
1929
	if (isset($config['snmpd']['enable'])) {
1930

    
1931
		if ($g['booting'])
1932
			echo gettext("Starting SNMP daemon... ");
1933

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

    
1941

    
1942
		$snmpdconf = <<<EOD
1943
location := "{$config['snmpd']['syslocation']}"
1944
contact := "{$config['snmpd']['syscontact']}"
1945
read := "{$config['snmpd']['rocommunity']}"
1946

    
1947
EOD;
1948

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

    
1955
EOD;
1956
		}
1957
*/
1958

    
1959

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

    
1967

    
1968
EOD;
1969
		}
1970

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

    
1979
		$snmpdconf .= <<<EOD
1980
system := 1     # pfSense
1981
%snmpd
1982
sysDescr			= "{$sysDescr}"
1983
begemotSnmpdDebugDumpPdus       = 2
1984
begemotSnmpdDebugSyslogPri      = 7
1985
begemotSnmpdCommunityString.0.1 = $(read)
1986

    
1987
EOD;
1988

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

    
1994
EOD;
1995
		}
1996
*/
1997

    
1998

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

    
2005
EOD;
2006
		}
2007

    
2008

    
2009
		$snmpdconf .= <<<EOD
2010
begemotSnmpdCommunityDisable    = 1
2011

    
2012
EOD;
2013

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

    
2029
		if(is_port( $config['snmpd']['pollport'] )) {
2030
		    $snmpdconf .= <<<EOD
2031
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2032

    
2033
EOD;
2034

    
2035
		}
2036

    
2037
		$snmpdconf .= <<<EOD
2038
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2039
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2040

    
2041
# These are bsnmp macros not php vars.
2042
sysContact      = $(contact)
2043
sysLocation     = $(location)
2044
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2045

    
2046
snmpEnableAuthenTraps = 2
2047

    
2048
EOD;
2049

    
2050
		if (is_array( $config['snmpd']['modules'] )) {
2051
		    if(isset($config['snmpd']['modules']['mibii'])) {
2052
			$snmpdconf .= <<<EOD
2053
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2054

    
2055
EOD;
2056
		    }
2057

    
2058
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2059
			$snmpdconf .= <<<EOD
2060
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2061
%netgraph
2062
begemotNgControlNodeName = "snmpd"
2063

    
2064
EOD;
2065
		    }
2066

    
2067
		    if(isset($config['snmpd']['modules']['pf'])) {
2068
			$snmpdconf .= <<<EOD
2069
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2070

    
2071
EOD;
2072
		    }
2073

    
2074
		    if(isset($config['snmpd']['modules']['hostres'])) {
2075
			$snmpdconf .= <<<EOD
2076
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2077

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

    
2085
EOD;
2086
		    }
2087
			if(isset($config['snmpd']['modules']['ucd'])) {
2088
				$snmpdconf .= <<<EOD
2089
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2090

    
2091
EOD;
2092
			}
2093
			if(isset($config['snmpd']['modules']['regex'])) {
2094
				$snmpdconf .= <<<EOD
2095
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2096

    
2097
EOD;
2098
			}
2099
		}
2100

    
2101
		fwrite($fd, $snmpdconf);
2102
		fclose($fd);
2103
		unset($snmpdconf);
2104

    
2105
		if (isset($config['snmpd']['bindlan'])) {
2106
			$bindlan = "";
2107
		}
2108

    
2109
		/* run bsnmpd */
2110
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2111
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2112

    
2113
		if ($g['booting'])
2114
			echo gettext("done.") . "\n";
2115
	}
2116

    
2117
	return 0;
2118
}
2119

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

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

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

    
2150
			if ($wanip || $wanipv6) {
2151
				$keyname = $dnsupdate['keyname'];
2152
				/* trailing dot */
2153
				if (substr($keyname, -1) != ".")
2154
					$keyname .= ".";
2155

    
2156
				$hostname = $dnsupdate['host'];
2157
				/* trailing dot */
2158
				if (substr($hostname, -1) != ".")
2159
					$hostname .= ".";
2160

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

    
2170
EOD;
2171
				fwrite($fd, $privkey);
2172
				fclose($fd);
2173

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

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

    
2190
				/* generate update instructions */
2191
				$upinst = "";
2192
				if (!empty($dnsupdate['server']))
2193
					$upinst .= "server {$dnsupdate['server']}\n";
2194

    
2195
				if (file_exists($cacheFile)) {
2196
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2197
				}
2198
				if (file_exists("{$cacheFile}.ipv6")) {
2199
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2200
				}
2201

    
2202
				// 25 Days
2203
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2204
				$need_update = false;
2205

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

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

    
2238
				$upinst .= "\n";	/* mind that trailing newline! */
2239

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

    
2258
	return 0;
2259
}
2260

    
2261
/* configure cron service */
2262
function configure_cron() {
2263
	global $g, $config;
2264

    
2265
	conf_mount_rw();
2266
	/* preserve existing crontab entries */
2267
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2268

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

    
2278

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

    
2285
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2286
			$http_proxy = $config['system']['proxyurl'];
2287
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2288
				$http_proxy .= ':' . $config['system']['proxyport'];
2289
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2290
		}
2291

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

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

    
2308
	/* please maintain the newline at the end of file */
2309
	file_put_contents("/etc/crontab", $crontab_contents);
2310
	unset($crontab_contents);
2311

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

    
2315
	conf_mount_ro();
2316
}
2317

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

    
2341
function upnp_start() {
2342
	global $config;
2343

    
2344
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2345
		return;
2346

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

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

    
2358
	$is_installed = false;
2359

    
2360
	if (!is_array($config['cron']))
2361
		$config['cron'] = array();
2362
	if (!is_array($config['cron']['item']))
2363
		$config['cron']['item'] = array();
2364

    
2365
	$x=0;
2366
	foreach($config['cron']['item'] as $item) {
2367
		if(strstr($item['command'], $command)) {
2368
			$is_installed = true;
2369
			break;
2370
		}
2371
		$x++;
2372
	}
2373

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

    
2399
?>
(50-50/68)