Project

General

Profile

Download (70.5 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 cloudflare custom custom-v6 eurodns');
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');
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 .= "host s_{$dhcpif}_{$i} {\n";
759

    
760
                if ($sm['mac'])
761
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
762

    
763
                if ($sm['cid'])
764
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
765

    
766
				if ($sm['ipaddr'])
767
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
768

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

    
777
				if ($sm['rootpath'])
778
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
779

    
780
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
781
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
782

    
783
				$smdnscfg = "";
784

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

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

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

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

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

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

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

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

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

    
826
				$dhcpdconf .= "}\n";
827
				$i++;
828
			}
829
		}
830

    
831
		$dhcpdifs[] = get_real_interface($dhcpif);
832
		if ($newzone['domain-name'])
833
			$ddns_zones[] = $newzone;
834
	}
835

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

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

    
885
	/* create an empty leases database */
886
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
887
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
888

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

    
895
	if ($g['booting'])
896
		print "done.\n";
897

    
898
	return 0;
899
}
900

    
901
function services_dhcpdv6_configure() {
902
	global $config, $g;
903

    
904
	if($g['services_dhcp_server_enable'] == false)
905
		return;
906

    
907
	if(isset($config['system']['developerspew'])) {
908
		$mt = microtime();
909
		echo "services_dhcpd_configure($if) being called $mt\n";
910
	}
911

    
912
	/* kill any running dhcpd */
913
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
914
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
915
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
916
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
917

    
918
	/* DHCP enabled on any interfaces? */
919
	if (!is_dhcpv6_server_enabled())
920
		return 0;
921

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

    
937
	$syscfg = $config['system'];
938
	if (!is_array($config['dhcpdv6']))
939
		$config['dhcpdv6'] = array();
940
	$dhcpdv6cfg = $config['dhcpdv6'];
941
	$Iflist = get_configured_interface_list();
942
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
943

    
944

    
945
	if ($g['booting'])
946
		echo "Starting DHCPv6 service...";
947
	else
948
		sleep(1);
949

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

    
978
				/* set the delegation start to half the current address block */
979
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
980
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
981

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

    
986
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
987
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
988
			}
989
		}
990
	}
991

    
992
	$custoptionsv6 = "";
993
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
994
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
995
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
996
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
997
			}
998
		}
999
	}
1000

    
1001
	$dhcpdv6conf = <<<EOD
1002

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

    
1015
EOD;
1016

    
1017
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1018
		$dhcpdv6conf .= "authoritative;\n";
1019

    
1020
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1021
		$dhcpdv6conf .= "always-broadcast on\n";
1022

    
1023
	$dhcpdv6ifs = array();
1024

    
1025
	$dhcpv6num = 0;
1026
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1027

    
1028
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1029

    
1030
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
1031
			continue;
1032
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1033
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1034
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1035

    
1036
		if ($is_olsr_enabled == true) {
1037
			if($dhcpv6ifconf['netmask'])
1038
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1039
		}
1040

    
1041
		$dnscfgv6 = "";
1042

    
1043
		if ($dhcpv6ifconf['domain']) {
1044
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1045
		}
1046

    
1047
    		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1048
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1049
    		}
1050

    
1051
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1052
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1053
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1054
			}
1055
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1056
		}
1057

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

    
1073
		if (is_ipaddrv6($ifcfgipv6)) {
1074
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1075
		} else {
1076
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1077
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1078
		}
1079
		$dhcpdv6conf .= " {\n";
1080

    
1081
		if($dhcpv6ifconf['failover_peerip'] <> "")
1082
			$dhcpdv6conf .= "		deny dynamic bootp clients;\n";
1083

    
1084
		if (isset($dhcpv6ifconf['denyunknown']))
1085
		   $dhcpdv6conf .= "		deny unknown-clients;\n";
1086

    
1087
		$dhcpdv6conf .= <<<EOD
1088
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1089
$dnscfgv6
1090

    
1091
EOD;
1092

    
1093
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1094
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']}/{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1095
		}
1096
    		// default-lease-time
1097
		if ($dhcpv6ifconf['defaultleasetime'])
1098
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1099

    
1100
		// max-lease-time
1101
		if ($dhcpv6ifconf['maxleasetime'])
1102
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1103

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

    
1120
		// Handle option, number rowhelper values
1121
		$dhcpdv6conf .= "\n";
1122
		if ($dhcpv6ifconf['numberoptions']['item']) {
1123
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1124
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1125
			}
1126
		}
1127

    
1128
		// ldap-server
1129
		if ($dhcpv6ifconf['ldap'] <> "")
1130
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1131

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

    
1145
		$dhcpdv6conf .= "}\n";
1146

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

    
1156
EOD;
1157
				if ($sm['ipaddrv6'])
1158
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1159

    
1160
				if ($sm['hostname']) {
1161
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1162
					$dhhostname = str_replace(".", "_", $dhhostname);
1163
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1164
				}
1165
				if ($sm['filename'])
1166
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1167

    
1168
				if ($sm['rootpath'])
1169
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1170

    
1171
				$dhcpdv6conf .= "}\n";
1172
				$i++;
1173
			}
1174
		}
1175

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

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

    
1204
	/* create an empty leases v6 database */
1205
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1206
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1207

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

    
1217
	return 0;
1218
}
1219

    
1220
function services_igmpproxy_configure() {
1221
        global $config, $g;
1222

    
1223
        /* kill any running igmpproxy */
1224
        killbyname("igmpproxy");
1225

    
1226
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1227
		return 1;
1228

    
1229
        $iflist = get_configured_interface_list();
1230

    
1231
        $igmpconf = <<<EOD
1232

    
1233
##------------------------------------------------------
1234
## Enable Quickleave mode (Sends Leave instantly)
1235
##------------------------------------------------------
1236
quickleave
1237

    
1238
EOD;
1239

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

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

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

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

    
1275
        return 0;
1276
}
1277

    
1278
function services_dhcrelay_configure() {
1279
	global $config, $g;
1280
	if ($g['platform'] == 'jail')
1281
		return;
1282
	if(isset($config['system']['developerspew'])) {
1283
		$mt = microtime();
1284
		echo "services_dhcrelay_configure() being called $mt\n";
1285
	}
1286

    
1287
	/* kill any running dhcrelay */
1288
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1289

    
1290
	$dhcrelaycfg =& $config['dhcrelay'];
1291

    
1292
	/* DHCPRelay enabled on any interfaces? */
1293
	if (!isset($dhcrelaycfg['enable']))
1294
		return 0;
1295

    
1296
	if ($g['booting'])
1297
		echo gettext("Starting DHCP relay service...");
1298
	else
1299
		sleep(1);
1300

    
1301
	$iflist = get_configured_interface_list();
1302

    
1303
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1304
	foreach ($dhcifaces as $dhcrelayif) {
1305
		if (!isset($iflist[$dhcrelayif]) ||
1306
			link_interface_to_bridge($dhcrelayif))
1307
			continue;
1308

    
1309
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1310
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1311
	}
1312

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

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

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

    
1378
		if (!empty($destif))
1379
			$dhcrelayifs[] = $destif;
1380
	}
1381
	$dhcrelayifs = array_unique($dhcrelayifs);
1382

    
1383
	/* fire up dhcrelay */
1384
	if (empty($dhcrelayifs)) {
1385
		log_error("No suitable interface found for running dhcrelay!");
1386
		return; /* XXX */
1387
	}
1388

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

    
1391
	if (isset($dhcrelaycfg['agentoption']))
1392
		$cmd .=  " -a -m replace";
1393

    
1394
	$cmd .= " " . implode(" ", $srvips);
1395
	mwexec($cmd);
1396
	unset($cmd);
1397

    
1398
	return 0;
1399
}
1400

    
1401
function services_dhcrelay6_configure() {
1402
	global $config, $g;
1403
	if ($g['platform'] == 'jail')
1404
		return;
1405
	if(isset($config['system']['developerspew'])) {
1406
		$mt = microtime();
1407
		echo "services_dhcrelay6_configure() being called $mt\n";
1408
	}
1409

    
1410
	/* kill any running dhcrelay */
1411
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1412

    
1413
	$dhcrelaycfg =& $config['dhcrelay6'];
1414

    
1415
	/* DHCPv6 Relay enabled on any interfaces? */
1416
	if (!isset($dhcrelaycfg['enable']))
1417
		return 0;
1418

    
1419
	if ($g['booting'])
1420
		echo gettext("Starting DHCPv6 relay service...");
1421
	else
1422
		sleep(1);
1423

    
1424
	$iflist = get_configured_interface_list();
1425

    
1426
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1427
	foreach ($dhcifaces as $dhcrelayif) {
1428
		if (!isset($iflist[$dhcrelayif]) ||
1429
			link_interface_to_bridge($dhcrelayif))
1430
			continue;
1431

    
1432
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1433
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1434
	}
1435
	$dhcrelayifs = array_unique($dhcrelayifs);
1436

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

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

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

    
1497
		if (!empty($destif)) {
1498
			$srvifaces[] = "{$srvip}%{$destif}";
1499
		}
1500
	}
1501

    
1502
	/* fire up dhcrelay */
1503
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1504
		log_error("No suitable interface found for running dhcrelay -6!");
1505
		return; /* XXX */
1506
	}
1507

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

    
1518
	return 0;
1519
}
1520

    
1521
function services_dyndns_configure_client($conf) {
1522

    
1523
	if (!isset($conf['enable']))
1524
		return;
1525

    
1526
	/* load up the dyndns.class */
1527
	require_once("dyndns.class");
1528

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

    
1551
function services_dyndns_configure($int = "") {
1552
	global $config, $g;
1553
	if(isset($config['system']['developerspew'])) {
1554
		$mt = microtime();
1555
		echo "services_dyndns_configure() being called $mt\n";
1556
	}
1557

    
1558
	$dyndnscfg = $config['dyndnses']['dyndns'];
1559
	$gwgroups = return_gateway_groups_array();
1560
	if (is_array($dyndnscfg)) {
1561
		if ($g['booting'])
1562
			echo gettext("Starting DynDNS clients...");
1563

    
1564
		foreach ($dyndnscfg as $dyndns) {
1565
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1566
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1567
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1568
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1569
				services_dyndns_configure_client($dyndns);
1570
				sleep(1);
1571
			}
1572
		}
1573

    
1574
		if ($g['booting'])
1575
			echo gettext("done.") . "\n";
1576
	}
1577

    
1578
	return 0;
1579
}
1580

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

    
1605
function services_dnsmasq_configure() {
1606
	global $config, $g;
1607
	$return = 0;
1608

    
1609
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1610
	$standard_args = array(
1611
		"dns-forward-max" => "--dns-forward-max=5000",
1612
		"cache-size" => "--cache-size=10000",
1613
		"local-ttl" => "--local-ttl=1"
1614
	);
1615

    
1616

    
1617
	if(isset($config['system']['developerspew'])) {
1618
		$mt = microtime();
1619
		echo "services_dnsmasq_configure() being called $mt\n";
1620
	}
1621

    
1622
	/* kill any running dnsmasq */
1623
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1624
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1625

    
1626
	if (isset($config['dnsmasq']['enable'])) {
1627

    
1628
		if ($g['booting'])
1629
			echo gettext("Starting DNS forwarder...");
1630
		else
1631
			sleep(1);
1632

    
1633
		/* generate hosts file */
1634
		if(system_hosts_generate()!=0)
1635
			$return = 1;
1636

    
1637
		$args = "";
1638

    
1639
		if (isset($config['dnsmasq']['regdhcp'])) {
1640
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1641
		}
1642

    
1643
		/* Setup listen port, if non-default */
1644
		if (is_port($config['dnsmasq']['port']))
1645
			$args .= " --port={$config['dnsmasq']['port']} ";
1646

    
1647
		$listen_addresses = "";
1648
		if(isset($config['dnsmasq']['interface'])) {
1649
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1650
			foreach ($interfaces as $interface) {
1651
				if (is_ipaddr($interface)) {
1652
					$listen_addresses .= " --listen-address={$interface} ";
1653
				} else {
1654
					$if = get_real_interface($interface);
1655
					if (does_interface_exist($if)) {
1656
						$laddr = find_interface_ip($if);
1657
						if (is_ipaddrv4($laddr))
1658
							$listen_addresses .= " --listen-address={$laddr} ";
1659
						$laddr6 = find_interface_ipv6($if);
1660
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind']))
1661
							$listen_addresses .= " --listen-address={$laddr6} ";
1662
					}
1663
				}
1664
			}
1665
			if (!empty($listen_addresses)) {
1666
				$args .= " {$listen_addresses} ";
1667
				if (isset($config['dnsmasq']['strictbind']))
1668
					$args .= " --bind-interfaces ";
1669
			}
1670
		}
1671

    
1672
		/* Setup forwarded domains */
1673
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1674
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1675
				if ($override['ip'] == "!")
1676
					$override[ip] = "";
1677
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1678
			}
1679
		}
1680

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

    
1694
		/* Allow DNS Rebind for forwarded domains */
1695
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1696
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1697
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1698
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1699
				}
1700
			}
1701
		}
1702

    
1703
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1704
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1705

    
1706
		if (isset($config['dnsmasq']['strict_order'])) {
1707
			$args .= " --strict-order ";
1708
		}
1709

    
1710
		if (isset($config['dnsmasq']['domain_needed'])) {
1711
			$args .= " --domain-needed ";
1712
		}
1713

    
1714
		if ($config['dnsmasq']['custom_options'])
1715
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1716
				$args .= " --$c";
1717
				$p = explode('=', $c);
1718
				if (array_key_exists($p[0], $standard_args))
1719
					unset($standard_args[$p[0]]);
1720
			}
1721
		$args .= ' ' . implode(' ', array_values($standard_args));
1722

    
1723
		/* run dnsmasq */
1724
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1725
		//log_error("dnsmasq command: {$cmd}");
1726
		mwexec_bg($cmd);
1727
		unset($args);
1728

    
1729
		if ($g['booting'])
1730
			echo gettext("done.") . "\n";
1731
	}
1732

    
1733
	if (!$g['booting']) {
1734
		if(services_dhcpd_configure()!=0)
1735
			$return = 1;
1736
	}
1737

    
1738
	return $return;
1739
}
1740

    
1741
function services_snmpd_configure() {
1742
	global $config, $g;
1743
	if(isset($config['system']['developerspew'])) {
1744
		$mt = microtime();
1745
		echo "services_snmpd_configure() being called $mt\n";
1746
	}
1747

    
1748
	/* kill any running snmpd */
1749
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1750
	sleep(2);
1751
	if(is_process_running("bsnmpd"))
1752
		mwexec("/usr/bin/killall bsnmpd", true);
1753

    
1754
	if (isset($config['snmpd']['enable'])) {
1755

    
1756
		if ($g['booting'])
1757
			echo gettext("Starting SNMP daemon... ");
1758

    
1759
		/* generate snmpd.conf */
1760
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1761
		if (!$fd) {
1762
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1763
			return 1;
1764
		}
1765

    
1766

    
1767
		$snmpdconf = <<<EOD
1768
location := "{$config['snmpd']['syslocation']}"
1769
contact := "{$config['snmpd']['syscontact']}"
1770
read := "{$config['snmpd']['rocommunity']}"
1771

    
1772
EOD;
1773

    
1774
/* No docs on what write strings do there for disable for now.
1775
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1776
		    $snmpdconf .= <<<EOD
1777
# write string
1778
write := "{$config['snmpd']['rwcommunity']}"
1779

    
1780
EOD;
1781
		}
1782
*/
1783

    
1784

    
1785
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1786
		    $snmpdconf .= <<<EOD
1787
# SNMP Trap support.
1788
traphost := {$config['snmpd']['trapserver']}
1789
trapport := {$config['snmpd']['trapserverport']}
1790
trap := "{$config['snmpd']['trapstring']}"
1791

    
1792

    
1793
EOD;
1794
		}
1795

    
1796
		$version = trim(file_get_contents('/etc/version'));
1797
		$platform = trim(file_get_contents('/etc/platform'));
1798
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1799
			$platform = $g['product_name'];
1800
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1801
			" {$version} {$platform} " . php_uname("s") .
1802
			" " . php_uname("r") . " " . php_uname("m");
1803

    
1804
		$snmpdconf .= <<<EOD
1805
system := 1     # pfSense
1806
%snmpd
1807
sysDescr			= "{$sysDescr}"
1808
begemotSnmpdDebugDumpPdus       = 2
1809
begemotSnmpdDebugSyslogPri      = 7
1810
begemotSnmpdCommunityString.0.1 = $(read)
1811

    
1812
EOD;
1813

    
1814
/* No docs on what write strings do there for disable for now.
1815
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1816
		    $snmpdconf .= <<<EOD
1817
begemotSnmpdCommunityString.0.2 = $(write)
1818

    
1819
EOD;
1820
		}
1821
*/
1822

    
1823

    
1824
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1825
		    $snmpdconf .= <<<EOD
1826
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1827
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1828
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1829

    
1830
EOD;
1831
		}
1832

    
1833

    
1834
		$snmpdconf .= <<<EOD
1835
begemotSnmpdCommunityDisable    = 1
1836

    
1837
EOD;
1838

    
1839
		if (isset($config['snmpd']['bindlan'])) {
1840
			$config['snmpd']['bindip'] = 'lan';
1841
			unset($config['snmpd']['bindlan']);
1842
		}
1843
		$bind_to_ip = "0.0.0.0";
1844
		if(isset($config['snmpd']['bindip'])) {
1845
			if (is_ipaddr($config['snmpd']['bindip'])) {
1846
				$bind_to_ip = $config['snmpd']['bindip'];
1847
			} else {
1848
				$if = get_real_interface($config['snmpd']['bindip']);
1849
				if (does_interface_exist($if))
1850
					$bind_to_ip = find_interface_ip($if);
1851
			}
1852
		}
1853

    
1854
		if(is_port( $config['snmpd']['pollport'] )) {
1855
		    $snmpdconf .= <<<EOD
1856
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1857

    
1858
EOD;
1859

    
1860
		}
1861

    
1862
		$snmpdconf .= <<<EOD
1863
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1864
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1865

    
1866
# These are bsnmp macros not php vars.
1867
sysContact      = $(contact)
1868
sysLocation     = $(location)
1869
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1870

    
1871
snmpEnableAuthenTraps = 2
1872

    
1873
EOD;
1874

    
1875
		if (is_array( $config['snmpd']['modules'] )) {
1876
		    if(isset($config['snmpd']['modules']['mibii'])) {
1877
			$snmpdconf .= <<<EOD
1878
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1879

    
1880
EOD;
1881
		    }
1882

    
1883
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1884
			$snmpdconf .= <<<EOD
1885
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1886
%netgraph
1887
begemotNgControlNodeName = "snmpd"
1888

    
1889
EOD;
1890
		    }
1891

    
1892
		    if(isset($config['snmpd']['modules']['pf'])) {
1893
			$snmpdconf .= <<<EOD
1894
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1895

    
1896
EOD;
1897
		    }
1898

    
1899
		    if(isset($config['snmpd']['modules']['hostres'])) {
1900
			$snmpdconf .= <<<EOD
1901
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1902

    
1903
EOD;
1904
		    }
1905
		    if(isset($config['snmpd']['modules']['bridge'])) {
1906
			$snmpdconf .= <<<EOD
1907
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1908
# config must end with blank line
1909

    
1910
EOD;
1911
		    }
1912
			if(isset($config['snmpd']['modules']['ucd'])) {
1913
				$snmpdconf .= <<<EOD
1914
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
1915

    
1916
EOD;
1917
			}
1918
			if(isset($config['snmpd']['modules']['regex'])) {
1919
				$snmpdconf .= <<<EOD
1920
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
1921

    
1922
EOD;
1923
			}
1924
		}
1925

    
1926
		fwrite($fd, $snmpdconf);
1927
		fclose($fd);
1928
		unset($snmpdconf);
1929

    
1930
		if (isset($config['snmpd']['bindlan'])) {
1931
			$bindlan = "";
1932
		}
1933

    
1934
		/* run bsnmpd */
1935
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
1936
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
1937

    
1938
		if ($g['booting'])
1939
			echo gettext("done.") . "\n";
1940
	}
1941

    
1942
	return 0;
1943
}
1944

    
1945
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
1946
	global $config, $g;
1947
	if(isset($config['system']['developerspew'])) {
1948
		$mt = microtime();
1949
		echo "services_dnsupdate_process() being called $mt\n";
1950
	}
1951

    
1952
	/* Dynamic DNS updating active? */
1953
	if (is_array($config['dnsupdates']['dnsupdate'])) {
1954
		$notify_text = "";
1955
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
1956
			if (!isset($dnsupdate['enable']))
1957
				continue;
1958
			if (!empty($int) && $int != $dnsupdate['interface'])
1959
				continue;
1960
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
1961
				continue;
1962

    
1963
			/* determine interface name */
1964
			$if = get_real_interface($dnsupdate['interface']);
1965
			$wanip = get_interface_ip($dnsupdate['interface']);
1966
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
1967

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

    
1971
			if ($wanip || $wanipv6) {
1972
				$keyname = $dnsupdate['keyname'];
1973
				/* trailing dot */
1974
				if (substr($keyname, -1) != ".")
1975
					$keyname .= ".";
1976

    
1977
				$hostname = $dnsupdate['host'];
1978
				/* trailing dot */
1979
				if (substr($hostname, -1) != ".")
1980
					$hostname .= ".";
1981

    
1982
				/* write private key file
1983
				   this is dumb - public and private keys are the same for HMAC-MD5,
1984
				   but nsupdate insists on having both */
1985
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
1986
				$privkey = <<<EOD
1987
Private-key-format: v1.2
1988
Algorithm: 157 (HMAC)
1989
Key: {$dnsupdate['keydata']}
1990

    
1991
EOD;
1992
				fwrite($fd, $privkey);
1993
				fclose($fd);
1994

    
1995
				/* write public key file */
1996
				if ($dnsupdate['keytype'] == "zone") {
1997
					$flags = 257;
1998
					$proto = 3;
1999
				} else if ($dnsupdate['keytype'] == "host") {
2000
					$flags = 513;
2001
					$proto = 3;
2002
				} else if ($dnsupdate['keytype'] == "user") {
2003
					$flags = 0;
2004
					$proto = 2;
2005
				}
2006

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

    
2011
				/* generate update instructions */
2012
				$upinst = "";
2013
				if (!empty($dnsupdate['server']))
2014
					$upinst .= "server {$dnsupdate['server']}\n";
2015

    
2016
				if (file_exists($cacheFile)) {
2017
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2018
				}
2019
				if (file_exists("{$cacheFile}.ipv6")) {
2020
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2021
				}
2022

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

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

    
2059
				$upinst .= "\n";	/* mind that trailing newline! */
2060

    
2061
				if ($need_update) {
2062
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2063
					unset($upinst);
2064
					/* invoke nsupdate */
2065
					$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2066
					if (isset($dnsupdate['usetcp']))
2067
						$cmd .= " -v";
2068
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2069
					mwexec_bg($cmd);
2070
					unset($cmd);
2071
				}
2072
			}
2073
		}
2074
		if (!empty($notify_text)) {
2075
			notify_all_remote($notify_text);
2076
		}
2077
	}
2078

    
2079
	return 0;
2080
}
2081

    
2082
/* configure cron service */
2083
function configure_cron() {
2084
	global $g, $config;
2085

    
2086
	conf_mount_rw();
2087
	/* preserve existing crontab entries */
2088
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2089

    
2090
	for ($i = 0; $i < count($crontab_contents); $i++) {
2091
		$cron_item =& $crontab_contents[$i];
2092
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2093
			array_splice($crontab_contents, $i - 1);
2094
			break;
2095
		}
2096
	}
2097
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2098

    
2099

    
2100
	if (is_array($config['cron']['item'])) {
2101
		$crontab_contents .= "#\n";
2102
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2103
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2104
		$crontab_contents .= "#\n";
2105

    
2106
		foreach ($config['cron']['item'] as $item) {
2107
			$crontab_contents .= "\n{$item['minute']}\t";
2108
			$crontab_contents .= "{$item['hour']}\t";
2109
			$crontab_contents .= "{$item['mday']}\t";
2110
			$crontab_contents .= "{$item['month']}\t";
2111
			$crontab_contents .= "{$item['wday']}\t";
2112
			$crontab_contents .= "{$item['who']}\t";
2113
			$crontab_contents .= "{$item['command']}";
2114
		}
2115

    
2116
		$crontab_contents .= "\n#\n";
2117
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2118
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2119
		$crontab_contents .= "#\n\n";
2120
	}
2121

    
2122
	/* please maintain the newline at the end of file */
2123
	file_put_contents("/etc/crontab", $crontab_contents);
2124
	unset($crontab_contents);
2125

    
2126
	/* do a HUP kill to force sync changes */
2127
	exec('/bin/pkill -HUP cron');
2128

    
2129
	conf_mount_ro();
2130
}
2131

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

    
2155
function upnp_start() {
2156
	global $config;
2157

    
2158
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2159
		return;
2160

    
2161
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2162
		echo gettext("Starting UPnP service... ");
2163
		require_once('/usr/local/pkg/miniupnpd.inc');
2164
		sync_package_miniupnpd();
2165
		echo "done.\n";
2166
	}
2167
}
2168

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

    
2172
	$is_installed = false;
2173

    
2174
	if (!is_array($config['cron']))
2175
		$config['cron'] = array();
2176
	if (!is_array($config['cron']['item']))
2177
		$config['cron']['item'] = array();
2178

    
2179
	$x=0;
2180
	foreach($config['cron']['item'] as $item) {
2181
		if(strstr($item['command'], $command)) {
2182
			$is_installed = true;
2183
			break;
2184
		}
2185
		$x++;
2186
	}
2187

    
2188
	if($active) {
2189
		$cron_item = array();
2190
		$cron_item['minute'] = $minute;
2191
		$cron_item['hour'] = $hour;
2192
		$cron_item['mday'] = $monthday;
2193
		$cron_item['month'] = $month;
2194
		$cron_item['wday'] = $weekday;
2195
		$cron_item['who'] = $who;
2196
		$cron_item['command'] = $command;
2197
		if(!$is_installed) {
2198
			$config['cron']['item'][] = $cron_item;
2199
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2200
		} else {
2201
			$config['cron']['item'][$x] = $cron_item;
2202
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2203
		}
2204
	} else {
2205
		if(($is_installed == true) && ($x > 0)) {
2206
			unset($config['cron']['item'][$x]);
2207
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2208
		}
2209
	}
2210
	configure_cron();
2211
}
2212

    
2213
?>
(49-49/66)