Project

General

Profile

Download (73.7 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services.inc
4
	part of the pfSense project (http://www.pfsense.com)
5

    
6
	originally part of m0n0wall (http://m0n0.ch/wall)
7
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
8
	Copyright (C) 2010	Ermal Luci
9
	All rights reserved.
10

    
11
	Redistribution and use in source and binary forms, with or without
12
	modification, are permitted provided that the following conditions are met:
13

    
14
	1. Redistributions of source code must retain the above copyright notice,
15
	   this list of conditions and the following disclaimer.
16

    
17
	2. Redistributions in binary form must reproduce the above copyright
18
	   notice, this list of conditions and the following disclaimer in the
19
	   documentation and/or other materials provided with the distribution.
20

    
21
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
23
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
	POSSIBILITY OF SUCH DAMAGE.
31
*/
32

    
33
/*
34
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/bin/pgrep	/bin/sh	/usr/local/sbin/dhcpd	/usr/local/sbin/igmpproxy
35
	pfSense_BUILDER_BINARIES:	/sbin/ifconfig		/usr/local/sbin/dnsmasq
36
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/miniupnpd	/usr/sbin/radvd
37
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/dhcleases6	/usr/sbin/bsnmpd
38
	pfSense_MODULE:	utils
39
*/
40

    
41
define('DYNDNS_PROVIDER_VALUES', 'dnsomatic dyndns dyndns-static dyndns-custom dhs dyns easydns noip noip-free ods zoneedit loopia freedns dnsexit opendns namecheap he-net he-net-v6 he-net-tunnelbroker selfhost route53 cloudflare custom custom-v6 eurodns gratisdns ovh-dynhost citynetwork');
42
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'DNS-O-Matic,DynDNS (dynamic),DynDNS (static),DynDNS (custom),DHS,DyNS,easyDNS,No-IP,No-IP (free),ODS.org,ZoneEdit,Loopia,freeDNS,DNSexit,OpenDNS,Namecheap,HE.net,HE.net (v6),HE.net Tunnelbroker,SelfHost,Route 53,CloudFlare,Custom,Custom (v6),Euro Dns,GratisDNS,OVH DynHOST,City Network');
43

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
358
	if ($g['booting']) {
359
		/* restore the leases, if we have them */
360
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
361
			$dhcprestore = "";
362
			$dhcpreturn = "";
363
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
364
			$dhcprestore = implode(" ", $dhcprestore);
365
			if($dhcpreturn <> 0) {
366
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
367
			}
368
		}
369
		/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
370
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
371
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
372
		}
373
	}
374

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

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

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

    
399
	$dhcpdconf = <<<EOD
400

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

    
413
EOD;
414

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

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

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

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

    
438
		interfaces_staticarp_configure($dhcpif);
439

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

    
443
		if($dhcpifconf['failover_peerip'] <> "") {
444
			$intip = get_interface_ip($dhcpif);
445
			/*
446
			 *    yep, failover peer is defined.
447
			 *    does it match up to a defined vip?
448
			 */
449
			$skew = 110;
450
			if(is_array($config['virtualip']['vip'])) {
451
				foreach ($config['virtualip']['vip'] as $vipent) {
452
					if($vipent['interface'] == $dhcpif) {
453
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
454
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
455
							/* this is the interface! */
456
							if(is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
457
								$skew = 0;
458
								break;
459
							}
460
						}
461
					}
462
				}
463
			} else {
464
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IP's defined!"));
465
			}
466
			if($skew > 10) {
467
				$type = "secondary";
468
				$dhcpdconf_pri  = "mclt 600;\n";
469
				$my_port = "520";
470
				$peer_port = "519";
471
			} else {
472
				$my_port = "519";
473
				$peer_port = "520";
474
				$type = "primary";
475
				$dhcpdconf_pri  = "split 128;\n";
476
				$dhcpdconf_pri .= "  mclt 600;\n";
477
			}
478

    
479
			if (is_ipaddrv4($intip)) {
480
			$dhcpdconf .= <<<EOPP
481
failover peer "dhcp_{$dhcpif}" {
482
  {$type};
483
  address {$intip};
484
  port {$my_port};
485
  peer address {$dhcpifconf['failover_peerip']};
486
  peer port {$peer_port};
487
  max-response-delay 10;
488
  max-unacked-updates 10;
489
  {$dhcpdconf_pri}
490
  load balance max seconds 3;
491
}
492

    
493
EOPP;
494
			}
495
		}
496
	}
497

    
498
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
499

    
500
		$newzone = array();
501
		$ifcfg = $config['interfaces'][$dhcpif];
502

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

    
510
		if (!is_ipaddr($subnet))
511
			continue;
512

    
513
		if($is_olsr_enabled == true)
514
			if($dhcpifconf['netmask'])
515
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
516

    
517
		$all_pools = array();
518
		$all_pools[] = $dhcpifconf;
519
		if (is_array($dhcpifconf['pool'])) {
520
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
521
		}
522

    
523
		$dnscfg = "";
524

    
525
		if ($dhcpifconf['domain']) {
526
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
527
		}
528

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

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

    
552
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
553
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
554
			if ($newzone['domain-name'])
555
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
556
		} else if (isset($config['dnsmasq']['enable'])) {
557
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
558
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
559
				$newzone['dns-servers'] = $syscfg['dnsserver'];
560
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
561
			$dnscfg .= "	option domain-name-servers " . join(",", $syscfg['dnsserver']) . ";";
562
			if ($newzone['domain-name'])
563
				$newzone['dns-servers'] = $syscfg['dnsserver'];
564
		}
565

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

    
587
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
588

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

    
600
			/* allow/deny MACs */
601
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
602
			foreach ($mac_allow_list as $mac) {
603
				if (empty($mac))
604
					continue;
605
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
606
			}
607
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
608
			foreach ($mac_deny_list as $mac) {
609
				if (empty($mac))
610
					continue;
611
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
612
			}
613

    
614
			if($poolconf['failover_peerip'] <> "")
615
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
616

    
617
			if (isset($poolconf['denyunknown']))
618
			   $dhcpdconf .= "		deny unknown-clients;\n";
619

    
620
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway']))
621
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
622

    
623
			if($dhcpifconf['failover_peerip'] <> "") {
624
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
625
			}
626

    
627
			$pdnscfg = "";
628

    
629
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
630
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
631
			}
632

    
633
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
634
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
635
			}
636

    
637
			if (isset($poolconf['ddnsupdate'])) {
638
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
639
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
640
				$pdnscfg .= "		ddns-update-style interim;\n";
641
			}
642

    
643
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
644
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
645
			}
646
			$dhcpdconf .= "{$pdnscfg}";
647

    
648
			// default-lease-time
649
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
650
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
651

    
652
			// max-lease-time
653
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
654
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
655

    
656
			// netbios-name*
657
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
658
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
659
				$dhcpdconf .= "		option netbios-node-type 8;\n";
660
			}
661

    
662
			// ntp-servers
663
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
664
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
665

    
666
			// tftp-server-name
667
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
668
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
669

    
670
			// ldap-server
671
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
672
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
673

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

    
691
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
692
			$routers = $dhcpifconf['gateway'];
693
			$add_routers = true;
694
		} elseif ($dhcpifconf['gateway'] == "none") {
695
			$add_routers = false;
696
		} else {
697
			$routers = $ifcfgip;
698
		}
699
		if($add_routers)
700
			$dhcpdconf .= "	option routers {$routers};\n";
701

    
702
		$dhcpdconf .= <<<EOD
703
$dnscfg
704

    
705
EOD;
706
    		// default-lease-time
707
		if ($dhcpifconf['defaultleasetime'])
708
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
709

    
710
		// max-lease-time
711
		if ($dhcpifconf['maxleasetime'])
712
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
713

    
714
		// netbios-name*
715
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
716
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
717
			$dhcpdconf .= "	option netbios-node-type 8;\n";
718
		}
719

    
720
		// ntp-servers
721
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
722
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
723

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

    
728
		// Handle option, number rowhelper values
729
		$dhcpdconf .= "\n";
730
		if($dhcpifconf['numberoptions']['item']) {
731
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
732
				if(empty($item['type']) || $item['type'] == "text")
733
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
734
				else
735
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
736
			}
737
		}
738

    
739
		// ldap-server
740
		if ($dhcpifconf['ldap'] <> "")
741
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
742

    
743
		// net boot information
744
		if(isset($dhcpifconf['netboot'])) {
745
			if ($dhcpifconf['nextserver'] <> "") {
746
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
747
			}
748
			if ($dhcpifconf['filename'] <> "") {
749
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
750
			}
751
			if ($dhcpifconf['rootpath'] <> "") {
752
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
753
			}
754
		}
755

    
756
		$dhcpdconf .= <<<EOD
757
}
758

    
759
EOD;
760

    
761
		/* add static mappings */
762
		if (is_array($dhcpifconf['staticmap'])) {
763

    
764
			$i = 0;
765
			foreach ($dhcpifconf['staticmap'] as $sm) {
766
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
767

    
768
                if ($sm['mac'])
769
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
770

    
771
                if ($sm['cid'])
772
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
773

    
774
				if ($sm['ipaddr'])
775
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
776

    
777
				if ($sm['hostname']) {
778
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
779
					$dhhostname = str_replace(".", "_", $dhhostname);
780
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
781
				}
782
				if ($sm['filename'])
783
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
784

    
785
				if ($sm['rootpath'])
786
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
787

    
788
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
789
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
790

    
791
				$smdnscfg = "";
792

    
793
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
794
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
795
				}
796

    
797
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
798
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
799
				}
800

    
801
				if (isset($sm['ddnsupdate'])) {
802
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
803
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
804
					$pdnscfg .= "		ddns-update-style interim;\n";
805
				}
806

    
807
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
808
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
809
				}
810
				$dhcpdconf .= "{$smdnscfg}";
811

    
812
				// default-lease-time
813
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
814
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
815

    
816
				// max-lease-time
817
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
818
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
819

    
820
				// netbios-name*
821
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
822
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
823
					$dhcpdconf .= "	option netbios-node-type 8;\n";
824
				}
825

    
826
				// ntp-servers
827
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
828
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
829

    
830
				// tftp-server-name
831
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
832
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
833

    
834
				$dhcpdconf .= "}\n";
835
				$i++;
836
			}
837
		}
838

    
839
		$dhcpdifs[] = get_real_interface($dhcpif);
840
		if ($newzone['domain-name'])
841
		{
842
			if ($need_ddns_updates)
843
			{
844
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
845
			}
846
			$ddns_zones[] = $newzone;
847
		}
848
	}
849

    
850
	if ($need_ddns_updates) {
851
		$dhcpdconf .= "ddns-update-style interim;\n";
852

    
853
		$dhcpdconf .= dhcpdkey($dhcpifconf);
854
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
855
	}
856

    
857
	/* write dhcpd.conf */
858
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
859
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
860
		unset($dhcpdconf);
861
		return 1;
862
	}
863
	unset($dhcpdconf);
864

    
865
	/* create an empty leases database */
866
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
867
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
868

    
869
	/* fire up dhcpd in a chroot */
870
	if (count($dhcpdifs) > 0) {
871
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
872
			join(" ", $dhcpdifs));
873
	}
874

    
875
	if ($g['booting'])
876
		print "done.\n";
877

    
878
	return 0;
879
}
880

    
881
function dhcpdkey($dhcpifconf)
882
{
883
	$dhcpdconf = "";
884
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
885
	{
886
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
887
		$dhcpdconf .= "	algorithm hmac-md5;\n";
888
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
889
		$dhcpdconf .= "}\n";
890
	}
891

    
892
	return $dhcpdconf;
893
}
894

    
895
function dhcpdzones($ddns_zones, $dhcpifconf)
896
{
897
	$dhcpdconf = "";
898

    
899
	if (is_array($ddns_zones)) {
900
		$added_zones = array();
901
		foreach ($ddns_zones as $zone) {
902
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
903
				continue;
904
			$primary = $zone['dns-servers'][0];
905
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
906

    
907
			// Make sure we aren't using any invalid or IPv6 DNS servers.
908
			if (!is_ipaddrv4($primary)) {
909
				if (is_ipaddrv4($secondary)) {
910
					$primary = $secondary;
911
					$secondary = "";
912
				} else {
913
					continue;
914
				}
915
			}
916

    
917
			// We don't need to add zones multiple times.
918
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
919
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
920
				$dhcpdconf .= "	primary {$primary};\n";
921
				if (is_ipaddrv4($secondary))
922
					$dhcpdconf .= "	secondary {$secondary};\n";
923
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
924
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
925
				$dhcpdconf .= "}\n";
926
				$added_zones[] = $zone['domain-name'];
927
			}
928
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
929
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
930
				$dhcpdconf .= "	primary {$primary};\n";
931
				if (is_ipaddrv4($secondary))
932
					$dhcpdconf .= "	secondary {$secondary};\n";
933
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
934
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
935
				$dhcpdconf .= "}\n";
936
				$added_zones[] = $zone['ptr-domain'];
937
			}
938
		}
939
	}
940

    
941
	return $dhcpdconf;
942
}
943

    
944
function services_dhcpdv6_configure() {
945
	global $config, $g;
946

    
947
	if($g['services_dhcp_server_enable'] == false)
948
		return;
949

    
950
	if(isset($config['system']['developerspew'])) {
951
		$mt = microtime();
952
		echo "services_dhcpd_configure($if) being called $mt\n";
953
	}
954

    
955
	/* kill any running dhcpd */
956
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
957
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
958
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
959
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
960

    
961
	/* DHCP enabled on any interfaces? */
962
	if (!is_dhcpv6_server_enabled())
963
		return 0;
964

    
965
	if ($g['booting']) {
966
		if ($g['platform'] != "pfSense") {
967
			/* restore the leases, if we have them */
968
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
969
				$dhcprestore = "";
970
				$dhcpreturn = "";
971
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
972
				$dhcprestore = implode(" ", $dhcprestore);
973
				if($dhcpreturn <> 0) {
974
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
975
				}
976
			}
977
		}
978
	}
979

    
980
	$syscfg = $config['system'];
981
	if (!is_array($config['dhcpdv6']))
982
		$config['dhcpdv6'] = array();
983
	$dhcpdv6cfg = $config['dhcpdv6'];
984
	$Iflist = get_configured_interface_list();
985
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
986

    
987

    
988
	if ($g['booting'])
989
		echo "Starting DHCPv6 service...";
990
	else
991
		sleep(1);
992

    
993
	/* we add a fake entry for interfaces that are set to track6 another WAN */
994
	foreach ($Iflist as $ifname) {
995
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
996
			$realif = get_real_interface($ifname, "inet6");
997
			$ifcfgipv6 = get_interface_ipv6($ifname);
998
			if(!is_ipaddrv6($ifcfgipv6))
999
				continue;
1000
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1001
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1002
			$trackcfg = $config['interfaces'][$trackifname];
1003
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1004
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1005
			$dhcpdv6cfg[$ifname] = array();
1006
			$dhcpdv6cfg[$ifname]['enable'] = true;
1007
			/* range */
1008
			$ifcfgipv6arr[7] = "1000";
1009
			$dhcpdv6cfg[$ifname]['range'] = array();
1010
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1011
			$ifcfgipv6arr[7] = "2000";
1012
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));;
1013
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1014
			if($pdlen > 2) {
1015
				$pdlenmax = $pdlen;
1016
				$pdlenhalf = $pdlenmax -1;
1017
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1018
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1019
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1020

    
1021
				/* set the delegation start to half the current address block */
1022
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1023
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1024

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

    
1029
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1030
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1031
				$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1032
			}
1033
		}
1034
	}
1035

    
1036
	$custoptionsv6 = "";
1037
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1038
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1039
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1040
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1041
			}
1042
		}
1043
	}
1044

    
1045
	if(isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url']))
1046
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1047

    
1048
	$dhcpdv6conf = <<<EOD
1049

    
1050
option domain-name "{$syscfg['domain']}";
1051
option ldap-server code 95 = text;
1052
option domain-search-list code 119 = text;
1053
{$custoptionsv6}
1054
default-lease-time 7200;
1055
max-lease-time 86400;
1056
log-facility local7;
1057
one-lease-per-client true;
1058
deny duplicates;
1059
ping-check true;
1060
update-conflict-detection false;
1061

    
1062
EOD;
1063

    
1064
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1065
		$dhcpdv6conf .= "authoritative;\n";
1066

    
1067
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1068
		$dhcpdv6conf .= "always-broadcast on\n";
1069

    
1070
	$dhcpdv6ifs = array();
1071

    
1072
	$dhcpv6num = 0;
1073
	$nsupdate = false;
1074

    
1075
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1076

    
1077
		$ddns_zones = array();
1078

    
1079
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1080

    
1081
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]))
1082
			continue;
1083
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1084
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1085
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1086

    
1087
		if ($is_olsr_enabled == true) {
1088
			if($dhcpv6ifconf['netmask'])
1089
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1090
		}
1091

    
1092
		$dnscfgv6 = "";
1093

    
1094
		if ($dhcpv6ifconf['domain']) {
1095
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1096
		}
1097

    
1098
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1099
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1100
    	}
1101

    
1102
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1103
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1104
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1105
			}
1106
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1107
			$nsupdate = true;
1108
		}
1109

    
1110
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1111
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1112
		} else if ((isset($config['dnsmasq']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1113
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1114
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1115
			$dns_arrv6 = array();
1116
			foreach($syscfg['dnsserver'] as $dnsserver) {
1117
				if (is_ipaddrv6($dnsserver)) {
1118
					$dns_arrv6[] = $dnsserver;
1119
				}
1120
			}
1121
			if(!empty($dns_arrv6))
1122
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1123
		}
1124

    
1125
		if ($dhcpv6ifconf['domain']) {
1126
			$newzone = array();
1127
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1128
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1129
			$ddns_zones[] = $newzone;
1130
		}
1131

    
1132
		if (is_ipaddrv6($ifcfgipv6)) {
1133
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1134
		} else {
1135
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1136
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1137
		}
1138
		$dhcpdv6conf .= " {\n";
1139

    
1140
		$dhcpdv6conf .= <<<EOD
1141
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1142
$dnscfgv6
1143

    
1144
EOD;
1145

    
1146
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1147
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']}/{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1148
		}
1149
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1150
			$dhcpdv6conf .= "       option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1151
		}
1152
    		// default-lease-time
1153
		if ($dhcpv6ifconf['defaultleasetime'])
1154
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1155

    
1156
		// max-lease-time
1157
		if ($dhcpv6ifconf['maxleasetime'])
1158
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1159

    
1160
		// ntp-servers
1161
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1162
			$ntpservers = array();
1163
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1164
				if(is_ipaddrv6($ntpserver))
1165
					$ntpservers[] = $ntpserver;
1166
			}
1167
			if(count($ntpservers) > 0 )
1168
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1169
		}
1170
		// tftp-server-name
1171
		/* Needs ISC DHCPD support
1172
		 if ($dhcpv6ifconf['tftp'] <> "")
1173
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1174
		*/
1175

    
1176
		// Handle option, number rowhelper values
1177
		$dhcpdv6conf .= "\n";
1178
		if ($dhcpv6ifconf['numberoptions']['item']) {
1179
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1180
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1181
			}
1182
		}
1183

    
1184
		// ldap-server
1185
		if ($dhcpv6ifconf['ldap'] <> "")
1186
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1187

    
1188
		// net boot information
1189
		if(isset($dhcpv6ifconf['netboot'])) {
1190
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1191
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1192
			}
1193
		}
1194

    
1195
		$dhcpdv6conf .= "}\n";
1196

    
1197
		/* add static mappings */
1198
		/* Needs to use DUID */
1199
		if (is_array($dhcpv6ifconf['staticmap'])) {
1200
			$i = 0;
1201
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1202
				$dhcpdv6conf .= <<<EOD
1203
host s_{$dhcpv6if}_{$i} {
1204
	host-identifier option dhcp6.client-id {$sm['duid']};
1205

    
1206
EOD;
1207
				if ($sm['ipaddrv6'])
1208
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1209

    
1210
				if ($sm['hostname']) {
1211
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1212
					$dhhostname = str_replace(".", "_", $dhhostname);
1213
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1214
				}
1215
				if ($sm['filename'])
1216
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1217

    
1218
				if ($sm['rootpath'])
1219
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1220

    
1221
				$dhcpdv6conf .= "}\n";
1222
				$i++;
1223
			}
1224
		}
1225

    
1226
		if ($dhcpv6ifconf['domain'])
1227
		{
1228
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1229
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1230
		}
1231

    
1232
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged") {
1233
			if(preg_match("/poes/si", $dhcpv6if)) {
1234
				/* magic here */
1235
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1236
			} else {
1237
				$realif = get_real_interface($dhcpv6if, "inet6");
1238
				if (stristr("$realif", "bridge")) {
1239
					$mac = get_interface_mac($realif);
1240
					$v6address = generate_ipv6_from_mac($mac);
1241
					/* Create link local address for bridges */
1242
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1243
				}
1244
				$realif = escapeshellcmd($realif);
1245
				$dhcpdv6ifs[] = $realif;
1246
			}
1247
		}
1248
	}
1249

    
1250
	if ($nsupdate)
1251
	{
1252
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1253
	}
1254
	else
1255
	{
1256
		$dhcpdv6conf .= "ddns-update-style none;\n";
1257
	}
1258

    
1259
	/* write dhcpdv6.conf */
1260
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1261
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1262
		if ($g['booting'])
1263
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1264
		unset($dhcpdv6conf);
1265
		return 1;
1266
	}
1267
	unset($dhcpdv6conf);
1268

    
1269
	/* create an empty leases v6 database */
1270
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1271
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1272

    
1273
	/* fire up dhcpd in a chroot */
1274
	if (count($dhcpdv6ifs) > 0) {
1275
		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 " .
1276
			join(" ", $dhcpdv6ifs));
1277
		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");
1278
	}
1279
	if ($g['booting'])
1280
		print gettext("done.") . "\n";
1281

    
1282
	return 0;
1283
}
1284

    
1285
function services_igmpproxy_configure() {
1286
        global $config, $g;
1287

    
1288
        /* kill any running igmpproxy */
1289
        killbyname("igmpproxy");
1290

    
1291
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1292
		return 1;
1293

    
1294
        $iflist = get_configured_interface_list();
1295

    
1296
        $igmpconf = <<<EOD
1297

    
1298
##------------------------------------------------------
1299
## Enable Quickleave mode (Sends Leave instantly)
1300
##------------------------------------------------------
1301
quickleave
1302

    
1303
EOD;
1304

    
1305
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1306
                unset($iflist[$igmpcf['ifname']]);
1307
                $realif = get_real_interface($igmpcf['ifname']);
1308
                if (empty($igmpcf['threshold']))
1309
                        $threshld = 1;
1310
                else
1311
                        $threshld = $igmpcf['threshold'];
1312
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1313

    
1314
                if ($igmpcf['address'] <> "") {
1315
                        $item = explode(" ", $igmpcf['address']);
1316
                        foreach($item as $iww)
1317
                                $igmpconf .= "altnet {$iww}\n";
1318
                }
1319
                $igmpconf .= "\n";
1320
        }
1321
        foreach ($iflist as $ifn) {
1322
                $realif = get_real_interface($ifn);
1323
                $igmpconf .= "phyint {$realif} disabled\n";
1324
        }
1325
	$igmpconf .= "\n";
1326

    
1327
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1328
        if (!$igmpfl) {
1329
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1330
                return;
1331
        }
1332
        fwrite($igmpfl, $igmpconf);
1333
        fclose($igmpfl);
1334
	unset($igmpconf);
1335

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

    
1340
        return 0;
1341
}
1342

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

    
1352
	/* kill any running dhcrelay */
1353
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1354

    
1355
	$dhcrelaycfg =& $config['dhcrelay'];
1356

    
1357
	/* DHCPRelay enabled on any interfaces? */
1358
	if (!isset($dhcrelaycfg['enable']))
1359
		return 0;
1360

    
1361
	if ($g['booting'])
1362
		echo gettext("Starting DHCP relay service...");
1363
	else
1364
		sleep(1);
1365

    
1366
	$iflist = get_configured_interface_list();
1367

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

    
1374
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1375
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1376
	}
1377

    
1378
	/*
1379
	 * In order for the relay to work, it needs to be active
1380
	 * on the interface in which the destination server sits.
1381
	 */
1382
	$srvips = explode(",", $dhcrelaycfg['server']);
1383
	foreach ($srvips as $srcidx => $srvip) {
1384
		unset($destif);
1385
		foreach ($iflist as $ifname) {
1386
			$subnet = get_interface_ip($ifname);
1387
			if (!is_ipaddr($subnet))
1388
				continue;
1389
			$subnet .=  "/" . get_interface_subnet($ifname);
1390
			if (ip_in_subnet($srvip, $subnet)) {
1391
				$destif = get_real_interface($ifname);
1392
				break;
1393
			}
1394
		}
1395
		if (!isset($destif)) {
1396
			foreach (get_staticroutes() as $rtent) {
1397
				if (ip_in_subnet($srvip, $rtent['network'])) {
1398
					$a_gateways = return_gateways_array(true);
1399
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1400
					break;
1401
				}
1402
			}
1403
		}
1404

    
1405
		if (!isset($destif)) {
1406
			/* Create a array from the existing route table */
1407
        		exec("/usr/bin/netstat -rnWf inet", $route_str);
1408
        		array_shift($route_str);
1409
        		array_shift($route_str);
1410
        		array_shift($route_str);
1411
        		array_shift($route_str);
1412
        		$route_arr = array();
1413
        		foreach($route_str as $routeline) {
1414
				$items = preg_split("/[ ]+/i", $routeline);
1415
				if (is_subnetv4($items[0])) {
1416
					$subnet = $items[0];
1417
				} elseif (is_ipaddrv4($items[0])) {
1418
					$subnet = "{$items[0]}/32";
1419
				} else {
1420
					// Not a subnet or IP address, skip to the next line.
1421
					continue;
1422
				}
1423
				if (ip_in_subnet($srvip, $subnet)) {
1424
					$destif = trim($items[6]);
1425
					break;
1426
				}
1427
			}
1428
		}
1429

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

    
1442
		if (!empty($destif))
1443
			$dhcrelayifs[] = $destif;
1444
	}
1445
	$dhcrelayifs = array_unique($dhcrelayifs);
1446

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

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

    
1455
	if (isset($dhcrelaycfg['agentoption']))
1456
		$cmd .=  " -a -m replace";
1457

    
1458
	$cmd .= " " . implode(" ", $srvips);
1459
	mwexec($cmd);
1460
	unset($cmd);
1461

    
1462
	return 0;
1463
}
1464

    
1465
function services_dhcrelay6_configure() {
1466
	global $config, $g;
1467
	if ($g['platform'] == 'jail')
1468
		return;
1469
	if(isset($config['system']['developerspew'])) {
1470
		$mt = microtime();
1471
		echo "services_dhcrelay6_configure() being called $mt\n";
1472
	}
1473

    
1474
	/* kill any running dhcrelay */
1475
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1476

    
1477
	$dhcrelaycfg =& $config['dhcrelay6'];
1478

    
1479
	/* DHCPv6 Relay enabled on any interfaces? */
1480
	if (!isset($dhcrelaycfg['enable']))
1481
		return 0;
1482

    
1483
	if ($g['booting'])
1484
		echo gettext("Starting DHCPv6 relay service...");
1485
	else
1486
		sleep(1);
1487

    
1488
	$iflist = get_configured_interface_list();
1489

    
1490
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1491
	foreach ($dhcifaces as $dhcrelayif) {
1492
		if (!isset($iflist[$dhcrelayif]) ||
1493
			link_interface_to_bridge($dhcrelayif))
1494
			continue;
1495

    
1496
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1497
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1498
	}
1499
	$dhcrelayifs = array_unique($dhcrelayifs);
1500

    
1501
	/*
1502
	 * In order for the relay to work, it needs to be active
1503
	 * on the interface in which the destination server sits.
1504
	 */
1505
	$srvips = explode(",", $dhcrelaycfg['server']);
1506
        $srvifaces = array();
1507
	foreach ($srvips as $srcidx => $srvip) {
1508
		unset($destif);
1509
		foreach ($iflist as $ifname) {
1510
			$subnet = get_interface_ipv6($ifname);
1511
			if (!is_ipaddrv6($subnet))
1512
				continue;
1513
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1514
			if (ip_in_subnet($srvip, $subnet)) {
1515
				$destif = get_real_interface($ifname);
1516
				break;
1517
			}
1518
		}
1519
		if (!isset($destif)) {
1520
			if (is_array($config['staticroutes']['route'])) {
1521
				foreach ($config['staticroutes']['route'] as $rtent) {
1522
					if (ip_in_subnet($srvip, $rtent['network'])) {
1523
						$a_gateways = return_gateways_array(true);
1524
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1525
						break;
1526
					}
1527
				}
1528
			}
1529
		}
1530

    
1531
		if (!isset($destif)) {
1532
			/* Create a array from the existing route table */
1533
        		exec("/usr/bin/netstat -rnWf inet6", $route_str);
1534
        		array_shift($route_str);
1535
        		array_shift($route_str);
1536
        		array_shift($route_str);
1537
        		array_shift($route_str);
1538
        		$route_arr = array();
1539
        		foreach($route_str as $routeline) {
1540
                		$items = preg_split("/[ ]+/i", $routeline);
1541
				if (ip_in_subnet($srvip, $items[0])) {
1542
					$destif = trim($items[6]);
1543
					break;
1544
				}
1545
        		}
1546
		}
1547

    
1548
		if (!isset($destif)) {
1549
			if (is_array($config['gateways']['gateway_item'])) {
1550
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1551
					if (isset($gateway['defaultgw'])) {
1552
						$destif = $gateway['interface'];
1553
						break;
1554
					}
1555
				}
1556
			} else
1557
				$destif = get_real_interface("wan");
1558
		}
1559

    
1560
		if (!empty($destif)) {
1561
			$srvifaces[] = "{$srvip}%{$destif}";
1562
		}
1563
	}
1564

    
1565
	/* fire up dhcrelay */
1566
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1567
		log_error("No suitable interface found for running dhcrelay -6!");
1568
		return; /* XXX */
1569
	}
1570

    
1571
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1572
	foreach ($dhcrelayifs as $dhcrelayif) {
1573
		$cmd .= " -l {$dhcrelayif}";
1574
	}
1575
	foreach ($srvifaces as $srviface) {
1576
		$cmd .= " -u \"{$srviface}\"";
1577
	}
1578
	mwexec($cmd);
1579
	unset($cmd);
1580

    
1581
	return 0;
1582
}
1583

    
1584
function services_dyndns_configure_client($conf) {
1585

    
1586
	if (!isset($conf['enable']))
1587
		return;
1588

    
1589
	/* load up the dyndns.class */
1590
	require_once("dyndns.class");
1591

    
1592
	$dns = new updatedns($dnsService = $conf['type'],
1593
		$dnsHost = $conf['host'],
1594
		$dnsUser = $conf['username'],
1595
		$dnsPass = $conf['password'],
1596
		$dnsWilcard = $conf['wildcard'],
1597
		$dnsMX = $conf['mx'],
1598
		$dnsIf = "{$conf['interface']}",
1599
		$dnsBackMX = NULL,
1600
		$dnsServer = NULL,
1601
		$dnsPort = NULL,
1602
		$dnsUpdateURL = "{$conf['updateurl']}",
1603
		$forceUpdate = $conf['force'],
1604
		$dnsZoneID=$conf['zoneid'],
1605
		$dnsTTL=$conf['ttl'],
1606
		$dnsResultMatch = "{$conf['resultmatch']}",
1607
		$dnsRequestIf = "{$conf['requestif']}",
1608
		$dnsID = "{$conf['id']}",
1609
		$dnsVerboseLog = $conf['verboselog'],
1610
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1611
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1612
}
1613

    
1614
function services_dyndns_configure($int = "") {
1615
	global $config, $g;
1616
	if(isset($config['system']['developerspew'])) {
1617
		$mt = microtime();
1618
		echo "services_dyndns_configure() being called $mt\n";
1619
	}
1620

    
1621
	$dyndnscfg = $config['dyndnses']['dyndns'];
1622
	$gwgroups = return_gateway_groups_array();
1623
	if (is_array($dyndnscfg)) {
1624
		if ($g['booting'])
1625
			echo gettext("Starting DynDNS clients...");
1626

    
1627
		foreach ($dyndnscfg as $dyndns) {
1628
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1629
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1630
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1631
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1632
				services_dyndns_configure_client($dyndns);
1633
				sleep(1);
1634
			}
1635
		}
1636

    
1637
		if ($g['booting'])
1638
			echo gettext("done.") . "\n";
1639
	}
1640

    
1641
	return 0;
1642
}
1643

    
1644
function dyndnsCheckIP($int) {
1645
	global $config;
1646
	$ip_address = get_interface_ip($int);
1647
	if (is_private_ip($ip_address)) {
1648
		$gateways_status = return_gateways_status(true);
1649
		// If the gateway for this interface is down, then the external check cannot work.
1650
		// Avoid the long wait for the external check to timeout.
1651
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1652
			return "down";
1653
		$hosttocheck = "checkip.dyndns.org";
1654
		$checkip = gethostbyname($hosttocheck);
1655
		$ip_ch = curl_init("http://{$checkip}");
1656
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1657
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1658
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1659
		$ip_result_page = curl_exec($ip_ch);
1660
		curl_close($ip_ch);
1661
		$ip_result_decoded = urldecode($ip_result_page);
1662
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1663
		$ip_address = trim($matches[1]);
1664
	}
1665
	return $ip_address;
1666
}
1667

    
1668
function services_dnsmasq_configure() {
1669
	global $config, $g;
1670
	$return = 0;
1671

    
1672
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1673
	$standard_args = array(
1674
		"dns-forward-max" => "--dns-forward-max=5000",
1675
		"cache-size" => "--cache-size=10000",
1676
		"local-ttl" => "--local-ttl=1"
1677
	);
1678

    
1679

    
1680
	if(isset($config['system']['developerspew'])) {
1681
		$mt = microtime();
1682
		echo "services_dnsmasq_configure() being called $mt\n";
1683
	}
1684

    
1685
	/* kill any running dnsmasq */
1686
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1687
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1688

    
1689
	if (isset($config['dnsmasq']['enable'])) {
1690

    
1691
		if ($g['booting'])
1692
			echo gettext("Starting DNS forwarder...");
1693
		else
1694
			sleep(1);
1695

    
1696
		$args = "";
1697

    
1698
		if (isset($config['dnsmasq']['regdhcp'])) {
1699
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1700
		}
1701

    
1702
		/* Setup listen port, if non-default */
1703
		if (is_port($config['dnsmasq']['port']))
1704
			$args .= " --port={$config['dnsmasq']['port']} ";
1705

    
1706
		$listen_addresses = "";
1707
		if(isset($config['dnsmasq']['interface'])) {
1708
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1709
			foreach ($interfaces as $interface) {
1710
				if (is_ipaddrv4($interface)) {
1711
					$listen_addresses .= " --listen-address={$interface} ";
1712
				} else if (is_ipaddrv6($interface)) {
1713
					/*
1714
					 * XXX: Since dnsmasq does not support link-local address
1715
					 * with scope specified. These checks are being done.
1716
					 */
1717
					if (is_linklocal($interface) && strstr($interface, "%")) {
1718
						$tmpaddrll6 = explode("%", $interface);
1719
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1720
					} else 
1721
						$listen_addresses .= " --listen-address={$interface} ";
1722
				} else {
1723
					$if = get_real_interface($interface);
1724
					if (does_interface_exist($if)) {
1725
						$laddr = find_interface_ip($if);
1726
						if (is_ipaddrv4($laddr))
1727
							$listen_addresses .= " --listen-address={$laddr} ";
1728
						$laddr6 = find_interface_ipv6($if);
1729
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1730
							/*
1731
							 * XXX: Since dnsmasq does not support link-local address
1732
							 * with scope specified. These checks are being done.
1733
							 */
1734
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1735
								$tmpaddrll6 = explode("%", $laddr6);
1736
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1737
							} else
1738
								$listen_addresses .= " --listen-address={$laddr6} ";
1739
						}
1740
					}
1741
				}
1742
			}
1743
			if (!empty($listen_addresses)) {
1744
				$args .= " {$listen_addresses} ";
1745
				if (isset($config['dnsmasq']['strictbind']))
1746
					$args .= " --bind-interfaces ";
1747
			}
1748
		}
1749

    
1750
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1751
		/* If any of these are duplicated by a user-specified domain override (e.g. 10.in-addr.arpa) then */
1752
		/* the user-specified entry made later on the command line below will be the one that is effective. */
1753
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1754
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1755
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1756
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1757
			$args .= " --server=/10.in-addr.arpa/ ";
1758
			$args .= " --server=/168.192.in-addr.arpa/ ";
1759
			/* Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme. */
1760
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1761
				$args .= " --server=/" . $subnet_num . ".172.in-addr.arpa/ ";
1762
			}
1763
		}
1764

    
1765
		/* Setup forwarded domains */
1766
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1767
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1768
				if ($override['ip'] == "!")
1769
					$override[ip] = "";
1770
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1771
			}
1772
		}
1773

    
1774
		/* Allow DNS Rebind for forwarded domains */
1775
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1776
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1777
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1778
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1779
				}
1780
			}
1781
		}
1782

    
1783
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1784
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1785

    
1786
		if (isset($config['dnsmasq']['strict_order'])) {
1787
			$args .= " --strict-order ";
1788
		}
1789

    
1790
		if (isset($config['dnsmasq']['domain_needed'])) {
1791
			$args .= " --domain-needed ";
1792
		}
1793

    
1794
		if ($config['dnsmasq']['custom_options'])
1795
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1796
				$args .= " --$c";
1797
				$p = explode('=', $c);
1798
				if (array_key_exists($p[0], $standard_args))
1799
					unset($standard_args[$p[0]]);
1800
			}
1801
		$args .= ' ' . implode(' ', array_values($standard_args));
1802

    
1803
		/* run dnsmasq */
1804
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1805
		//log_error("dnsmasq command: {$cmd}");
1806
		mwexec_bg($cmd);
1807
		unset($args);
1808

    
1809
		if ($g['booting'])
1810
			echo gettext("done.") . "\n";
1811
	}
1812

    
1813
	if (!$g['booting']) {
1814
		if(services_dhcpd_configure()!=0)
1815
			$return = 1;
1816
	}
1817

    
1818
	return $return;
1819
}
1820

    
1821
function services_unbound_configure() {
1822
	global $config, $g;
1823
	$return = 0;
1824

    
1825
	if (isset($config['system']['developerspew'])) {
1826
		$mt = microtime();
1827
		echo "services_unbound_configure() being called $mt\n";
1828
	}
1829

    
1830
	// kill any running Unbound instance
1831
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1832
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1833

    
1834
	if (isset($config['unbound']['enable'])) {
1835
		if ($g['booting'])
1836
			echo gettext("Starting Unbound DNS forwarder...");
1837
		else
1838
			sleep(1);
1839

    
1840
		require_once('/etc/inc/unbound.inc');
1841
		sync_unbound_service();
1842
		if ($g['booting'])
1843
			echo gettext("done.") . "\n";
1844
	}
1845

    
1846
	if (!$g['booting']) {
1847
		if (services_dhcpd_configure()!=0)
1848
			$return = 1;
1849
	}
1850

    
1851
	return $return;
1852
}
1853

    
1854
function services_snmpd_configure() {
1855
	global $config, $g;
1856
	if(isset($config['system']['developerspew'])) {
1857
		$mt = microtime();
1858
		echo "services_snmpd_configure() being called $mt\n";
1859
	}
1860

    
1861
	/* kill any running snmpd */
1862
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1863
	sleep(2);
1864
	if(is_process_running("bsnmpd"))
1865
		mwexec("/usr/bin/killall bsnmpd", true);
1866

    
1867
	if (isset($config['snmpd']['enable'])) {
1868

    
1869
		if ($g['booting'])
1870
			echo gettext("Starting SNMP daemon... ");
1871

    
1872
		/* generate snmpd.conf */
1873
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1874
		if (!$fd) {
1875
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1876
			return 1;
1877
		}
1878

    
1879

    
1880
		$snmpdconf = <<<EOD
1881
location := "{$config['snmpd']['syslocation']}"
1882
contact := "{$config['snmpd']['syscontact']}"
1883
read := "{$config['snmpd']['rocommunity']}"
1884

    
1885
EOD;
1886

    
1887
/* No docs on what write strings do there for disable for now.
1888
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1889
		    $snmpdconf .= <<<EOD
1890
# write string
1891
write := "{$config['snmpd']['rwcommunity']}"
1892

    
1893
EOD;
1894
		}
1895
*/
1896

    
1897

    
1898
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1899
		    $snmpdconf .= <<<EOD
1900
# SNMP Trap support.
1901
traphost := {$config['snmpd']['trapserver']}
1902
trapport := {$config['snmpd']['trapserverport']}
1903
trap := "{$config['snmpd']['trapstring']}"
1904

    
1905

    
1906
EOD;
1907
		}
1908

    
1909
		$version = trim(file_get_contents('/etc/version'));
1910
		$platform = trim(file_get_contents('/etc/platform'));
1911
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1912
			$platform = $g['product_name'];
1913
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1914
			" {$version} {$platform} " . php_uname("s") .
1915
			" " . php_uname("r") . " " . php_uname("m");
1916

    
1917
		$snmpdconf .= <<<EOD
1918
system := 1     # pfSense
1919
%snmpd
1920
sysDescr			= "{$sysDescr}"
1921
begemotSnmpdDebugDumpPdus       = 2
1922
begemotSnmpdDebugSyslogPri      = 7
1923
begemotSnmpdCommunityString.0.1 = $(read)
1924

    
1925
EOD;
1926

    
1927
/* No docs on what write strings do there for disable for now.
1928
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1929
		    $snmpdconf .= <<<EOD
1930
begemotSnmpdCommunityString.0.2 = $(write)
1931

    
1932
EOD;
1933
		}
1934
*/
1935

    
1936

    
1937
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1938
		    $snmpdconf .= <<<EOD
1939
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1940
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1941
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1942

    
1943
EOD;
1944
		}
1945

    
1946

    
1947
		$snmpdconf .= <<<EOD
1948
begemotSnmpdCommunityDisable    = 1
1949

    
1950
EOD;
1951

    
1952
		if (isset($config['snmpd']['bindlan'])) {
1953
			$config['snmpd']['bindip'] = 'lan';
1954
			unset($config['snmpd']['bindlan']);
1955
		}
1956
		$bind_to_ip = "0.0.0.0";
1957
		if(isset($config['snmpd']['bindip'])) {
1958
			if (is_ipaddr($config['snmpd']['bindip'])) {
1959
				$bind_to_ip = $config['snmpd']['bindip'];
1960
			} else {
1961
				$if = get_real_interface($config['snmpd']['bindip']);
1962
				if (does_interface_exist($if))
1963
					$bind_to_ip = find_interface_ip($if);
1964
			}
1965
		}
1966

    
1967
		if(is_port( $config['snmpd']['pollport'] )) {
1968
		    $snmpdconf .= <<<EOD
1969
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1970

    
1971
EOD;
1972

    
1973
		}
1974

    
1975
		$snmpdconf .= <<<EOD
1976
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1977
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1978

    
1979
# These are bsnmp macros not php vars.
1980
sysContact      = $(contact)
1981
sysLocation     = $(location)
1982
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1983

    
1984
snmpEnableAuthenTraps = 2
1985

    
1986
EOD;
1987

    
1988
		if (is_array( $config['snmpd']['modules'] )) {
1989
		    if(isset($config['snmpd']['modules']['mibii'])) {
1990
			$snmpdconf .= <<<EOD
1991
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1992

    
1993
EOD;
1994
		    }
1995

    
1996
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1997
			$snmpdconf .= <<<EOD
1998
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1999
%netgraph
2000
begemotNgControlNodeName = "snmpd"
2001

    
2002
EOD;
2003
		    }
2004

    
2005
		    if(isset($config['snmpd']['modules']['pf'])) {
2006
			$snmpdconf .= <<<EOD
2007
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2008

    
2009
EOD;
2010
		    }
2011

    
2012
		    if(isset($config['snmpd']['modules']['hostres'])) {
2013
			$snmpdconf .= <<<EOD
2014
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2015

    
2016
EOD;
2017
		    }
2018
		    if(isset($config['snmpd']['modules']['bridge'])) {
2019
			$snmpdconf .= <<<EOD
2020
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2021
# config must end with blank line
2022

    
2023
EOD;
2024
		    }
2025
			if(isset($config['snmpd']['modules']['ucd'])) {
2026
				$snmpdconf .= <<<EOD
2027
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2028

    
2029
EOD;
2030
			}
2031
			if(isset($config['snmpd']['modules']['regex'])) {
2032
				$snmpdconf .= <<<EOD
2033
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2034

    
2035
EOD;
2036
			}
2037
		}
2038

    
2039
		fwrite($fd, $snmpdconf);
2040
		fclose($fd);
2041
		unset($snmpdconf);
2042

    
2043
		if (isset($config['snmpd']['bindlan'])) {
2044
			$bindlan = "";
2045
		}
2046

    
2047
		/* run bsnmpd */
2048
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2049
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2050

    
2051
		if ($g['booting'])
2052
			echo gettext("done.") . "\n";
2053
	}
2054

    
2055
	return 0;
2056
}
2057

    
2058
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2059
	global $config, $g;
2060
	if(isset($config['system']['developerspew'])) {
2061
		$mt = microtime();
2062
		echo "services_dnsupdate_process() being called $mt\n";
2063
	}
2064

    
2065
	/* Dynamic DNS updating active? */
2066
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2067
		$notify_text = "";
2068
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2069
			if (!isset($dnsupdate['enable']))
2070
				continue;
2071
			if (!empty($int) && $int != $dnsupdate['interface'])
2072
				continue;
2073
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2074
				continue;
2075

    
2076
			/* determine interface name */
2077
			$if = get_real_interface($dnsupdate['interface']);
2078
			$wanip = get_interface_ip($dnsupdate['interface']);
2079
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2080

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

    
2084
			if ($wanip || $wanipv6) {
2085
				$keyname = $dnsupdate['keyname'];
2086
				/* trailing dot */
2087
				if (substr($keyname, -1) != ".")
2088
					$keyname .= ".";
2089

    
2090
				$hostname = $dnsupdate['host'];
2091
				/* trailing dot */
2092
				if (substr($hostname, -1) != ".")
2093
					$hostname .= ".";
2094

    
2095
				/* write private key file
2096
				   this is dumb - public and private keys are the same for HMAC-MD5,
2097
				   but nsupdate insists on having both */
2098
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2099
				$privkey = <<<EOD
2100
Private-key-format: v1.2
2101
Algorithm: 157 (HMAC)
2102
Key: {$dnsupdate['keydata']}
2103

    
2104
EOD;
2105
				fwrite($fd, $privkey);
2106
				fclose($fd);
2107

    
2108
				/* write public key file */
2109
				if ($dnsupdate['keytype'] == "zone") {
2110
					$flags = 257;
2111
					$proto = 3;
2112
				} else if ($dnsupdate['keytype'] == "host") {
2113
					$flags = 513;
2114
					$proto = 3;
2115
				} else if ($dnsupdate['keytype'] == "user") {
2116
					$flags = 0;
2117
					$proto = 2;
2118
				}
2119

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

    
2124
				/* generate update instructions */
2125
				$upinst = "";
2126
				if (!empty($dnsupdate['server']))
2127
					$upinst .= "server {$dnsupdate['server']}\n";
2128

    
2129
				if (file_exists($cacheFile)) {
2130
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2131
				}
2132
				if (file_exists("{$cacheFile}.ipv6")) {
2133
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2134
				}
2135

    
2136
				// 25 Days
2137
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2138
				$need_update = false;
2139

    
2140
				conf_mount_rw();
2141
				/* Update IPv4 if we have it. */
2142
				if (is_ipaddrv4($wanip)) {
2143
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2144
						if (isset($dnsupdate['usepublicip'])) {
2145
							$wanip = dyndnsCheckIP($dnsupdate['interface']);
2146
						}
2147
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2148
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2149
						$notify_text .= sprintf(gettext("DynDNS updated IP Address (A) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanip) . "\n";
2150
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2151
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2152
						$need_update = true;
2153
					} else {
2154
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2155
					}
2156
				} else
2157
					@unlink($cacheFile);
2158

    
2159
				/* Update IPv6 if we have it. */
2160
				if (is_ipaddrv6($wanipv6)) {
2161
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2162
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2163
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2164
						$notify_text .= sprintf(gettext("DynDNS updated IPv6 Address (AAAA) for {$dnsupdate['host']} on %s (%s) to %s"), convert_real_interface_to_friendly_descr($if), $if, $wanipv6) . "\n";
2165
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2166
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2167
						$need_update = true;
2168
					} else {
2169
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2170
					}
2171
				} else
2172
					@unlink("{$cacheFile}.ipv6");
2173
				conf_mount_ro();
2174

    
2175
				$upinst .= "\n";	/* mind that trailing newline! */
2176

    
2177
				if ($need_update) {
2178
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2179
					unset($upinst);
2180
					/* invoke nsupdate */
2181
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2182
					if (isset($dnsupdate['usetcp']))
2183
						$cmd .= " -v";
2184
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2185
					mwexec_bg($cmd);
2186
					unset($cmd);
2187
				}
2188
			}
2189
		}
2190
		if (!empty($notify_text)) {
2191
			notify_all_remote($notify_text);
2192
		}
2193
	}
2194

    
2195
	return 0;
2196
}
2197

    
2198
/* configure cron service */
2199
function configure_cron() {
2200
	global $g, $config;
2201

    
2202
	conf_mount_rw();
2203
	/* preserve existing crontab entries */
2204
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2205

    
2206
	for ($i = 0; $i < count($crontab_contents); $i++) {
2207
		$cron_item =& $crontab_contents[$i];
2208
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2209
			array_splice($crontab_contents, $i - 1);
2210
			break;
2211
		}
2212
	}
2213
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2214

    
2215

    
2216
	if (is_array($config['cron']['item'])) {
2217
		$crontab_contents .= "#\n";
2218
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2219
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2220
		$crontab_contents .= "#\n";
2221

    
2222
		foreach ($config['cron']['item'] as $item) {
2223
			$crontab_contents .= "\n{$item['minute']}\t";
2224
			$crontab_contents .= "{$item['hour']}\t";
2225
			$crontab_contents .= "{$item['mday']}\t";
2226
			$crontab_contents .= "{$item['month']}\t";
2227
			$crontab_contents .= "{$item['wday']}\t";
2228
			$crontab_contents .= "{$item['who']}\t";
2229
			$crontab_contents .= "{$item['command']}";
2230
		}
2231

    
2232
		$crontab_contents .= "\n#\n";
2233
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2234
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2235
		$crontab_contents .= "#\n\n";
2236
	}
2237

    
2238
	/* please maintain the newline at the end of file */
2239
	file_put_contents("/etc/crontab", $crontab_contents);
2240
	unset($crontab_contents);
2241

    
2242
	/* do a HUP kill to force sync changes */
2243
	exec('/bin/pkill -HUP cron');
2244

    
2245
	conf_mount_ro();
2246
}
2247

    
2248
function upnp_action ($action) {
2249
	global $g, $config;
2250
	switch($action) {
2251
		case "start":
2252
			if (file_exists('/var/etc/miniupnpd.conf')) {
2253
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2254
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2255
			}
2256
			break;
2257
		case "stop":
2258
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2259
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2260
				mwexec('killall miniupnpd 2>/dev/null', true);
2261
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2262
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2263
			break;
2264
		case "restart":
2265
			upnp_action('stop');
2266
			upnp_action('start');
2267
			break;
2268
	}
2269
}
2270

    
2271
function upnp_start() {
2272
	global $config;
2273

    
2274
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2275
		return;
2276

    
2277
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2278
		echo gettext("Starting UPnP service... ");
2279
		require_once('/usr/local/pkg/miniupnpd.inc');
2280
		sync_package_miniupnpd();
2281
		echo "done.\n";
2282
	}
2283
}
2284

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

    
2288
	$is_installed = false;
2289

    
2290
	if (!is_array($config['cron']))
2291
		$config['cron'] = array();
2292
	if (!is_array($config['cron']['item']))
2293
		$config['cron']['item'] = array();
2294

    
2295
	$x=0;
2296
	foreach($config['cron']['item'] as $item) {
2297
		if(strstr($item['command'], $command)) {
2298
			$is_installed = true;
2299
			break;
2300
		}
2301
		$x++;
2302
	}
2303

    
2304
	if($active) {
2305
		$cron_item = array();
2306
		$cron_item['minute'] = $minute;
2307
		$cron_item['hour'] = $hour;
2308
		$cron_item['mday'] = $monthday;
2309
		$cron_item['month'] = $month;
2310
		$cron_item['wday'] = $weekday;
2311
		$cron_item['who'] = $who;
2312
		$cron_item['command'] = $command;
2313
		if(!$is_installed) {
2314
			$config['cron']['item'][] = $cron_item;
2315
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2316
		} else {
2317
			$config['cron']['item'][$x] = $cron_item;
2318
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2319
		}
2320
	} else {
2321
		if($is_installed == true) {
2322
			unset($config['cron']['item'][$x]);
2323
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2324
		}
2325
	}
2326
	configure_cron();
2327
}
2328

    
2329
?>
(49-49/67)