Project

General

Profile

Download (79.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	services.inc
4
	part of the pfSense project (https://www.pfsense.org)
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', 'citynetwork cloudflare custom custom-v6 dnsexit dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost zoneedit');
42
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'City Network,CloudFlare,Custom,Custom (v6),DNSexit,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,ZoneEdit');
43

    
44
/* implement ipv6 route advertising daemon */
45
function services_radvd_configure($blacklist = array()) {
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
		/* Do not put in the config an interface which is down */
76
		if (isset($blacklist[$dhcpv6if]))
77
			continue;
78
		if (!isset($dhcpv6ifconf['ramode']))
79
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
80

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

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

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

    
98
		if (strstr($dhcpv6if, "_vip")) {
99
			// CARP IP, check if it's enabled and find parent
100
			if (!get_carp_status() || get_carp_interface_status($dhcpv6if) != "MASTER")
101
				continue;
102
			$ifparent = link_carp_interface_to_parent($dhcpv6if);
103
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
104
		} else {
105
			$realif = get_real_interface($dhcpv6if, "inet6");
106
		}
107
		
108
		if (isset($radvdifs[$realif]))
109
			continue;
110

    
111
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
112
		if (!is_ipaddrv6($ifcfgipv6))
113
			continue;
114

    
115
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
116
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
117
		$radvdifs[$realif] = $realif;
118

    
119
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
120
		$radvdconf .= "interface {$realif} {\n";
121
		if (strstr($realif, "ovpn")) {
122
			$radvdconf .= "\tUnicastOnly on;\n";
123
		}
124
		$radvdconf .= "\tAdvSendAdvert on;\n";
125
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
126
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
127
		$mtu = get_interface_mtu($realif);
128
		if (is_numeric($mtu))
129
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
130
		else
131
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
132

    
133
		switch($dhcpv6ifconf['rapriority']) {
134
			case "low":
135
				$radvdconf .= "\tAdvDefaultPreference low;\n";
136
				break;
137
			case "high":
138
				$radvdconf .= "\tAdvDefaultPreference high;\n";
139
				break;
140
			default:
141
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
142
				break;
143
		}
144
		switch($dhcpv6ifconf['ramode']) {
145
			case "managed":
146
			case "assist":
147
				$radvdconf .= "\tAdvManagedFlag on;\n";
148
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
149
				break;
150
			case "stateless_dhcp":
151
				$radvdconf .= "\tAdvManagedFlag off;\n";
152
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
153
				break;
154
		}
155
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
156
		if($carpif == true) {
157
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
158
		} else {
159
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
160
		}
161
		switch($dhcpv6ifconf['ramode']) {
162
			case "managed":
163
				$radvdconf .= "\t\tAdvOnLink on;\n";
164
				$radvdconf .= "\t\tAdvAutonomous off;\n";
165
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
166
				break;
167
			case "router":
168
				$radvdconf .= "\t\tAdvOnLink off;\n";
169
				$radvdconf .= "\t\tAdvAutonomous off;\n";
170
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
171
				break;
172
			case "stateless_dhcp":
173
			case "assist":
174
				$radvdconf .= "\t\tAdvOnLink on;\n";
175
				$radvdconf .= "\t\tAdvAutonomous on;\n";
176
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
177
				break;
178
			case "unmanaged":
179
				$radvdconf .= "\t\tAdvOnLink on;\n";
180
				$radvdconf .= "\t\tAdvAutonomous on;\n";
181
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
182
				break;				
183
		}
184
		$radvdconf .= "\t};\n";
185

    
186
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
187
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
188
				if (is_subnetv6($subnet)) {
189
					$radvdconf .= "\tprefix {$subnet} {\n";
190
					if($carpif == true) {
191
						$radvdconf .= "\t\tDeprecatePrefix off;\n";
192
					} else {
193
						$radvdconf .= "\t\tDeprecatePrefix on;\n";
194
					}
195
					switch($dhcpv6ifconf['ramode']) {
196
						case "managed":
197
							$radvdconf .= "\t\tAdvOnLink on;\n";
198
							$radvdconf .= "\t\tAdvAutonomous off;\n";
199
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
200
							break;
201
						case "router":
202
							$radvdconf .= "\t\tAdvOnLink off;\n";
203
							$radvdconf .= "\t\tAdvAutonomous off;\n";
204
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
205
							break;
206
						case "assist":
207
							$radvdconf .= "\t\tAdvOnLink on;\n";
208
							$radvdconf .= "\t\tAdvAutonomous on;\n";
209
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
210
							break;
211
						case "unmanaged":
212
							$radvdconf .= "\t\tAdvOnLink on;\n";
213
							$radvdconf .= "\t\tAdvAutonomous on;\n";
214
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
215
							break;				
216
					}
217
					$radvdconf .= "\t};\n";
218
				}
219
			}
220
		}
221
		if($carpif === true) {
222
			$radvdconf .= "\troute ::/0 {\n";
223
			$radvdconf .= "\t\tRemoveRoute off;\n";
224
			$radvdconf .= "\t};\n";
225
		} else {
226
			$radvdconf .= "\troute ::/0 {\n";
227
			$radvdconf .= "\t\tRemoveRoute on;\n";
228
			$radvdconf .= "\t};\n";
229
		}
230

    
231
		/* add DNS servers */
232
		$dnslist = array();
233
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
234
			foreach($dhcpv6ifconf['dnsserver'] as $server)
235
				if (is_ipaddrv6($server))
236
					$dnslist[] = $server;
237
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
238
			foreach($dhcpv6ifconf['radnsserver'] as $server)
239
				if (is_ipaddrv6($server))
240
					$dnslist[] = $server;
241
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
242
			$dnslist[] = get_interface_ipv6($realif);
243
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
244
			foreach($config['system']['dnsserver'] as $server) {
245
				if (is_ipaddrv6($server))
246
					$dnslist[] = $server;
247
			}
248
		}
249
		if (count($dnslist) > 0) {
250
			$dnsstring = implode(" ", $dnslist);
251
			if ($dnsstring <> "")
252
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
253
		}
254
		if (!empty($dhcpv6ifconf['domain'])) {
255
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
256
		} elseif (!empty($config['system']['domain'])) {
257
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
258
		}
259
		$radvdconf .= "};\n";
260
	}
261

    
262
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
263
	foreach ($Iflist as $if => $ifdescr) {
264
		if(!isset($config['interfaces'][$if]['track6-interface']))
265
			continue;
266
		if(!isset($config['interfaces'][$if]['enable']))
267
			continue;
268
		/* Do not put in the config an interface which is down */
269
		if (isset($blacklist[$if]))
270
			continue;
271
		$trackif = $config['interfaces'][$if]['track6-interface'];
272
		if (empty($config['interfaces'][$trackif]))
273
			continue;
274

    
275
		if (strstr($if, "_vip")) {
276
			// CARP IP, find parent
277
			$ifparent = link_carp_interface_to_parent($if);
278
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
279
		} else {
280
			$realif = get_real_interface($if, "inet6");
281
		}
282
		
283
		/* prevent duplicate entries, manual overrides */
284
		if (isset($radvdifs[$realif]))
285
			continue;
286

    
287
		$ifcfgipv6 = get_interface_ipv6($if);
288
		if(!is_ipaddrv6($ifcfgipv6)) {
289
			$subnetv6 = "::";
290
			$ifcfgsnv6 = "64";
291
		} else {
292
			$ifcfgsnv6 = get_interface_subnetv6($if);
293
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
294
		}
295
		$radvdifs[$realif] = $realif;
296

    
297
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
298
	
299
		if ($g['debug'])
300
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
301

    
302
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
303
		$radvdconf .= "interface {$realif} {\n";
304
		$radvdconf .= "\tAdvSendAdvert on;\n";
305
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
306
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
307
		$mtu = get_interface_mtu($realif);
308
		if (is_numeric($mtu))
309
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
310
		else
311
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
312
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
313
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
314
		$radvdconf .= "\t\tAdvOnLink on;\n";
315
		$radvdconf .= "\t\tAdvAutonomous on;\n";
316
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
317
		$radvdconf .= "\t};\n";
318

    
319
		/* add DNS servers */
320
		$dnslist = array();
321
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
322
			$dnslist[] = $ifcfgipv6;
323
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
324
			foreach($config['system']['dnsserver'] as $server) {
325
				if(is_ipaddrv6($server))
326
					$dnslist[] = $server;
327
			}
328
		}
329
		if (count($dnslist) > 0) {
330
			$dnsstring = implode(" ", $dnslist);
331
			if (!empty($dnsstring))
332
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
333
		}
334
		if (!empty($config['system']['domain'])) {
335
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
336
		}
337
		$radvdconf .= "};\n";
338
	}
339

    
340
	/* write radvd.conf */
341
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
342
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
343
		if (platform_booting())
344
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
345
	}
346
	unset($radvdconf);
347

    
348
	if (count($radvdifs) > 0) {
349
		if (isvalidpid("{$g['varrun_path']}/radvd.pid"))
350
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
351
		else
352
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
353
	} else {
354
		/* we need to shut down the radvd cleanly, it will send out the prefix
355
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
356
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
357
			log_error("Shutting down Router Advertisment daemon cleanly");
358
			killbypid("{$g['varrun_path']}/radvd.pid");
359
			@unlink("{$g['varrun_path']}/radvd.pid");
360
		}
361
	}
362
	return 0;
363
}
364

    
365
function services_dhcpd_configure($family = "all", $blacklist = array()) {
366
	global $config, $g;
367

    
368
	/* configure DHCPD chroot once */
369
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
370
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
371
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
372
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
373
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
374
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
375
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
376
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
377
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
378
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
379
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
380
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
381
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
382
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
383

    
384
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
385
	if (!trim($status))
386
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
387
	fclose($fd);
388
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
389

    
390
	if ($family == "all" || $family == "inet")
391
		services_dhcpdv4_configure();
392
	if ($family == "all" || $family == "inet6") {
393
		services_dhcpdv6_configure($blacklist);
394
		services_radvd_configure($blacklist);
395
	}
396
}
397

    
398
function services_dhcpdv4_configure() {
399
	global $config, $g;
400
	$need_ddns_updates = false;
401
	$ddns_zones = array();
402

    
403
	if($g['services_dhcp_server_enable'] == false)
404
		return;
405

    
406
	if(isset($config['system']['developerspew'])) {
407
		$mt = microtime();
408
		echo "services_dhcpdv4_configure($if) being called $mt\n";
409
	}
410

    
411
	/* kill any running dhcpd */
412
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid"))
413
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
414

    
415
	/* DHCP enabled on any interfaces? */
416
	if (!is_dhcp_server_enabled())
417
		return 0;
418

    
419
	/* if OLSRD is enabled, allow WAN to house DHCP. */
420
	if (!function_exists('is_package_installed'))
421
		require_once('pkg-utils.inc');
422
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd']))
423
		foreach($config['installedpackages']['olsrd']['config'] as $olsrd)
424
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
425
				$is_olsr_enabled = true;
426
				break;
427
			}
428

    
429
	if (platform_booting()) {
430
		/* restore the leases, if we have them */
431
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
432
			$dhcprestore = "";
433
			$dhcpreturn = "";
434
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
435
			$dhcprestore = implode(" ", $dhcprestore);
436
			if($dhcpreturn <> 0) {
437
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
438
			}
439
		}
440
		/* 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. */
441
		if (($g['platform'] == "pfSense") && !isset($config['system']['use_mfs_tmpvar'])) {
442
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
443
		}
444
	}
445

    
446
	$syscfg = $config['system'];
447
	if (!is_array($config['dhcpd']))
448
		$config['dhcpd'] = array();
449
	$dhcpdcfg = $config['dhcpd'];
450
	$Iflist = get_configured_interface_list();
451

    
452
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
453
	$dns_arrv4 = array();
454
	if (is_array($syscfg['dnsserver'])) {
455
		foreach($syscfg['dnsserver'] as $dnsserver) {
456
			if (is_ipaddrv4($dnsserver)) {
457
				$dns_arrv4[] = $dnsserver;
458
			}
459
		}
460
	}
461

    
462
	if (platform_booting())
463
		echo gettext("Starting DHCP service...");
464
	else
465
		sleep(1);
466

    
467
	$custoptions = "";
468
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
469
		if(is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
470
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
471
				if(!empty($item['type']))
472
					$itemtype = $item['type'];
473
				else
474
					$itemtype = "text";
475
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
476
			}
477
		}
478
	}
479

    
480
	$dhcpdconf = <<<EOD
481

    
482
option domain-name "{$syscfg['domain']}";
483
option ldap-server code 95 = text;
484
option domain-search-list code 119 = text;
485
option arch code 93 = unsigned integer 16; # RFC4578
486
{$custoptions}
487
default-lease-time 7200;
488
max-lease-time 86400;
489
log-facility local7;
490
one-lease-per-client true;
491
deny duplicates;
492
ping-check true;
493
update-conflict-detection false;
494

    
495
EOD;
496

    
497
	if(!isset($dhcpifconf['disableauthoritative']))
498
		$dhcpdconf .= "authoritative;\n";
499

    
500
	if(isset($dhcpifconf['alwaysbroadcast']))
501
		$dhcpdconf .= "always-broadcast on\n";
502

    
503
	$dhcpdifs = array();
504
	$enable_add_routers = false;
505
	$gateways_arr = return_gateways_array();
506
	/* only add a routers line if the system has any IPv4 gateway at all */
507
	/* a static route has a gateway, manually overriding this field always works */
508
	foreach($gateways_arr as $gwitem) {
509
		if($gwitem['ipprotocol'] == "inet") {
510
			$enable_add_routers = true;
511
			break;
512
		}
513
	}
514

    
515
	/*    loop through and determine if we need to setup
516
	 *    failover peer "bleh" entries
517
	 */
518
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
519

    
520
		if (!isset($config['interfaces'][$dhcpif]['enable']))
521
			continue;
522

    
523
		interfaces_staticarp_configure($dhcpif);
524

    
525
		if (!isset($dhcpifconf['enable']))
526
			continue;
527

    
528
		if($dhcpifconf['failover_peerip'] <> "") {
529
			$intip = get_interface_ip($dhcpif);
530
			/*
531
			 *    yep, failover peer is defined.
532
			 *    does it match up to a defined vip?
533
			 */
534
			$skew = 110;
535
			if(is_array($config['virtualip']['vip'])) {
536
				foreach ($config['virtualip']['vip'] as $vipent) {
537
					if($vipent['interface'] == $dhcpif) {
538
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
539
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
540
							/* this is the interface! */
541
							if(is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
542
								$skew = 0;
543
								break;
544
							}
545
						}
546
					}
547
				}
548
			} else {
549
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
550
			}
551
			if($skew > 10) {
552
				$type = "secondary";
553
				$my_port = "520";
554
				$peer_port = "519";
555
			} else {
556
				$my_port = "519";
557
				$peer_port = "520";
558
				$type = "primary";
559
				$dhcpdconf_pri  = "split 128;\n";
560
				$dhcpdconf_pri .= "  mclt 600;\n";
561
			}
562

    
563
			if (is_ipaddrv4($intip)) {
564
			$dhcpdconf .= <<<EOPP
565
failover peer "dhcp_{$dhcpif}" {
566
  {$type};
567
  address {$intip};
568
  port {$my_port};
569
  peer address {$dhcpifconf['failover_peerip']};
570
  peer port {$peer_port};
571
  max-response-delay 10;
572
  max-unacked-updates 10;
573
  {$dhcpdconf_pri}
574
  load balance max seconds 3;
575
}
576
\n
577
EOPP;
578
			}
579
		}
580
	}
581

    
582
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
583

    
584
		$newzone = array();
585
		$ifcfg = $config['interfaces'][$dhcpif];
586

    
587
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif]))
588
			continue;
589
		$ifcfgip = get_interface_ip($dhcpif);
590
		$ifcfgsn = get_interface_subnet($dhcpif);
591
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
592
		$subnetmask = gen_subnet_mask($ifcfgsn);
593

    
594
		if (!is_ipaddr($subnet))
595
			continue;
596

    
597
		if($is_olsr_enabled == true)
598
			if($dhcpifconf['netmask'])
599
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
600

    
601
		$all_pools = array();
602
		$all_pools[] = $dhcpifconf;
603
		if (is_array($dhcpifconf['pool'])) {
604
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
605
		}
606

    
607
		$dnscfg = "";
608

    
609
		if ($dhcpifconf['domain']) {
610
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
611
		}
612

    
613
		if($dhcpifconf['domainsearchlist'] <> "") {
614
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
615
		}
616

    
617
		if (isset($dhcpifconf['ddnsupdate'])) {
618
			$need_ddns_updates = true;
619
			$newzone = array();
620
			if($dhcpifconf['ddnsdomain'] <> "") {
621
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
622
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
623
			} else {
624
				$newzone['domain-name'] = $config['system']['domain'];
625
			}
626
			$revsubnet = explode(".", $subnet);
627
			$revsubnet = array_reverse($revsubnet);
628
			foreach ($revsubnet as $octet) {
629
				if ($octet != "0")
630
					break;
631
				array_shift($revsubnet);
632
			}
633
			$newzone['ptr-domain'] = implode(".", $revsubnet) . ".in-addr.arpa";
634
		}
635

    
636
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
637
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
638
			if ($newzone['domain-name'])
639
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
640
		} else if (isset($config['dnsmasq']['enable'])) {
641
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
642
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0]))
643
				$newzone['dns-servers'] = $syscfg['dnsserver'];
644
		} else if (isset($config['unbound']['enable'])) {
645
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
646
		} else if (!empty($dns_arrv4)) {
647
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
648
			if ($newzone['domain-name'])
649
				$newzone['dns-servers'] = $dns_arrv4;
650
		}
651

    
652
		/* Create classes - These all contain comma separated lists. Join them into one 
653
		   big comma separated string then split them all up. */
654
		$all_mac_strings = array();
655
		if (is_array($dhcpifconf['pool'])) {
656
			foreach($all_pools as $poolconf) {
657
				$all_mac_strings[] = $poolconf['mac_allow'];
658
				$all_mac_strings[] = $poolconf['mac_deny'];
659
			}
660
		}
661
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
662
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
663
		if (!empty($all_mac_strings)) {
664
			$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
665
			foreach ($all_mac_list as $mac) {
666
				if (empty($mac)) {
667
					continue;
668
				}
669
				$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
670
				// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
671
				$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
672
				$dhcpdconf .= '}' . "\n";
673
			}
674
		}
675

    
676
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
677

    
678
		// Setup pool options
679
		foreach($all_pools as $poolconf) {
680
			if (!(ip_in_subnet($poolconf['range']['from'], "{$subnet}/{$ifcfgsn}") && ip_in_subnet($poolconf['range']['to'], "{$subnet}/{$ifcfgsn}"))) {
681
				// If the user has changed the subnet from the interfaces page and applied,
682
				// but has not updated the DHCP range, then the range to/from of the pool can be outside the subnet.
683
				// This can also happen when implementing the batch of changes when the setup wizard reloads the new settings.
684
				$error_msg = sprintf(gettext("Invalid DHCP pool %s - %s for %s subnet %s/%s detected. Please correct the settings in Services, DHCP Server"), $poolconf['range']['from'], $poolconf['range']['to'], convert_real_interface_to_friendly_descr($dhcpif), $subnet, $ifcfgsn);
685
				$do_file_notice = true;
686
				$conf_ipv4_address = $ifcfg['ipaddr'];
687
				$conf_ipv4_subnetmask = $ifcfg['subnet'];
688
				if (is_ipaddrv4($conf_ipv4_address) && is_subnet("{$conf_ipv4_address}/{$conf_ipv4_subnetmask}")) {
689
					$conf_subnet_base = gen_subnet($conf_ipv4_address, $conf_ipv4_subnetmask);
690
					if (ip_in_subnet($poolconf['range']['from'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}") &&
691
					    ip_in_subnet($poolconf['range']['to'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}")) {
692
						// Even though the running interface subnet does not match the pool range,
693
						// the interface subnet in the config file contains the pool range.
694
						// We are somewhere part-way through a settings reload, e.g. after running the setup wizard.
695
						// services_dhcpdv4_configure will be called again later when the new interface settings from
696
						// the config are applied and at that time everything will match up.
697
						// Ignore this pool on this interface for now and just log the error to the system log.
698
						log_error($error_msg);
699
						$do_file_notice = false;
700
					}
701
				}
702
				if ($do_file_notice) {
703
					file_notice("DHCP", $error_msg);
704
				}
705
				continue;
706
			}
707
			$dhcpdconf .= "	pool {\n";
708
			/* is failover dns setup? */
709
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
710
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
711
				if($poolconf['dnsserver'][1] <> "")
712
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
713
				if($poolconf['dnsserver'][2] <> "")
714
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
715
				if($poolconf['dnsserver'][3] <> "")
716
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
717
				$dhcpdconf .= ";\n";
718
			}
719

    
720
			/* allow/deny MACs */
721
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
722
			foreach ($mac_allow_list as $mac) {
723
				if (empty($mac))
724
					continue;
725
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
726
			}
727
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
728
			foreach ($mac_deny_list as $mac) {
729
				if (empty($mac))
730
					continue;
731
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
732
			}
733

    
734
			if($poolconf['failover_peerip'] <> "")
735
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
736

    
737
			if (isset($poolconf['denyunknown']))
738
			   $dhcpdconf .= "		deny unknown-clients;\n";
739

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

    
743
			if($dhcpifconf['failover_peerip'] <> "") {
744
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
745
			}
746

    
747
			$pdnscfg = "";
748

    
749
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
750
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
751
			}
752

    
753
			if(!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
754
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
755
			}
756

    
757
			if (isset($poolconf['ddnsupdate'])) {
758
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
759
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
760
				$pdnscfg .= "		ddns-update-style interim;\n";
761
			}
762

    
763
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
764
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
765
			}
766
			$dhcpdconf .= "{$pdnscfg}";
767

    
768
			// default-lease-time
769
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
770
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
771

    
772
			// max-lease-time
773
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime']))
774
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
775

    
776
			// netbios-name*
777
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
778
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
779
				$dhcpdconf .= "		option netbios-node-type 8;\n";
780
			}
781

    
782
			// ntp-servers
783
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
784
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
785

    
786
			// tftp-server-name
787
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp']))
788
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
789

    
790
			// ldap-server
791
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap']))
792
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
793

    
794
			// net boot information
795
			if(isset($poolconf['netboot'])) {
796
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
797
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
798
				}
799
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
800
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
801
				}
802
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
803
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
804
				}
805
			}
806
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
807
			$dhcpdconf .= "	}\n\n";
808
		}
809
// End of settings inside pools
810

    
811
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
812
			$routers = $dhcpifconf['gateway'];
813
			$add_routers = true;
814
		} elseif ($dhcpifconf['gateway'] == "none") {
815
			$add_routers = false;
816
		} else {
817
			$add_routers = $enable_add_routers;
818
			$routers = $ifcfgip;
819
		}
820
		if($add_routers)
821
			$dhcpdconf .= "	option routers {$routers};\n";
822

    
823
		$dhcpdconf .= <<<EOD
824
$dnscfg
825

    
826
EOD;
827
    		// default-lease-time
828
		if ($dhcpifconf['defaultleasetime'])
829
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
830

    
831
		// max-lease-time
832
		if ($dhcpifconf['maxleasetime'])
833
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
834

    
835
		// netbios-name*
836
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
837
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
838
			$dhcpdconf .= "	option netbios-node-type 8;\n";
839
		}
840

    
841
		// ntp-servers
842
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0])
843
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
844

    
845
		// tftp-server-name
846
		if ($dhcpifconf['tftp'] <> "")
847
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
848

    
849
		// Handle option, number rowhelper values
850
		$dhcpdconf .= "\n";
851
		if($dhcpifconf['numberoptions']['item']) {
852
			foreach($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
853
				if(empty($item['type']) || $item['type'] == "text")
854
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item['value']}\";\n";
855
				else
856
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item['value']};\n";
857
			}
858
		}
859

    
860
		// ldap-server
861
		if ($dhcpifconf['ldap'] <> "")
862
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
863

    
864
		// net boot information
865
		if(isset($dhcpifconf['netboot'])) {
866
			if ($dhcpifconf['nextserver'] <> "") {
867
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
868
			}
869
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
870
				$dhcpdconf .= "	if option arch = 00:06 {\n";
871
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
872
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
873
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
874
				$dhcpdconf .= "	} else if option arch = 00:09 {\n";
875
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
876
				$dhcpdconf .= "	} else {\n";
877
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
878
				$dhcpdconf .= "	}\n\n";
879
			} elseif (!empty($dhcpifconf['filename'])) {
880
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
881
			}
882
			if (!empty($dhcpifconf['rootpath'])) {
883
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
884
			}
885
		}
886

    
887
		$dhcpdconf .= <<<EOD
888
}
889

    
890
EOD;
891

    
892
		/* add static mappings */
893
		if (is_array($dhcpifconf['staticmap'])) {
894

    
895
			$i = 0;
896
			foreach ($dhcpifconf['staticmap'] as $sm) {
897
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
898

    
899
                if ($sm['mac'])
900
                    $dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
901

    
902
                if ($sm['cid'])
903
                    $dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
904

    
905
				if ($sm['ipaddr'])
906
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
907

    
908
				if ($sm['hostname']) {
909
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
910
					$dhhostname = str_replace(".", "_", $dhhostname);
911
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
912
				}
913
				if ($sm['filename'])
914
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
915

    
916
				if ($sm['rootpath'])
917
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
918

    
919
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway']))
920
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
921

    
922
				$smdnscfg = "";
923

    
924
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
925
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
926
				}
927

    
928
				if(!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
929
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
930
				}
931

    
932
				if (isset($sm['ddnsupdate'])) {
933
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain']))
934
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
935
					$pdnscfg .= "		ddns-update-style interim;\n";
936
				}
937

    
938
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
939
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
940
				}
941
				$dhcpdconf .= "{$smdnscfg}";
942

    
943
				// default-lease-time
944
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime']))
945
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
946

    
947
				// max-lease-time
948
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime']))
949
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
950

    
951
				// netbios-name*
952
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
953
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
954
					$dhcpdconf .= "	option netbios-node-type 8;\n";
955
				}
956

    
957
				// ntp-servers
958
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0]))
959
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
960

    
961
				// tftp-server-name
962
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp']))
963
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
964

    
965
				$dhcpdconf .= "}\n";
966
				$i++;
967
			}
968
		}
969

    
970
		$dhcpdifs[] = get_real_interface($dhcpif);
971
		if ($newzone['domain-name'])
972
		{
973
			if ($need_ddns_updates)
974
			{
975
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
976
			}
977
			$ddns_zones[] = $newzone;
978
		}
979
	}
980

    
981
	if ($need_ddns_updates) {
982
		$dhcpdconf .= "ddns-update-style interim;\n";
983
		$dhcpdconf .= "update-static-leases on;\n";
984

    
985
		$dhcpdconf .= dhcpdkey($dhcpifconf);
986
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
987
	}
988

    
989
	/* write dhcpd.conf */
990
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
991
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
992
		unset($dhcpdconf);
993
		return 1;
994
	}
995
	unset($dhcpdconf);
996

    
997
	/* create an empty leases database */
998
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases"))
999
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1000

    
1001
	/* make sure there isn't a stale dhcpd.pid file, which can make dhcpd fail to start.   */
1002
	/* if we get here, dhcpd has been killed and is not started yet                        */ 
1003
	unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
1004

    
1005
	/* fire up dhcpd in a chroot */
1006
	if (count($dhcpdifs) > 0) {
1007
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1008
			join(" ", $dhcpdifs));
1009
	}
1010

    
1011
	if (platform_booting())
1012
		print "done.\n";
1013

    
1014
	return 0;
1015
}
1016

    
1017
function dhcpdkey($dhcpifconf)
1018
{
1019
	$dhcpdconf = "";
1020
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
1021
	{
1022
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1023
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1024
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1025
		$dhcpdconf .= "}\n";
1026
	}
1027

    
1028
	return $dhcpdconf;
1029
}
1030

    
1031
function dhcpdzones($ddns_zones, $dhcpifconf)
1032
{
1033
	$dhcpdconf = "";
1034

    
1035
	if (is_array($ddns_zones)) {
1036
		$added_zones = array();
1037
		foreach ($ddns_zones as $zone) {
1038
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers']))
1039
				continue;
1040
			$primary = $zone['dns-servers'][0];
1041
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1042

    
1043
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1044
			if (!is_ipaddrv4($primary)) {
1045
				if (is_ipaddrv4($secondary)) {
1046
					$primary = $secondary;
1047
					$secondary = "";
1048
				} else {
1049
					continue;
1050
				}
1051
			}
1052

    
1053
			// We don't need to add zones multiple times.
1054
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1055
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1056
				$dhcpdconf .= "	primary {$primary};\n";
1057
				if (is_ipaddrv4($secondary))
1058
					$dhcpdconf .= "	secondary {$secondary};\n";
1059
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
1060
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1061
				$dhcpdconf .= "}\n";
1062
				$added_zones[] = $zone['domain-name'];
1063
			}
1064
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1065
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1066
				$dhcpdconf .= "	primary {$primary};\n";
1067
				if (is_ipaddrv4($secondary))
1068
					$dhcpdconf .= "	secondary {$secondary};\n";
1069
				if($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "")
1070
                    $dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1071
				$dhcpdconf .= "}\n";
1072
				$added_zones[] = $zone['ptr-domain'];
1073
			}
1074
		}
1075
	}
1076

    
1077
	return $dhcpdconf;
1078
}
1079

    
1080
function services_dhcpdv6_configure($blacklist = array()) {
1081
	global $config, $g;
1082

    
1083
	if($g['services_dhcp_server_enable'] == false)
1084
		return;
1085

    
1086
	if(isset($config['system']['developerspew'])) {
1087
		$mt = microtime();
1088
		echo "services_dhcpd_configure($if) being called $mt\n";
1089
	}
1090

    
1091
	/* kill any running dhcpd */
1092
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid"))
1093
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1094
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid"))
1095
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1096

    
1097
	/* DHCP enabled on any interfaces? */
1098
	if (!is_dhcpv6_server_enabled())
1099
		return 0;
1100

    
1101
	if (platform_booting()) {
1102
		if ($g['platform'] != "pfSense") {
1103
			/* restore the leases, if we have them */
1104
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1105
				$dhcprestore = "";
1106
				$dhcpreturn = "";
1107
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1108
				$dhcprestore = implode(" ", $dhcprestore);
1109
				if($dhcpreturn <> 0) {
1110
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1111
				}
1112
			}
1113
		}
1114
	}
1115

    
1116
	$syscfg = $config['system'];
1117
	if (!is_array($config['dhcpdv6']))
1118
		$config['dhcpdv6'] = array();
1119
	$dhcpdv6cfg = $config['dhcpdv6'];
1120
	$Iflist = get_configured_interface_list();
1121
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1122

    
1123

    
1124
	if (platform_booting())
1125
		echo "Starting DHCPv6 service...";
1126
	else
1127
		sleep(1);
1128

    
1129
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1130
	foreach ($Iflist as $ifname) {
1131
		/* Do not put in the config an interface which is down */
1132
		if (isset($blacklist[$ifname]))
1133
			continue;
1134
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1135
			$realif = get_real_interface($ifname, "inet6");
1136
			$ifcfgipv6 = get_interface_ipv6($ifname);
1137
			if(!is_ipaddrv6($ifcfgipv6))
1138
				continue;
1139
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1140
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1141
			$trackcfg = $config['interfaces'][$trackifname];
1142
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1143
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1144
			$dhcpdv6cfg[$ifname] = array();
1145
			$dhcpdv6cfg[$ifname]['enable'] = true;
1146
			/* range */
1147
			$ifcfgipv6arr[7] = "1000";
1148
			$dhcpdv6cfg[$ifname]['range'] = array();
1149
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1150
			$ifcfgipv6arr[7] = "2000";
1151
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1152
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1153
			if($pdlen > 2) {
1154
				$pdlenmax = $pdlen;
1155
				$pdlenhalf = $pdlenmax -1;
1156
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1157
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1158
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1159

    
1160
				/* set the delegation start to half the current address block */
1161
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1162
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1163

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

    
1168
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1169
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1170
			}
1171
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1172
		}
1173
	}
1174

    
1175
	$custoptionsv6 = "";
1176
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1177
		if(is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1178
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1179
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1180
			}
1181
		}
1182
	}
1183

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

    
1187
	$dhcpdv6conf = <<<EOD
1188

    
1189
option domain-name "{$syscfg['domain']}";
1190
option ldap-server code 95 = text;
1191
option domain-search-list code 119 = text;
1192
{$custoptionsv6}
1193
default-lease-time 7200;
1194
max-lease-time 86400;
1195
log-facility local7;
1196
one-lease-per-client true;
1197
deny duplicates;
1198
ping-check true;
1199
update-conflict-detection false;
1200

    
1201
EOD;
1202

    
1203
	if(!isset($dhcpv6ifconf['disableauthoritative']))
1204
		$dhcpdv6conf .= "authoritative;\n";
1205

    
1206
	if(isset($dhcpv6ifconf['alwaysbroadcast']))
1207
		$dhcpdv6conf .= "always-broadcast on\n";
1208

    
1209
	$dhcpdv6ifs = array();
1210

    
1211
	$dhcpv6num = 0;
1212
	$nsupdate = false;
1213

    
1214
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1215

    
1216
		$ddns_zones = array();
1217

    
1218
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1219

    
1220
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable']))
1221
			continue;
1222
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1223
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1224
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1225

    
1226
		if ($is_olsr_enabled == true) {
1227
			if($dhcpv6ifconf['netmask'])
1228
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1229
		}
1230

    
1231
		$dnscfgv6 = "";
1232

    
1233
		if ($dhcpv6ifconf['domain']) {
1234
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1235
		}
1236

    
1237
    	if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1238
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1239
    	}
1240

    
1241
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1242
			if($dhcpv6ifconf['ddnsdomain'] <> "") {
1243
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1244
			}
1245
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1246
			$nsupdate = true;
1247
		}
1248

    
1249
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1250
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1251
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1252
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1253
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1254
			$dns_arrv6 = array();
1255
			foreach($syscfg['dnsserver'] as $dnsserver) {
1256
				if (is_ipaddrv6($dnsserver)) {
1257
					$dns_arrv6[] = $dnsserver;
1258
				}
1259
			}
1260
			if(!empty($dns_arrv6))
1261
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1262
		}
1263

    
1264
		if ($dhcpv6ifconf['domain']) {
1265
			$newzone = array();
1266
			$newzone['domain-name'] = $dhcpv6ifconf['domain']; 
1267
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1268
			$ddns_zones[] = $newzone;
1269
		}
1270

    
1271
		if (is_ipaddrv6($ifcfgipv6)) {
1272
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1273
		} else {
1274
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1275
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1276
		}
1277
		$dhcpdv6conf .= " {\n";
1278

    
1279
		$dhcpdv6conf .= <<<EOD
1280
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1281
$dnscfgv6
1282

    
1283
EOD;
1284

    
1285
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1286
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1287
		}
1288
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1289
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1290
		}
1291
    		// default-lease-time
1292
		if ($dhcpv6ifconf['defaultleasetime'])
1293
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1294

    
1295
		// max-lease-time
1296
		if ($dhcpv6ifconf['maxleasetime'])
1297
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1298

    
1299
		// ntp-servers
1300
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1301
			$ntpservers = array();
1302
			foreach($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1303
				if(is_ipaddrv6($ntpserver))
1304
					$ntpservers[] = $ntpserver;
1305
			}
1306
			if(count($ntpservers) > 0 )
1307
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1308
		}
1309
		// tftp-server-name
1310
		/* Needs ISC DHCPD support
1311
		 if ($dhcpv6ifconf['tftp'] <> "")
1312
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1313
		*/
1314

    
1315
		// Handle option, number rowhelper values
1316
		$dhcpdv6conf .= "\n";
1317
		if ($dhcpv6ifconf['numberoptions']['item']) {
1318
			foreach($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1319
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1320
			}
1321
		}
1322

    
1323
		// ldap-server
1324
		if ($dhcpv6ifconf['ldap'] <> "")
1325
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1326

    
1327
		// net boot information
1328
		if(isset($dhcpv6ifconf['netboot'])) {
1329
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1330
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1331
			}
1332
		}
1333

    
1334
		$dhcpdv6conf .= "}\n";
1335

    
1336
		/* add static mappings */
1337
		/* Needs to use DUID */
1338
		if (is_array($dhcpv6ifconf['staticmap'])) {
1339
			$i = 0;
1340
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1341
				$dhcpdv6conf .= <<<EOD
1342
host s_{$dhcpv6if}_{$i} {
1343
	host-identifier option dhcp6.client-id {$sm['duid']};
1344

    
1345
EOD;
1346
				if ($sm['ipaddrv6'])
1347
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1348

    
1349
				if ($sm['hostname']) {
1350
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1351
					$dhhostname = str_replace(".", "_", $dhhostname);
1352
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1353
				}
1354
				if ($sm['filename'])
1355
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1356

    
1357
				if ($sm['rootpath'])
1358
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1359

    
1360
				$dhcpdv6conf .= "}\n";
1361
				$i++;
1362
			}
1363
		}
1364

    
1365
		if ($dhcpv6ifconf['domain'])
1366
		{
1367
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1368
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1369
		}
1370

    
1371
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1372
			if(preg_match("/poes/si", $dhcpv6if)) {
1373
				/* magic here */
1374
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1375
			} else {
1376
				$realif = get_real_interface($dhcpv6if, "inet6");
1377
				if (stristr("$realif", "bridge")) {
1378
					$mac = get_interface_mac($realif);
1379
					$v6address = generate_ipv6_from_mac($mac);
1380
					/* Create link local address for bridges */
1381
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1382
				}
1383
				$realif = escapeshellcmd($realif);
1384
				$dhcpdv6ifs[] = $realif;
1385
			}
1386
		}
1387
	}
1388

    
1389
	if ($nsupdate)
1390
	{
1391
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1392
	}
1393
	else
1394
	{
1395
		$dhcpdv6conf .= "ddns-update-style none;\n";
1396
	}
1397

    
1398
	/* write dhcpdv6.conf */
1399
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1400
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1401
		if (platform_booting())
1402
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1403
		unset($dhcpdv6conf);
1404
		return 1;
1405
	}
1406
	unset($dhcpdv6conf);
1407

    
1408
	/* create an empty leases v6 database */
1409
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases"))
1410
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1411

    
1412
        /* make sure there isn't a stale dhcpdv6.pid file, which may make dhcpdv6 fail to start.  */
1413
        /* if we get here, dhcpdv6 has been killed and is not started yet                         */
1414
        unlink_if_exists("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1415

    
1416
	/* fire up dhcpd in a chroot */
1417
	if (count($dhcpdv6ifs) > 0) {
1418
		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 " .
1419
			join(" ", $dhcpdv6ifs));
1420
		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");
1421
	}
1422
	if (platform_booting())
1423
		print gettext("done.") . "\n";
1424

    
1425
	return 0;
1426
}
1427

    
1428
function services_igmpproxy_configure() {
1429
        global $config, $g;
1430

    
1431
        /* kill any running igmpproxy */
1432
        killbyname("igmpproxy");
1433

    
1434
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0))
1435
		return 1;
1436

    
1437
        $iflist = get_configured_interface_list();
1438

    
1439
        $igmpconf = <<<EOD
1440

    
1441
##------------------------------------------------------
1442
## Enable Quickleave mode (Sends Leave instantly)
1443
##------------------------------------------------------
1444
quickleave
1445

    
1446
EOD;
1447

    
1448
        foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1449
                unset($iflist[$igmpcf['ifname']]);
1450
                $realif = get_real_interface($igmpcf['ifname']);
1451
                if (empty($igmpcf['threshold']))
1452
                        $threshld = 1;
1453
                else
1454
                        $threshld = $igmpcf['threshold'];
1455
                $igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1456

    
1457
                if ($igmpcf['address'] <> "") {
1458
                        $item = explode(" ", $igmpcf['address']);
1459
                        foreach($item as $iww)
1460
                                $igmpconf .= "altnet {$iww}\n";
1461
                }
1462
                $igmpconf .= "\n";
1463
        }
1464
        foreach ($iflist as $ifn) {
1465
                $realif = get_real_interface($ifn);
1466
                $igmpconf .= "phyint {$realif} disabled\n";
1467
        }
1468
	$igmpconf .= "\n";
1469

    
1470
        $igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1471
        if (!$igmpfl) {
1472
                log_error(gettext("Could not write Igmpproxy configuration file!"));
1473
                return;
1474
        }
1475
        fwrite($igmpfl, $igmpconf);
1476
        fclose($igmpfl);
1477
	unset($igmpconf);
1478

    
1479
	/* NOTE: -d4 means everything LOG_WARNING and smaller */
1480
        mwexec("/usr/local/sbin/igmpproxy -d4 -c {$g['tmp_path']}/igmpproxy.conf");
1481
        log_error(gettext("Started IGMP proxy service."));
1482

    
1483
        return 0;
1484
}
1485

    
1486
function services_dhcrelay_configure() {
1487
	global $config, $g;
1488
	if ($g['platform'] == 'jail')
1489
		return;
1490
	if(isset($config['system']['developerspew'])) {
1491
		$mt = microtime();
1492
		echo "services_dhcrelay_configure() being called $mt\n";
1493
	}
1494

    
1495
	/* kill any running dhcrelay */
1496
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1497

    
1498
	$dhcrelaycfg =& $config['dhcrelay'];
1499

    
1500
	/* DHCPRelay enabled on any interfaces? */
1501
	if (!isset($dhcrelaycfg['enable']))
1502
		return 0;
1503

    
1504
	if (platform_booting())
1505
		echo gettext("Starting DHCP relay service...");
1506
	else
1507
		sleep(1);
1508

    
1509
	$iflist = get_configured_interface_list();
1510

    
1511
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1512
	foreach ($dhcifaces as $dhcrelayif) {
1513
		if (!isset($iflist[$dhcrelayif]) ||
1514
			link_interface_to_bridge($dhcrelayif))
1515
			continue;
1516

    
1517
		if (is_ipaddr(get_interface_ip($dhcrelayif)))
1518
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1519
	}
1520

    
1521
	$dhcrelayifs = array_unique($dhcrelayifs);
1522

    
1523
	/* fire up dhcrelay */
1524
	if (empty($dhcrelayifs)) {
1525
		log_error("No suitable interface found for running dhcrelay!");
1526
		return; /* XXX */
1527
	}
1528

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

    
1531
	if (isset($dhcrelaycfg['agentoption']))
1532
		$cmd .=  " -a -m replace";
1533

    
1534
	$srvips = explode(",", $dhcrelaycfg['server']);
1535
	if (!is_array($srvips)) {
1536
		log_error("No DHCP relay destination IP has been configured!");
1537
		return;
1538
	}
1539
	$cmd .= " " . implode(" ", $srvips);
1540
	mwexec($cmd);
1541
	unset($cmd);
1542

    
1543
	return 0;
1544
}
1545

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

    
1555
	/* kill any running dhcrelay */
1556
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1557

    
1558
	$dhcrelaycfg =& $config['dhcrelay6'];
1559

    
1560
	/* DHCPv6 Relay enabled on any interfaces? */
1561
	if (!isset($dhcrelaycfg['enable']))
1562
		return 0;
1563

    
1564
	if (platform_booting())
1565
		echo gettext("Starting DHCPv6 relay service...");
1566
	else
1567
		sleep(1);
1568

    
1569
	$iflist = get_configured_interface_list();
1570

    
1571
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1572
	foreach ($dhcifaces as $dhcrelayif) {
1573
		if (!isset($iflist[$dhcrelayif]) ||
1574
			link_interface_to_bridge($dhcrelayif))
1575
			continue;
1576

    
1577
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif)))
1578
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1579
	}
1580
	$dhcrelayifs = array_unique($dhcrelayifs);
1581
	$srvips = explode(",", $dhcrelaycfg['server']);
1582
	if (!is_array($srvips)) {
1583
		log_error("No destination IP has been configured!");
1584
		return;
1585
	}
1586

    
1587
	/* fire up dhcrelay */
1588
	if (empty($dhcrelayifs) || empty($srvifaces) ) {
1589
		log_error("No suitable interface found for running dhcrelay -6!");
1590
		return; /* XXX */
1591
	}
1592

    
1593
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1594
	foreach ($dhcrelayifs as $dhcrelayif) {
1595
		$cmd .= " -l {$dhcrelayif}";
1596
	}
1597
	foreach ($srvifaces as $srviface) {
1598
		$cmd .= " -u \"{$srviface}\"";
1599
	}
1600
	mwexec($cmd);
1601
	unset($cmd);
1602

    
1603
	return 0;
1604
}
1605

    
1606
function services_dyndns_configure_client($conf) {
1607

    
1608
	if (!isset($conf['enable']))
1609
		return;
1610

    
1611
	/* load up the dyndns.class */
1612
	require_once("dyndns.class");
1613

    
1614
	$dns = new updatedns($dnsService = $conf['type'],
1615
		$dnsHost = $conf['host'],
1616
		$dnsUser = $conf['username'],
1617
		$dnsPass = $conf['password'],
1618
		$dnsWildcard = $conf['wildcard'],
1619
		$dnsMX = $conf['mx'],
1620
		$dnsIf = "{$conf['interface']}",
1621
		$dnsBackMX = NULL,
1622
		$dnsServer = NULL,
1623
		$dnsPort = NULL,
1624
		$dnsUpdateURL = "{$conf['updateurl']}",
1625
		$forceUpdate = $conf['force'],
1626
		$dnsZoneID=$conf['zoneid'],
1627
		$dnsTTL=$conf['ttl'],
1628
		$dnsResultMatch = "{$conf['resultmatch']}",
1629
		$dnsRequestIf = "{$conf['requestif']}",
1630
		$dnsID = "{$conf['id']}",
1631
		$dnsVerboseLog = $conf['verboselog'],
1632
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1633
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1634
}
1635

    
1636
function services_dyndns_configure($int = "") {
1637
	global $config, $g;
1638
	if(isset($config['system']['developerspew'])) {
1639
		$mt = microtime();
1640
		echo "services_dyndns_configure() being called $mt\n";
1641
	}
1642

    
1643
	$dyndnscfg = $config['dyndnses']['dyndns'];
1644
	$gwgroups = return_gateway_groups_array();
1645
	if (is_array($dyndnscfg)) {
1646
		if (platform_booting())
1647
			echo gettext("Starting DynDNS clients...");
1648

    
1649
		foreach ($dyndnscfg as $dyndns) {
1650
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1651
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1652
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1653
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1654
				services_dyndns_configure_client($dyndns);
1655
				sleep(1);
1656
			}
1657
		}
1658

    
1659
		if (platform_booting())
1660
			echo gettext("done.") . "\n";
1661
	}
1662

    
1663
	return 0;
1664
}
1665

    
1666
function dyndnsCheckIP($int) {
1667
	global $config;
1668
	$ip_address = get_interface_ip($int);
1669
	if (is_private_ip($ip_address)) {
1670
		$gateways_status = return_gateways_status(true);
1671
		// If the gateway for this interface is down, then the external check cannot work.
1672
		// Avoid the long wait for the external check to timeout.
1673
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'],"down"))
1674
			return "down";
1675
		$hosttocheck = "http://checkip.dyndns.org";
1676
		$ip_ch = curl_init($hosttocheck);
1677
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1678
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1679
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
1680
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1681
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1682
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1683
		$ip_result_page = curl_exec($ip_ch);
1684
		curl_close($ip_ch);
1685
		$ip_result_decoded = urldecode($ip_result_page);
1686
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1687
		$ip_address = trim($matches[1]);
1688
	}
1689
	return $ip_address;
1690
}
1691

    
1692
function services_dnsmasq_configure() {
1693
	global $config, $g;
1694
	$return = 0;
1695

    
1696
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1697
	$standard_args = array(
1698
		"dns-forward-max" => "--dns-forward-max=5000",
1699
		"cache-size" => "--cache-size=10000",
1700
		"local-ttl" => "--local-ttl=1"
1701
	);
1702

    
1703

    
1704
	if(isset($config['system']['developerspew'])) {
1705
		$mt = microtime();
1706
		echo "services_dnsmasq_configure() being called $mt\n";
1707
	}
1708

    
1709
	/* kill any running dnsmasq */
1710
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid"))
1711
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1712

    
1713
	if (isset($config['dnsmasq']['enable'])) {
1714

    
1715
		if (platform_booting())
1716
			echo gettext("Starting DNS forwarder...");
1717
		else
1718
			sleep(1);
1719

    
1720
                /* generate hosts file */
1721
                if(system_hosts_generate()!=0)
1722
                        $return = 1;
1723

    
1724
		$args = "";
1725

    
1726
		if (isset($config['dnsmasq']['regdhcp'])) {
1727
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1728
		}
1729

    
1730
		/* Setup listen port, if non-default */
1731
		if (is_port($config['dnsmasq']['port']))
1732
			$args .= " --port={$config['dnsmasq']['port']} ";
1733

    
1734
		$listen_addresses = "";
1735
		if(isset($config['dnsmasq']['interface'])) {
1736
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1737
			foreach ($interfaces as $interface) {
1738
				if (is_ipaddrv4($interface)) {
1739
					$listen_addresses .= " --listen-address={$interface} ";
1740
				} else if (is_ipaddrv6($interface)) {
1741
					/*
1742
					 * XXX: Since dnsmasq does not support link-local address
1743
					 * with scope specified. These checks are being done.
1744
					 */
1745
					if (is_linklocal($interface) && strstr($interface, "%")) {
1746
						$tmpaddrll6 = explode("%", $interface);
1747
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1748
					} else 
1749
						$listen_addresses .= " --listen-address={$interface} ";
1750
				} else if (strstr($interface, "_vip")) {
1751
					$laddr = get_configured_carp_interface_list($interface);
1752
					if (is_ipaddr($laddr)) 
1753
						$listen_addresses .= " --listen-address={$laddr} ";
1754
				} else {
1755
					$if = get_real_interface($interface);
1756
					if (does_interface_exist($if)) {
1757
						$laddr = find_interface_ip($if);
1758
						if (is_ipaddrv4($laddr))
1759
							$listen_addresses .= " --listen-address={$laddr} ";
1760
						$laddr6 = find_interface_ipv6($if);
1761
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1762
							/*
1763
							 * XXX: Since dnsmasq does not support link-local address
1764
							 * with scope specified. These checks are being done.
1765
							 */
1766
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1767
								$tmpaddrll6 = explode("%", $laddr6);
1768
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1769
							} else
1770
								$listen_addresses .= " --listen-address={$laddr6} ";
1771
						}
1772
					}
1773
				}
1774
			}
1775
			if (!empty($listen_addresses)) {
1776
				$args .= " {$listen_addresses} ";
1777
				if (isset($config['dnsmasq']['strictbind']))
1778
					$args .= " --bind-interfaces ";
1779
			}
1780
		}
1781

    
1782
		/* If selected, then first forward reverse lookups for private IPv4 addresses to nowhere. */
1783
		/* Only make entries for reverse domains that do not have a matching domain override. */
1784
		if (isset($config['dnsmasq']['no_private_reverse'])) {
1785
			/* Note: Carrier Grade NAT (CGN) addresses 100.64.0.0/10 are intentionally not here. */
1786
			/* End-users should not be aware of CGN addresses, so reverse lookups for these should not happen. */
1787
			/* Just the pfSense WAN might get a CGN address from an ISP. */
1788

    
1789
			// Build an array of domain overrides to help in checking for matches.
1790
			$override_a = array();
1791
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1792
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1793
					$override_a[$override['domain']] = "y";
1794
				}
1795
			}
1796

    
1797
			// Build an array of the private reverse lookup domain names
1798
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
1799
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
1800
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) { 
1801
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
1802
			}
1803

    
1804
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
1805
			foreach ($reverse_domain_a as $reverse_domain) { 
1806
				if (!isset($override_a[$reverse_domain]))
1807
					$args .= " --server=/$reverse_domain/ ";
1808
			}
1809
			unset($override_a);
1810
			unset($reverse_domain_a);
1811
		}
1812

    
1813
		/* Setup forwarded domains */
1814
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1815
			foreach($config['dnsmasq']['domainoverrides'] as $override) {
1816
				if ($override['ip'] == "!")
1817
					$override[ip] = "";
1818
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
1819
			}
1820
		}
1821

    
1822
		/* Allow DNS Rebind for forwarded domains */
1823
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1824
			if(!isset($config['system']['webgui']['nodnsrebindcheck'])) {
1825
				foreach($config['dnsmasq']['domainoverrides'] as $override) {
1826
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
1827
				}
1828
			}
1829
		}
1830

    
1831
		if(!isset($config['system']['webgui']['nodnsrebindcheck']))
1832
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
1833

    
1834
		if (isset($config['dnsmasq']['strict_order'])) {
1835
			$args .= " --strict-order ";
1836
		}
1837

    
1838
		if (isset($config['dnsmasq']['domain_needed'])) {
1839
			$args .= " --domain-needed ";
1840
		}
1841

    
1842
		if ($config['dnsmasq']['custom_options'])
1843
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
1844
				$args .= " " . escapeshellarg("--{$c}");
1845
				$p = explode('=', $c);
1846
				if (array_key_exists($p[0], $standard_args))
1847
					unset($standard_args[$p[0]]);
1848
			}
1849
		$args .= ' ' . implode(' ', array_values($standard_args));
1850

    
1851
		/* run dnsmasq */
1852
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
1853
		//log_error("dnsmasq command: {$cmd}");
1854
		mwexec_bg($cmd);
1855
		unset($args);
1856

    
1857
        system_dhcpleases_configure();
1858

    
1859
		if (platform_booting())
1860
			echo gettext("done.") . "\n";
1861
	}
1862

    
1863
	if (!platform_booting()) {
1864
		if(services_dhcpd_configure()!=0)
1865
			$return = 1;
1866
	}
1867

    
1868
	return $return;
1869
}
1870

    
1871
function services_unbound_configure() {
1872
	global $config, $g;
1873
	$return = 0;
1874

    
1875
	if (isset($config['system']['developerspew'])) {
1876
		$mt = microtime();
1877
		echo "services_unbound_configure() being called $mt\n";
1878
	}
1879

    
1880
	// kill any running Unbound instance
1881
	if (file_exists("{$g['varrun_path']}/unbound.pid"))
1882
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
1883

    
1884
	if (isset($config['unbound']['enable'])) {
1885
		if (platform_booting())
1886
			echo gettext("Starting DNS Resolver...");
1887
		else
1888
			sleep(1);
1889

    
1890
		/* generate hosts file */
1891
		if(system_hosts_generate()!=0)
1892
			$return = 1;
1893

    
1894
		require_once('/etc/inc/unbound.inc');
1895
		sync_unbound_service();
1896
		if (platform_booting())
1897
			echo gettext("done.") . "\n";
1898

    
1899
        system_dhcpleases_configure();
1900
	}
1901

    
1902
	if (!platform_booting()) {
1903
		if (services_dhcpd_configure()!=0)
1904
			$return = 1;
1905
	}
1906

    
1907
	return $return;
1908
}
1909

    
1910
function services_snmpd_configure() {
1911
	global $config, $g;
1912
	if(isset($config['system']['developerspew'])) {
1913
		$mt = microtime();
1914
		echo "services_snmpd_configure() being called $mt\n";
1915
	}
1916

    
1917
	/* kill any running snmpd */
1918
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
1919
	sleep(2);
1920
	if(is_process_running("bsnmpd"))
1921
		mwexec("/usr/bin/killall bsnmpd", true);
1922

    
1923
	if (isset($config['snmpd']['enable'])) {
1924

    
1925
		if (platform_booting())
1926
			echo gettext("Starting SNMP daemon... ");
1927

    
1928
		/* generate snmpd.conf */
1929
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
1930
		if (!$fd) {
1931
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
1932
			return 1;
1933
		}
1934

    
1935

    
1936
		$snmpdconf = <<<EOD
1937
location := "{$config['snmpd']['syslocation']}"
1938
contact := "{$config['snmpd']['syscontact']}"
1939
read := "{$config['snmpd']['rocommunity']}"
1940

    
1941
EOD;
1942

    
1943
/* No docs on what write strings do there for disable for now.
1944
		if(isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1945
		    $snmpdconf .= <<<EOD
1946
# write string
1947
write := "{$config['snmpd']['rwcommunity']}"
1948

    
1949
EOD;
1950
		}
1951
*/
1952

    
1953

    
1954
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1955
		    $snmpdconf .= <<<EOD
1956
# SNMP Trap support.
1957
traphost := {$config['snmpd']['trapserver']}
1958
trapport := {$config['snmpd']['trapserverport']}
1959
trap := "{$config['snmpd']['trapstring']}"
1960

    
1961

    
1962
EOD;
1963
		}
1964

    
1965
		$version = trim(file_get_contents('/etc/version'));
1966
		$platform = trim(file_get_contents('/etc/platform'));
1967
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense"))
1968
			$platform = $g['product_name'];
1969
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
1970
			" {$version} {$platform} " . php_uname("s") .
1971
			" " . php_uname("r") . " " . php_uname("m");
1972

    
1973
		$snmpdconf .= <<<EOD
1974
system := 1     # pfSense
1975
%snmpd
1976
sysDescr			= "{$sysDescr}"
1977
begemotSnmpdDebugDumpPdus       = 2
1978
begemotSnmpdDebugSyslogPri      = 7
1979
begemotSnmpdCommunityString.0.1 = $(read)
1980

    
1981
EOD;
1982

    
1983
/* No docs on what write strings do there for disable for now.
1984
		if(isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])){
1985
		    $snmpdconf .= <<<EOD
1986
begemotSnmpdCommunityString.0.2 = $(write)
1987

    
1988
EOD;
1989
		}
1990
*/
1991

    
1992

    
1993
		if(isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])){
1994
		    $snmpdconf .= <<<EOD
1995
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
1996
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
1997
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
1998

    
1999
EOD;
2000
		}
2001

    
2002

    
2003
		$snmpdconf .= <<<EOD
2004
begemotSnmpdCommunityDisable    = 1
2005

    
2006
EOD;
2007

    
2008
		if (isset($config['snmpd']['bindlan'])) {
2009
			$config['snmpd']['bindip'] = 'lan';
2010
			unset($config['snmpd']['bindlan']);
2011
		}
2012
		$bind_to_ip = "0.0.0.0";
2013
		if(isset($config['snmpd']['bindip'])) {
2014
			if (is_ipaddr($config['snmpd']['bindip'])) {
2015
				$bind_to_ip = $config['snmpd']['bindip'];
2016
			} else {
2017
				$if = get_real_interface($config['snmpd']['bindip']);
2018
				if (does_interface_exist($if))
2019
					$bind_to_ip = find_interface_ip($if);
2020
			}
2021
		}
2022

    
2023
		if(is_port( $config['snmpd']['pollport'] )) {
2024
		    $snmpdconf .= <<<EOD
2025
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2026

    
2027
EOD;
2028

    
2029
		}
2030

    
2031
		$snmpdconf .= <<<EOD
2032
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2033
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2034

    
2035
# These are bsnmp macros not php vars.
2036
sysContact      = $(contact)
2037
sysLocation     = $(location)
2038
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2039

    
2040
snmpEnableAuthenTraps = 2
2041

    
2042
EOD;
2043

    
2044
		if (is_array( $config['snmpd']['modules'] )) {
2045
		    if(isset($config['snmpd']['modules']['mibii'])) {
2046
			$snmpdconf .= <<<EOD
2047
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2048

    
2049
EOD;
2050
		    }
2051

    
2052
		    if(isset($config['snmpd']['modules']['netgraph'])) {
2053
			$snmpdconf .= <<<EOD
2054
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2055
%netgraph
2056
begemotNgControlNodeName = "snmpd"
2057

    
2058
EOD;
2059
		    }
2060

    
2061
		    if(isset($config['snmpd']['modules']['pf'])) {
2062
			$snmpdconf .= <<<EOD
2063
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2064

    
2065
EOD;
2066
		    }
2067

    
2068
		    if(isset($config['snmpd']['modules']['hostres'])) {
2069
			/* XXX: hostres module crashes APU - ticket #4403 */
2070
			$specplatform = system_identify_specific_platform();
2071
			if ($specplatform['name'] == 'APU') {
2072
				log_error("'Host Resources' SNMP module was ignored because it can potentially crash system on APU boards");
2073
			} else {
2074
				$snmpdconf .= <<<EOD
2075
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2076

    
2077
EOD;
2078
			}
2079
			unset($specplatform);
2080
		    }
2081

    
2082
		    if(isset($config['snmpd']['modules']['bridge'])) {
2083
			$snmpdconf .= <<<EOD
2084
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2085
# config must end with blank line
2086

    
2087
EOD;
2088
		    }
2089
			if(isset($config['snmpd']['modules']['ucd'])) {
2090
				$snmpdconf .= <<<EOD
2091
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2092

    
2093
EOD;
2094
			}
2095
			if(isset($config['snmpd']['modules']['regex'])) {
2096
				$snmpdconf .= <<<EOD
2097
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2098

    
2099
EOD;
2100
			}
2101
		}
2102

    
2103
		fwrite($fd, $snmpdconf);
2104
		fclose($fd);
2105
		unset($snmpdconf);
2106

    
2107
		if (isset($config['snmpd']['bindlan'])) {
2108
			$bindlan = "";
2109
		}
2110

    
2111
		/* run bsnmpd */
2112
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2113
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2114

    
2115
		if (platform_booting())
2116
			echo gettext("done.") . "\n";
2117
	}
2118

    
2119
	return 0;
2120
}
2121

    
2122
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2123
	global $config, $g;
2124
	if(isset($config['system']['developerspew'])) {
2125
		$mt = microtime();
2126
		echo "services_dnsupdate_process() being called $mt\n";
2127
	}
2128

    
2129
	/* Dynamic DNS updating active? */
2130
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2131
		$notify_text = "";
2132
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2133
			if (!isset($dnsupdate['enable']))
2134
				continue;
2135
			if (!empty($int) && $int != $dnsupdate['interface'])
2136
				continue;
2137
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host']))
2138
				continue;
2139

    
2140
			/* determine interface name */
2141
			$if = get_real_interface($dnsupdate['interface']);
2142
			
2143
			if (isset($dnsupdate['usepublicip']))
2144
                                $wanip = dyndnsCheckIP($dnsupdate['interface']);
2145
                        else
2146
                                $wanip = get_interface_ip($dnsupdate['interface']);
2147
			
2148
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2149
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2150
			$currentTime = time();
2151

    
2152
			if ($wanip || $wanipv6) {
2153
				$keyname = $dnsupdate['keyname'];
2154
				/* trailing dot */
2155
				if (substr($keyname, -1) != ".")
2156
					$keyname .= ".";
2157

    
2158
				$hostname = $dnsupdate['host'];
2159
				/* trailing dot */
2160
				if (substr($hostname, -1) != ".")
2161
					$hostname .= ".";
2162

    
2163
				/* write private key file
2164
				   this is dumb - public and private keys are the same for HMAC-MD5,
2165
				   but nsupdate insists on having both */
2166
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2167
				$privkey = <<<EOD
2168
Private-key-format: v1.2
2169
Algorithm: 157 (HMAC)
2170
Key: {$dnsupdate['keydata']}
2171

    
2172
EOD;
2173
				fwrite($fd, $privkey);
2174
				fclose($fd);
2175

    
2176
				/* write public key file */
2177
				if ($dnsupdate['keytype'] == "zone") {
2178
					$flags = 257;
2179
					$proto = 3;
2180
				} else if ($dnsupdate['keytype'] == "host") {
2181
					$flags = 513;
2182
					$proto = 3;
2183
				} else if ($dnsupdate['keytype'] == "user") {
2184
					$flags = 0;
2185
					$proto = 2;
2186
				}
2187

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

    
2192
				/* generate update instructions */
2193
				$upinst = "";
2194
				if (!empty($dnsupdate['server']))
2195
					$upinst .= "server {$dnsupdate['server']}\n";
2196

    
2197
				if (file_exists($cacheFile)) {
2198
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2199
				}
2200
				if (file_exists("{$cacheFile}.ipv6")) {
2201
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2202
				}
2203

    
2204
				// 25 Days
2205
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2206
				$need_update = false;
2207

    
2208
				conf_mount_rw();
2209
				/* Update IPv4 if we have it. */
2210
				if (is_ipaddrv4($wanip)) {
2211
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2212
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2213
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2214
						$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";
2215
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2216
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2217
						$need_update = true;
2218
					} else {
2219
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2220
					}
2221
				} else
2222
					@unlink($cacheFile);
2223

    
2224
				/* Update IPv6 if we have it. */
2225
				if (is_ipaddrv6($wanipv6)) {
2226
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2227
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2228
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2229
						$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";
2230
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2231
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2232
						$need_update = true;
2233
					} else {
2234
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2235
					}
2236
				} else
2237
					@unlink("{$cacheFile}.ipv6");
2238
				conf_mount_ro();
2239

    
2240
				$upinst .= "\n";	/* mind that trailing newline! */
2241

    
2242
				if ($need_update) {
2243
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2244
					unset($upinst);
2245
					/* invoke nsupdate */
2246
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2247
					if (isset($dnsupdate['usetcp']))
2248
						$cmd .= " -v";
2249
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2250
					mwexec_bg($cmd);
2251
					unset($cmd);
2252
				}
2253
			}
2254
		}
2255
		if (!empty($notify_text)) {
2256
			notify_all_remote($notify_text);
2257
		}
2258
	}
2259

    
2260
	return 0;
2261
}
2262

    
2263
/* configure cron service */
2264
function configure_cron() {
2265
	global $g, $config;
2266

    
2267
	conf_mount_rw();
2268
	/* preserve existing crontab entries */
2269
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2270

    
2271
	for ($i = 0; $i < count($crontab_contents); $i++) {
2272
		$cron_item =& $crontab_contents[$i];
2273
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2274
			array_splice($crontab_contents, $i - 1);
2275
			break;
2276
		}
2277
	}
2278
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2279

    
2280

    
2281
	if (is_array($config['cron']['item'])) {
2282
		$crontab_contents .= "#\n";
2283
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2284
		$crontab_contents .= "# " .gettext( "Created:") . " " . date("F j, Y, g:i a") . "\n";
2285
		$crontab_contents .= "#\n";
2286

    
2287
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2288
			$http_proxy = $config['system']['proxyurl'];
2289
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport']))
2290
				$http_proxy .= ':' . $config['system']['proxyport'];
2291
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2292
		}
2293

    
2294
		foreach ($config['cron']['item'] as $item) {
2295
			$crontab_contents .= "\n{$item['minute']}\t";
2296
			$crontab_contents .= "{$item['hour']}\t";
2297
			$crontab_contents .= "{$item['mday']}\t";
2298
			$crontab_contents .= "{$item['month']}\t";
2299
			$crontab_contents .= "{$item['wday']}\t";
2300
			$crontab_contents .= "{$item['who']}\t";
2301
			$crontab_contents .= "{$item['command']}";
2302
		}
2303

    
2304
		$crontab_contents .= "\n#\n";
2305
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2306
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2307
		$crontab_contents .= "#\n\n";
2308
	}
2309

    
2310
	/* please maintain the newline at the end of file */
2311
	file_put_contents("/etc/crontab", $crontab_contents);
2312
	unset($crontab_contents);
2313

    
2314
	/* make sure that cron is running and start it if it got killed somehow */
2315
	if (!is_process_running("cron")) {
2316
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2317
	} else {
2318
	/* do a HUP kill to force sync changes */
2319
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2320
	}
2321

    
2322
	conf_mount_ro();
2323
}
2324

    
2325
function upnp_action ($action) {
2326
	global $g, $config;
2327
	switch($action) {
2328
		case "start":
2329
			if (file_exists('/var/etc/miniupnpd.conf')) {
2330
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2331
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2332
			}
2333
			break;
2334
		case "stop":
2335
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2336
			while((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0)
2337
				mwexec('killall miniupnpd 2>/dev/null', true);
2338
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2339
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2340
			break;
2341
		case "restart":
2342
			upnp_action('stop');
2343
			upnp_action('start');
2344
			break;
2345
	}
2346
}
2347

    
2348
function upnp_start() {
2349
	global $config;
2350

    
2351
	if(!isset($config['installedpackages']['miniupnpd']['config']))
2352
		return;
2353

    
2354
	if($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2355
		echo gettext("Starting UPnP service... ");
2356
		require_once('/usr/local/pkg/miniupnpd.inc');
2357
		sync_package_miniupnpd();
2358
		echo "done.\n";
2359
	}
2360
}
2361

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

    
2365
	$is_installed = false;
2366
	$cron_changed = true;
2367

    
2368
	if (!is_array($config['cron']))
2369
		$config['cron'] = array();
2370
	if (!is_array($config['cron']['item']))
2371
		$config['cron']['item'] = array();
2372

    
2373
	$x=0;
2374
	foreach($config['cron']['item'] as $item) {
2375
		if(strstr($item['command'], $command)) {
2376
			$is_installed = true;
2377
			break;
2378
		}
2379
		$x++;
2380
	}
2381

    
2382
	if($active) {
2383
		$cron_item = array();
2384
		$cron_item['minute'] = $minute;
2385
		$cron_item['hour'] = $hour;
2386
		$cron_item['mday'] = $monthday;
2387
		$cron_item['month'] = $month;
2388
		$cron_item['wday'] = $weekday;
2389
		$cron_item['who'] = $who;
2390
		$cron_item['command'] = $command;
2391
		if(!$is_installed) {
2392
			$config['cron']['item'][] = $cron_item;
2393
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2394
		} else {
2395
			if ($config['cron']['item'][$x] == $cron_item) {
2396
				$cron_changed = false;
2397
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2398
			} else {
2399
				$config['cron']['item'][$x] = $cron_item;
2400
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2401
			}
2402
		}
2403
	} else {
2404
		if($is_installed == true) {
2405
			unset($config['cron']['item'][$x]);
2406
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2407
		}
2408
	}
2409

    
2410
	if ($cron_changed)
2411
		configure_cron();
2412
}
2413

    
2414
?>
(50-50/68)