Project

General

Profile

Download (65.2 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
	if(isset($config['system']['developerspew'])) {
1551
		$mt = microtime();
1552
		echo "services_dnsmasq_configure() being called $mt\n";
1553
	}
1554

    
1555
	/* kill any running dnsmasq */
1556
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1557
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1558

    
1559
	if (isset($config['dnsmasq']['enable'])) {
1560

    
1561
		if ($g['booting'])
1562
			echo gettext("Starting DNS forwarder...");
1563
		else
1564
			sleep(1);
1565

    
1566
		/* generate hosts file */
1567
		if(system_hosts_generate()!=0)
1568
			$return = 1;
1569

    
1570
		$args = "";
1571

    
1572
		if (isset($config['dnsmasq']['regdhcp'])) {
1573
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1574
		}
1575

    
1576
		/* Setup listen port, if non-default */
1577
		if (is_port($config['dnsmasq']['port']))
1578
			$args .= " --port={$config['dnsmasq']['port']} ";
1579

    
1580
		$listen_addresses = "";
1581
		if(isset($config['dnsmasq']['interface'])) {
1582
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1583
			foreach ($interfaces as $interface) {
1584
				if (is_ipaddr($interface)) {
1585
					$listen_addresses .= " --listen-address={$interface} ";
1586
				} else {
1587
					$if = get_real_interface($interface);
1588
					if (does_interface_exist($if)) {
1589
						$laddr = find_interface_ip($if);
1590
						if (is_ipaddrv4($laddr))
1591
							$listen_addresses .= " --listen-address={$laddr} ";
1592
						$laddr6 = find_interface_ipv6($if);
1593
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind']))
1594
							$listen_addresses .= " --listen-address={$laddr6} ";
1595
					}
1596
				}
1597
			}
1598
			if (!empty($listen_addresses)) {
1599
				$args .= " {$listen_addresses} ";
1600
				if (isset($config['dnsmasq']['strictbind']))
1601
					$args .= " --bind-interfaces ";
1602
			}
1603
		}
1604

    
1605
		/* Setup forwarded domains */
1606
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1607
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1608
				if ($override['ip'] == "!")
1609
					$override[ip] = "";
1610
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1611
			}
1612
		}
1613

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

    
1627
		/* Allow DNS Rebind for forwarded domains */
1628
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1629
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1630
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1631
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1632
				}
1633
			}
1634
		}
1635

    
1636
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1637
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1638

    
1639
		if (isset($config['dnsmasq']['strict_order'])) {
1640
			$args .= " --strict-order ";
1641
		}
1642

    
1643
		if (isset($config['dnsmasq']['domain_needed'])) {
1644
			$args .= " --domain-needed ";
1645
		}
1646

    
1647
		if ($config['dnsmasq']['custom_options']) {
1648
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c)
1649
				$args .= " --$c";
1650
		}
1651

    
1652
		/* run dnsmasq */
1653
		$cmd = "/usr/local/sbin/dnsmasq --local-ttl 1 --all-servers {$dns_rebind} --dns-forward-max=5000 --cache-size=10000 {$args}";
1654
		//log_error("dnsmasq command: {$cmd}");
1655
		mwexec_bg($cmd);
1656
		unset($args);
1657

    
1658
		if ($g['booting'])
1659
			echo gettext("done.") . "\n";
1660
	}
1661

    
1662
	if (!$g['booting']) {
1663
		if(services_dhcpd_configure()!=0)
1664
			$return = 1;
1665
	}
1666

    
1667
	return $return;
1668
}
1669

    
1670
function services_snmpd_configure() {
1671
	global $config, $g;
1672
	if(isset($config['system']['developerspew'])) {
1673
		$mt = microtime();
1674
		echo "services_snmpd_configure() being called $mt\n";
1675
	}
1676

    
1677
	/* kill any running snmpd */
1678
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1679
	sleep(2);
1680
	if(is_process_running("bsnmpd"))
1681
		mwexec("/usr/bin/killall bsnmpd", true);
1682

    
1683
	if (isset($config['snmpd']['enable'])) {
1684

    
1685
		if ($g['booting'])
1686
			echo gettext("Starting SNMP daemon... ");
1687

    
1688
		/* generate snmpd.conf */
1689
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1690
		if (!$fd) {
1691
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1692
			return 1;
1693
		}
1694

    
1695

    
1696
		$snmpdconf = <<<EOD
1697
location := "{$config['snmpd']['syslocation']}"
1698
contact := "{$config['snmpd']['syscontact']}"
1699
read := "{$config['snmpd']['rocommunity']}"
1700

    
1701
EOD;
1702

    
1703
/* No docs on what write strings do there for disable for now.
1704
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1705
		    $snmpdconf .= <<<EOD
1706
# write string
1707
write := "{$config['snmpd']['rwcommunity']}"
1708

    
1709
EOD;
1710
		}
1711
*/
1712

    
1713

    
1714
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1715
		    $snmpdconf .= <<<EOD
1716
# SNMP Trap support.
1717
traphost := {$config['snmpd']['trapserver']}
1718
trapport := {$config['snmpd']['trapserverport']}
1719
trap := "{$config['snmpd']['trapstring']}"
1720

    
1721

    
1722
EOD;
1723
		}
1724

    
1725
		$version = trim(file_get_contents('/etc/version'));
1726
		$platform = trim(file_get_contents('/etc/platform'));
1727
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1728
			$platform = $g['product_name'];
1729
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1730
			" {$version} {$platform} " . php_uname("s") .
1731
			" " . php_uname("r") . " " . php_uname("m");
1732

    
1733
		$snmpdconf .= <<<EOD
1734
system := 1     # pfSense
1735
%snmpd
1736
sysDescr			= "{$sysDescr}"
1737
begemotSnmpdDebugDumpPdus       = 2
1738
begemotSnmpdDebugSyslogPri      = 7
1739
begemotSnmpdCommunityString.0.1 = $(read)
1740

    
1741
EOD;
1742

    
1743
/* No docs on what write strings do there for disable for now.
1744
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1745
		    $snmpdconf .= <<<EOD
1746
begemotSnmpdCommunityString.0.2 = $(write)
1747

    
1748
EOD;
1749
		}
1750
*/
1751

    
1752

    
1753
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1754
		    $snmpdconf .= <<<EOD
1755
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1756
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1757
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1758

    
1759
EOD;
1760
		}
1761

    
1762

    
1763
		$snmpdconf .= <<<EOD
1764
begemotSnmpdCommunityDisable    = 1
1765

    
1766
EOD;
1767

    
1768
		if (isset($config['snmpd']['bindlan'])) {
1769
			$config['snmpd']['bindip'] = 'lan';
1770
			unset($config['snmpd']['bindlan']);
1771
		}
1772
		$bind_to_ip = "0.0.0.0";
1773
		if(isset($config['snmpd']['bindip'])) {
1774
			if (is_ipaddr($config['snmpd']['bindip'])) {
1775
				$bind_to_ip = $config['snmpd']['bindip'];
1776
			} else {
1777
				$if = get_real_interface($config['snmpd']['bindip']);
1778
				if (does_interface_exist($if))
1779
					$bind_to_ip = find_interface_ip($if);
1780
			}
1781
		}
1782

    
1783
		if(is_port( $config['snmpd']['pollport'] )) {
1784
		    $snmpdconf .= <<<EOD
1785
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1786

    
1787
EOD;
1788

    
1789
		}
1790

    
1791
		$snmpdconf .= <<<EOD
1792
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1793
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1794

    
1795
# These are bsnmp macros not php vars.
1796
sysContact      = $(contact)
1797
sysLocation     = $(location)
1798
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1799

    
1800
snmpEnableAuthenTraps = 2
1801

    
1802
EOD;
1803

    
1804
		if (is_array( $config['snmpd']['modules'] )) {
1805
		    if(isset($config['snmpd']['modules']['mibii'])) {
1806
			$snmpdconf .= <<<EOD
1807
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1808

    
1809
EOD;
1810
		    }
1811

    
1812
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1813
			$snmpdconf .= <<<EOD
1814
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1815
%netgraph
1816
begemotNgControlNodeName = "snmpd"
1817

    
1818
EOD;
1819
		    }
1820

    
1821
		    if(isset($config['snmpd']['modules']['pf'])) {
1822
			$snmpdconf .= <<<EOD
1823
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1824

    
1825
EOD;
1826
		    }
1827

    
1828
		    if(isset($config['snmpd']['modules']['hostres'])) {
1829
			$snmpdconf .= <<<EOD
1830
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1831

    
1832
EOD;
1833
		    }
1834
		    if(isset($config['snmpd']['modules']['bridge'])) {
1835
			$snmpdconf .= <<<EOD
1836
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1837
# config must end with blank line
1838

    
1839
EOD;
1840
		    }
1841
			if(isset($config['snmpd']['modules']['ucd'])) {
1842
				$snmpdconf .= <<<EOD
1843
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
1844

    
1845
EOD;
1846
			}
1847
			if(isset($config['snmpd']['modules']['regex'])) {
1848
				$snmpdconf .= <<<EOD
1849
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
1850

    
1851
EOD;
1852
			}
1853
		}
1854

    
1855
		fwrite($fd, $snmpdconf);
1856
		fclose($fd);
1857
		unset($snmpdconf);
1858

    
1859
		if (isset($config['snmpd']['bindlan'])) {
1860
			$bindlan = "";
1861
		}
1862

    
1863
		/* run bsnmpd */
1864
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
1865
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
1866

    
1867
		if ($g['booting'])
1868
			echo gettext("done.") . "\n";
1869
	}
1870

    
1871
	return 0;
1872
}
1873

    
1874
function services_dnsupdate_process($int = "") {
1875
	global $config, $g;
1876
	if(isset($config['system']['developerspew'])) {
1877
		$mt = microtime();
1878
		echo "services_dnsupdate_process() being called $mt\n";
1879
	}
1880

    
1881
	/* Dynamic DNS updating active? */
1882
	if (is_array($config['dnsupdates']['dnsupdate'])) {
1883
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
1884
			if (!isset($dnsupdate['enable']))
1885
				continue;
1886
			if (!empty($int) && $int != $dnsupdate['interface'])
1887
				continue;
1888

    
1889
			/* determine interface name */
1890
			$if = get_real_interface($dnsupdate['interface']);
1891
			$wanip = get_interface_ip($dnsupdate['interface']);
1892
			if ($wanip) {
1893

    
1894
				$keyname = $dnsupdate['keyname'];
1895
				/* trailing dot */
1896
				if (substr($keyname, -1) != ".")
1897
					$keyname .= ".";
1898

    
1899
				$hostname = $dnsupdate['host'];
1900
				/* trailing dot */
1901
				if (substr($hostname, -1) != ".")
1902
					$hostname .= ".";
1903

    
1904
				/* write private key file
1905
				   this is dumb - public and private keys are the same for HMAC-MD5,
1906
				   but nsupdate insists on having both */
1907
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
1908
				$privkey = <<<EOD
1909
Private-key-format: v1.2
1910
Algorithm: 157 (HMAC)
1911
Key: {$dnsupdate['keydata']}
1912

    
1913
EOD;
1914
				fwrite($fd, $privkey);
1915
				fclose($fd);
1916

    
1917
				/* write public key file */
1918
				if ($dnsupdate['keytype'] == "zone") {
1919
					$flags = 257;
1920
					$proto = 3;
1921
				} else if ($dnsupdate['keytype'] == "host") {
1922
					$flags = 513;
1923
					$proto = 3;
1924
				} else if ($dnsupdate['keytype'] == "user") {
1925
					$flags = 0;
1926
					$proto = 2;
1927
				}
1928

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

    
1933
				/* generate update instructions */
1934
				$upinst = "";
1935
				if (!empty($dnsupdate['server']))
1936
					$upinst .= "server {$dnsupdate['server']}\n";
1937
				$upinst .= "update delete {$dnsupdate['host']} A\n";
1938
				$upinst .= "update add {$dnsupdate['host']} {$dnsupdate['ttl']} A {$wanip}\n";
1939
				$upinst .= "\n";	/* mind that trailing newline! */
1940

    
1941
				@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
1942
				unset($upinst);
1943

    
1944
				/* invoke nsupdate */
1945
				$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
1946
				if (isset($dnsupdate['usetcp']))
1947
					$cmd .= " -v";
1948
				$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
1949

    
1950
				mwexec_bg($cmd);
1951
				unset($cmd);
1952
			}
1953
		}
1954
	}
1955

    
1956
	return 0;
1957
}
1958

    
1959
/* configure cron service */
1960
function configure_cron() {
1961
	global $g, $config;
1962

    
1963
	conf_mount_rw();
1964
	/* preserve existing crontab entries */
1965
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
1966

    
1967
	for ($i = 0; $i < count($crontab_contents); $i++) {
1968
		$cron_item =& $crontab_contents[$i];
1969
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
1970
			array_splice($crontab_contents, $i - 1);
1971
			break;
1972
		}
1973
	}
1974
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
1975

    
1976

    
1977
	if (is_array($config['cron']['item'])) {
1978
		$crontab_contents .= "#\n";
1979
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
1980
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
1981
		$crontab_contents .= "#\n";
1982

    
1983
		foreach ($config['cron']['item'] as $item) {
1984
			$crontab_contents .= "\n{$item['minute']}\t";
1985
			$crontab_contents .= "{$item['hour']}\t";
1986
			$crontab_contents .= "{$item['mday']}\t";
1987
			$crontab_contents .= "{$item['month']}\t";
1988
			$crontab_contents .= "{$item['wday']}\t";
1989
			$crontab_contents .= "{$item['who']}\t";
1990
			$crontab_contents .= "{$item['command']}";
1991
		}
1992

    
1993
		$crontab_contents .= "\n#\n";
1994
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
1995
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
1996
		$crontab_contents .= "#\n\n";
1997
	}
1998

    
1999
	/* please maintain the newline at the end of file */
2000
	file_put_contents("/etc/crontab", $crontab_contents);
2001
	unset($crontab_contents);
2002

    
2003
	/* do a HUP kill to force sync changes */
2004
	exec('/bin/pkill -HUP cron');
2005

    
2006
	conf_mount_ro();
2007
}
2008

    
2009
function upnp_action ($action) {
2010
	global $g, $config;
2011
	switch($action) {
2012
		case "start":
2013
			if (file_exists('/var/etc/miniupnpd.conf')) {
2014
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2015
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2016
			}
2017
			break;
2018
		case "stop":
2019
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2020
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2021
				mwexec('killall miniupnpd 2>/dev/null', true);
2022
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2023
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2024
			break;
2025
		case "restart":
2026
			upnp_action('stop');
2027
			upnp_action('start');
2028
			break;
2029
	}
2030
}
2031

    
2032
function upnp_start() {
2033
	global $config;
2034

    
2035
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2036
		return;
2037

    
2038
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2039
		echo gettext("Starting UPnP service... ");
2040
		require_once('/usr/local/pkg/miniupnpd.inc');
2041
		sync_package_miniupnpd();
2042
		echo "done.\n";
2043
	}
2044
}
2045

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

    
2049
	$is_installed = false;
2050

    
2051
	if (!is_array($config['cron']))
2052
		$config['cron'] = array();
2053
	if (!is_array($config['cron']['item']))
2054
		$config['cron']['item'] = array();
2055

    
2056
	$x=0;
2057
	foreach($config['cron']['item'] as $item) {
2058
		if(strstr($item['command'], $command)) {
2059
			$is_installed = true;
2060
			break;
2061
		}
2062
		$x++;
2063
	}
2064

    
2065
	if($active) {
2066
		$cron_item = array();
2067
		$cron_item['minute'] = $minute;
2068
		$cron_item['hour'] = $hour;
2069
		$cron_item['mday'] = $monthday;
2070
		$cron_item['month'] = $month;
2071
		$cron_item['wday'] = $weekday;
2072
		$cron_item['who'] = $who;
2073
		$cron_item['command'] = $command;
2074
		if(!$is_installed) {
2075
			$config['cron']['item'][] = $cron_item;
2076
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2077
		} else {
2078
			$config['cron']['item'][$x] = $cron_item;
2079
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2080
		}
2081
	} else {
2082
		if(($is_installed == true) && ($x > 0)) {
2083
			unset($config['cron']['item'][$x]);
2084
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2085
		}
2086
	}
2087
	configure_cron();
2088
}
2089

    
2090
?>
(49-49/66)