Project

General

Profile

Download (79.2 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 dhs dnsexit dnsimple dnsomatic dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns glesys 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),DHS,DNSexit,DNSimple,DNS-O-Matic,DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,GleSYS,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

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

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

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

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

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

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

    
79
		/* Do not put in the config an interface which is down */
80
		if (isset($blacklist[$dhcpv6if])) {
81
			continue;
82
		}
83
		if (!isset($dhcpv6ifconf['ramode'])) {
84
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
85
		}
86

    
87
		/* are router advertisements enabled? */
88
		if ($dhcpv6ifconf['ramode'] == "disabled") {
89
			continue;
90
		}
91

    
92
		if (!isset($dhcpv6ifconf['rapriority'])) {
93
			$dhcpv6ifconf['rapriority'] = "medium";
94
		}
95

    
96
		/* always start with the real parent, we override with the carp if later */
97
		$carpif = false;
98
		/* check if we need to listen on a CARP interface */
99
		if (!empty($dhcpv6ifconf['rainterface'])) {
100
			if (!empty($carplist[$dhcpv6ifconf['rainterface']])) {
101
				$dhcpv6if = $dhcpv6ifconf['rainterface'];
102
				$carpif = true;
103
			}
104
		}
105

    
106
		if (strstr($dhcpv6if, "_vip")) {
107
			// CARP IP, check if it's enabled and find parent
108
			if (!get_carp_status() || get_carp_interface_status($dhcpv6if) != "MASTER") {
109
				continue;
110
			}
111
			$ifparent = link_carp_interface_to_parent($dhcpv6if);
112
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
113
		} else {
114
			$realif = get_real_interface($dhcpv6if, "inet6");
115
		}
116

    
117
		if (isset($radvdifs[$realif])) {
118
			continue;
119
		}
120

    
121
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
122
		if (!is_ipaddrv6($ifcfgipv6)) {
123
			continue;
124
		}
125

    
126
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
127
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
128
		$radvdifs[$realif] = $realif;
129

    
130
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
131
		$radvdconf .= "interface {$realif} {\n";
132
		$radvdconf .= "\tAdvSendAdvert on;\n";
133
		$radvdconf .= "\tMinRtrAdvInterval 5;\n";
134
		$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
135
		$mtu = get_interface_mtu($realif);
136
		if (is_numeric($mtu)) {
137
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
138
		} else {
139
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
140
		}
141
		// $radvdconf .= "\tDeprecatePrefix on;\n";
142
		switch ($dhcpv6ifconf['rapriority']) {
143
			case "low":
144
				$radvdconf .= "\tAdvDefaultPreference low;\n";
145
				break;
146
			case "high":
147
				$radvdconf .= "\tAdvDefaultPreference high;\n";
148
				break;
149
			default:
150
				$radvdconf .= "\tAdvDefaultPreference medium;\n";
151
				break;
152
		}
153
		switch ($dhcpv6ifconf['ramode']) {
154
			case "managed":
155
			case "assist":
156
				$radvdconf .= "\tAdvManagedFlag on;\n";
157
				$radvdconf .= "\tAdvOtherConfigFlag on;\n";
158
				break;
159
		}
160
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
161
		if ($carpif == true) {
162
			$radvdconf .= "\t\tDeprecatePrefix off;\n";
163
		} else {
164
			$radvdconf .= "\t\tDeprecatePrefix on;\n";
165
		}
166
		switch ($dhcpv6ifconf['ramode']) {
167
			case "managed":
168
				$radvdconf .= "\t\tAdvOnLink on;\n";
169
				$radvdconf .= "\t\tAdvAutonomous off;\n";
170
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
171
				break;
172
			case "router":
173
				$radvdconf .= "\t\tAdvOnLink off;\n";
174
				$radvdconf .= "\t\tAdvAutonomous off;\n";
175
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
176
				break;
177
			case "assist":
178
				$radvdconf .= "\t\tAdvOnLink on;\n";
179
				$radvdconf .= "\t\tAdvAutonomous on;\n";
180
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
181
				break;
182
			case "unmanaged":
183
				$radvdconf .= "\t\tAdvOnLink on;\n";
184
				$radvdconf .= "\t\tAdvAutonomous on;\n";
185
				$radvdconf .= "\t\tAdvRouterAddr on;\n";
186
				break;
187
		}
188
		$radvdconf .= "\t};\n";
189

    
190
		if ($carpif === true) {
191
			$radvdconf .= "\troute ::/0 {\n";
192
			$radvdconf .= "\t\tRemoveRoute off;\n";
193
			$radvdconf .= "\t};\n";
194
		} else {
195
			$radvdconf .= "\troute ::/0 {\n";
196
			$radvdconf .= "\t\tRemoveRoute on;\n";
197
			$radvdconf .= "\t};\n";
198
		}
199

    
200
		/* add DNS servers */
201
		$dnslist = array();
202
		if (isset($dhcpv6ifconf['rasamednsasdhcp6']) && is_array($dhcpv6ifconf['dnsserver']) && !empty($dhcpv6ifconf['dnsserver'])) {
203
			foreach ($dhcpv6ifconf['dnsserver'] as $server) {
204
				if (is_ipaddrv6($server)) {
205
					$dnslist[] = $server;
206
				}
207
			}
208
		} elseif (!isset($dhcpv6ifconf['rasamednsasdhcp6']) && isset($dhcpv6ifconf['radnsserver']) && is_array($dhcpv6ifconf['radnsserver'])) {
209
			foreach ($dhcpv6ifconf['radnsserver'] as $server) {
210
				if (is_ipaddrv6($server)) {
211
					$dnslist[] = $server;
212
				}
213
			}
214
		} elseif (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
215
			$dnslist[] = get_interface_ipv6($realif);
216
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
217
			foreach ($config['system']['dnsserver'] as $server) {
218
				if (is_ipaddrv6($server)) {
219
					$dnslist[] = $server;
220
				}
221
			}
222
		}
223
		if (count($dnslist) > 0) {
224
			$dnsstring = implode(" ", $dnslist);
225
			if ($dnsstring <> "") {
226
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
227
			}
228
		}
229
		if (!empty($dhcpv6ifconf['domain'])) {
230
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} { };\n";
231
		} elseif (!empty($config['system']['domain'])) {
232
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
233
		}
234
		$radvdconf .= "};\n";
235
	}
236

    
237
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
238
	foreach ($Iflist as $if => $ifdescr) {
239
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
240
			continue;
241
		}
242
		if (!isset($config['interfaces'][$if]['enable'])) {
243
			continue;
244
		}
245
		/* Do not put in the config an interface which is down */
246
		if (isset($blacklist[$if])) {
247
			continue;
248
		}
249
		$trackif = $config['interfaces'][$if]['track6-interface'];
250
		if (empty($config['interfaces'][$trackif])) {
251
			continue;
252
		}
253

    
254
		if (strstr($if, "_vip")) {
255
			// CARP IP, find parent
256
			$ifparent = link_carp_interface_to_parent($if);
257
			$realif = convert_friendly_interface_to_real_interface_name($ifparent);
258
		} else {
259
			$realif = get_real_interface($if, "inet6");
260
		}
261

    
262
		/* prevent duplicate entries, manual overrides */
263
		if (isset($radvdifs[$realif])) {
264
			continue;
265
		}
266

    
267
		$ifcfgipv6 = get_interface_ipv6($if);
268
		if (!is_ipaddrv6($ifcfgipv6)) {
269
			$subnetv6 = "::";
270
			$ifcfgsnv6 = "64";
271
		} else {
272
			$ifcfgsnv6 = get_interface_subnetv6($if);
273
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
274
		}
275
		$radvdifs[$realif] = $realif;
276

    
277
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
278

    
279
		if ($g['debug']) {
280
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
281
		}
282

    
283
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
284
		$radvdconf .= "interface {$realif} {\n";
285
		$radvdconf .= "\tAdvSendAdvert on;\n";
286
		$radvdconf .= "\tMinRtrAdvInterval 3;\n";
287
		$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
288
		$mtu = get_interface_mtu($realif);
289
		if (is_numeric($mtu)) {
290
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
291
		} else {
292
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
293
		}
294
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
295
		$radvdconf .= "\t\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
296
		$radvdconf .= "\t\tAdvOnLink on;\n";
297
		$radvdconf .= "\t\tAdvAutonomous on;\n";
298
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
299
		$radvdconf .= "\t};\n";
300

    
301
		/* add DNS servers */
302
		$dnslist = array();
303
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
304
			$dnslist[] = $ifcfgipv6;
305
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
306
			foreach ($config['system']['dnsserver'] as $server) {
307
				if (is_ipaddrv6($server)) {
308
					$dnslist[] = $server;
309
				}
310
			}
311
		}
312
		if (count($dnslist) > 0) {
313
			$dnsstring = implode(" ", $dnslist);
314
			if (!empty($dnsstring)) {
315
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
316
			}
317
		}
318
		if (!empty($config['system']['domain'])) {
319
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
320
		}
321
		$radvdconf .= "};\n";
322
	}
323

    
324
	/* write radvd.conf */
325
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
326
		log_error("Error: cannot open radvd.conf in services_radvd_configure().\n");
327
		if (platform_booting()) {
328
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
329
		}
330
	}
331
	unset($radvdconf);
332

    
333
	if (count($radvdifs) > 0) {
334
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
335
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
336
		} else {
337
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
338
		}
339
	} else {
340
		/* we need to shut down the radvd cleanly, it will send out the prefix
341
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
342
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
343
			log_error("Shutting down Router Advertisment daemon cleanly");
344
			killbypid("{$g['varrun_path']}/radvd.pid");
345
			@unlink("{$g['varrun_path']}/radvd.pid");
346
		}
347
	}
348
	return 0;
349
}
350

    
351
function services_dhcpd_configure($family = "all", $blacklist = array()) {
352
	global $config, $g;
353

    
354
	/* configure DHCPD chroot once */
355
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh","w");
356
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
357
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
358
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
359
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
360
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
361
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
362
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
363
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
364
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
365
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
366
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
367
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
368
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
369

    
370
	$status = `/sbin/mount | /usr/bin/grep -v grep  | /usr/bin/grep  "{$g['dhcpd_chroot_path']}/dev"`;
371
	if (!trim($status)) {
372
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
373
	}
374
	fclose($fd);
375
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
376

    
377
	if ($family == "all" || $family == "inet") {
378
		services_dhcpdv4_configure();
379
	}
380
	if ($family == "all" || $family == "inet6") {
381
		services_dhcpdv6_configure($blacklist);
382
		services_radvd_configure($blacklist);
383
	}
384
}
385

    
386
function services_dhcpdv4_configure() {
387
	global $config, $g;
388
	$need_ddns_updates = false;
389
	$ddns_zones = array();
390

    
391
	if ($g['services_dhcp_server_enable'] == false) {
392
		return;
393
	}
394

    
395
	if (isset($config['system']['developerspew'])) {
396
		$mt = microtime();
397
		echo "services_dhcpdv4_configure($if) being called $mt\n";
398
	}
399

    
400
	/* kill any running dhcpd */
401
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
402
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
403
	}
404

    
405
	/* DHCP enabled on any interfaces? */
406
	if (!is_dhcp_server_enabled()) {
407
		return 0;
408
	}
409

    
410
	/* if OLSRD is enabled, allow WAN to house DHCP. */
411
	if (!function_exists('is_package_installed')) {
412
		require_once('pkg-utils.inc');
413
	}
414
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) {
415
		foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
416
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
417
				$is_olsr_enabled = true;
418
				break;
419
			}
420
		}
421
	}
422

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

    
440
	$syscfg = $config['system'];
441
	if (!is_array($config['dhcpd'])) {
442
		$config['dhcpd'] = array();
443
	}
444
	$dhcpdcfg = $config['dhcpd'];
445
	$Iflist = get_configured_interface_list();
446

    
447
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
448
	$dns_arrv4 = array();
449
	if (is_array($syscfg['dnsserver'])) {
450
		foreach ($syscfg['dnsserver'] as $dnsserver) {
451
			if (is_ipaddrv4($dnsserver)) {
452
				$dns_arrv4[] = $dnsserver;
453
			}
454
		}
455
	}
456

    
457
	if (platform_booting()) {
458
		echo gettext("Starting DHCP service...");
459
	} else {
460
		sleep(1);
461
	}
462

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

    
477
	$dhcpdconf = <<<EOD
478

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

    
492
EOD;
493

    
494
	if (!isset($dhcpifconf['disableauthoritative'])) {
495
		$dhcpdconf .= "authoritative;\n";
496
	}
497

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

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

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

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

    
523
		interfaces_staticarp_configure($dhcpif);
524

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

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

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

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

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

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

    
596
		if (!is_ipaddr($subnet)) {
597
			continue;
598
		}
599

    
600
		if ($is_olsr_enabled == true) {
601
			if ($dhcpifconf['netmask']) {
602
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
603
			}
604
		}
605

    
606
		$all_pools = array();
607
		$all_pools[] = $dhcpifconf;
608
		if (is_array($dhcpifconf['pool'])) {
609
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
610
		}
611

    
612
		$dnscfg = "";
613

    
614
		if ($dhcpifconf['domain']) {
615
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
616
		}
617

    
618
		if ($dhcpifconf['domainsearchlist'] <> "") {
619
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
620
		}
621

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

    
642
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
643
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
644
			if ($newzone['domain-name']) {
645
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
646
			}
647
		} else if (isset($config['dnsmasq']['enable'])) {
648
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
649
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
650
				$newzone['dns-servers'] = $syscfg['dnsserver'];
651
			}
652
		} else if (isset($config['unbound']['enable'])) {
653
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
654
		} else if (!empty($dns_arrv4)) {
655
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
656
			if ($newzone['domain-name']) {
657
				$newzone['dns-servers'] = $dns_arrv4;
658
			}
659
		}
660

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

    
683
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
684

    
685
		// Setup pool options
686
		foreach ($all_pools as $poolconf) {
687
			$dhcpdconf .= "	pool {\n";
688
			/* is failover dns setup? */
689
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
690
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
691
				if ($poolconf['dnsserver'][1] <> "") {
692
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
693
				}
694
				if ($poolconf['dnsserver'][2] <> "") {
695
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
696
				}
697
				if ($poolconf['dnsserver'][3] <> "") {
698
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
699
				}
700
				$dhcpdconf .= ";\n";
701
			}
702

    
703
			/* allow/deny MACs */
704
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
705
			foreach ($mac_allow_list as $mac) {
706
				if (empty($mac)) {
707
					continue;
708
				}
709
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
710
			}
711
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
712
			foreach ($mac_deny_list as $mac) {
713
				if (empty($mac)) {
714
					continue;
715
				}
716
				$dhcpdconf .= "		deny members of \"" . str_replace(':', '', $mac) . "\";\n";
717
			}
718

    
719
			if ($poolconf['failover_peerip'] <> "") {
720
				$dhcpdconf .= "		deny dynamic bootp clients;\n";
721
			}
722

    
723
			if (isset($poolconf['denyunknown'])) {
724
			   $dhcpdconf .= "		deny unknown-clients;\n";
725
			}
726

    
727
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
728
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
729
			}
730

    
731
			if ($dhcpifconf['failover_peerip'] <> "") {
732
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
733
			}
734

    
735
			$pdnscfg = "";
736

    
737
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
738
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
739
			}
740

    
741
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
742
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
743
			}
744

    
745
			if (isset($poolconf['ddnsupdate'])) {
746
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
747
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
748
				}
749
				$pdnscfg .= "		ddns-update-style interim;\n";
750
			}
751

    
752
			if (is_array($poolconf['dnsserver']) && ($poolconf['dnsserver'][0]) && ($poolconf['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
753
				$pdnscfg .= "		option domain-name-servers " . join(",", $poolconf['dnsserver']) . ";\n";
754
			}
755
			$dhcpdconf .= "{$pdnscfg}";
756

    
757
			// default-lease-time
758
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
759
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
760
			}
761

    
762
			// max-lease-time
763
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
764
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
765
			}
766

    
767
			// netbios-name*
768
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
769
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
770
				$dhcpdconf .= "		option netbios-node-type 8;\n";
771
			}
772

    
773
			// ntp-servers
774
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
775
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
776
			}
777

    
778
			// tftp-server-name
779
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
780
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
781
			}
782

    
783
			// ldap-server
784
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
785
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
786
			}
787

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

    
805
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
806
			$routers = $dhcpifconf['gateway'];
807
			$add_routers = true;
808
		} elseif ($dhcpifconf['gateway'] == "none") {
809
			$add_routers = false;
810
		} else {
811
			$add_routers = $enable_add_routers;
812
			$routers = $ifcfgip;
813
		}
814
		if ($add_routers) {
815
			$dhcpdconf .= "	option routers {$routers};\n";
816
		}
817

    
818
		$dhcpdconf .= <<<EOD
819
$dnscfg
820

    
821
EOD;
822
		// default-lease-time
823
		if ($dhcpifconf['defaultleasetime']) {
824
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
825
		}
826

    
827
		// max-lease-time
828
		if ($dhcpifconf['maxleasetime']) {
829
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
830
		}
831

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

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

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

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

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

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

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

    
889
EOD;
890

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

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

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

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

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

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

    
919
				if ($sm['rootpath']) {
920
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
921
				}
922

    
923
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
924
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
925
				}
926

    
927
				$smdnscfg = "";
928

    
929
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
930
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
931
				}
932

    
933
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
934
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
935
				}
936

    
937
				if (isset($sm['ddnsupdate'])) {
938
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
939
						$pdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
940
					}
941
					$pdnscfg .= "		ddns-update-style interim;\n";
942
				}
943

    
944
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
945
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
946
				}
947
				$dhcpdconf .= "{$smdnscfg}";
948

    
949
				// default-lease-time
950
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
951
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
952
				}
953

    
954
				// max-lease-time
955
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
956
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
957
				}
958

    
959
				// netbios-name*
960
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
961
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
962
					$dhcpdconf .= "	option netbios-node-type 8;\n";
963
				}
964

    
965
				// ntp-servers
966
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
967
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
968
				}
969

    
970
				// tftp-server-name
971
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
972
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
973
				}
974

    
975
				$dhcpdconf .= "}\n";
976
				$i++;
977
			}
978
		}
979

    
980
		$dhcpdifs[] = get_real_interface($dhcpif);
981
		if ($newzone['domain-name']) {
982
			if ($need_ddns_updates) {
983
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
984
			}
985
			$ddns_zones[] = $newzone;
986
		}
987
	}
988

    
989
	if ($need_ddns_updates) {
990
		$dhcpdconf .= "ddns-update-style interim;\n";
991
		$dhcpdconf .= "update-static-leases on;\n";
992

    
993
		$dhcpdconf .= dhcpdkey($dhcpifconf);
994
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
995
	}
996

    
997
	/* write dhcpd.conf */
998
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
999
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1000
		unset($dhcpdconf);
1001
		return 1;
1002
	}
1003
	unset($dhcpdconf);
1004

    
1005
	/* create an empty leases database */
1006
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1007
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1008
	}
1009

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

    
1014
	/* fire up dhcpd in a chroot */
1015
	if (count($dhcpdifs) > 0) {
1016
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1017
			join(" ", $dhcpdifs));
1018
	}
1019

    
1020
	if (platform_booting()) {
1021
		print "done.\n";
1022
	}
1023

    
1024
	return 0;
1025
}
1026

    
1027
function dhcpdkey($dhcpifconf)
1028
{
1029
	$dhcpdconf = "";
1030
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1031
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1032
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1033
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1034
		$dhcpdconf .= "}\n";
1035
	}
1036

    
1037
	return $dhcpdconf;
1038
}
1039

    
1040
function dhcpdzones($ddns_zones, $dhcpifconf)
1041
{
1042
	$dhcpdconf = "";
1043

    
1044
	if (is_array($ddns_zones)) {
1045
		$added_zones = array();
1046
		foreach ($ddns_zones as $zone) {
1047
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1048
				continue;
1049
			}
1050
			$primary = $zone['dns-servers'][0];
1051
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1052

    
1053
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1054
			if (!is_ipaddrv4($primary)) {
1055
				if (is_ipaddrv4($secondary)) {
1056
					$primary = $secondary;
1057
					$secondary = "";
1058
				} else {
1059
					continue;
1060
				}
1061
			}
1062

    
1063
			// We don't need to add zones multiple times.
1064
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1065
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1066
				$dhcpdconf .= "	primary {$primary};\n";
1067
				if (is_ipaddrv4($secondary)) {
1068
					$dhcpdconf .= "	secondary {$secondary};\n";
1069
				}
1070
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1071
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1072
				}
1073
				$dhcpdconf .= "}\n";
1074
				$added_zones[] = $zone['domain-name'];
1075
			}
1076
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1077
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1078
				$dhcpdconf .= "	primary {$primary};\n";
1079
				if (is_ipaddrv4($secondary)) {
1080
					$dhcpdconf .= "	secondary {$secondary};\n";
1081
				}
1082
				if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1083
					$dhcpdconf .= "	key {$dhcpifconf['ddnsdomainkeyname']};\n";
1084
				}
1085
				$dhcpdconf .= "}\n";
1086
				$added_zones[] = $zone['ptr-domain'];
1087
			}
1088
		}
1089
	}
1090

    
1091
	return $dhcpdconf;
1092
}
1093

    
1094
function services_dhcpdv6_configure($blacklist = array()) {
1095
	global $config, $g;
1096

    
1097
	if ($g['services_dhcp_server_enable'] == false) {
1098
		return;
1099
	}
1100

    
1101
	if (isset($config['system']['developerspew'])) {
1102
		$mt = microtime();
1103
		echo "services_dhcpd_configure($if) being called $mt\n";
1104
	}
1105

    
1106
	/* kill any running dhcpd */
1107
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1108
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1109
	}
1110
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1111
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1112
	}
1113

    
1114
	/* DHCP enabled on any interfaces? */
1115
	if (!is_dhcpv6_server_enabled()) {
1116
		return 0;
1117
	}
1118

    
1119
	if (platform_booting()) {
1120
		if ($g['platform'] != "pfSense") {
1121
			/* restore the leases, if we have them */
1122
			if (file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1123
				$dhcprestore = "";
1124
				$dhcpreturn = "";
1125
				exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1", $dhcprestore, $dhcpreturn);
1126
				$dhcprestore = implode(" ", $dhcprestore);
1127
				if ($dhcpreturn <> 0) {
1128
					log_error("DHCP leases v6 restore failed exited with $dhcpreturn, the error is: $dhcprestore\n");
1129
				}
1130
			}
1131
		}
1132
	}
1133

    
1134
	$syscfg = $config['system'];
1135
	if (!is_array($config['dhcpdv6'])) {
1136
		$config['dhcpdv6'] = array();
1137
	}
1138
	$dhcpdv6cfg = $config['dhcpdv6'];
1139
	$Iflist = get_configured_interface_list();
1140
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1141

    
1142

    
1143
	if (platform_booting()) {
1144
		echo "Starting DHCPv6 service...";
1145
	} else {
1146
		sleep(1);
1147
	}
1148

    
1149
	/* we add a fake entry for interfaces that are set to track6 another WAN */
1150
	foreach ($Iflist as $ifname) {
1151
		/* Do not put in the config an interface which is down */
1152
		if (isset($blacklist[$ifname])) {
1153
			continue;
1154
		}
1155
		if (!empty($config['interfaces'][$ifname]['track6-interface'])) {
1156
			$realif = get_real_interface($ifname, "inet6");
1157
			$ifcfgipv6 = get_interface_ipv6($ifname);
1158
			if (!is_ipaddrv6($ifcfgipv6)) {
1159
				continue;
1160
			}
1161
			$ifcfgipv6 = Net_IPv6::getNetmask($ifcfgipv6, 64);
1162
			$trackifname = $config['interfaces'][$ifname]['track6-interface'];
1163
			$trackcfg = $config['interfaces'][$trackifname];
1164
			$pdlen = calculate_ipv6_delegation_length($trackifname);
1165
			$ifcfgipv6arr =explode(":", $ifcfgipv6);
1166
			$dhcpdv6cfg[$ifname] = array();
1167
			$dhcpdv6cfg[$ifname]['enable'] = true;
1168
			/* range */
1169
			$ifcfgipv6arr[7] = "1000";
1170
			$dhcpdv6cfg[$ifname]['range'] = array();
1171
			$dhcpdv6cfg[$ifname]['range']['from'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1172
			$ifcfgipv6arr[7] = "2000";
1173
			$dhcpdv6cfg[$ifname]['range']['to'] = Net_IPv6::compress(implode(":", $ifcfgipv6arr));
1174
			/* prefix length > 0? We can add dhcp6 prefix delegation server */
1175
			if ($pdlen > 2) {
1176
				$pdlenmax = $pdlen;
1177
				$pdlenhalf = $pdlenmax -1;
1178
				$pdlenmin = (64 - ceil($pdlenhalf / 4));
1179
				$dhcpdv6cfg[$ifname]['prefixrange'] = array();
1180
				$dhcpdv6cfg[$ifname]['prefixrange']['prefixlength'] = $pdlenmin;
1181

    
1182
				/* set the delegation start to half the current address block */
1183
				$range = Net_IPv6::parseAddress($ifcfgipv6, (64 - $pdlenmax));
1184
				$range['start'] = Net_IPv6::getNetmask($range['end'], (64 - $pdlenhalf));
1185

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

    
1190
				$dhcpdv6cfg[$ifname]['prefixrange']['from'] = Net_IPv6::compress($range['start']);
1191
				$dhcpdv6cfg[$ifname]['prefixrange']['to'] = Net_IPv6::compress($range['end']);
1192
			}
1193
			$dhcpdv6cfg[$ifname]['dns6ip'] = get_interface_ipv6($ifname);
1194
		}
1195
	}
1196

    
1197
	$custoptionsv6 = "";
1198
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1199
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1200
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1201
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1202
			}
1203
		}
1204
	}
1205

    
1206
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1207
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1208
	}
1209

    
1210
	$dhcpdv6conf = <<<EOD
1211

    
1212
option domain-name "{$syscfg['domain']}";
1213
option ldap-server code 95 = text;
1214
option domain-search-list code 119 = text;
1215
{$custoptionsv6}
1216
default-lease-time 7200;
1217
max-lease-time 86400;
1218
log-facility local7;
1219
one-lease-per-client true;
1220
deny duplicates;
1221
ping-check true;
1222
update-conflict-detection false;
1223

    
1224
EOD;
1225

    
1226
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1227
		$dhcpdv6conf .= "authoritative;\n";
1228
	}
1229

    
1230
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1231
		$dhcpdv6conf .= "always-broadcast on\n";
1232
	}
1233

    
1234
	$dhcpdv6ifs = array();
1235

    
1236
	$dhcpv6num = 0;
1237
	$nsupdate = false;
1238

    
1239
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1240

    
1241
		$ddns_zones = array();
1242

    
1243
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1244

    
1245
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1246
			continue;
1247
		}
1248
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1249
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1250
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1251

    
1252
		if ($is_olsr_enabled == true) {
1253
			if ($dhcpv6ifconf['netmask']) {
1254
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1255
			}
1256
		}
1257

    
1258
		$dnscfgv6 = "";
1259

    
1260
		if ($dhcpv6ifconf['domain']) {
1261
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1262
		}
1263

    
1264
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1265
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1266
		}
1267

    
1268
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1269
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1270
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1271
			}
1272
			$dnscfgv6 .= "	ddns-update-style interim;\n";
1273
			$nsupdate = true;
1274
		}
1275

    
1276
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1277
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1278
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1279
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1280
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1281
			$dns_arrv6 = array();
1282
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1283
				if (is_ipaddrv6($dnsserver)) {
1284
					$dns_arrv6[] = $dnsserver;
1285
				}
1286
			}
1287
			if (!empty($dns_arrv6)) {
1288
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1289
			}
1290
		}
1291

    
1292
		if ($dhcpv6ifconf['domain']) {
1293
			$newzone = array();
1294
			$newzone['domain-name'] = $dhcpv6ifconf['domain'];
1295
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1296
			$ddns_zones[] = $newzone;
1297
		}
1298

    
1299
		if (is_ipaddrv6($ifcfgipv6)) {
1300
			$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1301
		} else {
1302
			$subnet6 = gen_subnetv6($dhcpv6ifconf['range']['from'], "64");
1303
			$dhcpdv6conf .= "subnet6 {$subnet6}/64";
1304
		}
1305
		$dhcpdv6conf .= " {\n";
1306

    
1307
		$dhcpdv6conf .= <<<EOD
1308
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1309
$dnscfgv6
1310

    
1311
EOD;
1312

    
1313
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1314
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1315
		}
1316
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1317
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dhcpv6ifconf['dns6ip']};\n";
1318
		}
1319
		// default-lease-time
1320
		if ($dhcpv6ifconf['defaultleasetime']) {
1321
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1322
		}
1323

    
1324
		// max-lease-time
1325
		if ($dhcpv6ifconf['maxleasetime']) {
1326
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1327
		}
1328

    
1329
		// ntp-servers
1330
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1331
			$ntpservers = array();
1332
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1333
				if (is_ipaddrv6($ntpserver)) {
1334
					$ntpservers[] = $ntpserver;
1335
				}
1336
			}
1337
			if (count($ntpservers) > 0) {
1338
				$dhcpdv6conf .= "       option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1339
			}
1340
		}
1341
		// tftp-server-name
1342
		/* Needs ISC DHCPD support
1343
		 if ($dhcpv6ifconf['tftp'] <> "") {
1344
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1345
		 }
1346
		*/
1347

    
1348
		// Handle option, number rowhelper values
1349
		$dhcpdv6conf .= "\n";
1350
		if ($dhcpv6ifconf['numberoptions']['item']) {
1351
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1352
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6['value']}\";\n";
1353
			}
1354
		}
1355

    
1356
		// ldap-server
1357
		if ($dhcpv6ifconf['ldap'] <> "") {
1358
			$dhcpdv6conf .= "	option ldap-server \"{$dhcpv6ifconf['ldap']}\";\n";
1359
		}
1360

    
1361
		// net boot information
1362
		if (isset($dhcpv6ifconf['netboot'])) {
1363
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1364
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1365
			}
1366
		}
1367

    
1368
		$dhcpdv6conf .= "}\n";
1369

    
1370
		/* add static mappings */
1371
		/* Needs to use DUID */
1372
		if (is_array($dhcpv6ifconf['staticmap'])) {
1373
			$i = 0;
1374
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1375
				$dhcpdv6conf .= <<<EOD
1376
host s_{$dhcpv6if}_{$i} {
1377
	host-identifier option dhcp6.client-id {$sm['duid']};
1378

    
1379
EOD;
1380
				if ($sm['ipaddrv6']) {
1381
					$dhcpdv6conf .= "	fixed-address6 {$sm['ipaddrv6']};\n";
1382
				}
1383

    
1384
				if ($sm['hostname']) {
1385
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1386
					$dhhostname = str_replace(".", "_", $dhhostname);
1387
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1388
				}
1389
				if ($sm['filename']) {
1390
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1391
				}
1392

    
1393
				if ($sm['rootpath']) {
1394
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1395
				}
1396

    
1397
				$dhcpdv6conf .= "}\n";
1398
				$i++;
1399
			}
1400
		}
1401

    
1402
		if ($dhcpv6ifconf['domain']) {
1403
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1404
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1405
		}
1406

    
1407
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1408
			if (preg_match("/poes/si", $dhcpv6if)) {
1409
				/* magic here */
1410
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1411
			} else {
1412
				$realif = get_real_interface($dhcpv6if, "inet6");
1413
				if (stristr("$realif", "bridge")) {
1414
					$mac = get_interface_mac($realif);
1415
					$v6address = generate_ipv6_from_mac($mac);
1416
					/* Create link local address for bridges */
1417
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1418
				}
1419
				$realif = escapeshellcmd($realif);
1420
				$dhcpdv6ifs[] = $realif;
1421
			}
1422
		}
1423
	}
1424

    
1425
	if ($nsupdate) {
1426
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1427
	} else {
1428
		$dhcpdv6conf .= "ddns-update-style none;\n";
1429
	}
1430

    
1431
	/* write dhcpdv6.conf */
1432
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1433
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1434
		if (platform_booting()) {
1435
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1436
		}
1437
		unset($dhcpdv6conf);
1438
		return 1;
1439
	}
1440
	unset($dhcpdv6conf);
1441

    
1442
	/* create an empty leases v6 database */
1443
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1444
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1445
	}
1446

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

    
1451
	/* fire up dhcpd in a chroot */
1452
	if (count($dhcpdv6ifs) > 0) {
1453
		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 " .
1454
			join(" ", $dhcpdv6ifs));
1455
		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");
1456
	}
1457
	if (platform_booting()) {
1458
		print gettext("done.") . "\n";
1459
	}
1460

    
1461
	return 0;
1462
}
1463

    
1464
function services_igmpproxy_configure() {
1465
	global $config, $g;
1466

    
1467
	/* kill any running igmpproxy */
1468
	killbyname("igmpproxy");
1469

    
1470
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1471
		return 1;
1472
	}
1473

    
1474
	$iflist = get_configured_interface_list();
1475

    
1476
	$igmpconf = <<<EOD
1477

    
1478
##------------------------------------------------------
1479
## Enable Quickleave mode (Sends Leave instantly)
1480
##------------------------------------------------------
1481
quickleave
1482

    
1483
EOD;
1484

    
1485
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1486
		unset($iflist[$igmpcf['ifname']]);
1487
		$realif = get_real_interface($igmpcf['ifname']);
1488
		if (empty($igmpcf['threshold'])) {
1489
			$threshld = 1;
1490
		} else {
1491
			$threshld = $igmpcf['threshold'];
1492
		}
1493
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1494

    
1495
		if ($igmpcf['address'] <> "") {
1496
			$item = explode(" ", $igmpcf['address']);
1497
			foreach ($item as $iww) {
1498
				$igmpconf .= "altnet {$iww}\n";
1499
			}
1500
		}
1501
		$igmpconf .= "\n";
1502
	}
1503
	foreach ($iflist as $ifn) {
1504
		$realif = get_real_interface($ifn);
1505
		$igmpconf .= "phyint {$realif} disabled\n";
1506
	}
1507
	$igmpconf .= "\n";
1508

    
1509
	$igmpfl = fopen($g['tmp_path'] . "/igmpproxy.conf", "w");
1510
	if (!$igmpfl) {
1511
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1512
		return;
1513
	}
1514
	fwrite($igmpfl, $igmpconf);
1515
	fclose($igmpfl);
1516
	unset($igmpconf);
1517

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

    
1522
	return 0;
1523
}
1524

    
1525
function services_dhcrelay_configure() {
1526
	global $config, $g;
1527
	if ($g['platform'] == 'jail') {
1528
		return;
1529
	}
1530
	if (isset($config['system']['developerspew'])) {
1531
		$mt = microtime();
1532
		echo "services_dhcrelay_configure() being called $mt\n";
1533
	}
1534

    
1535
	/* kill any running dhcrelay */
1536
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1537

    
1538
	$dhcrelaycfg =& $config['dhcrelay'];
1539

    
1540
	/* DHCPRelay enabled on any interfaces? */
1541
	if (!isset($dhcrelaycfg['enable'])) {
1542
		return 0;
1543
	}
1544

    
1545
	if (platform_booting()) {
1546
		echo gettext("Starting DHCP relay service...");
1547
	} else {
1548
		sleep(1);
1549
	}
1550

    
1551
	$iflist = get_configured_interface_list();
1552

    
1553
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1554
	foreach ($dhcifaces as $dhcrelayif) {
1555
		if (!isset($iflist[$dhcrelayif]) ||
1556
		    link_interface_to_bridge($dhcrelayif)) {
1557
			continue;
1558
		}
1559

    
1560
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1561
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1562
		}
1563
	}
1564

    
1565
	/*
1566
	 * In order for the relay to work, it needs to be active
1567
	 * on the interface in which the destination server sits.
1568
	 */
1569
	$srvips = explode(",", $dhcrelaycfg['server']);
1570
	foreach ($srvips as $srcidx => $srvip) {
1571
		unset($destif);
1572
		foreach ($iflist as $ifname) {
1573
			$subnet = get_interface_ip($ifname);
1574
			if (!is_ipaddr($subnet)) {
1575
				continue;
1576
			}
1577
			$subnet .=  "/" . get_interface_subnet($ifname);
1578
			if (ip_in_subnet($srvip, $subnet)) {
1579
				$destif = get_real_interface($ifname);
1580
				break;
1581
			}
1582
		}
1583
		if (!isset($destif)) {
1584
			foreach (get_staticroutes() as $rtent) {
1585
				if (ip_in_subnet($srvip, $rtent['network'])) {
1586
					$a_gateways = return_gateways_array(true);
1587
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1588
					break;
1589
				}
1590
			}
1591
		}
1592

    
1593
		if (!isset($destif)) {
1594
			/* Create a array from the existing route table */
1595
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1596
			array_shift($route_str);
1597
			array_shift($route_str);
1598
			array_shift($route_str);
1599
			array_shift($route_str);
1600
			$route_arr = array();
1601
			foreach ($route_str as $routeline) {
1602
				$items = preg_split("/[ ]+/i", $routeline);
1603
				if (is_subnetv4($items[0])) {
1604
					$subnet = $items[0];
1605
				} elseif (is_ipaddrv4($items[0])) {
1606
					$subnet = "{$items[0]}/32";
1607
				} else {
1608
					// Not a subnet or IP address, skip to the next line.
1609
					continue;
1610
				}
1611
				if (ip_in_subnet($srvip, $subnet)) {
1612
					$destif = trim($items[6]);
1613
					break;
1614
				}
1615
			}
1616
		}
1617

    
1618
		if (!isset($destif)) {
1619
			if (is_array($config['gateways']['gateway_item'])) {
1620
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1621
					if (isset($gateway['defaultgw'])) {
1622
						$destif = get_real_interface($gateway['interface']);
1623
						break;
1624
					}
1625
				}
1626
			} else {
1627
				$destif = get_real_interface("wan");
1628
			}
1629
		}
1630

    
1631
		if (!empty($destif)) {
1632
			$dhcrelayifs[] = $destif;
1633
		}
1634
	}
1635
	$dhcrelayifs = array_unique($dhcrelayifs);
1636

    
1637
	/* fire up dhcrelay */
1638
	if (empty($dhcrelayifs)) {
1639
		log_error("No suitable interface found for running dhcrelay!");
1640
		return; /* XXX */
1641
	}
1642

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

    
1645
	if (isset($dhcrelaycfg['agentoption'])) {
1646
		$cmd .=  " -a -m replace";
1647
	}
1648

    
1649
	$cmd .= " " . implode(" ", $srvips);
1650
	mwexec($cmd);
1651
	unset($cmd);
1652

    
1653
	return 0;
1654
}
1655

    
1656
function services_dhcrelay6_configure() {
1657
	global $config, $g;
1658
	if ($g['platform'] == 'jail') {
1659
		return;
1660
	}
1661
	if (isset($config['system']['developerspew'])) {
1662
		$mt = microtime();
1663
		echo "services_dhcrelay6_configure() being called $mt\n";
1664
	}
1665

    
1666
	/* kill any running dhcrelay */
1667
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1668

    
1669
	$dhcrelaycfg =& $config['dhcrelay6'];
1670

    
1671
	/* DHCPv6 Relay enabled on any interfaces? */
1672
	if (!isset($dhcrelaycfg['enable'])) {
1673
		return 0;
1674
	}
1675

    
1676
	if (platform_booting()) {
1677
		echo gettext("Starting DHCPv6 relay service...");
1678
	} else {
1679
		sleep(1);
1680
	}
1681

    
1682
	$iflist = get_configured_interface_list();
1683

    
1684
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1685
	foreach ($dhcifaces as $dhcrelayif) {
1686
		if (!isset($iflist[$dhcrelayif]) ||
1687
		    link_interface_to_bridge($dhcrelayif))
1688
			continue;
1689

    
1690
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1691
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1692
		}
1693
	}
1694
	$dhcrelayifs = array_unique($dhcrelayifs);
1695

    
1696
	/*
1697
	 * In order for the relay to work, it needs to be active
1698
	 * on the interface in which the destination server sits.
1699
	 */
1700
	$srvips = explode(",", $dhcrelaycfg['server']);
1701
	$srvifaces = array();
1702
	foreach ($srvips as $srcidx => $srvip) {
1703
		unset($destif);
1704
		foreach ($iflist as $ifname) {
1705
			$subnet = get_interface_ipv6($ifname);
1706
			if (!is_ipaddrv6($subnet)) {
1707
				continue;
1708
			}
1709
			$subnet .=  "/" . get_interface_subnetv6($ifname);
1710
			if (ip_in_subnet($srvip, $subnet)) {
1711
				$destif = get_real_interface($ifname);
1712
				break;
1713
			}
1714
		}
1715
		if (!isset($destif)) {
1716
			if (is_array($config['staticroutes']['route'])) {
1717
				foreach ($config['staticroutes']['route'] as $rtent) {
1718
					if (ip_in_subnet($srvip, $rtent['network'])) {
1719
						$a_gateways = return_gateways_array(true);
1720
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1721
						break;
1722
					}
1723
				}
1724
			}
1725
		}
1726

    
1727
		if (!isset($destif)) {
1728
			/* Create a array from the existing route table */
1729
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1730
			array_shift($route_str);
1731
			array_shift($route_str);
1732
			array_shift($route_str);
1733
			array_shift($route_str);
1734
			$route_arr = array();
1735
			foreach ($route_str as $routeline) {
1736
				$items = preg_split("/[ ]+/i", $routeline);
1737
				if (ip_in_subnet($srvip, $items[0])) {
1738
					$destif = trim($items[6]);
1739
					break;
1740
				}
1741
			}
1742
		}
1743

    
1744
		if (!isset($destif)) {
1745
			if (is_array($config['gateways']['gateway_item'])) {
1746
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1747
					if (isset($gateway['defaultgw'])) {
1748
						$destif = $gateway['interface'];
1749
						break;
1750
					}
1751
				}
1752
			} else {
1753
				$destif = get_real_interface("wan");
1754
			}
1755
		}
1756

    
1757
		if (!empty($destif)) {
1758
			$srvifaces[] = "{$srvip}%{$destif}";
1759
		}
1760
	}
1761

    
1762
	/* fire up dhcrelay */
1763
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1764
		log_error("No suitable interface found for running dhcrelay -6!");
1765
		return; /* XXX */
1766
	}
1767

    
1768
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1769
	foreach ($dhcrelayifs as $dhcrelayif) {
1770
		$cmd .= " -l {$dhcrelayif}";
1771
	}
1772
	foreach ($srvifaces as $srviface) {
1773
		$cmd .= " -u \"{$srviface}\"";
1774
	}
1775
	mwexec($cmd);
1776
	unset($cmd);
1777

    
1778
	return 0;
1779
}
1780

    
1781
function services_dyndns_configure_client($conf) {
1782

    
1783
	if (!isset($conf['enable'])) {
1784
		return;
1785
	}
1786

    
1787
	/* load up the dyndns.class */
1788
	require_once("dyndns.class");
1789

    
1790
	$dns = new updatedns($dnsService = $conf['type'],
1791
		$dnsHost = $conf['host'],
1792
		$dnsUser = $conf['username'],
1793
		$dnsPass = $conf['password'],
1794
		$dnsWildcard = $conf['wildcard'],
1795
		$dnsMX = $conf['mx'],
1796
		$dnsIf = "{$conf['interface']}",
1797
		$dnsBackMX = NULL,
1798
		$dnsServer = NULL,
1799
		$dnsPort = NULL,
1800
		$dnsUpdateURL = "{$conf['updateurl']}",
1801
		$forceUpdate = $conf['force'],
1802
		$dnsZoneID=$conf['zoneid'],
1803
		$dnsTTL=$conf['ttl'],
1804
		$dnsResultMatch = "{$conf['resultmatch']}",
1805
		$dnsRequestIf = "{$conf['requestif']}",
1806
		$dnsID = "{$conf['id']}",
1807
		$dnsVerboseLog = $conf['verboselog'],
1808
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1809
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1810
}
1811

    
1812
function services_dyndns_configure($int = "") {
1813
	global $config, $g;
1814
	if (isset($config['system']['developerspew'])) {
1815
		$mt = microtime();
1816
		echo "services_dyndns_configure() being called $mt\n";
1817
	}
1818

    
1819
	$dyndnscfg = $config['dyndnses']['dyndns'];
1820
	$gwgroups = return_gateway_groups_array();
1821
	if (is_array($dyndnscfg)) {
1822
		if (platform_booting()) {
1823
			echo gettext("Starting DynDNS clients...");
1824
		}
1825

    
1826
		foreach ($dyndnscfg as $dyndns) {
1827
			if ((empty($int)) || ($int == $dyndns['interface']) || (is_array($gwgroups[$dyndns['interface']]))) {
1828
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
1829
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
1830
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
1831
				services_dyndns_configure_client($dyndns);
1832
				sleep(1);
1833
			}
1834
		}
1835

    
1836
		if (platform_booting()) {
1837
			echo gettext("done.") . "\n";
1838
		}
1839
	}
1840

    
1841
	return 0;
1842
}
1843

    
1844
function dyndnsCheckIP($int) {
1845
	global $config;
1846
	$ip_address = get_interface_ip($int);
1847
	if (is_private_ip($ip_address)) {
1848
		$gateways_status = return_gateways_status(true);
1849
		// If the gateway for this interface is down, then the external check cannot work.
1850
		// Avoid the long wait for the external check to timeout.
1851
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
1852
			return "down";
1853
		}
1854
		$hosttocheck = "http://checkip.dyndns.org";
1855
		$ip_ch = curl_init($hosttocheck);
1856
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
1857
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
1858
		curl_setopt($ip_ch, CURLOPT_INTERFACE, $ip_address);
1859
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
1860
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
1861
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1862
		$ip_result_page = curl_exec($ip_ch);
1863
		curl_close($ip_ch);
1864
		$ip_result_decoded = urldecode($ip_result_page);
1865
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
1866
		$ip_address = trim($matches[1]);
1867
	}
1868
	return $ip_address;
1869
}
1870

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

    
1875
	// hard coded args: will be removed to avoid duplication if specified in custom_options
1876
	$standard_args = array(
1877
		"dns-forward-max" => "--dns-forward-max=5000",
1878
		"cache-size" => "--cache-size=10000",
1879
		"local-ttl" => "--local-ttl=1"
1880
	);
1881

    
1882

    
1883
	if (isset($config['system']['developerspew'])) {
1884
		$mt = microtime();
1885
		echo "services_dnsmasq_configure() being called $mt\n";
1886
	}
1887

    
1888
	/* kill any running dnsmasq */
1889
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
1890
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
1891
	}
1892

    
1893
	if (isset($config['dnsmasq']['enable'])) {
1894

    
1895
		if (platform_booting()) {
1896
			echo gettext("Starting DNS forwarder...");
1897
		} else {
1898
			sleep(1);
1899
		}
1900

    
1901
		/* generate hosts file */
1902
		if (system_hosts_generate()!=0) {
1903
			$return = 1;
1904
		}
1905

    
1906
		$args = "";
1907

    
1908
		if (isset($config['dnsmasq']['regdhcp'])) {
1909
			$args .= " --dhcp-hostsfile={$g['varetc_path']}/hosts ";
1910
		}
1911

    
1912
		/* Setup listen port, if non-default */
1913
		if (is_port($config['dnsmasq']['port'])) {
1914
			$args .= " --port={$config['dnsmasq']['port']} ";
1915
		}
1916

    
1917
		$listen_addresses = "";
1918
		if (isset($config['dnsmasq']['interface'])) {
1919
			$interfaces = explode(",", $config['dnsmasq']['interface']);
1920
			foreach ($interfaces as $interface) {
1921
				if (is_ipaddrv4($interface)) {
1922
					$listen_addresses .= " --listen-address={$interface} ";
1923
				} else if (is_ipaddrv6($interface)) {
1924
					/*
1925
					 * XXX: Since dnsmasq does not support link-local address
1926
					 * with scope specified. These checks are being done.
1927
					 */
1928
					if (is_linklocal($interface) && strstr($interface, "%")) {
1929
						$tmpaddrll6 = explode("%", $interface);
1930
						$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1931
					} else {
1932
						$listen_addresses .= " --listen-address={$interface} ";
1933
					}
1934
				} else if (strstr($interface, "_vip")) {
1935
					$laddr = get_configured_carp_interface_list($interface);
1936
					if (is_ipaddr($laddr)) {
1937
						$listen_addresses .= " --listen-address={$laddr} ";
1938
					}
1939
				} else {
1940
					$if = get_real_interface($interface);
1941
					if (does_interface_exist($if)) {
1942
						$laddr = get_interface_ip($interface);
1943
						if (is_ipaddrv4($laddr)) {
1944
							$listen_addresses .= " --listen-address={$laddr} ";
1945
						}
1946
						$laddr6 = get_interface_ipv6($interface);
1947
						if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
1948
							/*
1949
							 * XXX: Since dnsmasq does not support link-local address
1950
							 * with scope specified. These checks are being done.
1951
							 */
1952
							if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
1953
								$tmpaddrll6 = explode("%", $laddr6);
1954
								$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
1955
							} else {
1956
								$listen_addresses .= " --listen-address={$laddr6} ";
1957
							}
1958
						}
1959
					}
1960
				}
1961
			}
1962
			if (!empty($listen_addresses)) {
1963
				$args .= " {$listen_addresses} ";
1964
				if (isset($config['dnsmasq']['strictbind'])) {
1965
					$args .= " --bind-interfaces ";
1966
				}
1967
			}
1968
		}
1969

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

    
1977
			// Build an array of domain overrides to help in checking for matches.
1978
			$override_a = array();
1979
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
1980
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
1981
					$override_a[$override['domain']] = "y";
1982
				}
1983
			}
1984

    
1985
			// Build an array of the private reverse lookup domain names
1986
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
1987
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
1988
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
1989
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
1990
			}
1991

    
1992
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
1993
			foreach ($reverse_domain_a as $reverse_domain) {
1994
				if (!isset($override_a[$reverse_domain])) {
1995
					$args .= " --server=/$reverse_domain/ ";
1996
				}
1997
			}
1998
			unset($override_a);
1999
			unset($reverse_domain_a);
2000
		}
2001

    
2002
		/* Setup forwarded domains */
2003
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2004
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2005
				if ($override['ip'] == "!") {
2006
					$override[ip] = "";
2007
				}
2008
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2009
			}
2010
		}
2011

    
2012
		/* Allow DNS Rebind for forwarded domains */
2013
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2014
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2015
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2016
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2017
				}
2018
			}
2019
		}
2020

    
2021
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2022
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2023
		}
2024

    
2025
		if (isset($config['dnsmasq']['strict_order'])) {
2026
			$args .= " --strict-order ";
2027
		}
2028

    
2029
		if (isset($config['dnsmasq']['domain_needed'])) {
2030
			$args .= " --domain-needed ";
2031
		}
2032

    
2033
		if ($config['dnsmasq']['custom_options']) {
2034
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2035
				$args .= " " . escapeshellarg("--{$c}");
2036
				$p = explode('=', $c);
2037
				if (array_key_exists($p[0], $standard_args)) {
2038
					unset($standard_args[$p[0]]);
2039
				}
2040
			}
2041
		}
2042
		$args .= ' ' . implode(' ', array_values($standard_args));
2043

    
2044
		/* run dnsmasq */
2045
		$cmd = "/usr/local/sbin/dnsmasq --all-servers {$dns_rebind} {$args}";
2046
		//log_error("dnsmasq command: {$cmd}");
2047
		mwexec_bg($cmd);
2048
		unset($args);
2049

    
2050
		system_dhcpleases_configure();
2051

    
2052
		if (platform_booting()) {
2053
			echo gettext("done.") . "\n";
2054
		}
2055
	}
2056

    
2057
	if (!platform_booting()) {
2058
		if (services_dhcpd_configure()!=0) {
2059
			$return = 1;
2060
		}
2061
	}
2062

    
2063
	return $return;
2064
}
2065

    
2066
function services_unbound_configure() {
2067
	global $config, $g;
2068
	$return = 0;
2069

    
2070
	if (isset($config['system']['developerspew'])) {
2071
		$mt = microtime();
2072
		echo "services_unbound_configure() being called $mt\n";
2073
	}
2074

    
2075
	// kill any running Unbound instance
2076
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2077
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2078
	}
2079

    
2080
	if (isset($config['unbound']['enable'])) {
2081
		if (platform_booting()) {
2082
			echo gettext("Starting DNS Resolver...");
2083
		} else {
2084
			sleep(1);
2085
		}
2086

    
2087
		/* generate hosts file */
2088
		if (system_hosts_generate()!=0) {
2089
			$return = 1;
2090
		}
2091

    
2092
		require_once('/etc/inc/unbound.inc');
2093
		sync_unbound_service();
2094
		if (platform_booting()) {
2095
			echo gettext("done.") . "\n";
2096
		}
2097

    
2098
		system_dhcpleases_configure();
2099
	}
2100

    
2101
	if (!platform_booting()) {
2102
		if (services_dhcpd_configure()!=0) {
2103
			$return = 1;
2104
		}
2105
	}
2106

    
2107
	return $return;
2108
}
2109

    
2110
function services_snmpd_configure() {
2111
	global $config, $g;
2112
	if (isset($config['system']['developerspew'])) {
2113
		$mt = microtime();
2114
		echo "services_snmpd_configure() being called $mt\n";
2115
	}
2116

    
2117
	/* kill any running snmpd */
2118
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2119
	sleep(2);
2120
	if (is_process_running("bsnmpd")) {
2121
		mwexec("/usr/bin/killall bsnmpd", true);
2122
	}
2123

    
2124
	if (isset($config['snmpd']['enable'])) {
2125

    
2126
		if (platform_booting()) {
2127
			echo gettext("Starting SNMP daemon... ");
2128
		}
2129

    
2130
		/* generate snmpd.conf */
2131
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2132
		if (!$fd) {
2133
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"),"\n");
2134
			return 1;
2135
		}
2136

    
2137

    
2138
		$snmpdconf = <<<EOD
2139
location := "{$config['snmpd']['syslocation']}"
2140
contact := "{$config['snmpd']['syscontact']}"
2141
read := "{$config['snmpd']['rocommunity']}"
2142

    
2143
EOD;
2144

    
2145
/* No docs on what write strings do there for disable for now.
2146
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2147
			$snmpdconf .= <<<EOD
2148
# write string
2149
write := "{$config['snmpd']['rwcommunity']}"
2150

    
2151
EOD;
2152
		}
2153
*/
2154

    
2155

    
2156
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2157
			$snmpdconf .= <<<EOD
2158
# SNMP Trap support.
2159
traphost := {$config['snmpd']['trapserver']}
2160
trapport := {$config['snmpd']['trapserverport']}
2161
trap := "{$config['snmpd']['trapstring']}"
2162

    
2163

    
2164
EOD;
2165
		}
2166

    
2167
		$version = trim(file_get_contents('/etc/version'));
2168
		$platform = trim(file_get_contents('/etc/platform'));
2169
		if (($platform == "pfSense") && ($g['product_name'] != "pfSense")) {
2170
			$platform = $g['product_name'];
2171
		}
2172
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2173
			" {$version} {$platform} " . php_uname("s") .
2174
			" " . php_uname("r") . " " . php_uname("m");
2175

    
2176
		$snmpdconf .= <<<EOD
2177
system := 1     # pfSense
2178
%snmpd
2179
sysDescr			= "{$sysDescr}"
2180
begemotSnmpdDebugDumpPdus       = 2
2181
begemotSnmpdDebugSyslogPri      = 7
2182
begemotSnmpdCommunityString.0.1 = $(read)
2183

    
2184
EOD;
2185

    
2186
/* No docs on what write strings do there for disable for now.
2187
		if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2188
			$snmpdconf .= <<<EOD
2189
begemotSnmpdCommunityString.0.2 = $(write)
2190

    
2191
EOD;
2192
		}
2193
*/
2194

    
2195

    
2196
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2197
			$snmpdconf .= <<<EOD
2198
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2199
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2200
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2201

    
2202
EOD;
2203
		}
2204

    
2205

    
2206
		$snmpdconf .= <<<EOD
2207
begemotSnmpdCommunityDisable    = 1
2208

    
2209
EOD;
2210

    
2211
		if (isset($config['snmpd']['bindlan'])) {
2212
			$config['snmpd']['bindip'] = 'lan';
2213
			unset($config['snmpd']['bindlan']);
2214
		}
2215
		$bind_to_ip = "0.0.0.0";
2216
		if (isset($config['snmpd']['bindip'])) {
2217
			if (is_ipaddr($config['snmpd']['bindip'])) {
2218
				$bind_to_ip = $config['snmpd']['bindip'];
2219
			} else {
2220
				$if = get_real_interface($config['snmpd']['bindip']);
2221
				if (does_interface_exist($if)) {
2222
					$bind_to_ip = get_interface_ip($config['snmpd']['bindip']);
2223
				}
2224
			}
2225
		}
2226

    
2227
		if (is_port($config['snmpd']['pollport'])) {
2228
			$snmpdconf .= <<<EOD
2229
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2230

    
2231
EOD;
2232

    
2233
		}
2234

    
2235
		$snmpdconf .= <<<EOD
2236
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2237
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2238

    
2239
# These are bsnmp macros not php vars.
2240
sysContact      = $(contact)
2241
sysLocation     = $(location)
2242
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2243

    
2244
snmpEnableAuthenTraps = 2
2245

    
2246
EOD;
2247

    
2248
		if (is_array($config['snmpd']['modules'])) {
2249
			if (isset($config['snmpd']['modules']['mibii'])) {
2250
			$snmpdconf .= <<<EOD
2251
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2252

    
2253
EOD;
2254
			}
2255

    
2256
			if (isset($config['snmpd']['modules']['netgraph'])) {
2257
				$snmpdconf .= <<<EOD
2258
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2259
%netgraph
2260
begemotNgControlNodeName = "snmpd"
2261

    
2262
EOD;
2263
			}
2264

    
2265
			if (isset($config['snmpd']['modules']['pf'])) {
2266
				$snmpdconf .= <<<EOD
2267
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2268

    
2269
EOD;
2270
			}
2271

    
2272
			if (isset($config['snmpd']['modules']['hostres'])) {
2273
				$snmpdconf .= <<<EOD
2274
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2275

    
2276
EOD;
2277
			}
2278
			if (isset($config['snmpd']['modules']['bridge'])) {
2279
				$snmpdconf .= <<<EOD
2280
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2281
# config must end with blank line
2282

    
2283
EOD;
2284
			}
2285
			if (isset($config['snmpd']['modules']['ucd'])) {
2286
				$snmpdconf .= <<<EOD
2287
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2288

    
2289
EOD;
2290
			}
2291
			if (isset($config['snmpd']['modules']['regex'])) {
2292
				$snmpdconf .= <<<EOD
2293
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2294

    
2295
EOD;
2296
			}
2297
		}
2298

    
2299
		fwrite($fd, $snmpdconf);
2300
		fclose($fd);
2301
		unset($snmpdconf);
2302

    
2303
		if (isset($config['snmpd']['bindlan'])) {
2304
			$bindlan = "";
2305
		}
2306

    
2307
		/* run bsnmpd */
2308
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2309
			"{$bindlan} -p {$g['varrun_path']}/snmpd.pid");
2310

    
2311
		if (platform_booting()) {
2312
			echo gettext("done.") . "\n";
2313
		}
2314
	}
2315

    
2316
	return 0;
2317
}
2318

    
2319
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2320
	global $config, $g;
2321
	if (isset($config['system']['developerspew'])) {
2322
		$mt = microtime();
2323
		echo "services_dnsupdate_process() being called $mt\n";
2324
	}
2325

    
2326
	/* Dynamic DNS updating active? */
2327
	if (is_array($config['dnsupdates']['dnsupdate'])) {
2328
		$notify_text = "";
2329
		foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2330
			if (!isset($dnsupdate['enable'])) {
2331
				continue;
2332
			}
2333
			if (!empty($int) && $int != $dnsupdate['interface']) {
2334
				continue;
2335
			}
2336
			if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2337
				continue;
2338
			}
2339

    
2340
			/* determine interface name */
2341
			$if = get_real_interface($dnsupdate['interface']);
2342

    
2343
			if (isset($dnsupdate['usepublicip'])) {
2344
				$wanip = dyndnsCheckIP($dnsupdate['interface']);
2345
			} else {
2346
				$wanip = get_interface_ip($dnsupdate['interface']);
2347
			}
2348

    
2349
			$wanipv6 = get_interface_ipv6($dnsupdate['interface']);
2350
			$cacheFile = "{$g['conf_path']}/dyndns_{$dnsupdate['interface']}_rfc2136_" . escapeshellarg($dnsupdate['host']) . "_{$dnsupdate['server']}.cache";
2351
			$currentTime = time();
2352

    
2353
			if ($wanip || $wanipv6) {
2354
				$keyname = $dnsupdate['keyname'];
2355
				/* trailing dot */
2356
				if (substr($keyname, -1) != ".") {
2357
					$keyname .= ".";
2358
				}
2359

    
2360
				$hostname = $dnsupdate['host'];
2361
				/* trailing dot */
2362
				if (substr($hostname, -1) != ".") {
2363
					$hostname .= ".";
2364
				}
2365

    
2366
				/* write private key file
2367
				   this is dumb - public and private keys are the same for HMAC-MD5,
2368
				   but nsupdate insists on having both */
2369
				$fd = fopen("{$g['varetc_path']}/K{$i}{$keyname}+157+00000.private", "w");
2370
				$privkey = <<<EOD
2371
Private-key-format: v1.2
2372
Algorithm: 157 (HMAC)
2373
Key: {$dnsupdate['keydata']}
2374

    
2375
EOD;
2376
				fwrite($fd, $privkey);
2377
				fclose($fd);
2378

    
2379
				/* write public key file */
2380
				if ($dnsupdate['keytype'] == "zone") {
2381
					$flags = 257;
2382
					$proto = 3;
2383
				} else if ($dnsupdate['keytype'] == "host") {
2384
					$flags = 513;
2385
					$proto = 3;
2386
				} else if ($dnsupdate['keytype'] == "user") {
2387
					$flags = 0;
2388
					$proto = 2;
2389
				}
2390

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

    
2395
				/* generate update instructions */
2396
				$upinst = "";
2397
				if (!empty($dnsupdate['server'])) {
2398
					$upinst .= "server {$dnsupdate['server']}\n";
2399
				}
2400

    
2401
				if (file_exists($cacheFile)) {
2402
					list($cachedipv4, $cacheTimev4) = explode("|", file_get_contents($cacheFile));
2403
				}
2404
				if (file_exists("{$cacheFile}.ipv6")) {
2405
					list($cachedipv6, $cacheTimev6) = explode("|", file_get_contents("{$cacheFile}.ipv6"));
2406
				}
2407

    
2408
				// 25 Days
2409
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2410
				$need_update = false;
2411

    
2412
				conf_mount_rw();
2413
				/* Update IPv4 if we have it. */
2414
				if (is_ipaddrv4($wanip)) {
2415
					if (($wanip != $cachedipv4) || (($currentTime - $cacheTimev4) > $maxCacheAgeSecs) || $forced) {
2416
						$upinst .= "update delete {$dnsupdate['host']}. A\n";
2417
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} A {$wanip}\n";
2418
						$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";
2419
						@file_put_contents($cacheFile, "{$wanip}|{$currentTime}");
2420
						log_error("phpDynDNS: updating cache file {$cacheFile}: {$wanip}");
2421
						$need_update = true;
2422
					} else {
2423
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} A record because the IP address has not changed.");
2424
					}
2425
				} else {
2426
					@unlink($cacheFile);
2427
				}
2428

    
2429
				/* Update IPv6 if we have it. */
2430
				if (is_ipaddrv6($wanipv6)) {
2431
					if (($wanipv6 != $cachedipv6) || (($currentTime - $cacheTimev6) > $maxCacheAgeSecs) || $forced) {
2432
						$upinst .= "update delete {$dnsupdate['host']}. AAAA\n";
2433
						$upinst .= "update add {$dnsupdate['host']}. {$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2434
						$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";
2435
						@file_put_contents("{$cacheFile}.ipv6", "{$wanipv6}|{$currentTime}");
2436
						log_error("phpDynDNS: updating cache file {$cacheFile}.ipv6: {$wanipv6}");
2437
						$need_update = true;
2438
					} else {
2439
						log_error("phpDynDNS: Not updating {$dnsupdate['host']} AAAA record because the IPv6 address has not changed.");
2440
					}
2441
				} else {
2442
					@unlink("{$cacheFile}.ipv6");
2443
				}
2444
				conf_mount_ro();
2445

    
2446
				$upinst .= "\n";	/* mind that trailing newline! */
2447

    
2448
				if ($need_update) {
2449
					@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}", $upinst);
2450
					unset($upinst);
2451
					/* invoke nsupdate */
2452
					$cmd = "/usr/local/bin/nsupdate -k {$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2453
					if (isset($dnsupdate['usetcp'])) {
2454
						$cmd .= " -v";
2455
					}
2456
					$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2457
					mwexec_bg($cmd);
2458
					unset($cmd);
2459
				}
2460
			}
2461
		}
2462
		if (!empty($notify_text)) {
2463
			notify_all_remote($notify_text);
2464
		}
2465
	}
2466

    
2467
	return 0;
2468
}
2469

    
2470
/* configure cron service */
2471
function configure_cron() {
2472
	global $g, $config;
2473

    
2474
	conf_mount_rw();
2475
	/* preserve existing crontab entries */
2476
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2477

    
2478
	for ($i = 0; $i < count($crontab_contents); $i++) {
2479
		$cron_item =& $crontab_contents[$i];
2480
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2481
			array_splice($crontab_contents, $i - 1);
2482
			break;
2483
		}
2484
	}
2485
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2486

    
2487

    
2488
	if (is_array($config['cron']['item'])) {
2489
		$crontab_contents .= "#\n";
2490
		$crontab_contents .= "# " . gettext("pfSense specific crontab entries") . "\n";
2491
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2492
		$crontab_contents .= "#\n";
2493

    
2494
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2495
			$http_proxy = $config['system']['proxyurl'];
2496
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2497
				$http_proxy .= ':' . $config['system']['proxyport'];
2498
			}
2499
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2500
		}
2501

    
2502
		foreach ($config['cron']['item'] as $item) {
2503
			$crontab_contents .= "\n{$item['minute']}\t";
2504
			$crontab_contents .= "{$item['hour']}\t";
2505
			$crontab_contents .= "{$item['mday']}\t";
2506
			$crontab_contents .= "{$item['month']}\t";
2507
			$crontab_contents .= "{$item['wday']}\t";
2508
			$crontab_contents .= "{$item['who']}\t";
2509
			$crontab_contents .= "{$item['command']}";
2510
		}
2511

    
2512
		$crontab_contents .= "\n#\n";
2513
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2514
		$crontab_contents .= "# " . gettext("If you do so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2515
		$crontab_contents .= "#\n\n";
2516
	}
2517

    
2518
	/* please maintain the newline at the end of file */
2519
	file_put_contents("/etc/crontab", $crontab_contents);
2520
	unset($crontab_contents);
2521

    
2522
	/* do a HUP kill to force sync changes */
2523
	sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2524

    
2525
	conf_mount_ro();
2526
}
2527

    
2528
function upnp_action ($action) {
2529
	global $g, $config;
2530
	switch ($action) {
2531
		case "start":
2532
			if (file_exists('/var/etc/miniupnpd.conf')) {
2533
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2534
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2535
			}
2536
			break;
2537
		case "stop":
2538
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2539
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2540
				mwexec('killall miniupnpd 2>/dev/null', true);
2541
			}
2542
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2543
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2544
			break;
2545
		case "restart":
2546
			upnp_action('stop');
2547
			upnp_action('start');
2548
			break;
2549
	}
2550
}
2551

    
2552
function upnp_start() {
2553
	global $config;
2554

    
2555
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2556
		return;
2557
	}
2558

    
2559
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2560
		echo gettext("Starting UPnP service... ");
2561
		require_once('/usr/local/pkg/miniupnpd.inc');
2562
		sync_package_miniupnpd();
2563
		echo "done.\n";
2564
	}
2565
}
2566

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

    
2570
	$is_installed = false;
2571
	$cron_changed = true;
2572

    
2573
	if (!is_array($config['cron'])) {
2574
		$config['cron'] = array();
2575
	}
2576
	if (!is_array($config['cron']['item'])) {
2577
		$config['cron']['item'] = array();
2578
	}
2579

    
2580
	$x=0;
2581
	foreach ($config['cron']['item'] as $item) {
2582
		if (strstr($item['command'], $command)) {
2583
			$is_installed = true;
2584
			break;
2585
		}
2586
		$x++;
2587
	}
2588

    
2589
	if ($active) {
2590
		$cron_item = array();
2591
		$cron_item['minute'] = $minute;
2592
		$cron_item['hour'] = $hour;
2593
		$cron_item['mday'] = $monthday;
2594
		$cron_item['month'] = $month;
2595
		$cron_item['wday'] = $weekday;
2596
		$cron_item['who'] = $who;
2597
		$cron_item['command'] = $command;
2598
		if (!$is_installed) {
2599
			$config['cron']['item'][] = $cron_item;
2600
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2601
		} else {
2602
			if ($config['cron']['item'][$x] == $cron_item) {
2603
				$cron_changed = false;
2604
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2605
			} else {
2606
				$config['cron']['item'][$x] = $cron_item;
2607
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2608
			}
2609
		}
2610
	} else {
2611
		if ($is_installed == true) {
2612
			unset($config['cron']['item'][$x]);
2613
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2614
		}
2615
	}
2616

    
2617
	if ($cron_changed) {
2618
		configure_cron();
2619
	}
2620
}
2621

    
2622
?>
(50-50/68)