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) 2014 Warren Baker <warren@decoy.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 > 0)
64
		$optimization['number_threads'] = "num-threads: {$numprocs}";
65
	else
66
		$optimization['number_threads'] = "num-threads: 1";
67

    
68
	// Slabs to help reduce lock contention.
69
	if ($numprocs > 4) {
70
		$optimization['msg_cache_slabs'] = "msg-cache-slabs: {$numprocs}";
71
		$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$numprocs}";
72
		$optimization['infra_cache_slabs'] = "infra-cache-slabs: {$numprocs}";
73
		$optimization['key_cache_slabs'] = "key-cache-slabs: {$numprocs}";
74
	} else {
75
		$optimization['msg_cache_slabs'] = "msg-cache-slabs: 4";
76
		$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: 4";
77
		$optimization['infra_cache_slabs'] = "infra-cache-slabs: 4";
78
		$optimization['key_cache_slabs'] = "key-cache-slabs: 4";
79
	}
80

    
81
	// Size of the RRset cache
82
	$optimization['rrset_cache_size'] = "rrset-cache-size: 8m";
83

    
84
	/*
85
	 * Larger socket buffer for busy servers
86
	 * Check that it is set to 4MB (by default the OS has it configured to 4MB)
87
	 */
88
	if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
89
		foreach ($config['sysctl']['item'] as $tunable) {
90
			if ($tunable['tunable'] == 'kern.ipc.maxsockbuf') {
91
				$so = floor(($tunable['value']/1024/1024)-4);
92
				// Check to ensure that the number is not a negative
93
				if ($so >= 4) {
94
					// Limit to 32MB, users might set maxsockbuf very high for other reasons.
95
					// We do not want unbound to fail because of that.
96
					$so = min($so, 32);
97
					$optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
98
				} else {
99
					unset($optimization['so_rcvbuf']);
100
				}
101
			}
102
		}
103
	}
104
	// Safety check in case kern.ipc.maxsockbuf is not available.
105
	if (!isset($optimization['so_rcvbuf']))
106
		$optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
107

    
108
	return $optimization;
109

    
110
}
111

    
112
function unbound_generate_config() {
113
	global $config, $g;
114

    
115
	// Setup optimization
116
	$optimization = unbound_optimization();
117

    
118
	// Setup DNSSEC support
119
	if (isset($config['unbound']['dnssec'])) {
120
		$module_config = "validator iterator";
121
		$anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root.key";
122
	} else
123
		$module_config = "iterator";
124

    
125
	// Setup DNS Rebinding
126
	if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
127
		// Private-addresses for DNS Rebinding
128
		$private_addr = <<<EOF
129
# For DNS Rebinding prevention
130
private-address: 10.0.0.0/8
131
private-address: 172.16.0.0/12
132
private-address: 169.254.0.0/16
133
private-address: 192.168.0.0/16
134
private-address: fd00::/8
135
private-address: fe80::/10
136
EOF;
137
	}
138

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

    
167
	// Determine interfaces to run on
168
	$outgoingints = "";
169
	if (!empty($config['unbound']['outgoing_interface'])) {
170
		$outgoingints = "# Outgoing interfaces to be used\n";
171
		$outgoing_interfaces = explode(",", $config['unbound']['outgoing_interface']);
172
		foreach($outgoing_interfaces as $outif) {
173
			$outip = get_interface_ip($outif);
174
			if (!is_null($outip))
175
				$outgoingints .= "outgoing-interface: $outip\n";
176
			$outip = get_interface_ipv6($outif);
177
			if (!is_null($outip))
178
				$outgoingints .= "outgoing-interface: $outip\n";
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
	// Server configuration variables
212
	$port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
213
	$hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
214
	$hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
215
	$harden_glue = isset($config['unbound']['hardenglue']) ? "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
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
232
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
233

    
234
	// Set up forwarding if it configured
235
	if (isset($config['unbound']['forwarding'])) {
236
		$dnsservers = array();
237
		if (isset($config['system']['dnsallowoverride'])) {
238
			$ns = array_unique(get_nameservers());
239
			foreach($ns as $nameserver) {
240
				if ($nameserver)
241
					$dnsservers[] = $nameserver;
242
			}
243
		} else {
244
			$ns = array_unique(get_dns_servers());
245
			foreach($ns as $nameserver) {
246
				if ($nameserver)
247
					$dnsservers[] = $nameserver;
248
			}
249
		}
250

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

    
257
EOD;
258
			foreach($dnsservers as $dnsserver)
259
				$forward_conf .= "\tforward-addr: $dnsserver\n";
260
		}
261
	} else
262
		$forward_conf = "";
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-referral-path: no
284
harden-glue: {$harden_glue}
285
do-ip4: yes
286
do-ip6: yes
287
do-udp: yes
288
do-tcp: yes
289
do-daemonize: yes
290
module-config: "{$module_config}"
291
unwanted-reply-threshold: {$unwanted_reply_threshold}
292
num-queries-per-thread: {$num_queries_per_thread}
293
jostle-timeout: {$jostle_timeout}
294
infra-host-ttl: {$infra_host_ttl}
295
infra-cache-numhosts: {$infra_cache_numhosts}
296
outgoing-num-tcp: {$outgoing_num_tcp}
297
incoming-num-tcp: {$incoming_num_tcp}
298
edns-buffer-size: {$edns_buffer_size}
299
cache-max-ttl: {$cache_max_ttl}
300
cache-min-ttl: {$cache_min_ttl}
301
harden-dnssec-stripped: {$harden_dnssec_stripped}
302
msg-cache-size: {$msg_cache_size}m
303
{$optimization['number_threads']}
304
{$optimization['msg_cache_slabs']}
305
{$optimization['rrset_cache_slabs']}
306
{$optimization['infra_cache_slabs']}
307
{$optimization['key_cache_slabs']}
308
{$optimization['rrset_cache_size']}
309
outgoing-range: 4096
310
{$optimization['so_rcvbuf']}
311
{$anchor_file}
312
prefetch: {$prefetch}
313
prefetch-key: {$prefetch_key}
314
# Statistics
315
{$statistics}
316
# Interface IP(s) to bind to
317
{$bindints}
318
{$outgoingints}
319

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

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

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

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

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

    
337
{$custom_options}
338

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

    
344
EOD;
345

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

    
349
	return 0;
350
}
351

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

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

    
366
EOF;
367

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

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

    
374
	}
375
}
376

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

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

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

    
406
	create_unbound_chroot_path();
407

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

    
417
}
418

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

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

    
427
	return false;
428
}
429

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
567
	}
568
}
569

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

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

    
593
EOF;
594

    
595
	return $stats;
596
}
597

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

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

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

    
667
}
668

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

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

    
678
?>
(54-54/68)