diff --git a/net/unbound/files/odhcpd.awk b/net/unbound/files/odhcpd.awk new file mode 100644 index 000000000..6ef02dfbf --- /dev/null +++ b/net/unbound/files/odhcpd.awk @@ -0,0 +1,156 @@ +#!/usr/bin/awk +############################################################################## +# +# 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 +# +############################################################################## +# +# Turn DHCP records into meaningful A, AAAA, and PTR records. Also lift a +# function from dnsmasq and use DHCPv4 MAC to find IPV6 SLAAC hosts. +# +# External Parameters +# "hostfile" = where this script will cache host DNS data +# "domain" = text domain suffix +# "bslaac" = boolean, use DHCPv4 MAC to find GA and ULA IPV6 SLAAC +# "bisolt" = boolean, format ... so you can isolate +# +############################################################################## + +/^#/ { + # We need to pick out DHCP v4 or v6 records + net = $2 ; id = $3 ; cls = $4 ; hst = $5 ; adr = $9 ; + cdr = adr ; + sub( /\/.*/, "", adr ) ; + sub( /.*\//, "", cdr ) ; + + + if ( bisolt == 1 ) { + # TODO: this might be better with a substituion option, + # or per DHCP pool do-not-DNS option, but its getting busy here. + fqdn = net + fqdn = sub( /\./, "-", fqdn ) ; + fqdn = tolower( hst "." fqdn "." domain ) ; + } + + else { + fqdn = tolower( hst "." domain ) ; + } + + + if ( cls == "ipv4" ) { + if ( NF == 8 ) { + # odhcpd errata in field format without host name + adr = $8 ; hst = "-" ; cdr = adr ; + sub( /\/.*/, "", adr ) ; + sub( /.*\//, "", cdr ) ; + } + + + if (( cdr == 32 ) && ( hst != "-" )) { + # only for provided hostnames and full /32 assignments + ptr = adr ; qpr = "" ; split( ptr, ptr, "." ) ; + slaac = slaac_eui64( id ) ; + for( i=1; i<=4; i++ ) { qpr = ( ptr[i] "." qpr) ; } + + # DHCP A and PTR records with FQDN + x = ( fqdn ". 120 IN A " adr ) ; + y = ( qpr "in-addr.arpa. 120 IN PTR " fqdn ) ; + print ( x "\n" y ) > hostfile ; + + + if ((bslaac == 1) && (slaac != 0)) { + # UCI option to discover IPV6 routed SLAAC addresses + # NOT TODO - ping probe take too long when added in awk-rule loop + cmd = ( "ip -6 --oneline route show dev " net ) ; + + + while ( ( cmd | getline adr ) > 0 ) { + if ( substr( adr, 1, 5 ) <= "fd00:" ) { + # GA or ULA routed addresses only (not LL or MC) + sub( /\/.*/, "", adr ) ; + adr = ( adr slaac ) ; + if ( split( adr, tmp0, ":" ) >= 8 ) { sub( "::", ":", adr ) ; } + qpr = ipv6_ptr( adr ) ; + x = ( fqdn ". 120 IN AAAA " adr ) ; + y = ( qpr " 120 IN PTR " fqdn ) ; + print ( x "\n" y ) > hostfile ; + } + } + + + close( cmd ) ; + } + } + } + + else { + if (( cdr == 128 ) && ( hst != "-" )) { + # only for provided hostnames and full /128 assignments + qpr = ipv6_ptr( adr ) ; + x = ( fqdn ". 120 IN AAAA " adr ) ; + y = ( qpr " 120 IN PTR " fqdn ) ; + print ( x "\n" y ) > hostfile ; + } + } +} + +############################################################################## + +function ipv6_ptr( ipv6, arpa, ary, end, i, j, new6, sz, start ) { + # IPV6 colon flexibility is a challenge when creating [ptr].ip6.arpa. + sz = split( ipv6, ary, ":" ) ; end = 9 - sz ; + + + for( i=1; i<=sz; i++ ) { + if( length(ary[i]) == 0 ) { + for( j=1; j<=end; j++ ) { ary[i] = ( ary[i] "0000" ) ; } + } + + else { + ary[i] = substr( ( "0000" ary[i] ), length( ary[i] )+5-4 ) ; + } + } + + + new6 = ary[1] ; + for( i = 2; i <= sz; i++ ) { new6 = ( new6 ary[i] ) ; } + start = length( new6 ) ; + for( i=start; i>0; i-- ) { arpa = ( arpa substr( new6, i, 1 ) ) ; } ; + gsub( /./, "&\.", arpa ) ; arpa = ( arpa "ip6.arpa" ) ; + + return arpa ; +} + +############################################################################## + +function slaac_eui64( mac, ary, glbit, eui64 ) { + if ( length(mac) >= 12 ) { + # RFC2373 and use DHCPv4 registered MAC to find SLAAC addresses + split( mac , ary , "" ) ; + glbit = ( "0x" ary[2] ) ; + glbit = sprintf( "%d", glbit ) ; + glbit = or( glbit, 2 ) ; + ary[2] = sprintf( "%x", glbit ) ; + eui64 = ( ary[1] ary[2] ary[3] ary[4] ":" ary[5] ary[6] "ff:fe" ) ; + eui64 = ( eui64 ary[7] ary[8] ":" ary[9] ary[10] ary[11] ary[12] ) ; + } + + else { + eui64 = 0 ; + } + + + return eui64 ; +} + +############################################################################## + diff --git a/net/unbound/files/odhcpd.sh b/net/unbound/files/odhcpd.sh new file mode 100644 index 000000000..68c822af9 --- /dev/null +++ b/net/unbound/files/odhcpd.sh @@ -0,0 +1,92 @@ +#!/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 script facilitates alternate installation of Unbound+odhcpd and no +# need for dnsmasq. There are some limitations, but it works and is small. +# The lease file is parsed to make "zone-data:" and "local-data:" entries. +# +# config odhcpd 'odhcpd' +# option leasetrigger '/usr/lib/unbound/odhcpd.sh' +# +############################################################################## + +# Common file location definitions +. /usr/lib/unbound/unbound.sh + +############################################################################## + +odhcpd_settings() { + # This trigger is out of normal init context, so we need to read some UCI. + local cfg="$1" + config_get UNBOUND_D_DHCP_LINK "$cfg" dhcp_link none + config_get_bool UNBOUND_B_SLAAC6_MAC "$cfg" dhcp4_slaac6 0 +} + +############################################################################## + +odhcpd_zonedata() { + local dns_ls_add=$UNBOUND_VARDIR/dhcp_dns.add + local dns_ls_del=$UNBOUND_VARDIR/dhcp_dns.del + local dhcp_ls_new=$UNBOUND_VARDIR/dhcp_lease.new + local dhcp_ls_old=$UNBOUND_VARDIR/dhcp_lease.old + local dhcp_ls_add=$UNBOUND_VARDIR/dhcp_lease.add + local dhcp_ls_del=$UNBOUND_VARDIR/dhcp_lease.del + local dhcp_origin=$( uci get dhcp.@odhcpd[0].leasefile ) + + config_load unbound + config_foreach odhcpd_settings unbound + + + if [ "$UNBOUND_D_DHCP_LINK" = "odhcpd" -a -f "$dhcp_origin" ] ; then + # Capture the lease file which could be changing often, + # and unbound-control only for changes in hosts (or else...) + cat $dhcp_origin | sort > $dhcp_ls_new + touch $dhcp_ls_old + sort $dhcp_ls_new $dhcp_ls_old $dhcp_ls_old | uniq -u > $dhcp_ls_add + sort $dhcp_ls_old $dhcp_ls_new $dhcp_ls_new | uniq -u > $dhcp_ls_del + + # Go through the messy business of coding up A, AAAA, and PTR records. + awk -v hostfile=$dns_ls_del -v domain=$UNBOUND_TXT_DOMAIN \ + -v bslaac=$UNBOUND_B_SLAAC6_MAC -v bisolt=0 \ + -f /usr/lib/unbound/odhcpd.awk $dhcp_ls_del + + awk -v hostfile=$dns_ls_add -v domain=$UNBOUND_TXT_DOMAIN \ + -v bslaac=$UNBOUND_B_SLAAC6_MAC -v bisolt=0 \ + -f /usr/lib/unbound/odhcpd.awk $dhcp_ls_add + + + if [ -f "$dns_ls_del" ] ; then + cat $dns_ls_del | $UNBOUND_CONTROL_CFG local_datas_remove + fi + + + if [ -f "$dns_ls_add" ] ; then + cat $dns_ls_add | $UNBOUND_CONTROL_CFG local_datas + fi + + + # prepare next round + mv $dhcp_ls_new $dhcp_ls_old + rm -f $dns_ls_del $dns_ls_add + fi +} + +############################################################################## + +odhcpd_zonedata + +############################################################################## +