Projet

Général

Profil

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

univnautes / etc / inc / services.inc @ d629f1ca

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
	/* make sure there isn't a stale dhcpd.pid file, which can make dhcpd fail to start.   */
897
	/* if we get here, dhcpd has been killed and is not started yet                        */ 
898
	unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
899

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

    
906
	if ($g['booting'])
907
		print "done.\n";
908

    
909
	return 0;
910
}
911

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

    
923
	return $dhcpdconf;
924
}
925

    
926
function dhcpdzones($ddns_zones, $dhcpifconf)
927
{
928
	$dhcpdconf = "";
929

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

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

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

    
972
	return $dhcpdconf;
973
}
974

    
975
function services_dhcpdv6_configure($blacklist = array()) {
976
	global $config, $g;
977

    
978
	if($g['services_dhcp_server_enable'] == false)
979
		return;
980

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

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

    
992
	/* DHCP enabled on any interfaces? */
993
	if (!is_dhcpv6_server_enabled())
994
		return 0;
995

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

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

    
1018

    
1019
	if ($g['booting'])
1020
		echo "Starting DHCPv6 service...";
1021
	else
1022
		sleep(1);
1023

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

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

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

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

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

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

    
1082
	$dhcpdv6conf = <<<EOD
1083

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

    
1096
EOD;
1097

    
1098
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1099
		$dhcpdv6conf .= "authoritative;\n";
1100

    
1101
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1102
		$dhcpdv6conf .= "always-broadcast on\n";
1103

    
1104
	$dhcpdv6ifs = array();
1105

    
1106
	$dhcpv6num = 0;
1107
	$nsupdate = false;
1108

    
1109
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1110

    
1111
		$ddns_zones = array();
1112

    
1113
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1114

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

    
1121
		if ($is_olsr_enabled == true) {
1122
			if($dhcpv6ifconf['netmask'])
1123
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1124
		}
1125

    
1126
		$dnscfgv6 = "";
1127

    
1128
		if ($dhcpv6ifconf['domain']) {
1129
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1130
		}
1131

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

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

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

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

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

    
1174
		$dhcpdv6conf .= <<<EOD
1175
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1176
$dnscfgv6
1177

    
1178
EOD;
1179

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

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

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

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

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

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

    
1229
		$dhcpdv6conf .= "}\n";
1230

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

    
1240
EOD;
1241
				if ($sm['ipaddrv6'])
1242
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1243

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

    
1252
				if ($sm['rootpath'])
1253
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1254

    
1255
				$dhcpdv6conf .= "}\n";
1256
				$i++;
1257
			}
1258
		}
1259

    
1260
		if ($dhcpv6ifconf['domain'])
1261
		{
1262
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1263
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1264
		}
1265

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

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

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

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

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

    
1311
	/* fire up dhcpd in a chroot */
1312
	if (count($dhcpdv6ifs) > 0) {
1313
		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 " .
1314
			join(" ", $dhcpdv6ifs));
1315
		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");
1316
	}
1317
	if ($g['booting'])
1318
		print gettext("done.") . "\n";
1319

    
1320
	return 0;
1321
}
1322

    
1323
function services_igmpproxy_configure() {
1324
        global $config, $g;
1325

    
1326
        /* kill any running igmpproxy */
1327
        killbyname("igmpproxy");
1328

    
1329
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1330
		return 1;
1331

    
1332
        $iflist = get_configured_interface_list();
1333

    
1334
        $igmpconf = <<<EOD
1335

    
1336
##------------------------------------------------------
1337
## Enable Quickleave mode (Sends Leave instantly)
1338
##------------------------------------------------------
1339
quickleave
1340

    
1341
EOD;
1342

    
1343
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1344
                unset($iflist[$igmpcf['ifname']]);
1345
                $realif = get_real_interface($igmpcf['ifname']);
1346
                if (empty($igmpcf['threshold']))
1347
                        $threshld = 1;
1348
                else
1349
                        $threshld = $igmpcf['threshold'];
1350
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1351

    
1352
                if ($igmpcf['address'] <> "") {
1353
                        $item = explode(" ", $igmpcf['address']);
1354
                        foreach($item as $iww)
1355
                                $igmpconf .= "altnet {$iww}\n";
1356
                }
1357
                $igmpconf .= "\n";
1358
        }
1359
        foreach ($iflist as $ifn) {
1360
                $realif = get_real_interface($ifn);
1361
                $igmpconf .= "phyint {$realif} disabled\n";
1362
        }
1363
	$igmpconf .= "\n";
1364

    
1365
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1366
        if (!$igmpfl) {
1367
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1368
                return;
1369
        }
1370
        fwrite($igmpfl, $igmpconf);
1371
        fclose($igmpfl);
1372
	unset($igmpconf);
1373

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

    
1378
        return 0;
1379
}
1380

    
1381
function services_dhcrelay_configure() {
1382
	global $config, $g;
1383
	if ($g['platform'] == 'jail')
1384
		return;
1385
	if(isset($config['system']['developerspew'])) {
1386
		$mt = microtime();
1387
		echo "services_dhcrelay_configure() being called $mt\n";
1388
	}
1389

    
1390
	/* kill any running dhcrelay */
1391
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1392

    
1393
	$dhcrelaycfg =& $config['dhcrelay'];
1394

    
1395
	/* DHCPRelay enabled on any interfaces? */
1396
	if (!isset($dhcrelaycfg['enable']))
1397
		return 0;
1398

    
1399
	if ($g['booting'])
1400
		echo gettext("Starting DHCP relay service...");
1401
	else
1402
		sleep(1);
1403

    
1404
	$iflist = get_configured_interface_list();
1405

    
1406
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1407
	foreach ($dhcifaces as $dhcrelayif) {
1408
		if (!isset($iflist[$dhcrelayif]) ||
1409
			link_interface_to_bridge($dhcrelayif))
1410
			continue;
1411

    
1412
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1413
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1414
	}
1415

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

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

    
1468
		if (!isset($destif)) {
1469
			if (is_array($config['gateways']['gateway_item'])) {
1470
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1471
					if (isset($gateway['defaultgw'])) {
1472
						$destif = get_real_interface($gateway['interface']);
1473
						break;
1474
					}
1475
				}
1476
			} else
1477
				$destif = get_real_interface("wan");
1478
		}
1479

    
1480
		if (!empty($destif))
1481
			$dhcrelayifs[] = $destif;
1482
	}
1483
	$dhcrelayifs = array_unique($dhcrelayifs);
1484

    
1485
	/* fire up dhcrelay */
1486
	if (empty($dhcrelayifs)) {
1487
		log_error("No suitable interface found for running dhcrelay!");
1488
		return; /* XXX */
1489
	}
1490

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

    
1493
	if (isset($dhcrelaycfg['agentoption']))
1494
		$cmd .=  " -a -m replace";
1495

    
1496
	$cmd .= " " . implode(" ", $srvips);
1497
	mwexec($cmd);
1498
	unset($cmd);
1499

    
1500
	return 0;
1501
}
1502

    
1503
function services_dhcrelay6_configure() {
1504
	global $config, $g;
1505
	if ($g['platform'] == 'jail')
1506
		return;
1507
	if(isset($config['system']['developerspew'])) {
1508
		$mt = microtime();
1509
		echo "services_dhcrelay6_configure() being called $mt\n";
1510
	}
1511

    
1512
	/* kill any running dhcrelay */
1513
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1514

    
1515
	$dhcrelaycfg =& $config['dhcrelay6'];
1516

    
1517
	/* DHCPv6 Relay enabled on any interfaces? */
1518
	if (!isset($dhcrelaycfg['enable']))
1519
		return 0;
1520

    
1521
	if ($g['booting'])
1522
		echo gettext("Starting DHCPv6 relay service...");
1523
	else
1524
		sleep(1);
1525

    
1526
	$iflist = get_configured_interface_list();
1527

    
1528
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1529
	foreach ($dhcifaces as $dhcrelayif) {
1530
		if (!isset($iflist[$dhcrelayif]) ||
1531
			link_interface_to_bridge($dhcrelayif))
1532
			continue;
1533

    
1534
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1535
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1536
	}
1537
	$dhcrelayifs = array_unique($dhcrelayifs);
1538

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

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

    
1586
		if (!isset($destif)) {
1587
			if (is_array($config['gateways']['gateway_item'])) {
1588
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1589
					if (isset($gateway['defaultgw'])) {
1590
						$destif = $gateway['interface'];
1591
						break;
1592
					}
1593
				}
1594
			} else
1595
				$destif = get_real_interface("wan");
1596
		}
1597

    
1598
		if (!empty($destif)) {
1599
			$srvifaces[] = "{$srvip}%{$destif}";
1600
		}
1601
	}
1602

    
1603
	/* fire up dhcrelay */
1604
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1605
		log_error("No suitable interface found for running dhcrelay -6!");
1606
		return; /* XXX */
1607
	}
1608

    
1609
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1610
	foreach ($dhcrelayifs as $dhcrelayif) {
1611
		$cmd .= " -l {$dhcrelayif}";
1612
	}
1613
	foreach ($srvifaces as $srviface) {
1614
		$cmd .= " -u \"{$srviface}\"";
1615
	}
1616
	mwexec($cmd);
1617
	unset($cmd);
1618

    
1619
	return 0;
1620
}
1621

    
1622
function services_dyndns_configure_client($conf) {
1623

    
1624
	if (!isset($conf['enable']))
1625
		return;
1626

    
1627
	/* load up the dyndns.class */
1628
	require_once("dyndns.class");
1629

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

    
1652
function services_dyndns_configure($int = "") {
1653
	global $config, $g;
1654
	if(isset($config['system']['developerspew'])) {
1655
		$mt = microtime();
1656
		echo "services_dyndns_configure() being called $mt\n";
1657
	}
1658

    
1659
	$dyndnscfg = $config['dyndnses']['dyndns'];
1660
	$gwgroups = return_gateway_groups_array();
1661
	if (is_array($dyndnscfg)) {
1662
		if ($g['booting'])
1663
			echo gettext("Starting DynDNS clients...");
1664

    
1665
		foreach ($dyndnscfg as $dyndns) {
1666
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1667
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1668
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1669
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1670
				services_dyndns_configure_client($dyndns);
1671
				sleep(1);
1672
			}
1673
		}
1674

    
1675
		if ($g['booting'])
1676
			echo gettext("done.") . "\n";
1677
	}
1678

    
1679
	return 0;
1680
}
1681

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

    
1708
function services_dnsmasq_configure() {
1709
	global $config, $g;
1710
	$return = 0;
1711

    
1712
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1713
	$standard_args = array(
1714
		"dns-forward-max" => "--dns-forward-max=5000",
1715
		"cache-size" => "--cache-size=10000",
1716
		"local-ttl" => "--local-ttl=1"
1717
	);
1718

    
1719

    
1720
	if(isset($config['system']['developerspew'])) {
1721
		$mt = microtime();
1722
		echo "services_dnsmasq_configure() being called $mt\n";
1723
	}
1724

    
1725
	/* kill any running dnsmasq */
1726
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1727
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1728

    
1729
	if (isset($config['dnsmasq']['enable'])) {
1730

    
1731
		if ($g['booting'])
1732
			echo gettext("Starting DNS forwarder...");
1733
		else
1734
			sleep(1);
1735

    
1736
		$args = "";
1737

    
1738
		if (isset($config['dnsmasq']['regdhcp'])) {
1739
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1740
		}
1741

    
1742
		/* Setup listen port, if non-default */
1743
		if (is_port($config['dnsmasq']['port']))
1744
			$args .= " --port={$config['dnsmasq']['port']} ";
1745

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

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

    
1805
		/* Setup forwarded domains */
1806
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1807
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1808
				if ($override['ip'] == "!")
1809
					$override[ip] = "";
1810
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1811
			}
1812
		}
1813

    
1814
		/* Allow DNS Rebind for forwarded domains */
1815
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1816
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1817
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1818
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1819
				}
1820
			}
1821
		}
1822

    
1823
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1824
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1825

    
1826
		if (isset($config['dnsmasq']['strict_order'])) {
1827
			$args .= " --strict-order ";
1828
		}
1829

    
1830
		if (isset($config['dnsmasq']['domain_needed'])) {
1831
			$args .= " --domain-needed ";
1832
		}
1833

    
1834
		if ($config['dnsmasq']['custom_options'])
1835
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1836
				$args .= " " . escapeshellarg("--{$c}");
1837
				$p = explode('=', $c);
1838
				if (array_key_exists($p[0], $standard_args))
1839
					unset($standard_args[$p[0]]);
1840
			}
1841
		$args .= ' ' . implode(' ', array_values($standard_args));
1842

    
1843
		/* run dnsmasq */
1844
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1845
		//log_error("dnsmasq command: {$cmd}");
1846
		mwexec_bg($cmd);
1847
		unset($args);
1848

    
1849
		if ($g['booting'])
1850
			echo gettext("done.") . "\n";
1851
	}
1852

    
1853
	if (!$g['booting']) {
1854
		if(services_dhcpd_configure()!=0)
1855
			$return = 1;
1856
	}
1857

    
1858
	return $return;
1859
}
1860

    
1861
function services_unbound_configure() {
1862
	global $config, $g;
1863
	$return = 0;
1864

    
1865
	if (isset($config['system']['developerspew'])) {
1866
		$mt = microtime();
1867
		echo "services_unbound_configure() being called $mt\n";
1868
	}
1869

    
1870
	// kill any running Unbound instance
1871
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1872
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1873

    
1874
	if (isset($config['unbound']['enable'])) {
1875
		if ($g['booting'])
1876
			echo gettext("Starting DNS Resolver...");
1877
		else
1878
			sleep(1);
1879

    
1880
		require_once('/etc/inc/unbound.inc');
1881
		sync_unbound_service();
1882
		if ($g['booting'])
1883
			echo gettext("done.") . "\n";
1884
	}
1885

    
1886
	if (!$g['booting']) {
1887
		if (services_dhcpd_configure()!=0)
1888
			$return = 1;
1889
	}
1890

    
1891
	return $return;
1892
}
1893

    
1894
function services_snmpd_configure() {
1895
	global $config, $g;
1896
	if(isset($config['system']['developerspew'])) {
1897
		$mt = microtime();
1898
		echo "services_snmpd_configure() being called $mt\n";
1899
	}
1900

    
1901
	/* kill any running snmpd */
1902
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1903
	sleep(2);
1904
	if(is_process_running("bsnmpd"))
1905
		mwexec("/usr/bin/killall bsnmpd", true);
1906

    
1907
	if (isset($config['snmpd']['enable'])) {
1908

    
1909
		if ($g['booting'])
1910
			echo gettext("Starting SNMP daemon... ");
1911

    
1912
		/* generate snmpd.conf */
1913
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1914
		if (!$fd) {
1915
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1916
			return 1;
1917
		}
1918

    
1919

    
1920
		$snmpdconf = <<<EOD
1921
location := "{$config['snmpd']['syslocation']}"
1922
contact := "{$config['snmpd']['syscontact']}"
1923
read := "{$config['snmpd']['rocommunity']}"
1924

    
1925
EOD;
1926

    
1927
/* No docs on what write strings do there for disable for now.
1928
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1929
		    $snmpdconf .= <<<EOD
1930
# write string
1931
write := "{$config['snmpd']['rwcommunity']}"
1932

    
1933
EOD;
1934
		}
1935
*/
1936

    
1937

    
1938
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1939
		    $snmpdconf .= <<<EOD
1940
# SNMP Trap support.
1941
traphost := {$config['snmpd']['trapserver']}
1942
trapport := {$config['snmpd']['trapserverport']}
1943
trap := "{$config['snmpd']['trapstring']}"
1944

    
1945

    
1946
EOD;
1947
		}
1948

    
1949
		$version = trim(file_get_contents('/etc/version'));
1950
		$platform = trim(file_get_contents('/etc/platform'));
1951
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1952
			$platform = $g['product_name'];
1953
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1954
			" {$version} {$platform} " . php_uname("s") .
1955
			" " . php_uname("r") . " " . php_uname("m");
1956

    
1957
		$snmpdconf .= <<<EOD
1958
system := 1     # pfSense
1959
%snmpd
1960
sysDescr			= "{$sysDescr}"
1961
begemotSnmpdDebugDumpPdus       = 2
1962
begemotSnmpdDebugSyslogPri      = 7
1963
begemotSnmpdCommunityString.0.1 = $(read)
1964

    
1965
EOD;
1966

    
1967
/* No docs on what write strings do there for disable for now.
1968
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1969
		    $snmpdconf .= <<<EOD
1970
begemotSnmpdCommunityString.0.2 = $(write)
1971

    
1972
EOD;
1973
		}
1974
*/
1975

    
1976

    
1977
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1978
		    $snmpdconf .= <<<EOD
1979
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1980
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1981
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1982

    
1983
EOD;
1984
		}
1985

    
1986

    
1987
		$snmpdconf .= <<<EOD
1988
begemotSnmpdCommunityDisable    = 1
1989

    
1990
EOD;
1991

    
1992
		if (isset($config['snmpd']['bindlan'])) {
1993
			$config['snmpd']['bindip'] = 'lan';
1994
			unset($config['snmpd']['bindlan']);
1995
		}
1996
		$bind_to_ip = "0.0.0.0";
1997
		if(isset($config['snmpd']['bindip'])) {
1998
			if (is_ipaddr($config['snmpd']['bindip'])) {
1999
				$bind_to_ip = $config['snmpd']['bindip'];
2000
			} else {
2001
				$if = get_real_interface($config['snmpd']['bindip']);
2002
				if (does_interface_exist($if))
2003
					$bind_to_ip = find_interface_ip($if);
2004
			}
2005
		}
2006

    
2007
		if(is_port( $config['snmpd']['pollport'] )) {
2008
		    $snmpdconf .= <<<EOD
2009
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2010

    
2011
EOD;
2012

    
2013
		}
2014

    
2015
		$snmpdconf .= <<<EOD
2016
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2017
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2018

    
2019
# These are bsnmp macros not php vars.
2020
sysContact      = $(contact)
2021
sysLocation     = $(location)
2022
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2023

    
2024
snmpEnableAuthenTraps = 2
2025

    
2026
EOD;
2027

    
2028
		if (is_array( $config['snmpd']['modules'] )) {
2029
		    if(isset($config['snmpd']['modules']['mibii'])) {
2030
			$snmpdconf .= <<<EOD
2031
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2032

    
2033
EOD;
2034
		    }
2035

    
2036
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2037
			$snmpdconf .= <<<EOD
2038
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2039
%netgraph
2040
begemotNgControlNodeName = "snmpd"
2041

    
2042
EOD;
2043
		    }
2044

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

    
2049
EOD;
2050
		    }
2051

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

    
2056
EOD;
2057
		    }
2058
		    if(isset($config['snmpd']['modules']['bridge'])) {
2059
			$snmpdconf .= <<<EOD
2060
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2061
# config must end with blank line
2062

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

    
2069
EOD;
2070
			}
2071
			if(isset($config['snmpd']['modules']['regex'])) {
2072
				$snmpdconf .= <<<EOD
2073
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2074

    
2075
EOD;
2076
			}
2077
		}
2078

    
2079
		fwrite($fd, $snmpdconf);
2080
		fclose($fd);
2081
		unset($snmpdconf);
2082

    
2083
		if (isset($config['snmpd']['bindlan'])) {
2084
			$bindlan = "";
2085
		}
2086

    
2087
		/* run bsnmpd */
2088
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2089
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2090

    
2091
		if ($g['booting'])
2092
			echo gettext("done.") . "\n";
2093
	}
2094

    
2095
	return 0;
2096
}
2097

    
2098
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2099
	global $config, $g;
2100
	if(isset($config['system']['developerspew'])) {
2101
		$mt = microtime();
2102
		echo "services_dnsupdate_process() being called $mt\n";
2103
	}
2104

    
2105
	/* Dynamic DNS updating active? */
2106
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2107
		$notify_text = "";
2108
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2109
			if (!isset($dnsupdate['enable']))
2110
				continue;
2111
			if (!empty($int) && $int != $dnsupdate['interface'])
2112
				continue;
2113
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2114
				continue;
2115

    
2116
			/* determine interface name */
2117
			$if = get_real_interface($dnsupdate['interface']);
2118
			
2119
			if (isset($dnsupdate['usepublicip']))
2120
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2121
                        else
2122
                                $wanip = get_interface_ip($dnsupdate['interface']);
2123
			
2124
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2125
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2126
			$currentTime = time();
2127

    
2128
			if ($wanip || $wanipv6) {
2129
				$keyname = $dnsupdate['keyname'];
2130
				/* trailing dot */
2131
				if (substr($keyname, -1) != ".")
2132
					$keyname .= ".";
2133

    
2134
				$hostname = $dnsupdate['host'];
2135
				/* trailing dot */
2136
				if (substr($hostname, -1) != ".")
2137
					$hostname .= ".";
2138

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

    
2148
EOD;
2149
				fwrite($fd, $privkey);
2150
				fclose($fd);
2151

    
2152
				/* write public key file */
2153
				if ($dnsupdate['keytype'] == "zone") {
2154
					$flags = 257;
2155
					$proto = 3;
2156
				} else if ($dnsupdate['keytype'] == "host") {
2157
					$flags = 513;
2158
					$proto = 3;
2159
				} else if ($dnsupdate['keytype'] == "user") {
2160
					$flags = 0;
2161
					$proto = 2;
2162
				}
2163

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

    
2168
				/* generate update instructions */
2169
				$upinst = "";
2170
				if (!empty($dnsupdate['server']))
2171
					$upinst .= "server {$dnsupdate['server']}\n";
2172

    
2173
				if (file_exists($cacheFile)) {
2174
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2175
				}
2176
				if (file_exists("{$cacheFile}.ipv6")) {
2177
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2178
				}
2179

    
2180
				// 25 Days
2181
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2182
				$need_update = false;
2183

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

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

    
2216
				$upinst .= "\n";	/* mind that trailing newline! */
2217

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

    
2236
	return 0;
2237
}
2238

    
2239
/* configure cron service */
2240
function configure_cron() {
2241
	global $g, $config;
2242

    
2243
	conf_mount_rw();
2244
	/* preserve existing crontab entries */
2245
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2246

    
2247
	for ($i = 0; $i < count($crontab_contents); $i++) {
2248
		$cron_item =& $crontab_contents[$i];
2249
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2250
			array_splice($crontab_contents, $i - 1);
2251
			break;
2252
		}
2253
	}
2254
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2255

    
2256

    
2257
	if (is_array($config['cron']['item'])) {
2258
		$crontab_contents .= "#\n";
2259
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2260
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2261
		$crontab_contents .= "#\n";
2262

    
2263
		foreach ($config['cron']['item'] as $item) {
2264
			$crontab_contents .= "\n{$item['minute']}\t";
2265
			$crontab_contents .= "{$item['hour']}\t";
2266
			$crontab_contents .= "{$item['mday']}\t";
2267
			$crontab_contents .= "{$item['month']}\t";
2268
			$crontab_contents .= "{$item['wday']}\t";
2269
			$crontab_contents .= "{$item['who']}\t";
2270
			$crontab_contents .= "{$item['command']}";
2271
		}
2272

    
2273
		$crontab_contents .= "\n#\n";
2274
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2275
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2276
		$crontab_contents .= "#\n\n";
2277
	}
2278

    
2279
	/* please maintain the newline at the end of file */
2280
	file_put_contents("/etc/crontab", $crontab_contents);
2281
	unset($crontab_contents);
2282

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

    
2286
	conf_mount_ro();
2287
}
2288

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

    
2312
function upnp_start() {
2313
	global $config;
2314

    
2315
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2316
		return;
2317

    
2318
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2319
		echo gettext("Starting UPnP service... ");
2320
		require_once('/usr/local/pkg/miniupnpd.inc');
2321
		sync_package_miniupnpd();
2322
		echo "done.\n";
2323
	}
2324
}
2325

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

    
2329
	$is_installed = false;
2330

    
2331
	if (!is_array($config['cron']))
2332
		$config['cron'] = array();
2333
	if (!is_array($config['cron']['item']))
2334
		$config['cron']['item'] = array();
2335

    
2336
	$x=0;
2337
	foreach($config['cron']['item'] as $item) {
2338
		if(strstr($item['command'], $command)) {
2339
			$is_installed = true;
2340
			break;
2341
		}
2342
		$x++;
2343
	}
2344

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

    
2370
?>
(50-50/68)