Project

General

Profile

Download (71.4 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
			if(is_array($config['virtualip']['vip'])) {
452
				foreach ($config['virtualip']['vip'] as $vipent) {
453
					if($vipent['subnet'] == $intip) {
454
						/* this is the interface! */
455
						if(is_numeric($vipent['advskew']) && ($vipent['advskew'] < "20"))
456
							$skew = 0;
457
					}
458
				}
459
			} else {
460
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IP's defined!"));
461
			}
462
			if($skew > 10) {
463
				$type = "secondary";
464
				$dhcpdconf_pri  = "mclt 600;\n";
465
				$my_port = "520";
466
				$peer_port = "519";
467
			} else {
468
				$my_port = "519";
469
				$peer_port = "520";
470
				$type = "primary";
471
				$dhcpdconf_pri  = "split 128;\n";
472
				$dhcpdconf_pri .= "  mclt 600;\n";
473
			}
474
			$dhcpdconf .= <<<EOPP
475
failover peer "dhcp_{$dhcpif}" {
476
  {$type};
477
  address {$intip};
478
  port {$my_port};
479
  peer address {$dhcpifconf['failover_peerip']};
480
  peer port {$peer_port};
481
  max-response-delay 10;
482
  max-unacked-updates 10;
483
  {$dhcpdconf_pri}
484
  load balance max seconds 3;
485
}
486

    
487
EOPP;
488
		}
489
	}
490

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

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

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

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

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

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

    
516
		$dnscfg = "";
517

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

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

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

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

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

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

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

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

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

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

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

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

    
620
			$pdnscfg = "";
621

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
750
EOD;
751

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

    
755
			$i = 0;
756
			foreach ($dhcpifconf['staticmap'] as $sm) {
757
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
758

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

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

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

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

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

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

    
782
				$smdnscfg = "";
783

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
897
	return 0;
898
}
899

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

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

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

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

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

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

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

    
943

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

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

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

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

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

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

    
1000
	$dhcpdv6conf = <<<EOD
1001

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

    
1014
EOD;
1015

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

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

    
1022
	$dhcpdv6ifs = array();
1023

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

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

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

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

    
1040
		$dnscfgv6 = "";
1041

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

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

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

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

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

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

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

    
1087
EOD;
1088

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1213
	return 0;
1214
}
1215

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

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

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

    
1225
        $iflist = get_configured_interface_list();
1226

    
1227
        $igmpconf = <<<EOD
1228

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

    
1234
EOD;
1235

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

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

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

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

    
1271
        return 0;
1272
}
1273

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

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

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

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

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

    
1297
	$iflist = get_configured_interface_list();
1298

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

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

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

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

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

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

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

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

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

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

    
1394
	return 0;
1395
}
1396

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

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

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

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

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

    
1420
	$iflist = get_configured_interface_list();
1421

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

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

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

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

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

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

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

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

    
1514
	return 0;
1515
}
1516

    
1517
function services_dyndns_configure_client($conf) {
1518

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

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

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

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

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

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

    
1570
		if ($g['booting'])
1571
			echo gettext("done.") . "\n";
1572
	}
1573

    
1574
	return 0;
1575
}
1576

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

    
1601
function services_dnsmasq_configure() {
1602
	global $config, $g;
1603
	$return = 0;
1604

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

    
1612

    
1613
	if(isset($config['system']['developerspew'])) {
1614
		$mt = microtime();
1615
		echo "services_dnsmasq_configure() being called $mt\n";
1616
	}
1617

    
1618
	/* kill any running dnsmasq */
1619
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1620
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1621

    
1622
	if (isset($config['dnsmasq']['enable'])) {
1623

    
1624
		if ($g['booting'])
1625
			echo gettext("Starting DNS forwarder...");
1626
		else
1627
			sleep(1);
1628

    
1629
		/* generate hosts file */
1630
		if(system_hosts_generate()!=0)
1631
			$return = 1;
1632

    
1633
		$args = "";
1634

    
1635
		if (isset($config['dnsmasq']['regdhcp'])) {
1636
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1637
		}
1638

    
1639
		/* Setup listen port, if non-default */
1640
		if (is_port($config['dnsmasq']['port']))
1641
			$args .= " --port={$config['dnsmasq']['port']} ";
1642

    
1643
		$listen_addresses = "";
1644
		if(isset($config['dnsmasq']['interface'])) {
1645
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1646
			foreach ($interfaces as $interface) {
1647
				if (is_ipaddrv4($interface)) {
1648
					$listen_addresses .= " --listen-address={$interface} ";
1649
				} else if (is_ipaddrv6($interface)) {
1650
					/*
1651
					 * XXX: Since dnsmasq does not support link-local address
1652
					 * with scope specified. These checks are being done.
1653
					 */
1654
					if (is_linklocal($interface) && strstr($interface, "%")) {
1655
						$tmpaddrll6 = explode("%", $interface);
1656
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1657
					} else 
1658
						$listen_addresses .= " --listen-address={$interface} ";
1659
				} else {
1660
					$if = get_real_interface($interface);
1661
					if (does_interface_exist($if)) {
1662
						$laddr = find_interface_ip($if);
1663
						if (is_ipaddrv4($laddr))
1664
							$listen_addresses .= " --listen-address={$laddr} ";
1665
						$laddr6 = find_interface_ipv6($if);
1666
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1667
							/*
1668
							 * XXX: Since dnsmasq does not support link-local address
1669
							 * with scope specified. These checks are being done.
1670
							 */
1671
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1672
								$tmpaddrll6 = explode("%", $laddr6);
1673
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1674
							} else
1675
								$listen_addresses .= " --listen-address={$laddr6} ";
1676
						}
1677
					}
1678
				}
1679
			}
1680
			if (!empty($listen_addresses)) {
1681
				$args .= " {$listen_addresses} ";
1682
				if (isset($config['dnsmasq']['strictbind']))
1683
					$args .= " --bind-interfaces ";
1684
			}
1685
		}
1686

    
1687
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1688
		/* If any of these are duplicated by a user-specified domain override (e.g. 10.in-addr.arpa) then */
1689
		/* the user-specified entry made later on the command line below will be the one that is effective. */
1690
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1691
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1692
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1693
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1694
			$args .= " --server=/10.in-addr.arpa/ ";
1695
			$args .= " --server=/168.192.in-addr.arpa/ ";
1696
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1697
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1698
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1699
			}
1700
		}
1701

    
1702
		/* Setup forwarded domains */
1703
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1704
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1705
				if ($override['ip'] == "!")
1706
					$override[ip] = "";
1707
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1708
			}
1709
		}
1710

    
1711
		/* Allow DNS Rebind for forwarded domains */
1712
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1713
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1714
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1715
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1716
				}
1717
			}
1718
		}
1719

    
1720
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1721
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1722

    
1723
		if (isset($config['dnsmasq']['strict_order'])) {
1724
			$args .= " --strict-order ";
1725
		}
1726

    
1727
		if (isset($config['dnsmasq']['domain_needed'])) {
1728
			$args .= " --domain-needed ";
1729
		}
1730

    
1731
		if ($config['dnsmasq']['custom_options'])
1732
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1733
				$args .= " --$c";
1734
				$p = explode('=', $c);
1735
				if (array_key_exists($p[0], $standard_args))
1736
					unset($standard_args[$p[0]]);
1737
			}
1738
		$args .= ' ' . implode(' ', array_values($standard_args));
1739

    
1740
		/* run dnsmasq */
1741
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1742
		//log_error("dnsmasq command: {$cmd}");
1743
		mwexec_bg($cmd);
1744
		unset($args);
1745

    
1746
		if ($g['booting'])
1747
			echo gettext("done.") . "\n";
1748
	}
1749

    
1750
	if (!$g['booting']) {
1751
		if(services_dhcpd_configure()!=0)
1752
			$return = 1;
1753
	}
1754

    
1755
	return $return;
1756
}
1757

    
1758
function services_snmpd_configure() {
1759
	global $config, $g;
1760
	if(isset($config['system']['developerspew'])) {
1761
		$mt = microtime();
1762
		echo "services_snmpd_configure() being called $mt\n";
1763
	}
1764

    
1765
	/* kill any running snmpd */
1766
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1767
	sleep(2);
1768
	if(is_process_running("bsnmpd"))
1769
		mwexec("/usr/bin/killall bsnmpd", true);
1770

    
1771
	if (isset($config['snmpd']['enable'])) {
1772

    
1773
		if ($g['booting'])
1774
			echo gettext("Starting SNMP daemon... ");
1775

    
1776
		/* generate snmpd.conf */
1777
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1778
		if (!$fd) {
1779
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1780
			return 1;
1781
		}
1782

    
1783

    
1784
		$snmpdconf = <<<EOD
1785
location := "{$config['snmpd']['syslocation']}"
1786
contact := "{$config['snmpd']['syscontact']}"
1787
read := "{$config['snmpd']['rocommunity']}"
1788

    
1789
EOD;
1790

    
1791
/* No docs on what write strings do there for disable for now.
1792
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1793
		    $snmpdconf .= <<<EOD
1794
# write string
1795
write := "{$config['snmpd']['rwcommunity']}"
1796

    
1797
EOD;
1798
		}
1799
*/
1800

    
1801

    
1802
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1803
		    $snmpdconf .= <<<EOD
1804
# SNMP Trap support.
1805
traphost := {$config['snmpd']['trapserver']}
1806
trapport := {$config['snmpd']['trapserverport']}
1807
trap := "{$config['snmpd']['trapstring']}"
1808

    
1809

    
1810
EOD;
1811
		}
1812

    
1813
		$version = trim(file_get_contents('/etc/version'));
1814
		$platform = trim(file_get_contents('/etc/platform'));
1815
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1816
			$platform = $g['product_name'];
1817
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1818
			" {$version} {$platform} " . php_uname("s") .
1819
			" " . php_uname("r") . " " . php_uname("m");
1820

    
1821
		$snmpdconf .= <<<EOD
1822
system := 1     # pfSense
1823
%snmpd
1824
sysDescr			= "{$sysDescr}"
1825
begemotSnmpdDebugDumpPdus       = 2
1826
begemotSnmpdDebugSyslogPri      = 7
1827
begemotSnmpdCommunityString.0.1 = $(read)
1828

    
1829
EOD;
1830

    
1831
/* No docs on what write strings do there for disable for now.
1832
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1833
		    $snmpdconf .= <<<EOD
1834
begemotSnmpdCommunityString.0.2 = $(write)
1835

    
1836
EOD;
1837
		}
1838
*/
1839

    
1840

    
1841
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1842
		    $snmpdconf .= <<<EOD
1843
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1844
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1845
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1846

    
1847
EOD;
1848
		}
1849

    
1850

    
1851
		$snmpdconf .= <<<EOD
1852
begemotSnmpdCommunityDisable    = 1
1853

    
1854
EOD;
1855

    
1856
		if (isset($config['snmpd']['bindlan'])) {
1857
			$config['snmpd']['bindip'] = 'lan';
1858
			unset($config['snmpd']['bindlan']);
1859
		}
1860
		$bind_to_ip = "0.0.0.0";
1861
		if(isset($config['snmpd']['bindip'])) {
1862
			if (is_ipaddr($config['snmpd']['bindip'])) {
1863
				$bind_to_ip = $config['snmpd']['bindip'];
1864
			} else {
1865
				$if = get_real_interface($config['snmpd']['bindip']);
1866
				if (does_interface_exist($if))
1867
					$bind_to_ip = find_interface_ip($if);
1868
			}
1869
		}
1870

    
1871
		if(is_port( $config['snmpd']['pollport'] )) {
1872
		    $snmpdconf .= <<<EOD
1873
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1874

    
1875
EOD;
1876

    
1877
		}
1878

    
1879
		$snmpdconf .= <<<EOD
1880
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1881
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1882

    
1883
# These are bsnmp macros not php vars.
1884
sysContact      = $(contact)
1885
sysLocation     = $(location)
1886
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1887

    
1888
snmpEnableAuthenTraps = 2
1889

    
1890
EOD;
1891

    
1892
		if (is_array( $config['snmpd']['modules'] )) {
1893
		    if(isset($config['snmpd']['modules']['mibii'])) {
1894
			$snmpdconf .= <<<EOD
1895
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1896

    
1897
EOD;
1898
		    }
1899

    
1900
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1901
			$snmpdconf .= <<<EOD
1902
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1903
%netgraph
1904
begemotNgControlNodeName = "snmpd"
1905

    
1906
EOD;
1907
		    }
1908

    
1909
		    if(isset($config['snmpd']['modules']['pf'])) {
1910
			$snmpdconf .= <<<EOD
1911
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1912

    
1913
EOD;
1914
		    }
1915

    
1916
		    if(isset($config['snmpd']['modules']['hostres'])) {
1917
			$snmpdconf .= <<<EOD
1918
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1919

    
1920
EOD;
1921
		    }
1922
		    if(isset($config['snmpd']['modules']['bridge'])) {
1923
			$snmpdconf .= <<<EOD
1924
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1925
# config must end with blank line
1926

    
1927
EOD;
1928
		    }
1929
			if(isset($config['snmpd']['modules']['ucd'])) {
1930
				$snmpdconf .= <<<EOD
1931
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
1932

    
1933
EOD;
1934
			}
1935
			if(isset($config['snmpd']['modules']['regex'])) {
1936
				$snmpdconf .= <<<EOD
1937
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
1938

    
1939
EOD;
1940
			}
1941
		}
1942

    
1943
		fwrite($fd, $snmpdconf);
1944
		fclose($fd);
1945
		unset($snmpdconf);
1946

    
1947
		if (isset($config['snmpd']['bindlan'])) {
1948
			$bindlan = "";
1949
		}
1950

    
1951
		/* run bsnmpd */
1952
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
1953
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
1954

    
1955
		if ($g['booting'])
1956
			echo gettext("done.") . "\n";
1957
	}
1958

    
1959
	return 0;
1960
}
1961

    
1962
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
1963
	global $config, $g;
1964
	if(isset($config['system']['developerspew'])) {
1965
		$mt = microtime();
1966
		echo "services_dnsupdate_process() being called $mt\n";
1967
	}
1968

    
1969
	/* Dynamic DNS updating active? */
1970
	if (is_array($config['dnsupdates']['dnsupdate'])) {
1971
		$notify_text = "";
1972
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
1973
			if (!isset($dnsupdate['enable']))
1974
				continue;
1975
			if (!empty($int) && $int != $dnsupdate['interface'])
1976
				continue;
1977
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
1978
				continue;
1979

    
1980
			/* determine interface name */
1981
			$if = get_real_interface($dnsupdate['interface']);
1982
			$wanip = get_interface_ip($dnsupdate['interface']);
1983
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
1984

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

    
1988
			if ($wanip || $wanipv6) {
1989
				$keyname = $dnsupdate['keyname'];
1990
				/* trailing dot */
1991
				if (substr($keyname, -1) != ".")
1992
					$keyname .= ".";
1993

    
1994
				$hostname = $dnsupdate['host'];
1995
				/* trailing dot */
1996
				if (substr($hostname, -1) != ".")
1997
					$hostname .= ".";
1998

    
1999
				/* write private key file
2000
				   this is dumb - public and private keys are the same for HMAC-MD5,
2001
				   but nsupdate insists on having both */
2002
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2003
				$privkey = <<<EOD
2004
Private-key-format: v1.2
2005
Algorithm: 157 (HMAC)
2006
Key: {$dnsupdate['keydata']}
2007

    
2008
EOD;
2009
				fwrite($fd, $privkey);
2010
				fclose($fd);
2011

    
2012
				/* write public key file */
2013
				if ($dnsupdate['keytype'] == "zone") {
2014
					$flags = 257;
2015
					$proto = 3;
2016
				} else if ($dnsupdate['keytype'] == "host") {
2017
					$flags = 513;
2018
					$proto = 3;
2019
				} else if ($dnsupdate['keytype'] == "user") {
2020
					$flags = 0;
2021
					$proto = 2;
2022
				}
2023

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

    
2028
				/* generate update instructions */
2029
				$upinst = "";
2030
				if (!empty($dnsupdate['server']))
2031
					$upinst .= "server {$dnsupdate['server']}\n";
2032

    
2033
				if (file_exists($cacheFile)) {
2034
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2035
				}
2036
				if (file_exists("{$cacheFile}.ipv6")) {
2037
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2038
				}
2039

    
2040
				// 25 Days
2041
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2042
				$need_update = false;
2043
				/* Update IPv4 if we have it. */
2044
				if (is_ipaddrv4($wanip)) {
2045
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2046
						if (isset($dnsupdate['usepublicip'])) {
2047
							$wanip = dyndnsCheckIP($dnsupdate['interface']);
2048
						}
2049
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2050
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2051
						$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";
2052
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2053
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2054
						$need_update = true;
2055
					} else {
2056
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2057
					}
2058
				} else
2059
					@unlink($cacheFile);
2060

    
2061
				/* Update IPv6 if we have it. */
2062
				if (is_ipaddrv6($wanipv6)) {
2063
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2064
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2065
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2066
						$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";
2067
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2068
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2069
						$need_update = true;
2070
					} else {
2071
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2072
					}
2073
				} else
2074
					@unlink("{$cacheFile}.ipv6");
2075

    
2076
				$upinst .= "\n";	/* mind that trailing newline! */
2077

    
2078
				if ($need_update) {
2079
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2080
					unset($upinst);
2081
					/* invoke nsupdate */
2082
					$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2083
					if (isset($dnsupdate['usetcp']))
2084
						$cmd .= " -v";
2085
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2086
					mwexec_bg($cmd);
2087
					unset($cmd);
2088
				}
2089
			}
2090
		}
2091
		if (!empty($notify_text)) {
2092
			notify_all_remote($notify_text);
2093
		}
2094
	}
2095

    
2096
	return 0;
2097
}
2098

    
2099
/* configure cron service */
2100
function configure_cron() {
2101
	global $g, $config;
2102

    
2103
	conf_mount_rw();
2104
	/* preserve existing crontab entries */
2105
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2106

    
2107
	for ($i = 0; $i < count($crontab_contents); $i++) {
2108
		$cron_item =& $crontab_contents[$i];
2109
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2110
			array_splice($crontab_contents, $i - 1);
2111
			break;
2112
		}
2113
	}
2114
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2115

    
2116

    
2117
	if (is_array($config['cron']['item'])) {
2118
		$crontab_contents .= "#\n";
2119
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2120
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2121
		$crontab_contents .= "#\n";
2122

    
2123
		foreach ($config['cron']['item'] as $item) {
2124
			$crontab_contents .= "\n{$item['minute']}\t";
2125
			$crontab_contents .= "{$item['hour']}\t";
2126
			$crontab_contents .= "{$item['mday']}\t";
2127
			$crontab_contents .= "{$item['month']}\t";
2128
			$crontab_contents .= "{$item['wday']}\t";
2129
			$crontab_contents .= "{$item['who']}\t";
2130
			$crontab_contents .= "{$item['command']}";
2131
		}
2132

    
2133
		$crontab_contents .= "\n#\n";
2134
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2135
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2136
		$crontab_contents .= "#\n\n";
2137
	}
2138

    
2139
	/* please maintain the newline at the end of file */
2140
	file_put_contents("/etc/crontab", $crontab_contents);
2141
	unset($crontab_contents);
2142

    
2143
	/* do a HUP kill to force sync changes */
2144
	exec('/bin/pkill -HUP cron');
2145

    
2146
	conf_mount_ro();
2147
}
2148

    
2149
function upnp_action ($action) {
2150
	global $g, $config;
2151
	switch($action) {
2152
		case "start":
2153
			if (file_exists('/var/etc/miniupnpd.conf')) {
2154
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2155
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2156
			}
2157
			break;
2158
		case "stop":
2159
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2160
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2161
				mwexec('killall miniupnpd 2>/dev/null', true);
2162
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2163
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2164
			break;
2165
		case "restart":
2166
			upnp_action('stop');
2167
			upnp_action('start');
2168
			break;
2169
	}
2170
}
2171

    
2172
function upnp_start() {
2173
	global $config;
2174

    
2175
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2176
		return;
2177

    
2178
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2179
		echo gettext("Starting UPnP service... ");
2180
		require_once('/usr/local/pkg/miniupnpd.inc');
2181
		sync_package_miniupnpd();
2182
		echo "done.\n";
2183
	}
2184
}
2185

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

    
2189
	$is_installed = false;
2190

    
2191
	if (!is_array($config['cron']))
2192
		$config['cron'] = array();
2193
	if (!is_array($config['cron']['item']))
2194
		$config['cron']['item'] = array();
2195

    
2196
	$x=0;
2197
	foreach($config['cron']['item'] as $item) {
2198
		if(strstr($item['command'], $command)) {
2199
			$is_installed = true;
2200
			break;
2201
		}
2202
		$x++;
2203
	}
2204

    
2205
	if($active) {
2206
		$cron_item = array();
2207
		$cron_item['minute'] = $minute;
2208
		$cron_item['hour'] = $hour;
2209
		$cron_item['mday'] = $monthday;
2210
		$cron_item['month'] = $month;
2211
		$cron_item['wday'] = $weekday;
2212
		$cron_item['who'] = $who;
2213
		$cron_item['command'] = $command;
2214
		if(!$is_installed) {
2215
			$config['cron']['item'][] = $cron_item;
2216
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2217
		} else {
2218
			$config['cron']['item'][$x] = $cron_item;
2219
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2220
		}
2221
	} else {
2222
		if(($is_installed == true) && ($x > 0)) {
2223
			unset($config['cron']['item'][$x]);
2224
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2225
		}
2226
	}
2227
	configure_cron();
2228
}
2229

    
2230
?>
(49-49/66)