Project

General

Profile

Download (87.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * services.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally part of m0n0wall (http://m0n0.ch/wall)
10
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
 * All rights reserved.
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 * http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25

    
26
define('DYNDNS_PROVIDER_VALUES', 'all-inkl citynetwork cloudflare cloudflare-v6 custom custom-v6 dnsexit dnsimple dnsmadeeasy dnsomatic duiadns duiadns-v6 dyndns dyndns-custom dyndns-static dyns easydns eurodns freedns freedns-v6 glesys googledomains gratisdns he-net he-net-v6 he-net-tunnelbroker loopia namecheap noip noip-free ods opendns ovh-dynhost route53 selfhost spdyn spdyn-v6 zoneedit');
27
define('DYNDNS_PROVIDER_DESCRIPTIONS', 'All-Inkl.com,City Network,CloudFlare,CloudFlare (v6),Custom,Custom (v6),DNSexit,DNSimple,DNS Made Easy,DNS-O-Matic,DuiaDns.net,DuiaDns.net (v6),DynDNS (dynamic),DynDNS (custom),DynDNS (static),DyNS,easyDNS,Euro Dns,freeDNS,freeDNS (v6),GleSYS,Google Domains,GratisDNS,HE.net,HE.net (v6),HE.net Tunnelbroker,Loopia,Namecheap,No-IP,No-IP (free),ODS.org,OpenDNS,OVH DynHOST,Route 53,SelfHost,SPDYN,SPDYN (v6),ZoneEdit');
28

    
29
/* implement ipv6 route advertising daemon */
30
function services_radvd_configure($blacklist = array()) {
31
	global $config, $g;
32

    
33
	if (isset($config['system']['developerspew'])) {
34
		$mt = microtime();
35
		echo "services_radvd_configure() being called $mt\n";
36
	}
37

    
38
	if (!is_array($config['dhcpdv6'])) {
39
		$config['dhcpdv6'] = array();
40
	}
41

    
42
	$Iflist = get_configured_interface_list();
43
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
44

    
45
	$radvdconf = "# Automatically Generated, do not edit\n";
46

    
47
	/* Process all links which need the router advertise daemon */
48
	$radvdifs = array();
49

    
50
	/* handle manually configured DHCP6 server settings first */
51
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
52
		if (!is_array($config['interfaces'][$dhcpv6if])) {
53
			continue;
54
		}
55
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
56
			continue;
57
		}
58

    
59
		/* Do not put in the config an interface which is down */
60
		if (isset($blacklist[$dhcpv6if])) {
61
			continue;
62
		}
63
		if (!isset($dhcpv6ifconf['ramode'])) {
64
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
65
		}
66

    
67
		/* are router advertisements enabled? */
68
		if ($dhcpv6ifconf['ramode'] == "disabled") {
69
			continue;
70
		}
71

    
72
		if (!isset($dhcpv6ifconf['rapriority'])) {
73
			$dhcpv6ifconf['rapriority'] = "medium";
74
		}
75

    
76
		$racarpif = false;
77
		/* check if binding to CARP IP */
78
		if (!empty($dhcpv6ifconf['rainterface'])) {
79
			if (strstr($dhcpv6ifconf['rainterface'], "_vip")) {
80
				if (get_carp_interface_status($dhcpv6ifconf['rainterface']) == "MASTER") {
81
					$dhcpv6if = $dhcpv6ifconf['rainterface'];
82
					$racarpif = true;
83
				} else {
84
					continue;
85
				}
86
			}
87
		}
88

    
89
		$realif = get_real_interface($dhcpv6if, "inet6");
90

    
91
		if (isset($radvdifs[$realif])) {
92
			continue;
93
		}
94

    
95
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
96
		if (!is_ipaddrv6($ifcfgipv6)) {
97
			continue;
98
		}
99

    
100
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
101
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
102
		if (!is_subnetv6($subnetv6 . "/" . $ifcfgsnv6)) {
103
			log_error("radvd: skipping configuration for interface $dhcpv6if because its subnet or prefix length is invalid.");
104
			continue;
105
		}
106
		$radvdifs[$realif] = $realif;
107

    
108
		$radvdconf .= "# Generated for DHCPv6 Server $dhcpv6if\n";
109
		$radvdconf .= "interface {$realif} {\n";
110
		if (strstr($realif, "ovpn")) {
111
			$radvdconf .= "\tUnicastOnly on;\n";
112
		}
113
		$radvdconf .= "\tAdvSendAdvert on;\n";
114

    
115
		if (is_numericint($dhcpv6ifconf['raminrtradvinterval'])) {
116
			$radvdconf .= "\tMinRtrAdvInterval {$dhcpv6ifconf['raminrtradvinterval']};\n";
117
		} else {
118
			$radvdconf .= "\tMinRtrAdvInterval 5;\n";
119
		}
120

    
121
		if (is_numericint($dhcpv6ifconf['ramaxrtradvinterval'])) {
122
			$radvdconf .= "\tMaxRtrAdvInterval {$dhcpv6ifconf['ramaxrtradvinterval']};\n";
123
		} else {
124
			$radvdconf .= "\tMaxRtrAdvInterval 20;\n";
125
		}
126
		if (is_numericint($dhcpv6ifconf['raadvdefaultlifetime'])) {
127
			$radvdconf .= "\tAdvDefaultLifetime {$dhcpv6ifconf['raadvdefaultlifetime']};\n";
128
		}
129

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

    
188
		if (is_numericint($dhcpv6ifconf['ravalidlifetime'])) {
189
		  $radvdconf .= "\t\tAdvValidLifetime {$dhcpv6ifconf['ravalidlifetime']};\n";
190
		} else {
191
		  $radvdconf .= "\t\tAdvValidLifetime 86400;\n";
192
		}
193

    
194
		if (is_numericint($dhcpv6ifconf['rapreferredlifetime'])) {
195
		  $radvdconf .= "\t\tAdvPreferredLifetime {$dhcpv6ifconf['rapreferredlifetime']};\n";
196
		} else {
197
		  $radvdconf .= "\t\tAdvPreferredLifetime 14400;\n";
198
		}
199

    
200
		$radvdconf .= "\t};\n";
201

    
202
		if (is_array($dhcpv6ifconf['subnets']['item'])) {
203
			foreach ($dhcpv6ifconf['subnets']['item'] as $subnet) {
204
				if (is_subnetv6($subnet)) {
205
					$radvdconf .= "\tprefix {$subnet} {\n";
206
					$radvdconf .= "\t\tDeprecatePrefix on;\n";
207
					switch ($dhcpv6ifconf['ramode']) {
208
						case "managed":
209
							$radvdconf .= "\t\tAdvOnLink on;\n";
210
							$radvdconf .= "\t\tAdvAutonomous off;\n";
211
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
212
							break;
213
						case "router":
214
							$radvdconf .= "\t\tAdvOnLink off;\n";
215
							$radvdconf .= "\t\tAdvAutonomous off;\n";
216
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
217
							break;
218
						case "assist":
219
							$radvdconf .= "\t\tAdvOnLink on;\n";
220
							$radvdconf .= "\t\tAdvAutonomous on;\n";
221
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
222
							break;
223
						case "unmanaged":
224
							$radvdconf .= "\t\tAdvOnLink on;\n";
225
							$radvdconf .= "\t\tAdvAutonomous on;\n";
226
							$radvdconf .= "\t\tAdvRouterAddr on;\n";
227
							break;
228
					}
229
					$radvdconf .= "\t};\n";
230
				}
231
			}
232
		}
233
		$radvdconf .= "\troute ::/0 {\n";
234
		$radvdconf .= "\t\tRemoveRoute on;\n";
235
		$radvdconf .= "\t};\n";
236

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

    
267
		$searchlist = array();
268
		$domainsearchlist = explode(';', $dhcpv6ifconf['radomainsearchlist']);
269
		foreach ($domainsearchlist as $sd) {
270
			$sd = trim($sd);
271
			if (is_hostname($sd)) {
272
				$searchlist[] = $sd;
273
			}
274
		}
275
		if (count($searchlist) > 0) {
276
			$searchliststring = trim(implode(" ", $searchlist));
277
		}
278
		if (!empty($dhcpv6ifconf['domain'])) {
279
			$radvdconf .= "\tDNSSL {$dhcpv6ifconf['domain']} {$searchliststring} { };\n";
280
		} elseif (!empty($config['system']['domain'])) {
281
			$radvdconf .= "\tDNSSL {$config['system']['domain']} {$searchliststring} { };\n";
282
		}
283
		$radvdconf .= "};\n";
284
	}
285

    
286
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
287
	foreach ($Iflist as $if => $ifdescr) {
288
		if (!isset($config['interfaces'][$if]['track6-interface']) ||
289
		    !isset($config['interfaces'][$if]['ipaddrv6']) ||
290
		    $config['interfaces'][$if]['ipaddrv6'] != 'track6') {
291
			continue;
292
		}
293
		if (!isset($config['interfaces'][$if]['enable'])) {
294
			continue;
295
		}
296
		if ($config['dhcpdv6'][$if]['ramode'] == "disabled") {
297
			continue;
298
		}
299
		/* Do not put in the config an interface which is down */
300
		if (isset($blacklist[$if])) {
301
			continue;
302
		}
303
		$trackif = $config['interfaces'][$if]['track6-interface'];
304
		if (empty($config['interfaces'][$trackif])) {
305
			continue;
306
		}
307

    
308
		$realif = get_real_interface($if, "inet6");
309

    
310
		/* prevent duplicate entries, manual overrides */
311
		if (isset($radvdifs[$realif])) {
312
			continue;
313
		}
314

    
315
		$ifcfgipv6 = get_interface_ipv6($if);
316
		if (!is_ipaddrv6($ifcfgipv6)) {
317
			$subnetv6 = "::";
318
			$ifcfgsnv6 = "64";
319
		} else {
320
			$ifcfgsnv6 = get_interface_subnetv6($if);
321
			$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
322
		}
323
		$radvdifs[$realif] = $realif;
324

    
325
		$autotype = $config['interfaces'][$trackif]['ipaddrv6'];
326

    
327
		if ($g['debug']) {
328
			log_error("configuring RA on {$if} for type {$autotype} radvd subnet {$subnetv6}/{$ifcfgsnv6}");
329
		}
330

    
331
		$radvdconf .= "# Generated config for {$autotype} delegation from {$trackif} on {$if}\n";
332
		$radvdconf .= "interface {$realif} {\n";
333
		$radvdconf .= "\tAdvSendAdvert on;\n";
334
		if (is_numericint($dhcpv6ifconf['raminrtradvinterval'])) {
335
			$radvdconf .= "\tMinRtrAdvInterval {$dhcpv6ifconf['raminrtradvinterval']};\n";
336
		} else {
337
			$radvdconf .= "\tMinRtrAdvInterval 5;\n";
338
                }
339
		if (is_numericint($dhcpv6ifconf['ramaxrtradvinterval'])) {
340
			$radvdconf .= "\tMaxRtrAdvInterval {$dhcpv6ifconf['ramaxrtradvinterval']};\n";
341
		} else {
342
			$radvdconf .= "\tMaxRtrAdvInterval 10;\n";
343
		}
344
		$mtu = get_interface_mtu($realif);
345
		if (is_numeric($mtu)) {
346
			$radvdconf .= "\tAdvLinkMTU {$mtu};\n";
347
		} else {
348
			$radvdconf .= "\tAdvLinkMTU 1280;\n";
349
		}
350
		$radvdconf .= "\tAdvOtherConfigFlag on;\n";
351
		$radvdconf .= "\tprefix {$subnetv6}/{$ifcfgsnv6} {\n";
352
		$radvdconf .= "\t\tAdvOnLink on;\n";
353
		$radvdconf .= "\t\tAdvAutonomous on;\n";
354
		$radvdconf .= "\t\tAdvRouterAddr on;\n";
355
		$radvdconf .= "\t};\n";
356

    
357
		/* add DNS servers */
358
		$dnslist = array();
359
		if (isset($config['dnsmasq']['enable']) || isset($config['unbound']['enable'])) {
360
			$dnslist[] = $ifcfgipv6;
361
		} elseif (is_array($config['system']['dnsserver']) && !empty($config['system']['dnsserver'])) {
362
			foreach ($config['system']['dnsserver'] as $server) {
363
				if (is_ipaddrv6($server)) {
364
					$dnslist[] = $server;
365
				}
366
			}
367
		}
368
		if (count($dnslist) > 0) {
369
			$dnsstring = implode(" ", $dnslist);
370
			if (!empty($dnsstring)) {
371
				$radvdconf .= "\tRDNSS {$dnsstring} { };\n";
372
			}
373
		}
374
		if (!empty($config['system']['domain'])) {
375
			$radvdconf .= "\tDNSSL {$config['system']['domain']} { };\n";
376
		}
377
		$radvdconf .= "};\n";
378
	}
379

    
380
	/* write radvd.conf */
381
	if (!@file_put_contents("{$g['varetc_path']}/radvd.conf", $radvdconf)) {
382
		log_error(gettext("Error: cannot open radvd.conf in services_radvd_configure()."));
383
		if (platform_booting()) {
384
			printf("Error: cannot open radvd.conf in services_radvd_configure().\n");
385
		}
386
	}
387
	unset($radvdconf);
388

    
389
	if (count($radvdifs) > 0) {
390
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
391
			sigkillbypid("{$g['varrun_path']}/radvd.pid", "HUP");
392
		} else {
393
			mwexec("/usr/local/sbin/radvd -p {$g['varrun_path']}/radvd.pid -C {$g['varetc_path']}/radvd.conf -m syslog");
394
		}
395
	} else {
396
		/* we need to shut down the radvd cleanly, it will send out the prefix
397
		 * information with a lifetime of 0 to notify clients of a (possible) new prefix */
398
		if (isvalidpid("{$g['varrun_path']}/radvd.pid")) {
399
			log_error(gettext("Shutting down Router Advertisment daemon cleanly"));
400
			killbypid("{$g['varrun_path']}/radvd.pid");
401
			@unlink("{$g['varrun_path']}/radvd.pid");
402
		}
403
	}
404
	return 0;
405
}
406

    
407
function services_dhcpd_configure($family = "all", $blacklist = array()) {
408
	global $config, $g;
409

    
410
	$dhcpdconfigurelck = lock("dhcpdconfigure", LOCK_EX);
411

    
412
	/* configure DHCPD chroot once */
413
	$fd = fopen("{$g['tmp_path']}/dhcpd.sh", "w");
414
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}\n");
415
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/dev\n");
416
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/etc\n");
417
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr/local/sbin\n");
418
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/db\n");
419
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/var/run\n");
420
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/usr\n");
421
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/lib\n");
422
	fwrite($fd, "/bin/mkdir -p {$g['dhcpd_chroot_path']}/run\n");
423
	fwrite($fd, "/usr/sbin/chown -R dhcpd:_dhcp {$g['dhcpd_chroot_path']}/*\n");
424
	fwrite($fd, "/bin/cp -n /lib/libc.so.* {$g['dhcpd_chroot_path']}/lib/\n");
425
	fwrite($fd, "/bin/cp -n /usr/local/sbin/dhcpd {$g['dhcpd_chroot_path']}/usr/local/sbin/\n");
426
	fwrite($fd, "/bin/chmod a+rx {$g['dhcpd_chroot_path']}/usr/local/sbin/dhcpd\n");
427

    
428
	$status = `/sbin/mount | /usr/bin/grep -v grep | /usr/bin/grep "{$g['dhcpd_chroot_path']}/dev"`;
429
	if (!trim($status)) {
430
		fwrite($fd, "/sbin/mount -t devfs devfs {$g['dhcpd_chroot_path']}/dev\n");
431
	}
432
	fclose($fd);
433
	mwexec("/bin/sh {$g['tmp_path']}/dhcpd.sh");
434

    
435
	if ($family == "all" || $family == "inet") {
436
		services_dhcpdv4_configure();
437
	}
438
	if ($family == "all" || $family == "inet6") {
439
		services_dhcpdv6_configure($blacklist);
440
		services_radvd_configure($blacklist);
441
	}
442

    
443
	unlock($dhcpdconfigurelck);
444
}
445

    
446
function services_dhcpdv4_configure() {
447
	global $config, $g;
448
	$need_ddns_updates = false;
449
	$ddns_zones = array();
450

    
451
	if ($g['services_dhcp_server_enable'] == false) {
452
		return;
453
	}
454

    
455
	if (isset($config['system']['developerspew'])) {
456
		$mt = microtime();
457
		echo "services_dhcpdv4_configure($if) being called $mt\n";
458
	}
459

    
460
	/* kill any running dhcpd */
461
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid")) {
462
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpd.pid");
463
	}
464

    
465
	/* DHCP enabled on any interfaces? */
466
	if (!is_dhcp_server_enabled()) {
467
		return 0;
468
	}
469

    
470
	/* if OLSRD is enabled, allow WAN to house DHCP. */
471
	if (!function_exists('is_package_installed')) {
472
		require_once('pkg-utils.inc');
473
	}
474
	if (is_package_installed('olsrd') && isset($config['installedpackages']['olsrd'])) {
475
		foreach ($config['installedpackages']['olsrd']['config'] as $olsrd) {
476
			if (isset($olsrd['enable']) && $olsrd['enable'] == "on") {
477
				$is_olsr_enabled = true;
478
				break;
479
			}
480
		}
481
	}
482

    
483
	if (platform_booting()) {
484
		/* restore the leases, if we have them */
485
		if (file_exists("{$g['cf_conf_path']}/dhcpleases.tgz")) {
486
			$dhcprestore = "";
487
			$dhcpreturn = "";
488
			exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcpleases.tgz 2>&1", $dhcprestore, $dhcpreturn);
489
			$dhcprestore = implode(" ", $dhcprestore);
490
			if ($dhcpreturn <> 0) {
491
				log_error(sprintf(gettext('DHCP leases restore failed exited with %1$s, the error is: %2$s%3$s'), $dhcpreturn, $dhcprestore, "\n"));
492
			}
493
		}
494
		/* 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. */
495
		if (!isset($config['system']['use_mfs_tmpvar'])) {
496
			unlink_if_exists("{$g['cf_conf_path']}/dhcpleases.tgz");
497
		}
498
	}
499

    
500
	$syscfg = $config['system'];
501
	if (!is_array($config['dhcpd'])) {
502
		$config['dhcpd'] = array();
503
	}
504
	$dhcpdcfg = $config['dhcpd'];
505
	$Iflist = get_configured_interface_list();
506

    
507
	/* Only consider DNS servers with IPv4 addresses for the IPv4 DHCP server. */
508
	$dns_arrv4 = array();
509
	if (is_array($syscfg['dnsserver'])) {
510
		foreach ($syscfg['dnsserver'] as $dnsserver) {
511
			if (is_ipaddrv4($dnsserver)) {
512
				$dns_arrv4[] = $dnsserver;
513
			}
514
		}
515
	}
516

    
517
	if (platform_booting()) {
518
		echo gettext("Starting DHCP service...");
519
	} else {
520
		sleep(1);
521
	}
522

    
523
	$custoptions = "";
524
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
525
		if (is_array($dhcpifconf['numberoptions']) && is_array($dhcpifconf['numberoptions']['item'])) {
526
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
527
				if (!empty($item['type'])) {
528
					$itemtype = $item['type'];
529
				} else {
530
					$itemtype = "text";
531
				}
532
				$custoptions .= "option custom-{$dhcpif}-{$itemidx} code {$item['number']} = {$itemtype};\n";
533
			}
534
		}
535
		if (is_array($dhcpifconf['pool'])) {
536
			foreach ($dhcpifconf['pool'] as $poolidx => $poolconf) {
537
				if (is_array($poolconf['numberoptions']) && is_array($poolconf['numberoptions']['item'])) {
538
					foreach ($poolconf['numberoptions']['item'] as $itemidx => $item) {
539
						if (!empty($item['type'])) {
540
							$itemtype = $item['type'];
541
						} else {
542
							$itemtype = "text";
543
						}
544
						$custoptions .= "option custom-{$dhcpif}-{$poolidx}-{$itemidx} code {$item['number']} = {$itemtype};\n";
545
					}
546
				}
547
			}
548
		}
549
	}
550

    
551
	$dhcpdconf = <<<EOD
552

    
553
option domain-name "{$syscfg['domain']}";
554
option ldap-server code 95 = text;
555
option domain-search-list code 119 = text;
556
option arch code 93 = unsigned integer 16; # RFC4578
557
{$custoptions}
558
default-lease-time 7200;
559
max-lease-time 86400;
560
log-facility local7;
561
one-lease-per-client true;
562
deny duplicates;
563
ping-check true;
564
update-conflict-detection false;
565

    
566
EOD;
567

    
568
	if (!isset($dhcpifconf['disableauthoritative'])) {
569
		$dhcpdconf .= "authoritative;\n";
570
	}
571

    
572
	if (isset($dhcpifconf['alwaysbroadcast'])) {
573
		$dhcpdconf .= "always-broadcast on\n";
574
	}
575

    
576
	$dhcpdifs = array();
577
	$enable_add_routers = false;
578
	$gateways_arr = return_gateways_array();
579
	/* only add a routers line if the system has any IPv4 gateway at all */
580
	/* a static route has a gateway, manually overriding this field always works */
581
	foreach ($gateways_arr as $gwitem) {
582
		if ($gwitem['ipprotocol'] == "inet") {
583
			$enable_add_routers = true;
584
			break;
585
		}
586
	}
587

    
588
	/*    loop through and determine if we need to setup
589
	 *    failover peer "bleh" entries
590
	 */
591
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
592

    
593
		if (!isset($config['interfaces'][$dhcpif]['enable'])) {
594
			continue;
595
		}
596

    
597
		interfaces_staticarp_configure($dhcpif);
598

    
599
		if (!isset($dhcpifconf['enable'])) {
600
			continue;
601
		}
602

    
603
		if ($dhcpifconf['failover_peerip'] <> "") {
604
			$intip = get_interface_ip($dhcpif);
605
			/*
606
			 *    yep, failover peer is defined.
607
			 *    does it match up to a defined vip?
608
			 */
609
			$skew = 110;
610
			if (is_array($config['virtualip']['vip'])) {
611
				foreach ($config['virtualip']['vip'] as $vipent) {
612
					if ($vipent['interface'] == $dhcpif) {
613
						$carp_nw = gen_subnet($vipent['subnet'], $vipent['subnet_bits']);
614
						if (ip_in_subnet($dhcpifconf['failover_peerip'], "{$carp_nw}/{$vipent['subnet_bits']}")) {
615
							/* this is the interface! */
616
							if (is_numeric($vipent['advskew']) && (intval($vipent['advskew']) < 20)) {
617
								$skew = 0;
618
								break;
619
							}
620
						}
621
					}
622
				}
623
			} else {
624
				log_error(gettext("Warning!  DHCP Failover setup and no CARP virtual IPs defined!"));
625
			}
626
			if ($skew > 10) {
627
				$type = "secondary";
628
				$my_port = "520";
629
				$peer_port = "519";
630
			} else {
631
				$my_port = "519";
632
				$peer_port = "520";
633
				$type = "primary";
634
				$dhcpdconf_pri = "split 128;\n";
635
				$dhcpdconf_pri .= "  mclt 600;\n";
636
			}
637

    
638
			if (is_ipaddrv4($intip)) {
639
				$dhcpdconf .= <<<EOPP
640
failover peer "dhcp_{$dhcpif}" {
641
  {$type};
642
  address {$intip};
643
  port {$my_port};
644
  peer address {$dhcpifconf['failover_peerip']};
645
  peer port {$peer_port};
646
  max-response-delay 10;
647
  max-unacked-updates 10;
648
  {$dhcpdconf_pri}
649
  load balance max seconds 3;
650
}
651
\n
652
EOPP;
653
			}
654
		}
655
	}
656

    
657
	foreach ($dhcpdcfg as $dhcpif => $dhcpifconf) {
658

    
659
		$newzone = array();
660
		$ifcfg = $config['interfaces'][$dhcpif];
661

    
662
		if (!isset($dhcpifconf['enable']) || !isset($Iflist[$dhcpif])) {
663
			continue;
664
		}
665
		$ifcfgip = get_interface_ip($dhcpif);
666
		$ifcfgsn = get_interface_subnet($dhcpif);
667
		$subnet = gen_subnet($ifcfgip, $ifcfgsn);
668
		$subnetmask = gen_subnet_mask($ifcfgsn);
669

    
670
		if (!is_ipaddr($subnet)) {
671
			continue;
672
		}
673

    
674
		if ($is_olsr_enabled == true) {
675
			if ($dhcpifconf['netmask']) {
676
				$subnetmask = gen_subnet_mask($dhcpifconf['netmask']);
677
			}
678
		}
679

    
680
		$all_pools = array();
681
		$all_pools[] = $dhcpifconf;
682
		if (is_array($dhcpifconf['pool'])) {
683
			$all_pools = array_merge($all_pools, $dhcpifconf['pool']);
684
		}
685

    
686
		$dnscfg = "";
687

    
688
		if ($dhcpifconf['domain']) {
689
			$dnscfg .= "	option domain-name \"{$dhcpifconf['domain']}\";\n";
690
		}
691

    
692
		if ($dhcpifconf['domainsearchlist'] <> "") {
693
			$dnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpifconf['domainsearchlist'])) . "\";\n";
694
		}
695

    
696
		if (isset($dhcpifconf['ddnsupdate'])) {
697
			$need_ddns_updates = true;
698
			$newzone = array();
699
			if ($dhcpifconf['ddnsdomain'] <> "") {
700
				$newzone['domain-name'] = $dhcpifconf['ddnsdomain'];
701
				$dnscfg .= "	ddns-domainname \"{$dhcpifconf['ddnsdomain']}\";\n";
702
			} else {
703
				$newzone['domain-name'] = $config['system']['domain'];
704
			}
705

    
706
			$revsubnet = array_reverse(explode('.',$subnet));
707

    
708
			/* Take care of full classes first */
709
			switch ($ifcfgsn) {
710
				case 8:
711
					$start_octet = 3;
712
					break;
713
				case 16:
714
					$start_octet = 2;
715
					break;
716
				case 24:
717
					$start_octet = 1;
718
					break;
719
				default:
720
					$start_octet = 0;
721
					/* Add subnet bitmask to first octet */
722
					$revsubnet[0] .= '-' . $ifcfgsn;
723
					break;
724

    
725
			}
726

    
727
			$ptr_domain = '';
728
			for ($octet = 0; $octet <= 3; $octet++) {
729
				if ($octet < $start_octet) {
730
					continue;
731
				}
732
				$ptr_domain .= ((empty($ptr_domain) && $ptr_domain !== "0") ? '' : '.');
733
				$ptr_domain .= $revsubnet[$octet];
734
			}
735
			$ptr_domain .= ".in-addr.arpa";
736
			$newzone['ptr-domain'] = $ptr_domain;
737
			unset($ptr_domain, $revsubnet, $start_octet);
738
		}
739

    
740
		if (is_array($dhcpifconf['dnsserver']) && ($dhcpifconf['dnsserver'][0])) {
741
			$dnscfg .= "	option domain-name-servers " . join(",", $dhcpifconf['dnsserver']) . ";";
742
			if ($newzone['domain-name']) {
743
				$newzone['dns-servers'] = $dhcpifconf['dnsserver'];
744
			}
745
		} else if (isset($config['dnsmasq']['enable'])) {
746
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
747
			if ($newzone['domain-name'] && is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
748
				$newzone['dns-servers'] = $syscfg['dnsserver'];
749
			}
750
		} else if (isset($config['unbound']['enable'])) {
751
			$dnscfg .= "	option domain-name-servers {$ifcfgip};";
752
		} else if (!empty($dns_arrv4)) {
753
			$dnscfg .= "	option domain-name-servers " . join(",", $dns_arrv4) . ";";
754
			if ($newzone['domain-name']) {
755
				$newzone['dns-servers'] = $dns_arrv4;
756
			}
757
		}
758

    
759
		/* Create classes - These all contain comma separated lists. Join them into one
760
		   big comma separated string then split them all up. */
761
		$all_mac_strings = array();
762
		if (is_array($dhcpifconf['pool'])) {
763
			foreach ($all_pools as $poolconf) {
764
				$all_mac_strings[] = $poolconf['mac_allow'];
765
				$all_mac_strings[] = $poolconf['mac_deny'];
766
			}
767
		}
768
		$all_mac_strings[] = $dhcpifconf['mac_allow'];
769
		$all_mac_strings[] = $dhcpifconf['mac_deny'];
770
		if (!empty($all_mac_strings)) {
771
			$all_mac_list = array_unique(explode(',', implode(',', $all_mac_strings)));
772
			foreach ($all_mac_list as $mac) {
773
				if (empty($mac)) {
774
					continue;
775
				}
776
				$dhcpdconf .= 'class "' . str_replace(':', '', $mac) . '" {' . "\n";
777
				// Skip the first octet of the MAC address - for media type, typically Ethernet ("01") and match the rest.
778
				$dhcpdconf .= '	match if substring (hardware, 1, ' . (substr_count($mac, ':') + 1) . ') = ' . $mac . ';' . "\n";
779
				$dhcpdconf .= '}' . "\n";
780
			}
781
		}
782

    
783
		$dhcpdconf .= "subnet {$subnet} netmask {$subnetmask} {\n";
784

    
785
		// Setup pool options
786
		foreach ($all_pools as $all_pools_idx => $poolconf) {
787
			if (!(ip_in_subnet($poolconf['range']['from'], "{$subnet}/{$ifcfgsn}") && ip_in_subnet($poolconf['range']['to'], "{$subnet}/{$ifcfgsn}"))) {
788
				// If the user has changed the subnet from the interfaces page and applied,
789
				// but has not updated the DHCP range, then the range to/from of the pool can be outside the subnet.
790
				// This can also happen when implementing the batch of changes when the setup wizard reloads the new settings.
791
				$error_msg = sprintf(gettext("Invalid DHCP pool %s - %s for %s subnet %s/%s detected. Please correct the settings in Services, DHCP Server"), $poolconf['range']['from'], $poolconf['range']['to'], convert_real_interface_to_friendly_descr($dhcpif), $subnet, $ifcfgsn);
792
				$do_file_notice = true;
793
				$conf_ipv4_address = $ifcfg['ipaddr'];
794
				$conf_ipv4_subnetmask = $ifcfg['subnet'];
795
				if (is_ipaddrv4($conf_ipv4_address) && is_subnet("{$conf_ipv4_address}/{$conf_ipv4_subnetmask}")) {
796
					$conf_subnet_base = gen_subnet($conf_ipv4_address, $conf_ipv4_subnetmask);
797
					if (ip_in_subnet($poolconf['range']['from'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}") &&
798
					    ip_in_subnet($poolconf['range']['to'], "{$conf_subnet_base}/{$conf_ipv4_subnetmask}")) {
799
						// Even though the running interface subnet does not match the pool range,
800
						// the interface subnet in the config file contains the pool range.
801
						// We are somewhere part-way through a settings reload, e.g. after running the setup wizard.
802
						// services_dhcpdv4_configure will be called again later when the new interface settings from
803
						// the config are applied and at that time everything will match up.
804
						// Ignore this pool on this interface for now and just log the error to the system log.
805
						log_error($error_msg);
806
						$do_file_notice = false;
807
					}
808
				}
809
				if ($do_file_notice) {
810
					file_notice("DHCP", $error_msg);
811
				}
812
				continue;
813
			}
814
			$dhcpdconf .= "	pool {\n";
815
			/* is failover dns setup? */
816
			if (is_array($poolconf['dnsserver']) && $poolconf['dnsserver'][0] <> "") {
817
				$dhcpdconf .= "		option domain-name-servers {$poolconf['dnsserver'][0]}";
818
				if ($poolconf['dnsserver'][1] <> "") {
819
					$dhcpdconf .= ",{$poolconf['dnsserver'][1]}";
820
				}
821
				if ($poolconf['dnsserver'][2] <> "") {
822
					$dhcpdconf .= ",{$poolconf['dnsserver'][2]}";
823
				}
824
				if ($poolconf['dnsserver'][3] <> "") {
825
					$dhcpdconf .= ",{$poolconf['dnsserver'][3]}";
826
				}
827
				$dhcpdconf .= ";\n";
828
			}
829

    
830
			/* allow/deny MACs */
831
			$mac_allow_list = array_unique(explode(',', $poolconf['mac_allow']));
832
			foreach ($mac_allow_list as $mac) {
833
				if (empty($mac)) {
834
					continue;
835
				}
836
				$dhcpdconf .= "		allow members of \"" . str_replace(':', '', $mac) . "\";\n";
837
			}
838
			$deny_action = "deny";
839
			if (isset($poolconf['nonak']) && empty($poolconf['failover_peerip'])) {
840
				$deny_action = "ignore";
841
			}
842
			$mac_deny_list = array_unique(explode(',', $poolconf['mac_deny']));
843
			foreach ($mac_deny_list as $mac) {
844
				if (empty($mac)) {
845
					continue;
846
				}
847
				$dhcpdconf .= "		$deny_action members of \"" . str_replace(':', '', $mac) . "\";\n";
848
			}
849

    
850
			if ($poolconf['failover_peerip'] <> "") {
851
				$dhcpdconf .= "		$deny_action dynamic bootp clients;\n";
852
			}
853

    
854
			if (isset($poolconf['denyunknown'])) {
855
				$dhcpdconf .= "		$deny_action unknown-clients;\n";
856
			}
857

    
858
			if ($poolconf['gateway'] && $poolconf['gateway'] != "none" && ($poolconf['gateway'] != $dhcpifconf['gateway'])) {
859
				$dhcpdconf .= "		option routers {$poolconf['gateway']};\n";
860
			}
861

    
862
			if ($dhcpifconf['failover_peerip'] <> "") {
863
				$dhcpdconf .= "		failover peer \"dhcp_{$dhcpif}\";\n";
864
			}
865

    
866
			$pdnscfg = "";
867

    
868
			if ($poolconf['domain'] && ($poolconf['domain'] != $dhcpifconf['domain'])) {
869
				$pdnscfg .= "		option domain-name \"{$poolconf['domain']}\";\n";
870
			}
871

    
872
			if (!empty($poolconf['domainsearchlist']) && ($poolconf['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
873
				$pdnscfg .= "		option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $poolconf['domainsearchlist'])) . "\";\n";
874
			}
875

    
876
			if (isset($poolconf['ddnsupdate'])) {
877
				if (($poolconf['ddnsdomain'] <> "") && ($poolconf['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
878
					$pdnscfg .= "		ddns-domainname \"{$poolconf['ddnsdomain']}\";\n";
879
				}
880
				$pdnscfg .= "		ddns-update-style interim;\n";
881
			}
882

    
883
			$dhcpdconf .= "{$pdnscfg}";
884

    
885
			// default-lease-time
886
			if ($poolconf['defaultleasetime'] && ($poolconf['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
887
				$dhcpdconf .= "		default-lease-time {$poolconf['defaultleasetime']};\n";
888
			}
889

    
890
			// max-lease-time
891
			if ($poolconf['maxleasetime'] && ($poolconf['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
892
				$dhcpdconf .= "		max-lease-time {$poolconf['maxleasetime']};\n";
893
			}
894

    
895
			// ignore bootp
896
			if (isset($poolconf['ignorebootp'])) {
897
				$dhcpdconf .= "		ignore bootp;\n";
898
			}
899

    
900
			// ignore-client-uids
901
			if (isset($poolconf['ignoreclientuids'])) {
902
				$dhcpdconf .= "		ignore-client-uids true;\n";
903
			}
904

    
905
			// netbios-name*
906
			if (is_array($poolconf['winsserver']) && $poolconf['winsserver'][0] && ($poolconf['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
907
				$dhcpdconf .= "		option netbios-name-servers " . join(",", $poolconf['winsserver']) . ";\n";
908
				$dhcpdconf .= "		option netbios-node-type 8;\n";
909
			}
910

    
911
			// ntp-servers
912
			if (is_array($poolconf['ntpserver']) && $poolconf['ntpserver'][0] && ($poolconf['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
913
				$dhcpdconf .= "		option ntp-servers " . join(",", $poolconf['ntpserver']) . ";\n";
914
			}
915

    
916
			// tftp-server-name
917
			if (!empty($poolconf['tftp']) && ($poolconf['tftp'] != $dhcpifconf['tftp'])) {
918
				$dhcpdconf .= "		option tftp-server-name \"{$poolconf['tftp']}\";\n";
919
			}
920

    
921
			// Handle pool-specific options
922
			$dhcpdconf .= "\n";
923
			// Ignore the first pool, which is the "overall" pool when $all_pools_idx is 0 - those are put outside the pool block later
924
			if ($poolconf['numberoptions']['item'] && ($all_pools_idx > 0)) {
925
				// Use the "real" pool index from the config, excluding the "overall" pool, and based from 0.
926
				// This matches the way $poolidx was used when generating the $custoptions string earlier.
927
				$poolidx = $all_pools_idx - 1;
928
				foreach ($poolconf['numberoptions']['item'] as $itemidx => $item) {
929
					$item_value = base64_decode($item['value']);
930
					if (empty($item['type']) || $item['type'] == "text") {
931
						$dhcpdconf .= "		option custom-{$dhcpif}-{$poolidx}-{$itemidx} \"{$item_value}\";\n";
932
					} else {
933
						$dhcpdconf .= "		option custom-{$dhcpif}-{$poolidx}-{$itemidx} {$item_value};\n";
934
					}
935
				}
936
			}
937

    
938
			// ldap-server
939
			if (!empty($poolconf['ldap']) && ($poolconf['ldap'] != $dhcpifconf['ldap'])) {
940
				$dhcpdconf .= "		option ldap-server \"{$poolconf['ldap']}\";\n";
941
			}
942

    
943
			// net boot information
944
			if (isset($poolconf['netboot'])) {
945
				if (!empty($poolconf['nextserver']) && ($poolconf['nextserver'] != $dhcpifconf['nextserver'])) {
946
					$dhcpdconf .= "		next-server {$poolconf['nextserver']};\n";
947
				}
948
				if (!empty($poolconf['filename']) && ($poolconf['filename'] != $dhcpifconf['filename'])) {
949
					$dhcpdconf .= "		filename \"{$poolconf['filename']}\";\n";
950
				}
951
				if (!empty($poolconf['rootpath']) && ($poolconf['rootpath'] != $dhcpifconf['rootpath'])) {
952
					$dhcpdconf .= "		option root-path \"{$poolconf['rootpath']}\";\n";
953
				}
954
			}
955
			$dhcpdconf .= "		range {$poolconf['range']['from']} {$poolconf['range']['to']};\n";
956
			$dhcpdconf .= "	}\n\n";
957
		}
958
// End of settings inside pools
959

    
960
		if ($dhcpifconf['gateway'] && $dhcpifconf['gateway'] != "none") {
961
			$routers = $dhcpifconf['gateway'];
962
			$add_routers = true;
963
		} elseif ($dhcpifconf['gateway'] == "none") {
964
			$add_routers = false;
965
		} else {
966
			$add_routers = $enable_add_routers;
967
			$routers = $ifcfgip;
968
		}
969
		if ($add_routers) {
970
			$dhcpdconf .= "	option routers {$routers};\n";
971
		}
972

    
973
		$dhcpdconf .= <<<EOD
974
$dnscfg
975

    
976
EOD;
977
		// default-lease-time
978
		if ($dhcpifconf['defaultleasetime']) {
979
			$dhcpdconf .= "	default-lease-time {$dhcpifconf['defaultleasetime']};\n";
980
		}
981

    
982
		// max-lease-time
983
		if ($dhcpifconf['maxleasetime']) {
984
			$dhcpdconf .= "	max-lease-time {$dhcpifconf['maxleasetime']};\n";
985
		}
986

    
987
		// netbios-name*
988
		if (is_array($dhcpifconf['winsserver']) && $dhcpifconf['winsserver'][0]) {
989
			$dhcpdconf .= "	option netbios-name-servers " . join(",", $dhcpifconf['winsserver']) . ";\n";
990
			$dhcpdconf .= "	option netbios-node-type 8;\n";
991
		}
992

    
993
		// ntp-servers
994
		if (is_array($dhcpifconf['ntpserver']) && $dhcpifconf['ntpserver'][0]) {
995
			$dhcpdconf .= "	option ntp-servers " . join(",", $dhcpifconf['ntpserver']) . ";\n";
996
		}
997

    
998
		// tftp-server-name
999
		if ($dhcpifconf['tftp'] <> "") {
1000
			$dhcpdconf .= "	option tftp-server-name \"{$dhcpifconf['tftp']}\";\n";
1001
		}
1002

    
1003
		// Handle option, number rowhelper values
1004
		$dhcpdconf .= "\n";
1005
		if ($dhcpifconf['numberoptions']['item']) {
1006
			foreach ($dhcpifconf['numberoptions']['item'] as $itemidx => $item) {
1007
				$item_value = base64_decode($item['value']);
1008
				if (empty($item['type']) || $item['type'] == "text") {
1009
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} \"{$item_value}\";\n";
1010
				} else {
1011
					$dhcpdconf .= "	option custom-{$dhcpif}-{$itemidx} {$item_value};\n";
1012
				}
1013
			}
1014
		}
1015

    
1016
		// ldap-server
1017
		if ($dhcpifconf['ldap'] <> "") {
1018
			$dhcpdconf .= "	option ldap-server \"{$dhcpifconf['ldap']}\";\n";
1019
		}
1020

    
1021
		// net boot information
1022
		if (isset($dhcpifconf['netboot'])) {
1023
			if ($dhcpifconf['nextserver'] <> "") {
1024
				$dhcpdconf .= "	next-server {$dhcpifconf['nextserver']};\n";
1025
			}
1026
			if (!empty($dhcpifconf['filename']) && !empty($dhcpifconf['filename32']) && !empty($dhcpifconf['filename64'])) {
1027
				$dhcpdconf .= "	if option arch = 00:06 {\n";
1028
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename32']}\";\n";
1029
				$dhcpdconf .= "	} else if option arch = 00:07 {\n";
1030
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
1031
				$dhcpdconf .= "	} else if option arch = 00:09 {\n";
1032
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename64']}\";\n";
1033
				$dhcpdconf .= "	} else {\n";
1034
				$dhcpdconf .= "		filename \"{$dhcpifconf['filename']}\";\n";
1035
				$dhcpdconf .= "	}\n\n";
1036
			} elseif (!empty($dhcpifconf['filename'])) {
1037
				$dhcpdconf .= "	filename \"{$dhcpifconf['filename']}\";\n";
1038
			}
1039
			if (!empty($dhcpifconf['rootpath'])) {
1040
				$dhcpdconf .= "	option root-path \"{$dhcpifconf['rootpath']}\";\n";
1041
			}
1042
		}
1043

    
1044
		$dhcpdconf .= <<<EOD
1045
}
1046

    
1047
EOD;
1048

    
1049
		/* add static mappings */
1050
		if (is_array($dhcpifconf['staticmap'])) {
1051

    
1052
			$i = 0;
1053
			foreach ($dhcpifconf['staticmap'] as $sm) {
1054
				$dhcpdconf .= "host s_{$dhcpif}_{$i} {\n";
1055

    
1056
				if ($sm['mac']) {
1057
					$dhcpdconf .= "        hardware ethernet {$sm['mac']};\n";
1058
				}
1059

    
1060
				if ($sm['cid']) {
1061
					$dhcpdconf .= "        option dhcp-client-identifier \"{$sm['cid']}\";\n";
1062
				}
1063

    
1064
				if ($sm['ipaddr']) {
1065
					$dhcpdconf .= "	fixed-address {$sm['ipaddr']};\n";
1066
				}
1067

    
1068
				if ($sm['hostname']) {
1069
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1070
					$dhhostname = str_replace(".", "_", $dhhostname);
1071
					$dhcpdconf .= "	option host-name \"{$dhhostname}\";\n";
1072
					if ((isset($dhcpifconf['ddnsupdate']) || isset($sm['ddnsupdate'])) && (isset($dhcpifconf['ddnsforcehostname']) || isset($sm['ddnsforcehostname']))) {
1073
						$dhcpdconf .= "	ddns-hostname \"{$dhhostname}\";\n";
1074
					}
1075
				}
1076
				if ($sm['filename']) {
1077
					$dhcpdconf .= "	filename \"{$sm['filename']}\";\n";
1078
				}
1079

    
1080
				if ($sm['rootpath']) {
1081
					$dhcpdconf .= "	option root-path \"{$sm['rootpath']}\";\n";
1082
				}
1083

    
1084
				if ($sm['gateway'] && ($sm['gateway'] != $dhcpifconf['gateway'])) {
1085
					$dhcpdconf .= "	option routers {$sm['gateway']};\n";
1086
				}
1087

    
1088
				$smdnscfg = "";
1089

    
1090
				if ($sm['domain'] && ($sm['domain'] != $dhcpifconf['domain'])) {
1091
					$smdnscfg .= "	option domain-name \"{$sm['domain']}\";\n";
1092
				}
1093

    
1094
				if (!empty($sm['domainsearchlist']) && ($sm['domainsearchlist'] != $dhcpifconf['domainsearchlist'])) {
1095
					$smdnscfg .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $sm['domainsearchlist'])) . "\";\n";
1096
				}
1097

    
1098
				if (isset($sm['ddnsupdate'])) {
1099
					if (($sm['ddnsdomain'] <> "") && ($sm['ddnsdomain'] != $dhcpifconf['ddnsdomain'])) {
1100
						$smdnscfg .= "		ddns-domainname \"{$sm['ddnsdomain']}\";\n";
1101
					}
1102
					$smdnscfg .= "		ddns-update-style interim;\n";
1103
				}
1104

    
1105
				if (is_array($sm['dnsserver']) && ($sm['dnsserver'][0]) && ($sm['dnsserver'][0] != $dhcpifconf['dnsserver'][0])) {
1106
					$smdnscfg .= "	option domain-name-servers " . join(",", $sm['dnsserver']) . ";\n";
1107
				}
1108
				$dhcpdconf .= "{$smdnscfg}";
1109

    
1110
				// default-lease-time
1111
				if ($sm['defaultleasetime'] && ($sm['defaultleasetime'] != $dhcpifconf['defaultleasetime'])) {
1112
					$dhcpdconf .= "	default-lease-time {$sm['defaultleasetime']};\n";
1113
				}
1114

    
1115
				// max-lease-time
1116
				if ($sm['maxleasetime'] && ($sm['maxleasetime'] != $dhcpifconf['maxleasetime'])) {
1117
					$dhcpdconf .= "	max-lease-time {$sm['maxleasetime']};\n";
1118
				}
1119

    
1120
				// netbios-name*
1121
				if (is_array($sm['winsserver']) && $sm['winsserver'][0] && ($sm['winsserver'][0] != $dhcpifconf['winsserver'][0])) {
1122
					$dhcpdconf .= "	option netbios-name-servers " . join(",", $sm['winsserver']) . ";\n";
1123
					$dhcpdconf .= "	option netbios-node-type 8;\n";
1124
				}
1125

    
1126
				// ntp-servers
1127
				if (is_array($sm['ntpserver']) && $sm['ntpserver'][0] && ($sm['ntpserver'][0] != $dhcpifconf['ntpserver'][0])) {
1128
					$dhcpdconf .= "	option ntp-servers " . join(",", $sm['ntpserver']) . ";\n";
1129
				}
1130

    
1131
				// tftp-server-name
1132
				if (!empty($sm['tftp']) && ($sm['tftp'] != $dhcpifconf['tftp'])) {
1133
					$dhcpdconf .= "	option tftp-server-name \"{$sm['tftp']}\";\n";
1134
				}
1135

    
1136
				$dhcpdconf .= "}\n";
1137
				$i++;
1138
			}
1139
		}
1140

    
1141
		$dhcpdifs[] = get_real_interface($dhcpif);
1142
		if ($newzone['domain-name']) {
1143
			if ($need_ddns_updates) {
1144
				$newzone['dns-servers'] = array($dhcpifconf['ddnsdomainprimary']);
1145
				$newzone['ddnsdomainkeyname'] = $dhcpifconf['ddnsdomainkeyname'];
1146
				$newzone['ddnsdomainkey'] = $dhcpifconf['ddnsdomainkey'];
1147
				$dhcpdconf .= dhcpdkey($dhcpifconf);
1148
			}
1149
			$ddns_zones[] = $newzone;
1150
		}
1151
	}
1152

    
1153
	if ($need_ddns_updates) {
1154
		$dhcpdconf .= "ddns-update-style interim;\n";
1155
		$dhcpdconf .= "update-static-leases on;\n";
1156

    
1157
		$dhcpdconf .= dhcpdzones($ddns_zones);
1158
	}
1159

    
1160
	/* write dhcpd.conf */
1161
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpd.conf", $dhcpdconf)) {
1162
		printf(gettext("Error: cannot open dhcpd.conf in services_dhcpdv4_configure().%s"), "\n");
1163
		unset($dhcpdconf);
1164
		return 1;
1165
	}
1166
	unset($dhcpdconf);
1167

    
1168
	/* create an empty leases database */
1169
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases")) {
1170
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases");
1171
	}
1172

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

    
1177
	/* fire up dhcpd in a chroot */
1178
	if (count($dhcpdifs) > 0) {
1179
		mwexec("/usr/local/sbin/dhcpd -user dhcpd -group _dhcp -chroot {$g['dhcpd_chroot_path']} -cf /etc/dhcpd.conf -pf {$g['varrun_path']}/dhcpd.pid " .
1180
			join(" ", $dhcpdifs));
1181
	}
1182

    
1183
	if (platform_booting()) {
1184
		print "done.\n";
1185
	}
1186

    
1187
	return 0;
1188
}
1189

    
1190
function dhcpdkey($dhcpifconf) {
1191
	$dhcpdconf = "";
1192
	if ($dhcpifconf['ddnsdomainkeyname'] <> "" && $dhcpifconf['ddnsdomainkey'] <> "") {
1193
		$dhcpdconf .= "key {$dhcpifconf['ddnsdomainkeyname']} {\n";
1194
		$dhcpdconf .= "	algorithm hmac-md5;\n";
1195
		$dhcpdconf .= "	secret {$dhcpifconf['ddnsdomainkey']};\n";
1196
		$dhcpdconf .= "}\n";
1197
	}
1198

    
1199
	return $dhcpdconf;
1200
}
1201

    
1202
function dhcpdzones($ddns_zones) {
1203
	$dhcpdconf = "";
1204

    
1205
	if (is_array($ddns_zones)) {
1206
		$added_zones = array();
1207
		foreach ($ddns_zones as $zone) {
1208
			if (!is_array($zone) || empty($zone) || !is_array($zone['dns-servers'])) {
1209
				continue;
1210
			}
1211
			$primary = $zone['dns-servers'][0];
1212
			$secondary = empty($zone['dns-servers'][1]) ? "" : $zone['dns-servers'][1];
1213

    
1214
			// Make sure we aren't using any invalid or IPv6 DNS servers.
1215
			if (!is_ipaddrv4($primary)) {
1216
				if (is_ipaddrv4($secondary)) {
1217
					$primary = $secondary;
1218
					$secondary = "";
1219
				} else {
1220
					continue;
1221
				}
1222
			}
1223

    
1224
			// We don't need to add zones multiple times.
1225
			if ($zone['domain-name'] && !in_array($zone['domain-name'], $added_zones)) {
1226
				$dhcpdconf .= "zone {$zone['domain-name']}. {\n";
1227
				$dhcpdconf .= "	primary {$primary};\n";
1228
				if (is_ipaddrv4($secondary)) {
1229
					$dhcpdconf .= "	secondary {$secondary};\n";
1230
				}
1231
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1232
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1233
				}
1234
				$dhcpdconf .= "}\n";
1235
				$added_zones[] = $zone['domain-name'];
1236
			}
1237
			if ($zone['ptr-domain'] && !in_array($zone['ptr-domain'], $added_zones)) {
1238
				$dhcpdconf .= "zone {$zone['ptr-domain']} {\n";
1239
				$dhcpdconf .= "	primary {$primary};\n";
1240
				if (is_ipaddrv4($secondary)) {
1241
					$dhcpdconf .= "	secondary {$secondary};\n";
1242
				}
1243
				if ($zone['ddnsdomainkeyname'] <> "" && $zone['ddnsdomainkey'] <> "") {
1244
					$dhcpdconf .= "	key {$zone['ddnsdomainkeyname']};\n";
1245
				}
1246
				$dhcpdconf .= "}\n";
1247
				$added_zones[] = $zone['ptr-domain'];
1248
			}
1249
		}
1250
	}
1251

    
1252
	return $dhcpdconf;
1253
}
1254

    
1255
function services_dhcpdv6_configure($blacklist = array()) {
1256
	global $config, $g;
1257

    
1258
	if ($g['services_dhcp_server_enable'] == false) {
1259
		return;
1260
	}
1261

    
1262
	if (isset($config['system']['developerspew'])) {
1263
		$mt = microtime();
1264
		echo "services_dhcpd_configure($if) being called $mt\n";
1265
	}
1266

    
1267
	/* kill any running dhcpd */
1268
	if (isvalidpid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid")) {
1269
		killbypid("{$g['dhcpd_chroot_path']}{$g['varrun_path']}/dhcpdv6.pid");
1270
	}
1271
	if (isvalidpid("{$g['varrun_path']}/dhcpleases6.pid")) {
1272
		killbypid("{$g['varrun_path']}/dhcpleases6.pid");
1273
	}
1274

    
1275
	/* DHCP enabled on any interfaces? */
1276
	if (!is_dhcpv6_server_enabled()) {
1277
		return 0;
1278
	}
1279

    
1280
	/* restore the leases, if we have them */
1281
	if (platform_booting() &&
1282
	    isset($config['system']['use_mfs_tmpvar']) &&
1283
	    file_exists("{$g['cf_conf_path']}/dhcp6leases.tgz")) {
1284
		$dhcprestore = "";
1285
		$dhcpreturn = "";
1286
		exec("cd /;LANG=C /usr/bin/tar -xzf {$g['cf_conf_path']}/dhcp6leases.tgz 2>&1",
1287
		    $dhcprestore, $dhcpreturn);
1288
		$dhcprestore = implode(" ", $dhcprestore);
1289
		if ($dhcpreturn <> 0) {
1290
			log_error(sprintf(gettext(
1291
			    'DHCP leases v6 restore failed exited with %1$s, the error is: %2$s'),
1292
			    $dhcpreturn, $dhcprestore));
1293
		}
1294
	}
1295

    
1296
	$syscfg = $config['system'];
1297
	if (!is_array($config['dhcpdv6'])) {
1298
		$config['dhcpdv6'] = array();
1299
	}
1300
	$dhcpdv6cfg = $config['dhcpdv6'];
1301
	$Iflist = get_configured_interface_list();
1302
	$Iflist = array_merge($Iflist, get_configured_pppoe_server_interfaces());
1303

    
1304

    
1305
	if (platform_booting()) {
1306
		echo "Starting DHCPv6 service...";
1307
	} else {
1308
		sleep(1);
1309
	}
1310

    
1311
	$custoptionsv6 = "";
1312
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1313
		if (is_array($dhcpv6ifconf['numberoptions']) && is_array($dhcpv6ifconf['numberoptions']['item'])) {
1314
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1315
				$custoptionsv6 .= "option custom-{$dhcpv6if}-{$itemv6idx} code {$itemv6['number']} = text;\n";
1316
			}
1317
		}
1318
	}
1319

    
1320
	if (isset($dhcpv6ifconf['netboot']) && !empty($dhcpv6ifconf['bootfile_url'])) {
1321
		$custoptionsv6 .= "option dhcp6.bootfile-url code 59 = string;\n";
1322
	}
1323

    
1324
	$dhcpdv6conf = <<<EOD
1325

    
1326
option domain-name "{$syscfg['domain']}";
1327
option ldap-server code 95 = text;
1328
option domain-search-list code 119 = text;
1329
{$custoptionsv6}
1330
default-lease-time 7200;
1331
max-lease-time 86400;
1332
log-facility local7;
1333
one-lease-per-client true;
1334
deny duplicates;
1335
ping-check true;
1336
update-conflict-detection false;
1337

    
1338
EOD;
1339

    
1340
	if (!isset($dhcpv6ifconf['disableauthoritative'])) {
1341
		$dhcpdv6conf .= "authoritative;\n";
1342
	}
1343

    
1344
	if (isset($dhcpv6ifconf['alwaysbroadcast'])) {
1345
		$dhcpdv6conf .= "always-broadcast on\n";
1346
	}
1347

    
1348
	$dhcpdv6ifs = array();
1349

    
1350
	$dhcpv6num = 0;
1351
	$nsupdate = false;
1352

    
1353
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1354

    
1355
		$ddns_zones = array();
1356

    
1357
		$ifcfgv6 = $config['interfaces'][$dhcpv6if];
1358

    
1359
		if (!isset($dhcpv6ifconf['enable']) || !isset($Iflist[$dhcpv6if]) || !isset($ifcfgv6['enable'])) {
1360
			continue;
1361
		}
1362
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1363
		if (!is_ipaddrv6($ifcfgipv6)) {
1364
			continue;
1365
		}
1366
		$ifcfgsnv6 = get_interface_subnetv6($dhcpv6if);
1367
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1368
		// We might have some prefix-delegation on WAN (e.g. /48),
1369
		// but then it is split and given out to individual interfaces
1370
		// (LAN, OPT1, OPT2...) as multiple /64 subnets. So the size
1371
		// of each subnet here is always /64.
1372
		$pdlen = 64;
1373

    
1374
		if ($is_olsr_enabled == true) {
1375
			if ($dhcpv6ifconf['netmask']) {
1376
				$subnetmask = gen_subnet_maskv6($dhcpv6ifconf['netmask']);
1377
			}
1378
		}
1379

    
1380
		$dnscfgv6 = "";
1381

    
1382
		if ($dhcpv6ifconf['domain']) {
1383
			$dnscfgv6 .= "	option domain-name \"{$dhcpv6ifconf['domain']}\";\n";
1384
		}
1385

    
1386
		if ($dhcpv6ifconf['domainsearchlist'] <> "") {
1387
			$dnscfgv6 .= "	option domain-search \"" . join("\",\"", preg_split("/[ ;]+/", $dhcpv6ifconf['domainsearchlist'])) . "\";\n";
1388
		}
1389

    
1390
		if (isset($dhcpv6ifconf['ddnsupdate'])) {
1391
			if ($dhcpv6ifconf['ddnsdomain'] <> "") {
1392
				$dnscfgv6 .= "	ddns-domainname \"{$dhcpv6ifconf['ddnsdomain']}\";\n";
1393
			}
1394
			if (empty($dhcpv6ifconf['ddnsclientupdates'])) {
1395
				$ddnsclientupdates = 'allow';
1396
			} else {
1397
				$ddnsclientupdates = $dhcpv6ifconf['ddnsclientupdates'];
1398
			}
1399
			$dnscfgv6 .= "	{$ddnsclientupdates} client-updates;\n";
1400
			$nsupdate = true;
1401
		} else {
1402
			$dnscfgv6 .= "	do-forward-updates false;\n";
1403
		}
1404

    
1405
		if (is_array($dhcpv6ifconf['dnsserver']) && ($dhcpv6ifconf['dnsserver'][0])) {
1406
			$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dhcpv6ifconf['dnsserver']) . ";";
1407
		} else if (((isset($config['dnsmasq']['enable'])) || isset($config['unbound']['enable'])) && (is_ipaddrv6($ifcfgipv6))) {
1408
			$dnscfgv6 .= "	option dhcp6.name-servers {$ifcfgipv6};";
1409
		} else if (is_array($syscfg['dnsserver']) && ($syscfg['dnsserver'][0])) {
1410
			$dns_arrv6 = array();
1411
			foreach ($syscfg['dnsserver'] as $dnsserver) {
1412
				if (is_ipaddrv6($dnsserver)) {
1413
					$dns_arrv6[] = $dnsserver;
1414
				}
1415
			}
1416
			if (!empty($dns_arrv6)) {
1417
				$dnscfgv6 .= "	option dhcp6.name-servers " . join(",", $dns_arrv6) . ";";
1418
			}
1419
		}
1420

    
1421
		if (!is_ipaddrv6($ifcfgipv6)) {
1422
			$ifcfgsnv6 = "64";
1423
			$subnetv6 = gen_subnetv6($dhcpv6ifconf['range']['from'], $ifcfgsnv6);
1424
		}
1425

    
1426
		$dhcpdv6conf .= "subnet6 {$subnetv6}/{$ifcfgsnv6}";
1427

    
1428
		if (isset($dhcpv6ifconf['ddnsupdate']) &&
1429
		    !empty($dhcpv6ifconf['ddnsdomain'])) {
1430
			$newzone = array();
1431
			$newzone['domain-name'] = $dhcpv6ifconf['ddnsdomain'];
1432
			$newzone['dns-servers'][] = $dhcpv6ifconf['ddnsdomainprimary'];
1433
			$newzone['ddnsdomainkeyname'] = $dhcpv6ifconf['ddnsdomainkeyname'];
1434
			$newzone['ddnsdomainkey'] = $dhcpv6ifconf['ddnsdomainkey'];
1435
			$ddns_zones[] = $newzone;
1436
			if (isset($dhcpv6ifconf['ddnsreverse'])) {
1437
				$ptr_zones = get_v6_ptr_zones($subnetv6, $ifcfgsnv6);
1438
				foreach ($ptr_zones as $ptr_zone) {
1439
					$reversezone = array();
1440
					$reversezone['domain-name'] = $ptr_zone;
1441
					$reversezone['dns-servers'][] =
1442
					    $dhcpv6ifconf['ddnsdomainprimary'];
1443
					$ddns_zones[] = $reversezone;
1444
				}
1445
			}
1446
		}
1447

    
1448
		$dhcpdv6conf .= " {\n";
1449

    
1450
		$range_from = $dhcpv6ifconf['range']['from'];
1451
		$range_to = $dhcpv6ifconf['range']['to'];
1452
		if ($ifcfgv6['ipaddrv6'] == 'track6') {
1453
			$range_from = merge_ipv6_delegated_prefix($ifcfgipv6, $range_from, $pdlen);
1454
			$range_to = merge_ipv6_delegated_prefix($ifcfgipv6, $range_to, $pdlen);
1455
		}
1456

    
1457
		$dhcpdv6conf .= <<<EOD
1458
	range6 {$range_from} {$range_to};
1459
$dnscfgv6
1460

    
1461
EOD;
1462

    
1463
		if (is_ipaddrv6($dhcpv6ifconf['prefixrange']['from']) && is_ipaddrv6($dhcpv6ifconf['prefixrange']['to'])) {
1464
			$dhcpdv6conf .= "	prefix6 {$dhcpv6ifconf['prefixrange']['from']} {$dhcpv6ifconf['prefixrange']['to']} /{$dhcpv6ifconf['prefixrange']['prefixlength']};\n";
1465
		}
1466
		if (is_ipaddrv6($dhcpv6ifconf['dns6ip'])) {
1467
			$dns6ip = $dhcpv6ifconf['dns6ip'];
1468
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1469
			    Net_IPv6::isInNetmask($dns6ip, '::', $pdlen)) {
1470
				$dns6ip = merge_ipv6_delegated_prefix($ifcfgipv6, $dns6ip, $pdlen);
1471
			}
1472
			$dhcpdv6conf .= "	option dhcp6.name-servers {$dns6ip};\n";
1473
		}
1474
		// default-lease-time
1475
		if ($dhcpv6ifconf['defaultleasetime']) {
1476
			$dhcpdv6conf .= "	default-lease-time {$dhcpv6ifconf['defaultleasetime']};\n";
1477
		}
1478

    
1479
		// max-lease-time
1480
		if ($dhcpv6ifconf['maxleasetime']) {
1481
			$dhcpdv6conf .= "	max-lease-time {$dhcpv6ifconf['maxleasetime']};\n";
1482
		}
1483

    
1484
		// ntp-servers
1485
		if (is_array($dhcpv6ifconf['ntpserver']) && $dhcpv6ifconf['ntpserver'][0]) {
1486
			$ntpservers = array();
1487
			foreach ($dhcpv6ifconf['ntpserver'] as $ntpserver) {
1488
				if (!is_ipaddrv6($ntpserver)) {
1489
					continue;
1490
				}
1491
				if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1492
				    Net_IPv6::isInNetmask($ntpserver, '::', $pdlen)) {
1493
					$ntpserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ntpserver, $pdlen);
1494
				}
1495
				$ntpservers[] = $ntpserver;
1496
			}
1497
			if (count($ntpservers) > 0) {
1498
				$dhcpdv6conf .= "        option dhcp6.sntp-servers " . join(",", $dhcpv6ifconf['ntpserver']) . ";\n";
1499
			}
1500
		}
1501
		// tftp-server-name
1502
		/* Needs ISC DHCPD support
1503
		 if ($dhcpv6ifconf['tftp'] <> "") {
1504
			$dhcpdv6conf .= "	option tftp-server-name \"{$dhcpv6ifconf['tftp']}\";\n";
1505
		 }
1506
		*/
1507

    
1508
		// Handle option, number rowhelper values
1509
		$dhcpdv6conf .= "\n";
1510
		if ($dhcpv6ifconf['numberoptions']['item']) {
1511
			foreach ($dhcpv6ifconf['numberoptions']['item'] as $itemv6idx => $itemv6) {
1512
				$itemv6_value = base64_decode($itemv6['value']);
1513
				$dhcpdv6conf .= "	option custom-{$dhcpv6if}-{$itemv6idx} \"{$itemv6_value}\";\n";
1514
			}
1515
		}
1516

    
1517
		// ldap-server
1518
		if ($dhcpv6ifconf['ldap'] <> "") {
1519
			$ldapserver = $dhcpv6ifconf['ldap'];
1520
			if ($ifcfgv6['ipaddrv6'] == 'track6' &&
1521
			    Net_IPv6::isInNetmask($ldapserver, '::', $pdlen)) {
1522
				$ldapserver = merge_ipv6_delegated_prefix($ifcfgipv6, $ldapserver, $pdlen);
1523
			}
1524
			$dhcpdv6conf .= "	option ldap-server \"{$ldapserver}\";\n";
1525
		}
1526

    
1527
		// net boot information
1528
		if (isset($dhcpv6ifconf['netboot'])) {
1529
			if (!empty($dhcpv6ifconf['bootfile_url'])) {
1530
				$dhcpdv6conf .= "	option dhcp6.bootfile-url \"{$dhcpv6ifconf['bootfile_url']}\";\n";
1531
			}
1532
		}
1533

    
1534
		$dhcpdv6conf .= "}\n";
1535

    
1536
		/* add static mappings */
1537
		/* Needs to use DUID */
1538
		if (is_array($dhcpv6ifconf['staticmap'])) {
1539
			$i = 0;
1540
			foreach ($dhcpv6ifconf['staticmap'] as $sm) {
1541
				$dhcpdv6conf .= <<<EOD
1542
host s_{$dhcpv6if}_{$i} {
1543
	host-identifier option dhcp6.client-id {$sm['duid']};
1544

    
1545
EOD;
1546
				if ($sm['ipaddrv6']) {
1547
					$ipaddrv6 = $sm['ipaddrv6'];
1548
					if ($ifcfgv6['ipaddrv6'] == 'track6') {
1549
						$ipaddrv6 = merge_ipv6_delegated_prefix($ifcfgipv6, $ipaddrv6, $pdlen);
1550
					}
1551
					$dhcpdv6conf .= "	fixed-address6 {$ipaddrv6};\n";
1552
				}
1553

    
1554
				if ($sm['hostname']) {
1555
					$dhhostname = str_replace(" ", "_", $sm['hostname']);
1556
					$dhhostname = str_replace(".", "_", $dhhostname);
1557
					$dhcpdv6conf .= "	option host-name {$dhhostname};\n";
1558
				}
1559
				if ($sm['filename']) {
1560
					$dhcpdv6conf .= "	filename \"{$sm['filename']}\";\n";
1561
				}
1562

    
1563
				if ($sm['rootpath']) {
1564
					$dhcpdv6conf .= "	option root-path \"{$sm['rootpath']}\";\n";
1565
				}
1566

    
1567
				$dhcpdv6conf .= "}\n";
1568
				$i++;
1569
			}
1570
		}
1571

    
1572
		if ($dhcpv6ifconf['ddnsdomain']) {
1573
			$dhcpdv6conf .= dhcpdkey($dhcpv6ifconf);
1574
			$dhcpdv6conf .= dhcpdzones($ddns_zones);
1575
		}
1576

    
1577
		if ($config['dhcpdv6'][$dhcpv6if]['ramode'] <> "unmanaged" && isset($config['interfaces'][$dhcpv6if]['enable'])) {
1578
			if (preg_match("/poes/si", $dhcpv6if)) {
1579
				/* magic here */
1580
				$dhcpdv6ifs = array_merge($dhcpdv6ifs, get_pppoes_child_interfaces($dhcpv6if));
1581
			} else {
1582
				$realif = get_real_interface($dhcpv6if, "inet6");
1583
				if (stristr("$realif", "bridge")) {
1584
					$mac = get_interface_mac($realif);
1585
					$v6address = generate_ipv6_from_mac($mac);
1586
					/* Create link local address for bridges */
1587
					mwexec("/sbin/ifconfig {$realif} inet6 {$v6address}");
1588
				}
1589
				$realif = escapeshellcmd($realif);
1590
				$dhcpdv6ifs[] = $realif;
1591
			}
1592
		}
1593
	}
1594

    
1595
	if ($nsupdate) {
1596
		$dhcpdv6conf .= "ddns-update-style interim;\n";
1597
	} else {
1598
		$dhcpdv6conf .= "ddns-update-style none;\n";
1599
	}
1600

    
1601
	/* write dhcpdv6.conf */
1602
	if (!@file_put_contents("{$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf", $dhcpdv6conf)) {
1603
		log_error("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1604
		if (platform_booting()) {
1605
			printf("Error: cannot open {$g['dhcpd_chroot_path']}/etc/dhcpdv6.conf in services_dhcpdv6_configure().\n");
1606
		}
1607
		unset($dhcpdv6conf);
1608
		return 1;
1609
	}
1610
	unset($dhcpdv6conf);
1611

    
1612
	/* create an empty leases v6 database */
1613
	if (!file_exists("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases")) {
1614
		@touch("{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1615
	}
1616

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

    
1621
	/* fire up dhcpd in a chroot */
1622
	if (count($dhcpdv6ifs) > 0) {
1623
		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 " .
1624
			join(" ", $dhcpdv6ifs));
1625
		mwexec("/usr/local/sbin/dhcpleases6 -c \"/usr/local/bin/php-cgi -f /usr/local/sbin/prefixes.php|/bin/sh\" -l {$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases");
1626
	}
1627
	if (platform_booting()) {
1628
		print gettext("done.") . "\n";
1629
	}
1630

    
1631
	return 0;
1632
}
1633

    
1634
function services_igmpproxy_configure() {
1635
	global $config, $g;
1636

    
1637
	/* kill any running igmpproxy */
1638
	killbyname("igmpproxy");
1639

    
1640
	if (!is_array($config['igmpproxy']['igmpentry']) || (count($config['igmpproxy']['igmpentry']) == 0)) {
1641
		return 1;
1642
	}
1643

    
1644
	$iflist = get_configured_interface_list();
1645

    
1646
	$igmpconf = <<<EOD
1647

    
1648
##------------------------------------------------------
1649
## Enable Quickleave mode (Sends Leave instantly)
1650
##------------------------------------------------------
1651
quickleave
1652

    
1653
EOD;
1654

    
1655
	foreach ($config['igmpproxy']['igmpentry'] as $igmpcf) {
1656
		unset($iflist[$igmpcf['ifname']]);
1657
		$realif = get_real_interface($igmpcf['ifname']);
1658
		if (empty($igmpcf['threshold'])) {
1659
			$threshld = 1;
1660
		} else {
1661
			$threshld = $igmpcf['threshold'];
1662
		}
1663
		$igmpconf .= "phyint {$realif} {$igmpcf['type']} ratelimit 0 threshold {$threshld}\n";
1664

    
1665
		if ($igmpcf['address'] <> "") {
1666
			$item = explode(" ", $igmpcf['address']);
1667
			foreach ($item as $iww) {
1668
				$igmpconf .= "altnet {$iww}\n";
1669
			}
1670
		}
1671
		$igmpconf .= "\n";
1672
	}
1673
	foreach ($iflist as $ifn) {
1674
		$realif = get_real_interface($ifn);
1675
		$igmpconf .= "phyint {$realif} disabled\n";
1676
	}
1677
	$igmpconf .= "\n";
1678

    
1679
	$igmpfl = fopen($g['varetc_path'] . "/igmpproxy.conf", "w");
1680
	if (!$igmpfl) {
1681
		log_error(gettext("Could not write Igmpproxy configuration file!"));
1682
		return;
1683
	}
1684
	fwrite($igmpfl, $igmpconf);
1685
	fclose($igmpfl);
1686
	unset($igmpconf);
1687

    
1688
	if (isset($config['syslog']['igmpxverbose'])) {
1689
		mwexec_bg("/usr/local/sbin/igmpproxy -v {$g['varetc_path']}/igmpproxy.conf");
1690
	} else {
1691
		mwexec_bg("/usr/local/sbin/igmpproxy {$g['varetc_path']}/igmpproxy.conf");
1692
	}
1693

    
1694
	log_error(gettext("Started IGMP proxy service."));
1695

    
1696
	return 0;
1697
}
1698

    
1699
function services_dhcrelay_configure() {
1700
	global $config, $g;
1701

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

    
1707
	/* kill any running dhcrelay */
1708
	killbypid("{$g['varrun_path']}/dhcrelay.pid");
1709

    
1710
	$dhcrelaycfg =& $config['dhcrelay'];
1711

    
1712
	/* DHCPRelay enabled on any interfaces? */
1713
	if (!isset($dhcrelaycfg['enable'])) {
1714
		return 0;
1715
	}
1716

    
1717
	if (platform_booting()) {
1718
		echo gettext("Starting DHCP relay service...");
1719
	} else {
1720
		sleep(1);
1721
	}
1722

    
1723
	$iflist = get_configured_interface_list();
1724

    
1725
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1726
	foreach ($dhcifaces as $dhcrelayif) {
1727
		if (!isset($iflist[$dhcrelayif]) ||
1728
		    link_interface_to_bridge($dhcrelayif)) {
1729
			continue;
1730
		}
1731

    
1732
		if (is_ipaddr(get_interface_ip($dhcrelayif))) {
1733
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1734
		}
1735
	}
1736

    
1737
	/*
1738
	 * In order for the relay to work, it needs to be active
1739
	 * on the interface in which the destination server sits.
1740
	 */
1741
	$srvips = explode(",", $dhcrelaycfg['server']);
1742
	if (!is_array($srvips)) {
1743
		log_error(gettext("No destination IP has been configured!"));
1744
		return;
1745
	}
1746

    
1747
	foreach ($srvips as $srcidx => $srvip) {
1748
		unset($destif);
1749
		foreach ($iflist as $ifname) {
1750
			$subnet = get_interface_ip($ifname);
1751
			if (!is_ipaddr($subnet)) {
1752
				continue;
1753
			}
1754
			$subnet .= "/" . get_interface_subnet($ifname);
1755
			if (ip_in_subnet($srvip, $subnet)) {
1756
				$destif = get_real_interface($ifname);
1757
				break;
1758
			}
1759
		}
1760
		if (!isset($destif)) {
1761
			// For each enabled static route
1762
			foreach (get_staticroutes(false, false, true) as $rtent) {
1763
				if (ip_in_subnet($srvip, $rtent['network'])) {
1764
					$a_gateways = return_gateways_array(true);
1765
					$destif = $a_gateways[$rtent['gateway']]['interface'];
1766
					break;
1767
				}
1768
			}
1769
		}
1770

    
1771
		if (!isset($destif)) {
1772
			/* Create a array from the existing route table */
1773
			exec("/usr/bin/netstat -rnWf inet", $route_str);
1774
			array_shift($route_str);
1775
			array_shift($route_str);
1776
			array_shift($route_str);
1777
			array_shift($route_str);
1778
			$route_arr = array();
1779
			foreach ($route_str as $routeline) {
1780
				$items = preg_split("/[ ]+/i", $routeline);
1781
				if (is_subnetv4($items[0])) {
1782
					$subnet = $items[0];
1783
				} elseif (is_ipaddrv4($items[0])) {
1784
					$subnet = "{$items[0]}/32";
1785
				} else {
1786
					// Not a subnet or IP address, skip to the next line.
1787
					continue;
1788
				}
1789
				if (ip_in_subnet($srvip, $subnet)) {
1790
					$destif = trim($items[6]);
1791
					break;
1792
				}
1793
			}
1794
		}
1795

    
1796
		if (!isset($destif)) {
1797
			if (is_array($config['gateways']['gateway_item'])) {
1798
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1799
					if (isset($gateway['defaultgw'])) {
1800
						$destif = get_real_interface($gateway['interface']);
1801
						break;
1802
					}
1803
				}
1804
			} else {
1805
				$destif = get_real_interface("wan");
1806
			}
1807
		}
1808

    
1809
		if (!empty($destif)) {
1810
			$dhcrelayifs[] = $destif;
1811
		}
1812
	}
1813
	$dhcrelayifs = array_unique($dhcrelayifs);
1814

    
1815
	/* fire up dhcrelay */
1816
	if (empty($dhcrelayifs)) {
1817
		log_error(gettext("No suitable interface found for running dhcrelay!"));
1818
		return; /* XXX */
1819
	}
1820

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

    
1823
	if (isset($dhcrelaycfg['agentoption'])) {
1824
		$cmd .= " -a -m replace";
1825
	}
1826

    
1827
	$cmd .= " " . implode(" ", $srvips);
1828
	mwexec($cmd);
1829
	unset($cmd);
1830

    
1831
	return 0;
1832
}
1833

    
1834
function services_dhcrelay6_configure() {
1835
	global $config, $g;
1836

    
1837
	if (isset($config['system']['developerspew'])) {
1838
		$mt = microtime();
1839
		echo "services_dhcrelay6_configure() being called $mt\n";
1840
	}
1841

    
1842
	/* kill any running dhcrelay */
1843
	killbypid("{$g['varrun_path']}/dhcrelay6.pid");
1844

    
1845
	$dhcrelaycfg =& $config['dhcrelay6'];
1846

    
1847
	/* DHCPv6 Relay enabled on any interfaces? */
1848
	if (!isset($dhcrelaycfg['enable'])) {
1849
		return 0;
1850
	}
1851

    
1852
	if (platform_booting()) {
1853
		echo gettext("Starting DHCPv6 relay service...");
1854
	} else {
1855
		sleep(1);
1856
	}
1857

    
1858
	$iflist = get_configured_interface_list();
1859

    
1860
	$dhcifaces = explode(",", $dhcrelaycfg['interface']);
1861
	foreach ($dhcifaces as $dhcrelayif) {
1862
		if (!isset($iflist[$dhcrelayif]) ||
1863
		    link_interface_to_bridge($dhcrelayif)) {
1864
			continue;
1865
		}
1866

    
1867
		if (is_ipaddrv6(get_interface_ipv6($dhcrelayif))) {
1868
			$dhcrelayifs[] = get_real_interface($dhcrelayif);
1869
		}
1870
	}
1871
	$dhcrelayifs = array_unique($dhcrelayifs);
1872

    
1873
	/*
1874
	 * In order for the relay to work, it needs to be active
1875
	 * on the interface in which the destination server sits.
1876
	 */
1877
	$srvips = explode(",", $dhcrelaycfg['server']);
1878
	$srvifaces = array();
1879
	foreach ($srvips as $srcidx => $srvip) {
1880
		unset($destif);
1881
		foreach ($iflist as $ifname) {
1882
			$subnet = get_interface_ipv6($ifname);
1883
			if (!is_ipaddrv6($subnet)) {
1884
				continue;
1885
			}
1886
			$subnet .= "/" . get_interface_subnetv6($ifname);
1887
			if (ip_in_subnet($srvip, $subnet)) {
1888
				$destif = get_real_interface($ifname);
1889
				break;
1890
			}
1891
		}
1892
		if (!isset($destif)) {
1893
			if (is_array($config['staticroutes']['route'])) {
1894
				foreach ($config['staticroutes']['route'] as $rtent) {
1895
					if (isset($rtent['disabled'])) {
1896
						continue;
1897
					}
1898
					if (ip_in_subnet($srvip, $rtent['network'])) {
1899
						$a_gateways = return_gateways_array(true);
1900
						$destif = $a_gateways[$rtent['gateway']]['interface'];
1901
						break;
1902
					}
1903
				}
1904
			}
1905
		}
1906

    
1907
		if (!isset($destif)) {
1908
			/* Create a array from the existing route table */
1909
			exec("/usr/bin/netstat -rnWf inet6", $route_str);
1910
			array_shift($route_str);
1911
			array_shift($route_str);
1912
			array_shift($route_str);
1913
			array_shift($route_str);
1914
			$route_arr = array();
1915
			foreach ($route_str as $routeline) {
1916
				$items = preg_split("/[ ]+/i", $routeline);
1917
				if (ip_in_subnet($srvip, $items[0])) {
1918
					$destif = trim($items[6]);
1919
					break;
1920
				}
1921
			}
1922
		}
1923

    
1924
		if (!isset($destif)) {
1925
			if (is_array($config['gateways']['gateway_item'])) {
1926
				foreach ($config['gateways']['gateway_item'] as $gateway) {
1927
					if (isset($gateway['defaultgw'])) {
1928
						$destif = get_real_interface($gateway['interface']);
1929
						break;
1930
					}
1931
				}
1932
			} else {
1933
				$destif = get_real_interface("wan");
1934
			}
1935
		}
1936

    
1937
		if (!empty($destif)) {
1938
			$srvifaces[] = "{$srvip}%{$destif}";
1939
		}
1940
	}
1941

    
1942
	/* fire up dhcrelay */
1943
	if (empty($dhcrelayifs) || empty($srvifaces)) {
1944
		log_error(gettext("No suitable interface found for running dhcrelay -6!"));
1945
		return; /* XXX */
1946
	}
1947

    
1948
	$cmd = "/usr/local/sbin/dhcrelay -6 -pf \"{$g['varrun_path']}/dhcrelay6.pid\"";
1949
	foreach ($dhcrelayifs as $dhcrelayif) {
1950
		$cmd .= " -l {$dhcrelayif}";
1951
	}
1952
	foreach ($srvifaces as $srviface) {
1953
		$cmd .= " -u \"{$srviface}\"";
1954
	}
1955
	mwexec($cmd);
1956
	unset($cmd);
1957

    
1958
	return 0;
1959
}
1960

    
1961
function services_dyndns_configure_client($conf) {
1962

    
1963
	if (!isset($conf['enable'])) {
1964
		return;
1965
	}
1966

    
1967
	/* load up the dyndns.class */
1968
	require_once("dyndns.class");
1969

    
1970
	$dns = new updatedns($dnsService = $conf['type'],
1971
		$dnsHost = $conf['host'],
1972
		$dnsDomain = $conf['domainname'],
1973
		$dnsUser = $conf['username'],
1974
		$dnsPass = $conf['password'],
1975
		$dnsWildcard = $conf['wildcard'],
1976
		$dnsProxied = $conf['proxied'],
1977
		$dnsMX = $conf['mx'],
1978
		$dnsIf = "{$conf['interface']}",
1979
		$dnsBackMX = NULL,
1980
		$dnsServer = NULL,
1981
		$dnsPort = NULL,
1982
		$dnsUpdateURL = "{$conf['updateurl']}",
1983
		$forceUpdate = $conf['force'],
1984
		$dnsZoneID = $conf['zoneid'],
1985
		$dnsTTL = $conf['ttl'],
1986
		$dnsResultMatch = "{$conf['resultmatch']}",
1987
		$dnsRequestIf = "{$conf['requestif']}",
1988
		$dnsID = "{$conf['id']}",
1989
		$dnsVerboseLog = $conf['verboselog'],
1990
		$curlIpresolveV4 = $conf['curl_ipresolve_v4'],
1991
		$curlSslVerifypeer = $conf['curl_ssl_verifypeer']);
1992
}
1993

    
1994
function services_dyndns_configure($int = "") {
1995
	global $config, $g;
1996
	if (isset($config['system']['developerspew'])) {
1997
		$mt = microtime();
1998
		echo "services_dyndns_configure() being called $mt\n";
1999
	}
2000

    
2001
	$dyndnscfg = $config['dyndnses']['dyndns'];
2002
	$gwgroups = return_gateway_groups_array();
2003
	if (is_array($dyndnscfg)) {
2004
		if (platform_booting()) {
2005
			echo gettext("Starting DynDNS clients...");
2006
		}
2007

    
2008
		foreach ($dyndnscfg as $dyndns) {
2009
			/*
2010
			 * If it's using a gateway group, check if interface is
2011
			 * the active gateway for that group
2012
			 */
2013
			$group_int = '';
2014
			if (is_array($gwgroups[$dyndns['interface']])) {
2015
				if (!empty($gwgroups[$dyndns['interface']][0]['vip'])) {
2016
					$group_int = $gwgroups[$dyndns['interface']][0]['vip'];
2017
				} else {
2018
					$group_int = $gwgroups[$dyndns['interface']][0]['int'];
2019
				}
2020
			}
2021
			if ((empty($int)) || ($int == $dyndns['interface']) || ($int == $group_int)) {
2022
				$dyndns['verboselog'] = isset($dyndns['verboselog']);
2023
				$dyndns['curl_ipresolve_v4'] = isset($dyndns['curl_ipresolve_v4']);
2024
				$dyndns['curl_ssl_verifypeer'] = isset($dyndns['curl_ssl_verifypeer']);
2025
				services_dyndns_configure_client($dyndns);
2026
				sleep(1);
2027
			}
2028
		}
2029

    
2030
		if (platform_booting()) {
2031
			echo gettext("done.") . "\n";
2032
		}
2033
	}
2034

    
2035
	return 0;
2036
}
2037

    
2038
function dyndnsCheckIP($int) {
2039
	global $config, $factory_default_checkipservice;
2040
	$ip_address = get_interface_ip($int);
2041
	if (is_private_ip($ip_address)) {
2042
		$gateways_status = return_gateways_status(true);
2043
		// If the gateway for this interface is down, then the external check cannot work.
2044
		// Avoid the long wait for the external check to timeout.
2045
		if (stristr($gateways_status[$config['interfaces'][$int]['gateway']]['status'], "down")) {
2046
			return "down";
2047
		}
2048

    
2049
		// Append the factory default check IP service to the list (if not disabled).
2050
		if (!isset($config['checkipservices']['disable_factory_default'])) {
2051
			$config['checkipservices']['checkipservice'][] = $factory_default_checkipservice;
2052
		}
2053

    
2054
		// Use the first enabled check IP service as the default.
2055
		if (is_array($config['checkipservices']['checkipservice'])) {
2056
			foreach ($config['checkipservices']['checkipservice'] as $i => $checkipservice) {
2057
				if (isset($checkipservice['enable'])) {
2058
					$url = $checkipservice['url'];
2059
					$username = $checkipservice['username'];
2060
					$password = $checkipservice['password'];
2061
					$verifysslpeer = isset($checkipservice['verifysslpeer']);
2062
					break;
2063
				}
2064
			}
2065
		}
2066

    
2067
		$hosttocheck = $url;
2068
		$ip_ch = curl_init($hosttocheck);
2069
		curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
2070
		curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, $verifysslpeer);
2071
		curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
2072
		curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
2073
		curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
2074
		curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
2075
		curl_setopt($ip_ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
2076
		curl_setopt($ip_ch, CURLOPT_USERPWD, "{$username}:{$password}");
2077
		$ip_result_page = curl_exec($ip_ch);
2078
		curl_close($ip_ch);
2079
		$ip_result_decoded = urldecode($ip_result_page);
2080
		preg_match('=Current IP Address: (.*)</body>=siU', $ip_result_decoded, $matches);
2081
		$ip_address = trim($matches[1]);
2082
	}
2083
	return $ip_address;
2084
}
2085

    
2086
function services_dnsmasq_configure($restart_dhcp = true) {
2087
	global $config, $g;
2088
	$return = 0;
2089

    
2090
	// hard coded args: will be removed to avoid duplication if specified in custom_options
2091
	$standard_args = array(
2092
		"dns-forward-max" => "--dns-forward-max=5000",
2093
		"cache-size" => "--cache-size=10000",
2094
		"local-ttl" => "--local-ttl=1"
2095
	);
2096

    
2097

    
2098
	if (isset($config['system']['developerspew'])) {
2099
		$mt = microtime();
2100
		echo "services_dnsmasq_configure() being called $mt\n";
2101
	}
2102

    
2103
	/* kill any running dnsmasq */
2104
	if (file_exists("{$g['varrun_path']}/dnsmasq.pid")) {
2105
		sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
2106
	}
2107

    
2108
	if (isset($config['dnsmasq']['enable'])) {
2109

    
2110
		if (platform_booting()) {
2111
			echo gettext("Starting DNS forwarder...");
2112
		} else {
2113
			sleep(1);
2114
		}
2115

    
2116
		/* generate hosts file */
2117
		if (system_hosts_generate() != 0) {
2118
			$return = 1;
2119
		}
2120

    
2121
		$args = "";
2122

    
2123
		if (isset($config['dnsmasq']['regdhcp'])) {
2124
			$args .= " --dhcp-hostsfile={$g['etc_path']}/hosts ";
2125
		}
2126

    
2127
		/* Setup listen port, if non-default */
2128
		if (is_port($config['dnsmasq']['port'])) {
2129
			$args .= " --port={$config['dnsmasq']['port']} ";
2130
		}
2131

    
2132
		$listen_addresses = "";
2133
		if (isset($config['dnsmasq']['interface'])) {
2134
			$interfaces = explode(",", $config['dnsmasq']['interface']);
2135
			foreach ($interfaces as $interface) {
2136
				$if = get_real_interface($interface);
2137
				if (does_interface_exist($if)) {
2138
					$laddr = get_interface_ip($interface);
2139
					if (is_ipaddrv4($laddr)) {
2140
						$listen_addresses .= " --listen-address={$laddr} ";
2141
					}
2142
					$laddr6 = get_interface_ipv6($interface);
2143
					if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
2144
						/*
2145
						 * XXX: Since dnsmasq does not support link-local address
2146
						 * with scope specified. These checks are being done.
2147
						 */
2148
						if (is_linklocal($laddr6) && strstr($laddr6, "%")) {
2149
							$tmpaddrll6 = explode("%", $laddr6);
2150
							$listen_addresses .= " --listen-address={$tmpaddrll6[0]} ";
2151
						} else {
2152
							$listen_addresses .= " --listen-address={$laddr6} ";
2153
						}
2154
					}
2155
				}
2156
			}
2157
			if (!empty($listen_addresses)) {
2158
				$args .= " {$listen_addresses} ";
2159
				if (isset($config['dnsmasq']['strictbind'])) {
2160
					$args .= " --bind-interfaces ";
2161
				}
2162
			}
2163
		}
2164

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

    
2172
			// Build an array of domain overrides to help in checking for matches.
2173
			$override_a = array();
2174
			if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2175
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2176
					$override_a[$override['domain']] = "y";
2177
				}
2178
			}
2179

    
2180
			// Build an array of the private reverse lookup domain names
2181
			$reverse_domain_a = array("10.in-addr.arpa", "168.192.in-addr.arpa");
2182
			// Unfortunately the 172.16.0.0/12 range does not map nicely to the in-addr.arpa scheme.
2183
			for ($subnet_num = 16; $subnet_num < 32; $subnet_num++) {
2184
				$reverse_domain_a[] = "$subnet_num.172.in-addr.arpa";
2185
			}
2186

    
2187
			// Set the --server parameter to nowhere for each reverse domain name that was not specifically specified in a domain override.
2188
			foreach ($reverse_domain_a as $reverse_domain) {
2189
				if (!isset($override_a[$reverse_domain])) {
2190
					$args .= " --server=/$reverse_domain/ ";
2191
				}
2192
			}
2193
			unset($override_a);
2194
			unset($reverse_domain_a);
2195
		}
2196

    
2197
		/* Setup forwarded domains */
2198
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2199
			foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2200
				if ($override['ip'] == "!") {
2201
					$override[ip] = "";
2202
				}
2203
				$args .= ' --server=/' . $override['domain'] . '/' . $override['ip'];
2204
			}
2205
		}
2206

    
2207
		/* Allow DNS Rebind for forwarded domains */
2208
		if (isset($config['dnsmasq']['domainoverrides']) && is_array($config['dnsmasq']['domainoverrides'])) {
2209
			if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2210
				foreach ($config['dnsmasq']['domainoverrides'] as $override) {
2211
					$args .= ' --rebind-domain-ok=/' . $override['domain'] . '/ ';
2212
				}
2213
			}
2214
		}
2215

    
2216
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
2217
			$dns_rebind = "--rebind-localhost-ok --stop-dns-rebind";
2218
		}
2219

    
2220
		if (isset($config['dnsmasq']['strict_order'])) {
2221
			$args .= " --strict-order ";
2222
		}
2223

    
2224
		if (isset($config['dnsmasq']['domain_needed'])) {
2225
			$args .= " --domain-needed ";
2226
		}
2227

    
2228
		if ($config['dnsmasq']['custom_options']) {
2229
			foreach (preg_split('/\s+/', $config['dnsmasq']['custom_options']) as $c) {
2230
				$args .= " " . escapeshellarg("--{$c}");
2231
				$p = explode('=', $c);
2232
				if (array_key_exists($p[0], $standard_args)) {
2233
					unset($standard_args[$p[0]]);
2234
				}
2235
			}
2236
		}
2237
		$args .= ' ' . implode(' ', array_values($standard_args));
2238

    
2239
		/* run dnsmasq. Use "-C /dev/null" since we use command line args only (Issue #6730) */
2240
		$cmd = "/usr/local/sbin/dnsmasq --all-servers -C /dev/null {$dns_rebind} {$args}";
2241
		//log_error("dnsmasq command: {$cmd}");
2242
		mwexec_bg($cmd);
2243
		unset($args);
2244

    
2245
		system_dhcpleases_configure();
2246

    
2247
		if (platform_booting()) {
2248
			echo gettext("done.") . "\n";
2249
		}
2250
	}
2251

    
2252
	if (!platform_booting() && $restart_dhcp) {
2253
		if (services_dhcpd_configure() != 0) {
2254
			$return = 1;
2255
		}
2256
	}
2257

    
2258
	return $return;
2259
}
2260

    
2261
function services_unbound_configure($restart_dhcp = true) {
2262
	global $config, $g;
2263
	$return = 0;
2264

    
2265
	if (isset($config['system']['developerspew'])) {
2266
		$mt = microtime();
2267
		echo "services_unbound_configure() being called $mt\n";
2268
	}
2269

    
2270
	// kill any running Unbound instance
2271
	if (file_exists("{$g['varrun_path']}/unbound.pid")) {
2272
		sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM");
2273
	}
2274

    
2275
	if (isset($config['unbound']['enable'])) {
2276
		if (platform_booting()) {
2277
			echo gettext("Starting DNS Resolver...");
2278
		} else {
2279
			sleep(1);
2280
		}
2281

    
2282
		/* generate hosts file */
2283
		if (system_hosts_generate() != 0) {
2284
			$return = 1;
2285
		}
2286

    
2287
		require_once('/etc/inc/unbound.inc');
2288
		sync_unbound_service();
2289
		if (platform_booting()) {
2290
			echo gettext("done.") . "\n";
2291
		}
2292

    
2293
		system_dhcpleases_configure();
2294
	}
2295

    
2296
	if (!platform_booting() && $restart_dhcp) {
2297
		if (services_dhcpd_configure() != 0) {
2298
			$return = 1;
2299
		}
2300
	}
2301

    
2302
	return $return;
2303
}
2304

    
2305
function services_snmpd_configure() {
2306
	global $config, $g;
2307
	if (isset($config['system']['developerspew'])) {
2308
		$mt = microtime();
2309
		echo "services_snmpd_configure() being called $mt\n";
2310
	}
2311

    
2312
	/* kill any running snmpd */
2313
	sigkillbypid("{$g['varrun_path']}/snmpd.pid", "TERM");
2314
	sleep(2);
2315
	if (is_process_running("bsnmpd")) {
2316
		mwexec("/usr/bin/killall bsnmpd", true);
2317
	}
2318

    
2319
	if (isset($config['snmpd']['enable'])) {
2320

    
2321
		if (platform_booting()) {
2322
			echo gettext("Starting SNMP daemon... ");
2323
		}
2324

    
2325
		/* Make sure a printcap file exists or else bsnmpd will log errors. See https://redmine.pfsense.org/issues/6838 */
2326
		if (!file_exists('/etc/printcap')) {
2327
			@file_put_contents('/etc/printcap', "# Empty file to prevent bsnmpd from logging errors.\n");
2328
		}
2329

    
2330
		/* generate snmpd.conf */
2331
		$fd = fopen("{$g['varetc_path']}/snmpd.conf", "w");
2332
		if (!$fd) {
2333
			printf(gettext("Error: cannot open snmpd.conf in services_snmpd_configure().%s"), "\n");
2334
			return 1;
2335
		}
2336

    
2337

    
2338
		$snmpdconf = <<<EOD
2339
location := "{$config['snmpd']['syslocation']}"
2340
contact := "{$config['snmpd']['syscontact']}"
2341
read := "{$config['snmpd']['rocommunity']}"
2342

    
2343
EOD;
2344

    
2345
/* No docs on what write strings do there so disable for now.
2346
		if (isset($config['snmpd']['rwenable']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2347
			$snmpdconf .= <<<EOD
2348
# write string
2349
write := "{$config['snmpd']['rwcommunity']}"
2350

    
2351
EOD;
2352
		}
2353
*/
2354

    
2355

    
2356
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2357
			$snmpdconf .= <<<EOD
2358
# SNMP Trap support.
2359
traphost := {$config['snmpd']['trapserver']}
2360
trapport := {$config['snmpd']['trapserverport']}
2361
trap := "{$config['snmpd']['trapstring']}"
2362

    
2363

    
2364
EOD;
2365
		}
2366

    
2367
		$sysDescr = "{$g['product_name']} " . php_uname("n") .
2368
			" {$g['product_version']} {$g['platform']} " . php_uname("s") .
2369
			" " . php_uname("r") . " " . php_uname("m");
2370

    
2371
		$snmpdconf .= <<<EOD
2372
system := 1     # pfSense
2373
%snmpd
2374
sysDescr			= "{$sysDescr}"
2375
begemotSnmpdDebugDumpPdus       = 2
2376
begemotSnmpdDebugSyslogPri      = 7
2377
begemotSnmpdCommunityString.0.1 = $(read)
2378

    
2379
EOD;
2380

    
2381
/* No docs on what write strings do there so disable for now.
2382
		if (isset($config['snmpd']['rwcommunity']) && preg_match('/^\S+$/', $config['snmpd']['rwcommunity'])) {
2383
			$snmpdconf .= <<<EOD
2384
begemotSnmpdCommunityString.0.2 = $(write)
2385

    
2386
EOD;
2387
		}
2388
*/
2389

    
2390

    
2391
		if (isset($config['snmpd']['trapenable']) && preg_match('/^\S+$/', $config['snmpd']['trapserver'])) {
2392
			$snmpdconf .= <<<EOD
2393
begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4
2394
begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2
2395
begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap)
2396

    
2397
EOD;
2398
		}
2399

    
2400

    
2401
		$snmpdconf .= <<<EOD
2402
begemotSnmpdCommunityDisable    = 1
2403

    
2404
EOD;
2405

    
2406
		$bind_to_ips = array();
2407
		if (isset($config['snmpd']['bindip'])) {
2408
			foreach (explode(",", $config['snmpd']['bindip']) as $bind_to_ip) {
2409
				if (is_ipaddr($bind_to_ip)) {
2410
					$bind_to_ips[] = $bind_to_ip;
2411
				} else {
2412
					$if = get_real_interface($bind_to_ip);
2413
					if (does_interface_exist($if)) {
2414
						$bindip = get_interface_ip($bind_to_ip);
2415
						if (is_ipaddr($bindip)) {
2416
							$bind_to_ips[] = $bindip;
2417
						}
2418
					}
2419
				}
2420
			}
2421
		}
2422
		if (!count($bind_to_ips)) {
2423
			$bind_to_ips = array("0.0.0.0");
2424
		}
2425

    
2426
		if (is_port($config['snmpd']['pollport'])) {
2427
			foreach ($bind_to_ips as $bind_to_ip) {
2428
				$snmpdconf .= <<<EOD
2429
begemotSnmpdPortStatus.{$bind_to_ip}.{$config['snmpd']['pollport']} = 1
2430

    
2431
EOD;
2432

    
2433
			}
2434
		}
2435

    
2436
		$snmpdconf .= <<<EOD
2437
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1
2438
begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4
2439

    
2440
# These are bsnmp macros not php vars.
2441
sysContact      = $(contact)
2442
sysLocation     = $(location)
2443
sysObjectId     = 1.3.6.1.4.1.12325.1.1.2.1.$(system)
2444

    
2445
snmpEnableAuthenTraps = 2
2446

    
2447
EOD;
2448

    
2449
		if (is_array($config['snmpd']['modules'])) {
2450
			if (isset($config['snmpd']['modules']['mibii'])) {
2451
			$snmpdconf .= <<<EOD
2452
begemotSnmpdModulePath."mibII"  = "/usr/lib/snmp_mibII.so"
2453

    
2454
EOD;
2455
			}
2456

    
2457
			if (isset($config['snmpd']['modules']['netgraph'])) {
2458
				$snmpdconf .= <<<EOD
2459
begemotSnmpdModulePath."netgraph" = "/usr/lib/snmp_netgraph.so"
2460
%netgraph
2461
begemotNgControlNodeName = "snmpd"
2462

    
2463
EOD;
2464
			}
2465

    
2466
			if (isset($config['snmpd']['modules']['pf'])) {
2467
				$snmpdconf .= <<<EOD
2468
begemotSnmpdModulePath."pf"     = "/usr/lib/snmp_pf.so"
2469

    
2470
EOD;
2471
			}
2472

    
2473
			if (isset($config['snmpd']['modules']['hostres'])) {
2474
				$snmpdconf .= <<<EOD
2475
begemotSnmpdModulePath."hostres"     = "/usr/lib/snmp_hostres.so"
2476

    
2477
EOD;
2478
			}
2479

    
2480
			if (isset($config['snmpd']['modules']['bridge'])) {
2481
				$snmpdconf .= <<<EOD
2482
begemotSnmpdModulePath."bridge"     = "/usr/lib/snmp_bridge.so"
2483
# config must end with blank line
2484

    
2485
EOD;
2486
			}
2487
			if (isset($config['snmpd']['modules']['ucd'])) {
2488
				$snmpdconf .= <<<EOD
2489
begemotSnmpdModulePath."ucd"     = "/usr/local/lib/snmp_ucd.so"
2490

    
2491
EOD;
2492
			}
2493
			if (isset($config['snmpd']['modules']['regex'])) {
2494
				$snmpdconf .= <<<EOD
2495
begemotSnmpdModulePath."regex"     = "/usr/local/lib/snmp_regex.so"
2496

    
2497
EOD;
2498
			}
2499
		}
2500

    
2501
		fwrite($fd, $snmpdconf);
2502
		fclose($fd);
2503
		unset($snmpdconf);
2504

    
2505
		/* run bsnmpd */
2506
		mwexec("/usr/sbin/bsnmpd -c {$g['varetc_path']}/snmpd.conf" .
2507
			" -p {$g['varrun_path']}/snmpd.pid");
2508

    
2509
		if (platform_booting()) {
2510
			echo gettext("done.") . "\n";
2511
		}
2512
	}
2513

    
2514
	return 0;
2515
}
2516

    
2517
function services_dnsupdate_process($int = "", $updatehost = "", $forced = false) {
2518
	global $config, $g;
2519
	if (isset($config['system']['developerspew'])) {
2520
		$mt = microtime();
2521
		echo "services_dnsupdate_process() being called $mt\n";
2522
	}
2523

    
2524
	/* Dynamic DNS updating active? */
2525
	if (!is_array($config['dnsupdates']['dnsupdate'])) {
2526
		return 0;
2527
	}
2528

    
2529
	$notify_text = "";
2530
	$gwgroups = return_gateway_groups_array();
2531
	foreach ($config['dnsupdates']['dnsupdate'] as $i => $dnsupdate) {
2532
		if (!isset($dnsupdate['enable'])) {
2533
			continue;
2534
		}
2535
		/*
2536
		 * If it's using a gateway group, check if interface is
2537
		 * the active gateway for that group
2538
		 */
2539
		$group_int = '';
2540
		if (is_array($gwgroups[$dnsupdate['interface']])) {
2541
			if (!empty($gwgroups[$dnsupdate['interface']][0]['vip'])) {
2542
				$group_int = $gwgroups[$dnsupdate['interface']][0]['vip'];
2543
			} else {
2544
				$group_int = $gwgroups[$dnsupdate['interface']][0]['int'];
2545
			}
2546
		}
2547
		if (!empty($int) && ($int != $dnsupdate['interface']) && ($int != $group_int)) {
2548
			continue;
2549
		}
2550
		if (!empty($updatehost) && ($updatehost != $dnsupdate['host'])) {
2551
			continue;
2552
		}
2553

    
2554
		/* determine interface name */
2555
		$if = get_failover_interface($dnsupdate['interface']);
2556

    
2557
		if (isset($dnsupdate['usepublicip'])) {
2558
			$wanip = dyndnsCheckIP($if);
2559
		} else {
2560
			$wanip = get_interface_ip($if);
2561
		}
2562

    
2563
		$wanipv6 = get_interface_ipv6($if);
2564
		$cacheFile = $g['conf_path'] .
2565
		    "/dyndns_{$dnsupdate['interface']}_rfc2136_" .
2566
		    escapeshellarg($dnsupdate['host']) .
2567
		    "_{$dnsupdate['server']}.cache";
2568
		$cacheFilev6 = $cacheFile . ".ipv6";
2569
		$currentTime = time();
2570

    
2571
		if (!$wanip && !$wanipv6) {
2572
			continue;
2573
		}
2574

    
2575
		$keyname = $dnsupdate['keyname'];
2576
		/* trailing dot */
2577
		if (substr($keyname, -1) != ".") {
2578
			$keyname .= ".";
2579
		}
2580

    
2581
		$hostname = $dnsupdate['host'];
2582
		/* trailing dot */
2583
		if (substr($hostname, -1) != ".") {
2584
			$hostname .= ".";
2585
		}
2586

    
2587
		/*
2588
		 * write private key file
2589
		 * this is dumb - public and private keys are the same for
2590
		 * HMAC-MD5, but nsupdate insists on having both
2591
		 */
2592
		$fd = fopen($g['varetc_path'] .
2593
		    "/K{$i}{$keyname}+157+00000.private", "w");
2594
		$privkey = <<<EOD
2595
Private-key-format: v1.2
2596
Algorithm: 157 (HMAC)
2597
Key: {$dnsupdate['keydata']}
2598

    
2599
EOD;
2600
		fwrite($fd, $privkey);
2601
		fclose($fd);
2602

    
2603
		/* write public key file */
2604
		if ($dnsupdate['keytype'] == "zone") {
2605
			$flags = 257;
2606
			$proto = 3;
2607
		} else if ($dnsupdate['keytype'] == "host") {
2608
			$flags = 513;
2609
			$proto = 3;
2610
		} else if ($dnsupdate['keytype'] == "user") {
2611
			$flags = 0;
2612
			$proto = 2;
2613
		}
2614

    
2615
		$fd = fopen($g['varetc_path'] .
2616
		    "/K{$i}{$keyname}+157+00000.key", "w");
2617
		fwrite($fd, "{$keyname} IN KEY {$flags} {$proto} 157 " .
2618
		    "{$dnsupdate['keydata']}\n");
2619
		fclose($fd);
2620

    
2621
		/* generate update instructions */
2622
		$upinst = "";
2623
		if (!empty($dnsupdate['server'])) {
2624
			$upinst .= "server {$dnsupdate['server']}\n";
2625
		}
2626

    
2627
		if (file_exists($cacheFile)) {
2628
			list($cachedipv4, $cacheTimev4) = explode("|",
2629
			    file_get_contents($cacheFile));
2630
		}
2631
		if (file_exists($cacheFilev6)) {
2632
			list($cachedipv6, $cacheTimev6) = explode("|",
2633
			    file_get_contents($cacheFilev6));
2634
		}
2635

    
2636
		// 25 Days
2637
		$maxCacheAgeSecs = 25 * 24 * 60 * 60;
2638
		$need_update = false;
2639

    
2640
		/* Update IPv4 if we have it. */
2641
		if (is_ipaddrv4($wanip) && $dnsupdate['recordtype'] != "AAAA") {
2642
			if (($wanip != $cachedipv4) || $forced ||
2643
			    (($currentTime - $cacheTimev4) > $maxCacheAgeSecs)) {
2644
				$upinst .= "update delete " .
2645
				    "{$dnsupdate['host']}. A\n";
2646
				$upinst .= "update add {$dnsupdate['host']}. " .
2647
				    "{$dnsupdate['ttl']} A {$wanip}\n";
2648
				$need_update = true;
2649
			} else {
2650
				log_error(sprintf(gettext(
2651
				    "phpDynDNS: Not updating %s A record because the IP address has not changed."),
2652
				    $dnsupdate['host']));
2653
			}
2654
		} else {
2655
			@unlink($cacheFile);
2656
			unset($cacheFile);
2657
		}
2658

    
2659
		/* Update IPv6 if we have it. */
2660
		if (is_ipaddrv6($wanipv6) && $dnsupdate['recordtype'] != "A") {
2661
			if (($wanipv6 != $cachedipv6) || $forced ||
2662
			    (($currentTime - $cacheTimev6) > $maxCacheAgeSecs)) {
2663
				$upinst .= "update delete " .
2664
				    "{$dnsupdate['host']}. AAAA\n";
2665
				$upinst .= "update add {$dnsupdate['host']}. " .
2666
				    "{$dnsupdate['ttl']} AAAA {$wanipv6}\n";
2667
				$need_update = true;
2668
			} else {
2669
				log_error(sprintf(gettext(
2670
				    "phpDynDNS: Not updating %s AAAA record because the IPv6 address has not changed."),
2671
				    $dnsupdate['host']));
2672
			}
2673
		} else {
2674
			@unlink($cacheFilev6);
2675
			unset($cacheFilev6);
2676
		}
2677

    
2678
		$upinst .= "\n";	/* mind that trailing newline! */
2679

    
2680
		if (!$need_update) {
2681
			continue;
2682
		}
2683

    
2684
		@file_put_contents("{$g['varetc_path']}/nsupdatecmds{$i}",
2685
		    $upinst);
2686
		unset($upinst);
2687
		/* invoke nsupdate */
2688
		$cmd = "/usr/local/bin/nsupdate -k " .
2689
		    "{$g['varetc_path']}/K{$i}{$keyname}+157+00000.key";
2690

    
2691
		if (isset($dnsupdate['usetcp'])) {
2692
			$cmd .= " -v";
2693
		}
2694

    
2695
		$cmd .= " {$g['varetc_path']}/nsupdatecmds{$i}";
2696

    
2697
		if (mwexec($cmd) == 0) {
2698
			if (!empty($cacheFile)) {
2699
				@file_put_contents($cacheFile,
2700
				    "{$wanip}|{$currentTime}");
2701
				log_error(sprintf(gettext(
2702
				    'phpDynDNS: updating cache file %1$s: %2$s'),
2703
				    $cacheFile, $wanip));
2704
				$notify_text .= sprintf(gettext(
2705
				    'DynDNS updated IP Address (A) for %1$s on %2$s (%3$s) to %4$s'),
2706
				    $dnsupdate['host'],
2707
				    convert_real_interface_to_friendly_descr($if),
2708
				    $if, $wanip) . "\n";
2709
			}
2710
			if (!empty($cacheFilev6)) {
2711
				@file_put_contents($cacheFilev6,
2712
				    "{$wanipv6}|{$currentTime}");
2713
				log_error(sprintf(gettext(
2714
				    'phpDynDNS: updating cache file %1$s: %2$s'),
2715
				    $cacheFilev6, $wanipv6));
2716
				$notify_text .= sprintf(gettext(
2717
				    'DynDNS updated IPv6 Address (AAAA) for %1$s on %2$s (%3$s) to %4$s'),
2718
				    $dnsupdate['host'],
2719
				    convert_real_interface_to_friendly_descr($if),
2720
				    $if, $wanipv6) . "\n";
2721
			}
2722
		} else {
2723
			if (!empty($cacheFile)) {
2724
				log_error(sprintf(gettext(
2725
				    'phpDynDNS: ERROR while updating IP Address (A) for %1$s (%2$s)'),
2726
				    $dnsupdate['host'], $wanip));
2727
			}
2728
			if (!empty($cacheFilev6)) {
2729
				log_error(sprintf(gettext(
2730
				    'phpDynDNS: ERROR while updating IP Address (AAAA) for %1$s (%2$s)'),
2731
				    $dnsupdate['host'], $wanipv6));
2732
			}
2733
		}
2734
		unset($cmd);
2735
	}
2736

    
2737
	if (!empty($notify_text)) {
2738
		notify_all_remote($notify_text);
2739
	}
2740

    
2741
	return 0;
2742
}
2743

    
2744
/* configure cron service */
2745
function configure_cron() {
2746
	global $g, $config;
2747

    
2748
	/* preserve existing crontab entries */
2749
	$crontab_contents = file("/etc/crontab", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
2750

    
2751
	for ($i = 0; $i < count($crontab_contents); $i++) {
2752
		$cron_item =& $crontab_contents[$i];
2753
		if (strpos($cron_item, "# pfSense specific crontab entries") !== false) {
2754
			array_splice($crontab_contents, $i - 1);
2755
			break;
2756
		}
2757
	}
2758
	$crontab_contents = implode("\n", $crontab_contents) . "\n";
2759

    
2760

    
2761
	if (is_array($config['cron']['item'])) {
2762
		$crontab_contents .= "#\n";
2763
		$crontab_contents .= "# pfSense specific crontab entries\n";
2764
		$crontab_contents .= "# " .gettext("Created:") . " " . date("F j, Y, g:i a") . "\n";
2765
		$crontab_contents .= "#\n";
2766

    
2767
		if (isset($config['system']['proxyurl']) && !empty($config['system']['proxyurl'])) {
2768
			$http_proxy = $config['system']['proxyurl'];
2769
			if (isset($config['system']['proxyport']) && !empty($config['system']['proxyport'])) {
2770
				$http_proxy .= ':' . $config['system']['proxyport'];
2771
			}
2772
			$crontab_contents .= "HTTP_PROXY={$http_proxy}";
2773

    
2774
			if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2775
				$crontab_contents .= "HTTP_PROXY_AUTH=basic:*:{$config['system']['proxyuser']}:{$config['system']['proxypass']}";
2776
			}
2777
		}
2778

    
2779
		foreach ($config['cron']['item'] as $item) {
2780
			$crontab_contents .= "\n{$item['minute']}\t";
2781
			$crontab_contents .= "{$item['hour']}\t";
2782
			$crontab_contents .= "{$item['mday']}\t";
2783
			$crontab_contents .= "{$item['month']}\t";
2784
			$crontab_contents .= "{$item['wday']}\t";
2785
			$crontab_contents .= "{$item['who']}\t";
2786
			$crontab_contents .= "{$item['command']}";
2787
		}
2788

    
2789
		$crontab_contents .= "\n#\n";
2790
		$crontab_contents .= "# " . gettext("If possible do not add items to this file manually.") . "\n";
2791
		$crontab_contents .= "# " . gettext("If done so, this file must be terminated with a blank line (e.g. new line)") . "\n";
2792
		$crontab_contents .= "#\n\n";
2793
	}
2794

    
2795
	/* please maintain the newline at the end of file */
2796
	file_put_contents("/etc/crontab", $crontab_contents);
2797
	unset($crontab_contents);
2798

    
2799
	/* make sure that cron is running and start it if it got killed somehow */
2800
	if (!is_process_running("cron")) {
2801
		exec("cd /tmp && /usr/sbin/cron -s 2>/dev/null");
2802
	} else {
2803
	/* do a HUP kill to force sync changes */
2804
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2805
	}
2806

    
2807
}
2808

    
2809
function upnp_action ($action) {
2810
	global $g, $config;
2811
	switch ($action) {
2812
		case "start":
2813
			if (file_exists('/var/etc/miniupnpd.conf')) {
2814
				@unlink("{$g['varrun_path']}/miniupnpd.pid");
2815
				mwexec_bg("/usr/local/sbin/miniupnpd -f /var/etc/miniupnpd.conf -P {$g['varrun_path']}/miniupnpd.pid");
2816
			}
2817
			break;
2818
		case "stop":
2819
			killbypid("{$g['varrun_path']}/miniupnpd.pid");
2820
			while ((int)exec("/bin/pgrep -a miniupnpd | wc -l") > 0) {
2821
				mwexec('/usr/bin/killall miniupnpd 2>/dev/null', true);
2822
			}
2823
			mwexec('/sbin/pfctl -aminiupnpd -Fr 2>&1 >/dev/null');
2824
			mwexec('/sbin/pfctl -aminiupnpd -Fn 2>&1 >/dev/null');
2825
			break;
2826
		case "restart":
2827
			upnp_action('stop');
2828
			upnp_action('start');
2829
			break;
2830
	}
2831
}
2832

    
2833
function upnp_start() {
2834
	global $config;
2835

    
2836
	if (!isset($config['installedpackages']['miniupnpd']['config'])) {
2837
		return;
2838
	}
2839

    
2840
	if ($config['installedpackages']['miniupnpd']['config'][0]['enable']) {
2841
		echo gettext("Starting UPnP service... ");
2842
		require_once('/usr/local/pkg/miniupnpd.inc');
2843
		sync_package_miniupnpd();
2844
		echo "done.\n";
2845
	}
2846
}
2847

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

    
2851
	$is_installed = false;
2852
	$cron_changed = true;
2853

    
2854
	if (!is_array($config['cron'])) {
2855
		$config['cron'] = array();
2856
	}
2857
	if (!is_array($config['cron']['item'])) {
2858
		$config['cron']['item'] = array();
2859
	}
2860

    
2861
	$x = 0;
2862
	foreach ($config['cron']['item'] as $item) {
2863
		if (strstr($item['command'], $command)) {
2864
			$is_installed = true;
2865
			break;
2866
		}
2867
		$x++;
2868
	}
2869

    
2870
	if ($active) {
2871
		$cron_item = array();
2872
		$cron_item['minute'] = $minute;
2873
		$cron_item['hour'] = $hour;
2874
		$cron_item['mday'] = $monthday;
2875
		$cron_item['month'] = $month;
2876
		$cron_item['wday'] = $weekday;
2877
		$cron_item['who'] = $who;
2878
		$cron_item['command'] = $command;
2879
		if (!$is_installed) {
2880
			$config['cron']['item'][] = $cron_item;
2881
			write_config(sprintf(gettext("Installed cron job for %s"), $command));
2882
		} else {
2883
			if ($config['cron']['item'][$x] == $cron_item) {
2884
				$cron_changed = false;
2885
				log_error(sprintf(gettext("Checked cron job for %s, no change needed"), $command));
2886
			} else {
2887
				$config['cron']['item'][$x] = $cron_item;
2888
				write_config(sprintf(gettext("Updated cron job for %s"), $command));
2889
			}
2890
		}
2891
	} else {
2892
		if ($is_installed == true) {
2893
			unset($config['cron']['item'][$x]);
2894
			write_config(sprintf(gettext("Removed cron job for %s"), $command));
2895
		}
2896
	}
2897

    
2898
	if ($cron_changed) {
2899
		configure_cron();
2900
	}
2901
}
2902

    
2903
?>
(38-38/51)