Project

General

Profile

Download (26.4 KB) Statistics
| Branch: | Tag: | Revision:
1 f20afeb6 Warren Baker
<?php
2
/*
3 8acd654a Renato Botelho
 * unbound.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6 aaec5634 Renato Botelho
 * Copyright (c) 2015 Warren Baker <warren@percol8.co.za>
7 2a2396a6 Renato Botelho
 * Copyright (c) 2015-2016 Rubicon Communications, LLC (Netgate)
8 8acd654a Renato Botelho
 * All rights reserved.
9
 *
10
 * originally part of m0n0wall (http://m0n0.ch/wall)
11 aaec5634 Renato Botelho
 * Copyright (c) 2003-2004 Manuel Kasper <mk@neon1.net>.
12 8acd654a Renato Botelho
 * All rights reserved.
13
 *
14
 * Redistribution and use in source and binary forms, with or without
15
 * modification, are permitted provided that the following conditions are met:
16
 *
17
 * 1. Redistributions of source code must retain the above copyright notice,
18
 *    this list of conditions and the following disclaimer.
19
 *
20
 * 2. Redistributions in binary form must reproduce the above copyright
21
 *    notice, this list of conditions and the following disclaimer in
22
 *    the documentation and/or other materials provided with the
23
 *    distribution.
24
 *
25
 * 3. All advertising materials mentioning features or use of this software
26
 *    must display the following acknowledgment:
27
 *    "This product includes software developed by the pfSense Project
28
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
29
 *
30
 * 4. The names "pfSense" and "pfSense Project" must not be used to
31
 *    endorse or promote products derived from this software without
32
 *    prior written permission. For written permission, please contact
33
 *    coreteam@pfsense.org.
34
 *
35
 * 5. Products derived from this software may not be called "pfSense"
36
 *    nor may "pfSense" appear in their names without prior written
37
 *    permission of the Electric Sheep Fencing, LLC.
38
 *
39
 * 6. Redistributions of any form whatsoever must retain the following
40
 *    acknowledgment:
41
 *
42
 * "This product includes software developed by the pfSense Project
43
 * for use in the pfSense software distribution (http://www.pfsense.org/).
44
 *
45
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
46
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
49
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
54
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
56
 * OF THE POSSIBILITY OF SUCH DAMAGE.
57
 */
58 f20afeb6 Warren Baker
59
/* include all configuration functions */
60
require_once("config.inc");
61
require_once("functions.inc");
62 3bdf2a70 Chris Buechler
require_once("filter.inc");
63
require_once("shaper.inc");
64 f20afeb6 Warren Baker
65 1548bd35 Phil Davis
function create_unbound_chroot_path($cfgsubdir = "") {
66 e318d592 Phil Davis
	global $config, $g;
67
68
	// Configure chroot
69
	if (!is_dir($g['unbound_chroot_path'])) {
70
		mkdir($g['unbound_chroot_path']);
71
		chown($g['unbound_chroot_path'], "unbound");
72
		chgrp($g['unbound_chroot_path'], "unbound");
73
	}
74
75 1548bd35 Phil Davis
	if ($cfgsubdir != "") {
76
		$cfgdir = $g['unbound_chroot_path'] . $cfgsubdir;
77
		if (!is_dir($cfgdir)) {
78
			mkdir($cfgdir);
79
			chown($cfgdir, "unbound");
80
			chgrp($cfgdir, "unbound");
81
		}
82
	}
83 e318d592 Phil Davis
}
84
85 f20afeb6 Warren Baker
/* Optimize Unbound for environment */
86
function unbound_optimization() {
87 fe9d4894 Renato Botelho
	global $config;
88
89
	$optimization_settings = array();
90
91 751533a2 Phil Davis
	/*
92 fe9d4894 Renato Botelho
	 * Set the number of threads equal to number of CPUs.
93
	 * Use 1 to disable threading, if for some reason this sysctl fails.
94
	 */
95
	$numprocs = intval(get_single_sysctl('kern.smp.cpus'));
96 46762efe Warren Baker
	if ($numprocs > 1) {
97 fe9d4894 Renato Botelho
		$optimization['number_threads'] = "num-threads: {$numprocs}";
98 086cf944 Phil Davis
		$optimize_num = pow(2, floor(log($numprocs, 2)));
99 46762efe Warren Baker
	} else {
100 fe9d4894 Renato Botelho
		$optimization['number_threads'] = "num-threads: 1";
101 46762efe Warren Baker
		$optimize_num = 4;
102
	}
103 fe9d4894 Renato Botelho
104
	// Slabs to help reduce lock contention.
105 46762efe Warren Baker
	$optimization['msg_cache_slabs'] = "msg-cache-slabs: {$optimize_num}";
106
	$optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$optimize_num}";
107
	$optimization['infra_cache_slabs'] = "infra-cache-slabs: {$optimize_num}";
108
	$optimization['key_cache_slabs'] = "key-cache-slabs: {$optimize_num}";
109 fe9d4894 Renato Botelho
110
	/*
111
	 * Larger socket buffer for busy servers
112
	 * Check that it is set to 4MB (by default the OS has it configured to 4MB)
113
	 */
114 d87fcac9 Ermal
	if (is_array($config['sysctl']) && is_array($config['sysctl']['item'])) {
115
		foreach ($config['sysctl']['item'] as $tunable) {
116
			if ($tunable['tunable'] == 'kern.ipc.maxsockbuf') {
117 ad04bbbf Warren Baker
				$so = floor(($tunable['value']/1024/1024)-4);
118 d87fcac9 Ermal
				// Check to ensure that the number is not a negative
119 ad04bbbf Warren Baker
				if ($so >= 4) {
120
					// Limit to 32MB, users might set maxsockbuf very high for other reasons.
121 4708c6f0 Phil Davis
					// We do not want unbound to fail because of that.
122 ad04bbbf Warren Baker
					$so = min($so, 32);
123 d87fcac9 Ermal
					$optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
124 ad04bbbf Warren Baker
				} else {
125 d87fcac9 Ermal
					unset($optimization['so_rcvbuf']);
126 ad04bbbf Warren Baker
				}
127 d87fcac9 Ermal
			}
128 fe9d4894 Renato Botelho
		}
129
	}
130
	// Safety check in case kern.ipc.maxsockbuf is not available.
131 751533a2 Phil Davis
	if (!isset($optimization['so_rcvbuf'])) {
132 fe9d4894 Renato Botelho
		$optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
133 751533a2 Phil Davis
	}
134 fe9d4894 Renato Botelho
135
	return $optimization;
136 f20afeb6 Warren Baker
137
}
138
139 932711c7 Matt Smith
function test_unbound_config($unboundcfg, &$output) {
140
	global $g;
141
142 1548bd35 Phil Davis
	$cfgsubdir = "/test";
143
	unbound_generate_config($unboundcfg, $cfgsubdir);
144
	unbound_remote_control_setup($cfgsubdir);
145
	do_as_unbound_user("unbound-anchor", $cfgsubdir);
146
147
	$cfgdir = "{$g['unbound_chroot_path']}{$cfgsubdir}";
148 932711c7 Matt Smith
149
	$rv = 0;
150 1548bd35 Phil Davis
	exec("/usr/local/sbin/unbound-checkconf {$cfgdir}/unbound.conf 2>&1", $output, $rv);
151
	rmdir_recursive($cfgdir);
152 932711c7 Matt Smith
153
	return $rv;
154
}
155
156
157 1548bd35 Phil Davis
function unbound_generate_config($unboundcfg = NULL, $cfgsubdir = "") {
158 a569071d Phil Davis
	global $g;
159 932711c7 Matt Smith
160 1548bd35 Phil Davis
	$unboundcfgtxt = unbound_generate_config_text($unboundcfg, $cfgsubdir);
161 932711c7 Matt Smith
162
	// Configure static Host entries
163 1548bd35 Phil Davis
	unbound_add_host_entries($cfgsubdir);
164 932711c7 Matt Smith
165
	// Configure Domain Overrides
166 1548bd35 Phil Davis
	unbound_add_domain_overrides("", $cfgsubdir);
167 932711c7 Matt Smith
168
	// Configure Unbound access-lists
169 1548bd35 Phil Davis
	unbound_acls_config($cfgsubdir);
170 932711c7 Matt Smith
171 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
172
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/unbound.conf", $unboundcfgtxt);
173 932711c7 Matt Smith
}
174
175
176 1548bd35 Phil Davis
function unbound_generate_config_text($unboundcfg = NULL, $cfgsubdir = "") {
177 932711c7 Matt Smith
178 fe9d4894 Renato Botelho
	global $config, $g;
179 932711c7 Matt Smith
	if (is_null($unboundcfg)) {
180
		$unboundcfg = $config['unbound'];
181
	}
182 fe9d4894 Renato Botelho
183
	// Setup optimization
184
	$optimization = unbound_optimization();
185
186
	// Setup DNSSEC support
187 932711c7 Matt Smith
	if (isset($unboundcfg['dnssec'])) {
188 fe9d4894 Renato Botelho
		$module_config = "validator iterator";
189 1548bd35 Phil Davis
		$anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}{$cfgsubdir}/root.key";
190 751533a2 Phil Davis
	} else {
191 fe9d4894 Renato Botelho
		$module_config = "iterator";
192 751533a2 Phil Davis
	}
193 fe9d4894 Renato Botelho
194
	// Setup DNS Rebinding
195
	if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
196
		// Private-addresses for DNS Rebinding
197
		$private_addr = <<<EOF
198 f20afeb6 Warren Baker
# For DNS Rebinding prevention
199
private-address: 10.0.0.0/8
200
private-address: 172.16.0.0/12
201 c683f627 Chris Buechler
private-address: 169.254.0.0/16
202 f20afeb6 Warren Baker
private-address: 192.168.0.0/16
203
private-address: fd00::/8
204
private-address: fe80::/10
205
EOF;
206 fe9d4894 Renato Botelho
	}
207
208
	// Determine interfaces to run on
209
	$bindints = "";
210 932711c7 Matt Smith
	if (!empty($unboundcfg['active_interface'])) {
211
		$active_interfaces = explode(",", $unboundcfg['active_interface']);
212 b7960673 Chris Buechler
		if (in_array("all", $active_interfaces, true)) {
213
			$bindints .= "interface: 0.0.0.0\n";
214
			$bindints .= "interface: ::0\n";
215 f358fe3f Chris Buechler
			$bindints .= "interface-automatic: yes\n";
216 b7960673 Chris Buechler
		} else {
217 751533a2 Phil Davis
			foreach ($active_interfaces as $ubif) {
218 a0e9e17d Chris Buechler
				if (is_ipaddr($ubif)) {
219 6cffaccc Chris Buechler
					$bindints .= "interface: $ubif\n";
220 a0e9e17d Chris Buechler
				} else {
221
					$intip = get_interface_ip($ubif);
222 751533a2 Phil Davis
					if (is_ipaddrv4($intip)) {
223 a0e9e17d Chris Buechler
						$bindints .= "interface: $intip\n";
224 751533a2 Phil Davis
					}
225 a0e9e17d Chris Buechler
					$intip = get_interface_ipv6($ubif);
226 751533a2 Phil Davis
					if (is_ipaddrv6($intip)) {
227 7cc0a76b Luiz Otavio O Souza
						$bindints .= "interface: $intip\n";
228 751533a2 Phil Davis
					}
229 a0e9e17d Chris Buechler
				}
230 751533a2 Phil Davis
			}
231 fe9d4894 Renato Botelho
		}
232
	} else {
233
		$bindints .= "interface: 0.0.0.0\n";
234
		$bindints .= "interface: ::0\n";
235 a2cbbb74 jim-p
		/* If the active interface array is empty, treat it the same as "All" as is done above. Otherwise it breaks CARP with a default config. */
236
		$bindints .= "interface-automatic: yes\n";
237 fe9d4894 Renato Botelho
	}
238
239
	// Determine interfaces to run on
240
	$outgoingints = "";
241 932711c7 Matt Smith
	if (!empty($unboundcfg['outgoing_interface'])) {
242 fe9d4894 Renato Botelho
		$outgoingints = "# Outgoing interfaces to be used\n";
243 932711c7 Matt Smith
		$outgoing_interfaces = explode(",", $unboundcfg['outgoing_interface']);
244 751533a2 Phil Davis
		foreach ($outgoing_interfaces as $outif) {
245 fe9d4894 Renato Botelho
			$outip = get_interface_ip($outif);
246 c37ffea8 Chris Buechler
			if (is_ipaddr($outip)) {
247 fe9d4894 Renato Botelho
				$outgoingints .= "outgoing-interface: $outip\n";
248 751533a2 Phil Davis
			}
249 fe9d4894 Renato Botelho
			$outip = get_interface_ipv6($outif);
250 c37ffea8 Chris Buechler
			if (is_ipaddrv6($outip)) {
251 fe9d4894 Renato Botelho
				$outgoingints .= "outgoing-interface: $outip\n";
252 751533a2 Phil Davis
			}
253 fe9d4894 Renato Botelho
		}
254
	}
255
256
	// Allow DNS Rebind for forwarded domains
257 932711c7 Matt Smith
	if (isset($unboundcfg['domainoverrides']) && is_array($unboundcfg['domainoverrides'])) {
258 984abd66 Phil Davis
		if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
259
			$private_domains = "# Set private domains in case authoritative name server returns a Private IP address\n";
260
			$private_domains .= unbound_add_domain_overrides("private");
261
		}
262
		$reverse_zones .= unbound_add_domain_overrides("reverse");
263 fe9d4894 Renato Botelho
	}
264
265 ab8f10f2 Phil Davis
	// Configure Unbound statistics
266
	$statistics = unbound_statistics();
267
268 fe9d4894 Renato Botelho
	// Add custom Unbound options
269 932711c7 Matt Smith
	if ($unboundcfg['custom_options']) {
270
		$custom_options_source = explode("\n", base64_decode($unboundcfg['custom_options']));
271 b9608ab6 Phil Davis
		$custom_options = "# Unbound custom options\n";
272 751533a2 Phil Davis
		foreach ($custom_options_source as $ent) {
273 b9608ab6 Phil Davis
			$custom_options .= $ent."\n";
274 751533a2 Phil Davis
		}
275 fe9d4894 Renato Botelho
	}
276
277
	// Server configuration variables
278 932711c7 Matt Smith
	$port = (is_port($unboundcfg['port'])) ? $unboundcfg['port'] : "53";
279
	$hide_identity = isset($unboundcfg['hideidentity']) ? "yes" : "no";
280
	$hide_version = isset($unboundcfg['hideversion']) ? "yes" : "no";
281
	$harden_dnssec_stripped = isset($unboundcfg['dnssecstripped']) ? "yes" : "no";
282
	$prefetch = isset($unboundcfg['prefetch']) ? "yes" : "no";
283
	$prefetch_key = isset($unboundcfg['prefetchkey']) ? "yes" : "no";
284 f8a475f5 lukehamburg
	$outgoing_num_tcp = isset($unboundcfg['outgoing_num_tcp']) ? $unboundcfg['outgoing_num_tcp'] : "10";
285
	$incoming_num_tcp = isset($unboundcfg['incoming_num_tcp']) ? $unboundcfg['incoming_num_tcp'] : "10";
286 932711c7 Matt Smith
	$edns_buffer_size = (!empty($unboundcfg['edns_buffer_size'])) ? $unboundcfg['edns_buffer_size'] : "4096";
287
	$num_queries_per_thread = (!empty($unboundcfg['num_queries_per_thread'])) ? $unboundcfg['num_queries_per_thread'] : "4096";
288
	$jostle_timeout = (!empty($unboundcfg['jostle_timeout'])) ? $unboundcfg['jostle_timeout'] : "200";
289
	$cache_max_ttl = (!empty($unboundcfg['cache_max_ttl'])) ? $unboundcfg['cache_max_ttl'] : "86400";
290
	$cache_min_ttl = (!empty($unboundcfg['cache_min_ttl'])) ? $unboundcfg['cache_min_ttl'] : "0";
291
	$infra_host_ttl = (!empty($unboundcfg['infra_host_ttl'])) ? $unboundcfg['infra_host_ttl'] : "900";
292
	$infra_cache_numhosts = (!empty($unboundcfg['infra_cache_numhosts'])) ? $unboundcfg['infra_cache_numhosts'] : "10000";
293
	$unwanted_reply_threshold = (!empty($unboundcfg['unwanted_reply_threshold'])) ? $unboundcfg['unwanted_reply_threshold'] : "0";
294 751533a2 Phil Davis
	if ($unwanted_reply_threshold == "disabled") {
295 b9608ab6 Phil Davis
		$unwanted_reply_threshold = "0";
296 751533a2 Phil Davis
	}
297 932711c7 Matt Smith
	$msg_cache_size = (!empty($unboundcfg['msgcachesize'])) ? $unboundcfg['msgcachesize'] : "4";
298
	$verbosity = isset($unboundcfg['log_verbosity']) ? $unboundcfg['log_verbosity'] : 1;
299
	$use_caps = isset($unboundcfg['use_caps']) ? "yes" : "no";
300 fe9d4894 Renato Botelho
301 a110a0cb Phil Davis
	// Set up forwarding if it is configured
302 932711c7 Matt Smith
	if (isset($unboundcfg['forwarding'])) {
303 fe9d4894 Renato Botelho
		$dnsservers = array();
304
		if (isset($config['system']['dnsallowoverride'])) {
305
			$ns = array_unique(get_nameservers());
306 751533a2 Phil Davis
			foreach ($ns as $nameserver) {
307
				if ($nameserver) {
308 fe9d4894 Renato Botelho
					$dnsservers[] = $nameserver;
309 751533a2 Phil Davis
				}
310 fe9d4894 Renato Botelho
			}
311 9b837c5d Phil Davis
		} else {
312
			$ns = array();
313 a110a0cb Phil Davis
		}
314
		$sys_dnsservers = array_unique(get_dns_servers());
315
		foreach ($sys_dnsservers as $sys_dnsserver) {
316
			if ($sys_dnsserver && (!in_array($sys_dnsserver, $ns))) {
317
				$dnsservers[] = $sys_dnsserver;
318 fe9d4894 Renato Botelho
			}
319
		}
320
321
		if (!empty($dnsservers)) {
322
			$forward_conf .=<<<EOD
323 75e6d1b2 Warren Baker
# Forwarding
324 be5aa310 Warren Baker
forward-zone:
325 fe9d4894 Renato Botelho
	name: "."
326 be5aa310 Warren Baker
327
EOD;
328 751533a2 Phil Davis
			foreach ($dnsservers as $dnsserver) {
329 84588e00 Chris Buechler
				if (is_ipaddr($dnsserver) && !ip_in_subnet($dnsserver, "127.0.0.0/8")) {
330
					$forward_conf .= "\tforward-addr: $dnsserver\n";
331
				}
332 751533a2 Phil Davis
			}
333 fe9d4894 Renato Botelho
		}
334 751533a2 Phil Davis
	} else {
335 fe9d4894 Renato Botelho
		$forward_conf = "";
336 751533a2 Phil Davis
	}
337 be5aa310 Warren Baker
338 2597415b Chris Buechler
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
339
	$rrset_cache_size = $msg_cache_size * 2;
340
341 fe9d4894 Renato Botelho
	$unboundconf = <<<EOD
342 f20afeb6 Warren Baker
##########################
343
# Unbound Configuration
344
##########################
345
346
##
347
# Server configuration
348
##
349
server:
350 984abd66 Phil Davis
{$reverse_zones}
351 f20afeb6 Warren Baker
chroot: {$g['unbound_chroot_path']}
352
username: "unbound"
353 56a87b19 Warren Baker
directory: "{$g['unbound_chroot_path']}"
354 f20afeb6 Warren Baker
pidfile: "/var/run/unbound.pid"
355
use-syslog: yes
356 d12889b0 Warren Baker
port: {$port}
357 56a87b19 Warren Baker
verbosity: {$verbosity}
358 b9608ab6 Phil Davis
hide-identity: {$hide_identity}
359
hide-version: {$hide_version}
360 5c7c369f Chris Buechler
harden-glue: yes
361 f20afeb6 Warren Baker
do-ip4: yes
362
do-ip6: yes
363
do-udp: yes
364
do-tcp: yes
365
do-daemonize: yes
366
module-config: "{$module_config}"
367 b9608ab6 Phil Davis
unwanted-reply-threshold: {$unwanted_reply_threshold}
368
num-queries-per-thread: {$num_queries_per_thread}
369
jostle-timeout: {$jostle_timeout}
370
infra-host-ttl: {$infra_host_ttl}
371
infra-cache-numhosts: {$infra_cache_numhosts}
372
outgoing-num-tcp: {$outgoing_num_tcp}
373
incoming-num-tcp: {$incoming_num_tcp}
374
edns-buffer-size: {$edns_buffer_size}
375 56a87b19 Warren Baker
cache-max-ttl: {$cache_max_ttl}
376
cache-min-ttl: {$cache_min_ttl}
377 b9608ab6 Phil Davis
harden-dnssec-stripped: {$harden_dnssec_stripped}
378
msg-cache-size: {$msg_cache_size}m
379 2597415b Chris Buechler
rrset-cache-size: {$rrset_cache_size}m
380
381 f20afeb6 Warren Baker
{$optimization['number_threads']}
382
{$optimization['msg_cache_slabs']}
383
{$optimization['rrset_cache_slabs']}
384
{$optimization['infra_cache_slabs']}
385
{$optimization['key_cache_slabs']}
386 2cbcc256 Warren Baker
outgoing-range: 4096
387 f20afeb6 Warren Baker
{$optimization['so_rcvbuf']}
388
{$anchor_file}
389 56a87b19 Warren Baker
prefetch: {$prefetch}
390
prefetch-key: {$prefetch_key}
391 a771a6ae Warren Baker
use-caps-for-id: {$use_caps}
392 f20afeb6 Warren Baker
# Statistics
393
{$statistics}
394
# Interface IP(s) to bind to
395 16a3108f Warren Baker
{$bindints}
396 6374fb57 Warren Baker
{$outgoingints}
397 f20afeb6 Warren Baker
398
# DNS Rebinding
399
{$private_addr}
400
{$private_domains}
401
402 4e8e8cc8 Warren Baker
# Access lists
403 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/access_lists.conf
404 4e8e8cc8 Warren Baker
405 f20afeb6 Warren Baker
# Static host entries
406 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/host_entries.conf
407 f20afeb6 Warren Baker
408 b3977493 Renato Botelho
# dhcp lease entries
409 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/dhcpleases_entries.conf
410 b3977493 Renato Botelho
411 f20afeb6 Warren Baker
# Domain overrides
412 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/domainoverrides.conf
413 be5aa310 Warren Baker
{$forward_conf}
414
415 f20afeb6 Warren Baker
{$custom_options}
416
417
###
418
# Remote Control Config
419
###
420 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf
421 f20afeb6 Warren Baker
422
EOD;
423
424 932711c7 Matt Smith
	return $unboundconf;
425 f20afeb6 Warren Baker
}
426
427 1548bd35 Phil Davis
function unbound_remote_control_setup($cfgsubdir = "") {
428 fe9d4894 Renato Botelho
	global $g;
429 f20afeb6 Warren Baker
430 1548bd35 Phil Davis
	if (!file_exists("{$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.key")) {
431 fe9d4894 Renato Botelho
		$remotcfg = <<<EOF
432 f20afeb6 Warren Baker
remote-control:
433 fe9d4894 Renato Botelho
	control-enable: yes
434
	control-interface: 127.0.0.1
435
	control-port: 953
436 1548bd35 Phil Davis
	server-key-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_server.key"
437
	server-cert-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_server.pem"
438
	control-key-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.key"
439
	control-cert-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.pem"
440 56a87b19 Warren Baker
441 f20afeb6 Warren Baker
EOF;
442
443 1548bd35 Phil Davis
		create_unbound_chroot_path($cfgsubdir);
444
		file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf", $remotcfg);
445 f20afeb6 Warren Baker
446 fe9d4894 Renato Botelho
		// Generate our keys
447 1548bd35 Phil Davis
		do_as_unbound_user("unbound-control-setup", $cfgsubdir);
448 f20afeb6 Warren Baker
449 fe9d4894 Renato Botelho
	}
450 56a87b19 Warren Baker
}
451 f20afeb6 Warren Baker
452
function sync_unbound_service() {
453 fe9d4894 Renato Botelho
	global $config, $g;
454
455 e318d592 Phil Davis
	create_unbound_chroot_path();
456 fe9d4894 Renato Botelho
457
	// Configure our Unbound service
458
	do_as_unbound_user("unbound-anchor");
459
	unbound_remote_control_setup();
460
	unbound_generate_config();
461
	do_as_unbound_user("start");
462
	require_once("service-utils.inc");
463 751533a2 Phil Davis
	if (is_service_running("unbound")) {
464 fe9d4894 Renato Botelho
		do_as_unbound_user("restore_cache");
465 751533a2 Phil Davis
	}
466 f20afeb6 Warren Baker
467
}
468
469
function unbound_acl_id_used($id) {
470 fe9d4894 Renato Botelho
	global $config;
471 f20afeb6 Warren Baker
472 751533a2 Phil Davis
	if (is_array($config['unbound']['acls'])) {
473
		foreach ($config['unbound']['acls'] as & $acls) {
474
			if ($id == $acls['aclid']) {
475 fe9d4894 Renato Botelho
				return true;
476 751533a2 Phil Davis
			}
477
		}
478
	}
479 f20afeb6 Warren Baker
480 fe9d4894 Renato Botelho
	return false;
481 f20afeb6 Warren Baker
}
482
483
function unbound_get_next_id() {
484 fe9d4894 Renato Botelho
	$aclid = 0;
485 751533a2 Phil Davis
	while (unbound_acl_id_used($aclid)) {
486 fe9d4894 Renato Botelho
		$aclid++;
487 751533a2 Phil Davis
	}
488 fe9d4894 Renato Botelho
	return $aclid;
489 f20afeb6 Warren Baker
}
490
491
// Execute commands as the user unbound
492 1548bd35 Phil Davis
function do_as_unbound_user($cmd, $param1 = "") {
493 fe9d4894 Renato Botelho
	global $g;
494
495
	switch ($cmd) {
496 751533a2 Phil Davis
		case "start":
497
			mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
498
			break;
499
		case "stop":
500 cad82db7 jim-p
			mwexec("echo '/usr/local/sbin/unbound-control -c {$g['unbound_chroot_path']}/unbound.conf stop' | /usr/bin/su -m unbound", true);
501 751533a2 Phil Davis
			break;
502
		case "reload":
503 cad82db7 jim-p
			mwexec("echo '/usr/local/sbin/unbound-control -c {$g['unbound_chroot_path']}/unbound.conf reload' | /usr/bin/su -m unbound", true);
504 751533a2 Phil Davis
			break;
505
		case "unbound-anchor":
506 1548bd35 Phil Davis
			$root_key_file = "{$g['unbound_chroot_path']}{$param1}/root.key";
507 4eeb2809 Chris Buechler
			// sanity check root.key because unbound-anchor will fail without manual removal otherwise. redmine #5334
508 1548bd35 Phil Davis
			if (file_exists($root_key_file)) {
509
				$rootkeycheck = mwexec("/usr/bin/grep 'autotrust trust anchor file' {$root_key_file}", true);
510 4eeb2809 Chris Buechler
				if ($rootkeycheck != "0") {
511 1548bd35 Phil Davis
					log_error("Unbound {$root_key_file} file is corrupt, removing and recreating.");
512
					unlink_if_exists($root_key_file);
513 4eeb2809 Chris Buechler
				}
514
			}
515 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-anchor -a {$root_key_file}' | /usr/bin/su -m unbound", true);
516
			// Only sync the file if this is the real (default) one, not a test one.
517
			if ($param1 == "") {
518
				pfSense_fsync($root_key_file);
519
			}
520 751533a2 Phil Davis
			break;
521
		case "unbound-control-setup":
522 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}{$param1}' | /usr/bin/su -m unbound", true);
523 751533a2 Phil Davis
			break;
524
		default:
525
			break;
526 fe9d4894 Renato Botelho
	}
527 f20afeb6 Warren Baker
}
528
529 1548bd35 Phil Davis
function unbound_add_domain_overrides($pvt_rev="", $cfgsubdir = "") {
530 fe9d4894 Renato Botelho
	global $config, $g;
531
532
	$domains = $config['unbound']['domainoverrides'];
533
534
	$sorted_domains = msort($domains, "domain");
535
	$result = array();
536 751533a2 Phil Davis
	foreach ($sorted_domains as $domain) {
537 fe9d4894 Renato Botelho
		$domain_key = current($domain);
538 751533a2 Phil Davis
		if (!isset($result[$domain_key])) {
539 fe9d4894 Renato Botelho
			$result[$domain_key] = array();
540 751533a2 Phil Davis
		}
541 fe9d4894 Renato Botelho
		$result[$domain_key][] = $domain['ip'];
542
	}
543
544
	// Domain overrides that have multiple entries need multiple stub-addr: added
545
	$domain_entries = "";
546 751533a2 Phil Davis
	foreach ($result as $domain=>$ips) {
547 984abd66 Phil Davis
		if ($pvt_rev == "private") {
548 fe9d4894 Renato Botelho
			$domain_entries .= "private-domain: \"$domain\"\n";
549
			$domain_entries .= "domain-insecure: \"$domain\"\n";
550 984abd66 Phil Davis
		} else if ($pvt_rev == "reverse") {
551 086cf944 Phil Davis
			if ((substr($domain, -14) == ".in-addr.arpa.") || (substr($domain, -13) == ".in-addr.arpa")) {
552 984abd66 Phil Davis
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
553
			}
554 fe9d4894 Renato Botelho
		} else {
555 6ecf66a9 Chris Buechler
			$domain_entries .= "forward-zone:\n";
556 fe9d4894 Renato Botelho
			$domain_entries .= "\tname: \"$domain\"\n";
557 751533a2 Phil Davis
			foreach ($ips as $ip) {
558 6ecf66a9 Chris Buechler
				$domain_entries .= "\tforward-addr: $ip\n";
559 751533a2 Phil Davis
			}
560 fe9d4894 Renato Botelho
		}
561
	}
562
563 751533a2 Phil Davis
	if ($pvt_rev != "") {
564 fe9d4894 Renato Botelho
		return $domain_entries;
565 751533a2 Phil Davis
	} else {
566 1548bd35 Phil Davis
		create_unbound_chroot_path($cfgsubdir);
567
		file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/domainoverrides.conf", $domain_entries);
568 e318d592 Phil Davis
	}
569 f20afeb6 Warren Baker
}
570
571 47914246 jim-p
function unbound_generate_zone_data($domain, $hosts, &$added_ptr, $zone_type = "transparent", $write_domain_zone_declaration = false, $always_add_short_names = false) {
572 324bbc3f jim-p
	global $config;
573 47914246 jim-p
	if ($write_domain_zone_declaration) {
574 324bbc3f jim-p
		$zone_data = "local-zone: \"{$domain}.\" {$zone_type}\n";
575 9a83872f NOYB
	} else {
576 324bbc3f jim-p
		$zone_data = "";
577 ca47c065 NOYB
	}
578 b3977493 Renato Botelho
	foreach ($hosts as $host) {
579 751533a2 Phil Davis
		if (is_ipaddrv4($host['ipaddr'])) {
580 b3977493 Renato Botelho
			$type = 'A';
581 751533a2 Phil Davis
		} else if (is_ipaddrv6($host['ipaddr'])) {
582 b3977493 Renato Botelho
			$type = 'AAAA';
583 751533a2 Phil Davis
		} else {
584 b3977493 Renato Botelho
			continue;
585 751533a2 Phil Davis
		}
586
		if (!$added_ptr[$host['ipaddr']]) {
587 324bbc3f jim-p
			$zone_data .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
588 f29610b0 Lorenz Schori
			$added_ptr[$host['ipaddr']] = true;
589 06266c34 Lorenz Schori
		}
590 324bbc3f jim-p
		/* For the system localhost entry, write an entry for just the hostname. */
591
		if ((($host['name'] == "localhost") && ($domain == $config['system']['domain'])) || $always_add_short_names) {
592
			$zone_data .= "local-data: \"{$host['name']}. {$type} {$host['ipaddr']}\"\n";
593 350a7001 Chris Buechler
		}
594 324bbc3f jim-p
		/* Redirect zones must have a zone declaration that matches the
595
		 * local-data record exactly, it cannot have entries "under" the
596
		 * domain.
597
		 */
598
		if ($zone_type == "redirect") {
599
			$zone_data .= "local-zone: \"{$host['fqdn']}.\" {$zone_type}\n";;
600
		}
601
		$zone_data .= "local-data: \"{$host['fqdn']}. {$type} {$host['ipaddr']}\"\n";
602
	}
603
	return $zone_data;
604
}
605
606
function unbound_add_host_entries($cfgsubdir = "") {
607
	global $config, $g;
608
609
	$hosts = system_hosts_entries($config['unbound']);
610
611
	/* Pass 1: Build domain list and hosts inside domains */
612
	$hosts_by_domain = array();
613
	foreach ($hosts as $host) {
614
		if (!array_key_exists($host['domain'], $hosts_by_domain)) {
615
			$hosts_by_domain[$host['domain']] = array();
616
		}
617
		$hosts_by_domain[$host['domain']][] = $host;
618
	}
619
620
	$added_ptr = array();
621
	/* Build local zone data */
622
	// Check if auto add host entries is not set
623
	$system_domain_local_zone_type = "transparent";
624
	if (!isset($config['unbound']['disable_auto_added_host_entries'])) {
625
		// Make sure the config setting is a valid unbound local zone type.  If not use "transparent".
626
		if (array_key_exists($config['unbound']['system_domain_local_zone_type'], unbound_local_zone_types())) {
627
			$system_domain_local_zone_type = $config['unbound']['system_domain_local_zone_type'];
628
		}
629
	}
630
	/* Add entries for the system domain before all others */
631
	if (array_key_exists($config['system']['domain'], $hosts_by_domain)) {
632
		$unbound_entries .= unbound_generate_zone_data($config['system']['domain'],
633
					$hosts_by_domain[$config['system']['domain']],
634
					$added_ptr,
635
					$system_domain_local_zone_type,
636
					true);
637
		/* Unset this so it isn't processed again by the loop below. */
638
		unset($hosts_by_domain[$config['system']['domain']]);
639
	}
640
641
	/* Build zone data for other domain */
642
	foreach ($hosts_by_domain as $domain => $hosts) {
643
		$unbound_entries .= unbound_generate_zone_data($domain,
644
					$hosts,
645
					$added_ptr,
646
					"transparent",
647
					false,
648
					isset($config['unbound']['always_add_short_names']));
649 fe9d4894 Renato Botelho
	}
650
651
	// Write out entries
652 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
653
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/host_entries.conf", $unbound_entries);
654 b3977493 Renato Botelho
655
	/* dhcpleases will write to this config file, make sure it exists */
656 1548bd35 Phil Davis
	@touch("{$g['unbound_chroot_path']}{$cfgsubdir}/dhcpleases_entries.conf");
657 f20afeb6 Warren Baker
}
658
659 56a87b19 Warren Baker
function unbound_control($action) {
660 fe9d4894 Renato Botelho
	global $config, $g;
661
662
	$cache_dumpfile = "/var/tmp/unbound_cache";
663
664
	switch ($action) {
665
	case "start":
666
		// Start Unbound
667
		if ($config['unbound']['enable'] == "on") {
668 751533a2 Phil Davis
			if (!is_service_running("unbound")) {
669 fe9d4894 Renato Botelho
				do_as_unbound_user("start");
670 751533a2 Phil Davis
			}
671 fe9d4894 Renato Botelho
		}
672
		break;
673
	case "stop":
674 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
675 fe9d4894 Renato Botelho
			do_as_unbound_user("stop");
676 751533a2 Phil Davis
		}
677 fe9d4894 Renato Botelho
		break;
678
	case "reload":
679 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
680 fe9d4894 Renato Botelho
			do_as_unbound_user("reload");
681 751533a2 Phil Davis
		}
682 fe9d4894 Renato Botelho
		break;
683
	case "dump_cache":
684
		// Dump Unbound's Cache
685 751533a2 Phil Davis
		if ($config['unbound']['dumpcache'] == "on") {
686 fe9d4894 Renato Botelho
			do_as_unbound_user("dump_cache");
687 751533a2 Phil Davis
		}
688 fe9d4894 Renato Botelho
		break;
689
	case "restore_cache":
690
		// Restore Unbound's Cache
691
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
692 751533a2 Phil Davis
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
693 fe9d4894 Renato Botelho
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
694 751533a2 Phil Davis
			}
695 fe9d4894 Renato Botelho
		}
696
		break;
697
	default:
698
		break;
699
700
	}
701 56a87b19 Warren Baker
}
702
703
// Generation of Unbound statistics
704
function unbound_statistics() {
705 fe9d4894 Renato Botelho
	global $config;
706
707
	if ($config['stats'] == "on") {
708
		$stats_interval = $config['unbound']['stats_interval'];
709
		$cumulative_stats = $config['cumulative_stats'];
710 751533a2 Phil Davis
		if ($config['extended_stats'] == "on") {
711 fe9d4894 Renato Botelho
			$extended_stats = "yes";
712 751533a2 Phil Davis
		} else {
713 fe9d4894 Renato Botelho
			$extended_stats = "no";
714 751533a2 Phil Davis
		}
715 fe9d4894 Renato Botelho
	} else {
716
		$stats_interval = "0";
717
		$cumulative_stats = "no";
718
		$extended_stats = "no";
719
	}
720
	/* XXX To do - add RRD graphs */
721
	$stats = <<<EOF
722 56a87b19 Warren Baker
# Unbound Statistics
723
statistics-interval: {$stats_interval}
724
extended-statistics: yes
725
statistics-cumulative: yes
726
727
EOF;
728
729 fe9d4894 Renato Botelho
	return $stats;
730 56a87b19 Warren Baker
}
731
732 8fccab67 Warren Baker
// Unbound Access lists
733 1548bd35 Phil Davis
function unbound_acls_config($cfgsubdir = "") {
734 fe9d4894 Renato Botelho
	global $g, $config;
735
736 f8f5ba1a Chris Buechler
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
737
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
738
		$aclcfg .= "access-control: ::1 allow\n";
739
		// Add our networks for active interfaces including localhost
740 8c2a5a73 Phil Davis
		if (!empty($config['unbound']['active_interface'])) {
741 f8f5ba1a Chris Buechler
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
742 751533a2 Phil Davis
			if (in_array("all", $active_interfaces)) {
743 80075b9e Chris Buechler
				$active_interfaces = get_configured_interface_with_descr();
744 751533a2 Phil Davis
			}
745
		} else {
746 f8f5ba1a Chris Buechler
			$active_interfaces = get_configured_interface_with_descr();
747 751533a2 Phil Davis
		}
748
749 f8f5ba1a Chris Buechler
		$bindints = "";
750 751533a2 Phil Davis
		foreach ($active_interfaces as $ubif => $ifdesc) {
751 f8f5ba1a Chris Buechler
			$ifip = get_interface_ip($ubif);
752
			if (is_ipaddrv4($ifip)) {
753
				// IPv4 is handled via NAT networks below
754
			}
755
			$ifip = get_interface_ipv6($ubif);
756
			if (is_ipaddrv6($ifip)) {
757 f302a333 Jean Cyr
				if (!is_linklocal($ifip)) {
758
					$subnet_bits = get_interface_subnetv6($ubif);
759
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
760 751533a2 Phil Davis
					// only add LAN-type interfaces
761
					if (!interface_has_gateway($ubif)) {
762 f302a333 Jean Cyr
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
763 751533a2 Phil Davis
					}
764 f302a333 Jean Cyr
				}
765 f8f5ba1a Chris Buechler
				// add for IPv6 static routes to local networks
766
				// for safety, we include only routes reachable on an interface with no
767 751533a2 Phil Davis
				// gateway specified - read: not an Internet connection.
768 25e5d826 Phil Davis
				$static_routes = get_staticroutes(false, false, true); // Parameter 3 returnenabledroutesonly
769 f8f5ba1a Chris Buechler
				foreach ($static_routes as $route) {
770
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
771
						// route is on this interface, interface doesn't have gateway, add it
772
						$aclcfg .= "access-control: {$route['network']} allow\n";
773
					}
774 e3045c51 Chris Buechler
				}
775
			}
776 fe9d4894 Renato Botelho
		}
777 751533a2 Phil Davis
778 f8f5ba1a Chris Buechler
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
779
		if (empty($FilterIflist)) {
780
			filter_generate_optcfg_array();
781
		}
782
		$natnetworks_array = array();
783
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
784
		foreach ($natnetworks_array as $allowednet) {
785 751533a2 Phil Davis
			$aclcfg .= "access-control: $allowednet allow \n";
786
		}
787 3bdf2a70 Chris Buechler
	}
788 fe9d4894 Renato Botelho
789
	// Configure the custom ACLs
790
	if (is_array($config['unbound']['acls'])) {
791 751533a2 Phil Davis
		foreach ($config['unbound']['acls'] as $unbound_acl) {
792 fe9d4894 Renato Botelho
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
793 751533a2 Phil Davis
			foreach ($unbound_acl['row'] as $network) {
794
				if ($unbound_acl['aclaction'] == "allow snoop") {
795 fe9d4894 Renato Botelho
					$unbound_acl['aclaction'] = "allow_snoop";
796 77b7b90b doktornotor
				} elseif ($unbound_acl['aclaction'] == "deny nonlocal") {
797
					$unbound_acl['aclaction'] = "deny_non_local";
798
				} elseif ($unbound_acl['aclaction'] == "refuse nonlocal") {
799
					$unbound_acl['aclaction'] = "refuse_non_local";
800 751533a2 Phil Davis
				}
801 fe9d4894 Renato Botelho
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
802
			}
803
		}
804
	}
805
	// Write out Access list
806 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
807
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/access_lists.conf", $aclcfg);
808 58d00e65 Warren Baker
809 8fccab67 Warren Baker
}
810
811 f6248774 Warren Baker
// Generate hosts and reload services
812
function unbound_hosts_generate() {
813 fe9d4894 Renato Botelho
	// Generate our hosts file
814
	unbound_add_host_entries();
815 f6248774 Warren Baker
816 fe9d4894 Renato Botelho
	// Reload our service to read the updates
817
	unbound_control("reload");
818 f6248774 Warren Baker
}
819
820 9a83872f NOYB
// Array of valid unbound local zone types
821
function unbound_local_zone_types() {
822
	return array(
823
		"deny" => gettext("Deny"),
824
		"refuse" => gettext("Refuse"),
825
		"static" => gettext("Static"),
826
		"transparent" => gettext("Transparent"),
827
		"typetransparent" => gettext("Type Transparent"),
828
		"redirect" => gettext("Redirect"),
829
		"inform" => gettext("Inform"),
830
		"inform_deny" => gettext("Inform Deny"),
831
		"nodefault" => gettext("No Default")
832
	);
833
}
834
835 3f0c20c3 Renato Botelho
?>