Project

General

Profile

Download (19.7 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

    
38
/* Optimize Unbound for environment */
39
function unbound_optimization() {
40
	global $config;
41

    
42
	$optimization_settings = array();
43

    
44
	/* 
45
	 * Set the number of threads equal to number of CPUs.
46
	 * Use 1 to disable threading, if for some reason this sysctl fails.
47
	 */
48
	$numprocs = intval(get_single_sysctl('kern.smp.cpus'));
49
	if ($numprocs > 0)
50
		$optimization['number_threads'] = "num-threads: {$numprocs}";
51
	else
52
		$optimization['number_threads'] = "num-threads: 1";
53

    
54
	// Slabs to help reduce lock contention.
55
	if ($numprocs > 4) {
56
		$optimization['msg_cache_slabs'] = "msg-cache-slabs: {$numprocs}";
57
		$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$numprocs}";
58
		$optimization['infra_cache_slabs'] = "infra-cache-slabs: {$numprocs}";
59
		$optimization['key_cache_slabs'] = "key-cache-slabs: {$numprocs}";
60
	} else {
61
		$optimization['msg_cache_slabs'] = "msg-cache-slabs: 4";
62
		$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: 4";
63
		$optimization['infra_cache_slabs'] = "infra-cache-slabs: 4";
64
		$optimization['key_cache_slabs'] = "key-cache-slabs: 4";
65
	}
66

    
67
	// Size of the RRset cache
68
	$optimization['rrset_cache_size'] = "rrset-cache-size: 8m";
69

    
70
	// More outgoing connections per thread otherwise assign a default of 4096 for a single thread
71
	if ($numprocs > 0) {
72
		$or = (1024/$numprocs) - 50;
73
		$optimization['outgoing_range'] = "outgoing-range: {$or}";
74
	} else
75
		$optimization['outgoing_range'] = "outgoing-range: {4096}";
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)-1);
85
				// Check to ensure that the number is not a negative
86
				if ($so > 0)
87
					$optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
88
				else
89
					unset($optimization['so_rcvbuf']);
90
			}
91
		}
92
	}
93
	// Safety check in case kern.ipc.maxsockbuf is not available.
94
	if (!isset($optimization['so_rcvbuf']))
95
		$optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
96

    
97
	return $optimization;
98

    
99
}
100

    
101
function unbound_generate_config() {
102
	global $config, $g;
103

    
104
	// Setup optimization
105
	$optimization = unbound_optimization();
106

    
107
	// Setup DNSSEC support
108
	if (isset($config['unbound']['dnssec'])) {
109
		$module_config = "validator iterator";
110
		$anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root.key";
111
	} else
112
		$module_config = "iterator";
113

    
114
	// Setup DNS Rebinding
115
	if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
116
		// Private-addresses for DNS Rebinding
117
		$private_addr = <<<EOF
118
# For DNS Rebinding prevention
119
private-address: 10.0.0.0/8
120
private-address: 172.16.0.0/12
121
private-address: 192.168.0.0/16
122
private-address: fd00::/8
123
private-address: fe80::/10
124
EOF;
125
	}
126

    
127
	// Determine interfaces to run on
128
	$bindints = "";
129
	if (!empty($config['unbound']['active_interface'])) {
130
		$active_interfaces = explode(",", $config['unbound']['active_interface']);
131
		foreach($active_interfaces as $ubif) {
132
			$intip = get_interface_ip($ubif);
133
			if (is_ipaddrv4($intip))
134
				$bindints .= "interface: $intip\n";
135
			$intip = get_interface_ipv6($ubif);
136
			if (is_ipaddrv6($intip))
137
				$bindints .= "interface: $intip\n";
138
		}
139
	} else {
140
		$bindints .= "interface: 0.0.0.0\n";
141
		$bindints .= "interface: ::0\n";
142
	}
143

    
144
	// Determine interfaces to run on
145
	$outgoingints = "";
146
	if (!empty($config['unbound']['outgoing_interface'])) {
147
		$outgoingints = "# Outgoing interfaces to be used\n";
148
		$outgoing_interfaces = explode(",", $config['unbound']['outgoing_interface']);
149
		foreach($outgoing_interfaces as $outif) {
150
			$outip = get_interface_ip($outif);
151
			if (!is_null($outip))
152
				$outgoingints .= "outgoing-interface: $outip\n";
153
			$outip = get_interface_ipv6($outif);
154
			if (!is_null($outip))
155
				$outgoingints .= "outgoing-interface: $outip\n";
156
		}
157
	}
158

    
159
	// Allow DNS Rebind for forwarded domains
160
	if (isset($config['unbound']['domainoverrides']) && is_array($config['unbound']['domainoverrides'])) {
161
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
162
			$private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n";
163
			$private_domains .= unbound_add_domain_overrides("private");
164
		}
165
		$reverse_zones .= unbound_add_domain_overrides("reverse");
166
	}
167

    
168
	// Configure static Host entries
169
	unbound_add_host_entries();
170

    
171
	// Configure Domain Overrides
172
	unbound_add_domain_overrides();
173

    
174
	// Configure Unbound statistics
175
	$statistics = unbound_statistics();
176

    
177
	// Configure Unbound access-lists
178
	unbound_acls_config();
179

    
180
	// Add custom Unbound options
181
	if ($config['unbound']['custom_options']) {
182
		$custom_options_source = explode("\n", $config['unbound']['custom_options']);
183
		$custom_options = "# Unbound custom options\n";
184
		foreach ($custom_options_source as $ent)
185
			$custom_options .= $ent."\n";
186
	}
187

    
188
	// Server configuration variables
189
	$port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
190
	$hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
191
	$hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
192
	$harden_glue = isset($config['unbound']['hardenglue']) ? "yes" : "no";
193
	$harden_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
194
	$prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
195
	$prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
196
	$outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
197
	$incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
198
	$edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
199
	$num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
200
	$jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
201
	$cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
202
	$cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
203
	$infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
204
	$infra_lame_ttl = (!empty($config['unbound']['infra_lame_ttl'])) ? $config['unbound']['infra_lame_ttl'] : "900";
205
	$infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
206
	$unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
207
	if ($unwanted_reply_threshold == "disabled")
208
		$unwanted_reply_threshold = "0";
209
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
210
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
211

    
212
	// Set up forwarding if it configured
213
	if (isset($config['unbound']['forwarding'])) {
214
		$dnsservers = array();
215
		if (isset($config['system']['dnsallowoverride'])) {
216
			$ns = array_unique(get_nameservers());
217
			foreach($ns as $nameserver) {
218
				if ($nameserver)
219
					$dnsservers[] = $nameserver;
220
			}
221
		} else {
222
			$ns = array_unique(get_dns_servers());
223
			foreach($ns as $nameserver) {
224
				if ($nameserver)
225
					$dnsservers[] = $nameserver;
226
			}
227
		}
228

    
229
		if (!empty($dnsservers)) {
230
			$forward_conf .=<<<EOD
231
# Forwarding
232
forward-zone:
233
	name: "."
234

    
235
EOD;
236
			foreach($dnsservers as $dnsserver)
237
				$forward_conf .= "\tforward-addr: $dnsserver\n";
238
		}
239
	} else
240
		$forward_conf = "";
241

    
242
	$unboundconf = <<<EOD
243
##########################
244
# Unbound Configuration
245
##########################
246

    
247
##
248
# Server configuration
249
##
250
server:
251
{$reverse_zones}
252
chroot: {$g['unbound_chroot_path']}
253
username: "unbound"
254
directory: "{$g['unbound_chroot_path']}"
255
pidfile: "/var/run/unbound.pid"
256
use-syslog: yes
257
port: {$port}
258
verbosity: {$verbosity}
259
hide-identity: {$hide_identity}
260
hide-version: {$hide_version}
261
harden-referral-path: no
262
harden-glue: {$harden_glue}
263
do-ip4: yes
264
do-ip6: yes
265
do-udp: yes
266
do-tcp: yes
267
do-daemonize: yes
268
module-config: "{$module_config}"
269
unwanted-reply-threshold: {$unwanted_reply_threshold}
270
num-queries-per-thread: {$num_queries_per_thread}
271
jostle-timeout: {$jostle_timeout}
272
infra-host-ttl: {$infra_host_ttl}
273
infra-lame-ttl: {$infra_lame_ttl}
274
infra-cache-numhosts: {$infra_cache_numhosts}
275
outgoing-num-tcp: {$outgoing_num_tcp}
276
incoming-num-tcp: {$incoming_num_tcp}
277
edns-buffer-size: {$edns_buffer_size}
278
cache-max-ttl: {$cache_max_ttl}
279
cache-min-ttl: {$cache_min_ttl}
280
harden-dnssec-stripped: {$harden_dnssec_stripped}
281
msg-cache-size: {$msg_cache_size}m
282
{$optimization['number_threads']}
283
{$optimization['msg_cache_slabs']}
284
{$optimization['rrset_cache_slabs']}
285
{$optimization['infra_cache_slabs']}
286
{$optimization['key_cache_slabs']}
287
{$optimization['rrset_cache_size']}
288
{$optimization['outgoing_range']}
289
{$optimization['so_rcvbuf']}
290
{$anchor_file}
291
prefetch: {$prefetch}
292
prefetch-key: {$prefetch_key}
293
# Statistics
294
{$statistics}
295
# Interface IP(s) to bind to
296
{$bindints}
297
{$outgoingints}
298

    
299
# DNS Rebinding
300
{$private_addr}
301
{$private_domains}
302

    
303
# Access lists
304
include: {$g['unbound_chroot_path']}/access_lists.conf
305

    
306
# Static host entries
307
include: {$g['unbound_chroot_path']}/host_entries.conf
308

    
309
# dhcp lease entries
310
include: {$g['unbound_chroot_path']}/dhcpleases_entries.conf
311

    
312
# Domain overrides
313
include: {$g['unbound_chroot_path']}/domainoverrides.conf
314
{$forward_conf}
315

    
316
{$custom_options}
317

    
318
###
319
# Remote Control Config
320
###
321
include: {$g['unbound_chroot_path']}/remotecontrol.conf
322

    
323
EOD;
324

    
325
	file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
326

    
327
	return 0;
328
}
329

    
330
function unbound_remote_control_setup() {
331
	global $g;
332

    
333
	if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
334
		$remotcfg = <<<EOF
335
remote-control:
336
	control-enable: yes
337
	control-interface: 127.0.0.1
338
	control-port: 953
339
	server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
340
	server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
341
	control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
342
	control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
343

    
344
EOF;
345

    
346
		file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
347

    
348
		// Generate our keys
349
		do_as_unbound_user("unbound-control-setup");
350

    
351
	}
352
}
353

    
354
// Read /etc/hosts
355
function read_hosts() {
356

    
357
	/* Open /etc/hosts and extract the only dhcpleases info
358
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
359
	 */
360
	$etc_hosts = array();
361
	foreach (file('/etc/hosts') as $line) {
362
		if (strpos($line, "dhcpleases automatically entered"))
363
			break;
364
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
365
		if (empty($d) || substr(reset($d), 0, 1) == "#")
366
			continue;
367
		$ip = array_shift($d);
368
		$fqdn = array_shift($d);
369
		$name = array_shift($d);
370
		if (!empty($fqdn) && $fqdn != "empty") {
371
			if (!empty($name) && $name != "empty")
372
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
373
			else
374
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
375
		}
376
	}
377
	return $etc_hosts;
378
}
379

    
380
function sync_unbound_service() {
381
	global $config, $g;
382

    
383
	// Configure chroot
384
	if (!is_dir($g['unbound_chroot_path'])) {
385
		mkdir($g['unbound_chroot_path']);
386
		chown($g['unbound_chroot_path'], "unbound");
387
		chgrp($g['unbound_chroot_path'], "unbound");
388
	}
389

    
390
	// Configure our Unbound service
391
	do_as_unbound_user("unbound-anchor");
392
	unbound_remote_control_setup();
393
	unbound_generate_config();
394
	do_as_unbound_user("start");
395
	require_once("service-utils.inc");
396
	if (is_service_running("unbound"))
397
		do_as_unbound_user("restore_cache");
398

    
399
}
400

    
401
function unbound_acl_id_used($id) {
402
	global $config;
403

    
404
	if (is_array($config['unbound']['acls']))
405
		foreach($config['unbound']['acls'] as & $acls)
406
			if ($id == $acls['aclid'])
407
				return true;
408

    
409
	return false;
410
}
411

    
412
function unbound_get_next_id() {
413
	$aclid = 0;
414
	while(unbound_acl_id_used($aclid))
415
		$aclid++;
416
	return $aclid;
417
}
418

    
419
// Execute commands as the user unbound
420
function do_as_unbound_user($cmd) {
421
	global $g;
422

    
423
	switch ($cmd) {
424
	case "start":
425
		mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
426
		break;
427
	case "stop":
428
		mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
429
		break;
430
	case "reload":
431
		mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
432
		break;
433
	case "unbound-anchor":
434
		mwexec("echo '/usr/local/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
435
		break;
436
	case "unbound-control-setup":
437
		mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
438
		break;
439
	default:
440
		break;
441
	}
442
}
443

    
444
function unbound_add_domain_overrides($pvt_rev="") {
445
	global $config, $g;
446

    
447
	$domains = $config['unbound']['domainoverrides'];
448

    
449
	$sorted_domains = msort($domains, "domain");
450
	$result = array();
451
	foreach($sorted_domains as $domain) {
452
		$domain_key = current($domain);
453
		if (!isset($result[$domain_key]))
454
			$result[$domain_key] = array();
455
		$result[$domain_key][] = $domain['ip'];
456
	}
457

    
458
	// Domain overrides that have multiple entries need multiple stub-addr: added
459
	$domain_entries = "";
460
	foreach($result as $domain=>$ips) {
461
		if ($pvt_rev == "private") {
462
			$domain_entries .= "private-domain: \"$domain\"\n";
463
			$domain_entries .= "domain-insecure: \"$domain\"\n";
464
		} else if ($pvt_rev == "reverse") {
465
			if ((substr($domain,-14) == ".in-addr.arpa.") || (substr($domain,-13) == ".in-addr.arpa")) {
466
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
467
			}
468
		} else {
469
			$domain_entries .= "stub-zone:\n";
470
			$domain_entries .= "\tname: \"$domain\"\n";
471
			foreach($ips as $ip)
472
				$domain_entries .= "\tstub-addr: $ip\n";
473
			$domain_entries .= "\tstub-prime: no\n";
474
		}
475
	}
476

    
477
	if ($pvt_rev != "")
478
		return $domain_entries;
479
	else
480
		file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
481
}
482

    
483
function unbound_add_host_entries() {
484
	global $config, $g;
485

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

    
488
	$hosts = read_hosts();
489
	foreach ($hosts as $host) {
490
		if (is_ipaddrv4($host['ipaddr']))
491
			$type = 'A';
492
		else if (is_ipaddrv6($host['ipaddr']))
493
			$type = 'AAAA';
494
		else
495
			continue;
496

    
497
		$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
498
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
499
		if (isset($host['name']))
500
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
501
	}
502

    
503
	// Write out entries
504
	file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
505

    
506
	/* dhcpleases will write to this config file, make sure it exists */
507
	@touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
508
}
509

    
510
function unbound_control($action) {
511
	global $config, $g;
512

    
513
	$cache_dumpfile = "/var/tmp/unbound_cache";
514

    
515
	switch ($action) {
516
	case "start":
517
		// Start Unbound
518
		if ($config['unbound']['enable'] == "on") {
519
			if (!is_service_running("unbound"))
520
				do_as_unbound_user("start");
521
		}
522
		break;
523
	case "stop":
524
		if ($config['unbound']['enable'] == "on")
525
			do_as_unbound_user("stop");
526
		break;
527
	case "reload":
528
		if ($config['unbound']['enable'] == "on")
529
			do_as_unbound_user("reload");
530
		break;
531
	case "dump_cache":
532
		// Dump Unbound's Cache
533
		if ($config['unbound']['dumpcache'] == "on")
534
			do_as_unbound_user("dump_cache");
535
		break;
536
	case "restore_cache":
537
		// Restore Unbound's Cache
538
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
539
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0)
540
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
541
		}
542
		break;
543
	default:
544
		break;
545

    
546
	}
547
}
548

    
549
// Generation of Unbound statistics
550
function unbound_statistics() {
551
	global $config;
552

    
553
	if ($config['stats'] == "on") {
554
		$stats_interval = $config['unbound']['stats_interval'];
555
		$cumulative_stats = $config['cumulative_stats'];
556
		if ($config['extended_stats'] == "on")
557
			$extended_stats = "yes";
558
		else
559
			$extended_stats = "no";
560
	} else {
561
		$stats_interval = "0";
562
		$cumulative_stats = "no";
563
		$extended_stats = "no";
564
	}
565
	/* XXX To do - add RRD graphs */
566
	$stats = <<<EOF
567
# Unbound Statistics
568
statistics-interval: {$stats_interval}
569
extended-statistics: yes
570
statistics-cumulative: yes
571

    
572
EOF;
573

    
574
	return $stats;
575
}
576

    
577
// Unbound Access lists
578
function unbound_acls_config() {
579
	global $g, $config;
580

    
581
	$aclcfg = "access-control: 127.0.0.1/32 allow\n";
582
	$aclcfg .= "access-control: ::1 allow\n";
583
	// Add our networks for active interfaces including localhost
584
	if (!empty($config['unbound']['active_interface']))
585
		$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
586
	else
587
		$active_interfaces = get_configured_interface_with_descr();
588

    
589
	$bindints = "";
590
	foreach($active_interfaces as $ubif => $ifdesc) {
591
		$ifip = get_interface_ip($ubif);
592
		if (is_ipaddrv4($ifip)) {
593
			$subnet_bits = get_interface_subnet($ubif);
594
			$subnet_ip = gen_subnet($ifip, $subnet_bits);
595
			$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
596
		}
597
		$ifip = get_interface_ipv6($ubif);
598
		if (is_ipaddrv6($ifip)) {
599
			$subnet_bits = get_interface_subnetv6($ubif);
600
			$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
601
			$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
602
		}
603
	}
604

    
605
	// Configure the custom ACLs
606
	if (is_array($config['unbound']['acls'])) {
607
		foreach($config['unbound']['acls'] as $unbound_acl) {
608
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
609
			foreach($unbound_acl['row'] as $network) {
610
				if ($unbound_acl['aclaction'] == "allow snoop")
611
					$unbound_acl['aclaction'] = "allow_snoop";
612
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
613
			}
614
		}
615
	}
616
	// Write out Access list
617
	file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $aclcfg);
618

    
619
}
620

    
621
// Generate hosts and reload services
622
function unbound_hosts_generate() {
623
	// Generate our hosts file
624
	unbound_add_host_entries();
625

    
626
	// Reload our service to read the updates
627
	unbound_control("reload");
628
}
629

    
630
?>
(54-54/68)