Project

General

Profile

Download (70 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services.inc
4
	part of the pfSense project (http://www.pfsense.com)
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 custom custom-v6');
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,Custom,Custom (v6)');
43

    
44
/* implement ipv6 route advertising deamon */
45
function services_radvd_configure() {
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
		if (!isset($dhcpv6ifconf['ramode']))
76
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
77

    
78
		/* are router advertisements enabled? */
79
		if ($dhcpv6ifconf['ramode'] == "disabled")
80
			continue;
81

    
82
		if (!isset($dhcpv6ifconf['rapriority']))
83
			$dhcpv6ifconf['rapriority'] = "medium";
84

    
85
		/* always start with the real parent, we override with the carp if later */
86
		$carpif = false;
87
		/* check if we need to listen on a CARP interface */
88
		if (!empty($dhcpv6ifconf['rainterface'])) {
89
			if (!empty($carplist[$dhcpv6ifconf['rainterface']])) {
90
				$dhcpv6if = $dhcpv6ifconf['rainterface'];
91
				$carpif = true;
92
			}
93
		}
94

    
95
		$realif = get_real_interface($dhcpv6if, "inet6");
96
		if (isset($radvdifs[$realif]))
97
			continue;
98

    
99
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
100
		if (!is_ipaddrv6($ifcfgipv6))
101
			continue;
102

    
103
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
104
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
105
		$radvdifs[$realif] = $realif;
106

    
107
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
108
		$radvdconf .= "interface {$realif} {\n";
109
		$radvdconf .= "\tAdvSendAdvert on;\n";
110
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
111
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
112
		$mtu = get_interface_mtu($realif);
113
		if (is_numeric($mtu))
114
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
115
		else
116
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
117
		// $radvdconf .= "\tDeprecatePrefix on;\n";
118
		switch($dhcpv6ifconf['rapriority']) {
119
			case "low":
120
				$radvdconf .= "\tAdvDefaultPreference low;\n";
121
				break;
122
			case "high":
123
				$radvdconf .= "\tAdvDefaultPreference high;\n";
124
				break;
125
			default:
126
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
127
				break;
128
		}
129
		switch($dhcpv6ifconf['ramode']) {
130
			case "managed":
131
			case "assist":
132
				$radvdconf .= "\tAdvManagedFlag on;\n";
133
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
134
				break;
135
		}
136
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
137
		if($carpif == true) {
138
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
139
		} else {
140
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
141
		}
142
		switch($dhcpv6ifconf['ramode']) {
143
			case "managed":
144
				$radvdconf .= "\t\tAdvOnLink on;\n";
145
				$radvdconf .= "\t\tAdvAutonomous off;\n";
146
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
147
				break;
148
			case "router":
149
				$radvdconf .= "\t\tAdvOnLink off;\n";
150
				$radvdconf .= "\t\tAdvAutonomous off;\n";
151
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
152
				break;
153
			case "assist":
154
				$radvdconf .= "\t\tAdvOnLink on;\n";
155
				$radvdconf .= "\t\tAdvAutonomous on;\n";
156
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
157
				break;
158
			case "unmanaged":
159
				$radvdconf .= "\t\tAdvOnLink on;\n";
160
				$radvdconf .= "\t\tAdvAutonomous on;\n";
161
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
162
				break;				
163
		}
164
		$radvdconf .= "\t};\n";
165

    
166
		if($carpif === true) {
167
			$radvdconf .= "\troute ::/0 {\n";
168
			$radvdconf .= "\t\tRemoveRoute off;\n";
169
			$radvdconf .= "\t};\n";
170
		} else {
171
			$radvdconf .= "\troute ::/0 {\n";
172
			$radvdconf .= "\t\tRemoveRoute on;\n";
173
			$radvdconf .= "\t};\n";
174
		}
175

    
176
		/* add DNS servers */
177
		$dnslist = array();
178
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
179
			foreach($dhcpv6ifconf['dnsserver'] as $server)
180
				if (is_ipaddrv6($server))
181
					$dnslist[] = $server;
182
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
183
			foreach($dhcpv6ifconf['radnsserver'] as $server)
184
				if (is_ipaddrv6($server))
185
					$dnslist[] = $server;
186
		} elseif (isset($config['dnsmasq']['enable'])) {
187
			$dnslist[] = get_interface_ipv6($realif);
188
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
189
			foreach($config['system']['dnsserver'] as $server) {
190
				if (is_ipaddrv6($server))
191
					$dnslist[] = $server;
192
			}
193
		}
194
		if (count($dnslist) > 0) {
195
			$dnsstring = implode(" ", $dnslist);
196
			if ($dnsstring <> "")
197
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
198
		}
199
		if (!empty($dhcpv6ifconf['domain'])) {
200
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
201
		} elseif (!empty($config['system']['domain'])) {
202
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
203
		}
204
		$radvdconf .= "};\n";
205
	}
206

    
207
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
208
	foreach ($Iflist as $if => $ifdescr) {
209
		if(!isset($config['interfaces'][$if]['track6-interface']))
210
			continue;
211
		if(!isset($config['interfaces'][$if]['enable']))
212
			continue;
213
		$trackif = $config['interfaces'][$if]['track6-interface'];
214
		if (empty($config['interfaces'][$trackif]))
215
			continue;
216

    
217
		$realif = get_real_interface($if, "inet6");
218
		/* prevent duplicate entries, manual overrides */
219
		if (isset($radvdifs[$realif]))
220
			continue;
221

    
222
		$ifcfgipv6 = get_interface_ipv6($if);
223
		if(!is_ipaddrv6($ifcfgipv6))
224
			continue;
225

    
226
		$ifcfgsnv6 = get_interface_subnetv6($if);
227
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
228
		$radvdifs[$realif] = $realif;
229

    
230
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
231
	
232
		if ($g['debug'])
233
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
234

    
235
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
236
		$radvdconf .= "interface {$realif} {\n";
237
		$radvdconf .= "\tAdvSendAdvert on;\n";
238
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
239
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
240
		$mtu = get_interface_mtu($realif);
241
		if (is_numeric($mtu))
242
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
243
		else
244
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
245
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
246
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
247
		$radvdconf .= "\t\tAdvOnLink on;\n";
248
		$radvdconf .= "\t\tAdvAutonomous on;\n";
249
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
250
		$radvdconf .= "\t};\n";
251

    
252
		/* add DNS servers */
253
		$dnslist = array();
254
		if (isset($config['dnsmasq']['enable'])) {
255
			$dnslist[] = $ifcfgipv6;
256
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
257
			foreach($config['system']['dnsserver'] as $server) {
258
				if(is_ipaddrv6($server))
259
					$dnslist[] = $server;
260
			}
261
		}
262
		if (count($dnslist) > 0) {
263
			$dnsstring = implode(" ", $dnslist);
264
			if (!empty($dnsstring))
265
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
266
		}
267
		if (!empty($config['system']['domain'])) {
268
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
269
		}
270
		$radvdconf .= "};\n";
271
	}
272

    
273
	/* write radvd.conf */
274
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
275
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
276
		if ($g['booting'])
277
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
278
	}
279
	unset($radvdconf);
280

    
281
	if (count($radvdifs) > 0) {
282
		if (isvalidpid("{$g['varrun_path']}/radvd.pid"))
283
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
284
		else
285
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
286
	} else {
287
		/* we need to shut down the radvd cleanly, it will send out the prefix
288
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
289
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
290
			log_error("Shutting down Router Advertisment daemon cleanly");
291
			killbypid("{$g['varrun_path']}/radvd.pid");
292
			@unlink("{$g['varrun_path']}/radvd.pid");
293
		}
294
	}
295
	return 0;
296
}
297

    
298
function services_dhcpd_configure($family = "all") {
299
	global $config, $g;
300

    
301
	/* configure DHCPD chroot once */
302
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
303
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
304
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
305
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
306
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
307
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
308
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
309
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
310
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
311
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
312
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
313
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
314
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
315
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
316

    
317
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
318
	if (!trim($status))
319
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
320
	fclose($fd);
321
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
322

    
323
	if ($family == "all" || $family == "inet")
324
		services_dhcpdv4_configure();
325
	if ($family == "all" || $family == "inet6") {
326
		services_dhcpdv6_configure();
327
		services_radvd_configure();
328
	}
329
}
330

    
331
function services_dhcpdv4_configure() {
332
	global $config, $g;
333
	$need_ddns_updates = false;
334
	$ddns_zones = array();
335

    
336
	if($g['services_dhcp_server_enable'] == false)
337
		return;
338

    
339
	if(isset($config['system']['developerspew'])) {
340
		$mt = microtime();
341
		echo "services_dhcpdv4_configure($if) being called $mt\n";
342
	}
343

    
344
	/* kill any running dhcpd */
345
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
346
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
347

    
348
	/* DHCP enabled on any interfaces? */
349
	if (!is_dhcp_server_enabled())
350
		return 0;
351

    
352
	/* if OLSRD is enabled, allow WAN to house DHCP. */
353
	if($config['installedpackages']['olsrd'])
354
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
355
				if($olsrd['enable'])
356
					$is_olsr_enabled = true;
357

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

    
375
	$syscfg = $config['system'];
376
	if (!is_array($config['dhcpd']))
377
		$config['dhcpd'] = array();
378
	$dhcpdcfg = $config['dhcpd'];
379
	$Iflist = get_configured_interface_list();
380

    
381
	if ($g['booting'])
382
		echo gettext("Starting DHCP service...");
383
	else
384
		sleep(1);
385

    
386
	$custoptions = "";
387
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
388
		if(is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
389
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
390
				if(!empty($item['type']))
391
					$itemtype = $item['type'];
392
				else
393
					$itemtype = "text";
394
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
395
			}
396
		}
397
	}
398

    
399
	$dhcpdconf = <<<EOD
400

    
401
option domain-name "{$syscfg['domain']}";
402
option ldap-server code 95 = text;
403
option domain-search-list code 119 = text;
404
{$custoptions}
405
default-lease-time 7200;
406
max-lease-time 86400;
407
log-facility local7;
408
one-lease-per-client true;
409
deny duplicates;
410
ping-check true;
411

    
412
EOD;
413

    
414
	if(!isset($dhcpifconf['disableauthoritative']))
415
		$dhcpdconf .= "authoritative;\n";
416

    
417
	if(isset($dhcpifconf['alwaysbroadcast']))
418
		$dhcpdconf .= "always-broadcast on\n";
419

    
420
	$dhcpdifs = array();
421
	$add_routers = false;
422
	$gateways_arr = return_gateways_array();
423
	/* only add a routers line if the system has any IPv4 gateway at all */
424
	/* a static route has a gateway, manually overriding this field always works */
425
	foreach($gateways_arr as $gwitem) {
426
		if($gwitem['ipprotocol'] == "inet") {
427
			$add_routers = true;
428
			break;
429
		}
430
	}
431

    
432
	/*    loop through and determine if we need to setup
433
	 *    failover peer "bleh" entries
434
	 */
435
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
436

    
437
		interfaces_staticarp_configure($dhcpif);
438

    
439
		if (!isset($dhcpifconf['enable']))
440
			continue;
441

    
442
		if($dhcpifconf['failover_peerip'] <> "") {
443
			$int = guess_interface_from_ip($dhcpifconf['failover_peerip']);
444
			$intip = find_interface_ip($int);
445
			$real_dhcpif = convert_friendly_interface_to_real_interface_name($dhcpif);
446
			/*
447
			 *    yep, failover peer is defined.
448
			 *    does it match up to a defined vip?
449
			 */
450
			$skew = 110;
451
			$a_vip = &$config['virtualip']['vip'];
452
			if(is_array($a_vip)) {
453
				foreach ($a_vip as $vipent) {
454
					if($int == $real_dhcpif) {
455
						/* this is the interface! */
456
						if(is_numeric($vipent['advskew']) && ($vipent['advskew'] < "20"))
457
							$skew = 0;
458
					}
459
				}
460
			} else {
461
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IP's defined!"));
462
			}
463
			if($skew > 10) {
464
				$type = "secondary";
465
				$dhcpdconf_pri  = "mclt 600;\n";
466
				$my_port = "520";
467
				$peer_port = "519";
468
			} else {
469
				$my_port = "519";
470
				$peer_port = "520";
471
				$type = "primary";
472
				$dhcpdconf_pri  = "split 128;\n";
473
				$dhcpdconf_pri .= "  mclt 600;\n";
474
			}
475
			$dhcpdconf .= <<<EOPP
476
failover peer "dhcp_{$dhcpif}" {
477
  {$type};
478
  address {$intip};
479
  port {$my_port};
480
  peer address {$dhcpifconf['failover_peerip']};
481
  peer port {$peer_port};
482
  max-response-delay 10;
483
  max-unacked-updates 10;
484
  {$dhcpdconf_pri}
485
  load balance max seconds 3;
486
}
487

    
488
EOPP;
489
		}
490
	}
491

    
492
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
493

    
494
		$newzone = array();
495
		$ifcfg = $config['interfaces'][$dhcpif];
496

    
497
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
498
			continue;
499
		$ifcfgip = get_interface_ip($dhcpif);
500
		$ifcfgsn = get_interface_subnet($dhcpif);
501
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
502
		$subnetmask = gen_subnet_mask($ifcfgsn);
503

    
504
		if (!is_ipaddr($subnet))
505
			continue;
506

    
507
		if($is_olsr_enabled == true)
508
			if($dhcpifconf['netmask'])
509
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
510

    
511
		$all_pools = array();
512
		$all_pools[] = $dhcpifconf;
513
		if (is_array($dhcpifconf['pool'])) {
514
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
515
		}
516

    
517
		$dnscfg = "";
518

    
519
		if ($dhcpifconf['domain']) {
520
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
521
		}
522

    
523
		if($dhcpifconf['domainsearchlist'] <> "") {
524
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
525
		}
526

    
527
		if (isset($dhcpifconf['ddnsupdate'])) {
528
			$need_ddns_updates = true;
529
			$newzone = array();
530
			if($dhcpifconf['ddnsdomain'] <> "") {
531
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
532
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
533
			} else {
534
				$newzone['domain-name'] = $config['system']['domain'];
535
			}
536
			$revsubnet = explode(".", $subnet);
537
			$revsubnet = array_reverse($revsubnet);
538
			foreach ($revsubnet as $octet) {
539
				if ($octet != "0")
540
					break;
541
				array_shift($revsubnet);
542
			}
543
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
544
		}
545

    
546
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
547
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
548
			if ($newzone['domain-name'])
549
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
550
		} else if (isset($config['dnsmasq']['enable'])) {
551
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
552
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
553
				$newzone['dns-servers'] = $syscfg['dnsserver'];
554
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
555
			$dnscfg .= "	option domain-name-servers " . join(",", $syscfg['dnsserver']) . ";";
556
			if ($newzone['domain-name'])
557
				$newzone['dns-servers'] = $syscfg['dnsserver'];
558
		}
559

    
560
		/* Create classes - These all contain comma separated lists. Join them into one 
561
		   big comma separated string then split them all up. */
562
		$all_mac_strings = array();
563
		if (is_array($dhcpifconf['pool'])) {
564
			foreach($all_pools as $poolconf) {
565
				$all_mac_strings[] = $poolconf['mac_allow'];
566
				$all_mac_strings[] = $poolconf['mac_deny'];
567
			}
568
		}
569
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
570
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
571
		$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
572
		foreach ($all_mac_list as $mac) {
573
			if (empty($mac))
574
				continue;
575
			$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
576
			// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
577
			$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
578
			$dhcpdconf .= '}' . "\n";
579
		}
580

    
581
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
582

    
583
// Setup pool options
584
		foreach($all_pools as $poolconf) {
585
			$dhcpdconf .= "	pool {\n";
586
			/* is failover dns setup? */
587
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
588
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
589
				if($poolconf['dnsserver'][1] <> "")
590
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
591
				$dhcpdconf .= ";\n";
592
			}
593

    
594
			/* allow/deny MACs */
595
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
596
			foreach ($mac_allow_list as $mac) {
597
				if (empty($mac))
598
					continue;
599
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
600
			}
601
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
602
			foreach ($mac_deny_list as $mac) {
603
				if (empty($mac))
604
					continue;
605
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
606
			}
607

    
608
			if($poolconf['failover_peerip'] <> "")
609
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
610

    
611
			if (isset($poolconf['denyunknown']))
612
			   $dhcpdconf .= "		deny unknown-clients;\n";
613

    
614
			if ($poolconf['gateway'] && ($poolconf['gateway'] != $dhcpifconf['gateway']))
615
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
616

    
617
			if($dhcpifconf['failover_peerip'] <> "") {
618
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
619
			}
620

    
621
			$pdnscfg = "";
622

    
623
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
624
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
625
			}
626

    
627
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
628
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
629
			}
630

    
631
			if (isset($poolconf['ddnsupdate'])) {
632
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
633
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
634
				$pdnscfg .= "		ddns-update-style interim;\n";
635
			}
636

    
637
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
638
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
639
			}
640
			$dhcpdconf .= "{$pdnscfg}";
641

    
642
			// default-lease-time
643
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
644
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
645

    
646
			// max-lease-time
647
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
648
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
649

    
650
			// netbios-name*
651
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
652
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
653
				$dhcpdconf .= "		option netbios-node-type 8;\n";
654
			}
655

    
656
			// ntp-servers
657
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
658
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
659

    
660
			// tftp-server-name
661
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
662
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
663

    
664
			// ldap-server
665
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
666
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
667

    
668
			// net boot information
669
			if(isset($poolconf['netboot'])) {
670
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
671
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
672
				}
673
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
674
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
675
				}
676
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
677
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
678
				}
679
			}
680
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
681
			$dhcpdconf .= "	}\n\n";
682
		}
683
// End of settings inside pools
684

    
685
		if ($dhcpifconf['gateway']) {
686
			$routers = $dhcpifconf['gateway'];
687
			$add_routers = true;
688
		} else {
689
			$routers = $ifcfgip;
690
		}
691
		if($add_routers)
692
			$dhcpdconf .= "	option routers {$routers};\n";
693

    
694
		$dhcpdconf .= <<<EOD
695
$dnscfg
696

    
697
EOD;
698
    		// default-lease-time
699
		if ($dhcpifconf['defaultleasetime'])
700
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
701

    
702
		// max-lease-time
703
		if ($dhcpifconf['maxleasetime'])
704
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
705

    
706
		// netbios-name*
707
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
708
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
709
			$dhcpdconf .= "	option netbios-node-type 8;\n";
710
		}
711

    
712
		// ntp-servers
713
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
714
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
715

    
716
		// tftp-server-name
717
		if ($dhcpifconf['tftp'] <> "")
718
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
719

    
720
		// Handle option, number rowhelper values
721
		$dhcpdconf .= "\n";
722
		if($dhcpifconf['numberoptions']['item']) {
723
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
724
				if(empty($item['type']) || $item['type'] == "text")
725
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
726
				else
727
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
728
			}
729
		}
730

    
731
		// ldap-server
732
		if ($dhcpifconf['ldap'] <> "")
733
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
734

    
735
		// net boot information
736
		if(isset($dhcpifconf['netboot'])) {
737
			if ($dhcpifconf['nextserver'] <> "") {
738
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
739
			}
740
			if ($dhcpifconf['filename'] <> "") {
741
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
742
			}
743
			if ($dhcpifconf['rootpath'] <> "") {
744
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
745
			}
746
		}
747

    
748
		$dhcpdconf .= <<<EOD
749
}
750

    
751
EOD;
752

    
753
		/* add static mappings */
754
		if (is_array($dhcpifconf['staticmap'])) {
755

    
756
			$i = 0;
757
			foreach ($dhcpifconf['staticmap'] as $sm) {
758
				$dhcpdconf .= <<<EOD
759
host s_{$dhcpif}_{$i} {
760
	hardware ethernet {$sm['mac']};
761

    
762
EOD;
763
				if ($sm['ipaddr'])
764
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
765

    
766
				if ($sm['hostname']) {
767
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
768
					$dhhostname = str_replace(".", "_", $dhhostname);
769
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
770
				}
771
				if ($sm['filename'])
772
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
773

    
774
				if ($sm['rootpath'])
775
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
776

    
777
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
778
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
779

    
780
				$smdnscfg = "";
781

    
782
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
783
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
784
				}
785

    
786
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
787
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
788
				}
789

    
790
				if (isset($sm['ddnsupdate'])) {
791
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
792
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
793
					$pdnscfg .= "		ddns-update-style interim;\n";
794
				}
795

    
796
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
797
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
798
				}
799
				$dhcpdconf .= "{$smdnscfg}";
800

    
801
				// default-lease-time
802
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
803
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
804

    
805
				// max-lease-time
806
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
807
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
808

    
809
				// netbios-name*
810
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
811
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
812
					$dhcpdconf .= "	option netbios-node-type 8;\n";
813
				}
814

    
815
				// ntp-servers
816
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
817
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
818

    
819
				// tftp-server-name
820
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
821
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
822

    
823
				$dhcpdconf .= "}\n";
824
				$i++;
825
			}
826
		}
827

    
828
		$dhcpdifs[] = get_real_interface($dhcpif);
829
		if ($newzone['domain-name'])
830
			$ddns_zones[] = $newzone;
831
	}
832

    
833
	if ($need_ddns_updates) {
834
		$dhcpdconf .= "ddns-update-style interim;\n";
835
		if (is_array($ddns_zones)) {
836
			$added_zones = array();
837
			foreach ($ddns_zones as $zone) {
838
				if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
839
					continue;
840
				$primary = $zone['dns-servers'][0];
841
				$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
842
				// Make sure we aren't using any invalid or IPv6 DNS servers.
843
				if (!is_ipaddrv4($primary)) {
844
					if (is_ipaddrv4($secondary)) {
845
						$primary = $secondary;
846
						$secondary = "";
847
					} else {
848
						continue;
849
					}
850
				}
851
				// We don't need to add zones multiple times.
852
				if (!in_array($zone['domain-name'], $added_zones)) {
853
					$dhcpdconf .= "zone {$zone['domain-name']} {\n";
854
					$dhcpdconf .= "	primary {$primary};\n";
855
					if (is_ipaddrv4($secondary))
856
						$dhcpdconf .= "	secondary {$secondary};\n";
857
					$dhcpdconf .= "}\n";
858
					$added_zones[] = $zone['domain-name'];
859
				}
860
				if (!in_array($zone['ptr-domain'], $added_zones)) {
861
					$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
862
					$dhcpdconf .= "	primary {$primary};\n";
863
					if (is_ipaddrv4($secondary))
864
						$dhcpdconf .= "	secondary {$secondary};\n";
865
					$dhcpdconf .= "}\n";
866
					$added_zones[] = $zone['ptr-domain'];
867
				}
868
			}
869
		}
870
	}
871

    
872
	/* write dhcpd.conf */
873
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
874
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
875
		unset($dhcpdconf);
876
		return 1;
877
	}
878
	unset($dhcpdconf);
879

    
880
	/* create an empty leases database */
881
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
882
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
883

    
884
	/* fire up dhcpd in a chroot */
885
	if (count($dhcpdifs) > 0) {
886
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
887
			join(" ", $dhcpdifs));
888
	}
889

    
890
	if ($g['booting'])
891
		print "done.\n";
892

    
893
	return 0;
894
}
895

    
896
function services_dhcpdv6_configure() {
897
	global $config, $g;
898

    
899
	if($g['services_dhcp_server_enable'] == false)
900
		return;
901

    
902
	if(isset($config['system']['developerspew'])) {
903
		$mt = microtime();
904
		echo "services_dhcpd_configure($if) being called $mt\n";
905
	}
906

    
907
	/* kill any running dhcpd */
908
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
909
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
910
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
911
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
912

    
913
	/* DHCP enabled on any interfaces? */
914
	if (!is_dhcpv6_server_enabled())
915
		return 0;
916

    
917
	if ($g['booting']) {
918
		if ($g['platform'] != "pfSense") {
919
			/* restore the leases, if we have them */
920
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
921
				$dhcprestore = "";
922
				$dhcpreturn = "";
923
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
924
				$dhcprestore = implode(" ", $dhcprestore);
925
				if($dhcpreturn <> 0) {
926
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
927
				}
928
			}
929
		}
930
	}
931

    
932
	$syscfg = $config['system'];
933
	if (!is_array($config['dhcpdv6']))
934
		$config['dhcpdv6'] = array();
935
	$dhcpdv6cfg = $config['dhcpdv6'];
936
	$Iflist = get_configured_interface_list();
937
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
938

    
939

    
940
	if ($g['booting'])
941
		echo "Starting DHCPv6 service...";
942
	else
943
		sleep(1);
944

    
945
	/* we add a fake entry for interfaces that are set to track6 another WAN */
946
	foreach ($Iflist as $ifname) {
947
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
948
			$realif = get_real_interface($ifname, "inet6");
949
			$ifcfgipv6 = get_interface_ipv6($ifname);
950
			if(!is_ipaddrv6($ifcfgipv6))
951
				continue;
952
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
953
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
954
			$trackcfg = $config['interfaces'][$trackifname];
955
			$pdlen = calculate_ipv6_delegation_length($trackifname);
956
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
957
			$dhcpdv6cfg[$ifname] = array();
958
			$dhcpdv6cfg[$ifname]['enable'] = true;
959
			/* range */
960
			$ifcfgipv6arr[7] = "1000";
961
			$dhcpdv6cfg[$ifname]['range'] = array();
962
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
963
			$ifcfgipv6arr[7] = "2000";
964
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));;
965
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
966
			if($pdlen > 2) {
967
				$pdlenmax = $pdlen;
968
				$pdlenhalf = $pdlenmax -1;
969
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
970
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
971
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
972

    
973
				/* set the delegation start to half the current address block */
974
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
975
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
976

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

    
981
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
982
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
983
			}
984
		}
985
	}
986

    
987
	$custoptionsv6 = "";
988
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
989
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
990
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
991
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
992
			}
993
		}
994
	}
995

    
996
	$dhcpdv6conf = <<<EOD
997

    
998
option domain-name "{$syscfg['domain']}";
999
option ldap-server code 95 = text;
1000
option domain-search-list code 119 = text;
1001
{$custoptions}
1002
default-lease-time 7200;
1003
max-lease-time 86400;
1004
log-facility local7;
1005
ddns-update-style none;
1006
one-lease-per-client true;
1007
deny duplicates;
1008
ping-check true;
1009

    
1010
EOD;
1011

    
1012
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1013
		$dhcpdv6conf .= "authoritative;\n";
1014

    
1015
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1016
		$dhcpdv6conf .= "always-broadcast on\n";
1017

    
1018
	$dhcpdv6ifs = array();
1019

    
1020
	$dhcpv6num = 0;
1021
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1022

    
1023
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1024

    
1025
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
1026
			continue;
1027
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1028
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1029
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1030

    
1031
		if ($is_olsr_enabled == true) {
1032
			if($dhcpv6ifconf['netmask'])
1033
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1034
		}
1035

    
1036
		$dnscfgv6 = "";
1037

    
1038
		if ($dhcpv6ifconf['domain']) {
1039
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1040
		}
1041

    
1042
    		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1043
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1044
    		}
1045

    
1046
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1047
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1048
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1049
			}
1050
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1051
		}
1052

    
1053
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1054
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1055
		} else if ((isset($config['dnsmasq']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1056
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1057
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1058
			$dns_arrv6 = array();
1059
			foreach($syscfg['dnsserver'] as $dnsserver) {
1060
				if (is_ipaddrv6($dnsserver)) {
1061
					$dns_arrv6[] = $dnsserver;
1062
				}
1063
			}
1064
			if(!empty($dns_arrv6))
1065
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1066
		}
1067

    
1068
		if (is_ipaddrv6($ifcfgipv6)) {
1069
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1070
		} else {
1071
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1072
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1073
		}
1074
		$dhcpdv6conf .= " {\n";
1075

    
1076
		if($dhcpv6ifconf['failover_peerip'] <> "")
1077
			$dhcpdv6conf .= "		deny dynamic bootp clients;\n";
1078

    
1079
		if (isset($dhcpv6ifconf['denyunknown']))
1080
		   $dhcpdv6conf .= "		deny unknown-clients;\n";
1081

    
1082
		$dhcpdv6conf .= <<<EOD
1083
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1084
$dnscfgv6
1085

    
1086
EOD;
1087

    
1088
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1089
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']}/{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1090
		}
1091
    		// default-lease-time
1092
		if ($dhcpv6ifconf['defaultleasetime'])
1093
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1094

    
1095
		// max-lease-time
1096
		if ($dhcpv6ifconf['maxleasetime'])
1097
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1098

    
1099
		// ntp-servers
1100
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1101
			$ntpservers = array();
1102
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1103
				if(is_ipaddrv6($ntpserver))
1104
					$ntpservers[] = $ntpserver;
1105
			}
1106
			if(count($ntpservers) > 0 )
1107
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1108
		}
1109
		// tftp-server-name
1110
		/* Needs ISC DHCPD support
1111
		 if ($dhcpv6ifconf['tftp'] <> "")
1112
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1113
		*/
1114

    
1115
		// Handle option, number rowhelper values
1116
		$dhcpdv6conf .= "\n";
1117
		if ($dhcpv6ifconf['numberoptions']['item']) {
1118
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1119
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1120
			}
1121
		}
1122

    
1123
		// ldap-server
1124
		if ($dhcpv6ifconf['ldap'] <> "")
1125
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1126

    
1127
		// net boot information
1128
		if(isset($dhcpv6ifconf['netboot'])) {
1129
			if ($dhcpv6ifconf['nextserver'] <> "") {
1130
				$dhcpdv6conf .= "	next-server {$dhcpv6ifconf['nextserver']};\n";
1131
			}
1132
			if ($dhcpv6ifconf['filename'] <> "") {
1133
				$dhcpdv6conf .= "	filename \"{$dhcpv6ifconf['filename']}\";\n";
1134
			}
1135
			if ($dhcpv6ifconf['rootpath'] <> "") {
1136
				$dhcpdv6conf .= "	option root-path \"{$dhcpv6ifconf['rootpath']}\";\n";
1137
			}
1138
		}
1139

    
1140
		$dhcpdv6conf .= "}\n";
1141

    
1142
		/* add static mappings */
1143
		/* Needs to use DUID */
1144
		if (is_array($dhcpv6ifconf['staticmap'])) {
1145
			$i = 0;
1146
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1147
				$dhcpdv6conf .= <<<EOD
1148
host s_{$dhcpv6if}_{$i} {
1149
	host-identifier option dhcp6.client-id {$sm['duid']};
1150

    
1151
EOD;
1152
				if ($sm['ipaddrv6'])
1153
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1154

    
1155
				if ($sm['hostname']) {
1156
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1157
					$dhhostname = str_replace(".", "_", $dhhostname);
1158
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1159
				}
1160
				if ($sm['filename'])
1161
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1162

    
1163
				if ($sm['rootpath'])
1164
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1165

    
1166
				$dhcpdv6conf .= "}\n";
1167
				$i++;
1168
			}
1169
		}
1170

    
1171
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged") {
1172
			if(preg_match("/poes/si", $dhcpv6if)) {
1173
				/* magic here */
1174
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1175
			} else {
1176
				$realif = get_real_interface($dhcpv6if, "inet6");
1177
				if (stristr("$realif", "bridge")) {
1178
					$mac = get_interface_mac($realif);
1179
					$v6address = generate_ipv6_from_mac($mac);
1180
					/* Create link local address for bridges */
1181
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1182
				}
1183
				$realif = escapeshellcmd($realif);
1184
				$dhcpdv6ifs[] = $realif;
1185
			}
1186
		}
1187
	}
1188

    
1189
	/* write dhcpdv6.conf */
1190
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1191
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1192
		if ($g['booting'])
1193
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1194
		unset($dhcpdv6conf);
1195
		return 1;
1196
	}
1197
	unset($dhcpdv6conf);
1198

    
1199
	/* create an empty leases v6 database */
1200
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1201
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1202

    
1203
	/* fire up dhcpd in a chroot */
1204
	if (count($dhcpdv6ifs) > 0) {
1205
		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 " .
1206
			join(" ", $dhcpdv6ifs));
1207
		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");
1208
	}
1209
	if ($g['booting'])
1210
		print gettext("done.") . "\n";
1211

    
1212
	return 0;
1213
}
1214

    
1215
function services_igmpproxy_configure() {
1216
        global $config, $g;
1217

    
1218
        /* kill any running igmpproxy */
1219
        killbyname("igmpproxy");
1220

    
1221
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1222
		return 1;
1223

    
1224
        $iflist = get_configured_interface_list();
1225

    
1226
        $igmpconf = <<<EOD
1227

    
1228
##------------------------------------------------------
1229
## Enable Quickleave mode (Sends Leave instantly)
1230
##------------------------------------------------------
1231
quickleave
1232

    
1233
EOD;
1234

    
1235
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1236
                unset($iflist[$igmpcf['ifname']]);
1237
                $realif = get_real_interface($igmpcf['ifname']);
1238
                if (empty($igmpcf['threshold']))
1239
                        $threshld = 1;
1240
                else
1241
                        $threshld = $igmpcf['threshold'];
1242
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1243

    
1244
                if ($igmpcf['address'] <> "") {
1245
                        $item = explode(" ", $igmpcf['address']);
1246
                        foreach($item as $iww)
1247
                                $igmpconf .= "altnet {$iww}\n";
1248
                }
1249
                $igmpconf .= "\n";
1250
        }
1251
        foreach ($iflist as $ifn) {
1252
                $realif = get_real_interface($ifn);
1253
                $igmpconf .= "phyint {$realif} disabled\n";
1254
        }
1255
	$igmpconf .= "\n";
1256

    
1257
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1258
        if (!$igmpfl) {
1259
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1260
                return;
1261
        }
1262
        fwrite($igmpfl, $igmpconf);
1263
        fclose($igmpfl);
1264
	unset($igmpconf);
1265

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

    
1270
        return 0;
1271
}
1272

    
1273
function services_dhcrelay_configure() {
1274
	global $config, $g;
1275
	if ($g['platform'] == 'jail')
1276
		return;
1277
	if(isset($config['system']['developerspew'])) {
1278
		$mt = microtime();
1279
		echo "services_dhcrelay_configure() being called $mt\n";
1280
	}
1281

    
1282
	/* kill any running dhcrelay */
1283
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1284

    
1285
	$dhcrelaycfg =& $config['dhcrelay'];
1286

    
1287
	/* DHCPRelay enabled on any interfaces? */
1288
	if (!isset($dhcrelaycfg['enable']))
1289
		return 0;
1290

    
1291
	if ($g['booting'])
1292
		echo gettext("Starting DHCP relay service...");
1293
	else
1294
		sleep(1);
1295

    
1296
	$iflist = get_configured_interface_list();
1297

    
1298
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1299
	foreach ($dhcifaces as $dhcrelayif) {
1300
		if (!isset($iflist[$dhcrelayif]) ||
1301
			link_interface_to_bridge($dhcrelayif))
1302
			continue;
1303

    
1304
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1305
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1306
	}
1307

    
1308
	/*
1309
	 * In order for the relay to work, it needs to be active
1310
	 * on the interface in which the destination server sits.
1311
	 */
1312
	$srvips = explode(",", $dhcrelaycfg['server']);
1313
	foreach ($srvips as $srcidx => $srvip) {
1314
		unset($destif);
1315
		foreach ($iflist as $ifname) {
1316
			$subnet = get_interface_ip($ifname);
1317
			if (!is_ipaddr($subnet))
1318
				continue;
1319
			$subnet .=  "/" . get_interface_subnet($ifname);
1320
			if (ip_in_subnet($srvip, $subnet)) {
1321
				$destif = get_real_interface($ifname);
1322
				break;
1323
			}
1324
		}
1325
		if (!isset($destif)) {
1326
			foreach (get_staticroutes() as $rtent) {
1327
				if (ip_in_subnet($srvip, $rtent['network'])) {
1328
					$a_gateways = return_gateways_array(true);
1329
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1330
					break;
1331
				}
1332
			}
1333
		}
1334

    
1335
		if (!isset($destif)) {
1336
			/* Create a array from the existing route table */
1337
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1338
        		array_shift($route_str);
1339
        		array_shift($route_str);
1340
        		array_shift($route_str);
1341
        		array_shift($route_str);
1342
        		$route_arr = array();
1343
        		foreach($route_str as $routeline) {
1344
				$items = preg_split("/[ ]+/i", $routeline);
1345
				if (is_subnetv4($items[0])) {
1346
					$subnet = $items[0];
1347
				} elseif (is_ipaddrv4($items[0])) {
1348
					$subnet = "{$items[0]}/32";
1349
				} else {
1350
					// Not a subnet or IP address, skip to the next line.
1351
					continue;
1352
				}
1353
				if (ip_in_subnet($srvip, $subnet)) {
1354
					$destif = trim($items[6]);
1355
					break;
1356
				}
1357
			}
1358
		}
1359

    
1360
		if (!isset($destif)) {
1361
			if (is_array($config['gateways']['gateway_item'])) {
1362
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1363
					if (isset($gateway['defaultgw'])) {
1364
						$a_gateways = return_gateways_array(true);
1365
                                        	$destif = $a_gateways[$rtent['gateway']]['interface'];
1366
						break;
1367
					}
1368
				}
1369
			} else
1370
				$destif = get_real_interface("wan");
1371
		}
1372

    
1373
		if (!empty($destif))
1374
			$dhcrelayifs[] = $destif;
1375
	}
1376
	$dhcrelayifs = array_unique($dhcrelayifs);
1377

    
1378
	/* fire up dhcrelay */
1379
	if (empty($dhcrelayifs)) {
1380
		log_error("No suitable interface found for running dhcrelay!");
1381
		return; /* XXX */
1382
	}
1383

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

    
1386
	if (isset($dhcrelaycfg['agentoption']))
1387
		$cmd .=  " -a -m replace";
1388

    
1389
	$cmd .= " " . implode(" ", $srvips);
1390
	mwexec($cmd);
1391
	unset($cmd);
1392

    
1393
	return 0;
1394
}
1395

    
1396
function services_dhcrelay6_configure() {
1397
	global $config, $g;
1398
	if ($g['platform'] == 'jail')
1399
		return;
1400
	if(isset($config['system']['developerspew'])) {
1401
		$mt = microtime();
1402
		echo "services_dhcrelay6_configure() being called $mt\n";
1403
	}
1404

    
1405
	/* kill any running dhcrelay */
1406
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1407

    
1408
	$dhcrelaycfg =& $config['dhcrelay6'];
1409

    
1410
	/* DHCPv6 Relay enabled on any interfaces? */
1411
	if (!isset($dhcrelaycfg['enable']))
1412
		return 0;
1413

    
1414
	if ($g['booting'])
1415
		echo gettext("Starting DHCPv6 relay service...");
1416
	else
1417
		sleep(1);
1418

    
1419
	$iflist = get_configured_interface_list();
1420

    
1421
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1422
	foreach ($dhcifaces as $dhcrelayif) {
1423
		if (!isset($iflist[$dhcrelayif]) ||
1424
			link_interface_to_bridge($dhcrelayif))
1425
			continue;
1426

    
1427
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1428
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1429
	}
1430
	$dhcrelayifs = array_unique($dhcrelayifs);
1431

    
1432
	/*
1433
	 * In order for the relay to work, it needs to be active
1434
	 * on the interface in which the destination server sits.
1435
	 */
1436
	$srvips = explode(",", $dhcrelaycfg['server']);
1437
        $srvifaces = array();
1438
	foreach ($srvips as $srcidx => $srvip) {
1439
		unset($destif);
1440
		foreach ($iflist as $ifname) {
1441
			$subnet = get_interface_ipv6($ifname);
1442
			if (!is_ipaddrv6($subnet))
1443
				continue;
1444
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1445
			if (ip_in_subnet($srvip, $subnet)) {
1446
				$destif = get_real_interface($ifname);
1447
				break;
1448
			}
1449
		}
1450
		if (!isset($destif)) {
1451
			if (is_array($config['staticroutes']['route'])) {
1452
				foreach ($config['staticroutes']['route'] as $rtent) {
1453
					if (ip_in_subnet($srvip, $rtent['network'])) {
1454
						$a_gateways = return_gateways_array(true);
1455
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1456
						break;
1457
					}
1458
				}
1459
			}
1460
		}
1461

    
1462
		if (!isset($destif)) {
1463
			/* Create a array from the existing route table */
1464
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1465
        		array_shift($route_str);
1466
        		array_shift($route_str);
1467
        		array_shift($route_str);
1468
        		array_shift($route_str);
1469
        		$route_arr = array();
1470
        		foreach($route_str as $routeline) {
1471
                		$items = preg_split("/[ ]+/i", $routeline);
1472
				if (ip_in_subnet($srvip, $items[0])) {
1473
					$destif = trim($items[6]);
1474
					break;
1475
				}
1476
        		}
1477
		}
1478

    
1479
		if (!isset($destif)) {
1480
			if (is_array($config['gateways']['gateway_item'])) {
1481
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1482
					if (isset($gateway['defaultgw'])) {
1483
						$a_gateways = return_gateways_array(true);
1484
                                        	$destif = $a_gateways[$rtent['gateway']]['interface'];
1485
						break;
1486
					}
1487
				}
1488
			} else
1489
				$destif = get_real_interface("wan");
1490
		}
1491

    
1492
		if (!empty($destif)) {
1493
			$srvifaces[] = "{$srvip}%{$destif}";
1494
		}
1495
	}
1496

    
1497
	/* fire up dhcrelay */
1498
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1499
		log_error("No suitable interface found for running dhcrelay -6!");
1500
		return; /* XXX */
1501
	}
1502

    
1503
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1504
	foreach ($dhcrelayifs as $dhcrelayif) {
1505
		$cmd .= " -l {$dhcrelayif}";
1506
	}
1507
	foreach ($srvifaces as $srviface) {
1508
		$cmd .= " -u \"{$srviface}\"";
1509
	}
1510
	mwexec($cmd);
1511
	unset($cmd);
1512

    
1513
	return 0;
1514
}
1515

    
1516
function services_dyndns_configure_client($conf) {
1517

    
1518
	if (!isset($conf['enable']))
1519
		return;
1520

    
1521
	/* load up the dyndns.class */
1522
	require_once("dyndns.class");
1523

    
1524
	$dns = new updatedns($dnsService = $conf['type'],
1525
		$dnsHost = $conf['host'],
1526
		$dnsUser = $conf['username'],
1527
		$dnsPass = $conf['password'],
1528
		$dnsWilcard = $conf['wildcard'],
1529
		$dnsMX = $conf['mx'],
1530
		$dnsIf = "{$conf['interface']}",
1531
		$dnsBackMX = NULL,
1532
		$dnsServer = NULL,
1533
		$dnsPort = NULL,
1534
		$dnsUpdateURL = "{$conf['updateurl']}",
1535
		$forceUpdate = $conf['force'],
1536
		$dnsZoneID=$conf['zoneid'],
1537
		$dnsTTL=$conf['ttl'],
1538
		$dnsResultMatch = "{$conf['resultmatch']}",
1539
		$dnsRequestIf = "{$conf['requestif']}",
1540
		$dnsID = "{$conf['id']}",
1541
		$dnsVerboseLog = $conf['verboselog']);
1542
}
1543

    
1544
function services_dyndns_configure($int = "") {
1545
	global $config, $g;
1546
	if(isset($config['system']['developerspew'])) {
1547
		$mt = microtime();
1548
		echo "services_dyndns_configure() being called $mt\n";
1549
	}
1550

    
1551
	$dyndnscfg = $config['dyndnses']['dyndns'];
1552
	$gwgroups = return_gateway_groups_array();
1553
	if (is_array($dyndnscfg)) {
1554
		if ($g['booting'])
1555
			echo gettext("Starting DynDNS clients...");
1556

    
1557
		foreach ($dyndnscfg as $dyndns) {
1558
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1559
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1560
				services_dyndns_configure_client($dyndns);
1561
				sleep(1);
1562
			}
1563
		}
1564

    
1565
		if ($g['booting'])
1566
			echo gettext("done.") . "\n";
1567
	}
1568

    
1569
	return 0;
1570
}
1571

    
1572
function dyndnsCheckIP($int) {
1573
	global $config;
1574
	$ip_address = get_interface_ip($int);
1575
	if (is_private_ip($ip_address)) {
1576
		$gateways_status = return_gateways_status(true);
1577
		// If the gateway for this interface is down, then the external check cannot work.
1578
		// Avoid the long wait for the external check to timeout.
1579
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1580
			return "down";
1581
		$hosttocheck = "checkip.dyndns.org";
1582
		$checkip = gethostbyname($hosttocheck);
1583
		$ip_ch = curl_init("http://{$checkip}");
1584
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1585
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1586
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1587
		$ip_result_page = curl_exec($ip_ch);
1588
		curl_close($ip_ch);
1589
		$ip_result_decoded = urldecode($ip_result_page);
1590
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1591
		$ip_address = trim($matches[1]);
1592
	}
1593
	return $ip_address;
1594
}
1595

    
1596
function services_dnsmasq_configure() {
1597
	global $config, $g;
1598
	$return = 0;
1599

    
1600
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1601
	$standard_args = array(
1602
		"dns-forward-max" => "--dns-forward-max=5000",
1603
		"cache-size" => "--cache-size=10000",
1604
		"local-ttl" => "--local-ttl=1"
1605
	);
1606

    
1607

    
1608
	if(isset($config['system']['developerspew'])) {
1609
		$mt = microtime();
1610
		echo "services_dnsmasq_configure() being called $mt\n";
1611
	}
1612

    
1613
	/* kill any running dnsmasq */
1614
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1615
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1616

    
1617
	if (isset($config['dnsmasq']['enable'])) {
1618

    
1619
		if ($g['booting'])
1620
			echo gettext("Starting DNS forwarder...");
1621
		else
1622
			sleep(1);
1623

    
1624
		/* generate hosts file */
1625
		if(system_hosts_generate()!=0)
1626
			$return = 1;
1627

    
1628
		$args = "";
1629

    
1630
		if (isset($config['dnsmasq']['regdhcp'])) {
1631
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1632
		}
1633

    
1634
		/* Setup listen port, if non-default */
1635
		if (is_port($config['dnsmasq']['port']))
1636
			$args .= " --port={$config['dnsmasq']['port']} ";
1637

    
1638
		$listen_addresses = "";
1639
		if(isset($config['dnsmasq']['interface'])) {
1640
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1641
			foreach ($interfaces as $interface) {
1642
				if (is_ipaddr($interface)) {
1643
					$listen_addresses .= " --listen-address={$interface} ";
1644
				} else {
1645
					$if = get_real_interface($interface);
1646
					if (does_interface_exist($if)) {
1647
						$laddr = find_interface_ip($if);
1648
						if (is_ipaddrv4($laddr))
1649
							$listen_addresses .= " --listen-address={$laddr} ";
1650
						$laddr6 = find_interface_ipv6($if);
1651
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind']))
1652
							$listen_addresses .= " --listen-address={$laddr6} ";
1653
					}
1654
				}
1655
			}
1656
			if (!empty($listen_addresses)) {
1657
				$args .= " {$listen_addresses} ";
1658
				if (isset($config['dnsmasq']['strictbind']))
1659
					$args .= " --bind-interfaces ";
1660
			}
1661
		}
1662

    
1663
		/* Setup forwarded domains */
1664
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1665
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1666
				if ($override['ip'] == "!")
1667
					$override[ip] = "";
1668
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1669
			}
1670
		}
1671

    
1672
		/* If selected, then forward reverse lookups for private IPv4 addresses to nowhere. */
1673
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1674
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1675
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1676
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1677
			$args .= " --server=/10.in-addr.arpa/ ";
1678
			$args .= " --server=/168.192.in-addr.arpa/ ";
1679
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1680
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1681
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1682
			}
1683
		}
1684

    
1685
		/* Allow DNS Rebind for forwarded domains */
1686
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1687
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1688
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1689
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1690
				}
1691
			}
1692
		}
1693

    
1694
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1695
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1696

    
1697
		if (isset($config['dnsmasq']['strict_order'])) {
1698
			$args .= " --strict-order ";
1699
		}
1700

    
1701
		if (isset($config['dnsmasq']['domain_needed'])) {
1702
			$args .= " --domain-needed ";
1703
		}
1704

    
1705
		if ($config['dnsmasq']['custom_options'])
1706
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1707
				$args .= " --$c";
1708
				$p = explode('=', $c);
1709
				if (array_key_exists($p[0], $standard_args))
1710
					unset($standard_args[$p[0]]);
1711
			}
1712
		$args .= ' ' . implode(' ', array_values($standard_args));
1713

    
1714
		/* run dnsmasq */
1715
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1716
		//log_error("dnsmasq command: {$cmd}");
1717
		mwexec_bg($cmd);
1718
		unset($args);
1719

    
1720
		if ($g['booting'])
1721
			echo gettext("done.") . "\n";
1722
	}
1723

    
1724
	if (!$g['booting']) {
1725
		if(services_dhcpd_configure()!=0)
1726
			$return = 1;
1727
	}
1728

    
1729
	return $return;
1730
}
1731

    
1732
function services_snmpd_configure() {
1733
	global $config, $g;
1734
	if(isset($config['system']['developerspew'])) {
1735
		$mt = microtime();
1736
		echo "services_snmpd_configure() being called $mt\n";
1737
	}
1738

    
1739
	/* kill any running snmpd */
1740
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1741
	sleep(2);
1742
	if(is_process_running("bsnmpd"))
1743
		mwexec("/usr/bin/killall bsnmpd", true);
1744

    
1745
	if (isset($config['snmpd']['enable'])) {
1746

    
1747
		if ($g['booting'])
1748
			echo gettext("Starting SNMP daemon... ");
1749

    
1750
		/* generate snmpd.conf */
1751
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1752
		if (!$fd) {
1753
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1754
			return 1;
1755
		}
1756

    
1757

    
1758
		$snmpdconf = <<<EOD
1759
location := "{$config['snmpd']['syslocation']}"
1760
contact := "{$config['snmpd']['syscontact']}"
1761
read := "{$config['snmpd']['rocommunity']}"
1762

    
1763
EOD;
1764

    
1765
/* No docs on what write strings do there for disable for now.
1766
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1767
		    $snmpdconf .= <<<EOD
1768
# write string
1769
write := "{$config['snmpd']['rwcommunity']}"
1770

    
1771
EOD;
1772
		}
1773
*/
1774

    
1775

    
1776
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1777
		    $snmpdconf .= <<<EOD
1778
# SNMP Trap support.
1779
traphost := {$config['snmpd']['trapserver']}
1780
trapport := {$config['snmpd']['trapserverport']}
1781
trap := "{$config['snmpd']['trapstring']}"
1782

    
1783

    
1784
EOD;
1785
		}
1786

    
1787
		$version = trim(file_get_contents('/etc/version'));
1788
		$platform = trim(file_get_contents('/etc/platform'));
1789
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1790
			$platform = $g['product_name'];
1791
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1792
			" {$version} {$platform} " . php_uname("s") .
1793
			" " . php_uname("r") . " " . php_uname("m");
1794

    
1795
		$snmpdconf .= <<<EOD
1796
system := 1     # pfSense
1797
%snmpd
1798
sysDescr			= "{$sysDescr}"
1799
begemotSnmpdDebugDumpPdus       = 2
1800
begemotSnmpdDebugSyslogPri      = 7
1801
begemotSnmpdCommunityString.0.1 = $(read)
1802

    
1803
EOD;
1804

    
1805
/* No docs on what write strings do there for disable for now.
1806
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1807
		    $snmpdconf .= <<<EOD
1808
begemotSnmpdCommunityString.0.2 = $(write)
1809

    
1810
EOD;
1811
		}
1812
*/
1813

    
1814

    
1815
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1816
		    $snmpdconf .= <<<EOD
1817
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1818
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1819
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1820

    
1821
EOD;
1822
		}
1823

    
1824

    
1825
		$snmpdconf .= <<<EOD
1826
begemotSnmpdCommunityDisable    = 1
1827

    
1828
EOD;
1829

    
1830
		if (isset($config['snmpd']['bindlan'])) {
1831
			$config['snmpd']['bindip'] = 'lan';
1832
			unset($config['snmpd']['bindlan']);
1833
		}
1834
		$bind_to_ip = "0.0.0.0";
1835
		if(isset($config['snmpd']['bindip'])) {
1836
			if (is_ipaddr($config['snmpd']['bindip'])) {
1837
				$bind_to_ip = $config['snmpd']['bindip'];
1838
			} else {
1839
				$if = get_real_interface($config['snmpd']['bindip']);
1840
				if (does_interface_exist($if))
1841
					$bind_to_ip = find_interface_ip($if);
1842
			}
1843
		}
1844

    
1845
		if(is_port( $config['snmpd']['pollport'] )) {
1846
		    $snmpdconf .= <<<EOD
1847
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1848

    
1849
EOD;
1850

    
1851
		}
1852

    
1853
		$snmpdconf .= <<<EOD
1854
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1855
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1856

    
1857
# These are bsnmp macros not php vars.
1858
sysContact      = $(contact)
1859
sysLocation     = $(location)
1860
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1861

    
1862
snmpEnableAuthenTraps = 2
1863

    
1864
EOD;
1865

    
1866
		if (is_array( $config['snmpd']['modules'] )) {
1867
		    if(isset($config['snmpd']['modules']['mibii'])) {
1868
			$snmpdconf .= <<<EOD
1869
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1870

    
1871
EOD;
1872
		    }
1873

    
1874
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1875
			$snmpdconf .= <<<EOD
1876
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1877
%netgraph
1878
begemotNgControlNodeName = "snmpd"
1879

    
1880
EOD;
1881
		    }
1882

    
1883
		    if(isset($config['snmpd']['modules']['pf'])) {
1884
			$snmpdconf .= <<<EOD
1885
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1886

    
1887
EOD;
1888
		    }
1889

    
1890
		    if(isset($config['snmpd']['modules']['hostres'])) {
1891
			$snmpdconf .= <<<EOD
1892
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1893

    
1894
EOD;
1895
		    }
1896
		    if(isset($config['snmpd']['modules']['bridge'])) {
1897
			$snmpdconf .= <<<EOD
1898
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1899
# config must end with blank line
1900

    
1901
EOD;
1902
		    }
1903
			if(isset($config['snmpd']['modules']['ucd'])) {
1904
				$snmpdconf .= <<<EOD
1905
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
1906

    
1907
EOD;
1908
			}
1909
			if(isset($config['snmpd']['modules']['regex'])) {
1910
				$snmpdconf .= <<<EOD
1911
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
1912

    
1913
EOD;
1914
			}
1915
		}
1916

    
1917
		fwrite($fd, $snmpdconf);
1918
		fclose($fd);
1919
		unset($snmpdconf);
1920

    
1921
		if (isset($config['snmpd']['bindlan'])) {
1922
			$bindlan = "";
1923
		}
1924

    
1925
		/* run bsnmpd */
1926
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
1927
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
1928

    
1929
		if ($g['booting'])
1930
			echo gettext("done.") . "\n";
1931
	}
1932

    
1933
	return 0;
1934
}
1935

    
1936
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
1937
	global $config, $g;
1938
	if(isset($config['system']['developerspew'])) {
1939
		$mt = microtime();
1940
		echo "services_dnsupdate_process() being called $mt\n";
1941
	}
1942

    
1943
	/* Dynamic DNS updating active? */
1944
	if (is_array($config['dnsupdates']['dnsupdate'])) {
1945
		$notify_text = "";
1946
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
1947
			if (!isset($dnsupdate['enable']))
1948
				continue;
1949
			if (!empty($int) && $int != $dnsupdate['interface'])
1950
				continue;
1951
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
1952
				continue;
1953

    
1954
			/* determine interface name */
1955
			$if = get_real_interface($dnsupdate['interface']);
1956
			$wanip = get_interface_ip($dnsupdate['interface']);
1957
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
1958

    
1959
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
1960
			$currentTime = time();
1961

    
1962
			if ($wanip || $wanipv6) {
1963
				$keyname = $dnsupdate['keyname'];
1964
				/* trailing dot */
1965
				if (substr($keyname, -1) != ".")
1966
					$keyname .= ".";
1967

    
1968
				$hostname = $dnsupdate['host'];
1969
				/* trailing dot */
1970
				if (substr($hostname, -1) != ".")
1971
					$hostname .= ".";
1972

    
1973
				/* write private key file
1974
				   this is dumb - public and private keys are the same for HMAC-MD5,
1975
				   but nsupdate insists on having both */
1976
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
1977
				$privkey = <<<EOD
1978
Private-key-format: v1.2
1979
Algorithm: 157 (HMAC)
1980
Key: {$dnsupdate['keydata']}
1981

    
1982
EOD;
1983
				fwrite($fd, $privkey);
1984
				fclose($fd);
1985

    
1986
				/* write public key file */
1987
				if ($dnsupdate['keytype'] == "zone") {
1988
					$flags = 257;
1989
					$proto = 3;
1990
				} else if ($dnsupdate['keytype'] == "host") {
1991
					$flags = 513;
1992
					$proto = 3;
1993
				} else if ($dnsupdate['keytype'] == "user") {
1994
					$flags = 0;
1995
					$proto = 2;
1996
				}
1997

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

    
2002
				/* generate update instructions */
2003
				$upinst = "";
2004
				if (!empty($dnsupdate['server']))
2005
					$upinst .= "server {$dnsupdate['server']}\n";
2006

    
2007
				if (file_exists($cacheFile)) {
2008
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2009
				}
2010
				if (file_exists("{$cacheFile}.ipv6")) {
2011
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2012
				}
2013

    
2014
				// 25 Days
2015
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2016
				$need_update = false;
2017
				/* Update IPv4 if we have it. */
2018
				if (is_ipaddrv4($wanip)) {
2019
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2020
						if (isset($dnsupdate['usepublicip'])) {
2021
							$wanip = dyndnsCheckIP($dnsupdate['interface']);
2022
						}
2023
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2024
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2025
						$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";
2026
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2027
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2028
						$need_update = true;
2029
					} else {
2030
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2031
					}
2032
				} else
2033
					@unlink($cacheFile);
2034

    
2035
				/* Update IPv6 if we have it. */
2036
				if (is_ipaddrv6($wanipv6)) {
2037
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2038
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2039
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2040
						$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";
2041
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2042
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2043
						$need_update = true;
2044
					} else {
2045
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2046
					}
2047
				} else
2048
					@unlink("{$cacheFile}.ipv6");
2049

    
2050
				$upinst .= "\n";	/* mind that trailing newline! */
2051

    
2052
				if ($need_update) {
2053
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2054
					unset($upinst);
2055
					/* invoke nsupdate */
2056
					$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2057
					if (isset($dnsupdate['usetcp']))
2058
						$cmd .= " -v";
2059
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2060
					mwexec_bg($cmd);
2061
					unset($cmd);
2062
				}
2063
			}
2064
		}
2065
		if (!empty($notify_text)) {
2066
			notify_all_remote($notify_text);
2067
		}
2068
	}
2069

    
2070
	return 0;
2071
}
2072

    
2073
/* configure cron service */
2074
function configure_cron() {
2075
	global $g, $config;
2076

    
2077
	conf_mount_rw();
2078
	/* preserve existing crontab entries */
2079
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2080

    
2081
	for ($i = 0; $i < count($crontab_contents); $i++) {
2082
		$cron_item =& $crontab_contents[$i];
2083
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2084
			array_splice($crontab_contents, $i - 1);
2085
			break;
2086
		}
2087
	}
2088
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2089

    
2090

    
2091
	if (is_array($config['cron']['item'])) {
2092
		$crontab_contents .= "#\n";
2093
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2094
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2095
		$crontab_contents .= "#\n";
2096

    
2097
		foreach ($config['cron']['item'] as $item) {
2098
			$crontab_contents .= "\n{$item['minute']}\t";
2099
			$crontab_contents .= "{$item['hour']}\t";
2100
			$crontab_contents .= "{$item['mday']}\t";
2101
			$crontab_contents .= "{$item['month']}\t";
2102
			$crontab_contents .= "{$item['wday']}\t";
2103
			$crontab_contents .= "{$item['who']}\t";
2104
			$crontab_contents .= "{$item['command']}";
2105
		}
2106

    
2107
		$crontab_contents .= "\n#\n";
2108
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2109
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2110
		$crontab_contents .= "#\n\n";
2111
	}
2112

    
2113
	/* please maintain the newline at the end of file */
2114
	file_put_contents("/etc/crontab", $crontab_contents);
2115
	unset($crontab_contents);
2116

    
2117
	/* do a HUP kill to force sync changes */
2118
	exec('/bin/pkill -HUP cron');
2119

    
2120
	conf_mount_ro();
2121
}
2122

    
2123
function upnp_action ($action) {
2124
	global $g, $config;
2125
	switch($action) {
2126
		case "start":
2127
			if (file_exists('/var/etc/miniupnpd.conf')) {
2128
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2129
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2130
			}
2131
			break;
2132
		case "stop":
2133
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2134
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2135
				mwexec('killall miniupnpd 2>/dev/null', true);
2136
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2137
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2138
			break;
2139
		case "restart":
2140
			upnp_action('stop');
2141
			upnp_action('start');
2142
			break;
2143
	}
2144
}
2145

    
2146
function upnp_start() {
2147
	global $config;
2148

    
2149
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2150
		return;
2151

    
2152
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2153
		echo gettext("Starting UPnP service... ");
2154
		require_once('/usr/local/pkg/miniupnpd.inc');
2155
		sync_package_miniupnpd();
2156
		echo "done.\n";
2157
	}
2158
}
2159

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

    
2163
	$is_installed = false;
2164

    
2165
	if (!is_array($config['cron']))
2166
		$config['cron'] = array();
2167
	if (!is_array($config['cron']['item']))
2168
		$config['cron']['item'] = array();
2169

    
2170
	$x=0;
2171
	foreach($config['cron']['item'] as $item) {
2172
		if(strstr($item['command'], $command)) {
2173
			$is_installed = true;
2174
			break;
2175
		}
2176
		$x++;
2177
	}
2178

    
2179
	if($active) {
2180
		$cron_item = array();
2181
		$cron_item['minute'] = $minute;
2182
		$cron_item['hour'] = $hour;
2183
		$cron_item['mday'] = $monthday;
2184
		$cron_item['month'] = $month;
2185
		$cron_item['wday'] = $weekday;
2186
		$cron_item['who'] = $who;
2187
		$cron_item['command'] = $command;
2188
		if(!$is_installed) {
2189
			$config['cron']['item'][] = $cron_item;
2190
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2191
		} else {
2192
			$config['cron']['item'][$x] = $cron_item;
2193
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2194
		}
2195
	} else {
2196
		if(($is_installed == true) && ($x > 0)) {
2197
			unset($config['cron']['item'][$x]);
2198
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2199
		}
2200
	}
2201
	configure_cron();
2202
}
2203

    
2204
?>
(49-49/66)