Projet

Général

Profil

Télécharger (75,1 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / services.inc @ 959dc96b

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($config['installedpackages']['olsrd'])
362
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
363
				if($olsrd['enable'])
364
					$is_olsr_enabled = true;
365

    
366
	if ($g['booting']) {
367
		/* restore the leases, if we have them */
368
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
369
			$dhcprestore = "";
370
			$dhcpreturn = "";
371
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
372
			$dhcprestore = implode(" ", $dhcprestore);
373
			if($dhcpreturn <> 0) {
374
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
375
			}
376
		}
377
		/* 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. */
378
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
379
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
380
		}
381
	}
382

    
383
	$syscfg = $config['system'];
384
	if (!is_array($config['dhcpd']))
385
		$config['dhcpd'] = array();
386
	$dhcpdcfg = $config['dhcpd'];
387
	$Iflist = get_configured_interface_list();
388

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

    
399
	if ($g['booting'])
400
		echo gettext("Starting DHCP service...");
401
	else
402
		sleep(1);
403

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

    
417
	$dhcpdconf = <<<EOD
418

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

    
432
EOD;
433

    
434
	if(!isset($dhcpifconf['disableauthoritative']))
435
		$dhcpdconf .= "authoritative;\n";
436

    
437
	if(isset($dhcpifconf['alwaysbroadcast']))
438
		$dhcpdconf .= "always-broadcast on\n";
439

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

    
452
	/*    loop through and determine if we need to setup
453
	 *    failover peer "bleh" entries
454
	 */
455
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
456

    
457
		interfaces_staticarp_configure($dhcpif);
458

    
459
		if (!isset($dhcpifconf['enable']))
460
			continue;
461

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

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

    
516
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
517

    
518
		$newzone = array();
519
		$ifcfg = $config['interfaces'][$dhcpif];
520

    
521
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
522
			continue;
523
		$ifcfgip = get_interface_ip($dhcpif);
524
		$ifcfgsn = get_interface_subnet($dhcpif);
525
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
526
		$subnetmask = gen_subnet_mask($ifcfgsn);
527

    
528
		if (!is_ipaddr($subnet))
529
			continue;
530

    
531
		if($is_olsr_enabled == true)
532
			if($dhcpifconf['netmask'])
533
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
534

    
535
		$all_pools = array();
536
		$all_pools[] = $dhcpifconf;
537
		if (is_array($dhcpifconf['pool'])) {
538
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
539
		}
540

    
541
		$dnscfg = "";
542

    
543
		if ($dhcpifconf['domain']) {
544
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
545
		}
546

    
547
		if($dhcpifconf['domainsearchlist'] <> "") {
548
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
549
		}
550

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

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

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

    
605
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
606

    
607
// Setup pool options
608
		foreach($all_pools as $poolconf) {
609
			$dhcpdconf .= "	pool {\n";
610
			/* is failover dns setup? */
611
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
612
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
613
				if($poolconf['dnsserver'][1] <> "")
614
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
615
				$dhcpdconf .= ";\n";
616
			}
617

    
618
			/* allow/deny MACs */
619
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
620
			foreach ($mac_allow_list as $mac) {
621
				if (empty($mac))
622
					continue;
623
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
624
			}
625
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
626
			foreach ($mac_deny_list as $mac) {
627
				if (empty($mac))
628
					continue;
629
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
630
			}
631

    
632
			if($poolconf['failover_peerip'] <> "")
633
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
634

    
635
			if (isset($poolconf['denyunknown']))
636
			   $dhcpdconf .= "		deny unknown-clients;\n";
637

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

    
641
			if($dhcpifconf['failover_peerip'] <> "") {
642
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
643
			}
644

    
645
			$pdnscfg = "";
646

    
647
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
648
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
649
			}
650

    
651
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
652
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
653
			}
654

    
655
			if (isset($poolconf['ddnsupdate'])) {
656
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
657
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
658
				$pdnscfg .= "		ddns-update-style interim;\n";
659
			}
660

    
661
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
662
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
663
			}
664
			$dhcpdconf .= "{$pdnscfg}";
665

    
666
			// default-lease-time
667
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
668
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
669

    
670
			// max-lease-time
671
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
672
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
673

    
674
			// netbios-name*
675
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
676
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
677
				$dhcpdconf .= "		option netbios-node-type 8;\n";
678
			}
679

    
680
			// ntp-servers
681
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
682
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
683

    
684
			// tftp-server-name
685
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
686
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
687

    
688
			// ldap-server
689
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
690
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
691

    
692
			// net boot information
693
			if(isset($poolconf['netboot'])) {
694
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
695
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
696
				}
697
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
698
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
699
				}
700
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
701
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
702
				}
703
			}
704
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
705
			$dhcpdconf .= "	}\n\n";
706
		}
707
// End of settings inside pools
708

    
709
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
710
			$routers = $dhcpifconf['gateway'];
711
			$add_routers = true;
712
		} elseif ($dhcpifconf['gateway'] == "none") {
713
			$add_routers = false;
714
		} else {
715
			$routers = $ifcfgip;
716
		}
717
		if($add_routers)
718
			$dhcpdconf .= "	option routers {$routers};\n";
719

    
720
		$dhcpdconf .= <<<EOD
721
$dnscfg
722

    
723
EOD;
724
    		// default-lease-time
725
		if ($dhcpifconf['defaultleasetime'])
726
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
727

    
728
		// max-lease-time
729
		if ($dhcpifconf['maxleasetime'])
730
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
731

    
732
		// netbios-name*
733
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
734
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
735
			$dhcpdconf .= "	option netbios-node-type 8;\n";
736
		}
737

    
738
		// ntp-servers
739
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
740
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
741

    
742
		// tftp-server-name
743
		if ($dhcpifconf['tftp'] <> "")
744
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
745

    
746
		// Handle option, number rowhelper values
747
		$dhcpdconf .= "\n";
748
		if($dhcpifconf['numberoptions']['item']) {
749
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
750
				if(empty($item['type']) || $item['type'] == "text")
751
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
752
				else
753
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
754
			}
755
		}
756

    
757
		// ldap-server
758
		if ($dhcpifconf['ldap'] <> "")
759
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
760

    
761
		// net boot information
762
		if(isset($dhcpifconf['netboot'])) {
763
			if ($dhcpifconf['nextserver'] <> "") {
764
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
765
			}
766
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
767
				$dhcpdconf .= "	if option arch = 00:06 {\n";
768
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
769
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
770
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
771
				$dhcpdconf .= "	} else {\n";
772
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
773
				$dhcpdconf .= "	}\n\n";
774
			} elseif (!empty($dhcpifconf['filename'])) {
775
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
776
			}
777
			if (!empty($dhcpifconf['rootpath'])) {
778
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
779
			}
780
		}
781

    
782
		$dhcpdconf .= <<<EOD
783
}
784

    
785
EOD;
786

    
787
		/* add static mappings */
788
		if (is_array($dhcpifconf['staticmap'])) {
789

    
790
			$i = 0;
791
			foreach ($dhcpifconf['staticmap'] as $sm) {
792
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
793

    
794
                if ($sm['mac'])
795
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
796

    
797
                if ($sm['cid'])
798
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
799

    
800
				if ($sm['ipaddr'])
801
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
802

    
803
				if ($sm['hostname']) {
804
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
805
					$dhhostname = str_replace(".", "_", $dhhostname);
806
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
807
				}
808
				if ($sm['filename'])
809
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
810

    
811
				if ($sm['rootpath'])
812
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
813

    
814
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
815
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
816

    
817
				$smdnscfg = "";
818

    
819
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
820
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
821
				}
822

    
823
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
824
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
825
				}
826

    
827
				if (isset($sm['ddnsupdate'])) {
828
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
829
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
830
					$pdnscfg .= "		ddns-update-style interim;\n";
831
				}
832

    
833
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
834
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
835
				}
836
				$dhcpdconf .= "{$smdnscfg}";
837

    
838
				// default-lease-time
839
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
840
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
841

    
842
				// max-lease-time
843
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
844
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
845

    
846
				// netbios-name*
847
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
848
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
849
					$dhcpdconf .= "	option netbios-node-type 8;\n";
850
				}
851

    
852
				// ntp-servers
853
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
854
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
855

    
856
				// tftp-server-name
857
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
858
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
859

    
860
				$dhcpdconf .= "}\n";
861
				$i++;
862
			}
863
		}
864

    
865
		$dhcpdifs[] = get_real_interface($dhcpif);
866
		if ($newzone['domain-name'])
867
		{
868
			if ($need_ddns_updates)
869
			{
870
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
871
			}
872
			$ddns_zones[] = $newzone;
873
		}
874
	}
875

    
876
	if ($need_ddns_updates) {
877
		$dhcpdconf .= "ddns-update-style interim;\n";
878
		$dhcpdconf .= "update-static-leases on;\n";
879

    
880
		$dhcpdconf .= dhcpdkey($dhcpifconf);
881
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
882
	}
883

    
884
	/* write dhcpd.conf */
885
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
886
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
887
		unset($dhcpdconf);
888
		return 1;
889
	}
890
	unset($dhcpdconf);
891

    
892
	/* create an empty leases database */
893
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
894
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
895

    
896
	/* fire up dhcpd in a chroot */
897
	if (count($dhcpdifs) > 0) {
898
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
899
			join(" ", $dhcpdifs));
900
	}
901

    
902
	if ($g['booting'])
903
		print "done.\n";
904

    
905
	return 0;
906
}
907

    
908
function dhcpdkey($dhcpifconf)
909
{
910
	$dhcpdconf = "";
911
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
912
	{
913
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
914
		$dhcpdconf .= "	algorithm hmac-md5;\n";
915
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
916
		$dhcpdconf .= "}\n";
917
	}
918

    
919
	return $dhcpdconf;
920
}
921

    
922
function dhcpdzones($ddns_zones, $dhcpifconf)
923
{
924
	$dhcpdconf = "";
925

    
926
	if (is_array($ddns_zones)) {
927
		$added_zones = array();
928
		foreach ($ddns_zones as $zone) {
929
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
930
				continue;
931
			$primary = $zone['dns-servers'][0];
932
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
933

    
934
			// Make sure we aren't using any invalid or IPv6 DNS servers.
935
			if (!is_ipaddrv4($primary)) {
936
				if (is_ipaddrv4($secondary)) {
937
					$primary = $secondary;
938
					$secondary = "";
939
				} else {
940
					continue;
941
				}
942
			}
943

    
944
			// We don't need to add zones multiple times.
945
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
946
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
947
				$dhcpdconf .= "	primary {$primary};\n";
948
				if (is_ipaddrv4($secondary))
949
					$dhcpdconf .= "	secondary {$secondary};\n";
950
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
951
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
952
				$dhcpdconf .= "}\n";
953
				$added_zones[] = $zone['domain-name'];
954
			}
955
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
956
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
957
				$dhcpdconf .= "	primary {$primary};\n";
958
				if (is_ipaddrv4($secondary))
959
					$dhcpdconf .= "	secondary {$secondary};\n";
960
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
961
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
962
				$dhcpdconf .= "}\n";
963
				$added_zones[] = $zone['ptr-domain'];
964
			}
965
		}
966
	}
967

    
968
	return $dhcpdconf;
969
}
970

    
971
function services_dhcpdv6_configure($blacklist = array()) {
972
	global $config, $g;
973

    
974
	if($g['services_dhcp_server_enable'] == false)
975
		return;
976

    
977
	if(isset($config['system']['developerspew'])) {
978
		$mt = microtime();
979
		echo "services_dhcpd_configure($if) being called $mt\n";
980
	}
981

    
982
	/* kill any running dhcpd */
983
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
984
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
985
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
986
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
987

    
988
	/* DHCP enabled on any interfaces? */
989
	if (!is_dhcpv6_server_enabled())
990
		return 0;
991

    
992
	if ($g['booting']) {
993
		if ($g['platform'] != "pfSense") {
994
			/* restore the leases, if we have them */
995
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
996
				$dhcprestore = "";
997
				$dhcpreturn = "";
998
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
999
				$dhcprestore = implode(" ", $dhcprestore);
1000
				if($dhcpreturn <> 0) {
1001
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1002
				}
1003
			}
1004
		}
1005
	}
1006

    
1007
	$syscfg = $config['system'];
1008
	if (!is_array($config['dhcpdv6']))
1009
		$config['dhcpdv6'] = array();
1010
	$dhcpdv6cfg = $config['dhcpdv6'];
1011
	$Iflist = get_configured_interface_list();
1012
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1013

    
1014

    
1015
	if ($g['booting'])
1016
		echo "Starting DHCPv6 service...";
1017
	else
1018
		sleep(1);
1019

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

    
1051
				/* set the delegation start to half the current address block */
1052
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1053
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1054

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

    
1059
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1060
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1061
				$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1062
			}
1063
		}
1064
	}
1065

    
1066
	$custoptionsv6 = "";
1067
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1068
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1069
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1070
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1071
			}
1072
		}
1073
	}
1074

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

    
1078
	$dhcpdv6conf = <<<EOD
1079

    
1080
option domain-name "{$syscfg['domain']}";
1081
option ldap-server code 95 = text;
1082
option domain-search-list code 119 = text;
1083
{$custoptionsv6}
1084
default-lease-time 7200;
1085
max-lease-time 86400;
1086
log-facility local7;
1087
one-lease-per-client true;
1088
deny duplicates;
1089
ping-check true;
1090
update-conflict-detection false;
1091

    
1092
EOD;
1093

    
1094
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1095
		$dhcpdv6conf .= "authoritative;\n";
1096

    
1097
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1098
		$dhcpdv6conf .= "always-broadcast on\n";
1099

    
1100
	$dhcpdv6ifs = array();
1101

    
1102
	$dhcpv6num = 0;
1103
	$nsupdate = false;
1104

    
1105
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1106

    
1107
		$ddns_zones = array();
1108

    
1109
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1110

    
1111
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
1112
			continue;
1113
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1114
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1115
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1116

    
1117
		if ($is_olsr_enabled == true) {
1118
			if($dhcpv6ifconf['netmask'])
1119
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1120
		}
1121

    
1122
		$dnscfgv6 = "";
1123

    
1124
		if ($dhcpv6ifconf['domain']) {
1125
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1126
		}
1127

    
1128
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1129
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1130
    	}
1131

    
1132
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1133
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1134
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1135
			}
1136
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1137
			$nsupdate = true;
1138
		}
1139

    
1140
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1141
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1142
		} else if ((isset($config['dnsmasq']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1143
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1144
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1145
			$dns_arrv6 = array();
1146
			foreach($syscfg['dnsserver'] as $dnsserver) {
1147
				if (is_ipaddrv6($dnsserver)) {
1148
					$dns_arrv6[] = $dnsserver;
1149
				}
1150
			}
1151
			if(!empty($dns_arrv6))
1152
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1153
		}
1154

    
1155
		if ($dhcpv6ifconf['domain']) {
1156
			$newzone = array();
1157
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1158
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1159
			$ddns_zones[] = $newzone;
1160
		}
1161

    
1162
		if (is_ipaddrv6($ifcfgipv6)) {
1163
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1164
		} else {
1165
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1166
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1167
		}
1168
		$dhcpdv6conf .= " {\n";
1169

    
1170
		$dhcpdv6conf .= <<<EOD
1171
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1172
$dnscfgv6
1173

    
1174
EOD;
1175

    
1176
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1177
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']}/{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1178
		}
1179
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1180
			$dhcpdv6conf .= "       option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1181
		}
1182
    		// default-lease-time
1183
		if ($dhcpv6ifconf['defaultleasetime'])
1184
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1185

    
1186
		// max-lease-time
1187
		if ($dhcpv6ifconf['maxleasetime'])
1188
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1189

    
1190
		// ntp-servers
1191
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1192
			$ntpservers = array();
1193
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1194
				if(is_ipaddrv6($ntpserver))
1195
					$ntpservers[] = $ntpserver;
1196
			}
1197
			if(count($ntpservers) > 0 )
1198
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1199
		}
1200
		// tftp-server-name
1201
		/* Needs ISC DHCPD support
1202
		 if ($dhcpv6ifconf['tftp'] <> "")
1203
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1204
		*/
1205

    
1206
		// Handle option, number rowhelper values
1207
		$dhcpdv6conf .= "\n";
1208
		if ($dhcpv6ifconf['numberoptions']['item']) {
1209
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1210
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1211
			}
1212
		}
1213

    
1214
		// ldap-server
1215
		if ($dhcpv6ifconf['ldap'] <> "")
1216
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1217

    
1218
		// net boot information
1219
		if(isset($dhcpv6ifconf['netboot'])) {
1220
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1221
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1222
			}
1223
		}
1224

    
1225
		$dhcpdv6conf .= "}\n";
1226

    
1227
		/* add static mappings */
1228
		/* Needs to use DUID */
1229
		if (is_array($dhcpv6ifconf['staticmap'])) {
1230
			$i = 0;
1231
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1232
				$dhcpdv6conf .= <<<EOD
1233
host s_{$dhcpv6if}_{$i} {
1234
	host-identifier option dhcp6.client-id {$sm['duid']};
1235

    
1236
EOD;
1237
				if ($sm['ipaddrv6'])
1238
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1239

    
1240
				if ($sm['hostname']) {
1241
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1242
					$dhhostname = str_replace(".", "_", $dhhostname);
1243
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1244
				}
1245
				if ($sm['filename'])
1246
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1247

    
1248
				if ($sm['rootpath'])
1249
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1250

    
1251
				$dhcpdv6conf .= "}\n";
1252
				$i++;
1253
			}
1254
		}
1255

    
1256
		if ($dhcpv6ifconf['domain'])
1257
		{
1258
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1259
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1260
		}
1261

    
1262
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged") {
1263
			if(preg_match("/poes/si", $dhcpv6if)) {
1264
				/* magic here */
1265
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1266
			} else {
1267
				$realif = get_real_interface($dhcpv6if, "inet6");
1268
				if (stristr("$realif", "bridge")) {
1269
					$mac = get_interface_mac($realif);
1270
					$v6address = generate_ipv6_from_mac($mac);
1271
					/* Create link local address for bridges */
1272
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1273
				}
1274
				$realif = escapeshellcmd($realif);
1275
				$dhcpdv6ifs[] = $realif;
1276
			}
1277
		}
1278
	}
1279

    
1280
	if ($nsupdate)
1281
	{
1282
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1283
	}
1284
	else
1285
	{
1286
		$dhcpdv6conf .= "ddns-update-style none;\n";
1287
	}
1288

    
1289
	/* write dhcpdv6.conf */
1290
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1291
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1292
		if ($g['booting'])
1293
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1294
		unset($dhcpdv6conf);
1295
		return 1;
1296
	}
1297
	unset($dhcpdv6conf);
1298

    
1299
	/* create an empty leases v6 database */
1300
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1301
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1302

    
1303
	/* fire up dhcpd in a chroot */
1304
	if (count($dhcpdv6ifs) > 0) {
1305
		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 " .
1306
			join(" ", $dhcpdv6ifs));
1307
		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");
1308
	}
1309
	if ($g['booting'])
1310
		print gettext("done.") . "\n";
1311

    
1312
	return 0;
1313
}
1314

    
1315
function services_igmpproxy_configure() {
1316
        global $config, $g;
1317

    
1318
        /* kill any running igmpproxy */
1319
        killbyname("igmpproxy");
1320

    
1321
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1322
		return 1;
1323

    
1324
        $iflist = get_configured_interface_list();
1325

    
1326
        $igmpconf = <<<EOD
1327

    
1328
##------------------------------------------------------
1329
## Enable Quickleave mode (Sends Leave instantly)
1330
##------------------------------------------------------
1331
quickleave
1332

    
1333
EOD;
1334

    
1335
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1336
                unset($iflist[$igmpcf['ifname']]);
1337
                $realif = get_real_interface($igmpcf['ifname']);
1338
                if (empty($igmpcf['threshold']))
1339
                        $threshld = 1;
1340
                else
1341
                        $threshld = $igmpcf['threshold'];
1342
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1343

    
1344
                if ($igmpcf['address'] <> "") {
1345
                        $item = explode(" ", $igmpcf['address']);
1346
                        foreach($item as $iww)
1347
                                $igmpconf .= "altnet {$iww}\n";
1348
                }
1349
                $igmpconf .= "\n";
1350
        }
1351
        foreach ($iflist as $ifn) {
1352
                $realif = get_real_interface($ifn);
1353
                $igmpconf .= "phyint {$realif} disabled\n";
1354
        }
1355
	$igmpconf .= "\n";
1356

    
1357
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1358
        if (!$igmpfl) {
1359
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1360
                return;
1361
        }
1362
        fwrite($igmpfl, $igmpconf);
1363
        fclose($igmpfl);
1364
	unset($igmpconf);
1365

    
1366
	/* NOTE: -d 4 means everything LOG_WARNING and smaller */
1367
        mwexec("/usr/local/sbin/igmpproxy -d 4 -c {$g['tmp_path']}/igmpproxy.conf");
1368
        log_error(gettext("Started IGMP proxy service."));
1369

    
1370
        return 0;
1371
}
1372

    
1373
function services_dhcrelay_configure() {
1374
	global $config, $g;
1375
	if ($g['platform'] == 'jail')
1376
		return;
1377
	if(isset($config['system']['developerspew'])) {
1378
		$mt = microtime();
1379
		echo "services_dhcrelay_configure() being called $mt\n";
1380
	}
1381

    
1382
	/* kill any running dhcrelay */
1383
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1384

    
1385
	$dhcrelaycfg =& $config['dhcrelay'];
1386

    
1387
	/* DHCPRelay enabled on any interfaces? */
1388
	if (!isset($dhcrelaycfg['enable']))
1389
		return 0;
1390

    
1391
	if ($g['booting'])
1392
		echo gettext("Starting DHCP relay service...");
1393
	else
1394
		sleep(1);
1395

    
1396
	$iflist = get_configured_interface_list();
1397

    
1398
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1399
	foreach ($dhcifaces as $dhcrelayif) {
1400
		if (!isset($iflist[$dhcrelayif]) ||
1401
			link_interface_to_bridge($dhcrelayif))
1402
			continue;
1403

    
1404
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1405
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1406
	}
1407

    
1408
	/*
1409
	 * In order for the relay to work, it needs to be active
1410
	 * on the interface in which the destination server sits.
1411
	 */
1412
	$srvips = explode(",", $dhcrelaycfg['server']);
1413
	foreach ($srvips as $srcidx => $srvip) {
1414
		unset($destif);
1415
		foreach ($iflist as $ifname) {
1416
			$subnet = get_interface_ip($ifname);
1417
			if (!is_ipaddr($subnet))
1418
				continue;
1419
			$subnet .=  "/" . get_interface_subnet($ifname);
1420
			if (ip_in_subnet($srvip, $subnet)) {
1421
				$destif = get_real_interface($ifname);
1422
				break;
1423
			}
1424
		}
1425
		if (!isset($destif)) {
1426
			foreach (get_staticroutes() as $rtent) {
1427
				if (ip_in_subnet($srvip, $rtent['network'])) {
1428
					$a_gateways = return_gateways_array(true);
1429
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1430
					break;
1431
				}
1432
			}
1433
		}
1434

    
1435
		if (!isset($destif)) {
1436
			/* Create a array from the existing route table */
1437
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1438
        		array_shift($route_str);
1439
        		array_shift($route_str);
1440
        		array_shift($route_str);
1441
        		array_shift($route_str);
1442
        		$route_arr = array();
1443
        		foreach($route_str as $routeline) {
1444
				$items = preg_split("/[ ]+/i", $routeline);
1445
				if (is_subnetv4($items[0])) {
1446
					$subnet = $items[0];
1447
				} elseif (is_ipaddrv4($items[0])) {
1448
					$subnet = "{$items[0]}/32";
1449
				} else {
1450
					// Not a subnet or IP address, skip to the next line.
1451
					continue;
1452
				}
1453
				if (ip_in_subnet($srvip, $subnet)) {
1454
					$destif = trim($items[6]);
1455
					break;
1456
				}
1457
			}
1458
		}
1459

    
1460
		if (!isset($destif)) {
1461
			if (is_array($config['gateways']['gateway_item'])) {
1462
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1463
					if (isset($gateway['defaultgw'])) {
1464
						$destif = get_real_interface($gateway['interface']);
1465
						break;
1466
					}
1467
				}
1468
			} else
1469
				$destif = get_real_interface("wan");
1470
		}
1471

    
1472
		if (!empty($destif))
1473
			$dhcrelayifs[] = $destif;
1474
	}
1475
	$dhcrelayifs = array_unique($dhcrelayifs);
1476

    
1477
	/* fire up dhcrelay */
1478
	if (empty($dhcrelayifs)) {
1479
		log_error("No suitable interface found for running dhcrelay!");
1480
		return; /* XXX */
1481
	}
1482

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

    
1485
	if (isset($dhcrelaycfg['agentoption']))
1486
		$cmd .=  " -a -m replace";
1487

    
1488
	$cmd .= " " . implode(" ", $srvips);
1489
	mwexec($cmd);
1490
	unset($cmd);
1491

    
1492
	return 0;
1493
}
1494

    
1495
function services_dhcrelay6_configure() {
1496
	global $config, $g;
1497
	if ($g['platform'] == 'jail')
1498
		return;
1499
	if(isset($config['system']['developerspew'])) {
1500
		$mt = microtime();
1501
		echo "services_dhcrelay6_configure() being called $mt\n";
1502
	}
1503

    
1504
	/* kill any running dhcrelay */
1505
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1506

    
1507
	$dhcrelaycfg =& $config['dhcrelay6'];
1508

    
1509
	/* DHCPv6 Relay enabled on any interfaces? */
1510
	if (!isset($dhcrelaycfg['enable']))
1511
		return 0;
1512

    
1513
	if ($g['booting'])
1514
		echo gettext("Starting DHCPv6 relay service...");
1515
	else
1516
		sleep(1);
1517

    
1518
	$iflist = get_configured_interface_list();
1519

    
1520
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1521
	foreach ($dhcifaces as $dhcrelayif) {
1522
		if (!isset($iflist[$dhcrelayif]) ||
1523
			link_interface_to_bridge($dhcrelayif))
1524
			continue;
1525

    
1526
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1527
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1528
	}
1529
	$dhcrelayifs = array_unique($dhcrelayifs);
1530

    
1531
	/*
1532
	 * In order for the relay to work, it needs to be active
1533
	 * on the interface in which the destination server sits.
1534
	 */
1535
	$srvips = explode(",", $dhcrelaycfg['server']);
1536
        $srvifaces = array();
1537
	foreach ($srvips as $srcidx => $srvip) {
1538
		unset($destif);
1539
		foreach ($iflist as $ifname) {
1540
			$subnet = get_interface_ipv6($ifname);
1541
			if (!is_ipaddrv6($subnet))
1542
				continue;
1543
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1544
			if (ip_in_subnet($srvip, $subnet)) {
1545
				$destif = get_real_interface($ifname);
1546
				break;
1547
			}
1548
		}
1549
		if (!isset($destif)) {
1550
			if (is_array($config['staticroutes']['route'])) {
1551
				foreach ($config['staticroutes']['route'] as $rtent) {
1552
					if (ip_in_subnet($srvip, $rtent['network'])) {
1553
						$a_gateways = return_gateways_array(true);
1554
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1555
						break;
1556
					}
1557
				}
1558
			}
1559
		}
1560

    
1561
		if (!isset($destif)) {
1562
			/* Create a array from the existing route table */
1563
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1564
        		array_shift($route_str);
1565
        		array_shift($route_str);
1566
        		array_shift($route_str);
1567
        		array_shift($route_str);
1568
        		$route_arr = array();
1569
        		foreach($route_str as $routeline) {
1570
                		$items = preg_split("/[ ]+/i", $routeline);
1571
				if (ip_in_subnet($srvip, $items[0])) {
1572
					$destif = trim($items[6]);
1573
					break;
1574
				}
1575
        		}
1576
		}
1577

    
1578
		if (!isset($destif)) {
1579
			if (is_array($config['gateways']['gateway_item'])) {
1580
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1581
					if (isset($gateway['defaultgw'])) {
1582
						$destif = $gateway['interface'];
1583
						break;
1584
					}
1585
				}
1586
			} else
1587
				$destif = get_real_interface("wan");
1588
		}
1589

    
1590
		if (!empty($destif)) {
1591
			$srvifaces[] = "{$srvip}%{$destif}";
1592
		}
1593
	}
1594

    
1595
	/* fire up dhcrelay */
1596
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1597
		log_error("No suitable interface found for running dhcrelay -6!");
1598
		return; /* XXX */
1599
	}
1600

    
1601
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1602
	foreach ($dhcrelayifs as $dhcrelayif) {
1603
		$cmd .= " -l {$dhcrelayif}";
1604
	}
1605
	foreach ($srvifaces as $srviface) {
1606
		$cmd .= " -u \"{$srviface}\"";
1607
	}
1608
	mwexec($cmd);
1609
	unset($cmd);
1610

    
1611
	return 0;
1612
}
1613

    
1614
function services_dyndns_configure_client($conf) {
1615

    
1616
	if (!isset($conf['enable']))
1617
		return;
1618

    
1619
	/* load up the dyndns.class */
1620
	require_once("dyndns.class");
1621

    
1622
	$dns = new updatedns($dnsService = $conf['type'],
1623
		$dnsHost = $conf['host'],
1624
		$dnsUser = $conf['username'],
1625
		$dnsPass = $conf['password'],
1626
		$dnsWilcard = $conf['wildcard'],
1627
		$dnsMX = $conf['mx'],
1628
		$dnsIf = "{$conf['interface']}",
1629
		$dnsBackMX = NULL,
1630
		$dnsServer = NULL,
1631
		$dnsPort = NULL,
1632
		$dnsUpdateURL = "{$conf['updateurl']}",
1633
		$forceUpdate = $conf['force'],
1634
		$dnsZoneID=$conf['zoneid'],
1635
		$dnsTTL=$conf['ttl'],
1636
		$dnsResultMatch = "{$conf['resultmatch']}",
1637
		$dnsRequestIf = "{$conf['requestif']}",
1638
		$dnsID = "{$conf['id']}",
1639
		$dnsVerboseLog = $conf['verboselog'],
1640
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1641
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1642
}
1643

    
1644
function services_dyndns_configure($int = "") {
1645
	global $config, $g;
1646
	if(isset($config['system']['developerspew'])) {
1647
		$mt = microtime();
1648
		echo "services_dyndns_configure() being called $mt\n";
1649
	}
1650

    
1651
	$dyndnscfg = $config['dyndnses']['dyndns'];
1652
	$gwgroups = return_gateway_groups_array();
1653
	if (is_array($dyndnscfg)) {
1654
		if ($g['booting'])
1655
			echo gettext("Starting DynDNS clients...");
1656

    
1657
		foreach ($dyndnscfg as $dyndns) {
1658
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1659
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1660
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1661
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1662
				services_dyndns_configure_client($dyndns);
1663
				sleep(1);
1664
			}
1665
		}
1666

    
1667
		if ($g['booting'])
1668
			echo gettext("done.") . "\n";
1669
	}
1670

    
1671
	return 0;
1672
}
1673

    
1674
function dyndnsCheckIP($int) {
1675
	global $config;
1676
	$ip_address = get_interface_ip($int);
1677
	if (is_private_ip($ip_address)) {
1678
		$gateways_status = return_gateways_status(true);
1679
		// If the gateway for this interface is down, then the external check cannot work.
1680
		// Avoid the long wait for the external check to timeout.
1681
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1682
			return "down";
1683
		$hosttocheck = "http://checkip.dyndns.org";
1684
		$ip_ch = curl_init($hosttocheck);
1685
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1686
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1687
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1688
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1689
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1690
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1691
		$ip_result_page = curl_exec($ip_ch);
1692
		curl_close($ip_ch);
1693
		$ip_result_decoded = urldecode($ip_result_page);
1694
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1695
		$ip_address = trim($matches[1]);
1696
	}
1697
	return $ip_address;
1698
}
1699

    
1700
function services_dnsmasq_configure() {
1701
	global $config, $g;
1702
	$return = 0;
1703

    
1704
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1705
	$standard_args = array(
1706
		"dns-forward-max" => "--dns-forward-max=5000",
1707
		"cache-size" => "--cache-size=10000",
1708
		"local-ttl" => "--local-ttl=1"
1709
	);
1710

    
1711

    
1712
	if(isset($config['system']['developerspew'])) {
1713
		$mt = microtime();
1714
		echo "services_dnsmasq_configure() being called $mt\n";
1715
	}
1716

    
1717
	/* kill any running dnsmasq */
1718
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1719
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1720

    
1721
	if (isset($config['dnsmasq']['enable'])) {
1722

    
1723
		if ($g['booting'])
1724
			echo gettext("Starting DNS forwarder...");
1725
		else
1726
			sleep(1);
1727

    
1728
		$args = "";
1729

    
1730
		if (isset($config['dnsmasq']['regdhcp'])) {
1731
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1732
		}
1733

    
1734
		/* Setup listen port, if non-default */
1735
		if (is_port($config['dnsmasq']['port']))
1736
			$args .= " --port={$config['dnsmasq']['port']} ";
1737

    
1738
		$listen_addresses = "";
1739
		if(isset($config['dnsmasq']['interface'])) {
1740
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1741
			foreach ($interfaces as $interface) {
1742
				if (is_ipaddrv4($interface)) {
1743
					$listen_addresses .= " --listen-address={$interface} ";
1744
				} else if (is_ipaddrv6($interface)) {
1745
					/*
1746
					 * XXX: Since dnsmasq does not support link-local address
1747
					 * with scope specified. These checks are being done.
1748
					 */
1749
					if (is_linklocal($interface) && strstr($interface, "%")) {
1750
						$tmpaddrll6 = explode("%", $interface);
1751
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1752
					} else 
1753
						$listen_addresses .= " --listen-address={$interface} ";
1754
				} else {
1755
					$if = get_real_interface($interface);
1756
					if (does_interface_exist($if)) {
1757
						$laddr = find_interface_ip($if);
1758
						if (is_ipaddrv4($laddr))
1759
							$listen_addresses .= " --listen-address={$laddr} ";
1760
						$laddr6 = find_interface_ipv6($if);
1761
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1762
							/*
1763
							 * XXX: Since dnsmasq does not support link-local address
1764
							 * with scope specified. These checks are being done.
1765
							 */
1766
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1767
								$tmpaddrll6 = explode("%", $laddr6);
1768
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1769
							} else
1770
								$listen_addresses .= " --listen-address={$laddr6} ";
1771
						}
1772
					}
1773
				}
1774
			}
1775
			if (!empty($listen_addresses)) {
1776
				$args .= " {$listen_addresses} ";
1777
				if (isset($config['dnsmasq']['strictbind']))
1778
					$args .= " --bind-interfaces ";
1779
			}
1780
		}
1781

    
1782
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1783
		/* If any of these are duplicated by a user-specified domain override (e.g. 10.in-addr.arpa) then */
1784
		/* the user-specified entry made later on the command line below will be the one that is effective. */
1785
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1786
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1787
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1788
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1789
			$args .= " --server=/10.in-addr.arpa/ ";
1790
			$args .= " --server=/168.192.in-addr.arpa/ ";
1791
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1792
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1793
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1794
			}
1795
		}
1796

    
1797
		/* Setup forwarded domains */
1798
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1799
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1800
				if ($override['ip'] == "!")
1801
					$override[ip] = "";
1802
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1803
			}
1804
		}
1805

    
1806
		/* Allow DNS Rebind for forwarded domains */
1807
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1808
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1809
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1810
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1811
				}
1812
			}
1813
		}
1814

    
1815
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1816
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1817

    
1818
		if (isset($config['dnsmasq']['strict_order'])) {
1819
			$args .= " --strict-order ";
1820
		}
1821

    
1822
		if (isset($config['dnsmasq']['domain_needed'])) {
1823
			$args .= " --domain-needed ";
1824
		}
1825

    
1826
		if ($config['dnsmasq']['custom_options'])
1827
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1828
				$args .= " " . escapeshellarg("--{$c}");
1829
				$p = explode('=', $c);
1830
				if (array_key_exists($p[0], $standard_args))
1831
					unset($standard_args[$p[0]]);
1832
			}
1833
		$args .= ' ' . implode(' ', array_values($standard_args));
1834

    
1835
		/* run dnsmasq */
1836
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1837
		//log_error("dnsmasq command: {$cmd}");
1838
		mwexec_bg($cmd);
1839
		unset($args);
1840

    
1841
		if ($g['booting'])
1842
			echo gettext("done.") . "\n";
1843
	}
1844

    
1845
	if (!$g['booting']) {
1846
		if(services_dhcpd_configure()!=0)
1847
			$return = 1;
1848
	}
1849

    
1850
	return $return;
1851
}
1852

    
1853
function services_unbound_configure() {
1854
	global $config, $g;
1855
	$return = 0;
1856

    
1857
	if (isset($config['system']['developerspew'])) {
1858
		$mt = microtime();
1859
		echo "services_unbound_configure() being called $mt\n";
1860
	}
1861

    
1862
	// kill any running Unbound instance
1863
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1864
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1865

    
1866
	if (isset($config['unbound']['enable'])) {
1867
		if ($g['booting'])
1868
			echo gettext("Starting DNS Resolver...");
1869
		else
1870
			sleep(1);
1871

    
1872
		require_once('/etc/inc/unbound.inc');
1873
		sync_unbound_service();
1874
		if ($g['booting'])
1875
			echo gettext("done.") . "\n";
1876
	}
1877

    
1878
	if (!$g['booting']) {
1879
		if (services_dhcpd_configure()!=0)
1880
			$return = 1;
1881
	}
1882

    
1883
	return $return;
1884
}
1885

    
1886
function services_snmpd_configure() {
1887
	global $config, $g;
1888
	if(isset($config['system']['developerspew'])) {
1889
		$mt = microtime();
1890
		echo "services_snmpd_configure() being called $mt\n";
1891
	}
1892

    
1893
	/* kill any running snmpd */
1894
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1895
	sleep(2);
1896
	if(is_process_running("bsnmpd"))
1897
		mwexec("/usr/bin/killall bsnmpd", true);
1898

    
1899
	if (isset($config['snmpd']['enable'])) {
1900

    
1901
		if ($g['booting'])
1902
			echo gettext("Starting SNMP daemon... ");
1903

    
1904
		/* generate snmpd.conf */
1905
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1906
		if (!$fd) {
1907
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1908
			return 1;
1909
		}
1910

    
1911

    
1912
		$snmpdconf = <<<EOD
1913
location := "{$config['snmpd']['syslocation']}"
1914
contact := "{$config['snmpd']['syscontact']}"
1915
read := "{$config['snmpd']['rocommunity']}"
1916

    
1917
EOD;
1918

    
1919
/* No docs on what write strings do there for disable for now.
1920
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1921
		    $snmpdconf .= <<<EOD
1922
# write string
1923
write := "{$config['snmpd']['rwcommunity']}"
1924

    
1925
EOD;
1926
		}
1927
*/
1928

    
1929

    
1930
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1931
		    $snmpdconf .= <<<EOD
1932
# SNMP Trap support.
1933
traphost := {$config['snmpd']['trapserver']}
1934
trapport := {$config['snmpd']['trapserverport']}
1935
trap := "{$config['snmpd']['trapstring']}"
1936

    
1937

    
1938
EOD;
1939
		}
1940

    
1941
		$version = trim(file_get_contents('/etc/version'));
1942
		$platform = trim(file_get_contents('/etc/platform'));
1943
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1944
			$platform = $g['product_name'];
1945
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1946
			" {$version} {$platform} " . php_uname("s") .
1947
			" " . php_uname("r") . " " . php_uname("m");
1948

    
1949
		$snmpdconf .= <<<EOD
1950
system := 1     # pfSense
1951
%snmpd
1952
sysDescr			= "{$sysDescr}"
1953
begemotSnmpdDebugDumpPdus       = 2
1954
begemotSnmpdDebugSyslogPri      = 7
1955
begemotSnmpdCommunityString.0.1 = $(read)
1956

    
1957
EOD;
1958

    
1959
/* No docs on what write strings do there for disable for now.
1960
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1961
		    $snmpdconf .= <<<EOD
1962
begemotSnmpdCommunityString.0.2 = $(write)
1963

    
1964
EOD;
1965
		}
1966
*/
1967

    
1968

    
1969
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1970
		    $snmpdconf .= <<<EOD
1971
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1972
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1973
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1974

    
1975
EOD;
1976
		}
1977

    
1978

    
1979
		$snmpdconf .= <<<EOD
1980
begemotSnmpdCommunityDisable    = 1
1981

    
1982
EOD;
1983

    
1984
		if (isset($config['snmpd']['bindlan'])) {
1985
			$config['snmpd']['bindip'] = 'lan';
1986
			unset($config['snmpd']['bindlan']);
1987
		}
1988
		$bind_to_ip = "0.0.0.0";
1989
		if(isset($config['snmpd']['bindip'])) {
1990
			if (is_ipaddr($config['snmpd']['bindip'])) {
1991
				$bind_to_ip = $config['snmpd']['bindip'];
1992
			} else {
1993
				$if = get_real_interface($config['snmpd']['bindip']);
1994
				if (does_interface_exist($if))
1995
					$bind_to_ip = find_interface_ip($if);
1996
			}
1997
		}
1998

    
1999
		if(is_port( $config['snmpd']['pollport'] )) {
2000
		    $snmpdconf .= <<<EOD
2001
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2002

    
2003
EOD;
2004

    
2005
		}
2006

    
2007
		$snmpdconf .= <<<EOD
2008
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2009
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2010

    
2011
# These are bsnmp macros not php vars.
2012
sysContact      = $(contact)
2013
sysLocation     = $(location)
2014
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2015

    
2016
snmpEnableAuthenTraps = 2
2017

    
2018
EOD;
2019

    
2020
		if (is_array( $config['snmpd']['modules'] )) {
2021
		    if(isset($config['snmpd']['modules']['mibii'])) {
2022
			$snmpdconf .= <<<EOD
2023
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2024

    
2025
EOD;
2026
		    }
2027

    
2028
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2029
			$snmpdconf .= <<<EOD
2030
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2031
%netgraph
2032
begemotNgControlNodeName = "snmpd"
2033

    
2034
EOD;
2035
		    }
2036

    
2037
		    if(isset($config['snmpd']['modules']['pf'])) {
2038
			$snmpdconf .= <<<EOD
2039
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2040

    
2041
EOD;
2042
		    }
2043

    
2044
		    if(isset($config['snmpd']['modules']['hostres'])) {
2045
			$snmpdconf .= <<<EOD
2046
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2047

    
2048
EOD;
2049
		    }
2050
		    if(isset($config['snmpd']['modules']['bridge'])) {
2051
			$snmpdconf .= <<<EOD
2052
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2053
# config must end with blank line
2054

    
2055
EOD;
2056
		    }
2057
			if(isset($config['snmpd']['modules']['ucd'])) {
2058
				$snmpdconf .= <<<EOD
2059
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2060

    
2061
EOD;
2062
			}
2063
			if(isset($config['snmpd']['modules']['regex'])) {
2064
				$snmpdconf .= <<<EOD
2065
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2066

    
2067
EOD;
2068
			}
2069
		}
2070

    
2071
		fwrite($fd, $snmpdconf);
2072
		fclose($fd);
2073
		unset($snmpdconf);
2074

    
2075
		if (isset($config['snmpd']['bindlan'])) {
2076
			$bindlan = "";
2077
		}
2078

    
2079
		/* run bsnmpd */
2080
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2081
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2082

    
2083
		if ($g['booting'])
2084
			echo gettext("done.") . "\n";
2085
	}
2086

    
2087
	return 0;
2088
}
2089

    
2090
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2091
	global $config, $g;
2092
	if(isset($config['system']['developerspew'])) {
2093
		$mt = microtime();
2094
		echo "services_dnsupdate_process() being called $mt\n";
2095
	}
2096

    
2097
	/* Dynamic DNS updating active? */
2098
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2099
		$notify_text = "";
2100
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2101
			if (!isset($dnsupdate['enable']))
2102
				continue;
2103
			if (!empty($int) && $int != $dnsupdate['interface'])
2104
				continue;
2105
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2106
				continue;
2107

    
2108
			/* determine interface name */
2109
			$if = get_real_interface($dnsupdate['interface']);
2110
			
2111
			if (isset($dnsupdate['usepublicip']))
2112
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2113
                        else
2114
                                $wanip = get_interface_ip($dnsupdate['interface']);
2115
			
2116
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2117
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2118
			$currentTime = time();
2119

    
2120
			if ($wanip || $wanipv6) {
2121
				$keyname = $dnsupdate['keyname'];
2122
				/* trailing dot */
2123
				if (substr($keyname, -1) != ".")
2124
					$keyname .= ".";
2125

    
2126
				$hostname = $dnsupdate['host'];
2127
				/* trailing dot */
2128
				if (substr($hostname, -1) != ".")
2129
					$hostname .= ".";
2130

    
2131
				/* write private key file
2132
				   this is dumb - public and private keys are the same for HMAC-MD5,
2133
				   but nsupdate insists on having both */
2134
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2135
				$privkey = <<<EOD
2136
Private-key-format: v1.2
2137
Algorithm: 157 (HMAC)
2138
Key: {$dnsupdate['keydata']}
2139

    
2140
EOD;
2141
				fwrite($fd, $privkey);
2142
				fclose($fd);
2143

    
2144
				/* write public key file */
2145
				if ($dnsupdate['keytype'] == "zone") {
2146
					$flags = 257;
2147
					$proto = 3;
2148
				} else if ($dnsupdate['keytype'] == "host") {
2149
					$flags = 513;
2150
					$proto = 3;
2151
				} else if ($dnsupdate['keytype'] == "user") {
2152
					$flags = 0;
2153
					$proto = 2;
2154
				}
2155

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

    
2160
				/* generate update instructions */
2161
				$upinst = "";
2162
				if (!empty($dnsupdate['server']))
2163
					$upinst .= "server {$dnsupdate['server']}\n";
2164

    
2165
				if (file_exists($cacheFile)) {
2166
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2167
				}
2168
				if (file_exists("{$cacheFile}.ipv6")) {
2169
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2170
				}
2171

    
2172
				// 25 Days
2173
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2174
				$need_update = false;
2175

    
2176
				conf_mount_rw();
2177
				/* Update IPv4 if we have it. */
2178
				if (is_ipaddrv4($wanip)) {
2179
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2180
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2181
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2182
						$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";
2183
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2184
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2185
						$need_update = true;
2186
					} else {
2187
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2188
					}
2189
				} else
2190
					@unlink($cacheFile);
2191

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

    
2208
				$upinst .= "\n";	/* mind that trailing newline! */
2209

    
2210
				if ($need_update) {
2211
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2212
					unset($upinst);
2213
					/* invoke nsupdate */
2214
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2215
					if (isset($dnsupdate['usetcp']))
2216
						$cmd .= " -v";
2217
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2218
					mwexec_bg($cmd);
2219
					unset($cmd);
2220
				}
2221
			}
2222
		}
2223
		if (!empty($notify_text)) {
2224
			notify_all_remote($notify_text);
2225
		}
2226
	}
2227

    
2228
	return 0;
2229
}
2230

    
2231
/* configure cron service */
2232
function configure_cron() {
2233
	global $g, $config;
2234

    
2235
	conf_mount_rw();
2236
	/* preserve existing crontab entries */
2237
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2238

    
2239
	for ($i = 0; $i < count($crontab_contents); $i++) {
2240
		$cron_item =& $crontab_contents[$i];
2241
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2242
			array_splice($crontab_contents, $i - 1);
2243
			break;
2244
		}
2245
	}
2246
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2247

    
2248

    
2249
	if (is_array($config['cron']['item'])) {
2250
		$crontab_contents .= "#\n";
2251
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2252
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2253
		$crontab_contents .= "#\n";
2254

    
2255
		foreach ($config['cron']['item'] as $item) {
2256
			$crontab_contents .= "\n{$item['minute']}\t";
2257
			$crontab_contents .= "{$item['hour']}\t";
2258
			$crontab_contents .= "{$item['mday']}\t";
2259
			$crontab_contents .= "{$item['month']}\t";
2260
			$crontab_contents .= "{$item['wday']}\t";
2261
			$crontab_contents .= "{$item['who']}\t";
2262
			$crontab_contents .= "{$item['command']}";
2263
		}
2264

    
2265
		$crontab_contents .= "\n#\n";
2266
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2267
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2268
		$crontab_contents .= "#\n\n";
2269
	}
2270

    
2271
	/* please maintain the newline at the end of file */
2272
	file_put_contents("/etc/crontab", $crontab_contents);
2273
	unset($crontab_contents);
2274

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

    
2278
	conf_mount_ro();
2279
}
2280

    
2281
function upnp_action ($action) {
2282
	global $g, $config;
2283
	switch($action) {
2284
		case "start":
2285
			if (file_exists('/var/etc/miniupnpd.conf')) {
2286
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2287
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2288
			}
2289
			break;
2290
		case "stop":
2291
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2292
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2293
				mwexec('killall miniupnpd 2>/dev/null', true);
2294
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2295
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2296
			break;
2297
		case "restart":
2298
			upnp_action('stop');
2299
			upnp_action('start');
2300
			break;
2301
	}
2302
}
2303

    
2304
function upnp_start() {
2305
	global $config;
2306

    
2307
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2308
		return;
2309

    
2310
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2311
		echo gettext("Starting UPnP service... ");
2312
		require_once('/usr/local/pkg/miniupnpd.inc');
2313
		sync_package_miniupnpd();
2314
		echo "done.\n";
2315
	}
2316
}
2317

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

    
2321
	$is_installed = false;
2322

    
2323
	if (!is_array($config['cron']))
2324
		$config['cron'] = array();
2325
	if (!is_array($config['cron']['item']))
2326
		$config['cron']['item'] = array();
2327

    
2328
	$x=0;
2329
	foreach($config['cron']['item'] as $item) {
2330
		if(strstr($item['command'], $command)) {
2331
			$is_installed = true;
2332
			break;
2333
		}
2334
		$x++;
2335
	}
2336

    
2337
	if($active) {
2338
		$cron_item = array();
2339
		$cron_item['minute'] = $minute;
2340
		$cron_item['hour'] = $hour;
2341
		$cron_item['mday'] = $monthday;
2342
		$cron_item['month'] = $month;
2343
		$cron_item['wday'] = $weekday;
2344
		$cron_item['who'] = $who;
2345
		$cron_item['command'] = $command;
2346
		if(!$is_installed) {
2347
			$config['cron']['item'][] = $cron_item;
2348
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2349
		} else {
2350
			$config['cron']['item'][$x] = $cron_item;
2351
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2352
		}
2353
	} else {
2354
		if($is_installed == true) {
2355
			unset($config['cron']['item'][$x]);
2356
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2357
		}
2358
	}
2359
	configure_cron();
2360
}
2361

    
2362
?>
(50-50/68)