Projet

Général

Profil

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

univnautes / etc / inc / services.inc @ 071f6059

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 IP's defined!"));
484
			}
485
			if($skew > 10) {
486
				$type = "secondary";
487
				$dhcpdconf_pri  = "mclt 600;\n";
488
				$my_port = "520";
489
				$peer_port = "519";
490
			} else {
491
				$my_port = "519";
492
				$peer_port = "520";
493
				$type = "primary";
494
				$dhcpdconf_pri  = "split 128;\n";
495
				$dhcpdconf_pri .= "  mclt 600;\n";
496
			}
497

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

    
512
EOPP;
513
			}
514
		}
515
	}
516

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

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

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

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

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

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

    
542
		$dnscfg = "";
543

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

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

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

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

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

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

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

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

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

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

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

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

    
646
			$pdnscfg = "";
647

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
786
EOD;
787

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

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

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

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

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

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

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

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

    
818
				$smdnscfg = "";
819

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
906
	return 0;
907
}
908

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

    
920
	return $dhcpdconf;
921
}
922

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

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

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

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

    
969
	return $dhcpdconf;
970
}
971

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

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

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

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

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

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

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

    
1015

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

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

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

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

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

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

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

    
1079
	$dhcpdv6conf = <<<EOD
1080

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

    
1093
EOD;
1094

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

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

    
1101
	$dhcpdv6ifs = array();
1102

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

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

    
1108
		$ddns_zones = array();
1109

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

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

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

    
1123
		$dnscfgv6 = "";
1124

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

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

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

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

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

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

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

    
1175
EOD;
1176

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1313
	return 0;
1314
}
1315

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

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

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

    
1325
        $iflist = get_configured_interface_list();
1326

    
1327
        $igmpconf = <<<EOD
1328

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

    
1334
EOD;
1335

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

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

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

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

    
1371
        return 0;
1372
}
1373

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

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

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

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

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

    
1397
	$iflist = get_configured_interface_list();
1398

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

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

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

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

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

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

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

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

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

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

    
1493
	return 0;
1494
}
1495

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

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

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

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

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

    
1519
	$iflist = get_configured_interface_list();
1520

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

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

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

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

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

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

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

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

    
1612
	return 0;
1613
}
1614

    
1615
function services_dyndns_configure_client($conf) {
1616

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

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

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

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

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

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

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

    
1672
	return 0;
1673
}
1674

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

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

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

    
1712

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

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

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

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

    
1729
		$args = "";
1730

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1851
	return $return;
1852
}
1853

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

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

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

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

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

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

    
1884
	return $return;
1885
}
1886

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

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

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

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

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

    
1912

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

    
1918
EOD;
1919

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

    
1926
EOD;
1927
		}
1928
*/
1929

    
1930

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

    
1938

    
1939
EOD;
1940
		}
1941

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

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

    
1958
EOD;
1959

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

    
1965
EOD;
1966
		}
1967
*/
1968

    
1969

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

    
1976
EOD;
1977
		}
1978

    
1979

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

    
1983
EOD;
1984

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

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

    
2004
EOD;
2005

    
2006
		}
2007

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

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

    
2017
snmpEnableAuthenTraps = 2
2018

    
2019
EOD;
2020

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

    
2026
EOD;
2027
		    }
2028

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

    
2035
EOD;
2036
		    }
2037

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

    
2042
EOD;
2043
		    }
2044

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

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

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

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

    
2068
EOD;
2069
			}
2070
		}
2071

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

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

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

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

    
2088
	return 0;
2089
}
2090

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2229
	return 0;
2230
}
2231

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

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

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

    
2249

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

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

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

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

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

    
2279
	conf_mount_ro();
2280
}
2281

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

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

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

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

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

    
2322
	$is_installed = false;
2323

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

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

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

    
2363
?>
(50-50/68)