Project

General

Profile

Download (65.6 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/sbin/arp	/sbin/ifconfig	/usr/local/sbin/dnsmasq
36
	pfSense_BUILDER_BINARIES:	/usr/sbin/bsnmpd	/sbin/route
37
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/miniupnpd	/usr/sbin/radvd
38
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcleases6
39
	pfSense_MODULE:	utils
40
*/
41

    
42
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-tunnelbroker selfhost route53 custom');
43
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 Tunnelbroker,SelfHost,Route 53,Custom');
44

    
45
/* implement ipv6 route advertising deamon */
46
function services_radvd_configure() {
47
	global $config, $g;
48
	
49
	if ($g['platform'] == 'jail') 
50
		return;
51

    
52
	if(isset($config['system']['developerspew'])) {
53
		$mt = microtime();
54
		echo "services_radvd_configure() being called $mt\n";
55
	}
56

    
57
	if (!is_array($config['dhcpdv6']))
58
		$config['dhcpdv6'] = array();
59

    
60
	$Iflist = get_configured_interface_list();
61
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
62
	$carplist = get_configured_carp_interface_list();
63

    
64
	$radvdconf = "# Automatically Generated, do not edit\n";
65

    
66
	/* Process all links which need the router advertise daemon */
67
	$radvdifs = array();
68

    
69
	/* handle manually configured DHCP6 server settings first */
70
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
71
		if (!is_array($config['interfaces'][$dhcpv6if]))
72
			continue;
73
		if (!isset($config['interfaces'][$dhcpv6if]['enable']))
74
			continue;
75

    
76
		if (!isset($dhcpv6ifconf['ramode']))
77
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
78

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

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

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

    
96
		$realif = get_real_interface($dhcpv6if);
97
		if (in_array($realif, $radvdifs))
98
			continue;
99
		$radvdifs[] = $realif;
100

    
101
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
102
		if (!is_ipaddrv6($ifcfgipv6))
103
			continue;
104

    
105
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
106
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
107

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

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

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

    
209
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
210
	foreach ($Iflist as $if => $ifdescr) {
211
		if(!isset($config['interfaces'][$if]['track6-interface']))
212
			continue;
213
		if(!isset($config['interfaces'][$if]['enable']))
214
			continue;
215
			
216
		$realif = get_real_interface($if);
217
		/* prevent duplicate entries, manual overrides */
218
		if(in_array($realif, $radvdifs))
219
			continue;
220

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

    
225
		$ifcfgsnv6 = get_interface_subnetv6($if);
226
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
227
		$trackif = $config['interfaces'][$if]['track6-interface'];
228
		if (empty($config['interfaces'][$trackif]))
229
			continue;
230
		$radvdifs[] = $realif;
231

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

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

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

    
278
	/* write radvd.conf */
279
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
280
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
281
		if ($g['booting'])
282
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
283
	}
284
	unset($radvdconf);
285

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

    
303
function services_dhcpd_configure($family = "all") {
304
	global $config, $g;
305

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

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

    
328
	if ($family == "all" || $family == "inet")
329
		services_dhcpdv4_configure();
330
	if ($family == "all" || $family == "inet6") {
331
		services_dhcpdv6_configure();
332
		services_radvd_configure();
333
	}
334
}
335

    
336
function services_dhcpdv4_configure() {
337
	global $config, $g;
338

    
339
	if($g['services_dhcp_server_enable'] == false)
340
		return;
341

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

    
347
	/* kill any running dhcpd */
348
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
349
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
350
	else
351
		mwexec("/usr/bin/killall dhcpd", true);
352

    
353
	/* DHCP enabled on any interfaces? */
354
	if (!is_dhcp_server_enabled())
355
		return 0;
356

    
357
	/* if OLSRD is enabled, allow WAN to house DHCP. */
358
	if($config['installedpackages']['olsrd'])
359
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
360
				if($olsrd['enable'])
361
					$is_olsr_enabled = true;
362

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

    
380
	$syscfg = $config['system'];
381
	if (!is_array($config['dhcpd']))
382
		$config['dhcpd'] = array();
383
	$dhcpdcfg = $config['dhcpd'];
384
	$Iflist = get_configured_interface_list();
385

    
386
	if ($g['booting'])
387
		echo gettext("Starting DHCP service...");
388
	else
389
		sleep(1);
390

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

    
404
	$dhcpdconf = <<<EOD
405

    
406
option domain-name "{$syscfg['domain']}";
407
option ldap-server code 95 = text;
408
option domain-search-list code 119 = text;
409
{$custoptions}
410
default-lease-time 7200;
411
max-lease-time 86400;
412
log-facility local7;
413
ddns-update-style none;
414
one-lease-per-client true;
415
deny duplicates;
416
ping-check true;
417

    
418
EOD;
419

    
420
	if(!isset($dhcpifconf['disableauthoritative']))
421
		$dhcpdconf .= "authoritative;\n";
422

    
423
	if(isset($dhcpifconf['alwaysbroadcast']))
424
		$dhcpdconf .= "always-broadcast on\n";
425

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

    
438
	/*    loop through and determine if we need to setup
439
	 *    failover peer "bleh" entries
440
	 */
441
	$dhcpnum = 0;
442
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
443

    
444
		interfaces_staticarp_configure($dhcpif);
445

    
446
		if (!isset($dhcpifconf['enable']))
447
			continue;
448

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

    
495
EOPP;
496
		$dhcpnum++;
497
		}
498
	}
499

    
500
	$dhcpnum = 0;
501

    
502
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
503

    
504
		$ifcfg = $config['interfaces'][$dhcpif];
505

    
506
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
507
			continue;
508
		$ifcfgip = get_interface_ip($dhcpif);
509
		$ifcfgsn = get_interface_subnet($dhcpif);
510
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
511
		$subnetmask = gen_subnet_mask($ifcfgsn);
512

    
513
		if (!is_ipaddr($subnet))
514
			continue;
515

    
516
		if($is_olsr_enabled == true)
517
			if($dhcpifconf['netmask'])
518
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
519

    
520
		$all_pools = array();
521
		$all_pools[] = $dhcpifconf;
522
		if (is_array($dhcpifconf['pool'])) {
523
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
524
		}
525

    
526
		$dnscfg = "";
527

    
528
		if ($dhcpifconf['domain']) {
529
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
530
		}
531

    
532
		if($dhcpifconf['domainsearchlist'] <> "") {
533
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
534
		}
535

    
536
		if (isset($dhcpifconf['ddnsupdate'])) {
537
			if($dhcpifconf['ddnsdomain'] <> "") {
538
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
539
			}
540
			$dnscfg .= "	ddns-update-style interim;\n";
541
		}
542

    
543
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
544
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
545
		} else if (isset($config['dnsmasq']['enable'])) {
546
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
547
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
548
			$dnscfg .= "	option domain-name-servers " . join(",", $syscfg['dnsserver']) . ";";
549
		}
550

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

    
572
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
573

    
574
// Setup pool options
575
		foreach($all_pools as $poolconf) {
576
			$dhcpdconf .= "	pool {\n";
577
			/* is failover dns setup? */
578
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
579
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
580
				if($poolconf['dnsserver'][1] <> "")
581
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
582
				$dhcpdconf .= ";\n";
583
			}
584

    
585
			/* allow/deny MACs */
586
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
587
			foreach ($mac_allow_list as $mac) {
588
				if (empty($mac))
589
					continue;
590
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
591
			}
592
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
593
			foreach ($mac_deny_list as $mac) {
594
				if (empty($mac))
595
					continue;
596
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
597
			}
598

    
599
			if($poolconf['failover_peerip'] <> "")
600
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
601

    
602
			if (isset($poolconf['denyunknown']))
603
			   $dhcpdconf .= "		deny unknown-clients;\n";
604

    
605
			if ($poolconf['gateway'] && ($poolconf['gateway'] != $dhcpifconf['gateway']))
606
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
607

    
608
			if($dhcpifconf['failover_peerip'] <> "") {
609
				$dhcpdconf .= "		failover peer \"dhcp{$dhcpnum}\";\n";
610
				$dhcpnum++;
611
			}
612

    
613
			$pdnscfg = "";
614

    
615
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
616
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
617
			}
618

    
619
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
620
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
621
			}
622

    
623
			if (isset($poolconf['ddnsupdate'])) {
624
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
625
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
626
				$pdnscfg .= "		ddns-update-style interim;\n";
627
			}
628

    
629
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
630
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
631
			}
632
			$dhcpdconf .= "{$pdnscfg}";
633

    
634
			// default-lease-time
635
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
636
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
637

    
638
			// max-lease-time
639
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
640
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
641

    
642
			// netbios-name*
643
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
644
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
645
				$dhcpdconf .= "		option netbios-node-type 8;\n";
646
			}
647

    
648
			// ntp-servers
649
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
650
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
651

    
652
			// tftp-server-name
653
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
654
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
655

    
656
			// ldap-server
657
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
658
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
659

    
660
			// net boot information
661
			if(isset($poolconf['netboot'])) {
662
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
663
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
664
				}
665
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
666
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
667
				}
668
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
669
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
670
				}
671
			}
672
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
673
			$dhcpdconf .= "	}\n\n";
674
		}
675
// End of settings inside pools
676

    
677
		if ($dhcpifconf['gateway']) {
678
			$routers = $dhcpifconf['gateway'];
679
			$add_routers = true;
680
		} else {
681
			$routers = $ifcfgip;
682
		}
683
		if($add_routers)
684
			$dhcpdconf .= "	option routers {$routers};\n";
685

    
686
		$dhcpdconf .= <<<EOD
687
$dnscfg
688

    
689
EOD;
690
    		// default-lease-time
691
		if ($dhcpifconf['defaultleasetime'])
692
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
693

    
694
		// max-lease-time
695
		if ($dhcpifconf['maxleasetime'])
696
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
697

    
698
		// netbios-name*
699
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
700
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
701
			$dhcpdconf .= "	option netbios-node-type 8;\n";
702
		}
703

    
704
		// ntp-servers
705
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
706
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
707

    
708
		// tftp-server-name
709
		if ($dhcpifconf['tftp'] <> "")
710
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
711

    
712
		// Handle option, number rowhelper values
713
		$dhcpdconf .= "\n";
714
		if($dhcpifconf['numberoptions']['item']) {
715
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
716
				if(empty($item['type']) || $item['type'] == "text")
717
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
718
				else
719
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
720
			}
721
		}
722

    
723
		// ldap-server
724
		if ($dhcpifconf['ldap'] <> "")
725
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
726

    
727
		// net boot information
728
		if(isset($dhcpifconf['netboot'])) {
729
			if ($dhcpifconf['nextserver'] <> "") {
730
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
731
			}
732
			if ($dhcpifconf['filename'] <> "") {
733
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
734
			}
735
			if ($dhcpifconf['rootpath'] <> "") {
736
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
737
			}
738
		}
739

    
740
		$dhcpdconf .= <<<EOD
741
}
742

    
743
EOD;
744

    
745
		/* add static mappings */
746
		if (is_array($dhcpifconf['staticmap'])) {
747

    
748
			$i = 0;
749
			foreach ($dhcpifconf['staticmap'] as $sm) {
750
				$dhcpdconf .= <<<EOD
751
host s_{$dhcpif}_{$i} {
752
	hardware ethernet {$sm['mac']};
753

    
754
EOD;
755
				if ($sm['ipaddr'])
756
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
757

    
758
				if ($sm['hostname']) {
759
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
760
					$dhhostname = str_replace(".", "_", $dhhostname);
761
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
762
				}
763
				if ($sm['filename'])
764
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
765

    
766
				if ($sm['rootpath'])
767
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
768

    
769
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
770
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
771

    
772
				$smdnscfg = "";
773

    
774
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
775
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
776
				}
777

    
778
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
779
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
780
				}
781

    
782
				if (isset($sm['ddnsupdate'])) {
783
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
784
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
785
					$pdnscfg .= "		ddns-update-style interim;\n";
786
				}
787

    
788
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
789
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
790
				}
791
				$dhcpdconf .= "{$smdnscfg}";
792

    
793
				// default-lease-time
794
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
795
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
796

    
797
				// max-lease-time
798
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
799
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
800

    
801
				// netbios-name*
802
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
803
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
804
					$dhcpdconf .= "	option netbios-node-type 8;\n";
805
				}
806

    
807
				// ntp-servers
808
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
809
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
810

    
811
				// tftp-server-name
812
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
813
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
814

    
815
				$dhcpdconf .= "}\n";
816
				$i++;
817
			}
818
		}
819

    
820
		$dhcpdifs[] = get_real_interface($dhcpif);
821
	}
822

    
823
	/* write dhcpd.conf */
824
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
825
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
826
		unset($dhcpdconf);
827
		return 1;
828
	}
829
	unset($dhcpdconf);
830

    
831
	/* create an empty leases database */
832
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
833
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
834

    
835
	/* fire up dhcpd in a chroot */
836
	if (count($dhcpdifs) > 0) {
837
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
838
			join(" ", $dhcpdifs));
839
	}
840

    
841
	if ($g['booting'])
842
		print "done.\n";
843

    
844
	return 0;
845
}
846

    
847
function services_dhcpdv6_configure() {
848
	global $config, $g;
849

    
850
	if($g['services_dhcp_server_enable'] == false)
851
		return;
852

    
853
	if(isset($config['system']['developerspew'])) {
854
		$mt = microtime();
855
		echo "services_dhcpd_configure($if) being called $mt\n";
856
	}
857

    
858
	/* kill any running dhcpd */
859
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
860
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
861
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
862
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
863

    
864
	/* DHCP enabled on any interfaces? */
865
	if (!is_dhcpv6_server_enabled())
866
		return 0;
867

    
868
	if ($g['booting']) {
869
		if ($g['platform'] != "pfSense") {
870
			/* restore the leases, if we have them */
871
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
872
				$dhcprestore = "";
873
				$dhcpreturn = "";
874
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
875
				$dhcprestore = implode(" ", $dhcprestore);
876
				if($dhcpreturn <> 0) {
877
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
878
				}
879
			}
880
		}
881
	}
882

    
883
	$syscfg = $config['system'];
884
	if (!is_array($config['dhcpdv6']))
885
		$config['dhcpdv6'] = array();
886
	$dhcpdv6cfg = $config['dhcpdv6'];
887
	$Iflist = get_configured_interface_list();
888
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
889

    
890

    
891
	if ($g['booting'])
892
		echo "Starting DHCPv6 service...";
893
	else
894
		sleep(1);
895

    
896
	/* we add a fake entry for interfaces that are set to track6 another WAN */
897
	foreach ($Iflist as $ifname) {
898
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
899
			$realif = get_real_interface($ifname);
900
			$ifcfgipv6 = get_interface_ipv6($ifname);
901
			if(!is_ipaddrv6($ifcfgipv6))
902
				continue;
903
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
904
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
905
			$trackcfg = $config['interfaces'][$trackifname];
906
			$pdlen = calculate_ipv6_delegation_length($trackifname);
907
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
908
			$dhcpdv6cfg[$ifname] = array();
909
			$dhcpdv6cfg[$ifname]['enable'] = true;
910
			/* range */
911
			$ifcfgipv6arr[7] = "1000";
912
			$dhcpdv6cfg[$ifname]['range'] = array();
913
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
914
			$ifcfgipv6arr[7] = "2000";
915
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));;
916
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
917
			if($pdlen > 2) {
918
				$pdlenmax = $pdlen;
919
				$pdlenhalf = $pdlenmax -1;
920
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
921
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
922
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
923

    
924
				/* set the delegation start to half the current address block */
925
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
926
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
927

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

    
932
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
933
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
934
			}
935
		}
936
	}
937

    
938
	$custoptionsv6 = "";
939
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
940
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
941
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
942
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
943
			}
944
		}
945
	}
946

    
947
	$dhcpdv6conf = <<<EOD
948

    
949
option domain-name "{$syscfg['domain']}";
950
option ldap-server code 95 = text;
951
option domain-search-list code 119 = text;
952
{$custoptions}
953
default-lease-time 7200;
954
max-lease-time 86400;
955
log-facility local7;
956
ddns-update-style none;
957
one-lease-per-client true;
958
deny duplicates;
959
ping-check true;
960

    
961
EOD;
962

    
963
	if(!isset($dhcpv6ifconf['disableauthoritative']))
964
		$dhcpdv6conf .= "authoritative;\n";
965

    
966
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
967
		$dhcpdv6conf .= "always-broadcast on\n";
968

    
969
	$dhcpdv6ifs = array();
970

    
971
	$dhcpv6num = 0;
972
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
973

    
974
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
975

    
976
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
977
			continue;
978
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
979
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
980
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
981

    
982
		if($is_olsr_enabled == true)
983
			if($dhcpv6ifconf['netmask'])
984
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
985

    
986
		$dnscfgv6 = "";
987

    
988
		if ($dhcpv6ifconf['domain']) {
989
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
990
		}
991

    
992
    		if($dhcpv6ifconf['domainsearchlist'] <> "") {
993
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
994
    		}
995

    
996
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
997
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
998
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
999
			}
1000
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1001
		}
1002

    
1003
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1004
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1005
		} else if ((isset($config['dnsmasq']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1006
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1007
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1008
			$dns_arrv6 = array();
1009
			foreach($syscfg['dnsserver'] as $dnsserver) {
1010
				if(is_ipaddrv6($dnsserver)) {
1011
					$dns_arrv6[] = $dnsserver;
1012
				}
1013
			}
1014
			if(!empty($dns_arrv6))
1015
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1016
		}
1017

    
1018
		if(is_ipaddrv6($ifcfgipv6)) {
1019
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6} {\n";
1020
		} else {
1021
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1022
			$dhcpdv6conf .= "subnet6 {$subnet6}/64 {\n";
1023
		}
1024

    
1025
		if($dhcpv6ifconf['failover_peerip'] <> "")
1026
			$dhcpdv6conf .= "		deny dynamic bootp clients;\n";
1027

    
1028
		if (isset($dhcpv6ifconf['denyunknown']))
1029
		   $dhcpdv6conf .= "		deny unknown-clients;\n";
1030

    
1031
		$dhcpdv6conf .= <<<EOD
1032
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1033
$dnscfgv6
1034

    
1035
EOD;
1036

    
1037
		if(is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1038
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']}/{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1039

    
1040
		}
1041
    		// default-lease-time
1042
		if ($dhcpv6ifconf['defaultleasetime'])
1043
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1044

    
1045
		// max-lease-time
1046
		if ($dhcpv6ifconf['maxleasetime'])
1047
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1048

    
1049
		// ntp-servers
1050
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1051
			$ntpservers = array();
1052
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1053
				if(is_ipaddrv6($ntpserver))
1054
					$ntpservers[] = $ntpserver;
1055
			}
1056
			if(count($ntpservers) > 0 )
1057
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1058
		}
1059
		// tftp-server-name
1060
		/* Needs ISC DHCPD support
1061
		 if ($dhcpv6ifconf['tftp'] <> "")
1062
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1063
		*/
1064

    
1065
		// Handle option, number rowhelper values
1066
		$dhcpdv6conf .= "\n";
1067
		if($dhcpv6ifconf['numberoptions']['item']) {
1068
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1069
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1070
			}
1071
		}
1072

    
1073
		// ldap-server
1074
		if ($dhcpv6ifconf['ldap'] <> "")
1075
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1076

    
1077
		// net boot information
1078
		if(isset($dhcpv6ifconf['netboot'])) {
1079
			if ($dhcpv6ifconf['nextserver'] <> "") {
1080
				$dhcpdv6conf .= "	next-server {$dhcpv6ifconf['nextserver']};\n";
1081
			}
1082
			if ($dhcpv6ifconf['filename'] <> "") {
1083
				$dhcpdv6conf .= "	filename \"{$dhcpv6ifconf['filename']}\";\n";
1084
			}
1085
			if ($dhcpv6ifconf['rootpath'] <> "") {
1086
				$dhcpdv6conf .= "	option root-path \"{$dhcpv6ifconf['rootpath']}\";\n";
1087
			}
1088
		}
1089

    
1090
		$dhcpdv6conf .= "}\n";
1091

    
1092
		/* add static mappings */
1093
		/* Needs to use DUID */
1094
		if (is_array($dhcpv6ifconf['staticmap'])) {
1095
			$i = 0;
1096
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1097
				$dhcpdv6conf .= <<<EOD
1098
host s_{$dhcpv6if}_{$i} {
1099
	host-identifier option dhcp6.client-id {$sm['duid']};
1100

    
1101
EOD;
1102
				if ($sm['ipaddrv6'])
1103
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1104

    
1105
				if ($sm['hostname']) {
1106
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1107
					$dhhostname = str_replace(".", "_", $dhhostname);
1108
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1109
				}
1110
				if ($sm['filename'])
1111
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1112

    
1113
				if ($sm['rootpath'])
1114
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1115

    
1116
				$dhcpdv6conf .= "}\n";
1117
				$i++;
1118
			}
1119
		}
1120

    
1121
		if($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged") {
1122
			if(preg_match("/poes/si", $dhcpv6if)) {
1123
				/* magic here */
1124
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1125
			} else {
1126
				$realif = get_real_interface($dhcpv6if);
1127
				if (stristr("$realif", "bridge")) {
1128
					$mac = get_interface_mac($realif);
1129
					$v6address = generate_ipv6_from_mac($mac);
1130
					/* Create link local address for bridges */
1131
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1132
				}
1133
				$realif = escapeshellcmd($realif);
1134
				$dhcpdv6ifs[] = $realif;
1135
			}
1136
		}
1137
	}
1138

    
1139
	/* write dhcpdv6.conf */
1140
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1141
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1142
		if ($g['booting'])
1143
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1144
		unset($dhcpdv6conf);
1145
		return 1;
1146
	}
1147
	unset($dhcpdv6conf);
1148

    
1149
	/* create an empty leases v6 database */
1150
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1151
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1152

    
1153
	/* fire up dhcpd in a chroot */
1154
	if (count($dhcpdv6ifs) > 0) {
1155
		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 " .
1156
			join(" ", $dhcpdv6ifs));
1157
		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");
1158
	}
1159
	if ($g['booting'])
1160
		print gettext("done.") . "\n";
1161

    
1162
	return 0;
1163
}
1164

    
1165
function services_igmpproxy_configure() {
1166
        global $config, $g;
1167

    
1168
        /* kill any running igmpproxy */
1169
        killbyname("igmpproxy");
1170

    
1171
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1172
		return 1;
1173

    
1174
        $iflist = get_configured_interface_list();
1175

    
1176
        $igmpconf = <<<EOD
1177

    
1178
##------------------------------------------------------
1179
## Enable Quickleave mode (Sends Leave instantly)
1180
##------------------------------------------------------
1181
quickleave
1182

    
1183
EOD;
1184

    
1185
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1186
                unset($iflist[$igmpcf['ifname']]);
1187
                $realif = get_real_interface($igmpcf['ifname']);
1188
                if (empty($igmpcf['threshold']))
1189
                        $threshld = 1;
1190
                else
1191
                        $threshld = $igmpcf['threshold'];
1192
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1193

    
1194
                if ($igmpcf['address'] <> "") {
1195
                        $item = explode(" ", $igmpcf['address']);
1196
                        foreach($item as $iww)
1197
                                $igmpconf .= "altnet {$iww}\n";
1198
                }
1199
                $igmpconf .= "\n";
1200
        }
1201
        foreach ($iflist as $ifn) {
1202
                $realif = get_real_interface($ifn);
1203
                $igmpconf .= "phyint {$realif} disabled\n";
1204
        }
1205
	$igmpconf .= "\n";
1206

    
1207
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1208
        if (!$igmpfl) {
1209
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1210
                return;
1211
        }
1212
        fwrite($igmpfl, $igmpconf);
1213
        fclose($igmpfl);
1214
	unset($igmpconf);
1215

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

    
1220
        return 0;
1221
}
1222

    
1223
function services_dhcrelay_configure() {
1224
	global $config, $g;
1225
	if ($g['platform'] == 'jail')
1226
		return;
1227
	if(isset($config['system']['developerspew'])) {
1228
		$mt = microtime();
1229
		echo "services_dhcrelay_configure() being called $mt\n";
1230
	}
1231

    
1232
	/* kill any running dhcrelay */
1233
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1234

    
1235
	$dhcrelaycfg =& $config['dhcrelay'];
1236

    
1237
	/* DHCPRelay enabled on any interfaces? */
1238
	if (!isset($dhcrelaycfg['enable']))
1239
		return 0;
1240

    
1241
	if ($g['booting'])
1242
		echo gettext("Starting DHCP relay service...");
1243
	else
1244
		sleep(1);
1245

    
1246
	$iflist = get_configured_interface_list();
1247

    
1248
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1249
	foreach ($dhcifaces as $dhcrelayif) {
1250
		if (!isset($iflist[$dhcrelayif]) ||
1251
			link_interface_to_bridge($dhcrelayif))
1252
			continue;
1253

    
1254
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1255
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1256
	}
1257

    
1258
	/*
1259
	 * In order for the relay to work, it needs to be active
1260
	 * on the interface in which the destination server sits.
1261
	 */
1262
	$srvips = explode(",", $dhcrelaycfg['server']);
1263
	foreach ($srvips as $srcidx => $srvip) {
1264
		unset($destif);
1265
		foreach ($iflist as $ifname) {
1266
			$subnet = get_interface_ip($ifname);
1267
			if (!is_ipaddr($subnet))
1268
				continue;
1269
			$subnet .=  "/" . get_interface_subnet($ifname);
1270
			if (ip_in_subnet($srvip, $subnet)) {
1271
				$destif = get_real_interface($ifname);
1272
				break;
1273
			}
1274
		}
1275
		if (!isset($destif)) {
1276
			foreach (get_staticroutes() as $rtent) {
1277
				if (ip_in_subnet($srvip, $rtent['network'])) {
1278
					$a_gateways = return_gateways_array(true);
1279
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1280
					break;
1281
				}
1282
			}
1283
		}
1284

    
1285
		if (!isset($destif)) {
1286
			/* Create a array from the existing route table */
1287
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1288
        		array_shift($route_str);
1289
        		array_shift($route_str);
1290
        		array_shift($route_str);
1291
        		array_shift($route_str);
1292
        		$route_arr = array();
1293
        		foreach($route_str as $routeline) {
1294
				$items = preg_split("/[ ]+/i", $routeline);
1295
				if (is_subnetv4($items[0])) {
1296
					$subnet = $items[0];
1297
				} elseif (is_ipaddrv4($items[0])) {
1298
					$subnet = "{$items[0]}/32";
1299
				} else {
1300
					// Not a subnet or IP address, skip to the next line.
1301
					continue;
1302
				}
1303
				if (ip_in_subnet($srvip, $subnet)) {
1304
					$destif = trim($items[6]);
1305
					break;
1306
				}
1307
			}
1308
		}
1309

    
1310
		if (!isset($destif)) {
1311
			if (is_array($config['gateways']['gateway_item'])) {
1312
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1313
					if (isset($gateway['defaultgw'])) {
1314
						$a_gateways = return_gateways_array(true);
1315
                                        	$destif = $a_gateways[$rtent['gateway']]['interface'];
1316
						break;
1317
					}
1318
				}
1319
			} else
1320
				$destif = get_real_interface("wan");
1321
		}
1322

    
1323
		if (!empty($destif))
1324
			$dhcrelayifs[] = $destif;
1325
	}
1326
	$dhcrelayifs = array_unique($dhcrelayifs);
1327

    
1328
	/* fire up dhcrelay */
1329
	if (empty($dhcrelayifs)) {
1330
		log_error("No suitable interface found for running dhcrelay!");
1331
		return; /* XXX */
1332
	}
1333

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

    
1336
	if (isset($dhcrelaycfg['agentoption']))
1337
		$cmd .=  " -a -m replace";
1338

    
1339
	$cmd .= " " . implode(" ", $srvips);
1340
	mwexec($cmd);
1341
	unset($cmd);
1342

    
1343
	return 0;
1344
}
1345

    
1346
function services_dhcrelay6_configure() {
1347
	global $config, $g;
1348
	if ($g['platform'] == 'jail')
1349
		return;
1350
	if(isset($config['system']['developerspew'])) {
1351
		$mt = microtime();
1352
		echo "services_dhcrelay_configure() being called $mt\n";
1353
	}
1354

    
1355
	/* kill any running dhcrelay */
1356
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1357

    
1358
	$dhcrelaycfg =& $config['dhcrelay6'];
1359

    
1360
	/* DHCPv6 Relay enabled on any interfaces? */
1361
	if (!isset($dhcrelaycfg['enable']))
1362
		return 0;
1363

    
1364
	if ($g['booting'])
1365
		echo gettext("Starting DHCPv6 relay service...");
1366
	else
1367
		sleep(1);
1368

    
1369
	$iflist = get_configured_interface_list();
1370

    
1371
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1372
	foreach ($dhcifaces as $dhcrelayif) {
1373
		if (!isset($iflist[$dhcrelayif]) ||
1374
			link_interface_to_bridge($dhcrelayif))
1375
			continue;
1376

    
1377
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1378
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1379
	}
1380
	$dhcrelayifs = array_unique($dhcrelayifs);
1381

    
1382
	/*
1383
	 * In order for the relay to work, it needs to be active
1384
	 * on the interface in which the destination server sits.
1385
	 */
1386
	$srvips = explode(",", $dhcrelaycfg['server']);
1387
        $srvifaces = array();
1388
	foreach ($srvips as $srcidx => $srvip) {
1389
		unset($destif);
1390
		foreach ($iflist as $ifname) {
1391
			$subnet = get_interface_ipv6($ifname);
1392
			if (!is_ipaddrv6($subnet))
1393
				continue;
1394
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1395
			if (ip_in_subnet($srvip, $subnet)) {
1396
				$destif = get_real_interface($ifname);
1397
				break;
1398
			}
1399
		}
1400
		if (!isset($destif)) {
1401
			if (is_array($config['staticroutes']['route'])) {
1402
				foreach ($config['staticroutes']['route'] as $rtent) {
1403
					if (ip_in_subnet($srvip, $rtent['network'])) {
1404
						$a_gateways = return_gateways_array(true);
1405
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1406
						break;
1407
					}
1408
				}
1409
			}
1410
		}
1411

    
1412
		if (!isset($destif)) {
1413
			/* Create a array from the existing route table */
1414
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1415
        		array_shift($route_str);
1416
        		array_shift($route_str);
1417
        		array_shift($route_str);
1418
        		array_shift($route_str);
1419
        		$route_arr = array();
1420
        		foreach($route_str as $routeline) {
1421
                		$items = preg_split("/[ ]+/i", $routeline);
1422
				if (ip_in_subnet($srvip, $items[0])) {
1423
					$destif = trim($items[6]);
1424
					break;
1425
				}
1426
        		}
1427
		}
1428

    
1429
		if (!isset($destif)) {
1430
			if (is_array($config['gateways']['gateway_item'])) {
1431
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1432
					if (isset($gateway['defaultgw'])) {
1433
						$a_gateways = return_gateways_array(true);
1434
                                        	$destif = $a_gateways[$rtent['gateway']]['interface'];
1435
						break;
1436
					}
1437
				}
1438
			} else
1439
				$destif = get_real_interface("wan");
1440
		}
1441

    
1442
		if (!empty($destif)) {
1443
			$srvifaces[] = "{$srvip}%{$destif}";
1444
		}
1445
	}
1446

    
1447
	/* fire up dhcrelay */
1448
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1449
		log_error("No suitable interface found for running dhcrelay -6!");
1450
		return; /* XXX */
1451
	}
1452

    
1453
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varetc_path']}/dhcrelay6.pid\"";
1454
	foreach ($dhcrelayifs as $dhcrelayif) {
1455
		$cmd .= " -l {$dhcrelayif}";
1456
	}
1457
	foreach ($srvifaces as $srviface) {
1458
		$cmd .= " -u \"{$srviface}\"";
1459
	}
1460
	mwexec($cmd);
1461
	unset($cmd);
1462

    
1463
	return 0;
1464
}
1465

    
1466
function services_dyndns_configure_client($conf) {
1467

    
1468
	if (!isset($conf['enable']))
1469
		return;
1470

    
1471
	/* load up the dyndns.class */
1472
	require_once("dyndns.class");
1473

    
1474
	$dns = new updatedns($dnsService = $conf['type'],
1475
		$dnsHost = $conf['host'],
1476
		$dnsUser = $conf['username'],
1477
		$dnsPass = $conf['password'],
1478
		$dnsWilcard = $conf['wildcard'],
1479
		$dnsMX = $conf['mx'],
1480
		$dnsIf = "{$conf['interface']}",
1481
		$dnsBackMX = NULL,
1482
		$dnsServer = NULL,
1483
		$dnsPort = NULL,
1484
		$dnsUpdateURL = "{$conf['updateurl']}",
1485
		$forceUpdate = $conf['force'],
1486
		$dnsZoneID=$conf['zoneid'],
1487
		$dnsTTL=$conf['ttl'],
1488
		$dnsResultMatch = "{$conf['resultmatch']}",
1489
		$dnsRequestIf = "{$conf['requestif']}",
1490
		$dnsID = "{$conf['id']}",
1491
		$dnsVerboseLog = $conf['verboselog']);
1492
}
1493

    
1494
function services_dyndns_configure($int = "") {
1495
	global $config, $g;
1496
	if(isset($config['system']['developerspew'])) {
1497
		$mt = microtime();
1498
		echo "services_dyndns_configure() being called $mt\n";
1499
	}
1500

    
1501
	$dyndnscfg = $config['dyndnses']['dyndns'];
1502
	$gwgroups = return_gateway_groups_array();
1503
	if (is_array($dyndnscfg)) {
1504
		if ($g['booting'])
1505
			echo gettext("Starting DynDNS clients...");
1506

    
1507
		foreach ($dyndnscfg as $dyndns) {
1508
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1509
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1510
				services_dyndns_configure_client($dyndns);
1511
				sleep(1);
1512
			}
1513
		}
1514

    
1515
		if ($g['booting'])
1516
			echo gettext("done.") . "\n";
1517
	}
1518

    
1519
	return 0;
1520
}
1521

    
1522
function dyndnsCheckIP($int) {
1523
	global $config;
1524
	$ip_address = get_interface_ip($int);
1525
	if (is_private_ip($ip_address)) {
1526
		$gateways_status = return_gateways_status(true);
1527
		// If the gateway for this interface is down, then the external check cannot work.
1528
		// Avoid the long wait for the external check to timeout.
1529
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1530
			return "down";
1531
		$hosttocheck = "checkip.dyndns.org";
1532
		$checkip = gethostbyname($hosttocheck);
1533
		$ip_ch = curl_init("http://{$checkip}");
1534
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1535
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1536
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1537
		$ip_result_page = curl_exec($ip_ch);
1538
		curl_close($ip_ch);
1539
		$ip_result_decoded = urldecode($ip_result_page);
1540
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1541
		$ip_address = trim($matches[1]);
1542
	}
1543
	return $ip_address;
1544
}
1545

    
1546
function services_dnsmasq_configure() {
1547
	global $config, $g;
1548
	$return = 0;
1549

    
1550
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1551
	$standard_args = array(
1552
		"dns-forward-max" => "--dns-forward-max=5000",
1553
		"cache-size" => "--cache-size=10000",
1554
		"local-ttl" => "--local-ttl=1"
1555
	);
1556

    
1557

    
1558
	if(isset($config['system']['developerspew'])) {
1559
		$mt = microtime();
1560
		echo "services_dnsmasq_configure() being called $mt\n";
1561
	}
1562

    
1563
	/* kill any running dnsmasq */
1564
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1565
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1566

    
1567
	if (isset($config['dnsmasq']['enable'])) {
1568

    
1569
		if ($g['booting'])
1570
			echo gettext("Starting DNS forwarder...");
1571
		else
1572
			sleep(1);
1573

    
1574
		/* generate hosts file */
1575
		if(system_hosts_generate()!=0)
1576
			$return = 1;
1577

    
1578
		$args = "";
1579

    
1580
		if (isset($config['dnsmasq']['regdhcp'])) {
1581
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1582
		}
1583

    
1584
		/* Setup listen port, if non-default */
1585
		if (is_port($config['dnsmasq']['port']))
1586
			$args .= " --port={$config['dnsmasq']['port']} ";
1587

    
1588
		$listen_addresses = "";
1589
		if(isset($config['dnsmasq']['interface'])) {
1590
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1591
			foreach ($interfaces as $interface) {
1592
				if (is_ipaddr($interface)) {
1593
					$listen_addresses .= " --listen-address={$interface} ";
1594
				} else {
1595
					$if = get_real_interface($interface);
1596
					if (does_interface_exist($if)) {
1597
						$laddr = find_interface_ip($if);
1598
						if (is_ipaddrv4($laddr))
1599
							$listen_addresses .= " --listen-address={$laddr} ";
1600
						$laddr6 = find_interface_ipv6($if);
1601
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind']))
1602
							$listen_addresses .= " --listen-address={$laddr6} ";
1603
					}
1604
				}
1605
			}
1606
			if (!empty($listen_addresses)) {
1607
				$args .= " {$listen_addresses} ";
1608
				if (isset($config['dnsmasq']['strictbind']))
1609
					$args .= " --bind-interfaces ";
1610
			}
1611
		}
1612

    
1613
		/* Setup forwarded domains */
1614
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1615
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1616
				if ($override['ip'] == "!")
1617
					$override[ip] = "";
1618
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1619
			}
1620
		}
1621

    
1622
		/* If selected, then forward reverse lookups for private IPv4 addresses to nowhere. */
1623
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1624
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1625
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1626
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1627
			$args .= " --server=/10.in-addr.arpa/ ";
1628
			$args .= " --server=/168.192.in-addr.arpa/ ";
1629
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1630
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1631
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1632
			}
1633
		}
1634

    
1635
		/* Allow DNS Rebind for forwarded domains */
1636
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1637
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1638
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1639
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1640
				}
1641
			}
1642
		}
1643

    
1644
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1645
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1646

    
1647
		if (isset($config['dnsmasq']['strict_order'])) {
1648
			$args .= " --strict-order ";
1649
		}
1650

    
1651
		if (isset($config['dnsmasq']['domain_needed'])) {
1652
			$args .= " --domain-needed ";
1653
		}
1654

    
1655
		if ($config['dnsmasq']['custom_options'])
1656
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1657
				$args .= " --$c";
1658
				$p = explode('=', $c);
1659
				if (array_key_exists($p[0], $standard_args))
1660
					unset($standard_args[$p[0]]);
1661
			}
1662
		$args .= implode(' ', array_values($standard_args));
1663

    
1664
		/* run dnsmasq */
1665
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1666
		//log_error("dnsmasq command: {$cmd}");
1667
		mwexec_bg($cmd);
1668
		unset($args);
1669

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

    
1674
	if (!$g['booting']) {
1675
		if(services_dhcpd_configure()!=0)
1676
			$return = 1;
1677
	}
1678

    
1679
	return $return;
1680
}
1681

    
1682
function services_snmpd_configure() {
1683
	global $config, $g;
1684
	if(isset($config['system']['developerspew'])) {
1685
		$mt = microtime();
1686
		echo "services_snmpd_configure() being called $mt\n";
1687
	}
1688

    
1689
	/* kill any running snmpd */
1690
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1691
	sleep(2);
1692
	if(is_process_running("bsnmpd"))
1693
		mwexec("/usr/bin/killall bsnmpd", true);
1694

    
1695
	if (isset($config['snmpd']['enable'])) {
1696

    
1697
		if ($g['booting'])
1698
			echo gettext("Starting SNMP daemon... ");
1699

    
1700
		/* generate snmpd.conf */
1701
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1702
		if (!$fd) {
1703
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1704
			return 1;
1705
		}
1706

    
1707

    
1708
		$snmpdconf = <<<EOD
1709
location := "{$config['snmpd']['syslocation']}"
1710
contact := "{$config['snmpd']['syscontact']}"
1711
read := "{$config['snmpd']['rocommunity']}"
1712

    
1713
EOD;
1714

    
1715
/* No docs on what write strings do there for disable for now.
1716
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1717
		    $snmpdconf .= <<<EOD
1718
# write string
1719
write := "{$config['snmpd']['rwcommunity']}"
1720

    
1721
EOD;
1722
		}
1723
*/
1724

    
1725

    
1726
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1727
		    $snmpdconf .= <<<EOD
1728
# SNMP Trap support.
1729
traphost := {$config['snmpd']['trapserver']}
1730
trapport := {$config['snmpd']['trapserverport']}
1731
trap := "{$config['snmpd']['trapstring']}"
1732

    
1733

    
1734
EOD;
1735
		}
1736

    
1737
		$version = trim(file_get_contents('/etc/version'));
1738
		$platform = trim(file_get_contents('/etc/platform'));
1739
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1740
			$platform = $g['product_name'];
1741
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1742
			" {$version} {$platform} " . php_uname("s") .
1743
			" " . php_uname("r") . " " . php_uname("m");
1744

    
1745
		$snmpdconf .= <<<EOD
1746
system := 1     # pfSense
1747
%snmpd
1748
sysDescr			= "{$sysDescr}"
1749
begemotSnmpdDebugDumpPdus       = 2
1750
begemotSnmpdDebugSyslogPri      = 7
1751
begemotSnmpdCommunityString.0.1 = $(read)
1752

    
1753
EOD;
1754

    
1755
/* No docs on what write strings do there for disable for now.
1756
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1757
		    $snmpdconf .= <<<EOD
1758
begemotSnmpdCommunityString.0.2 = $(write)
1759

    
1760
EOD;
1761
		}
1762
*/
1763

    
1764

    
1765
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1766
		    $snmpdconf .= <<<EOD
1767
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1768
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1769
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1770

    
1771
EOD;
1772
		}
1773

    
1774

    
1775
		$snmpdconf .= <<<EOD
1776
begemotSnmpdCommunityDisable    = 1
1777

    
1778
EOD;
1779

    
1780
		if (isset($config['snmpd']['bindlan'])) {
1781
			$config['snmpd']['bindip'] = 'lan';
1782
			unset($config['snmpd']['bindlan']);
1783
		}
1784
		$bind_to_ip = "0.0.0.0";
1785
		if(isset($config['snmpd']['bindip'])) {
1786
			if (is_ipaddr($config['snmpd']['bindip'])) {
1787
				$bind_to_ip = $config['snmpd']['bindip'];
1788
			} else {
1789
				$if = get_real_interface($config['snmpd']['bindip']);
1790
				if (does_interface_exist($if))
1791
					$bind_to_ip = find_interface_ip($if);
1792
			}
1793
		}
1794

    
1795
		if(is_port( $config['snmpd']['pollport'] )) {
1796
		    $snmpdconf .= <<<EOD
1797
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1798

    
1799
EOD;
1800

    
1801
		}
1802

    
1803
		$snmpdconf .= <<<EOD
1804
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1805
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1806

    
1807
# These are bsnmp macros not php vars.
1808
sysContact      = $(contact)
1809
sysLocation     = $(location)
1810
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1811

    
1812
snmpEnableAuthenTraps = 2
1813

    
1814
EOD;
1815

    
1816
		if (is_array( $config['snmpd']['modules'] )) {
1817
		    if(isset($config['snmpd']['modules']['mibii'])) {
1818
			$snmpdconf .= <<<EOD
1819
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1820

    
1821
EOD;
1822
		    }
1823

    
1824
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1825
			$snmpdconf .= <<<EOD
1826
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1827
%netgraph
1828
begemotNgControlNodeName = "snmpd"
1829

    
1830
EOD;
1831
		    }
1832

    
1833
		    if(isset($config['snmpd']['modules']['pf'])) {
1834
			$snmpdconf .= <<<EOD
1835
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1836

    
1837
EOD;
1838
		    }
1839

    
1840
		    if(isset($config['snmpd']['modules']['hostres'])) {
1841
			$snmpdconf .= <<<EOD
1842
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1843

    
1844
EOD;
1845
		    }
1846
		    if(isset($config['snmpd']['modules']['bridge'])) {
1847
			$snmpdconf .= <<<EOD
1848
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1849
# config must end with blank line
1850

    
1851
EOD;
1852
		    }
1853
			if(isset($config['snmpd']['modules']['ucd'])) {
1854
				$snmpdconf .= <<<EOD
1855
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
1856

    
1857
EOD;
1858
			}
1859
			if(isset($config['snmpd']['modules']['regex'])) {
1860
				$snmpdconf .= <<<EOD
1861
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
1862

    
1863
EOD;
1864
			}
1865
		}
1866

    
1867
		fwrite($fd, $snmpdconf);
1868
		fclose($fd);
1869
		unset($snmpdconf);
1870

    
1871
		if (isset($config['snmpd']['bindlan'])) {
1872
			$bindlan = "";
1873
		}
1874

    
1875
		/* run bsnmpd */
1876
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
1877
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
1878

    
1879
		if ($g['booting'])
1880
			echo gettext("done.") . "\n";
1881
	}
1882

    
1883
	return 0;
1884
}
1885

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

    
1893
	/* Dynamic DNS updating active? */
1894
	if (is_array($config['dnsupdates']['dnsupdate'])) {
1895
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
1896
			if (!isset($dnsupdate['enable']))
1897
				continue;
1898
			if (!empty($int) && $int != $dnsupdate['interface'])
1899
				continue;
1900

    
1901
			/* determine interface name */
1902
			$if = get_real_interface($dnsupdate['interface']);
1903
			$wanip = get_interface_ip($dnsupdate['interface']);
1904
			if ($wanip) {
1905

    
1906
				$keyname = $dnsupdate['keyname'];
1907
				/* trailing dot */
1908
				if (substr($keyname, -1) != ".")
1909
					$keyname .= ".";
1910

    
1911
				$hostname = $dnsupdate['host'];
1912
				/* trailing dot */
1913
				if (substr($hostname, -1) != ".")
1914
					$hostname .= ".";
1915

    
1916
				/* write private key file
1917
				   this is dumb - public and private keys are the same for HMAC-MD5,
1918
				   but nsupdate insists on having both */
1919
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
1920
				$privkey = <<<EOD
1921
Private-key-format: v1.2
1922
Algorithm: 157 (HMAC)
1923
Key: {$dnsupdate['keydata']}
1924

    
1925
EOD;
1926
				fwrite($fd, $privkey);
1927
				fclose($fd);
1928

    
1929
				/* write public key file */
1930
				if ($dnsupdate['keytype'] == "zone") {
1931
					$flags = 257;
1932
					$proto = 3;
1933
				} else if ($dnsupdate['keytype'] == "host") {
1934
					$flags = 513;
1935
					$proto = 3;
1936
				} else if ($dnsupdate['keytype'] == "user") {
1937
					$flags = 0;
1938
					$proto = 2;
1939
				}
1940

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

    
1945
				/* generate update instructions */
1946
				$upinst = "";
1947
				if (!empty($dnsupdate['server']))
1948
					$upinst .= "server {$dnsupdate['server']}\n";
1949
				$upinst .= "update delete {$dnsupdate['host']} A\n";
1950
				$upinst .= "update add {$dnsupdate['host']} {$dnsupdate['ttl']} A {$wanip}\n";
1951
				$upinst .= "\n";	/* mind that trailing newline! */
1952

    
1953
				@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
1954
				unset($upinst);
1955

    
1956
				/* invoke nsupdate */
1957
				$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
1958
				if (isset($dnsupdate['usetcp']))
1959
					$cmd .= " -v";
1960
				$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
1961

    
1962
				mwexec_bg($cmd);
1963
				unset($cmd);
1964
			}
1965
		}
1966
	}
1967

    
1968
	return 0;
1969
}
1970

    
1971
/* configure cron service */
1972
function configure_cron() {
1973
	global $g, $config;
1974

    
1975
	conf_mount_rw();
1976
	/* preserve existing crontab entries */
1977
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1978

    
1979
	for ($i = 0; $i < count($crontab_contents); $i++) {
1980
		$cron_item =& $crontab_contents[$i];
1981
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
1982
			array_splice($crontab_contents, $i - 1);
1983
			break;
1984
		}
1985
	}
1986
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
1987

    
1988

    
1989
	if (is_array($config['cron']['item'])) {
1990
		$crontab_contents .= "#\n";
1991
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
1992
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
1993
		$crontab_contents .= "#\n";
1994

    
1995
		foreach ($config['cron']['item'] as $item) {
1996
			$crontab_contents .= "\n{$item['minute']}\t";
1997
			$crontab_contents .= "{$item['hour']}\t";
1998
			$crontab_contents .= "{$item['mday']}\t";
1999
			$crontab_contents .= "{$item['month']}\t";
2000
			$crontab_contents .= "{$item['wday']}\t";
2001
			$crontab_contents .= "{$item['who']}\t";
2002
			$crontab_contents .= "{$item['command']}";
2003
		}
2004

    
2005
		$crontab_contents .= "\n#\n";
2006
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2007
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2008
		$crontab_contents .= "#\n\n";
2009
	}
2010

    
2011
	/* please maintain the newline at the end of file */
2012
	file_put_contents("/etc/crontab", $crontab_contents);
2013
	unset($crontab_contents);
2014

    
2015
	/* do a HUP kill to force sync changes */
2016
	exec('/bin/pkill -HUP cron');
2017

    
2018
	conf_mount_ro();
2019
}
2020

    
2021
function upnp_action ($action) {
2022
	global $g, $config;
2023
	switch($action) {
2024
		case "start":
2025
			if (file_exists('/var/etc/miniupnpd.conf')) {
2026
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2027
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2028
			}
2029
			break;
2030
		case "stop":
2031
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2032
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2033
				mwexec('killall miniupnpd 2>/dev/null', true);
2034
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2035
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2036
			break;
2037
		case "restart":
2038
			upnp_action('stop');
2039
			upnp_action('start');
2040
			break;
2041
	}
2042
}
2043

    
2044
function upnp_start() {
2045
	global $config;
2046

    
2047
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2048
		return;
2049

    
2050
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2051
		echo gettext("Starting UPnP service... ");
2052
		require_once('/usr/local/pkg/miniupnpd.inc');
2053
		sync_package_miniupnpd();
2054
		echo "done.\n";
2055
	}
2056
}
2057

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

    
2061
	$is_installed = false;
2062

    
2063
	if (!is_array($config['cron']))
2064
		$config['cron'] = array();
2065
	if (!is_array($config['cron']['item']))
2066
		$config['cron']['item'] = array();
2067

    
2068
	$x=0;
2069
	foreach($config['cron']['item'] as $item) {
2070
		if(strstr($item['command'], $command)) {
2071
			$is_installed = true;
2072
			break;
2073
		}
2074
		$x++;
2075
	}
2076

    
2077
	if($active) {
2078
		$cron_item = array();
2079
		$cron_item['minute'] = $minute;
2080
		$cron_item['hour'] = $hour;
2081
		$cron_item['mday'] = $monthday;
2082
		$cron_item['month'] = $month;
2083
		$cron_item['wday'] = $weekday;
2084
		$cron_item['who'] = $who;
2085
		$cron_item['command'] = $command;
2086
		if(!$is_installed) {
2087
			$config['cron']['item'][] = $cron_item;
2088
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2089
		} else {
2090
			$config['cron']['item'][$x] = $cron_item;
2091
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2092
		}
2093
	} else {
2094
		if(($is_installed == true) && ($x > 0)) {
2095
			unset($config['cron']['item'][$x]);
2096
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2097
		}
2098
	}
2099
	configure_cron();
2100
}
2101

    
2102
?>
(49-49/66)