Project

General

Profile

Download (21.4 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-glue: {$harden_glue}
281
do-ip4: yes
282
do-ip6: yes
283
do-udp: yes
284
do-tcp: yes
285
do-daemonize: yes
286
module-config: "{$module_config}"
287
unwanted-reply-threshold: {$unwanted_reply_threshold}
288
num-queries-per-thread: {$num_queries_per_thread}
289
jostle-timeout: {$jostle_timeout}
290
infra-host-ttl: {$infra_host_ttl}
291
infra-cache-numhosts: {$infra_cache_numhosts}
292
outgoing-num-tcp: {$outgoing_num_tcp}
293
incoming-num-tcp: {$incoming_num_tcp}
294
edns-buffer-size: {$edns_buffer_size}
295
cache-max-ttl: {$cache_max_ttl}
296
cache-min-ttl: {$cache_min_ttl}
297
harden-dnssec-stripped: {$harden_dnssec_stripped}
298
msg-cache-size: {$msg_cache_size}m
299
rrset-cache-size: {$rrset_cache_size}m
300

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

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

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

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

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

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

    
335
{$custom_options}
336

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

    
342
EOD;
343

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

    
347
	return 0;
348
}
349

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

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

    
364
EOF;
365

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

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

    
372
	}
373
}
374

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

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

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

    
404
	create_unbound_chroot_path();
405

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

    
415
}
416

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

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

    
425
	return false;
426
}
427

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

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

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

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

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

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

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

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

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

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

    
506
	$hosts = read_hosts();
507
	$added_ptr = array();
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
		if(!$added_ptr[$host['ipaddr']]) {
517
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
518
			$added_ptr[$host['ipaddr']] = true;
519
		}
520
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
521
		if (isset($host['name']))
522
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
523
	}
524

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

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

    
533
function unbound_control($action) {
534
	global $config, $g;
535

    
536
	$cache_dumpfile = "/var/tmp/unbound_cache";
537

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

    
569
	}
570
}
571

    
572
// Generation of Unbound statistics
573
function unbound_statistics() {
574
	global $config;
575

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

    
595
EOF;
596

    
597
	return $stats;
598
}
599

    
600
// Unbound Access lists
601
function unbound_acls_config() {
602
	global $g, $config;
603

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

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

    
669
}
670

    
671
// Generate hosts and reload services
672
function unbound_hosts_generate() {
673
	// Generate our hosts file
674
	unbound_add_host_entries();
675

    
676
	// Reload our service to read the updates
677
	unbound_control("reload");
678
}
679

    
680
?>
(54-54/68)