Project

General

Profile

Download (21.3 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
	return $optimization;
102

    
103
}
104

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

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

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

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

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

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

    
175
	// Allow DNS Rebind for forwarded domains
176
	if (isset($config['unbound']['domainoverrides']) && is_array($config['unbound']['domainoverrides'])) {
177
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
178
			$private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n";
179
			$private_domains .= unbound_add_domain_overrides("private");
180
		}
181
		$reverse_zones .= unbound_add_domain_overrides("reverse");
182
	}
183

    
184
	// Configure static Host entries
185
	unbound_add_host_entries();
186

    
187
	// Configure Domain Overrides
188
	unbound_add_domain_overrides();
189

    
190
	// Configure Unbound statistics
191
	$statistics = unbound_statistics();
192

    
193
	// Configure Unbound access-lists
194
	unbound_acls_config();
195

    
196
	// Add custom Unbound options
197
	if ($config['unbound']['custom_options']) {
198
		$custom_options_source = explode("\n", base64_decode($config['unbound']['custom_options']));
199
		$custom_options = "# Unbound custom options\n";
200
		foreach ($custom_options_source as $ent)
201
			$custom_options .= $ent."\n";
202
	}
203

    
204
	// Server configuration variables
205
	$port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
206
	$hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
207
	$hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
208
	$harden_glue = isset($config['unbound']['hardenglue']) ? "yes" : "no";
209
	$harden_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
210
	$prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
211
	$prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
212
	$outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
213
	$incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
214
	$edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
215
	$num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
216
	$jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
217
	$cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
218
	$cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
219
	$infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
220
	$infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
221
	$unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
222
	if ($unwanted_reply_threshold == "disabled")
223
		$unwanted_reply_threshold = "0";
224
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
225
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
226
	$use_caps = isset($config['unbound']['use_caps']) ? "yes" : "no";
227

    
228
	// Set up forwarding if it configured
229
	if (isset($config['unbound']['forwarding'])) {
230
		$dnsservers = array();
231
		if (isset($config['system']['dnsallowoverride'])) {
232
			$ns = array_unique(get_nameservers());
233
			foreach($ns as $nameserver) {
234
				if ($nameserver)
235
					$dnsservers[] = $nameserver;
236
			}
237
		} else {
238
			$ns = array_unique(get_dns_servers());
239
			foreach($ns as $nameserver) {
240
				if ($nameserver)
241
					$dnsservers[] = $nameserver;
242
			}
243
		}
244

    
245
		if (!empty($dnsservers)) {
246
			$forward_conf .=<<<EOD
247
# Forwarding
248
forward-zone:
249
	name: "."
250

    
251
EOD;
252
			foreach($dnsservers as $dnsserver)
253
				$forward_conf .= "\tforward-addr: $dnsserver\n";
254
		}
255
	} else
256
		$forward_conf = "";
257

    
258
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
259
	$rrset_cache_size = $msg_cache_size * 2;
260

    
261
	$unboundconf = <<<EOD
262
##########################
263
# Unbound Configuration
264
##########################
265

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

    
302
{$optimization['number_threads']}
303
{$optimization['msg_cache_slabs']}
304
{$optimization['rrset_cache_slabs']}
305
{$optimization['infra_cache_slabs']}
306
{$optimization['key_cache_slabs']}
307
outgoing-range: 4096
308
{$optimization['so_rcvbuf']}
309
{$anchor_file}
310
prefetch: {$prefetch}
311
prefetch-key: {$prefetch_key}
312
use-caps-for-id: {$use_caps}
313
# Statistics
314
{$statistics}
315
# Interface IP(s) to bind to
316
{$bindints}
317
{$outgoingints}
318

    
319
# DNS Rebinding
320
{$private_addr}
321
{$private_domains}
322

    
323
# Access lists
324
include: {$g['unbound_chroot_path']}/access_lists.conf
325

    
326
# Static host entries
327
include: {$g['unbound_chroot_path']}/host_entries.conf
328

    
329
# dhcp lease entries
330
include: {$g['unbound_chroot_path']}/dhcpleases_entries.conf
331

    
332
# Domain overrides
333
include: {$g['unbound_chroot_path']}/domainoverrides.conf
334
{$forward_conf}
335

    
336
{$custom_options}
337

    
338
###
339
# Remote Control Config
340
###
341
include: {$g['unbound_chroot_path']}/remotecontrol.conf
342

    
343
EOD;
344

    
345
	create_unbound_chroot_path();
346
	file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
347

    
348
	return 0;
349
}
350

    
351
function unbound_remote_control_setup() {
352
	global $g;
353

    
354
	if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
355
		$remotcfg = <<<EOF
356
remote-control:
357
	control-enable: yes
358
	control-interface: 127.0.0.1
359
	control-port: 953
360
	server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
361
	server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
362
	control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
363
	control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
364

    
365
EOF;
366

    
367
		create_unbound_chroot_path();
368
		file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
369

    
370
		// Generate our keys
371
		do_as_unbound_user("unbound-control-setup");
372

    
373
	}
374
}
375

    
376
// Read /etc/hosts
377
function read_hosts() {
378

    
379
	/* Open /etc/hosts and extract the only dhcpleases info
380
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
381
	 */
382
	$etc_hosts = array();
383
	foreach (file('/etc/hosts') as $line) {
384
		if (strpos($line, "dhcpleases automatically entered"))
385
			break;
386
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
387
		if (empty($d) || substr(reset($d), 0, 1) == "#")
388
			continue;
389
		$ip = array_shift($d);
390
		$fqdn = array_shift($d);
391
		$name = array_shift($d);
392
		if (!empty($fqdn) && $fqdn != "empty") {
393
			if (!empty($name) && $name != "empty")
394
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
395
			else
396
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
397
		}
398
	}
399
	return $etc_hosts;
400
}
401

    
402
function sync_unbound_service() {
403
	global $config, $g;
404

    
405
	create_unbound_chroot_path();
406

    
407
	// Configure our Unbound service
408
	do_as_unbound_user("unbound-anchor");
409
	unbound_remote_control_setup();
410
	unbound_generate_config();
411
	do_as_unbound_user("start");
412
	require_once("service-utils.inc");
413
	if (is_service_running("unbound"))
414
		do_as_unbound_user("restore_cache");
415

    
416
}
417

    
418
function unbound_acl_id_used($id) {
419
	global $config;
420

    
421
	if (is_array($config['unbound']['acls']))
422
		foreach($config['unbound']['acls'] as & $acls)
423
			if ($id == $acls['aclid'])
424
				return true;
425

    
426
	return false;
427
}
428

    
429
function unbound_get_next_id() {
430
	$aclid = 0;
431
	while(unbound_acl_id_used($aclid))
432
		$aclid++;
433
	return $aclid;
434
}
435

    
436
// Execute commands as the user unbound
437
function do_as_unbound_user($cmd) {
438
	global $g;
439

    
440
	switch ($cmd) {
441
	case "start":
442
		mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
443
		break;
444
	case "stop":
445
		mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
446
		break;
447
	case "reload":
448
		mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
449
		break;
450
	case "unbound-anchor":
451
		mwexec("echo '/usr/local/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
452
		break;
453
	case "unbound-control-setup":
454
		mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
455
		break;
456
	default:
457
		break;
458
	}
459
}
460

    
461
function unbound_add_domain_overrides($pvt_rev="") {
462
	global $config, $g;
463

    
464
	$domains = $config['unbound']['domainoverrides'];
465

    
466
	$sorted_domains = msort($domains, "domain");
467
	$result = array();
468
	foreach($sorted_domains as $domain) {
469
		$domain_key = current($domain);
470
		if (!isset($result[$domain_key]))
471
			$result[$domain_key] = array();
472
		$result[$domain_key][] = $domain['ip'];
473
	}
474

    
475
	// Domain overrides that have multiple entries need multiple stub-addr: added
476
	$domain_entries = "";
477
	foreach($result as $domain=>$ips) {
478
		if ($pvt_rev == "private") {
479
			$domain_entries .= "private-domain: \"$domain\"\n";
480
			$domain_entries .= "domain-insecure: \"$domain\"\n";
481
		} else if ($pvt_rev == "reverse") {
482
			if ((substr($domain,-14) == ".in-addr.arpa.") || (substr($domain,-13) == ".in-addr.arpa")) {
483
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
484
			}
485
		} else {
486
			$domain_entries .= "stub-zone:\n";
487
			$domain_entries .= "\tname: \"$domain\"\n";
488
			foreach($ips as $ip)
489
				$domain_entries .= "\tstub-addr: $ip\n";
490
			$domain_entries .= "\tstub-prime: no\n";
491
		}
492
	}
493

    
494
	if ($pvt_rev != "")
495
		return $domain_entries;
496
	else {
497
		create_unbound_chroot_path();
498
		file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
499
	}
500
}
501

    
502
function unbound_add_host_entries() {
503
	global $config, $g;
504

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

    
507
	$hosts = read_hosts();
508
	foreach ($hosts as $host) {
509
		if (is_ipaddrv4($host['ipaddr']))
510
			$type = 'A';
511
		else if (is_ipaddrv6($host['ipaddr']))
512
			$type = 'AAAA';
513
		else
514
			continue;
515

    
516
		$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
517
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
518
		if (isset($host['name']))
519
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
520
	}
521

    
522
	// Write out entries
523
	create_unbound_chroot_path();
524
	file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
525

    
526
	/* dhcpleases will write to this config file, make sure it exists */
527
	@touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
528
}
529

    
530
function unbound_control($action) {
531
	global $config, $g;
532

    
533
	$cache_dumpfile = "/var/tmp/unbound_cache";
534

    
535
	switch ($action) {
536
	case "start":
537
		// Start Unbound
538
		if ($config['unbound']['enable'] == "on") {
539
			if (!is_service_running("unbound"))
540
				do_as_unbound_user("start");
541
		}
542
		break;
543
	case "stop":
544
		if ($config['unbound']['enable'] == "on")
545
			do_as_unbound_user("stop");
546
		break;
547
	case "reload":
548
		if ($config['unbound']['enable'] == "on")
549
			do_as_unbound_user("reload");
550
		break;
551
	case "dump_cache":
552
		// Dump Unbound's Cache
553
		if ($config['unbound']['dumpcache'] == "on")
554
			do_as_unbound_user("dump_cache");
555
		break;
556
	case "restore_cache":
557
		// Restore Unbound's Cache
558
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
559
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0)
560
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
561
		}
562
		break;
563
	default:
564
		break;
565

    
566
	}
567
}
568

    
569
// Generation of Unbound statistics
570
function unbound_statistics() {
571
	global $config;
572

    
573
	if ($config['stats'] == "on") {
574
		$stats_interval = $config['unbound']['stats_interval'];
575
		$cumulative_stats = $config['cumulative_stats'];
576
		if ($config['extended_stats'] == "on")
577
			$extended_stats = "yes";
578
		else
579
			$extended_stats = "no";
580
	} else {
581
		$stats_interval = "0";
582
		$cumulative_stats = "no";
583
		$extended_stats = "no";
584
	}
585
	/* XXX To do - add RRD graphs */
586
	$stats = <<<EOF
587
# Unbound Statistics
588
statistics-interval: {$stats_interval}
589
extended-statistics: yes
590
statistics-cumulative: yes
591

    
592
EOF;
593

    
594
	return $stats;
595
}
596

    
597
// Unbound Access lists
598
function unbound_acls_config() {
599
	global $g, $config;
600

    
601
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
602
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
603
		$aclcfg .= "access-control: ::1 allow\n";
604
		// Add our networks for active interfaces including localhost
605
		if (!empty($config['unbound']['active_interface'])) {
606
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
607
			if (in_array("all", $active_interfaces))
608
				$active_interfaces = get_configured_interface_with_descr();
609
		} else
610
			$active_interfaces = get_configured_interface_with_descr();
611
	
612
		$bindints = "";
613
		foreach($active_interfaces as $ubif => $ifdesc) {
614
			$ifip = get_interface_ip($ubif);
615
			if (is_ipaddrv4($ifip)) {
616
				// IPv4 is handled via NAT networks below
617
			}
618
			$ifip = get_interface_ipv6($ubif);
619
			if (is_ipaddrv6($ifip)) {
620
				if (!is_linklocal($ifip)) {
621
					$subnet_bits = get_interface_subnetv6($ubif);
622
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
623
					// only add LAN-type interfaces 
624
					if (!interface_has_gateway($ubif))
625
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
626
				}
627
				// add for IPv6 static routes to local networks
628
				// for safety, we include only routes reachable on an interface with no
629
				// gateway specified - read: not an Internet connection. 
630
				$static_routes = get_staticroutes();
631
				foreach ($static_routes as $route) {
632
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
633
						// route is on this interface, interface doesn't have gateway, add it
634
						$aclcfg .= "access-control: {$route['network']} allow\n";
635
					}
636
				}
637
			}
638
		}
639
		
640
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
641
		if (empty($FilterIflist)) {
642
			filter_generate_optcfg_array();
643
		}
644
		$natnetworks_array = array();
645
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
646
		foreach ($natnetworks_array as $allowednet) {
647
			$aclcfg .= "access-control: $allowednet allow \n";	
648
		}	
649
	}
650

    
651
	// Configure the custom ACLs
652
	if (is_array($config['unbound']['acls'])) {
653
		foreach($config['unbound']['acls'] as $unbound_acl) {
654
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
655
			foreach($unbound_acl['row'] as $network) {
656
				if ($unbound_acl['aclaction'] == "allow snoop")
657
					$unbound_acl['aclaction'] = "allow_snoop";
658
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
659
			}
660
		}
661
	}
662
	// Write out Access list
663
	create_unbound_chroot_path();
664
	file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $aclcfg);
665

    
666
}
667

    
668
// Generate hosts and reload services
669
function unbound_hosts_generate() {
670
	// Generate our hosts file
671
	unbound_add_host_entries();
672

    
673
	// Reload our service to read the updates
674
	unbound_control("reload");
675
}
676

    
677
?>
(54-54/68)