aboutsummaryrefslogtreecommitdiffstats
path: root/config/unbound/unbound.inc
diff options
context:
space:
mode:
authorWarren Baker <warren@decoy.co.za>2010-11-16 22:13:42 +0200
committerWarren Baker <warren@decoy.co.za>2010-11-16 22:13:42 +0200
commit6abd1181c88bcae7524203a8fd5fdb95f58173a3 (patch)
tree8e27d2f737e9222fb3fde365f855612c89d7f0cc /config/unbound/unbound.inc
parent117b7641cbaa8540368e1a0f2c8b5ac519681d90 (diff)
downloadpfsense-packages-6abd1181c88bcae7524203a8fd5fdb95f58173a3.tar.gz
pfsense-packages-6abd1181c88bcae7524203a8fd5fdb95f58173a3.tar.bz2
pfsense-packages-6abd1181c88bcae7524203a8fd5fdb95f58173a3.zip
Initial commit of the Unbound package (that 1 day will replace dnsmasq). It is currently limited in configuration options but it does what DNSMasq does excluding the DNS rebind check. Need to investigate that.
Diffstat (limited to 'config/unbound/unbound.inc')
-rw-r--r--config/unbound/unbound.inc415
1 files changed, 415 insertions, 0 deletions
diff --git a/config/unbound/unbound.inc b/config/unbound/unbound.inc
new file mode 100644
index 00000000..dd7d3024
--- /dev/null
+++ b/config/unbound/unbound.inc
@@ -0,0 +1,415 @@
+<?php
+/* unbound.inc
+ (C)2010 Warren Baker
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+if(!function_exists("get_dns_servers"))
+ require_once("pfsense-utils.inc");
+
+if(!function_exists("get_nameservers"))
+ require_once("system.inc");
+
+function unbound_initial_setup() {
+ global $config;
+
+ if (!array($config['installedpackages']['unbound']['config']))
+ $config['installedpackages']['unbound']['config'] = array();
+
+ $unbound_config = &$config['installedpackages']['unbound']['config'][0];
+
+ // Setup unbound
+ mwexec("/bin/mkdir -p /usr/local/etc/unbound /usr/local/etc/unbound/dev");
+ touch("/usr/local/etc/unbound/root.hints");
+ touch("/usr/local/etc/unbound/root-trust-anchor");
+ chown("/usr/local/etc/unbound/root-trust-anchor", "unbound");
+ chgrp("/usr/local/etc/unbound/root-trust-anchor", "wheel");
+ chmod("/usr/local/etc/unbound/root-trust-anchor", 0600);
+ unlink("/usr/local/etc/unbound/unbound.conf.sample");
+ unlink("/usr/local/etc/rc.d/unbound");
+
+ // Setup rc file for startup and shutdown.
+ unbound_rc_setup();
+
+ // Disable DNSMasq and enable UNBound
+ $unbound_config['unbound_status'] = "on";
+
+ // Set initial interfaces that are allowed to query to lan, if that does not exist set it to the wan
+ if(count($config['interfaces']) > 1)
+ $unbound_config['active_interface'] = "lan";
+ else
+ $unbound_config['active_interface'] = "wan";
+
+ unbound_anchor_setup();
+ unbound_resync_config();
+ unbound_keys_setup();
+
+ // Write out the XML config
+ write_config();
+
+}
+
+function unbound_anchor_setup() {
+
+ $conf = <<<EOD
+. IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
+EOD;
+
+ file_put_contents("/usr/local/etc/unbound/root-trust-anchor", $conf);
+
+}
+
+function unbound_keys_setup() {
+
+ // Generate SSL Keys for controlling the unbound server
+ mwexec("/usr/local/sbin/unbound-control-setup");
+
+}
+
+function unbound_rc_setup() {
+ global $config;
+
+
+ // Startup process and idea taken from TinyDNS package (author sullrich@gmail.com)
+ $filename = "unbound.sh";
+ $start = "/usr/local/bin/php -q -d auto_prepend_file=config.inc <<ENDPHP
+<?php
+ require_once(\"/usr/local/pkg/unbound.inc\");
+ echo \"Starting and configuring Unbound...\";
+ fetch_root_hints();
+ unbound_control(\"start\");
+ unbound_control(\"forward\");
+ echo \"done.\\n\";
+?>
+ENDPHP\n";
+
+$stop = "/usr/local/bin/php -q -d auto_prepend_file=config.inc <<ENDPHP
+<?php
+ require_once(\"/usr/local/pkg/unbound.inc\");
+ echo \"Stopping Unbound...\";
+ unbound_control(\"termstop\");
+ echo \"done.\\n\";
+?>
+
+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");
+ unbound_ctl_exec("reload");
+ } 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";
+ }
+ 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";
+
+ // Syslog logging
+ $unbound_config['use-syslog'] = "yes";
+
+ // Host entries
+ $host_entries = unbound_add_host_entries();
+
+ // Domain Overrides
+ $domain_overrides = unbound_add_domain_overrides();
+
+ $unbound_conf = <<<EOD
+# Unbound configuration
+
+server:
+ verbosity: 1
+ port: 53
+ do-ip4: yes
+ do-ip6: no
+ do-udp: yes
+ do-tcp: yes
+ do-daemonize: yes
+ statistics-interval: 300
+ extended-statistics: yes
+ statistics-cumulative: no
+ {$unbound_bind_interfaces}
+ chroot: ""
+ username: "unbound"
+ directory: "/usr/local/etc/unbound"
+ pidfile: "/var/run/unbound.pid"
+ root-hints: "root.hints"
+ harden-dnssec-stripped: {$unbound_config['harden-dnssec-stripped']}
+ harden-referral-path: no
+ private-address: 10.0.0.0/8
+ private-address: 172.16.0.0/12
+ private-address: 192.168.0.0/16
+ prefetch: yes
+ prefetch-key: yes
+ use-syslog: {$unbound_config['use-syslog']}
+ module-config: "{$module_config}"
+ unwanted-reply-threshold: 10000000
+ {$anchor_file}
+ access-control: 127.0.0.0/8 allow
+ {$unbound_allowed_networks}
+ {$host_entries}
+ {$domain_overrides}
+
+remote-control:
+ control-enable: yes
+ control-interface: 127.0.0.1
+ control-port: 953
+ server-key-file: "/usr/local/etc/unbound/unbound_server.key"
+ server-cert-file: "/usr/local/etc/unbound/unbound_server.pem"
+ control-key-file: "/usr/local/etc/unbound/unbound_control.key"
+ control-cert-file: "/usr/local/etc/unbound/unbound_control.pem"
+
+EOD;
+
+ file_put_contents("/usr/local/etc/unbound/unbound.conf", $unbound_conf);
+
+}
+
+function unbound_ctl_exec($cmd) {
+
+ mwexec("/usr/local/sbin/unbound-control $cmd");
+
+}
+
+function fetch_root_hints() {
+
+ $destination_file = "/usr/local/etc/unbound/root.hints";
+ if (filesize($destination_file) == 0 ) {
+ $fout = fopen($destination_file, "w");
+ $url = "ftp://ftp.internic.net/domain/named.cache";
+
+ $ch = curl_init();
+ curl_setopt($ch, CURLOPT_URL, $url);
+ curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, '5');
+ $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $data = curl_exec($ch);
+ curl_close($ch);
+
+ fwrite($fout, $data);
+ fclose($fout);
+
+ return ($http_code == 200) ? true : $http_code;
+ } else {
+ return false;
+ }
+}
+
+function unbound_reconfigure() {
+ global $config,$g;
+
+ $unbound_config = $config['installedpackages']['unbound']['config'][0];
+
+ if ($unbound_config['unbound_status'] != "on") {
+ if(is_service_running("unbound")) {
+ unbound_control("termstop");
+ }
+ } else {
+ if(isset($config['dnsmasq']['enable'])) {
+ unset($config['dnsmasq']['enable']);
+ sigkillbypid("{$g['varrun_path']}/dnsmasq.pid", "TERM");
+ }
+ if(is_service_running("unbound")) {
+ unbound_control("termstop");
+ }
+ unbound_resync_config();
+ unbound_control("start");
+ unbound_control("forward");
+ }
+
+}
+
+function unbound_uninstall() {
+ global $g, $config;
+
+ conf_mount_rw();
+
+ unbound_control("termstop");
+ // Remove pkg config directory and startup file
+ mwexec("rm -rf /usr/local/etc/unbound");
+ mwexec("rm -f /usr/local/etc/rc.d/unbound.sh");
+
+ conf_mount_ro();
+
+}
+
+/* Setup /etc/hosts entries by overriding with local-data
+ */
+function unbound_add_host_entries() {
+ global $config;
+
+ if (isset($config['dnsmasq']['hosts'])) {
+ $hosts = $config['dnsmasq']['hosts'];
+ $host_entries = "";
+
+ foreach ($hosts as $host) {
+ $host_entries .= "local-data: '{$host['host']}.{$host['domain']}. IN A {$host['ip']}'\n";
+ $host_entries .= "\tlocal-data: '{$host['host']}.{$host['domain']}. TXT \"{$host['descr']}\"'\n";
+ }
+ return $host_entries;
+ }
+}
+
+/* Setup any domain overrides that have been configured with local-zone
+ */
+function unbound_add_domain_overrides() {
+ global $config;
+
+ if (isset($config['dnsmasq']['domainoverrides'])) {
+ $domains = $config['dnsmasq']['domainoverrides'];
+ $domain_entries = "";
+
+ foreach($domains as $domain) {
+ $domain_entries .= "local-zone: '{$domain['domain']}.' redirect\n";
+ $domain_entries .= "\tlocal-data: '{$domain['domain']}. A {$domain['ip']}'\n";
+ $domain_entries .= "\tlocal-data: '{$domain['domain']}. TXT \"{$domain['descr']}\"'\n";
+
+ }
+ return $domain_entries;
+ }
+}
+
+?> \ No newline at end of file