Project

General

Profile

Download (25 KB) Statistics
| Branch: | Tag: | Revision:
1 f20afeb6 Warren Baker
<?php
2
/*
3 fe9d4894 Renato Botelho
	unbound.inc
4 09221bc3 Renato Botelho
5
	part of pfSense (https://www.pfsense.org)
6 a771a6ae Warren Baker
	Copyright (C) 2015 Warren Baker <warren@percol8.co.za>
7 09221bc3 Renato Botelho
	Copyright (c) 2015-2016 Electric Sheep Fencing, LLC.
8
	All rights reserved.
9
10
	originally part of m0n0wall (http://m0n0.ch/wall)
11
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
12 fe9d4894 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 09221bc3 Renato Botelho
	   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 f20afeb6 Warren Baker
*/
58
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 56a87b19 Warren Baker
// Read /etc/hosts
453 f20afeb6 Warren Baker
function read_hosts() {
454
455 fe9d4894 Renato Botelho
	/* Open /etc/hosts and extract the only dhcpleases info
456
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
457
	 */
458
	$etc_hosts = array();
459
	foreach (file('/etc/hosts') as $line) {
460 751533a2 Phil Davis
		if (strpos($line, "dhcpleases automatically entered")) {
461 b3977493 Renato Botelho
			break;
462 751533a2 Phil Davis
		}
463 b3977493 Renato Botelho
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
464 751533a2 Phil Davis
		if (empty($d) || substr(reset($d), 0, 1) == "#") {
465 fe9d4894 Renato Botelho
			continue;
466 751533a2 Phil Davis
		}
467 b3977493 Renato Botelho
		$ip = array_shift($d);
468
		$fqdn = array_shift($d);
469
		$name = array_shift($d);
470
		if (!empty($fqdn) && $fqdn != "empty") {
471 751533a2 Phil Davis
			if (!empty($name) && $name != "empty") {
472 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
473 751533a2 Phil Davis
			} else {
474 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
475 751533a2 Phil Davis
			}
476 fe9d4894 Renato Botelho
		}
477
	}
478
	return $etc_hosts;
479 f20afeb6 Warren Baker
}
480
481
function sync_unbound_service() {
482 fe9d4894 Renato Botelho
	global $config, $g;
483
484 e318d592 Phil Davis
	create_unbound_chroot_path();
485 fe9d4894 Renato Botelho
486
	// Configure our Unbound service
487
	do_as_unbound_user("unbound-anchor");
488
	unbound_remote_control_setup();
489
	unbound_generate_config();
490
	do_as_unbound_user("start");
491
	require_once("service-utils.inc");
492 751533a2 Phil Davis
	if (is_service_running("unbound")) {
493 fe9d4894 Renato Botelho
		do_as_unbound_user("restore_cache");
494 751533a2 Phil Davis
	}
495 f20afeb6 Warren Baker
496
}
497
498
function unbound_acl_id_used($id) {
499 fe9d4894 Renato Botelho
	global $config;
500 f20afeb6 Warren Baker
501 751533a2 Phil Davis
	if (is_array($config['unbound']['acls'])) {
502
		foreach ($config['unbound']['acls'] as & $acls) {
503
			if ($id == $acls['aclid']) {
504 fe9d4894 Renato Botelho
				return true;
505 751533a2 Phil Davis
			}
506
		}
507
	}
508 f20afeb6 Warren Baker
509 fe9d4894 Renato Botelho
	return false;
510 f20afeb6 Warren Baker
}
511
512
function unbound_get_next_id() {
513 fe9d4894 Renato Botelho
	$aclid = 0;
514 751533a2 Phil Davis
	while (unbound_acl_id_used($aclid)) {
515 fe9d4894 Renato Botelho
		$aclid++;
516 751533a2 Phil Davis
	}
517 fe9d4894 Renato Botelho
	return $aclid;
518 f20afeb6 Warren Baker
}
519
520
// Execute commands as the user unbound
521 1548bd35 Phil Davis
function do_as_unbound_user($cmd, $param1 = "") {
522 fe9d4894 Renato Botelho
	global $g;
523
524
	switch ($cmd) {
525 751533a2 Phil Davis
		case "start":
526
			mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
527
			break;
528
		case "stop":
529
			mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
530
			break;
531
		case "reload":
532
			mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
533
			break;
534
		case "unbound-anchor":
535 1548bd35 Phil Davis
			$root_key_file = "{$g['unbound_chroot_path']}{$param1}/root.key";
536 4eeb2809 Chris Buechler
			// sanity check root.key because unbound-anchor will fail without manual removal otherwise. redmine #5334
537 1548bd35 Phil Davis
			if (file_exists($root_key_file)) {
538
				$rootkeycheck = mwexec("/usr/bin/grep 'autotrust trust anchor file' {$root_key_file}", true);
539 4eeb2809 Chris Buechler
				if ($rootkeycheck != "0") {
540 1548bd35 Phil Davis
					log_error("Unbound {$root_key_file} file is corrupt, removing and recreating.");
541
					unlink_if_exists($root_key_file);
542 4eeb2809 Chris Buechler
				}
543
			}
544 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-anchor -a {$root_key_file}' | /usr/bin/su -m unbound", true);
545
			// Only sync the file if this is the real (default) one, not a test one.
546
			if ($param1 == "") {
547
				pfSense_fsync($root_key_file);
548
			}
549 751533a2 Phil Davis
			break;
550
		case "unbound-control-setup":
551 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}{$param1}' | /usr/bin/su -m unbound", true);
552 751533a2 Phil Davis
			break;
553
		default:
554
			break;
555 fe9d4894 Renato Botelho
	}
556 f20afeb6 Warren Baker
}
557
558 1548bd35 Phil Davis
function unbound_add_domain_overrides($pvt_rev="", $cfgsubdir = "") {
559 fe9d4894 Renato Botelho
	global $config, $g;
560
561
	$domains = $config['unbound']['domainoverrides'];
562
563
	$sorted_domains = msort($domains, "domain");
564
	$result = array();
565 751533a2 Phil Davis
	foreach ($sorted_domains as $domain) {
566 fe9d4894 Renato Botelho
		$domain_key = current($domain);
567 751533a2 Phil Davis
		if (!isset($result[$domain_key])) {
568 fe9d4894 Renato Botelho
			$result[$domain_key] = array();
569 751533a2 Phil Davis
		}
570 fe9d4894 Renato Botelho
		$result[$domain_key][] = $domain['ip'];
571
	}
572
573
	// Domain overrides that have multiple entries need multiple stub-addr: added
574
	$domain_entries = "";
575 751533a2 Phil Davis
	foreach ($result as $domain=>$ips) {
576 984abd66 Phil Davis
		if ($pvt_rev == "private") {
577 fe9d4894 Renato Botelho
			$domain_entries .= "private-domain: \"$domain\"\n";
578
			$domain_entries .= "domain-insecure: \"$domain\"\n";
579 984abd66 Phil Davis
		} else if ($pvt_rev == "reverse") {
580 086cf944 Phil Davis
			if ((substr($domain, -14) == ".in-addr.arpa.") || (substr($domain, -13) == ".in-addr.arpa")) {
581 984abd66 Phil Davis
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
582
			}
583 fe9d4894 Renato Botelho
		} else {
584
			$domain_entries .= "stub-zone:\n";
585
			$domain_entries .= "\tname: \"$domain\"\n";
586 751533a2 Phil Davis
			foreach ($ips as $ip) {
587 fe9d4894 Renato Botelho
				$domain_entries .= "\tstub-addr: $ip\n";
588 751533a2 Phil Davis
			}
589 fe9d4894 Renato Botelho
			$domain_entries .= "\tstub-prime: no\n";
590
		}
591
	}
592
593 751533a2 Phil Davis
	if ($pvt_rev != "") {
594 fe9d4894 Renato Botelho
		return $domain_entries;
595 751533a2 Phil Davis
	} else {
596 1548bd35 Phil Davis
		create_unbound_chroot_path($cfgsubdir);
597
		file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/domainoverrides.conf", $domain_entries);
598 e318d592 Phil Davis
	}
599 f20afeb6 Warren Baker
}
600
601 1548bd35 Phil Davis
function unbound_add_host_entries($cfgsubdir = "") {
602 fe9d4894 Renato Botelho
	global $config, $g;
603
604 9a83872f NOYB
	// Make sure the config setting is a valid unbound local zone type.  If not use "transparent".
605
	if (array_key_exists($config['unbound']['system_domain_local_zone_type'], unbound_local_zone_types())) {
606 ca47c065 NOYB
		$system_domain_local_zone_type = $config['unbound']['system_domain_local_zone_type'];
607 9a83872f NOYB
	} else {
608
		$system_domain_local_zone_type = "transparent";
609 ca47c065 NOYB
	}
610
611 77d9edf5 NOYB
	$unbound_entries = "local-zone: \"{$config['system']['domain']}\" {$system_domain_local_zone_type}\n";
612 fe9d4894 Renato Botelho
613 b3977493 Renato Botelho
	$hosts = read_hosts();
614 06266c34 Lorenz Schori
	$added_ptr = array();
615 b3977493 Renato Botelho
	foreach ($hosts as $host) {
616 751533a2 Phil Davis
		if (is_ipaddrv4($host['ipaddr'])) {
617 b3977493 Renato Botelho
			$type = 'A';
618 751533a2 Phil Davis
		} else if (is_ipaddrv6($host['ipaddr'])) {
619 b3977493 Renato Botelho
			$type = 'AAAA';
620 751533a2 Phil Davis
		} else {
621 b3977493 Renato Botelho
			continue;
622 751533a2 Phil Davis
		}
623 fe9d4894 Renato Botelho
624 751533a2 Phil Davis
		if (!$added_ptr[$host['ipaddr']]) {
625 06266c34 Lorenz Schori
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
626 f29610b0 Lorenz Schori
			$added_ptr[$host['ipaddr']] = true;
627 06266c34 Lorenz Schori
		}
628 b3977493 Renato Botelho
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
629 751533a2 Phil Davis
		if (isset($host['name'])) {
630 b3977493 Renato Botelho
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
631 751533a2 Phil Davis
		}
632 fe9d4894 Renato Botelho
	}
633
634
	// Write out entries
635 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
636
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/host_entries.conf", $unbound_entries);
637 b3977493 Renato Botelho
638
	/* dhcpleases will write to this config file, make sure it exists */
639 1548bd35 Phil Davis
	@touch("{$g['unbound_chroot_path']}{$cfgsubdir}/dhcpleases_entries.conf");
640 f20afeb6 Warren Baker
}
641
642 56a87b19 Warren Baker
function unbound_control($action) {
643 fe9d4894 Renato Botelho
	global $config, $g;
644
645
	$cache_dumpfile = "/var/tmp/unbound_cache";
646
647
	switch ($action) {
648
	case "start":
649
		// Start Unbound
650
		if ($config['unbound']['enable'] == "on") {
651 751533a2 Phil Davis
			if (!is_service_running("unbound")) {
652 fe9d4894 Renato Botelho
				do_as_unbound_user("start");
653 751533a2 Phil Davis
			}
654 fe9d4894 Renato Botelho
		}
655
		break;
656
	case "stop":
657 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
658 fe9d4894 Renato Botelho
			do_as_unbound_user("stop");
659 751533a2 Phil Davis
		}
660 fe9d4894 Renato Botelho
		break;
661
	case "reload":
662 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
663 fe9d4894 Renato Botelho
			do_as_unbound_user("reload");
664 751533a2 Phil Davis
		}
665 fe9d4894 Renato Botelho
		break;
666
	case "dump_cache":
667
		// Dump Unbound's Cache
668 751533a2 Phil Davis
		if ($config['unbound']['dumpcache'] == "on") {
669 fe9d4894 Renato Botelho
			do_as_unbound_user("dump_cache");
670 751533a2 Phil Davis
		}
671 fe9d4894 Renato Botelho
		break;
672
	case "restore_cache":
673
		// Restore Unbound's Cache
674
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
675 751533a2 Phil Davis
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
676 fe9d4894 Renato Botelho
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
677 751533a2 Phil Davis
			}
678 fe9d4894 Renato Botelho
		}
679
		break;
680
	default:
681
		break;
682
683
	}
684 56a87b19 Warren Baker
}
685
686
// Generation of Unbound statistics
687
function unbound_statistics() {
688 fe9d4894 Renato Botelho
	global $config;
689
690
	if ($config['stats'] == "on") {
691
		$stats_interval = $config['unbound']['stats_interval'];
692
		$cumulative_stats = $config['cumulative_stats'];
693 751533a2 Phil Davis
		if ($config['extended_stats'] == "on") {
694 fe9d4894 Renato Botelho
			$extended_stats = "yes";
695 751533a2 Phil Davis
		} else {
696 fe9d4894 Renato Botelho
			$extended_stats = "no";
697 751533a2 Phil Davis
		}
698 fe9d4894 Renato Botelho
	} else {
699
		$stats_interval = "0";
700
		$cumulative_stats = "no";
701
		$extended_stats = "no";
702
	}
703
	/* XXX To do - add RRD graphs */
704
	$stats = <<<EOF
705 56a87b19 Warren Baker
# Unbound Statistics
706
statistics-interval: {$stats_interval}
707
extended-statistics: yes
708
statistics-cumulative: yes
709
710
EOF;
711
712 fe9d4894 Renato Botelho
	return $stats;
713 56a87b19 Warren Baker
}
714
715 8fccab67 Warren Baker
// Unbound Access lists
716 1548bd35 Phil Davis
function unbound_acls_config($cfgsubdir = "") {
717 fe9d4894 Renato Botelho
	global $g, $config;
718
719 f8f5ba1a Chris Buechler
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
720
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
721
		$aclcfg .= "access-control: ::1 allow\n";
722
		// Add our networks for active interfaces including localhost
723 8c2a5a73 Phil Davis
		if (!empty($config['unbound']['active_interface'])) {
724 f8f5ba1a Chris Buechler
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
725 751533a2 Phil Davis
			if (in_array("all", $active_interfaces)) {
726 80075b9e Chris Buechler
				$active_interfaces = get_configured_interface_with_descr();
727 751533a2 Phil Davis
			}
728
		} else {
729 f8f5ba1a Chris Buechler
			$active_interfaces = get_configured_interface_with_descr();
730 751533a2 Phil Davis
		}
731
732 f8f5ba1a Chris Buechler
		$bindints = "";
733 751533a2 Phil Davis
		foreach ($active_interfaces as $ubif => $ifdesc) {
734 f8f5ba1a Chris Buechler
			$ifip = get_interface_ip($ubif);
735
			if (is_ipaddrv4($ifip)) {
736
				// IPv4 is handled via NAT networks below
737
			}
738
			$ifip = get_interface_ipv6($ubif);
739
			if (is_ipaddrv6($ifip)) {
740 f302a333 Jean Cyr
				if (!is_linklocal($ifip)) {
741
					$subnet_bits = get_interface_subnetv6($ubif);
742
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
743 751533a2 Phil Davis
					// only add LAN-type interfaces
744
					if (!interface_has_gateway($ubif)) {
745 f302a333 Jean Cyr
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
746 751533a2 Phil Davis
					}
747 f302a333 Jean Cyr
				}
748 f8f5ba1a Chris Buechler
				// add for IPv6 static routes to local networks
749
				// for safety, we include only routes reachable on an interface with no
750 751533a2 Phil Davis
				// gateway specified - read: not an Internet connection.
751 f8f5ba1a Chris Buechler
				$static_routes = get_staticroutes();
752
				foreach ($static_routes as $route) {
753
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
754
						// route is on this interface, interface doesn't have gateway, add it
755
						$aclcfg .= "access-control: {$route['network']} allow\n";
756
					}
757 e3045c51 Chris Buechler
				}
758
			}
759 fe9d4894 Renato Botelho
		}
760 751533a2 Phil Davis
761 f8f5ba1a Chris Buechler
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
762
		if (empty($FilterIflist)) {
763
			filter_generate_optcfg_array();
764
		}
765
		$natnetworks_array = array();
766
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
767
		foreach ($natnetworks_array as $allowednet) {
768 751533a2 Phil Davis
			$aclcfg .= "access-control: $allowednet allow \n";
769
		}
770 3bdf2a70 Chris Buechler
	}
771 fe9d4894 Renato Botelho
772
	// Configure the custom ACLs
773
	if (is_array($config['unbound']['acls'])) {
774 751533a2 Phil Davis
		foreach ($config['unbound']['acls'] as $unbound_acl) {
775 fe9d4894 Renato Botelho
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
776 751533a2 Phil Davis
			foreach ($unbound_acl['row'] as $network) {
777
				if ($unbound_acl['aclaction'] == "allow snoop") {
778 fe9d4894 Renato Botelho
					$unbound_acl['aclaction'] = "allow_snoop";
779 751533a2 Phil Davis
				}
780 fe9d4894 Renato Botelho
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
781
			}
782
		}
783
	}
784
	// Write out Access list
785 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
786
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/access_lists.conf", $aclcfg);
787 58d00e65 Warren Baker
788 8fccab67 Warren Baker
}
789
790 f6248774 Warren Baker
// Generate hosts and reload services
791
function unbound_hosts_generate() {
792 fe9d4894 Renato Botelho
	// Generate our hosts file
793
	unbound_add_host_entries();
794 f6248774 Warren Baker
795 fe9d4894 Renato Botelho
	// Reload our service to read the updates
796
	unbound_control("reload");
797 f6248774 Warren Baker
}
798
799 9a83872f NOYB
// Array of valid unbound local zone types
800
function unbound_local_zone_types() {
801
	return array(
802
		"deny" => gettext("Deny"),
803
		"refuse" => gettext("Refuse"),
804
		"static" => gettext("Static"),
805
		"transparent" => gettext("Transparent"),
806
		"typetransparent" => gettext("Type Transparent"),
807
		"redirect" => gettext("Redirect"),
808
		"inform" => gettext("Inform"),
809
		"inform_deny" => gettext("Inform Deny"),
810
		"nodefault" => gettext("No Default")
811
	);
812
}
813
814 3f0c20c3 Renato Botelho
?>