Project

General

Profile

Download (24.9 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
	$outgoing_num_tcp = (!empty($unboundcfg['outgoing_num_tcp'])) ? $unboundcfg['outgoing_num_tcp'] : "10";
285
	$incoming_num_tcp = (!empty($unboundcfg['incoming_num_tcp'])) ? $unboundcfg['incoming_num_tcp'] : "10";
286
	$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 fe9d4894 Renato Botelho
				$forward_conf .= "\tforward-addr: $dnsserver\n";
330 751533a2 Phil Davis
			}
331 fe9d4894 Renato Botelho
		}
332 751533a2 Phil Davis
	} else {
333 fe9d4894 Renato Botelho
		$forward_conf = "";
334 751533a2 Phil Davis
	}
335 be5aa310 Warren Baker
336 2597415b Chris Buechler
	// Size of the RRset cache == 2 * msg-cache-size per Unbound's recommendations
337
	$rrset_cache_size = $msg_cache_size * 2;
338
339 fe9d4894 Renato Botelho
	$unboundconf = <<<EOD
340 f20afeb6 Warren Baker
##########################
341
# Unbound Configuration
342
##########################
343
344
##
345
# Server configuration
346
##
347
server:
348 984abd66 Phil Davis
{$reverse_zones}
349 f20afeb6 Warren Baker
chroot: {$g['unbound_chroot_path']}
350
username: "unbound"
351 56a87b19 Warren Baker
directory: "{$g['unbound_chroot_path']}"
352 f20afeb6 Warren Baker
pidfile: "/var/run/unbound.pid"
353
use-syslog: yes
354 d12889b0 Warren Baker
port: {$port}
355 56a87b19 Warren Baker
verbosity: {$verbosity}
356 b9608ab6 Phil Davis
hide-identity: {$hide_identity}
357
hide-version: {$hide_version}
358 5c7c369f Chris Buechler
harden-glue: yes
359 f20afeb6 Warren Baker
do-ip4: yes
360
do-ip6: yes
361
do-udp: yes
362
do-tcp: yes
363
do-daemonize: yes
364
module-config: "{$module_config}"
365 b9608ab6 Phil Davis
unwanted-reply-threshold: {$unwanted_reply_threshold}
366
num-queries-per-thread: {$num_queries_per_thread}
367
jostle-timeout: {$jostle_timeout}
368
infra-host-ttl: {$infra_host_ttl}
369
infra-cache-numhosts: {$infra_cache_numhosts}
370
outgoing-num-tcp: {$outgoing_num_tcp}
371
incoming-num-tcp: {$incoming_num_tcp}
372
edns-buffer-size: {$edns_buffer_size}
373 56a87b19 Warren Baker
cache-max-ttl: {$cache_max_ttl}
374
cache-min-ttl: {$cache_min_ttl}
375 b9608ab6 Phil Davis
harden-dnssec-stripped: {$harden_dnssec_stripped}
376
msg-cache-size: {$msg_cache_size}m
377 2597415b Chris Buechler
rrset-cache-size: {$rrset_cache_size}m
378
379 f20afeb6 Warren Baker
{$optimization['number_threads']}
380
{$optimization['msg_cache_slabs']}
381
{$optimization['rrset_cache_slabs']}
382
{$optimization['infra_cache_slabs']}
383
{$optimization['key_cache_slabs']}
384 2cbcc256 Warren Baker
outgoing-range: 4096
385 f20afeb6 Warren Baker
{$optimization['so_rcvbuf']}
386
{$anchor_file}
387 56a87b19 Warren Baker
prefetch: {$prefetch}
388
prefetch-key: {$prefetch_key}
389 a771a6ae Warren Baker
use-caps-for-id: {$use_caps}
390 f20afeb6 Warren Baker
# Statistics
391
{$statistics}
392
# Interface IP(s) to bind to
393 16a3108f Warren Baker
{$bindints}
394 6374fb57 Warren Baker
{$outgoingints}
395 f20afeb6 Warren Baker
396
# DNS Rebinding
397
{$private_addr}
398
{$private_domains}
399
400 4e8e8cc8 Warren Baker
# Access lists
401 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/access_lists.conf
402 4e8e8cc8 Warren Baker
403 f20afeb6 Warren Baker
# Static host entries
404 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/host_entries.conf
405 f20afeb6 Warren Baker
406 b3977493 Renato Botelho
# dhcp lease entries
407 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/dhcpleases_entries.conf
408 b3977493 Renato Botelho
409 f20afeb6 Warren Baker
# Domain overrides
410 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/domainoverrides.conf
411 be5aa310 Warren Baker
{$forward_conf}
412
413 f20afeb6 Warren Baker
{$custom_options}
414
415
###
416
# Remote Control Config
417
###
418 1548bd35 Phil Davis
include: {$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf
419 f20afeb6 Warren Baker
420
EOD;
421
422 932711c7 Matt Smith
	return $unboundconf;
423 f20afeb6 Warren Baker
}
424
425 1548bd35 Phil Davis
function unbound_remote_control_setup($cfgsubdir = "") {
426 fe9d4894 Renato Botelho
	global $g;
427 f20afeb6 Warren Baker
428 1548bd35 Phil Davis
	if (!file_exists("{$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.key")) {
429 fe9d4894 Renato Botelho
		$remotcfg = <<<EOF
430 f20afeb6 Warren Baker
remote-control:
431 fe9d4894 Renato Botelho
	control-enable: yes
432
	control-interface: 127.0.0.1
433
	control-port: 953
434 1548bd35 Phil Davis
	server-key-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_server.key"
435
	server-cert-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_server.pem"
436
	control-key-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.key"
437
	control-cert-file: "{$g['unbound_chroot_path']}{$cfgsubdir}/unbound_control.pem"
438 56a87b19 Warren Baker
439 f20afeb6 Warren Baker
EOF;
440
441 1548bd35 Phil Davis
		create_unbound_chroot_path($cfgsubdir);
442
		file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/remotecontrol.conf", $remotcfg);
443 f20afeb6 Warren Baker
444 fe9d4894 Renato Botelho
		// Generate our keys
445 1548bd35 Phil Davis
		do_as_unbound_user("unbound-control-setup", $cfgsubdir);
446 f20afeb6 Warren Baker
447 fe9d4894 Renato Botelho
	}
448 56a87b19 Warren Baker
}
449 f20afeb6 Warren Baker
450 56a87b19 Warren Baker
// Read /etc/hosts
451 f20afeb6 Warren Baker
function read_hosts() {
452
453 fe9d4894 Renato Botelho
	/* Open /etc/hosts and extract the only dhcpleases info
454
	 * XXX - to convert to an unbound C library which reads /etc/hosts automatically
455
	 */
456
	$etc_hosts = array();
457
	foreach (file('/etc/hosts') as $line) {
458 751533a2 Phil Davis
		if (strpos($line, "dhcpleases automatically entered")) {
459 b3977493 Renato Botelho
			break;
460 751533a2 Phil Davis
		}
461 b3977493 Renato Botelho
		$d = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
462 751533a2 Phil Davis
		if (empty($d) || substr(reset($d), 0, 1) == "#") {
463 fe9d4894 Renato Botelho
			continue;
464 751533a2 Phil Davis
		}
465 b3977493 Renato Botelho
		$ip = array_shift($d);
466
		$fqdn = array_shift($d);
467
		$name = array_shift($d);
468
		if (!empty($fqdn) && $fqdn != "empty") {
469 751533a2 Phil Davis
			if (!empty($name) && $name != "empty") {
470 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
471 751533a2 Phil Davis
			} else {
472 b3977493 Renato Botelho
				array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
473 751533a2 Phil Davis
			}
474 fe9d4894 Renato Botelho
		}
475
	}
476
	return $etc_hosts;
477 f20afeb6 Warren Baker
}
478
479
function sync_unbound_service() {
480 fe9d4894 Renato Botelho
	global $config, $g;
481
482 e318d592 Phil Davis
	create_unbound_chroot_path();
483 fe9d4894 Renato Botelho
484
	// Configure our Unbound service
485
	do_as_unbound_user("unbound-anchor");
486
	unbound_remote_control_setup();
487
	unbound_generate_config();
488
	do_as_unbound_user("start");
489
	require_once("service-utils.inc");
490 751533a2 Phil Davis
	if (is_service_running("unbound")) {
491 fe9d4894 Renato Botelho
		do_as_unbound_user("restore_cache");
492 751533a2 Phil Davis
	}
493 f20afeb6 Warren Baker
494
}
495
496
function unbound_acl_id_used($id) {
497 fe9d4894 Renato Botelho
	global $config;
498 f20afeb6 Warren Baker
499 751533a2 Phil Davis
	if (is_array($config['unbound']['acls'])) {
500
		foreach ($config['unbound']['acls'] as & $acls) {
501
			if ($id == $acls['aclid']) {
502 fe9d4894 Renato Botelho
				return true;
503 751533a2 Phil Davis
			}
504
		}
505
	}
506 f20afeb6 Warren Baker
507 fe9d4894 Renato Botelho
	return false;
508 f20afeb6 Warren Baker
}
509
510
function unbound_get_next_id() {
511 fe9d4894 Renato Botelho
	$aclid = 0;
512 751533a2 Phil Davis
	while (unbound_acl_id_used($aclid)) {
513 fe9d4894 Renato Botelho
		$aclid++;
514 751533a2 Phil Davis
	}
515 fe9d4894 Renato Botelho
	return $aclid;
516 f20afeb6 Warren Baker
}
517
518
// Execute commands as the user unbound
519 1548bd35 Phil Davis
function do_as_unbound_user($cmd, $param1 = "") {
520 fe9d4894 Renato Botelho
	global $g;
521
522
	switch ($cmd) {
523 751533a2 Phil Davis
		case "start":
524
			mwexec("/usr/local/sbin/unbound -c {$g['unbound_chroot_path']}/unbound.conf");
525
			break;
526
		case "stop":
527
			mwexec("echo '/usr/local/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
528
			break;
529
		case "reload":
530
			mwexec("echo '/usr/local/sbin/unbound-control reload' | /usr/bin/su -m unbound", true);
531
			break;
532
		case "unbound-anchor":
533 1548bd35 Phil Davis
			$root_key_file = "{$g['unbound_chroot_path']}{$param1}/root.key";
534 4eeb2809 Chris Buechler
			// sanity check root.key because unbound-anchor will fail without manual removal otherwise. redmine #5334
535 1548bd35 Phil Davis
			if (file_exists($root_key_file)) {
536
				$rootkeycheck = mwexec("/usr/bin/grep 'autotrust trust anchor file' {$root_key_file}", true);
537 4eeb2809 Chris Buechler
				if ($rootkeycheck != "0") {
538 1548bd35 Phil Davis
					log_error("Unbound {$root_key_file} file is corrupt, removing and recreating.");
539
					unlink_if_exists($root_key_file);
540 4eeb2809 Chris Buechler
				}
541
			}
542 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-anchor -a {$root_key_file}' | /usr/bin/su -m unbound", true);
543
			// Only sync the file if this is the real (default) one, not a test one.
544
			if ($param1 == "") {
545
				pfSense_fsync($root_key_file);
546
			}
547 751533a2 Phil Davis
			break;
548
		case "unbound-control-setup":
549 1548bd35 Phil Davis
			mwexec("echo '/usr/local/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}{$param1}' | /usr/bin/su -m unbound", true);
550 751533a2 Phil Davis
			break;
551
		default:
552
			break;
553 fe9d4894 Renato Botelho
	}
554 f20afeb6 Warren Baker
}
555
556 1548bd35 Phil Davis
function unbound_add_domain_overrides($pvt_rev="", $cfgsubdir = "") {
557 fe9d4894 Renato Botelho
	global $config, $g;
558
559
	$domains = $config['unbound']['domainoverrides'];
560
561
	$sorted_domains = msort($domains, "domain");
562
	$result = array();
563 751533a2 Phil Davis
	foreach ($sorted_domains as $domain) {
564 fe9d4894 Renato Botelho
		$domain_key = current($domain);
565 751533a2 Phil Davis
		if (!isset($result[$domain_key])) {
566 fe9d4894 Renato Botelho
			$result[$domain_key] = array();
567 751533a2 Phil Davis
		}
568 fe9d4894 Renato Botelho
		$result[$domain_key][] = $domain['ip'];
569
	}
570
571
	// Domain overrides that have multiple entries need multiple stub-addr: added
572
	$domain_entries = "";
573 751533a2 Phil Davis
	foreach ($result as $domain=>$ips) {
574 984abd66 Phil Davis
		if ($pvt_rev == "private") {
575 fe9d4894 Renato Botelho
			$domain_entries .= "private-domain: \"$domain\"\n";
576
			$domain_entries .= "domain-insecure: \"$domain\"\n";
577 984abd66 Phil Davis
		} else if ($pvt_rev == "reverse") {
578 086cf944 Phil Davis
			if ((substr($domain, -14) == ".in-addr.arpa.") || (substr($domain, -13) == ".in-addr.arpa")) {
579 984abd66 Phil Davis
				$domain_entries .= "local-zone: \"$domain\" typetransparent\n";
580
			}
581 fe9d4894 Renato Botelho
		} else {
582
			$domain_entries .= "stub-zone:\n";
583
			$domain_entries .= "\tname: \"$domain\"\n";
584 751533a2 Phil Davis
			foreach ($ips as $ip) {
585 fe9d4894 Renato Botelho
				$domain_entries .= "\tstub-addr: $ip\n";
586 751533a2 Phil Davis
			}
587 fe9d4894 Renato Botelho
			$domain_entries .= "\tstub-prime: no\n";
588
		}
589
	}
590
591 751533a2 Phil Davis
	if ($pvt_rev != "") {
592 fe9d4894 Renato Botelho
		return $domain_entries;
593 751533a2 Phil Davis
	} else {
594 1548bd35 Phil Davis
		create_unbound_chroot_path($cfgsubdir);
595
		file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/domainoverrides.conf", $domain_entries);
596 e318d592 Phil Davis
	}
597 f20afeb6 Warren Baker
}
598
599 1548bd35 Phil Davis
function unbound_add_host_entries($cfgsubdir = "") {
600 fe9d4894 Renato Botelho
	global $config, $g;
601
602 9a83872f NOYB
	// Make sure the config setting is a valid unbound local zone type.  If not use "transparent".
603
	if (array_key_exists($config['unbound']['system_domain_local_zone_type'], unbound_local_zone_types())) {
604 ca47c065 NOYB
		$system_domain_local_zone_type = $config['unbound']['system_domain_local_zone_type'];
605 9a83872f NOYB
	} else {
606
		$system_domain_local_zone_type = "transparent";
607 ca47c065 NOYB
	}
608
609 77d9edf5 NOYB
	$unbound_entries = "local-zone: \"{$config['system']['domain']}\" {$system_domain_local_zone_type}\n";
610 fe9d4894 Renato Botelho
611 b3977493 Renato Botelho
	$hosts = read_hosts();
612 06266c34 Lorenz Schori
	$added_ptr = array();
613 b3977493 Renato Botelho
	foreach ($hosts as $host) {
614 751533a2 Phil Davis
		if (is_ipaddrv4($host['ipaddr'])) {
615 b3977493 Renato Botelho
			$type = 'A';
616 751533a2 Phil Davis
		} else if (is_ipaddrv6($host['ipaddr'])) {
617 b3977493 Renato Botelho
			$type = 'AAAA';
618 751533a2 Phil Davis
		} else {
619 b3977493 Renato Botelho
			continue;
620 751533a2 Phil Davis
		}
621 fe9d4894 Renato Botelho
622 751533a2 Phil Davis
		if (!$added_ptr[$host['ipaddr']]) {
623 06266c34 Lorenz Schori
			$unbound_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
624 f29610b0 Lorenz Schori
			$added_ptr[$host['ipaddr']] = true;
625 06266c34 Lorenz Schori
		}
626 b3977493 Renato Botelho
		$unbound_entries .= "local-data: \"{$host['fqdn']} {$type} {$host['ipaddr']}\"\n";
627 751533a2 Phil Davis
		if (isset($host['name'])) {
628 b3977493 Renato Botelho
			$unbound_entries .= "local-data: \"{$host['name']} {$type} {$host['ipaddr']}\"\n";
629 751533a2 Phil Davis
		}
630 fe9d4894 Renato Botelho
	}
631
632
	// Write out entries
633 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
634
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/host_entries.conf", $unbound_entries);
635 b3977493 Renato Botelho
636
	/* dhcpleases will write to this config file, make sure it exists */
637 1548bd35 Phil Davis
	@touch("{$g['unbound_chroot_path']}{$cfgsubdir}/dhcpleases_entries.conf");
638 f20afeb6 Warren Baker
}
639
640 56a87b19 Warren Baker
function unbound_control($action) {
641 fe9d4894 Renato Botelho
	global $config, $g;
642
643
	$cache_dumpfile = "/var/tmp/unbound_cache";
644
645
	switch ($action) {
646
	case "start":
647
		// Start Unbound
648
		if ($config['unbound']['enable'] == "on") {
649 751533a2 Phil Davis
			if (!is_service_running("unbound")) {
650 fe9d4894 Renato Botelho
				do_as_unbound_user("start");
651 751533a2 Phil Davis
			}
652 fe9d4894 Renato Botelho
		}
653
		break;
654
	case "stop":
655 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
656 fe9d4894 Renato Botelho
			do_as_unbound_user("stop");
657 751533a2 Phil Davis
		}
658 fe9d4894 Renato Botelho
		break;
659
	case "reload":
660 751533a2 Phil Davis
		if ($config['unbound']['enable'] == "on") {
661 fe9d4894 Renato Botelho
			do_as_unbound_user("reload");
662 751533a2 Phil Davis
		}
663 fe9d4894 Renato Botelho
		break;
664
	case "dump_cache":
665
		// Dump Unbound's Cache
666 751533a2 Phil Davis
		if ($config['unbound']['dumpcache'] == "on") {
667 fe9d4894 Renato Botelho
			do_as_unbound_user("dump_cache");
668 751533a2 Phil Davis
		}
669 fe9d4894 Renato Botelho
		break;
670
	case "restore_cache":
671
		// Restore Unbound's Cache
672
		if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
673 751533a2 Phil Davis
			if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0) {
674 fe9d4894 Renato Botelho
				do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
675 751533a2 Phil Davis
			}
676 fe9d4894 Renato Botelho
		}
677
		break;
678
	default:
679
		break;
680
681
	}
682 56a87b19 Warren Baker
}
683
684
// Generation of Unbound statistics
685
function unbound_statistics() {
686 fe9d4894 Renato Botelho
	global $config;
687
688
	if ($config['stats'] == "on") {
689
		$stats_interval = $config['unbound']['stats_interval'];
690
		$cumulative_stats = $config['cumulative_stats'];
691 751533a2 Phil Davis
		if ($config['extended_stats'] == "on") {
692 fe9d4894 Renato Botelho
			$extended_stats = "yes";
693 751533a2 Phil Davis
		} else {
694 fe9d4894 Renato Botelho
			$extended_stats = "no";
695 751533a2 Phil Davis
		}
696 fe9d4894 Renato Botelho
	} else {
697
		$stats_interval = "0";
698
		$cumulative_stats = "no";
699
		$extended_stats = "no";
700
	}
701
	/* XXX To do - add RRD graphs */
702
	$stats = <<<EOF
703 56a87b19 Warren Baker
# Unbound Statistics
704
statistics-interval: {$stats_interval}
705
extended-statistics: yes
706
statistics-cumulative: yes
707
708
EOF;
709
710 fe9d4894 Renato Botelho
	return $stats;
711 56a87b19 Warren Baker
}
712
713 8fccab67 Warren Baker
// Unbound Access lists
714 1548bd35 Phil Davis
function unbound_acls_config($cfgsubdir = "") {
715 fe9d4894 Renato Botelho
	global $g, $config;
716
717 f8f5ba1a Chris Buechler
	if (!isset($config['unbound']['disable_auto_added_access_control'])) {
718
		$aclcfg = "access-control: 127.0.0.1/32 allow\n";
719
		$aclcfg .= "access-control: ::1 allow\n";
720
		// Add our networks for active interfaces including localhost
721 8c2a5a73 Phil Davis
		if (!empty($config['unbound']['active_interface'])) {
722 f8f5ba1a Chris Buechler
			$active_interfaces = array_flip(explode(",", $config['unbound']['active_interface']));
723 751533a2 Phil Davis
			if (in_array("all", $active_interfaces)) {
724 80075b9e Chris Buechler
				$active_interfaces = get_configured_interface_with_descr();
725 751533a2 Phil Davis
			}
726
		} else {
727 f8f5ba1a Chris Buechler
			$active_interfaces = get_configured_interface_with_descr();
728 751533a2 Phil Davis
		}
729
730 f8f5ba1a Chris Buechler
		$bindints = "";
731 751533a2 Phil Davis
		foreach ($active_interfaces as $ubif => $ifdesc) {
732 f8f5ba1a Chris Buechler
			$ifip = get_interface_ip($ubif);
733
			if (is_ipaddrv4($ifip)) {
734
				// IPv4 is handled via NAT networks below
735
			}
736
			$ifip = get_interface_ipv6($ubif);
737
			if (is_ipaddrv6($ifip)) {
738 f302a333 Jean Cyr
				if (!is_linklocal($ifip)) {
739
					$subnet_bits = get_interface_subnetv6($ubif);
740
					$subnet_ip = gen_subnetv6($ifip, $subnet_bits);
741 751533a2 Phil Davis
					// only add LAN-type interfaces
742
					if (!interface_has_gateway($ubif)) {
743 f302a333 Jean Cyr
						$aclcfg .= "access-control: {$subnet_ip}/{$subnet_bits} allow\n";
744 751533a2 Phil Davis
					}
745 f302a333 Jean Cyr
				}
746 f8f5ba1a Chris Buechler
				// add for IPv6 static routes to local networks
747
				// for safety, we include only routes reachable on an interface with no
748 751533a2 Phil Davis
				// gateway specified - read: not an Internet connection.
749 f8f5ba1a Chris Buechler
				$static_routes = get_staticroutes();
750
				foreach ($static_routes as $route) {
751
					if ((lookup_gateway_interface_by_name($route['gateway']) == $ubif) && !interface_has_gateway($ubif)) {
752
						// route is on this interface, interface doesn't have gateway, add it
753
						$aclcfg .= "access-control: {$route['network']} allow\n";
754
					}
755 e3045c51 Chris Buechler
				}
756
			}
757 fe9d4894 Renato Botelho
		}
758 751533a2 Phil Davis
759 f8f5ba1a Chris Buechler
		// Generate IPv4 access-control entries using the same logic as automatic outbound NAT
760
		if (empty($FilterIflist)) {
761
			filter_generate_optcfg_array();
762
		}
763
		$natnetworks_array = array();
764
		$natnetworks_array = filter_nat_rules_automatic_tonathosts();
765
		foreach ($natnetworks_array as $allowednet) {
766 751533a2 Phil Davis
			$aclcfg .= "access-control: $allowednet allow \n";
767
		}
768 3bdf2a70 Chris Buechler
	}
769 fe9d4894 Renato Botelho
770
	// Configure the custom ACLs
771
	if (is_array($config['unbound']['acls'])) {
772 751533a2 Phil Davis
		foreach ($config['unbound']['acls'] as $unbound_acl) {
773 fe9d4894 Renato Botelho
			$aclcfg .= "#{$unbound_acl['aclname']}\n";
774 751533a2 Phil Davis
			foreach ($unbound_acl['row'] as $network) {
775
				if ($unbound_acl['aclaction'] == "allow snoop") {
776 fe9d4894 Renato Botelho
					$unbound_acl['aclaction'] = "allow_snoop";
777 751533a2 Phil Davis
				}
778 fe9d4894 Renato Botelho
				$aclcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
779
			}
780
		}
781
	}
782
	// Write out Access list
783 1548bd35 Phil Davis
	create_unbound_chroot_path($cfgsubdir);
784
	file_put_contents("{$g['unbound_chroot_path']}{$cfgsubdir}/access_lists.conf", $aclcfg);
785 58d00e65 Warren Baker
786 8fccab67 Warren Baker
}
787
788 f6248774 Warren Baker
// Generate hosts and reload services
789
function unbound_hosts_generate() {
790 fe9d4894 Renato Botelho
	// Generate our hosts file
791
	unbound_add_host_entries();
792 f6248774 Warren Baker
793 fe9d4894 Renato Botelho
	// Reload our service to read the updates
794
	unbound_control("reload");
795 f6248774 Warren Baker
}
796
797 9a83872f NOYB
// Array of valid unbound local zone types
798
function unbound_local_zone_types() {
799
	return array(
800
		"deny" => gettext("Deny"),
801
		"refuse" => gettext("Refuse"),
802
		"static" => gettext("Static"),
803
		"transparent" => gettext("Transparent"),
804
		"typetransparent" => gettext("Type Transparent"),
805
		"redirect" => gettext("Redirect"),
806
		"inform" => gettext("Inform"),
807
		"inform_deny" => gettext("Inform Deny"),
808
		"nodefault" => gettext("No Default")
809
	);
810
}
811
812 3f0c20c3 Renato Botelho
?>