#!/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
0 B
|👍
/👎