Project

General

Profile

Download (21.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	unbound.inc
4
	part of the pfSense project (https://www.pfsense.org)
5
	Copyright (C) 2015 Warren Baker <warren@percol8.co.za>
6
	All rights reserved.
7

    
8
	Redistribution and use in source and binary forms, with or without
9
	modification, are permitted provided that the following conditions are met:
10

    
11
	1. Redistributions of source code must retain the above copyright notice,
12
	   this list of conditions and the following disclaimer.
13

    
14
	2. Redistributions in binary form must reproduce the above copyright
15
	   notice, this list of conditions and the following disclaimer in the
16
	   documentation and/or other materials provided with the distribution.
17

    
18
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
	POSSIBILITY OF SUCH DAMAGE.
28

    
29
	pfSense_BUILDER_BINARIES:   /usr/local/sbin/unbound  /usr/local/sbin/unbound-anchor    /usr/local/sbin/unbound-checkconf
30
	pfSense_BUILDER_BINARIES:   /usr/local/sbin/unbound-control    /usr/local/sbin/unbound-control-setup
31
	pfSense_MODULE: unbound
32
*/
33

    
34
/* include all configuration functions */
35
require_once("config.inc");
36
require_once("functions.inc");
37
require_once("filter.inc");
38
require_once("shaper.inc");
39

    
40
function create_unbound_chroot_path() {
41
	global $config, $g;
42

    
43
	// Configure chroot
44
	if (!is_dir($g['unbound_chroot_path'])) {
45
		mkdir($g['unbound_chroot_path']);
46
		chown($g['unbound_chroot_path'], "unbound");
47
		chgrp($g['unbound_chroot_path'], "unbound");
48
	}
49

    
50
}
51

    
52
/* Optimize Unbound for environment */
53
function unbound_optimization() {
54
	global $config;
55

    
56
	$optimization_settings = array();
57

    
58
	/*
59
	 * Set the number of threads equal to number of CPUs.
60
	 * Use 1 to disable threading, if for some reason this sysctl fails.
61
	 */
62
	$numprocs = intval(get_single_sysctl('kern.smp.cpus'));
63
	if ($numprocs > 1) {
64
		$optimization['number_threads'] = "num-threads: {$numprocs}";
65
		$optimize_num = pow(2,floor(log($numprocs,2)));
66
	} else {
67
		$optimization['number_threads'] = "num-threads: 1";
68
		$optimize_num = 4;
69
	}
70

    
71
	// Slabs to help reduce lock contention.
72
	$optimization['msg_cache_slabs'] = "msg-cache-slabs: {$optimize_num}";
73
	$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$optimize_num}";
74
	$optimization['infra_cache_slabs'] = "infra-cache-slabs: {$optimize_num}";
75
	$optimization['key_cache_slabs'] = "key-cache-slabs: {$optimize_num}";
76

    
77
	/*
78
	 * Larger socket buffer for busy servers
79
	 * Check that it is set to 4MB (by default the OS has it configured to 4MB)
80
	 */
81
	if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
82
		foreach ($config['sysctl']['item'] as $tunable) {
83
			if ($tunable['tunable'] == 'kern.ipc.maxsockbuf') {
84
				$so = floor(($tunable['value']/1024/1024)-4);
85
				// Check to ensure that the number is not a negative
86
				if ($so >= 4) {
87
					// Limit to 32MB, users might set maxsockbuf very high for other reasons.
88
					// We do not want unbound to fail because of that.
89
					$so = min($so, 32);
90
					$optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
91
				} else {
92
					unset($optimization['so_rcvbuf']);
93
				}
94
			}
95
		}
96
	}
97
	// Safety check in case kern.ipc.maxsockbuf is not available.
98
	if (!isset($optimization['so_rcvbuf'])) {
99
		$optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
100
	}
101

    
102
	return $optimization;
103

    
104
}
105

    
106
function unbound_generate_config() {
107
	global $config, $g;
108

    
109
	// Setup optimization
110
	$optimization = unbound_optimization();
111

    
112
	// Setup DNSSEC support
113
	if (isset($config['unbound']['dnssec'])) {
114
		$module_config = "validator iterator";
115
		$anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root.key";
116
	} else {
117
		$module_config = "iterator";
118
	}
119

    
120
	// Setup DNS Rebinding
121
	if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
122
		// Private-addresses for DNS Rebinding
123
		$private_addr = <<<EOF
124
# For DNS Rebinding prevention
125
private-address: 10.0.0.0/8
126
private-address: 172.16.0.0/12
127
private-address: 169.254.0.0/16
128
private-address: 192.168.0.0/16
129
private-address: fd00::/8
130
private-address: fe80::/10
131
EOF;
132
	}
133

    
134
	// Determine interfaces to run on
135
	$bindints = "";
136
	if (!empty($config['unbound']['active_interface'])) {
137
		$active_interfaces = explode(",", $config['unbound']['active_interface']);
138
		if (in_array("all", $active_interfaces, true)) {
139
			$bindints .= "interface: 0.0.0.0\n";
140
			$bindints .= "interface: ::0\n";
141
			$bindints .= "interface-automatic: yes\n";
142
		} else {
143
			foreach ($active_interfaces as $ubif) {
144
				if (is_ipaddr($ubif)) {
145
					//$bindints .= "interface: $ubif\n";  -- until redmine #4062 is fixed, then uncomment this.
146
				} else {
147
					$intip = get_interface_ip($ubif);
148
					if (is_ipaddrv4($intip)) {
149
						$bindints .= "interface: $intip\n";
150
					}
151
					$intip = get_interface_ipv6($ubif);
152
					if (is_ipaddrv6($intip)) {
153
						if (!is_linklocal($intip)) {  // skipping link local for the moment to not break people's configs: https://redmine.pfsense.org/issues/4062
154
							$bindints .= "interface: $intip\n";
155
						}
156
					}
157
				}
158
			}
159
		}
160
	} else {
161
		$bindints .= "interface: 0.0.0.0\n";
162
		$bindints .= "interface: ::0\n";
163
	}
164

    
165
	// Determine interfaces to run on
166
	$outgoingints = "";
167
	if (!empty($config['unbound']['outgoing_interface'])) {
168
		$outgoingints = "# Outgoing interfaces to be used\n";
169
		$outgoing_interfaces = explode(",", $config['unbound']['outgoing_interface']);
170
		foreach ($outgoing_interfaces as $outif) {
171
			$outip = get_interface_ip($outif);
172
			if (!is_null($outip)) {
173
				$outgoingints .= "outgoing-interface: $outip\n";
174
			}
175
			$outip = get_interface_ipv6($outif);
176
			if (!is_null($outip)) {
177
				$outgoingints .= "outgoing-interface: $outip\n";
178
			}
179
		}
180
	}
181

    
182
	// Allow DNS Rebind for forwarded domains
183
	if (isset($config['unbound']['domainoverrides']) && is_array($config['unbound']['domainoverrides'])) {
184
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
185
			$private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n";
186
			$private_domains .= unbound_add_domain_overrides("private");
187
		}
188
		$reverse_zones .= unbound_add_domain_overrides("reverse");
189
	}
190

    
191
	// Configure static Host entries
192
	unbound_add_host_entries();
193

    
194
	// Configure Domain Overrides
195
	unbound_add_domain_overrides();
196

    
197
	// Configure Unbound statistics
198
	$statistics = unbound_statistics();
199

    
200
	// Configure Unbound access-lists
201
	unbound_acls_config();
202

    
203
	// Add custom Unbound options
204
	if ($config['unbound']['custom_options']) {
205
		$custom_options_source = explode("\n", base64_decode($config['unbound']['custom_options']));
206
		$custom_options = "# Unbound custom options\n";
207
		foreach ($custom_options_source as $ent) {
208
			$custom_options .= $ent."\n";
209
		}
210
	}
211

    
212
	// Server configuration variables
213
	$port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
214
	$hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
215
	$hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
216
	$harden_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
217
	$prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
218
	$prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
219
	$outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
220
	$incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
221
	$edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
222
	$num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
223
	$jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
224
	$cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
225
	$cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
226
	$infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
227
	$infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
228
	$unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
229
	if ($unwanted_reply_threshold == "disabled") {
230
		$unwanted_reply_threshold = "0";
231
	}
232
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
233
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
234
	$use_caps = isset($config['unbound']['use_caps']) ? "yes" : "no";
235

    
236
	// Set up forwarding if it configured
237
	if (isset($config['unbound']['forwarding'])) {
238
		$dnsservers = array();
239
		if (isset($config['system']['dnsallowoverride'])) {
240
			$ns = array_unique(get_nameservers());
241
			foreach ($ns as $nameserver) {
242
				if ($nameserver) {
243
					$dnsservers[] = $nameserver;
244
				}
245
			}
246
		} else {
247
			$ns = array_unique(get_dns_servers());
248
			foreach ($ns as $nameserver) {
249
				if ($nameserver) {
250
					$dnsservers[] = $nameserver;
251
				}
252
			}
253
		}
254

    
255
		if (!empty($dnsservers)) {
256
			$forward_conf .=<<<EOD
257
# Forwarding
258
forward-zone:
259
	name: "."
260

    
261
EOD;
262
			foreach ($dnsservers as $dnsserver) {
263
				$forward_conf .= "\tforward-addr: $dnsserver\n";
264
			}
265
		}
266
	} else {
267
		$forward_conf = "";
268
	}
269

    
270
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
271
	$rrset_cache_size = $msg_cache_size * 2;
272

    
273
	$unboundconf = <<<EOD
274
##########################
275
# Unbound Configuration
276
##########################
277

    
278
##
279
# Server configuration
280
##
281
server:
282
{$reverse_zones}
283
chroot: {$g['unbound_chroot_path']}
284
username: "unbound"
285
directory: "{$g['unbound_chroot_path']}"
286
pidfile: "/var/run/unbound.pid"
287
use-syslog: yes
288
port: {$port}
289
verbosity: {$verbosity}
290
hide-identity: {$hide_identity}
291
hide-version: {$hide_version}
292
harden-glue: yes
293
do-ip4: yes
294
do-ip6: yes
295
do-udp: yes
296
do-tcp: yes
297
do-daemonize: yes
298
module-config: "{$module_config}"
299
unwanted-reply-threshold: {$unwanted_reply_threshold}
300
num-queries-per-thread: {$num_queries_per_thread}
301
jostle-timeout: {$jostle_timeout}
302
infra-host-ttl: {$infra_host_ttl}
303
infra-cache-numhosts: {$infra_cache_numhosts}
304
outgoing-num-tcp: {$outgoing_num_tcp}
305
incoming-num-tcp: {$incoming_num_tcp}
306
edns-buffer-size: {$edns_buffer_size}
307
cache-max-ttl: {$cache_max_ttl}
308
cache-min-ttl: {$cache_min_ttl}
309
harden-dnssec-stripped: {$harden_dnssec_stripped}
310
msg-cache-size: {$msg_cache_size}m
311
rrset-cache-size: {$rrset_cache_size}m
312

    
313
{$optimization['number_threads']}
314
{$optimization['msg_cache_slabs']}
315
{$optimization['rrset_cache_slabs']}
316
{$optimization['infra_cache_slabs']}
317
{$optimization['key_cache_slabs']}
318
outgoing-range: 4096
319
{$optimization['so_rcvbuf']}
320
{$anchor_file}
321
prefetch: {$prefetch}
322
prefetch-key: {$prefetch_key}
323
use-caps-for-id: {$use_caps}
324
# Statistics
325
{$statistics}
326
# Interface IP(s) to bind to
327
{$bindints}
328
{$outgoingints}
329

    
330
# DNS Rebinding
331
{$private_addr}
332
{$private_domains}
333

    
334
# Access lists
335
include: {$g['unbound_chroot_path']}/access_lists.conf
336

    
337
# Static host entries
338
include: {$g['unbound_chroot_path']}/host_entries.conf
339

    
340
# dhcp lease entries
341
include: {$g['unbound_chroot_path']}/dhcpleases_entries.conf
342

    
343
# Domain overrides
344
include: {$g['unbound_chroot_path']}/domainoverrides.conf
345
{$forward_conf}
346

    
347
{$custom_options}
348

    
349
###
350
# Remote Control Config
351
###
352
include: {$g['unbound_chroot_path']}/remotecontrol.conf
353

    
354
EOD;
355

    
356
	create_unbound_chroot_path();
357
	file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
358

    
359
	return 0;
360
}
361

    
362
function unbound_remote_control_setup() {
363
	global $g;
364

    
365
	if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
366
		$remotcfg = <<<EOF
367
remote-control:
368
	control-enable: yes
369
	control-interface: 127.0.0.1
370
	control-port: 953
371
	server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
372
	server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
373
	control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
374
	control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
375

    
376
EOF;
377

    
378
		create_unbound_chroot_path();
379
		file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
380

    
381
		// Generate our keys
382
		do_as_unbound_user("unbound-control-setup");
383

    
384
	}
385
}
386

    
387
// Read /etc/hosts
388
function read_hosts() {
389

    
390
	/* Open /etc/hosts and extract the only dhcpleases info
391
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
392
	 */
393
	$etc_hosts = array();
394
	foreach (file('/etc/hosts') as $line) {
395
		if (strpos($line, "dhcpleases automatically entered")) {
396
			break;
397
		}
398
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
399
		if (empty($d) || substr(reset($d), 0, 1) == "#") {
400
			continue;
401
		}
402
		$ip = array_shift($d);
403
		$fqdn = array_shift($d);
404
		$name = array_shift($d);
405
		if (!empty($fqdn) && $fqdn != "empty") {
406
			if (!empty($name) && $name != "empty") {
407
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
408
			} else {
409
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
410
			}
411
		}
412
	}
413
	return $etc_hosts;
414
}
415

    
416
function sync_unbound_service() {
417
	global $config, $g;
418

    
419
	create_unbound_chroot_path();
420

    
421
	// Configure our Unbound service
422
	do_as_unbound_user("unbound-anchor");
423
	unbound_remote_control_setup();
424
	unbound_generate_config();
425
	do_as_unbound_user("start");
426
	require_once("service-utils.inc");
427
	if (is_service_running("unbound")) {
428
		do_as_unbound_user("restore_cache");
429
	}
430

    
431
}
432

    
433
function unbound_acl_id_used($id) {
434
	global $config;
435

    
436
	if (is_array($config['unbound']['acls'])) {
437
		foreach ($config['unbound']['acls'] as & $acls) {
438
			if ($id == $acls['aclid']) {
439
				return true;
440
			}
441
		}
442
	}
443

    
444
	return false;
445
}
446

    
447
function unbound_get_next_id() {
448
	$aclid = 0;
449
	while (unbound_acl_id_used($aclid)) {
450
		$aclid++;
451
	}
452
	return $aclid;
453
}
454

    
455
// Execute commands as the user unbound
456
function do_as_unbound_user($cmd) {
457
	global $g;
458

    
459
	switch ($cmd) {
460
		case "start":
461
			mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
462
			break;
463
		case "stop":
464
			mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
465
			break;
466
		case "reload":
467
			mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
468
			break;
469
		case "unbound-anchor":
470
			mwexec("echo '/usr/local/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
471
			break;
472
		case "unbound-control-setup":
473
			mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
474
			break;
475
		default:
476
			break;
477
	}
478
}
479

    
480
function unbound_add_domain_overrides($pvt_rev="") {
481
	global $config, $g;
482

    
483
	$domains = $config['unbound']['domainoverrides'];
484

    
485
	$sorted_domains = msort($domains, "domain");
486
	$result = array();
487
	foreach ($sorted_domains as $domain) {
488
		$domain_key = current($domain);
489
		if (!isset($result[$domain_key])) {
490
			$result[$domain_key] = array();
491
		}
492
		$result[$domain_key][] = $domain['ip'];
493
	}
494

    
495
	// Domain overrides that have multiple entries need multiple stub-addr: added
496
	$domain_entries = "";
497
	foreach ($result as $domain=>$ips) {
498
		if ($pvt_rev == "private") {
499
			$domain_entries .= "private-domain: \"$domain\"\n";
500
			$domain_entries .= "domain-insecure: \"$domain\"\n";
501
		} else if ($pvt_rev == "reverse") {
502
			if ((substr($domain,-14) == ".in-addr.arpa.") || (substr($domain,-13) == ".in-addr.arpa")) {
503
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
504
			}
505
		} else {
506
			$domain_entries .= "stub-zone:\n";
507
			$domain_entries .= "\tname: \"$domain\"\n";
508
			foreach ($ips as $ip) {
509
				$domain_entries .= "\tstub-addr: $ip\n";
510
			}
511
			$domain_entries .= "\tstub-prime: no\n";
512
		}
513
	}
514

    
515
	if ($pvt_rev != "") {
516
		return $domain_entries;
517
	} else {
518
		create_unbound_chroot_path();
519
		file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
520
	}
521
}
522

    
523
function unbound_add_host_entries() {
524
	global $config, $g;
525

    
526
	$unbound_entries = "local-zone: \"{$config['system']['domain']}\" transparent\n";
527

    
528
	$hosts = read_hosts();
529
	$added_ptr = array();
530
	foreach ($hosts as $host) {
531
		if (is_ipaddrv4($host['ipaddr'])) {
532
			$type = 'A';
533
		} else if (is_ipaddrv6($host['ipaddr'])) {
534
			$type = 'AAAA';
535
		} else {
536
			continue;
537
		}
538

    
539
		if (!$added_ptr[$host['ipaddr']]) {
540
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
541
			$added_ptr[$host['ipaddr']] = true;
542
		}
543
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
544
		if (isset($host['name'])) {
545
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
546
		}
547
	}
548

    
549
	// Write out entries
550
	create_unbound_chroot_path();
551
	file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
552

    
553
	/* dhcpleases will write to this config file, make sure it exists */
554
	@touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
555
}
556

    
557
function unbound_control($action) {
558
	global $config, $g;
559

    
560
	$cache_dumpfile = "/var/tmp/unbound_cache";
561

    
562
	switch ($action) {
563
	case "start":
564
		// Start Unbound
565
		if ($config['unbound']['enable'] == "on") {
566
			if (!is_service_running("unbound")) {
567
				do_as_unbound_user("start");
568
			}
569
		}
570
		break;
571
	case "stop":
572
		if ($config['unbound']['enable'] == "on") {
573
			do_as_unbound_user("stop");
574
		}
575
		break;
576
	case "reload":
577
		if ($config['unbound']['enable'] == "on") {
578
			do_as_unbound_user("reload");
579
		}
580
		break;
581
	case "dump_cache":
582
		// Dump Unbound's Cache
583
		if ($config['unbound']['dumpcache'] == "on") {
584
			do_as_unbound_user("dump_cache");
585
		}
586
		break;
587
	case "restore_cache":
588
		// Restore Unbound's Cache
589
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
590
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
591
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
592
			}
593
		}
594
		break;
595
	default:
596
		break;
597

    
598
	}
599
}
600

    
601
// Generation of Unbound statistics
602
function unbound_statistics() {
603
	global $config;
604

    
605
	if ($config['stats'] == "on") {
606
		$stats_interval = $config['unbound']['stats_interval'];
607
		$cumulative_stats = $config['cumulative_stats'];
608
		if ($config['extended_stats'] == "on") {
609
			$extended_stats = "yes";
610
		} else {
611
			$extended_stats = "no";
612
		}
613
	} else {
614
		$stats_interval = "0";
615
		$cumulative_stats = "no";
616
		$extended_stats = "no";
617
	}
618
	/* XXX To do - add RRD graphs */
619
	$stats = <<<EOF
620
# Unbound Statistics
621
statistics-interval: {$stats_interval}
622
extended-statistics: yes
623
statistics-cumulative: yes
624

    
625
EOF;
626

    
627
	return $stats;
628
}
629

    
630
// Unbound Access lists
631
function unbound_acls_config() {
632
	global $g, $config;
633

    
634
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
635
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
636
		$aclcfg .= "access-control: ::1 allow\n";
637
		// Add our networks for active interfaces including localhost
638
		if (!empty($config['unbound']['active_interface'])) {
639
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
640
			if (in_array("all", $active_interfaces)) {
641
				$active_interfaces = get_configured_interface_with_descr();
642
			}
643
		} else {
644
			$active_interfaces = get_configured_interface_with_descr();
645
		}
646

    
647
		$bindints = "";
648
		foreach ($active_interfaces as $ubif => $ifdesc) {
649
			$ifip = get_interface_ip($ubif);
650
			if (is_ipaddrv4($ifip)) {
651
				// IPv4 is handled via NAT networks below
652
			}
653
			$ifip = get_interface_ipv6($ubif);
654
			if (is_ipaddrv6($ifip)) {
655
				if (!is_linklocal($ifip)) {
656
					$subnet_bits = get_interface_subnetv6($ubif);
657
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
658
					// only add LAN-type interfaces
659
					if (!interface_has_gateway($ubif)) {
660
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
661
					}
662
				}
663
				// add for IPv6 static routes to local networks
664
				// for safety, we include only routes reachable on an interface with no
665
				// gateway specified - read: not an Internet connection.
666
				$static_routes = get_staticroutes();
667
				foreach ($static_routes as $route) {
668
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
669
						// route is on this interface, interface doesn't have gateway, add it
670
						$aclcfg .= "access-control: {$route['network']} allow\n";
671
					}
672
				}
673
			}
674
		}
675

    
676
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
677
		if (empty($FilterIflist)) {
678
			filter_generate_optcfg_array();
679
		}
680
		$natnetworks_array = array();
681
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
682
		foreach ($natnetworks_array as $allowednet) {
683
			$aclcfg .= "access-control: $allowednet allow \n";
684
		}
685
	}
686

    
687
	// Configure the custom ACLs
688
	if (is_array($config['unbound']['acls'])) {
689
		foreach ($config['unbound']['acls'] as $unbound_acl) {
690
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
691
			foreach ($unbound_acl['row'] as $network) {
692
				if ($unbound_acl['aclaction'] == "allow snoop") {
693
					$unbound_acl['aclaction'] = "allow_snoop";
694
				}
695
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
696
			}
697
		}
698
	}
699
	// Write out Access list
700
	create_unbound_chroot_path();
701
	file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $aclcfg);
702

    
703
}
704

    
705
// Generate hosts and reload services
706
function unbound_hosts_generate() {
707
	// Generate our hosts file
708
	unbound_add_host_entries();
709

    
710
	// Reload our service to read the updates
711
	unbound_control("reload");
712
}
713

    
714
?>
(54-54/68)