allan icon

DHCPd: dns-krbnsupdate.sh

allan | PRO | 10/20/18 05:57:42 PM UTC | 0 ⭐ | 448 👁️ | Never ⏰ | []
Bash |

8.42 KB

|

None

|

0 👍

/

0 👎

#!/bin/bash
 
# This script is for secure DDNS updates using GSS/TSIG
# Version: 0.1
#
# Cloned from https://pastebin.com/wmWuXqdE on 10/20/2018
 
## CONFIGURATION ##
# Kerberos realm
REALM="EXAMPLE.COM"
# Kerberos principal
PRINCIPAL="dns-update@${REALM}"
# Kerberos keytab
KEYTAB="/etc/krb5.dhcpd.keytab"
# Kerberos credentials cache
KRB5CC="/var/run/isc-dhcpd/dhcpd.krb5cc"
# Use MIT kerberos args instead of heimdal.
#KRB5MIT="YES"
 
# Domain appended to hostname
DOMAIN="example.com"
# Space separated list of DNS servers for sending updates to
NSRVS="ns1.example.com ns2.example.com"
# Default DNS resource records TTL
RRTTL="3600"
# Do not use TXT RRs (rfc4701)
NOTXTRRS="YES"
# Default to IPv4
PROTO="IPv4"
 
# Additional nsupdate flags (-g already applied), e.g. "-d" for debug
#NSUPDFLAGS="-d"
# Run in the foreground (for manual run only!!!), it's better to use "-d" as script's first argument
#DEBUG="YES"
 
######################################################
 
_usage() {
  if [ "${NOTXTRRS}" == "YES" ]
  then
    echo "Usage:"
    echo "`basename ${0}` add ip-address -h hostname [-m dhcid|mac-address] [-p IP version | --ipv4 | --ipv6] [-t dns-ttl] [-d]"
    echo "`basename ${0}` delete ip-address [-m dhcid|mac-address] [-p IP version | --ipv4 | --ipv6]"
  else
    echo "Usage:"
    echo "`basename ${0}` add ip-address -h hostname -m dhcid|mac-address [-p IP version | --ipv4 | --ipv6] [-t dns-ttl] [-d]"
    echo "`basename ${0}` delete ip-address -m dhcid|mac-address [-p IP version | --ipv4 | --ipv6]"
  fi
}
 
## VARIABLES ##
ACTION=${1}
IP=${2}
shift && shift
while [ ! -z ${1} ]
do
  case "${1}" in
    "-d")
      DEBUG="YES"
      shift
    ;;
    "-m")
      DHCID=${2}
      shift && shift
    ;;
    "-h")
      NAME=${2%%.*}
      shift && shift
    ;;
    "-t")
      RRTTL="${2}"
      shift && shift
    ;;
    "-p")
      PROTO=${2}
      shift && shift
    ;;
    "--ipv4")
      PROTO="IPv4"
      shift
    ;;
    "--ipv6")
      PROTO="IPv6"
      shift
    ;;
    "--help")
      _usage
      exit 0
    ;;
    *)
      echo "Unknown option: ${1}"
      _usage
      exit 1
  esac
done
 
_kerberos() {
  export KRB5_KTNAME="${KEYTAB}"
  export KRB5CCNAME="${KRB5CC}"
 
  if [ "${KRB5MIT}" = "YES" ]; then
    KLISTARG="-s"
  else
    KLISTARG="-t"
  fi
 
  klist ${KLISTARG} || kinit -k -t "${KEYTAB}" -c "${KRB5CC}" "${PRINCIPAL}" || { echo "DDNS: kinit failed"; exit 1; }
}
 
_expandv6() {
# Adapted from https://github.com/mutax/IPv6-Address-checks by
# Florian Streibelt <[email protected]>
  local __revipv6=${2}
  local INPUT="${1}"
  local O=""
 
  while [ "${O}" != "${INPUT}" ]; do
    O="${INPUT}"
 
    # fill all words with zeroes
    INPUT="$( sed  's|:\([0-9a-f]\{3\}\):|:0\1:|g' <<< "${INPUT}" )"
    INPUT="$( sed  's|:\([0-9a-f]\{3\}\)$|:0\1|g'  <<< "${INPUT}")"
    INPUT="$( sed  's|^\([0-9a-f]\{3\}\):|0\1:|g'  <<< "${INPUT}" )"
 
    INPUT="$( sed  's|:\([0-9a-f]\{2\}\):|:00\1:|g' <<< "${INPUT}")"
    INPUT="$( sed  's|:\([0-9a-f]\{2\}\)$|:00\1|g'  <<< "${INPUT}")"
    INPUT="$( sed  's|^\([0-9a-f]\{2\}\):|00\1:|g'  <<< "${INPUT}")"
 
    INPUT="$( sed  's|:\([0-9a-f]\):|:000\1:|g'  <<< "${INPUT}")"
    INPUT="$( sed  's|:\([0-9a-f]\)$|:000\1|g'   <<< "${INPUT}")"
    INPUT="$( sed  's|^\([0-9a-f]\):|000\1:|g'   <<< "${INPUT}")"
  done
 
  # now expand the ::
  grep -qs "::" <<< "${INPUT}"
  if [ "$?" -eq 0 ]; then
    GRPS="$(sed  's|[0-9a-f]||g' <<< "${INPUT}" | wc -m)"
    ((GRPS--)) # carriage return
    ((MISSING=8-GRPS))
    for ((i=0;i<$MISSING;i++)); do
      ZEROES="$ZEROES:0000"
    done
 
    # be careful where to place the :
    INPUT="$( sed  's|\(.\)::\(.\)|\1'$ZEROES':\2|g'   <<< "${INPUT}")"
    INPUT="$( sed  's|\(.\)::$|\1'$ZEROES':0000|g'   <<< "${INPUT}")"
    INPUT="$( sed  's|^::\(.\)|'$ZEROES':0000:\1|g;s|^:||g'   <<< "${INPUT}")"
  fi
 
  # an expanded address has 39 chars + CR
  if [ $(echo ${INPUT} | wc -m) != 40 ]; then
    echo "Invalid IPv6 Address"
    exit 1
  fi
 
  LEN=${#INPUT}
  for ((i=LEN-1;i>=0;i--))
  do
    [ ${INPUT:i:1} != ":" ] && TMPSTR=${TMPSTR}"."${INPUT:i:1}
  done
  INPUT=${TMPSTR:1}".ip6.arpa"
 
  # echo the fully expanded version of the address
  eval ${__revipv6}="'${INPUT}'"
}
 
_main() {
  umask 77
 
  if [ -z "${IP}" ]
  then
    _usage
    exit 1
  fi
 
  if [ "${NOTXTRRS}" != "YES" ] && [ -z "${DHCID}" ]
  then
    _usage
    exit 1
  fi
 
  ## NSUPDATE ##
  case "${ACTION}" in
    add)
      if [ -z "${NAME}" ]
      then
        _usage
        exit 1
      fi
 
      RRPTR="${NAME}.${DOMAIN}"
      if [ "${NOTXTRRS}" != "YES" ]; then
        NOTXTRRS=""
        RRAOLD=`host ${RRPTR} | awk '/has address/ {print $4}'`
        if [ -n "${RRAOLD}" ]; then
          RRTXTOLD=`host -t txt "${RRPTR}" | sed -n '/descriptive text/s/^.*[[:space:]]descriptive text[[:space:]]*"\(.*\)"$/\1/p'`
          [ -z "${RRTXTOLD}" ] && echo "DDNS: adding records for $ip (${RRPTR}) FAILED: has A record but no DHCID, not mine" && exit 1
 
          RRTXT=`echo "${DHCID}${RRPTR}" | sha256sum`
          RRTXT="000101${RRTXT%% *}"
          [ "${RRTXT}" != "${RRTXTOLD}" ] && echo "DDNS: adding records for $ip (${RRPTR}) FAILED: has A record but DHCID is wrong" && exit 1
        else
          RRTXT=`echo "${DHCID}${RRPTR}" | sha256sum`
          RRTXT="000101${RRTXT%% *}"
        fi
      else
        NOTXTRRS=";"
      fi
 
      echo "${PROTO}!"
 
      case "${PROTO}" in
        "IPv4")
           RRPTRNAME=`echo ${IP} | awk -F '.' '{print $4"."$3"."$2"."$1".in-addr.arpa"}'`
           RECNAME="A"
        ;;
        "IPv6")
          _expandv6 ${IP} RRPTRNAME
          RECNAME="AAAA"
        ;;
        *)
          echo "Unknown IP version: ${PROTO}"
          exit 1
      esac
 
      _kerberos
 
      for NSRV in ${NSRVS}; do
        nsupdate -g ${NSUPDFLAGS} << UPDATE
server ${NSRV}
realm ${REALM}
update delete ${RRPTR}. ${RRTTL} ${RECNAME}
${NOTXTRRS}update delete ${RRPTR}. ${RRTTL} TXT
${NOTXTRRS}update add ${RRPTR}. ${RRTTL} TXT ${RRTXT}
update add ${RRPTR}. ${RRTTL} ${RECNAME} ${IP}
send
update delete ${RRPTRNAME}. ${RRTTL} PTR
update add ${RRPTRNAME}. ${RRTTL} PTR ${NAME}.${DOMAIN}.
send
UPDATE
 
        RESULT=${?}
        [ "${RESULT}" -eq "0" ] && echo "DDNS: adding records for ${IP} (${RRPTR}) succeeded" && exit 0
      done
 
      [ "${RESULT}" != "0" ] && echo "DDNS: adding records for ${IP} (${RRPTR}) FAILED: nsupdate status ${RESULT}" && exit "${RESULT}"
    ;;
    delete)
      RRPTR=`host ${IP} | awk '/domain name pointer/ { sub(/\.$/, "", $5); print $5}'`
      if [ "${NOTXTRRS}" != "YES" ]; then
        NOTXTRRS=""
        if [ -n "${RRPTR}" ]; then
          RRTXTOLD=`host -t txt "${RRPTR}" | sed -n '/descriptive text/s/^.*[[:space:]]descriptive text[[:space:]]*"\(.*\)"$/\1/p'`
          [ -z "${RRTXTOLD}" ] && echo "DDNS: removing records for $ip (${RRPTR}) FAILED: has A record but no DHCID, not mine" && exit 1
 
          RRTXT=`echo "${DHCID}${RRPTR}" | sha256sum`
          RRTXT="000101${RRTXT%% *}"
          [ "${RRTXT}" != "${RRTXTOLD}" ] && echo "DDNS: removing records for ${IP} (${RRPTR}) FAILED: has A record but DHCID is wrong" && exit 1
        else
          echo "DDNS: removing records for ${IP} FAILED: has no PTR, can not determine A record" && exit 1
        fi
      else
        NOTXTRRS=";"
      fi
 
      case "${PROTO}" in
        "IPv4")
           RRPTRNAME=`echo ${IP} | awk -F '.' '{print $4"."$3"."$2"."$1".in-addr.arpa"}'`
           RECNAME="A"
        ;;
        "IPv6")
          _expandv6 ${IP} RRPTRNAME
          RECNAME="AAAA"
        ;;
        *)
          echo "Unknown IP version: ${PROTO}"
          exit 1
      esac
 
      _kerberos
 
      for NSRV in ${NSRVS}; do
        nsupdate -g ${NSUPDFLAGS} << UPDATE
server ${NSRV}
realm ${REALM}
update delete ${RRPTR}. ${RRTTL} ${RECNAME}
${NOTXTRRS}update delete ${RRPTR}. ${RRTTL} TXT
send
update delete ${RRPTRNAME}. ${RRTTL} PTR
send
UPDATE
 
        RESULT=${?}
        [ "${RESULT}" -eq "0" ] && echo "DDNS: removing records for ${IP} (${RRPTR}) succeeded" && exit 0
      done
 
      [ "${RESULT}" != "0" ] && echo "DDNS: removing records for ${IP} (${RRPTR}) FAILED: nsupdate status ${RESULT}" && exit "${RESULT}"
    ;;
    *)
      _usage && exit 1
    ;;
esac
}
 
if [ "$DEBUG" = "YES" ]; then
  _main
else
  :
  _main | logger -s -t dhcpd &
fi

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎