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 is 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
		}
247
		$sys_dnsservers = array_unique(get_dns_servers());
248
		foreach ($sys_dnsservers as $sys_dnsserver) {
249
			if ($sys_dnsserver && (!in_array($sys_dnsserver, $ns))) {
250
				$dnsservers[] = $sys_dnsserver;
251
			}
252
		}
253

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

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

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

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

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

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

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

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

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

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

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

    
346
{$custom_options}
347

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

    
353
EOD;
354

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

    
358
	return 0;
359
}
360

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

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

    
375
EOF;
376

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

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

    
383
	}
384
}
385

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

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

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

    
418
	create_unbound_chroot_path();
419

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

    
430
}
431

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

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

    
443
	return false;
444
}
445

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
597
	}
598
}
599

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

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

    
624
EOF;
625

    
626
	return $stats;
627
}
628

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

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

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

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

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

    
702
}
703

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

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

    
713
?>
(54-54/68)