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

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

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

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

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

    
265
		/* prevent duplicate entries, manual overrides */
266
		if (isset($radvdifs[$realif])) {
267
			continue;
268
		}
269

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

    
280
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
281

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

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

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

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

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

    
354
function services_dhcpd_configure($family = "all", $blacklist = array()) {
355
	global $config, $g;
356

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

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

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

    
389
function services_dhcpdv4_configure() {
390
	global $config, $g;
391
	$need_ddns_updates = false;
392
	$ddns_zones = array();
393

    
394
	if ($g['services_dhcp_server_enable'] == false) {
395
		return;
396
	}
397

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

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

    
408
	/* DHCP enabled on any interfaces? */
409
	if (!is_dhcp_server_enabled()) {
410
		return 0;
411
	}
412

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

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

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

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

    
460
	if (platform_booting()) {
461
		echo gettext("Starting DHCP service...");
462
	} else {
463
		sleep(1);
464
	}
465

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

    
480
	$dhcpdconf = <<<EOD
481

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

    
495
EOD;
496

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

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

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

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

    
522
		if (!isset($config['interfaces'][$dhcpif]['enable'])) {
523
			continue;
524
		}
525

    
526
		interfaces_staticarp_configure($dhcpif);
527

    
528
		if (!isset($dhcpifconf['enable'])) {
529
			continue;
530
		}
531

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

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

    
586
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
587

    
588
		$newzone = array();
589
		$ifcfg = $config['interfaces'][$dhcpif];
590

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

    
599
		if (!is_ipaddr($subnet)) {
600
			continue;
601
		}
602

    
603
		if ($is_olsr_enabled == true) {
604
			if ($dhcpifconf['netmask']) {
605
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
606
			}
607
		}
608

    
609
		$all_pools = array();
610
		$all_pools[] = $dhcpifconf;
611
		if (is_array($dhcpifconf['pool'])) {
612
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
613
		}
614

    
615
		$dnscfg = "";
616

    
617
		if ($dhcpifconf['domain']) {
618
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
619
		}
620

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

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

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

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

    
686
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
687

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

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

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

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

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

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

    
738
			$pdnscfg = "";
739

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

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

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

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

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

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

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

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

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

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

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

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

    
821
		$dhcpdconf .= <<<EOD
822
$dnscfg
823

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

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

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

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

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

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

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

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

    
889
		$dhcpdconf .= <<<EOD
890
}
891

    
892
EOD;
893

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

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

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

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

    
909
				if ($sm['ipaddr']) {
910
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
911
				}
912

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

    
922
				if ($sm['rootpath']) {
923
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
924
				}
925

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

    
930
				$smdnscfg = "";
931

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

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

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

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

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

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

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

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

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

    
978
				$dhcpdconf .= "}\n";
979
				$i++;
980
			}
981
		}
982

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

    
992
	if ($need_ddns_updates) {
993
		$dhcpdconf .= "ddns-update-style interim;\n";
994
		$dhcpdconf .= "update-static-leases on;\n";
995

    
996
		$dhcpdconf .= dhcpdkey($dhcpifconf);
997
		$dhcpdconf .= dhcpdzones($ddns_zones, $dhcpifconf);
998
	}
999

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

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

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

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

    
1023
	if (platform_booting()) {
1024
		print "done.\n";
1025
	}
1026

    
1027
	return 0;
1028
}
1029

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

    
1040
	return $dhcpdconf;
1041
}
1042

    
1043
function dhcpdzones($ddns_zones, $dhcpifconf)
1044
{
1045
	$dhcpdconf = "";
1046

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

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

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

    
1094
	return $dhcpdconf;
1095
}
1096

    
1097
function services_dhcpdv6_configure($blacklist = array()) {
1098
	global $config, $g;
1099

    
1100
	if ($g['services_dhcp_server_enable'] == false) {
1101
		return;
1102
	}
1103

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

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

    
1117
	/* DHCP enabled on any interfaces? */
1118
	if (!is_dhcpv6_server_enabled()) {
1119
		return 0;
1120
	}
1121

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

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

    
1145

    
1146
	if (platform_booting()) {
1147
		echo "Starting DHCPv6 service...";
1148
	} else {
1149
		sleep(1);
1150
	}
1151

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

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

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

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

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

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

    
1213
	$dhcpdv6conf = <<<EOD
1214

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

    
1227
EOD;
1228

    
1229
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1230
		$dhcpdv6conf .= "authoritative;\n";
1231
	}
1232

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

    
1237
	$dhcpdv6ifs = array();
1238

    
1239
	$dhcpv6num = 0;
1240
	$nsupdate = false;
1241

    
1242
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1243

    
1244
		$ddns_zones = array();
1245

    
1246
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1247

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

    
1255
		if ($is_olsr_enabled == true) {
1256
			if ($dhcpv6ifconf['netmask']) {
1257
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1258
			}
1259
		}
1260

    
1261
		$dnscfgv6 = "";
1262

    
1263
		if ($dhcpv6ifconf['domain']) {
1264
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1265
		}
1266

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

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

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

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

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

    
1310
		$dhcpdv6conf .= <<<EOD
1311
	range6 {$dhcpv6ifconf['range']['from']} {$dhcpv6ifconf['range']['to']};
1312
$dnscfgv6
1313

    
1314
EOD;
1315

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

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

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

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

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

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

    
1371
		$dhcpdv6conf .= "}\n";
1372

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

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

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

    
1396
				if ($sm['rootpath']) {
1397
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1398
				}
1399

    
1400
				$dhcpdv6conf .= "}\n";
1401
				$i++;
1402
			}
1403
		}
1404

    
1405
		if ($dhcpv6ifconf['domain']) {
1406
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1407
			$dhcpdv6conf .= dhcpdzones($ddns_zones, $dhcpv6ifconf);
1408
		}
1409

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

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

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

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

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

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

    
1464
	return 0;
1465
}
1466

    
1467
function services_igmpproxy_configure() {
1468
	global $config, $g;
1469

    
1470
	/* kill any running igmpproxy */
1471
	killbyname("igmpproxy");
1472

    
1473
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1474
		return 1;
1475
	}
1476

    
1477
	$iflist = get_configured_interface_list();
1478

    
1479
	$igmpconf = <<<EOD
1480

    
1481
##------------------------------------------------------
1482
## Enable Quickleave mode (Sends Leave instantly)
1483
##------------------------------------------------------
1484
quickleave
1485

    
1486
EOD;
1487

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

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

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

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

    
1525
	return 0;
1526
}
1527

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

    
1538
	/* kill any running dhcrelay */
1539
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1540

    
1541
	$dhcrelaycfg =& $config['dhcrelay'];
1542

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

    
1548
	if (platform_booting()) {
1549
		echo gettext("Starting DHCP relay service...");
1550
	} else {
1551
		sleep(1);
1552
	}
1553

    
1554
	$iflist = get_configured_interface_list();
1555

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

    
1563
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1564
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1565
		}
1566
	}
1567

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

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

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

    
1634
		if (!empty($destif)) {
1635
			$dhcrelayifs[] = $destif;
1636
		}
1637
	}
1638
	$dhcrelayifs = array_unique($dhcrelayifs);
1639

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

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

    
1648
	if (isset($dhcrelaycfg['agentoption'])) {
1649
		$cmd .=  " -a -m replace";
1650
	}
1651

    
1652
	$cmd .= " " . implode(" ", $srvips);
1653
	mwexec($cmd);
1654
	unset($cmd);
1655

    
1656
	return 0;
1657
}
1658

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

    
1669
	/* kill any running dhcrelay */
1670
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1671

    
1672
	$dhcrelaycfg =& $config['dhcrelay6'];
1673

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

    
1679
	if (platform_booting()) {
1680
		echo gettext("Starting DHCPv6 relay service...");
1681
	} else {
1682
		sleep(1);
1683
	}
1684

    
1685
	$iflist = get_configured_interface_list();
1686

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

    
1693
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1694
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1695
		}
1696
	}
1697
	$dhcrelayifs = array_unique($dhcrelayifs);
1698

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

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

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

    
1760
		if (!empty($destif)) {
1761
			$srvifaces[] = "{$srvip}%{$destif}";
1762
		}
1763
	}
1764

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

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

    
1781
	return 0;
1782
}
1783

    
1784
function services_dyndns_configure_client($conf) {
1785

    
1786
	if (!isset($conf['enable'])) {
1787
		return;
1788
	}
1789

    
1790
	/* load up the dyndns.class */
1791
	require_once("dyndns.class");
1792

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

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

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

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

    
1839
		if (platform_booting()) {
1840
			echo gettext("done.") . "\n";
1841
		}
1842
	}
1843

    
1844
	return 0;
1845
}
1846

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

    
1874
function services_dnsmasq_configure() {
1875
	global $config, $g;
1876
	$return = 0;
1877

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

    
1885

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

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

    
1896
	if (isset($config['dnsmasq']['enable'])) {
1897

    
1898
		if (platform_booting()) {
1899
			echo gettext("Starting DNS forwarder...");
1900
		} else {
1901
			sleep(1);
1902
		}
1903

    
1904
		/* generate hosts file */
1905
		if (system_hosts_generate()!=0) {
1906
			$return = 1;
1907
		}
1908

    
1909
		$args = "";
1910

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

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

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

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

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

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

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

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

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

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

    
2028
		if (isset($config['dnsmasq']['strict_order'])) {
2029
			$args .= " --strict-order ";
2030
		}
2031

    
2032
		if (isset($config['dnsmasq']['domain_needed'])) {
2033
			$args .= " --domain-needed ";
2034
		}
2035

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

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

    
2053
		system_dhcpleases_configure();
2054

    
2055
		if (platform_booting()) {
2056
			echo gettext("done.") . "\n";
2057
		}
2058
	}
2059

    
2060
	if (!platform_booting()) {
2061
		if (services_dhcpd_configure()!=0) {
2062
			$return = 1;
2063
		}
2064
	}
2065

    
2066
	return $return;
2067
}
2068

    
2069
function services_unbound_configure() {
2070
	global $config, $g;
2071
	$return = 0;
2072

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

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

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

    
2090
		/* generate hosts file */
2091
		if (system_hosts_generate()!=0) {
2092
			$return = 1;
2093
		}
2094

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

    
2101
		system_dhcpleases_configure();
2102
	}
2103

    
2104
	if (!platform_booting()) {
2105
		if (services_dhcpd_configure()!=0) {
2106
			$return = 1;
2107
		}
2108
	}
2109

    
2110
	return $return;
2111
}
2112

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

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

    
2127
	if (isset($config['snmpd']['enable'])) {
2128

    
2129
		if (platform_booting()) {
2130
			echo gettext("Starting SNMP daemon... ");
2131
		}
2132

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

    
2140

    
2141
		$snmpdconf = <<<EOD
2142
location := "{$config['snmpd']['syslocation']}"
2143
contact := "{$config['snmpd']['syscontact']}"
2144
read := "{$config['snmpd']['rocommunity']}"
2145

    
2146
EOD;
2147

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

    
2154
EOD;
2155
		}
2156
*/
2157

    
2158

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

    
2166

    
2167
EOD;
2168
		}
2169

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

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

    
2187
EOD;
2188

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

    
2194
EOD;
2195
		}
2196
*/
2197

    
2198

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

    
2205
EOD;
2206
		}
2207

    
2208

    
2209
		$snmpdconf .= <<<EOD
2210
begemotSnmpdCommunityDisable    = 1
2211

    
2212
EOD;
2213

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

    
2230
		if (is_port($config['snmpd']['pollport'])) {
2231
			$snmpdconf .= <<<EOD
2232
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2233

    
2234
EOD;
2235

    
2236
		}
2237

    
2238
		$snmpdconf .= <<<EOD
2239
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2240
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2241

    
2242
# These are bsnmp macros not php vars.
2243
sysContact      = $(contact)
2244
sysLocation     = $(location)
2245
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2246

    
2247
snmpEnableAuthenTraps = 2
2248

    
2249
EOD;
2250

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

    
2256
EOD;
2257
			}
2258

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

    
2265
EOD;
2266
			}
2267

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

    
2272
EOD;
2273
			}
2274

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

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

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

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

    
2298
EOD;
2299
			}
2300
		}
2301

    
2302
		fwrite($fd, $snmpdconf);
2303
		fclose($fd);
2304
		unset($snmpdconf);
2305

    
2306
		if (isset($config['snmpd']['bindlan'])) {
2307
			$bindlan = "";
2308
		}
2309

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

    
2314
		if (platform_booting()) {
2315
			echo gettext("done.") . "\n";
2316
		}
2317
	}
2318

    
2319
	return 0;
2320
}
2321

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

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

    
2343
			/* determine interface name */
2344
			$if = get_real_interface($dnsupdate['interface']);
2345

    
2346
			if (isset($dnsupdate['usepublicip'])) {
2347
				$wanip = dyndnsCheckIP($dnsupdate['interface']);
2348
			} else {
2349
				$wanip = get_interface_ip($dnsupdate['interface']);
2350
			}
2351

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

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

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

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

    
2378
EOD;
2379
				fwrite($fd, $privkey);
2380
				fclose($fd);
2381

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

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

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

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

    
2411
				// 25 Days
2412
				$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2413
				$need_update = false;
2414

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

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

    
2449
				$upinst .= "\n";	/* mind that trailing newline! */
2450

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

    
2470
	return 0;
2471
}
2472

    
2473
/* configure cron service */
2474
function configure_cron() {
2475
	global $g, $config;
2476

    
2477
	conf_mount_rw();
2478
	/* preserve existing crontab entries */
2479
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2480

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

    
2490

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

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

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

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

    
2521
	/* please maintain the newline at the end of file */
2522
	file_put_contents("/etc/crontab", $crontab_contents);
2523
	unset($crontab_contents);
2524

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

    
2528
	conf_mount_ro();
2529
}
2530

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

    
2555
function upnp_start() {
2556
	global $config;
2557

    
2558
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2559
		return;
2560
	}
2561

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

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

    
2573
	$is_installed = false;
2574
	$cron_changed = true;
2575

    
2576
	if (!is_array($config['cron'])) {
2577
		$config['cron'] = array();
2578
	}
2579
	if (!is_array($config['cron']['item'])) {
2580
		$config['cron']['item'] = array();
2581
	}
2582

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

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

    
2620
	if ($cron_changed) {
2621
		configure_cron();
2622
	}
2623
}
2624

    
2625
?>
(50-50/68)