Project

General

Profile

Download (73.1 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
		$dhcpdconf .= "update-static-leases on;\n";
853

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

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

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

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

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

    
879
	return 0;
880
}
881

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

    
893
	return $dhcpdconf;
894
}
895

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

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

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

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

    
942
	return $dhcpdconf;
943
}
944

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

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

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

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

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

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

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

    
988

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

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

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

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

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

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

    
1046
	$dhcpdv6conf = <<<EOD
1047

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

    
1060
EOD;
1061

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

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

    
1068
	$dhcpdv6ifs = array();
1069

    
1070
	$dhcpv6num = 0;
1071
	$nsupdate = false;
1072

    
1073
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1074

    
1075
		$ddns_zones = array();
1076

    
1077
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1078

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

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

    
1090
		$dnscfgv6 = "";
1091

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

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

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

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

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

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

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

    
1142
EOD;
1143

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

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

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

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

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

    
1186
		// net boot information
1187
		if(isset($dhcpv6ifconf['netboot'])) {
1188
			if ($dhcpv6ifconf['nextserver'] <> "") {
1189
				$dhcpdv6conf .= "	next-server {$dhcpv6ifconf['nextserver']};\n";
1190
			}
1191
			if ($dhcpv6ifconf['filename'] <> "") {
1192
				$dhcpdv6conf .= "	filename \"{$dhcpv6ifconf['filename']}\";\n";
1193
			}
1194
			if ($dhcpv6ifconf['rootpath'] <> "") {
1195
				$dhcpdv6conf .= "	option root-path \"{$dhcpv6ifconf['rootpath']}\";\n";
1196
			}
1197
		}
1198

    
1199
		$dhcpdv6conf .= "}\n";
1200

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

    
1210
EOD;
1211
				if ($sm['ipaddrv6'])
1212
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1213

    
1214
				if ($sm['hostname']) {
1215
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1216
					$dhhostname = str_replace(".", "_", $dhhostname);
1217
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1218
				}
1219
				if ($sm['filename'])
1220
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1221

    
1222
				if ($sm['rootpath'])
1223
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1224

    
1225
				$dhcpdv6conf .= "}\n";
1226
				$i++;
1227
			}
1228
		}
1229

    
1230
		if ($dhcpv6ifconf['domain'])
1231
		{
1232
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1233
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1234
		}
1235

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

    
1254
	if ($nsupdate)
1255
	{
1256
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1257
	}
1258
	else
1259
	{
1260
		$dhcpdv6conf .= "ddns-update-style none;\n";
1261
	}
1262

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

    
1273
	/* create an empty leases v6 database */
1274
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1275
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1276

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

    
1286
	return 0;
1287
}
1288

    
1289
function services_igmpproxy_configure() {
1290
        global $config, $g;
1291

    
1292
        /* kill any running igmpproxy */
1293
        killbyname("igmpproxy");
1294

    
1295
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1296
		return 1;
1297

    
1298
        $iflist = get_configured_interface_list();
1299

    
1300
        $igmpconf = <<<EOD
1301

    
1302
##------------------------------------------------------
1303
## Enable Quickleave mode (Sends Leave instantly)
1304
##------------------------------------------------------
1305
quickleave
1306

    
1307
EOD;
1308

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

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

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

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

    
1344
        return 0;
1345
}
1346

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

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

    
1359
	$dhcrelaycfg =& $config['dhcrelay'];
1360

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

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

    
1370
	$iflist = get_configured_interface_list();
1371

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

    
1378
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1379
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1380
	}
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
	foreach ($srvips as $srcidx => $srvip) {
1388
		unset($destif);
1389
		foreach ($iflist as $ifname) {
1390
			$subnet = get_interface_ip($ifname);
1391
			if (!is_ipaddr($subnet))
1392
				continue;
1393
			$subnet .=  "/" . get_interface_subnet($ifname);
1394
			if (ip_in_subnet($srvip, $subnet)) {
1395
				$destif = get_real_interface($ifname);
1396
				break;
1397
			}
1398
		}
1399
		if (!isset($destif)) {
1400
			foreach (get_staticroutes() as $rtent) {
1401
				if (ip_in_subnet($srvip, $rtent['network'])) {
1402
					$a_gateways = return_gateways_array(true);
1403
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1404
					break;
1405
				}
1406
			}
1407
		}
1408

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

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

    
1446
		if (!empty($destif))
1447
			$dhcrelayifs[] = $destif;
1448
	}
1449
	$dhcrelayifs = array_unique($dhcrelayifs);
1450

    
1451
	/* fire up dhcrelay */
1452
	if (empty($dhcrelayifs)) {
1453
		log_error("No suitable interface found for running dhcrelay!");
1454
		return; /* XXX */
1455
	}
1456

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

    
1459
	if (isset($dhcrelaycfg['agentoption']))
1460
		$cmd .=  " -a -m replace";
1461

    
1462
	$cmd .= " " . implode(" ", $srvips);
1463
	mwexec($cmd);
1464
	unset($cmd);
1465

    
1466
	return 0;
1467
}
1468

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

    
1478
	/* kill any running dhcrelay */
1479
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1480

    
1481
	$dhcrelaycfg =& $config['dhcrelay6'];
1482

    
1483
	/* DHCPv6 Relay enabled on any interfaces? */
1484
	if (!isset($dhcrelaycfg['enable']))
1485
		return 0;
1486

    
1487
	if ($g['booting'])
1488
		echo gettext("Starting DHCPv6 relay service...");
1489
	else
1490
		sleep(1);
1491

    
1492
	$iflist = get_configured_interface_list();
1493

    
1494
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1495
	foreach ($dhcifaces as $dhcrelayif) {
1496
		if (!isset($iflist[$dhcrelayif]) ||
1497
			link_interface_to_bridge($dhcrelayif))
1498
			continue;
1499

    
1500
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1501
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1502
	}
1503
	$dhcrelayifs = array_unique($dhcrelayifs);
1504

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

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

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

    
1564
		if (!empty($destif)) {
1565
			$srvifaces[] = "{$srvip}%{$destif}";
1566
		}
1567
	}
1568

    
1569
	/* fire up dhcrelay */
1570
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1571
		log_error("No suitable interface found for running dhcrelay -6!");
1572
		return; /* XXX */
1573
	}
1574

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

    
1585
	return 0;
1586
}
1587

    
1588
function services_dyndns_configure_client($conf) {
1589

    
1590
	if (!isset($conf['enable']))
1591
		return;
1592

    
1593
	/* load up the dyndns.class */
1594
	require_once("dyndns.class");
1595

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

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

    
1625
	$dyndnscfg = $config['dyndnses']['dyndns'];
1626
	$gwgroups = return_gateway_groups_array();
1627
	if (is_array($dyndnscfg)) {
1628
		if ($g['booting'])
1629
			echo gettext("Starting DynDNS clients...");
1630

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

    
1641
		if ($g['booting'])
1642
			echo gettext("done.") . "\n";
1643
	}
1644

    
1645
	return 0;
1646
}
1647

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

    
1672
function services_dnsmasq_configure() {
1673
	global $config, $g;
1674
	$return = 0;
1675

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

    
1683

    
1684
	if(isset($config['system']['developerspew'])) {
1685
		$mt = microtime();
1686
		echo "services_dnsmasq_configure() being called $mt\n";
1687
	}
1688

    
1689
	/* kill any running dnsmasq */
1690
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1691
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1692

    
1693
	if (isset($config['dnsmasq']['enable'])) {
1694

    
1695
		if ($g['booting'])
1696
			echo gettext("Starting DNS forwarder...");
1697
		else
1698
			sleep(1);
1699

    
1700
		/* generate hosts file */
1701
		if(system_hosts_generate()!=0)
1702
			$return = 1;
1703

    
1704
		$args = "";
1705

    
1706
		if (isset($config['dnsmasq']['regdhcp'])) {
1707
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1708
		}
1709

    
1710
		/* Setup listen port, if non-default */
1711
		if (is_port($config['dnsmasq']['port']))
1712
			$args .= " --port={$config['dnsmasq']['port']} ";
1713

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

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

    
1773
		/* Setup forwarded domains */
1774
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1775
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1776
				if ($override['ip'] == "!")
1777
					$override[ip] = "";
1778
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1779
			}
1780
		}
1781

    
1782
		/* Allow DNS Rebind for forwarded domains */
1783
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1784
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1785
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1786
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1787
				}
1788
			}
1789
		}
1790

    
1791
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1792
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1793

    
1794
		if (isset($config['dnsmasq']['strict_order'])) {
1795
			$args .= " --strict-order ";
1796
		}
1797

    
1798
		if (isset($config['dnsmasq']['domain_needed'])) {
1799
			$args .= " --domain-needed ";
1800
		}
1801

    
1802
		if ($config['dnsmasq']['custom_options'])
1803
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1804
				$args .= " --$c";
1805
				$p = explode('=', $c);
1806
				if (array_key_exists($p[0], $standard_args))
1807
					unset($standard_args[$p[0]]);
1808
			}
1809
		$args .= ' ' . implode(' ', array_values($standard_args));
1810

    
1811
		/* run dnsmasq */
1812
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1813
		//log_error("dnsmasq command: {$cmd}");
1814
		mwexec_bg($cmd);
1815
		unset($args);
1816

    
1817
		if ($g['booting'])
1818
			echo gettext("done.") . "\n";
1819
	}
1820

    
1821
	if (!$g['booting']) {
1822
		if(services_dhcpd_configure()!=0)
1823
			$return = 1;
1824
	}
1825

    
1826
	return $return;
1827
}
1828

    
1829
function services_snmpd_configure() {
1830
	global $config, $g;
1831
	if(isset($config['system']['developerspew'])) {
1832
		$mt = microtime();
1833
		echo "services_snmpd_configure() being called $mt\n";
1834
	}
1835

    
1836
	/* kill any running snmpd */
1837
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1838
	sleep(2);
1839
	if(is_process_running("bsnmpd"))
1840
		mwexec("/usr/bin/killall bsnmpd", true);
1841

    
1842
	if (isset($config['snmpd']['enable'])) {
1843

    
1844
		if ($g['booting'])
1845
			echo gettext("Starting SNMP daemon... ");
1846

    
1847
		/* generate snmpd.conf */
1848
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1849
		if (!$fd) {
1850
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1851
			return 1;
1852
		}
1853

    
1854

    
1855
		$snmpdconf = <<<EOD
1856
location := "{$config['snmpd']['syslocation']}"
1857
contact := "{$config['snmpd']['syscontact']}"
1858
read := "{$config['snmpd']['rocommunity']}"
1859

    
1860
EOD;
1861

    
1862
/* No docs on what write strings do there for disable for now.
1863
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1864
		    $snmpdconf .= <<<EOD
1865
# write string
1866
write := "{$config['snmpd']['rwcommunity']}"
1867

    
1868
EOD;
1869
		}
1870
*/
1871

    
1872

    
1873
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1874
		    $snmpdconf .= <<<EOD
1875
# SNMP Trap support.
1876
traphost := {$config['snmpd']['trapserver']}
1877
trapport := {$config['snmpd']['trapserverport']}
1878
trap := "{$config['snmpd']['trapstring']}"
1879

    
1880

    
1881
EOD;
1882
		}
1883

    
1884
		$version = trim(file_get_contents('/etc/version'));
1885
		$platform = trim(file_get_contents('/etc/platform'));
1886
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1887
			$platform = $g['product_name'];
1888
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1889
			" {$version} {$platform} " . php_uname("s") .
1890
			" " . php_uname("r") . " " . php_uname("m");
1891

    
1892
		$snmpdconf .= <<<EOD
1893
system := 1     # pfSense
1894
%snmpd
1895
sysDescr			= "{$sysDescr}"
1896
begemotSnmpdDebugDumpPdus       = 2
1897
begemotSnmpdDebugSyslogPri      = 7
1898
begemotSnmpdCommunityString.0.1 = $(read)
1899

    
1900
EOD;
1901

    
1902
/* No docs on what write strings do there for disable for now.
1903
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1904
		    $snmpdconf .= <<<EOD
1905
begemotSnmpdCommunityString.0.2 = $(write)
1906

    
1907
EOD;
1908
		}
1909
*/
1910

    
1911

    
1912
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1913
		    $snmpdconf .= <<<EOD
1914
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1915
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1916
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1917

    
1918
EOD;
1919
		}
1920

    
1921

    
1922
		$snmpdconf .= <<<EOD
1923
begemotSnmpdCommunityDisable    = 1
1924

    
1925
EOD;
1926

    
1927
		if (isset($config['snmpd']['bindlan'])) {
1928
			$config['snmpd']['bindip'] = 'lan';
1929
			unset($config['snmpd']['bindlan']);
1930
		}
1931
		$bind_to_ip = "0.0.0.0";
1932
		if(isset($config['snmpd']['bindip'])) {
1933
			if (is_ipaddr($config['snmpd']['bindip'])) {
1934
				$bind_to_ip = $config['snmpd']['bindip'];
1935
			} else {
1936
				$if = get_real_interface($config['snmpd']['bindip']);
1937
				if (does_interface_exist($if))
1938
					$bind_to_ip = find_interface_ip($if);
1939
			}
1940
		}
1941

    
1942
		if(is_port( $config['snmpd']['pollport'] )) {
1943
		    $snmpdconf .= <<<EOD
1944
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
1945

    
1946
EOD;
1947

    
1948
		}
1949

    
1950
		$snmpdconf .= <<<EOD
1951
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
1952
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
1953

    
1954
# These are bsnmp macros not php vars.
1955
sysContact      = $(contact)
1956
sysLocation     = $(location)
1957
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
1958

    
1959
snmpEnableAuthenTraps = 2
1960

    
1961
EOD;
1962

    
1963
		if (is_array( $config['snmpd']['modules'] )) {
1964
		    if(isset($config['snmpd']['modules']['mibii'])) {
1965
			$snmpdconf .= <<<EOD
1966
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
1967

    
1968
EOD;
1969
		    }
1970

    
1971
		    if(isset($config['snmpd']['modules']['netgraph'])) {
1972
			$snmpdconf .= <<<EOD
1973
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
1974
%netgraph
1975
begemotNgControlNodeName = "snmpd"
1976

    
1977
EOD;
1978
		    }
1979

    
1980
		    if(isset($config['snmpd']['modules']['pf'])) {
1981
			$snmpdconf .= <<<EOD
1982
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
1983

    
1984
EOD;
1985
		    }
1986

    
1987
		    if(isset($config['snmpd']['modules']['hostres'])) {
1988
			$snmpdconf .= <<<EOD
1989
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
1990

    
1991
EOD;
1992
		    }
1993
		    if(isset($config['snmpd']['modules']['bridge'])) {
1994
			$snmpdconf .= <<<EOD
1995
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
1996
# config must end with blank line
1997

    
1998
EOD;
1999
		    }
2000
			if(isset($config['snmpd']['modules']['ucd'])) {
2001
				$snmpdconf .= <<<EOD
2002
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2003

    
2004
EOD;
2005
			}
2006
			if(isset($config['snmpd']['modules']['regex'])) {
2007
				$snmpdconf .= <<<EOD
2008
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2009

    
2010
EOD;
2011
			}
2012
		}
2013

    
2014
		fwrite($fd, $snmpdconf);
2015
		fclose($fd);
2016
		unset($snmpdconf);
2017

    
2018
		if (isset($config['snmpd']['bindlan'])) {
2019
			$bindlan = "";
2020
		}
2021

    
2022
		/* run bsnmpd */
2023
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2024
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2025

    
2026
		if ($g['booting'])
2027
			echo gettext("done.") . "\n";
2028
	}
2029

    
2030
	return 0;
2031
}
2032

    
2033
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2034
	global $config, $g;
2035
	if(isset($config['system']['developerspew'])) {
2036
		$mt = microtime();
2037
		echo "services_dnsupdate_process() being called $mt\n";
2038
	}
2039

    
2040
	/* Dynamic DNS updating active? */
2041
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2042
		$notify_text = "";
2043
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2044
			if (!isset($dnsupdate['enable']))
2045
				continue;
2046
			if (!empty($int) && $int != $dnsupdate['interface'])
2047
				continue;
2048
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2049
				continue;
2050

    
2051
			/* determine interface name */
2052
			$if = get_real_interface($dnsupdate['interface']);
2053
			$wanip = get_interface_ip($dnsupdate['interface']);
2054
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2055

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

    
2059
			if ($wanip || $wanipv6) {
2060
				$keyname = $dnsupdate['keyname'];
2061
				/* trailing dot */
2062
				if (substr($keyname, -1) != ".")
2063
					$keyname .= ".";
2064

    
2065
				$hostname = $dnsupdate['host'];
2066
				/* trailing dot */
2067
				if (substr($hostname, -1) != ".")
2068
					$hostname .= ".";
2069

    
2070
				/* write private key file
2071
				   this is dumb - public and private keys are the same for HMAC-MD5,
2072
				   but nsupdate insists on having both */
2073
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2074
				$privkey = <<<EOD
2075
Private-key-format: v1.2
2076
Algorithm: 157 (HMAC)
2077
Key: {$dnsupdate['keydata']}
2078

    
2079
EOD;
2080
				fwrite($fd, $privkey);
2081
				fclose($fd);
2082

    
2083
				/* write public key file */
2084
				if ($dnsupdate['keytype'] == "zone") {
2085
					$flags = 257;
2086
					$proto = 3;
2087
				} else if ($dnsupdate['keytype'] == "host") {
2088
					$flags = 513;
2089
					$proto = 3;
2090
				} else if ($dnsupdate['keytype'] == "user") {
2091
					$flags = 0;
2092
					$proto = 2;
2093
				}
2094

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

    
2099
				/* generate update instructions */
2100
				$upinst = "";
2101
				if (!empty($dnsupdate['server']))
2102
					$upinst .= "server {$dnsupdate['server']}\n";
2103

    
2104
				if (file_exists($cacheFile)) {
2105
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2106
				}
2107
				if (file_exists("{$cacheFile}.ipv6")) {
2108
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2109
				}
2110

    
2111
				// 25 Days
2112
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2113
				$need_update = false;
2114

    
2115
				conf_mount_rw();
2116
				/* Update IPv4 if we have it. */
2117
				if (is_ipaddrv4($wanip)) {
2118
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2119
						if (isset($dnsupdate['usepublicip'])) {
2120
							$wanip = dyndnsCheckIP($dnsupdate['interface']);
2121
						}
2122
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2123
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2124
						$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";
2125
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2126
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2127
						$need_update = true;
2128
					} else {
2129
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2130
					}
2131
				} else
2132
					@unlink($cacheFile);
2133

    
2134
				/* Update IPv6 if we have it. */
2135
				if (is_ipaddrv6($wanipv6)) {
2136
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2137
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2138
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2139
						$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";
2140
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2141
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2142
						$need_update = true;
2143
					} else {
2144
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2145
					}
2146
				} else
2147
					@unlink("{$cacheFile}.ipv6");
2148
				conf_mount_ro();
2149

    
2150
				$upinst .= "\n";	/* mind that trailing newline! */
2151

    
2152
				if ($need_update) {
2153
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2154
					unset($upinst);
2155
					/* invoke nsupdate */
2156
					$cmd = "/usr/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2157
					if (isset($dnsupdate['usetcp']))
2158
						$cmd .= " -v";
2159
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2160
					mwexec_bg($cmd);
2161
					unset($cmd);
2162
				}
2163
			}
2164
		}
2165
		if (!empty($notify_text)) {
2166
			notify_all_remote($notify_text);
2167
		}
2168
	}
2169

    
2170
	return 0;
2171
}
2172

    
2173
/* configure cron service */
2174
function configure_cron() {
2175
	global $g, $config;
2176

    
2177
	conf_mount_rw();
2178
	/* preserve existing crontab entries */
2179
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2180

    
2181
	for ($i = 0; $i < count($crontab_contents); $i++) {
2182
		$cron_item =& $crontab_contents[$i];
2183
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2184
			array_splice($crontab_contents, $i - 1);
2185
			break;
2186
		}
2187
	}
2188
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2189

    
2190

    
2191
	if (is_array($config['cron']['item'])) {
2192
		$crontab_contents .= "#\n";
2193
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2194
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2195
		$crontab_contents .= "#\n";
2196

    
2197
		foreach ($config['cron']['item'] as $item) {
2198
			$crontab_contents .= "\n{$item['minute']}\t";
2199
			$crontab_contents .= "{$item['hour']}\t";
2200
			$crontab_contents .= "{$item['mday']}\t";
2201
			$crontab_contents .= "{$item['month']}\t";
2202
			$crontab_contents .= "{$item['wday']}\t";
2203
			$crontab_contents .= "{$item['who']}\t";
2204
			$crontab_contents .= "{$item['command']}";
2205
		}
2206

    
2207
		$crontab_contents .= "\n#\n";
2208
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2209
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2210
		$crontab_contents .= "#\n\n";
2211
	}
2212

    
2213
	/* please maintain the newline at the end of file */
2214
	file_put_contents("/etc/crontab", $crontab_contents);
2215
	unset($crontab_contents);
2216

    
2217
	/* do a HUP kill to force sync changes */
2218
	exec('/bin/pkill -HUP cron');
2219

    
2220
	conf_mount_ro();
2221
}
2222

    
2223
function upnp_action ($action) {
2224
	global $g, $config;
2225
	switch($action) {
2226
		case "start":
2227
			if (file_exists('/var/etc/miniupnpd.conf')) {
2228
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2229
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2230
			}
2231
			break;
2232
		case "stop":
2233
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2234
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2235
				mwexec('killall miniupnpd 2>/dev/null', true);
2236
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2237
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2238
			break;
2239
		case "restart":
2240
			upnp_action('stop');
2241
			upnp_action('start');
2242
			break;
2243
	}
2244
}
2245

    
2246
function upnp_start() {
2247
	global $config;
2248

    
2249
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2250
		return;
2251

    
2252
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2253
		echo gettext("Starting UPnP service... ");
2254
		require_once('/usr/local/pkg/miniupnpd.inc');
2255
		sync_package_miniupnpd();
2256
		echo "done.\n";
2257
	}
2258
}
2259

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

    
2263
	$is_installed = false;
2264

    
2265
	if (!is_array($config['cron']))
2266
		$config['cron'] = array();
2267
	if (!is_array($config['cron']['item']))
2268
		$config['cron']['item'] = array();
2269

    
2270
	$x=0;
2271
	foreach($config['cron']['item'] as $item) {
2272
		if(strstr($item['command'], $command)) {
2273
			$is_installed = true;
2274
			break;
2275
		}
2276
		$x++;
2277
	}
2278

    
2279
	if($active) {
2280
		$cron_item = array();
2281
		$cron_item['minute'] = $minute;
2282
		$cron_item['hour'] = $hour;
2283
		$cron_item['mday'] = $monthday;
2284
		$cron_item['month'] = $month;
2285
		$cron_item['wday'] = $weekday;
2286
		$cron_item['who'] = $who;
2287
		$cron_item['command'] = $command;
2288
		if(!$is_installed) {
2289
			$config['cron']['item'][] = $cron_item;
2290
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2291
		} else {
2292
			$config['cron']['item'][$x] = $cron_item;
2293
			write_config(sprintf(gettext("Updated cron job for %s"), $command));
2294
		}
2295
	} else {
2296
		if($is_installed == true) {
2297
			unset($config['cron']['item'][$x]);
2298
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2299
		}
2300
	}
2301
	configure_cron();
2302
}
2303

    
2304
?>
(49-49/66)