Project

General

Profile

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