1) $unbound_config['active_interface'] = "lan"; else $unbound_config['active_interface'] = "wan"; unbound_anchor_setup(); unbound_resync_config(); unbound_keys_setup(); exec("/usr/sbin/chown -R unbound:wheel /usr/local/etc/unbound/*"); // Write out the XML config write_config(); // Back to read-only conf_mount_ro(); } function unbound_anchor_setup() { $conf = << ENDPHP\n"; $stop = "/usr/local/bin/php -q -d auto_prepend_file=config.inc < ENDPHP\n"; write_rcfile(array( "file" => $filename, "start" => $start, "stop" => $stop ) ); } function unbound_install() { conf_mount_rw(); unbound_initial_setup(); conf_mount_ro(); } function unbound_control($action) { global $config, $g; $unbound_config = $config['installedpackages']['unbound']['config'][0]; switch ($action) { case "forward": /* Dont utilize forward cmd if Unbound is doing DNS queries directly * XXX: We could make this an option to then make pfSense use Unbound * as the recursive nameserver instead of upstream ones(?) */ if ($unbound_config['forwarding_mode'] == "on") { // Get configured DNS servers and add them as forwarders if (!isset($config['system']['dnsallowoverride'])) { $ns = array_unique(get_nameservers()); foreach($ns as $nameserver) { if($nameserver) $dns_servers .= " $nameserver"; } } else { $ns = array_unique(get_dns_servers()); foreach($ns as $nameserver) { if($nameserver) $dns_servers .= " $nameserver"; } } if(is_service_running("unbound")) { unbound_ctl_exec("forward $dns_servers"); } else { unbound_control("start"); unbound_control("forward"); } } break; case "start": //Start unbound if($unbound_config['unbound_status'] == "on") { unbound_ctl_exec("start"); fetch_root_hints(); sleep(1); } break; case "stop": //Stop unbound and unmount the file system if($unbound_config['unbound_status'] == "on") { unbound_ctl_exec("stop"); } break; case "termstop": //Stop Unbound by sigkillbypid(); sigkillbypid("{$g['varrun_path']}/unbound.pid", "TERM"); break; default: break; } } function unbound_get_network_interface_addresses($subnet=false, $mask=false) { global $config; /* calculate interface ip + subnet information */ $interfaces = explode(",", $config['installedpackages']['unbound']['config'][0]['active_interface']); $unbound_interfaces = array(); foreach ($interfaces as $unboundidx => $unboundif) { $unboundrealif = convert_friendly_interface_to_real_interface_name($unboundif); $unboundip = find_interface_ip($unboundrealif); $ipmask = find_interface_subnet($unboundrealif); // If $subnet is passed then calculate the beginning of the network range for the IP address if ($subnet) $network = gen_subnet($unboundip, $ipmask); else $network = $unboundip; if ($mask) $unbound_interfaces[] = "$network/$ipmask"; else { $unbound_interfaces[] = $network; // Check for CARP addresses and also return those if (isset($config['virtualip'])) { if(is_array($config['virtualip']['vip'])) { foreach($config['virtualip']['vip'] as $vip) { if (($vip['interface'] == $unboundif) && ($vip['mode'] == "carp")) { $virtual_ip = find_interface_ip(link_ip_to_carp_interface($vip['subnet'])); $unbound_interfaces[] = $virtual_ip; } } } } } } return $unbound_interfaces; } function unbound_resync_config() { global $config, $g; if (!array($config['installedpackages']['unbound']['config'])) $config['installedpackages']['unbound']['config'] = array(); $unbound_config = &$config['installedpackages']['unbound']['config'][0]; $interfaces = unbound_get_network_interface_addresses(true, true); foreach($interfaces as $allowed_network) { $unbound_allowed_networks .= "access-control: $allowed_network allow\n"; } if($unbound_config['dnssec_status'] == "on") { $module_config = "validator iterator"; $anchor_file = "auto-trust-anchor-file: /usr/local/etc/unbound/root-trust-anchor"; } else { $module_config = "iterator"; } // Interfaces to bind to $interface_ips = unbound_get_network_interface_addresses(); foreach($interface_ips as $ifip) { $unbound_bind_interfaces .="interface: $ifip\n"; } /* Harden DNSSec responses - if DNSSec is absent, zone is marked as bogus * XXX: for now we always have this set to yes */ $unbound_config['harden-dnssec-stripped'] = "yes"; // Host entries $host_entries = unbound_add_host_entries(); // Domain Overrides $domain_overrides = unbound_add_domain_overrides(); // Unbound Statistics if($unbound_config['stats'] == "on") { $stats_interval = $unbound_config['stats_interval']; $cumulative_stats = $unbound_config['cumulative_stats']; if ($unbound_config['extended_stats'] == "on") $extended_stats = "yes"; else $extended_stats = "no"; } else { $stats_interval = "0"; $cumulative_stats = "no"; $extended_stats = "no"; } // Private-address support for DNS Rebinding if($unbound_config['private_address'] == "on") { $pvt_addr = << 0) $number_threads = "num-threads: {$numprocs}"; else $number_threads = "num-threads: 1"; $unbound_conf = << "$ip", fqdn => "$fqdn", name => "$name")); else array_push($etc_hosts, array(ipaddr => "$ip", fqdn => "$fqdn")); } } } return $etc_hosts; } /* Setup /etc/hosts entries by overriding with local-data */ function unbound_add_host_entries() { global $config; /* XXX: break this out into a separate config file and make use of include */ $unboundcfg = $config['installedpackages']['unbound']['config'][0]; $syscfg = $config['system']; $dnsmasqcfg = $config['dnsmasq']; $unbound_entries = "local-zone: \"{$syscfg['domain']}\" transparent\n"; // IPv4 entries $unbound_entries .= "local-data-ptr: \"127.0.0.1 localhost\"\n"; $unbound_entries .= "local-data: \"localhost A 127.0.0.1\"\n"; $unbound_entries .= "local-data: \"localhost.{$syscfg['domain']} A 127.0.0.1\"\n"; if ($config['interfaces']['lan']) { $cfgip = get_interface_ip("lan"); if (is_ipaddr($cfgip)) { $unbound_entries .= "local-data-ptr: \"{$cfgip} {$syscfg['hostname']}.{$syscfg['domain']}\"\n"; $unbound_entries .= "local-data: \"{$syscfg['hostname']}.{$syscfg['domain']} A {$cfgip}\"\n"; $unbound_entries .= "local-data: \"{$syscfg['hostname']} A {$cfgip}\"\n"; } } else { $sysiflist = get_configured_interface_list(); foreach ($sysiflist as $sysif) { if (!interface_has_gateway($sysif)) { $cfgip = get_interface_ip($sysif); if (is_ipaddr($cfgip)) { $unbound_entries .= "local-data-ptr: \"{$cfgip} {$syscfg['hostname']}.{$syscfg['domain']}\"\n"; $unbound_entries .= "local-data: \"{$syscfg['hostname']}.{$syscfg['domain']} A {$cfgip}\"\n"; $unbound_entries .= "local-data: \"{$syscfg['hostname']} A {$cfgip}\"\n"; break; } } } } // DNSMasq entries static host entries if (isset($dnsmasqcfg['hosts'])) { $hosts = $dnsmasqcfg['hosts']; $host_entries = ""; $added_item = array(); foreach ($hosts as $host) { $current_host = $host['host']; if(!$added_item[$current_host]) { $host_entries .= "local-data-ptr: \"{$host['ip']} {$host['host']}.{$host['domain']}\"\n"; $host_entries .= "local-data: \"{$host['host']}.{$host['domain']} IN A {$host['ip']}\"\n"; if (!empty($host['descr'])) $host_entries .= "local-data: '{$host['host']}.{$host['domain']} TXT \"".addslashes($host['descr'])."\"'\n"; // Do not add duplicate entries $added_item[$current_host] = true; } } $unbound_entries .= $host_entries; } // Static DHCP entries $host_entries = ""; if (isset($unboundcfg['regdhcpstatic']) && is_array($config['dhcpd'])) { foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) if(is_array($dhcpifconf['staticmap']) && isset($dhcpifconf['enable'])) foreach ($dhcpifconf['staticmap'] as $host) if ($host['ipaddr'] && $host['hostname']) { $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['hostname']}.{$syscfg['domain']}\"\n"; $host_entries .= "local-data: \"{$host['hostname']}.{$syscfg['domain']} IN A {$host['ipaddr']}\"\n"; if (!empty($host['descr'])) $host_entries .= "local-data: '{$host['hostname']}.{$syscfg['domain']} TXT \"".addslashes($host['descr'])."\"'\n"; } $unbound_entries .= $host_entries; } // Handle DHCPLeases added host entries $dhcplcfg = read_hosts(); $host_entries = ""; if(is_array($dhcplcfg)) { foreach($dhcplcfg as $key=>$host) { $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['fqdn']}\"\n"; $host_entries .= "local-data: \"{$host['fqdn']} IN A {$host['ipaddr']}\"\n"; if (!empty($host['name'])) { $host_entries .= "local-data-ptr: \"{$host['ipaddr']} {$host['name']}\"\n"; $host_entries .= "local-data: \"{$host['name']} IN A {$host['ipaddr']}\"\n"; } } $unbound_entries .= $host_entries; } return $unbound_entries; } /* Setup any domain overrides that have been configured with stub-zone parameter */ function unbound_add_domain_overrides($pvt=false) { global $config; if (isset($config['dnsmasq']['domainoverrides'])) { $domains = $config['dnsmasq']['domainoverrides']; // Domain overrides that have multiple entries need multiple stub-addr: added $sorted_domains = msort($domains, "domain"); $result = array(); foreach($sorted_domains as $domain) { $domain_key = current($domain); if(!isset($result[$domain_key])) { $result[$domain_key] = array(); } $result[$domain_key][] = $domain['ip']; } $domain_entries = ""; foreach($result as $domain=>$ips) { if($pvt == true) { $domain_entries .= "private-domain: \"$domain\"\n"; } else { $domain_entries .= "stub-zone:\n"; $domain_entries .= "\tname: \"$domain\"\n"; foreach($ips as $ip) { $domain_entries .= "\tstub-addr: $ip\n"; } $domain_entries .= "\tstub-prime: no\n"; } } return $domain_entries; } } ?>