Unbound: Add files to enable forward link to dnsmasq
authorEric Luehrsen <ericluehrsen@hotmail.com>
Fri, 28 Oct 2016 02:03:00 +0000 (22:03 -0400)
committerEric Luehrsen <ericluehrsen@hotmail.com>
Wed, 30 Nov 2016 01:49:46 +0000 (20:49 -0500)
-dnsmasq really provides nice local DHCP-DNS records
-Unbound host records would be clumsy to update
-Unbound can be configured to forward to dnsmasq
-iptools provided to facilitate PTR records
-flexible ipv6 colon notation is a bit complex

Signed-off-by: Eric Luehrsen <ericluehrsen@hotmail.com>
net/unbound/files/dnsmasq.sh [new file with mode: 0644]
net/unbound/files/iptools.sh [new file with mode: 0644]

diff --git a/net/unbound/files/dnsmasq.sh b/net/unbound/files/dnsmasq.sh
new file mode 100644 (file)
index 0000000..f9eec7d
--- /dev/null
@@ -0,0 +1,182 @@
+#!/bin/sh
+##############################################################################
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Copyright (C) 2016 Eric Luehrsen
+#
+##############################################################################
+#
+# This crosses over to the dnsmasq UCI file "dhcp" and parses it for fields
+# that will allow Unbound to request local host DNS of dnsmasq. We need to look
+# at the interfaces in "dhcp" and get their subnets. The Unbound conf syntax
+# makes this a little difficult. First in "server:" we need to create private
+# zones for the domain and PTR records. Then we need to create numerous
+# "forward:" clauses to forward those zones to dnsmasq.
+#
+##############################################################################
+
+create_local_zone() {
+  local cfg="$1"
+  local fwd_port fwd_domain
+
+  config_get fwd_domain "$cfg" domain
+  config_get fwd_port   "$cfg" port
+
+
+  if [ -n "$fwd_domain" -a -n "$fwd_port" -a ! "$fwd_port" -eq 53 ] ; then
+    # dnsmasq localhost listening ports (possible multiple instances)
+    UNBOUND_N_FWD_PORTS="$UNBOUND_N_FWD_PORTS $fwd_port"
+    UNBOUND_TXT_FWD_ZONE="$UNBOUND_TXT_FWD_ZONE $fwd_domain"
+
+    {
+      # This creates DOMAIN local privledges
+      echo "  private-domain: \"$fwd_domain\""
+      echo "  local-zone: \"$fwd_domain.\" transparent"
+      echo "  domain-insecure: \"$fwd_domain\""
+      echo
+    } >> $UNBOUND_CONFFILE
+  fi
+}
+
+##############################################################################
+
+create_local_arpa() {
+  local cfg="$1"
+  local logint dhcpv4 dhcpv6 ignore
+  local subnets subnets4 subnets6
+  local forward arpa
+  local validip4 validip6 privateip
+
+  config_get logint "$cfg" interface
+  config_get dhcpv4 "$cfg" dhcpv4
+  config_get dhcpv6 "$cfg" dhcpv6
+  config_get_bool ignore "$cfg" ignore 0
+
+  # Find the list of addresses assigned to a logical interface
+  # Its typical to have a logical gateway split NAME and NAME6
+  network_get_subnets  subnets4 "$logint"
+  network_get_subnets6 subnets6 "$logint"
+  subnets="$subnets4 $subnets6"
+
+  network_get_subnets  subnets4 "${logint}6"
+  network_get_subnets6 subnets6 "${logint}6"
+  subnets="$subnets $subnets4 $subnets6"
+
+
+  if [ -z "$subnets" ] ; then
+    forward=""
+
+  elif [ -z "$UNBOUND_N_FWD_PORTS" ] ; then
+    forward=""
+
+  elif [ "$ignore" -gt 0 ] ; then
+    if [ "$UNBOUND_B_GATE_NAME" -gt 0 ] ; then
+      # Only forward the one gateway host.
+      forward="host"
+
+    else
+      forward=""
+    fi
+
+  else
+    # Forward the entire private subnet.
+    forward="domain"
+  fi
+
+
+  if [ -n "$forward" ] ; then
+    for subnet in $subnets ; do
+      validip4=$( valid_subnet4 $subnet )
+      validip6=$( valid_subnet6 $subnet )
+      privateip=$( private_subnet $subnet )
+
+
+      if [ "$validip4" = "ok" -a "$dhcpv4" != "disable" ] ; then
+        if [ "$forward" = "domain" ] ; then
+          arpa=$( domain_ptr_ip4 "$subnet" )
+        else
+          arpa=$( host_ptr_ip4 "$subnet" )
+        fi
+
+      elif [ "$validip6" = "ok" -a "$dhcpv6" != "disable" ] ; then
+        if [ "$forward" = "domain" ] ; then
+          arpa=$( domain_ptr_ip6 "$subnet" )
+        else
+          arpa=$( host_ptr_ip6 "$subnet" )
+        fi
+
+      else
+        arpa=""
+      fi
+
+
+      if [ -n "$arpa" ] ; then
+        if [ "$privateip" = "ok" ] ; then
+          {
+            # This creates ARPA local zone privledges
+            echo "  local-zone: \"$arpa.\" transparent"
+            echo "  domain-insecure: \"$arpa\""
+            echo
+          } >> $UNBOUND_CONFFILE
+        fi
+
+
+        UNBOUND_TXT_FWD_ZONE="$UNBOUND_TXT_FWD_ZONE $arpa"
+      fi
+    done
+  fi
+}
+
+##############################################################################
+
+forward_local_zone() {
+  if [ -n "$UNBOUND_N_FWD_PORTS" -a -n "$UNBOUND_TXT_FWD_ZONE" ] ; then
+    for fwd_domain in $UNBOUND_TXT_FWD_ZONE ; do
+      {
+        # This is derived of create_local_zone/arpa
+        # but forward: clauses need to be seperate
+        echo "forward-zone:"
+        echo "  name: \"$fwd_domain.\""
+
+        for port in $UNBOUND_N_FWD_PORTS ; do
+          echo "  forward-addr: 127.0.0.1@$port"
+        done
+
+        echo
+      } >> $UNBOUND_CONFFILE
+    done
+  fi
+}
+
+##############################################################################
+
+dnsmasq_link() {
+  ####################
+  # UCI @ dhcp       #
+  ####################
+
+
+  if [ "$UNBOUND_B_DNSMASQ" -gt 0 ] ; then
+    # Forward to dnsmasq on same host for DHCP lease hosts
+    echo "  do-not-query-localhost: no" >> $UNBOUND_CONFFILE
+    # Look at dnsmasq settings
+    config_load dhcp
+    # Zone for DHCP / SLAAC-PING DOMAIN
+    config_foreach create_local_zone dnsmasq
+    # Zone for DHCP / SLAAC-PING ARPA
+    config_foreach create_local_arpa dhcp
+    # Now create ALL seperate forward: clauses
+    forward_local_zone
+  fi
+}
+
+##############################################################################
+
diff --git a/net/unbound/files/iptools.sh b/net/unbound/files/iptools.sh
new file mode 100644 (file)
index 0000000..1725242
--- /dev/null
@@ -0,0 +1,140 @@
+#!/bin/sh
+##############################################################################
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# Copyright (C) 2016 Eric Luehrsen
+#
+##############################################################################
+#
+# These are iptools that might be useful in a larger package, if provided
+# elsewhere for common use. One example that many may find useful is turning
+# flexible IPV6 colon dividers into PTR. Otherwise these are incomplete and
+# would need robustness improvements for more generic applications.
+#
+##############################################################################
+
+domain_ptr_ip6() {
+  # Get the nibble rounded /CIDR ...ip6.arpa.
+  echo "$1" | awk -F: \
+  'BEGIN { OFS = "" ; }
+  { CIDR = $0 ;
+  sub(/.*\//,"",CIDR) ;
+  CIDR = (CIDR / 4) ;
+  sub(/\/[0-9]+/,"",$0) ;
+  ct_stop = 9 - NF ;
+  for(i=1; i<=NF; i++) {
+    if(length($i) == 0) {
+      for(j=1; j<=ct_stop; j++) { $i = ($i "0000") ; } }
+    else { $i = substr(("0000" $i), length($i)+5-4) ; } } ;
+  y = $0 ;
+  ct_start = length(y) - 32 + CIDR ;
+  for(i=ct_start; i>0; i--) { x = (x substr(y,i,1)) ; } ;
+  gsub(/./,"&\.",x) ;
+  x = (x "ip6.arpa") ;
+  print x }'
+}
+
+##############################################################################
+
+host_ptr_ip6() {
+  # Get complete host ...ip6.arpa.
+  echo "$1" | awk -F: \
+  'BEGIN { OFS = "" ; }
+  { sub(/\/[0-9]+/,"",$0) ;
+  ct_stop = 9 - NF ;
+  for(i=1; i<=NF; i++) {
+    if(length($i) == 0) {
+      for(j=1; j<=ct_stop; j++) { $i = ($i "0000") ; } }
+    else { $i = substr(("0000" $i), length($i)+5-4) ; } } ;
+  y = $0 ;
+  ct_start = length(y);
+  for(i=ct_start; i>0; i--) { x = (x substr(y,i,1)) ; } ;
+  sub(/[0-9]+\//,"",x) ;
+  gsub(/./,"&\.",x) ;
+  x = (x "ip6.arpa") ;
+  print x }'
+}
+
+##############################################################################
+
+domain_ptr_ip4() {
+  # Get the byte rounded /CIDR ...in-addr.arpa.
+  echo "$1" | awk \
+  '{ CIDR = $0 ;
+  sub(/.*\//,"",CIDR) ;
+  CIDR = (CIDR / 8) ;
+  dtxt = $0 ;
+  sub(/\/.*/,"",dtxt) ;
+  split(dtxt, dtxt, ".") ;
+  for(i=1; i<=CIDR; i++) { x = (dtxt[i] "." x) ; }
+  x = (x "in-addr.arpa") ;
+  print x }'
+}
+
+##############################################################################
+
+host_ptr_ip4() {
+  # Get omplete host ...in-addr.arpa.
+  echo "$1" | awk -F. \
+  '{ x = ( $4"."$3"."$2"."$1".in-addr.arpa" ) ;
+  sub(/\/[0-9]+/,"",x) ;
+  print x }'
+}
+
+##############################################################################
+
+valid_subnet6() {
+  case "$1" in
+    # GA
+    [1-9][0-9a-f][0-9a-f][0-9a-f]":"*) echo "ok" ;;
+    # ULA
+    f[cd][0-9a-f][0-9a-f]":"*) echo "ok" ;;
+    # fe80::, ::1, and such
+    *) echo "not" ;;
+  esac
+}
+
+##############################################################################
+
+valid_subnet4() {
+  case "$1" in
+    # Link, Local, and Such
+    169"."254"."*) echo "not" ;;
+    127"."*) echo "not" ;;
+    0"."*) echo "not" ;;
+    255"."*) echo "not" ;;
+    # Other Normal
+    25[0-4]"."[0-9]*) echo "ok" ;;
+    2[0-4][0-9]"."[0-9]*) echo "ok" ;;
+    1[0-9][0-9]"."[0-9]*) echo "ok" ;;
+    [0-9][0-9]"."[0-9]*) echo "ok" ;;
+    [0-9]"."[0-9]*) echo "ok" ;;
+    # Not Right
+    *) echo "not";;
+  esac
+}
+
+##############################################################################
+
+private_subnet() {
+  case "$1" in
+    10"."*) echo "ok" ;;
+    172"."1[6-9]"."*) echo "ok" ;;
+    172"."2[0-9]"."*) echo "ok" ;;
+    172"."3[0-1]"."*) echo "ok" ;;
+    192"."168"."*) echo "ok" ;;
+    f[cd][0-9a-f][0-9a-f]":"*) echo "ok" ;;
+    *) echo "not" ;;
+  esac
+}
+
+##############################################################################
+