Project

General

Profile

Download (23 KB) Statistics
| Branch: | Tag: | Revision:
1 f20afeb6 Warren Baker
<?php
2
/*
3
    unbound.inc
4
    part of the pfSense project (http://www.pfsense.com)
5
6
    originally part of m0n0wall (http://m0n0.ch/wall)
7
    Copyright (C) 2014  Warren Baker <warren@decoy.co.za>
8
    All rights reserved.
9
10
    Redistribution and use in source and binary forms, with or without
11
    modification, are permitted provided that the following conditions are met:
12
13
    1. Redistributions of source code must retain the above copyright notice,
14
       this list of conditions and the following disclaimer.
15
16
    2. Redistributions in binary form must reproduce the above copyright
17
       notice, this list of conditions and the following disclaimer in the
18
       documentation and/or other materials provided with the distribution.
19
20
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
    AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
    AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24
    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
    POSSIBILITY OF SUCH DAMAGE.
30
    
31
    pfSense_BUILDER_BINARIES:   /usr/sbin/unbound  /usr/sbin/unbound-anchor    /usr/sbin/unbound-checkconf
32
    pfSense_BUILDER_BINARIES:   /usr/sbin/unbound-control    /usr/sbin/unbound-control-setup
33
    pfSense_MODULE: unbound
34
*/
35
36
/* include all configuration functions */
37
require_once("config.inc");
38
require_once("functions.inc");
39
40
/* Optimize Unbound for environment */
41
function unbound_optimization() {
42
    global $config;
43
44
    $optimization_settings = array();
45
    
46
    /* 
47
     * Set the number of threads equal to number of CPUs.
48
     * Use 1 to disable threading, if for some reason this sysctl fails.
49
     */
50
    $numprocs = intval(trim(`/sbin/sysctl kern.smp.cpus | /usr/bin/cut -d" " -f2`));
51
    if ($numprocs > 0)
52
        $optimization['number_threads'] = "num-threads: {$numprocs}";
53
    else
54
        $optimization['number_threads'] = "num-threads: 1";
55
    
56
    // Slabs to help reduce lock contention.
57
    if ($numprocs > 4) {
58
        $optimization['msg_cache_slabs'] = "msg-cache-slabs: {$numprocs}";
59
        $optimization['rrset_cache_slabs'] = "rrset-cache-slabs: {$numprocs}";
60
        $optimization['infra_cache_slabs'] = "infra-cache-slabs: {$numprocs}";
61
        $optimization['key_cache_slabs'] = "key-cache-slabs: {$numprocs}";
62
    } else {
63
        $optimization['msg_cache_slabs'] = "msg-cache-slabs: 4";
64
        $optimization['rrset_cache_slabs'] = "rrset-cache-slabs: 4";
65
        $optimization['infra_cache_slabs'] = "infra-cache-slabs: 4";
66
        $optimization['key_cache_slabs'] = "key-cache-slabs: 4";
67
    }
68
    
69
    // Memory usage default of 4MB
70
    $optimization['msg_cache_size'] = "msg-cache-size: 4m";
71
    $optimization['rrset_cache_size'] = "rrset-cache-size: 8m";
72
73
    // More outgoing connections per thread otherwise assign a default of 4096 for a single thread
74
    if ($numprocs > 0) {
75
        $or = (1024/$numprocs) - 50;
76
        $optimization['outgoing_range'] = "outgoing-range: {$or}";
77
    } else
78
        $optimization['outgoing_range'] = "outgoing-range: {4096}";
79
80
    /*
81
     * Larger socket buffer for busy servers
82
     * Check that it is set to 4MB (by default the OS has it configured to 4MB)
83
     */
84
    foreach ($config['sysctl']['item'] as $tunable) {
85
        if ($tunable['tunable'] == 'kern.ipc.maxsockbuf') {
86
            $so = floor(($tunable['value']/1024/1024)-1);
87
            // Check to ensure that the number is not a negative
88
            if ($so > 0)
89
                $optimization['so_rcvbuf'] = "so-rcvbuf: {$so}m";
90
            else
91
                unset($optimization['so_rcvbuf']);
92
        }
93
    }
94
    // Safety check in case kern.ipc.maxsockbuf is not available.
95
    if (!isset($optimization['so_rcvbuf']))
96
        $optimization['so_rcvbuf'] = "#so-rcvbuf: 4m";
97
98
    return $optimization;
99
100
}
101
102
function unbound_generate_config() {
103
    global $config, $g;
104
105
    // Setup optimization
106
    $optimization = unbound_optimization();
107
108
    // Setup DNSSEC support
109
    if (isset($config['unbound']['dnssec_status'])) {
110
        $module_config = "validator iterator";
111 56a87b19 Warren Baker
        $anchor_file = "auto-trust-anchor-file: {$g['unbound_chroot_path']}/root-trust-anchor";
112 f20afeb6 Warren Baker
    } else
113
        $module_config = "iterator";
114
115
    // Setup DNS Rebinding
116
    if (!isset($config['system']['webgui']['nodnsrebindcheck'])) {
117
        // Private-addresses for DNS Rebinding
118
        $private_addr = <<<EOF
119
# For DNS Rebinding prevention
120
private-address: 10.0.0.0/8
121
private-address: 172.16.0.0/12
122
private-address: 192.168.0.0/16
123
private-address: 192.254.0.0/16
124
private-address: fd00::/8
125
private-address: fe80::/10
126
EOF;
127
    }
128
129
    // Allow DNS Rebind for forwarded domains
130
    if ((isset($config['unbound']['domainoverrides']) && is_array($config['unbound']['domainoverrides'])) && !isset($config['system']['webgui']['nodnsrebindcheck'])) {
131
        $private_domains = "# Set private domains in case authoritative name server returns a Private IP address";
132
        $private_domains .= unbound_add_domain_overrides(true);
133
    }
134
135
    // Configure static Host entries
136 8fccab67 Warren Baker
    unbound_add_host_entries();
137 f20afeb6 Warren Baker
138
    // Configure Domain Overrides
139 8fccab67 Warren Baker
    unbound_add_domain_overrides();
140 f20afeb6 Warren Baker
141
    // Configure Unbound statistics
142
    $statistics = unbound_statistics();
143
144 8fccab67 Warren Baker
    // Configure Unbound access-lists
145
    unbound_acls_config();
146
147 f20afeb6 Warren Baker
    // Add custom Unbound options
148
    if ($config['unbound']['custom_options']) {
149
        $custom_option = "# Unbound custom option";
150
        foreach (preg_split('/\s+/', $config['unbound']['custom_options']) as $ent)
151
            $custom_option .= $ent."\n";
152
    }
153
154 56a87b19 Warren Baker
    // Server configuration variables
155
    $hide_id = ($config['unbound']['hide_id'] == "on") ? "yes" : "no";
156
    $hide_version = ($config['unbound']['hide_version'] == "on") ? "yes" : "no";
157
    $harden_glue = ($config['unbound']['harden_glue'] == "on") ? "yes" : "no";
158
    $harden_dnssec_stripped = ($config['unbound']['harden_dnssec_stripped'] == "on") ? "yes" : "no";
159
    $prefetch = ($config['unbound']['prefetch'] == "on") ? "yes" : "no";
160
    $prefetch_key = ($config['unbound']['prefetch_key'] == "on") ? "yes" : "no";
161
    $outgoing_num_tcp = (!empty($config['unbound']['outgoing_num_tcp'])) ? $config['unbound']['outgoing_num_tcp'] : "10";
162
    $incoming_num_tcp = (!empty($config['unbound']['incoming_num_tcp'])) ? $config['unbound']['incoming_num_tcp'] : "10";
163
    $edns_buffer_size = (!empty($config['unbound']['edns_buffer_size'])) ? $config['unbound']['edns_buffer_size'] : "4096";
164
    $num_queries_per_thread = (!empty($config['unbound']['num_queries_per_thread'])) ? $config['unbound']['num_queries_per_thread'] : "4096";
165
    $jostle_timeout = (!empty($config['unbound']['jostle_timeout'])) ? $config['unbound']['jostle_timeout'] : "200";
166
    $cache_max_ttl = (!empty($config['unbound']['cache_max_ttl'])) ? $config['unbound']['cache_max_ttl'] : "86400";
167
    $cache_min_ttl = (!empty($config['unbound']['cache_min_ttl'])) ? $config['unbound']['cache_min_ttl'] : "0";
168
    $infra_host_ttl = (!empty($config['unbound']['infra_host_ttl'])) ? $config['unbound']['infra_host_ttl'] : "900";
169
    $infra_lame_ttl = (!empty($config['unbound']['infra_lame_ttl'])) ? $config['unbound']['infra_lame_ttl'] : "900";
170
    $infra_cache_numhosts = (!empty($config['unbound']['infra_cache_numhosts'])) ? $config['unbound']['infra_cache_numhosts'] : "10000";
171
    $unwanted_reply_threshold = (!empty($config['unbound']['unwanted_reply_threshold'])) ? $config['unbound']['unwanted_reply_threshold'] : "0";
172
    $verbosity = isset($config['unbound']['loglevel']) ? $config['unbound']['loglevel'] : 1;
173
174 f20afeb6 Warren Baker
    $unboundconf = <<<EOD
175
##########################
176
# Unbound Configuration
177
##########################
178
179
##
180
# Server configuration
181
##
182
server:
183
chroot: {$g['unbound_chroot_path']}
184
username: "unbound"
185 56a87b19 Warren Baker
directory: "{$g['unbound_chroot_path']}"
186 f20afeb6 Warren Baker
pidfile: "/var/run/unbound.pid"
187
use-syslog: yes
188
port: 53
189 56a87b19 Warren Baker
verbosity: {$verbosity}
190 f20afeb6 Warren Baker
harden-referral-path: no
191
do-ip4: yes
192
do-ip6: yes
193
do-udp: yes
194
do-tcp: yes
195
do-daemonize: yes
196
module-config: "{$module_config}"
197
unwanted-reply-threshold: 0
198
num-queries-per-thread: 1024
199
jostle-timeout: 200
200
infra-host-ttl: 900
201
infra-lame-ttl: 900
202
infra-cache-numhosts: 10000
203
outgoing-num-tcp: 10
204
incoming-num-tcp: 10
205
edns-buffer-size: 4096
206 56a87b19 Warren Baker
cache-max-ttl: {$cache_max_ttl}
207
cache-min-ttl: {$cache_min_ttl}
208 f20afeb6 Warren Baker
harden-dnssec-stripped: yes
209
{$optimization['number_threads']}
210
{$optimization['msg_cache_slabs']}
211
{$optimization['rrset_cache_slabs']}
212
{$optimization['infra_cache_slabs']}
213
{$optimization['key_cache_slabs']}
214
{$optimization['msg_cache_size']}
215
{$optimization['rrset_cache_size']}
216
{$optimization['outgoing_range']}
217
{$optimization['so_rcvbuf']}
218
{$anchor_file}
219 56a87b19 Warren Baker
prefetch: {$prefetch}
220
prefetch-key: {$prefetch_key}
221 f20afeb6 Warren Baker
# Statistics
222
{$statistics}
223
# Interface IP(s) to bind to
224
interface: 0.0.0.0
225
interface: ::0
226
227
# DNS Rebinding
228
{$private_addr}
229
{$private_domains}
230
231
# Static host entries
232 56a87b19 Warren Baker
include: {$g['unbound_chroot_path']}/host_entries.conf
233 f20afeb6 Warren Baker
234
# Domain overrides
235 56a87b19 Warren Baker
include: {$g['unbound_chroot_path']}/domainoverrides.conf
236 f20afeb6 Warren Baker
237
{$custom_options}
238
239
###
240
# Remote Control Config
241
###
242 56a87b19 Warren Baker
include: {$g['unbound_chroot_path']}/remotecontrol.conf
243 f20afeb6 Warren Baker
244
EOD;
245
246 56a87b19 Warren Baker
    file_put_contents("{$g['unbound_chroot_path']}/unbound.conf", $unboundconf);
247 f20afeb6 Warren Baker
248
    return 0;
249
}
250
251
function unbound_remote_control_setup() {
252
    global $g;
253
254 56a87b19 Warren Baker
    if (!file_exists("{$g['unbound_chroot_path']}/remotecontrol.conf") || !file_exists("{$g['unbound_chroot_path']}/unbound_control.key")) {
255 f20afeb6 Warren Baker
        $remotcfg = <<<EOF
256
remote-control:
257
    control-enable: yes
258
    control-interface: 127.0.0.1
259
    control-port: 953
260
    server-key-file: "{$g['unbound_chroot_path']}/unbound_server.key"
261
    server-cert-file: "{$g['unbound_chroot_path']}/unbound_server.pem"
262
    control-key-file: "{$g['unbound_chroot_path']}/unbound_control.key"
263
    control-cert-file: "{$g['unbound_chroot_path']}/unbound_control.pem"
264 56a87b19 Warren Baker
265 f20afeb6 Warren Baker
EOF;
266
267
        file_put_contents("{$g['unbound_chroot_path']}/remotecontrol.conf", $remotcfg);
268
269 56a87b19 Warren Baker
        // Generate our keys
270
        do_as_unbound_user("unbound-control-setup");
271 f20afeb6 Warren Baker
272 56a87b19 Warren Baker
    }
273
}
274 f20afeb6 Warren Baker
275
276 56a87b19 Warren Baker
// Read /etc/hosts
277 f20afeb6 Warren Baker
function read_hosts() {
278
279
    /* Open /etc/hosts and extract the only dhcpleases info
280
     * XXX - to convert to an unbound C library which reads /etc/hosts automatically
281
     */
282
    $etc_hosts = array();
283
    foreach (file('/etc/hosts') as $line) {
284
        $d = preg_split('/\s/', $line, -1, PREG_SPLIT_NO_EMPTY);
285
        if (empty($d) || substr(reset($d), 0, 1) == "#")
286
            continue;
287
        if ($d[3] == "#") {
288
            $ip = array_shift($d);
289
            $fqdn = array_shift($d);
290
            $name = array_shift($d);
291
            if ($fqdn != "empty") {
292
                if ($name != "empty")
293
                    array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn", name => "$name"));
294
                else
295
                    array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn"));
296
            }
297
        }
298
    }
299
    return $etc_hosts;
300
}
301
302
function sync_unbound_service() {
303
    global $config, $g;
304
305
    // Configure chroot
306
    if (!is_dir($g['unbound_chroot_path'])) {
307
        mkdir($g['unbound_chroot_path']);
308
        chown($g['unbound_chroot_path'], "unbound");
309
        chgrp($g['unbound_chroot_path'], "unbound");
310
    }
311
312
    // Configure our Unbound service
313
    do_as_unbound_user("unbound-anchor");
314
    unbound_remote_control_setup();
315 56a87b19 Warren Baker
    unbound_generate_config();
316
    do_as_unbound_user("start");
317
    require_once("service-utils.inc");
318
    if (is_service_running("unbound")) {
319
        do_as_unbound_user("forward");
320
        do_as_unbound_user("restore_cache");
321
    }
322 f20afeb6 Warren Baker
323
}
324
325
function unbound_acl_id_used($id) {
326
    global $config;
327
328 8fccab67 Warren Baker
    if (is_array($config['unbound']['acls']))
329
        foreach($config['unbound']['acls'] as & $acls)
330 f20afeb6 Warren Baker
            if ($id == $acls['aclid'])
331
                return true;
332
333
    return false;
334
}
335
336
function unbound_get_next_id() {
337
    $aclid = 0;
338
    while(unbound_acl_id_used($aclid))
339
        $aclid++;
340
    return $aclid;
341
}
342
343
// Execute commands as the user unbound
344
function do_as_unbound_user($cmd) {
345
    global $g;
346
347
    switch ($cmd) {
348 56a87b19 Warren Baker
        case "start":
349 327a4fc6 Warren Baker
            mwexec("/usr/sbin/unbound -c{$g['unbound_chroot_path']}/unbound.conf");
350 56a87b19 Warren Baker
            break;
351
        case "stop":
352
            mwexec("echo '/usr/sbin/unbound-control stop' | /usr/bin/su -m unbound", true);
353
            break;
354 f20afeb6 Warren Baker
        case "unbound-anchor":
355
            mwexec("echo '/usr/sbin/unbound-anchor -a {$g['unbound_chroot_path']}/root.key' | /usr/bin/su -m unbound", true);
356
            break;
357
        case "unbound-control-setup":
358 56a87b19 Warren Baker
            mwexec("echo '/usr/sbin/unbound-control-setup -d {$g['unbound_chroot_path']}' | /usr/bin/su -m unbound", true);
359 f20afeb6 Warren Baker
            break;
360
        default:
361
            break;
362
    }
363
}
364
365
function unbound_add_domain_overrides($pvt=false) {
366
    global $config, $g;
367
368
    $domains = $config['unbound']['domainoverrides'];
369
370
    $sorted_domains = msort($domains, "domain");
371
    $result = array();      
372
    foreach($sorted_domains as $domain) {
373
        $domain_key = current($domain);
374
        if (!isset($result[$domain_key]))
375
            $result[$domain_key] = array();
376
        $result[$domain_key][] = $domain['ip'];
377
    }
378
379
    // Domain overrides that have multiple entries need multiple stub-addr: added
380
    $domain_entries = "";
381
    foreach($result as $domain=>$ips) {
382
        if ($pvt == true) {
383
            $domain_entries .= "private-domain: \"$domain\"\n";
384
            $domain_entries .= "domain-insecure: \"$domain\"\n";
385
        } else {
386
            $domain_entries .= "stub-zone:\n";
387
            $domain_entries .= "\tname: \"$domain\"\n";
388
            foreach($ips as $ip)
389
                $domain_entries .= "\tstub-addr: $ip\n";
390
            $domain_entries .= "\tstub-prime: no\n";
391
        }
392
    }
393
    
394
    if ($pvt == true)
395
        return $domain_entries;
396
    else
397
        file_put_contents("{$g['unbound_chroot_path']}/domainoverrides.conf", $domain_entries);
398
}
399
400
function unbound_add_host_entries() {
401
    global $config, $g;
402
403 56a87b19 Warren Baker
    $unbound_entries = "local-zone: \"{$config['system']['domain']}\" transparent\n";
404 f20afeb6 Warren Baker
    // IPv4 entries
405 56a87b19 Warren Baker
    $unbound_entries .= "local-data-ptr: \"127.0.0.1 localhost\"\n";
406
    $unbound_entries .= "local-data: \"localhost A 127.0.0.1\"\n";
407
    $unbound_entries .= "local-data: \"localhost.{$config['system']['domain']} A 127.0.0.1\"\n";
408 f20afeb6 Warren Baker
    // IPv6 entries
409 56a87b19 Warren Baker
    $unbound_entries .= "local-data-ptr: \"::1 localhost\"\n";
410
    $unbound_entries .= "local-data: \"localhost AAAA ::1\"\n";
411
    $unbound_entries .= "local-data: \"localhost.{$config['system']['domain']} AAAA ::1\"\n";
412 f20afeb6 Warren Baker
413
    $listen_addresses = "";
414
    if (isset($config['unbound']['interface'])) {
415
        $interfaces = explode(",", $config['unbound']['interface']);
416
        foreach ($interfaces as $interface) {
417
            if (is_ipaddrv4($interface)) {
418 56a87b19 Warren Baker
                $unbound_entries .= "local-data-ptr: \"{$interface} {$config['system']['hostname']}.{$config['system']['domain']}\"\n";
419 f20afeb6 Warren Baker
                $unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$config['system']['domain']} A {$interface}\"\n";
420
                $unbound_entries .= "local-data: \"{$config['system']['hostname']} A {$interface}\"\n";
421
            } else if (is_ipaddrv6($interface)) {
422
                $unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$config['system']['domain']} AAAA {$interface}\"\n";
423
                $unbound_entries .= "local-data: \"{$config['system']['hostname']} AAAA {$interface}\"\n";
424
            } else {
425
                $if = get_real_interface($interface);
426
                if (does_interface_exist($if)) {
427
                    $laddr = find_interface_ip($if);
428
                    if (is_ipaddrv4($laddr)) {
429 56a87b19 Warren Baker
                        $unbound_entries .= "local-data-ptr: \"{$laddr} {$config['system']['hostname']}.{$config['system']['domain']}\"\n";
430 f20afeb6 Warren Baker
                        $unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$config['system']['domain']} A {$laddr}\"\n";
431
                        $unbound_entries .= "local-data: \"{$config['system']['hostname']} A {$laddr}\"\n";
432
                    }
433
                    $laddr6 = find_interface_ipv6($if);
434
                    if (is_ipaddrv6($laddr6) && !isset($config['dnsmasq']['strictbind'])) {
435 56a87b19 Warren Baker
                        $unbound_entries .= "local-data-ptr: \"{$laddr6} {$config['system']['hostname']}.{$config['system']['domain']}\"\n";
436 f20afeb6 Warren Baker
                        $unbound_entries .= "local-data: \"{$config['system']['hostname']}.{$config['system']['domain']} AAAA {$laddr}\"\n";
437
                        $unbound_entries .= "local-data: \"{$config['system']['hostname']} AAAA {$laddr}\"\n";
438
                    }
439
                }
440
            }
441
        }
442
    }
443
444
    // Static Host entries
445
    if (isset($config['unbound']['hosts'])) {
446
        $host_entries = "";
447
        $added_item = array();
448
        foreach($config['unbound']['hosts'] as $host) {
449
            $current_host = $host['host'];
450
            if ($host['host'] != "")
451
                $host['host'] = $host['host'].".";
452
            if (!$added_item[$current_host]) {
453
                $host_entries .= "local-data-ptr: \"{$host['ip']} {$host['host']}{$host['domain']}\"\n";
454
                if (is_ipaddrv6($host['ip']))
455
                    $host_entries .= "local-data: \"{$host['host']}{$host['domain']} IN AAAA {$host['ip']}\"\n";
456
                else
457
                    $host_entries .= "local-data: \"{$host['host']}{$host['domain']} IN A {$host['ip']}\"\n";
458
                if (!empty($host['descr']) && $dnscfg['txtsupport'] == 'on')
459
                    $host_entries .= "local-data: '{$host['host']}{$host['domain']} TXT \"".addslashes($host['descr'])."\"'\n";
460
461
                // Do not add duplicate entries
462
                $added_item[$current_host] = true;
463
            }
464
        }
465
        $unbound_entries .= $host_entries;
466
    }
467
468
    // Static DHCP entries
469
    $host_entries = "";
470
    if (isset($config['unbound']['regdhcpstatic']) && is_array($config['dhcpd'])) {
471
        foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf)
472
            if (is_array($dhcpifconf['staticmap']) && isset($dhcpifconf['enable']))
473
                foreach ($dhcpifconf['staticmap'] as $host)
474
                    if ($host['ipaddr'] && $host['hostname']) {
475
                        $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['hostname']}.{$config['system']['domain']}\"\n";
476
                        $host_entries .= "local-data: \"{$host['hostname']}.{$config['system']['domain']} IN A {$host['ipaddr']}\"\n";
477
                        if (!empty($host['descr']) && $unboundcfg['txtsupport'] == 'on')
478
                            $host_entries .= "local-data: '{$host['hostname']}.{$config['system']['domain']} TXT \"".addslashes($host['descr'])."\"'\n";
479
                    }
480
        $unbound_entries .= $host_entries;
481
    }
482
483
    // Handle DHCPLeases added host entries
484
    $dhcplcfg = read_hosts();
485
    $host_entries = "";
486
    if (is_array($dhcplcfg)) {
487
        foreach($dhcplcfg as $key=>$host) {
488
            $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n";
489
            $host_entries .= "local-data: \"{$host['fqdn']} IN A {$host['ipaddr']}\"\n";
490
            if (!empty($host['name'])) {
491
                $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['name']}\"\n";
492
                $host_entries .= "local-data: \"{$host['name']} IN A {$host['ipaddr']}\"\n";
493
            }
494
        }
495
        $unbound_entries .= $host_entries;
496
    }
497
498
    // Write out entries
499
    file_put_contents("{$g['unbound_chroot_path']}/host_entries.conf", $unbound_entries);
500
}
501
502 56a87b19 Warren Baker
function unbound_control($action) {
503
    global $config, $g;
504
505
    $cache_dumpfile = "/var/tmp/unbound_cache";
506
507
    switch ($action) {
508
        case "forward":
509
            if ($config['unbound']['forwarding_mode'] == "on") {
510
               // Get configured DNS servers and add them as forwarders
511
                if (!isset($config['system']['dnsallowoverride'])) {
512
                    $ns = array_unique(get_nameservers());
513
                    foreach($ns as $nameserver) {
514
                        if($nameserver)
515
                            $dns_servers .= " $nameserver";
516
                    }
517
                } else {
518
                    $ns = array_unique(get_dns_servers());
519
                    foreach($ns as $nameserver) {
520
                        if($nameserver)
521
                            $dns_servers .= " $nameserver";
522
                    }
523
                }
524
525
                if(is_service_running("unbound")) {
526
                    unbound_ctl_exec("forward $dns_servers");
527
                } else {
528
                    unbound_control("start");
529
                    sleep(1);
530
                    unbound_control("forward");
531
                }
532
            }
533
            break;
534
        case "start":
535
            // Start Unbound
536
            if ($config['unbound']['enable'] == "on") {
537
                if (!is_service_running("unbound"))
538
                    do_as_unbound_user("start");
539
            }
540
            break;
541
        case "stop":
542
            if ($config['unbound']['enable'] == "on")
543
                do_as_unbound_user("stop");
544
            break;
545
        case "dump_cache":
546
            // Dump Unbound's Cache
547
            if ($config['unbound']['dumpcache'] == "on")
548
                do_as_unbound_user("dump_cache");
549
            break;
550
        case "restore_cache":
551
            // Restore Unbound's Cache
552
            if ((is_service_running("unbound")) && ($config['unbound']['dumpcache'] == "on")) {
553
                if (file_exists($cache_dumpfile) && filesize($cache_dumpfile) > 0)
554
                    do_as_unbound_user("load_cache < /var/tmp/unbound_cache");
555
            }
556
            break;
557
        default:
558
                break;
559
560
        }
561
}
562
563
// Generation of Unbound statistics
564
function unbound_statistics() {
565
    global $config;
566
567
    if ($config['stats'] == "on") {
568
        $stats_interval = $config['unbound']['stats_interval'];
569
        $cumulative_stats = $config['cumulative_stats'];
570
        if ($config['extended_stats'] == "on")
571
            $extended_stats = "yes";
572
        else
573
            $extended_stats = "no";
574
    } else {
575
        $stats_interval = "0";
576
        $cumulative_stats = "no";
577
        $extended_stats = "no";
578
    }
579
    /* XXX To do - add RRD graphs */
580
    $stats = <<<EOF
581
# Unbound Statistics
582
statistics-interval: {$stats_interval}
583
extended-statistics: yes
584
statistics-cumulative: yes
585
586
EOF;
587
588
    return $stats;
589
}
590
591 8fccab67 Warren Baker
// Unbound Access lists
592
function unbound_acls_config() {
593
    global $config;
594
595
    // Configure the ACLs
596
    if (is_array($config['unbound']['acls'])) {
597
        $unboundcfg = "";
598
        foreach($config['unbound']['acls'] as $unbound_acl) {
599
            $unboundcfg .= "#{$unbound_acl['aclname']}\n";
600
            foreach($unbound_acl['row'] as $network) {
601
                if ($unbound_acl['aclaction'] == "allow snoop")
602
                    $unbound_acl['aclaction'] = "allow_snoop";
603
                $unboundcfg .= "access-control: {$network['acl_network']}/{$network['mask']} {$unbound_acl['aclaction']}\n";
604
            }
605
        }
606
        // Write out Access list
607
        file_put_contents("{$g['unbound_chroot_path']}/access_lists.conf", $unboundcfg);
608
    } else
609
        return;
610
}
611
612 f20afeb6 Warren Baker
?>