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_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
209
	$prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
210
	$prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
211
	$outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
212
	$incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
213
	$edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
214
	$num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
215
	$jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
216
	$cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
217
	$cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
218
	$infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
219
	$infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
220
	$unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
221
	if ($unwanted_reply_threshold == "disabled")
222
		$unwanted_reply_threshold = "0";
223
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
224
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
225
	$use_caps = isset($config['unbound']['use_caps']) ? "yes" : "no";
226

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

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

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

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

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

    
267
##
268
# Server configuration
269
##
270
server:
271
{$reverse_zones}
272
chroot: {$g['unbound_chroot_path']}
273
username: "unbound"
274
directory: "{$g['unbound_chroot_path']}"
275
pidfile: "/var/run/unbound.pid"
276
use-syslog: yes
277
port: {$port}
278
verbosity: {$verbosity}
279
hide-identity: {$hide_identity}
280
hide-version: {$hide_version}
281
harden-glue: yes
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
	$added_ptr = array();
509
	foreach ($hosts as $host) {
510
		if (is_ipaddrv4($host['ipaddr']))
511
			$type = 'A';
512
		else if (is_ipaddrv6($host['ipaddr']))
513
			$type = 'AAAA';
514
		else
515
			continue;
516

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

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

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

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

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

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

    
570
	}
571
}
572

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

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

    
596
EOF;
597

    
598
	return $stats;
599
}
600

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

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

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

    
670
}
671

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

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

    
681
?>
(54-54/68)