Project

General

Profile

Download (21.6 KB) Statistics
| Branch: | Tag: | Revision:
1 f20afeb6 Warren Baker
<?php
2
/*
3 fe9d4894 Renato Botelho
	unbound.inc
4
	part of the pfSense project (https://www.pfsense.org)
5 a771a6ae Warren Baker
	Copyright (C) 2015 Warren Baker <warren@percol8.co.za>
6 fe9d4894 Renato Botelho
	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 3ba07784 Renato Botelho
	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 fe9d4894 Renato Botelho
	pfSense_MODULE: unbound
32 f20afeb6 Warren Baker
*/
33
34
/* include all configuration functions */
35
require_once("config.inc");
36
require_once("functions.inc");
37 3bdf2a70 Chris Buechler
require_once("filter.inc");
38
require_once("shaper.inc");
39 f20afeb6 Warren Baker
40 e318d592 Phil Davis
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 f20afeb6 Warren Baker
/* Optimize Unbound for environment */
53
function unbound_optimization() {
54 fe9d4894 Renato Botelho
	global $config;
55
56
	$optimization_settings = array();
57
58 751533a2 Phil Davis
	/*
59 fe9d4894 Renato Botelho
	 * 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 46762efe Warren Baker
	if ($numprocs > 1) {
64 fe9d4894 Renato Botelho
		$optimization['number_threads'] = "num-threads: {$numprocs}";
65 46762efe Warren Baker
		$optimize_num = pow(2,floor(log($numprocs,2)));
66
	} else {
67 fe9d4894 Renato Botelho
		$optimization['number_threads'] = "num-threads: 1";
68 46762efe Warren Baker
		$optimize_num = 4;
69
	}
70 fe9d4894 Renato Botelho
71
	// Slabs to help reduce lock contention.
72 46762efe Warren Baker
	$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 fe9d4894 Renato Botelho
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 d87fcac9 Ermal
	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 ad04bbbf Warren Baker
				$so = floor(($tunable['value']/1024/1024)-4);
85 d87fcac9 Ermal
				// Check to ensure that the number is not a negative
86 ad04bbbf Warren Baker
				if ($so >= 4) {
87
					// Limit to 32MB, users might set maxsockbuf very high for other reasons.
88 4708c6f0 Phil Davis
					// We do not want unbound to fail because of that.
89 ad04bbbf Warren Baker
					$so = min($so, 32);
90 d87fcac9 Ermal
					$optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
91 ad04bbbf Warren Baker
				} else {
92 d87fcac9 Ermal
					unset($optimization['so_rcvbuf']);
93 ad04bbbf Warren Baker
				}
94 d87fcac9 Ermal
			}
95 fe9d4894 Renato Botelho
		}
96
	}
97
	// Safety check in case kern.ipc.maxsockbuf is not available.
98 751533a2 Phil Davis
	if (!isset($optimization['so_rcvbuf'])) {
99 fe9d4894 Renato Botelho
		$optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
100 751533a2 Phil Davis
	}
101 fe9d4894 Renato Botelho
102
	return $optimization;
103 f20afeb6 Warren Baker
104
}
105
106
function unbound_generate_config() {
107 fe9d4894 Renato Botelho
	global $config, $g;
108
109
	// Setup optimization
110
	$optimization = unbound_optimization();
111
112
	// Setup DNSSEC support
113
	if (isset($config['unbound']['dnssec'])) {
114
		$module_config = "validator iterator";
115
		$anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root.key";
116 751533a2 Phil Davis
	} else {
117 fe9d4894 Renato Botelho
		$module_config = "iterator";
118 751533a2 Phil Davis
	}
119 fe9d4894 Renato Botelho
120
	// Setup DNS Rebinding
121
	if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
122
		// Private-addresses for DNS Rebinding
123
		$private_addr = <<<EOF
124 f20afeb6 Warren Baker
# For DNS Rebinding prevention
125
private-address: 10.0.0.0/8
126
private-address: 172.16.0.0/12
127 c683f627 Chris Buechler
private-address: 169.254.0.0/16
128 f20afeb6 Warren Baker
private-address: 192.168.0.0/16
129
private-address: fd00::/8
130
private-address: fe80::/10
131
EOF;
132 fe9d4894 Renato Botelho
	}
133
134
	// Determine interfaces to run on
135
	$bindints = "";
136
	if (!empty($config['unbound']['active_interface'])) {
137
		$active_interfaces = explode(",", $config['unbound']['active_interface']);
138 b7960673 Chris Buechler
		if (in_array("all", $active_interfaces, true)) {
139
			$bindints .= "interface: 0.0.0.0\n";
140
			$bindints .= "interface: ::0\n";
141 f358fe3f Chris Buechler
			$bindints .= "interface-automatic: yes\n";
142 b7960673 Chris Buechler
		} else {
143 751533a2 Phil Davis
			foreach ($active_interfaces as $ubif) {
144 a0e9e17d Chris Buechler
				if (is_ipaddr($ubif)) {
145 751533a2 Phil Davis
					//$bindints .= "interface: $ubif\n";  -- until redmine #4062 is fixed, then uncomment this.
146 a0e9e17d Chris Buechler
				} else {
147
					$intip = get_interface_ip($ubif);
148 751533a2 Phil Davis
					if (is_ipaddrv4($intip)) {
149 a0e9e17d Chris Buechler
						$bindints .= "interface: $intip\n";
150 751533a2 Phil Davis
					}
151 a0e9e17d Chris Buechler
					$intip = get_interface_ipv6($ubif);
152 751533a2 Phil Davis
					if (is_ipaddrv6($intip)) {
153
						if (!is_linklocal($intip)) {  // skipping link local for the moment to not break people's configs: https://redmine.pfsense.org/issues/4062
154 a0e9e17d Chris Buechler
							$bindints .= "interface: $intip\n";
155 751533a2 Phil Davis
						}
156
					}
157 a0e9e17d Chris Buechler
				}
158 751533a2 Phil Davis
			}
159 fe9d4894 Renato Botelho
		}
160
	} else {
161
		$bindints .= "interface: 0.0.0.0\n";
162
		$bindints .= "interface: ::0\n";
163
	}
164
165
	// Determine interfaces to run on
166
	$outgoingints = "";
167
	if (!empty($config['unbound']['outgoing_interface'])) {
168
		$outgoingints = "# Outgoing interfaces to be used\n";
169
		$outgoing_interfaces = explode(",", $config['unbound']['outgoing_interface']);
170 751533a2 Phil Davis
		foreach ($outgoing_interfaces as $outif) {
171 fe9d4894 Renato Botelho
			$outip = get_interface_ip($outif);
172 751533a2 Phil Davis
			if (!is_null($outip)) {
173 fe9d4894 Renato Botelho
				$outgoingints .= "outgoing-interface: $outip\n";
174 751533a2 Phil Davis
			}
175 fe9d4894 Renato Botelho
			$outip = get_interface_ipv6($outif);
176 751533a2 Phil Davis
			if (!is_null($outip)) {
177 fe9d4894 Renato Botelho
				$outgoingints .= "outgoing-interface: $outip\n";
178 751533a2 Phil Davis
			}
179 fe9d4894 Renato Botelho
		}
180
	}
181
182
	// Allow DNS Rebind for forwarded domains
183 984abd66 Phil Davis
	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 fe9d4894 Renato Botelho
	}
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 cfb5073f Renato Botelho
		$custom_options_source = explode("\n", base64_decode($config['unbound']['custom_options']));
206 b9608ab6 Phil Davis
		$custom_options = "# Unbound custom options\n";
207 751533a2 Phil Davis
		foreach ($custom_options_source as $ent) {
208 b9608ab6 Phil Davis
			$custom_options .= $ent."\n";
209 751533a2 Phil Davis
		}
210 fe9d4894 Renato Botelho
	}
211
212
	// Server configuration variables
213
	$port = (is_port($config['unbound']['port'])) ? $config['unbound']['port'] : "53";
214 b9608ab6 Phil Davis
	$hide_identity = isset($config['unbound']['hideidentity']) ? "yes" : "no";
215
	$hide_version = isset($config['unbound']['hideversion']) ? "yes" : "no";
216
	$harden_dnssec_stripped = isset($config['unbound']['dnssecstripped']) ? "yes" : "no";
217
	$prefetch = isset($config['unbound']['prefetch']) ? "yes" : "no";
218
	$prefetch_key = isset($config['unbound']['prefetchkey']) ? "yes" : "no";
219 fe9d4894 Renato Botelho
	$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 751533a2 Phil Davis
	if ($unwanted_reply_threshold == "disabled") {
230 b9608ab6 Phil Davis
		$unwanted_reply_threshold = "0";
231 751533a2 Phil Davis
	}
232 b9608ab6 Phil Davis
	$msg_cache_size = (!empty($config['unbound']['msgcachesize'])) ? $config['unbound']['msgcachesize'] : "4";
233
	$verbosity = isset($config['unbound']['log_verbosity']) ? $config['unbound']['log_verbosity'] : 1;
234 a771a6ae Warren Baker
	$use_caps = isset($config['unbound']['use_caps']) ? "yes" : "no";
235 fe9d4894 Renato Botelho
236
	// Set up forwarding if it configured
237
	if (isset($config['unbound']['forwarding'])) {
238
		$dnsservers = array();
239
		if (isset($config['system']['dnsallowoverride'])) {
240
			$ns = array_unique(get_nameservers());
241 751533a2 Phil Davis
			foreach ($ns as $nameserver) {
242
				if ($nameserver) {
243 fe9d4894 Renato Botelho
					$dnsservers[] = $nameserver;
244 751533a2 Phil Davis
				}
245 fe9d4894 Renato Botelho
			}
246
		} else {
247
			$ns = array_unique(get_dns_servers());
248 751533a2 Phil Davis
			foreach ($ns as $nameserver) {
249
				if ($nameserver) {
250 fe9d4894 Renato Botelho
					$dnsservers[] = $nameserver;
251 751533a2 Phil Davis
				}
252 fe9d4894 Renato Botelho
			}
253
		}
254
255
		if (!empty($dnsservers)) {
256
			$forward_conf .=<<<EOD
257 75e6d1b2 Warren Baker
# Forwarding
258 be5aa310 Warren Baker
forward-zone:
259 fe9d4894 Renato Botelho
	name: "."
260 be5aa310 Warren Baker
261
EOD;
262 751533a2 Phil Davis
			foreach ($dnsservers as $dnsserver) {
263 fe9d4894 Renato Botelho
				$forward_conf .= "\tforward-addr: $dnsserver\n";
264 751533a2 Phil Davis
			}
265 fe9d4894 Renato Botelho
		}
266 751533a2 Phil Davis
	} else {
267 fe9d4894 Renato Botelho
		$forward_conf = "";
268 751533a2 Phil Davis
	}
269 be5aa310 Warren Baker
270 2597415b Chris Buechler
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
271
	$rrset_cache_size = $msg_cache_size * 2;
272
273 fe9d4894 Renato Botelho
	$unboundconf = <<<EOD
274 f20afeb6 Warren Baker
##########################
275
# Unbound Configuration
276
##########################
277
278
##
279
# Server configuration
280
##
281
server:
282 984abd66 Phil Davis
{$reverse_zones}
283 f20afeb6 Warren Baker
chroot: {$g['unbound_chroot_path']}
284
username: "unbound"
285 56a87b19 Warren Baker
directory: "{$g['unbound_chroot_path']}"
286 f20afeb6 Warren Baker
pidfile: "/var/run/unbound.pid"
287
use-syslog: yes
288 d12889b0 Warren Baker
port: {$port}
289 56a87b19 Warren Baker
verbosity: {$verbosity}
290 b9608ab6 Phil Davis
hide-identity: {$hide_identity}
291
hide-version: {$hide_version}
292 5c7c369f Chris Buechler
harden-glue: yes
293 f20afeb6 Warren Baker
do-ip4: yes
294
do-ip6: yes
295
do-udp: yes
296
do-tcp: yes
297
do-daemonize: yes
298
module-config: "{$module_config}"
299 b9608ab6 Phil Davis
unwanted-reply-threshold: {$unwanted_reply_threshold}
300
num-queries-per-thread: {$num_queries_per_thread}
301
jostle-timeout: {$jostle_timeout}
302
infra-host-ttl: {$infra_host_ttl}
303
infra-cache-numhosts: {$infra_cache_numhosts}
304
outgoing-num-tcp: {$outgoing_num_tcp}
305
incoming-num-tcp: {$incoming_num_tcp}
306
edns-buffer-size: {$edns_buffer_size}
307 56a87b19 Warren Baker
cache-max-ttl: {$cache_max_ttl}
308
cache-min-ttl: {$cache_min_ttl}
309 b9608ab6 Phil Davis
harden-dnssec-stripped: {$harden_dnssec_stripped}
310
msg-cache-size: {$msg_cache_size}m
311 2597415b Chris Buechler
rrset-cache-size: {$rrset_cache_size}m
312
313 f20afeb6 Warren Baker
{$optimization['number_threads']}
314
{$optimization['msg_cache_slabs']}
315
{$optimization['rrset_cache_slabs']}
316
{$optimization['infra_cache_slabs']}
317
{$optimization['key_cache_slabs']}
318 2cbcc256 Warren Baker
outgoing-range: 4096
319 f20afeb6 Warren Baker
{$optimization['so_rcvbuf']}
320
{$anchor_file}
321 56a87b19 Warren Baker
prefetch: {$prefetch}
322
prefetch-key: {$prefetch_key}
323 a771a6ae Warren Baker
use-caps-for-id: {$use_caps}
324 f20afeb6 Warren Baker
# Statistics
325
{$statistics}
326
# Interface IP(s) to bind to
327 16a3108f Warren Baker
{$bindints}
328 6374fb57 Warren Baker
{$outgoingints}
329 f20afeb6 Warren Baker
330
# DNS Rebinding
331
{$private_addr}
332
{$private_domains}
333
334 4e8e8cc8 Warren Baker
# Access lists
335
include: {$g['unbound_chroot_path']}/access_lists.conf
336
337 f20afeb6 Warren Baker
# Static host entries
338 56a87b19 Warren Baker
include: {$g['unbound_chroot_path']}/host_entries.conf
339 f20afeb6 Warren Baker
340 b3977493 Renato Botelho
# dhcp lease entries
341
include: {$g['unbound_chroot_path']}/dhcpleases_entries.conf
342
343 f20afeb6 Warren Baker
# Domain overrides
344 ae5bbb64 Warren Baker
include: {$g['unbound_chroot_path']}/domainoverrides.conf
345 be5aa310 Warren Baker
{$forward_conf}
346
347 f20afeb6 Warren Baker
{$custom_options}
348
349
###
350
# Remote Control Config
351
###
352 56a87b19 Warren Baker
include: {$g['unbound_chroot_path']}/remotecontrol.conf
353 f20afeb6 Warren Baker
354
EOD;
355
356 e318d592 Phil Davis
	create_unbound_chroot_path();
357 fe9d4894 Renato Botelho
	file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
358 f20afeb6 Warren Baker
359 fe9d4894 Renato Botelho
	return 0;
360 f20afeb6 Warren Baker
}
361
362
function unbound_remote_control_setup() {
363 fe9d4894 Renato Botelho
	global $g;
364 f20afeb6 Warren Baker
365 fe9d4894 Renato Botelho
	if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
366
		$remotcfg = <<<EOF
367 f20afeb6 Warren Baker
remote-control:
368 fe9d4894 Renato Botelho
	control-enable: yes
369
	control-interface: 127.0.0.1
370
	control-port: 953
371
	server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
372
	server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
373
	control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
374
	control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
375 56a87b19 Warren Baker
376 f20afeb6 Warren Baker
EOF;
377
378 e318d592 Phil Davis
		create_unbound_chroot_path();
379 fe9d4894 Renato Botelho
		file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
380 f20afeb6 Warren Baker
381 fe9d4894 Renato Botelho
		// Generate our keys
382
		do_as_unbound_user("unbound-control-setup");
383 f20afeb6 Warren Baker
384 fe9d4894 Renato Botelho
	}
385 56a87b19 Warren Baker
}
386 f20afeb6 Warren Baker
387 56a87b19 Warren Baker
// Read /etc/hosts
388 f20afeb6 Warren Baker
function read_hosts() {
389
390 fe9d4894 Renato Botelho
	/* Open /etc/hosts and extract the only dhcpleases info
391
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
392
	 */
393
	$etc_hosts = array();
394
	foreach (file('/etc/hosts') as $line) {
395 751533a2 Phil Davis
		if (strpos($line, "dhcpleases automatically entered")) {
396 b3977493 Renato Botelho
			break;
397 751533a2 Phil Davis
		}
398 b3977493 Renato Botelho
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
399 751533a2 Phil Davis
		if (empty($d) || substr(reset($d), 0, 1) == "#") {
400 fe9d4894 Renato Botelho
			continue;
401 751533a2 Phil Davis
		}
402 b3977493 Renato Botelho
		$ip = array_shift($d);
403
		$fqdn = array_shift($d);
404
		$name = array_shift($d);
405
		if (!empty($fqdn) && $fqdn != "empty") {
406 751533a2 Phil Davis
			if (!empty($name) && $name != "empty") {
407 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
408 751533a2 Phil Davis
			} else {
409 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
410 751533a2 Phil Davis
			}
411 fe9d4894 Renato Botelho
		}
412
	}
413
	return $etc_hosts;
414 f20afeb6 Warren Baker
}
415
416
function sync_unbound_service() {
417 fe9d4894 Renato Botelho
	global $config, $g;
418
419 e318d592 Phil Davis
	create_unbound_chroot_path();
420 fe9d4894 Renato Botelho
421
	// Configure our Unbound service
422
	do_as_unbound_user("unbound-anchor");
423
	unbound_remote_control_setup();
424
	unbound_generate_config();
425
	do_as_unbound_user("start");
426
	require_once("service-utils.inc");
427 751533a2 Phil Davis
	if (is_service_running("unbound")) {
428 fe9d4894 Renato Botelho
		do_as_unbound_user("restore_cache");
429 751533a2 Phil Davis
	}
430 f20afeb6 Warren Baker
431
}
432
433
function unbound_acl_id_used($id) {
434 fe9d4894 Renato Botelho
	global $config;
435 f20afeb6 Warren Baker
436 751533a2 Phil Davis
	if (is_array($config['unbound']['acls'])) {
437
		foreach ($config['unbound']['acls'] as & $acls) {
438
			if ($id == $acls['aclid']) {
439 fe9d4894 Renato Botelho
				return true;
440 751533a2 Phil Davis
			}
441
		}
442
	}
443 f20afeb6 Warren Baker
444 fe9d4894 Renato Botelho
	return false;
445 f20afeb6 Warren Baker
}
446
447
function unbound_get_next_id() {
448 fe9d4894 Renato Botelho
	$aclid = 0;
449 751533a2 Phil Davis
	while (unbound_acl_id_used($aclid)) {
450 fe9d4894 Renato Botelho
		$aclid++;
451 751533a2 Phil Davis
	}
452 fe9d4894 Renato Botelho
	return $aclid;
453 f20afeb6 Warren Baker
}
454
455
// Execute commands as the user unbound
456
function do_as_unbound_user($cmd) {
457 fe9d4894 Renato Botelho
	global $g;
458
459
	switch ($cmd) {
460 751533a2 Phil Davis
		case "start":
461
			mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
462
			break;
463
		case "stop":
464
			mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
465
			break;
466
		case "reload":
467
			mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
468
			break;
469
		case "unbound-anchor":
470
			mwexec("echo '/usr/local/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
471
			break;
472
		case "unbound-control-setup":
473
			mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
474
			break;
475
		default:
476
			break;
477 fe9d4894 Renato Botelho
	}
478 f20afeb6 Warren Baker
}
479
480 984abd66 Phil Davis
function unbound_add_domain_overrides($pvt_rev="") {
481 fe9d4894 Renato Botelho
	global $config, $g;
482
483
	$domains = $config['unbound']['domainoverrides'];
484
485
	$sorted_domains = msort($domains, "domain");
486
	$result = array();
487 751533a2 Phil Davis
	foreach ($sorted_domains as $domain) {
488 fe9d4894 Renato Botelho
		$domain_key = current($domain);
489 751533a2 Phil Davis
		if (!isset($result[$domain_key])) {
490 fe9d4894 Renato Botelho
			$result[$domain_key] = array();
491 751533a2 Phil Davis
		}
492 fe9d4894 Renato Botelho
		$result[$domain_key][] = $domain['ip'];
493
	}
494
495
	// Domain overrides that have multiple entries need multiple stub-addr: added
496
	$domain_entries = "";
497 751533a2 Phil Davis
	foreach ($result as $domain=>$ips) {
498 984abd66 Phil Davis
		if ($pvt_rev == "private") {
499 fe9d4894 Renato Botelho
			$domain_entries .= "private-domain: \"$domain\"\n";
500
			$domain_entries .= "domain-insecure: \"$domain\"\n";
501 984abd66 Phil Davis
		} else if ($pvt_rev == "reverse") {
502
			if ((substr($domain,-14) == ".in-addr.arpa.") || (substr($domain,-13) == ".in-addr.arpa")) {
503
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
504
			}
505 fe9d4894 Renato Botelho
		} else {
506
			$domain_entries .= "stub-zone:\n";
507
			$domain_entries .= "\tname: \"$domain\"\n";
508 751533a2 Phil Davis
			foreach ($ips as $ip) {
509 fe9d4894 Renato Botelho
				$domain_entries .= "\tstub-addr: $ip\n";
510 751533a2 Phil Davis
			}
511 fe9d4894 Renato Botelho
			$domain_entries .= "\tstub-prime: no\n";
512
		}
513
	}
514
515 751533a2 Phil Davis
	if ($pvt_rev != "") {
516 fe9d4894 Renato Botelho
		return $domain_entries;
517 751533a2 Phil Davis
	} else {
518 e318d592 Phil Davis
		create_unbound_chroot_path();
519 fe9d4894 Renato Botelho
		file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
520 e318d592 Phil Davis
	}
521 f20afeb6 Warren Baker
}
522
523
function unbound_add_host_entries() {
524 fe9d4894 Renato Botelho
	global $config, $g;
525
526
	$unbound_entries = "local-zone: \"{$config['system']['domain']}\" transparent\n";
527
528 b3977493 Renato Botelho
	$hosts = read_hosts();
529 06266c34 Lorenz Schori
	$added_ptr = array();
530 b3977493 Renato Botelho
	foreach ($hosts as $host) {
531 751533a2 Phil Davis
		if (is_ipaddrv4($host['ipaddr'])) {
532 b3977493 Renato Botelho
			$type = 'A';
533 751533a2 Phil Davis
		} else if (is_ipaddrv6($host['ipaddr'])) {
534 b3977493 Renato Botelho
			$type = 'AAAA';
535 751533a2 Phil Davis
		} else {
536 b3977493 Renato Botelho
			continue;
537 751533a2 Phil Davis
		}
538 fe9d4894 Renato Botelho
539 751533a2 Phil Davis
		if (!$added_ptr[$host['ipaddr']]) {
540 06266c34 Lorenz Schori
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
541 f29610b0 Lorenz Schori
			$added_ptr[$host['ipaddr']] = true;
542 06266c34 Lorenz Schori
		}
543 b3977493 Renato Botelho
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
544 751533a2 Phil Davis
		if (isset($host['name'])) {
545 b3977493 Renato Botelho
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
546 751533a2 Phil Davis
		}
547 fe9d4894 Renato Botelho
	}
548
549
	// Write out entries
550 e318d592 Phil Davis
	create_unbound_chroot_path();
551 fe9d4894 Renato Botelho
	file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
552 b3977493 Renato Botelho
553
	/* dhcpleases will write to this config file, make sure it exists */
554
	@touch("{$g['unbound_chroot_path']}/dhcpleases_entries.conf");
555 f20afeb6 Warren Baker
}
556
557 56a87b19 Warren Baker
function unbound_control($action) {
558 fe9d4894 Renato Botelho
	global $config, $g;
559
560
	$cache_dumpfile = "/var/tmp/unbound_cache";
561
562
	switch ($action) {
563
	case "start":
564
		// Start Unbound
565
		if ($config['unbound']['enable'] == "on") {
566 751533a2 Phil Davis
			if (!is_service_running("unbound")) {
567 fe9d4894 Renato Botelho
				do_as_unbound_user("start");
568 751533a2 Phil Davis
			}
569 fe9d4894 Renato Botelho
		}
570
		break;
571
	case "stop":
572 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
573 fe9d4894 Renato Botelho
			do_as_unbound_user("stop");
574 751533a2 Phil Davis
		}
575 fe9d4894 Renato Botelho
		break;
576
	case "reload":
577 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
578 fe9d4894 Renato Botelho
			do_as_unbound_user("reload");
579 751533a2 Phil Davis
		}
580 fe9d4894 Renato Botelho
		break;
581
	case "dump_cache":
582
		// Dump Unbound's Cache
583 751533a2 Phil Davis
		if ($config['unbound']['dumpcache'] == "on") {
584 fe9d4894 Renato Botelho
			do_as_unbound_user("dump_cache");
585 751533a2 Phil Davis
		}
586 fe9d4894 Renato Botelho
		break;
587
	case "restore_cache":
588
		// Restore Unbound's Cache
589
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
590 751533a2 Phil Davis
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
591 fe9d4894 Renato Botelho
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
592 751533a2 Phil Davis
			}
593 fe9d4894 Renato Botelho
		}
594
		break;
595
	default:
596
		break;
597
598
	}
599 56a87b19 Warren Baker
}
600
601
// Generation of Unbound statistics
602
function unbound_statistics() {
603 fe9d4894 Renato Botelho
	global $config;
604
605
	if ($config['stats'] == "on") {
606
		$stats_interval = $config['unbound']['stats_interval'];
607
		$cumulative_stats = $config['cumulative_stats'];
608 751533a2 Phil Davis
		if ($config['extended_stats'] == "on") {
609 fe9d4894 Renato Botelho
			$extended_stats = "yes";
610 751533a2 Phil Davis
		} else {
611 fe9d4894 Renato Botelho
			$extended_stats = "no";
612 751533a2 Phil Davis
		}
613 fe9d4894 Renato Botelho
	} else {
614
		$stats_interval = "0";
615
		$cumulative_stats = "no";
616
		$extended_stats = "no";
617
	}
618
	/* XXX To do - add RRD graphs */
619
	$stats = <<<EOF
620 56a87b19 Warren Baker
# Unbound Statistics
621
statistics-interval: {$stats_interval}
622
extended-statistics: yes
623
statistics-cumulative: yes
624
625
EOF;
626
627 fe9d4894 Renato Botelho
	return $stats;
628 56a87b19 Warren Baker
}
629
630 8fccab67 Warren Baker
// Unbound Access lists
631
function unbound_acls_config() {
632 fe9d4894 Renato Botelho
	global $g, $config;
633
634 f8f5ba1a Chris Buechler
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
635
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
636
		$aclcfg .= "access-control: ::1 allow\n";
637
		// Add our networks for active interfaces including localhost
638 8c2a5a73 Phil Davis
		if (!empty($config['unbound']['active_interface'])) {
639 f8f5ba1a Chris Buechler
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
640 751533a2 Phil Davis
			if (in_array("all", $active_interfaces)) {
641 80075b9e Chris Buechler
				$active_interfaces = get_configured_interface_with_descr();
642 751533a2 Phil Davis
			}
643
		} else {
644 f8f5ba1a Chris Buechler
			$active_interfaces = get_configured_interface_with_descr();
645 751533a2 Phil Davis
		}
646
647 f8f5ba1a Chris Buechler
		$bindints = "";
648 751533a2 Phil Davis
		foreach ($active_interfaces as $ubif => $ifdesc) {
649 f8f5ba1a Chris Buechler
			$ifip = get_interface_ip($ubif);
650
			if (is_ipaddrv4($ifip)) {
651
				// IPv4 is handled via NAT networks below
652
			}
653
			$ifip = get_interface_ipv6($ubif);
654
			if (is_ipaddrv6($ifip)) {
655 f302a333 Jean Cyr
				if (!is_linklocal($ifip)) {
656
					$subnet_bits = get_interface_subnetv6($ubif);
657
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
658 751533a2 Phil Davis
					// only add LAN-type interfaces
659
					if (!interface_has_gateway($ubif)) {
660 f302a333 Jean Cyr
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
661 751533a2 Phil Davis
					}
662 f302a333 Jean Cyr
				}
663 f8f5ba1a Chris Buechler
				// add for IPv6 static routes to local networks
664
				// for safety, we include only routes reachable on an interface with no
665 751533a2 Phil Davis
				// gateway specified - read: not an Internet connection.
666 f8f5ba1a Chris Buechler
				$static_routes = get_staticroutes();
667
				foreach ($static_routes as $route) {
668
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
669
						// route is on this interface, interface doesn't have gateway, add it
670
						$aclcfg .= "access-control: {$route['network']} allow\n";
671
					}
672 e3045c51 Chris Buechler
				}
673
			}
674 fe9d4894 Renato Botelho
		}
675 751533a2 Phil Davis
676 f8f5ba1a Chris Buechler
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
677
		if (empty($FilterIflist)) {
678
			filter_generate_optcfg_array();
679
		}
680
		$natnetworks_array = array();
681
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
682
		foreach ($natnetworks_array as $allowednet) {
683 751533a2 Phil Davis
			$aclcfg .= "access-control: $allowednet allow \n";
684
		}
685 3bdf2a70 Chris Buechler
	}
686 fe9d4894 Renato Botelho
687
	// Configure the custom ACLs
688
	if (is_array($config['unbound']['acls'])) {
689 751533a2 Phil Davis
		foreach ($config['unbound']['acls'] as $unbound_acl) {
690 fe9d4894 Renato Botelho
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
691 751533a2 Phil Davis
			foreach ($unbound_acl['row'] as $network) {
692
				if ($unbound_acl['aclaction'] == "allow snoop") {
693 fe9d4894 Renato Botelho
					$unbound_acl['aclaction'] = "allow_snoop";
694 751533a2 Phil Davis
				}
695 fe9d4894 Renato Botelho
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
696
			}
697
		}
698
	}
699
	// Write out Access list
700 e318d592 Phil Davis
	create_unbound_chroot_path();
701 fe9d4894 Renato Botelho
	file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $aclcfg);
702 58d00e65 Warren Baker
703 8fccab67 Warren Baker
}
704
705 f6248774 Warren Baker
// Generate hosts and reload services
706
function unbound_hosts_generate() {
707 fe9d4894 Renato Botelho
	// Generate our hosts file
708
	unbound_add_host_entries();
709 f6248774 Warren Baker
710 fe9d4894 Renato Botelho
	// Reload our service to read the updates
711
	unbound_control("reload");
712 f6248774 Warren Baker
}
713
714 3f0c20c3 Renato Botelho
?>