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
	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
		/* If the active interface array is empty, treat it the same as "All" as is done above. Otherwise it breaks CARP with a default config. */
159
		$bindints .= "interface-automatic: yes\n";
160
	}
161

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

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

    
186
	// Configure static Host entries
187
	unbound_add_host_entries();
188

    
189
	// Configure Domain Overrides
190
	unbound_add_domain_overrides();
191

    
192
	// Configure Unbound statistics
193
	$statistics = unbound_statistics();
194

    
195
	// Configure Unbound access-lists
196
	unbound_acls_config();
197

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

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

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

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

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

    
261
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
262
	$rrset_cache_size = $msg_cache_size * 2;
263

    
264
	$unboundconf = <<<EOD
265
##########################
266
# Unbound Configuration
267
##########################
268

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

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

    
321
# DNS Rebinding
322
{$private_addr}
323
{$private_domains}
324

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

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

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

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

    
338
{$custom_options}
339

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

    
345
EOD;
346

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

    
350
	return 0;
351
}
352

    
353
function unbound_remote_control_setup() {
354
	global $g;
355

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

    
367
EOF;
368

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

    
372
		// Generate our keys
373
		do_as_unbound_user("unbound-control-setup");
374

    
375
	}
376
}
377

    
378
// Read /etc/hosts
379
function read_hosts() {
380

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

    
404
function sync_unbound_service() {
405
	global $config, $g;
406

    
407
	create_unbound_chroot_path();
408

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

    
418
}
419

    
420
function unbound_acl_id_used($id) {
421
	global $config;
422

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

    
428
	return false;
429
}
430

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

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

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

    
463
function unbound_add_domain_overrides($pvt_rev="") {
464
	global $config, $g;
465

    
466
	$domains = $config['unbound']['domainoverrides'];
467

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

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

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

    
504
function unbound_add_host_entries() {
505
	global $config, $g;
506

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

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

    
519
		if(!$added_ptr[$host['ipaddr']]) {
520
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
521
			$added_ptr[$host['ipaddr']] = true;
522
		}
523
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
524
		if (isset($host['name']))
525
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
526
	}
527

    
528
	// Write out entries
529
	create_unbound_chroot_path();
530
	file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
531

    
532
	/* dhcpleases will write to this config file, make sure it exists */
533
	@touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
534
}
535

    
536
function unbound_control($action) {
537
	global $config, $g;
538

    
539
	$cache_dumpfile = "/var/tmp/unbound_cache";
540

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

    
572
	}
573
}
574

    
575
// Generation of Unbound statistics
576
function unbound_statistics() {
577
	global $config;
578

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

    
598
EOF;
599

    
600
	return $stats;
601
}
602

    
603
// Unbound Access lists
604
function unbound_acls_config() {
605
	global $g, $config;
606

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

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

    
672
}
673

    
674
// Generate hosts and reload services
675
function unbound_hosts_generate() {
676
	// Generate our hosts file
677
	unbound_add_host_entries();
678

    
679
	// Reload our service to read the updates
680
	unbound_control("reload");
681
}
682

    
683
?>
(54-54/68)