Added a script for managing rDNS zones (in-addr.arpa) in cPanel. Can be modified for standard BIND9 setups
This commit is contained in:
parent
647c881b79
commit
4987b8c300
|
@ -0,0 +1,285 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
#rdns.sh - script for dealing with rDNS.
|
||||
#Report any bugs to matthew.connelly@simplexwebs.com
|
||||
|
||||
#TODO
|
||||
#Add more _BIN variables to decrease reliance on $PATH
|
||||
#IPv6 support
|
||||
#Finish domain validation function
|
||||
#RDNS_QUERY_SERVER round-robin?
|
||||
|
||||
#variables
|
||||
PROVIDERNAME=""
|
||||
DEFAULT_RDNS="hosted-by.$PROVIDERNAME."
|
||||
ZONE_LOCATION="/var/named/"
|
||||
ZONE_TAIL="in-addr.arpa"
|
||||
ZONE_FTAIL=".db"
|
||||
SYNC_SCRIPT="/scripts/dnscluster synczone"
|
||||
RDNS_QUERY_SERVER="8.8.4.4"
|
||||
DIG_BIN="$(command -v dig)"
|
||||
if [ $? -ne 0 -o -z "$DIG_BIN" ]; then
|
||||
echo "Failed to locate 'dig'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#functions
|
||||
function usage () {
|
||||
# Usage function. Obvious.
|
||||
echo "$0 - Usage
|
||||
$0 ip.address : Show current rDNS for the given IP address.
|
||||
$0 ip.address dns.address : Set given IP address's rDNS to the given DNS address.
|
||||
$0 -v ip.address dns.address : Set given IP's rDNS, and verify it after syncing.
|
||||
$0 -r ip.address : Reset given IP's rDNS to the default ($DEFAULT_RDNS).
|
||||
$0 -R ip.address : Remove the given IP's rDNS entry altogether.
|
||||
$0 [-h] : Show this help text."
|
||||
}
|
||||
|
||||
function validateIP () {
|
||||
#validateIP - validates a given IP to ensure it isn't invalid.
|
||||
local IP=$1
|
||||
local stat=1
|
||||
#Regex to do basic IP validation.
|
||||
if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
OIFS=$IFS
|
||||
IFS="."
|
||||
IP=($IP)
|
||||
IFS=$OIFS
|
||||
if [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]; then
|
||||
stat=0
|
||||
else
|
||||
stat=1
|
||||
fi
|
||||
fi
|
||||
return $stat
|
||||
}
|
||||
|
||||
function convertIPToDNSZone () {
|
||||
#Converts a given IP to an in-addr.arpa zone (ie, convertIPToDNSZone 192.210.132.5 would return "132.210.192.in-addr.arpa."
|
||||
OIFS=$IFS
|
||||
set `IFS=".";echo $1`
|
||||
IFS=$OIFS
|
||||
echo $3.$2.$1.$ZONE_TAIL
|
||||
}
|
||||
|
||||
function getLastOctet () {
|
||||
#Gets the last octet of an IP. Since all our IP ranges are /24s, this is okay.
|
||||
OIFS=$IFS
|
||||
set `IFS=".";echo $1`
|
||||
IFS=$OIFS
|
||||
echo $4
|
||||
}
|
||||
|
||||
function validateDomain () {
|
||||
#Validate a given domain to ensure it's a real domain.
|
||||
#This will be implemented later. For now, just please make sure the PTR value is valid.
|
||||
return 0
|
||||
}
|
||||
|
||||
function setRDNS () {
|
||||
#Modify the rDNS record for the given IP.
|
||||
TARGET_IP=$1
|
||||
NEW_PTR=$2
|
||||
ZONEFILE=$(convertIPToDNSZone $TARGET_IP)
|
||||
RECORD=$(getLastOctet $TARGET_IP)
|
||||
if [ ! -w "$ZONE_LOCATION$ZONEFILE$ZONE_FTAIL" ]; then
|
||||
echo "Failed to locate: $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL"
|
||||
return 1
|
||||
fi
|
||||
CUR_REC=$(getRDNS $TARGET_IP)
|
||||
if [ $? -ne 0 ]; then
|
||||
#we create the record
|
||||
APPENDREC="$RECORD 14400 IN PTR $DEFAULT_RDNS"
|
||||
#This is disabled for now. We warn, but do not touch.
|
||||
echo "$APPENDREC" >> $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL
|
||||
echo "Warning: Record for $TARGET_IP, new record has been created."
|
||||
CUR_REC=$(getRDNS $TARGET_IP)
|
||||
fi
|
||||
#I would use sed for this, but for some reason I can't get match groups to work in sed.
|
||||
perl -pi.bak -e "s/^($RECORD\s+.*)\s$CUR_REC/\1\t$NEW_PTR/" $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL
|
||||
return 0
|
||||
}
|
||||
|
||||
function getRDNS () {
|
||||
#Retrieve the current rDNS record (if any) for the given IP
|
||||
ZONEFILE=$(convertIPToDNSZone $1)
|
||||
RECORD=$(getLastOctet $1)
|
||||
if [ ! -w "$ZONE_LOCATION$ZONEFILE$ZONE_FTAIL" ]; then
|
||||
echo "Failed to locate: $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL"
|
||||
return 1
|
||||
fi
|
||||
ZRECORD=$(egrep "^$RECORD\s.*PTR" $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "ZONEFILE: $ZONEFILE$ZONE_FTAIL ; LAST OCTET: $RECORD"
|
||||
return 1
|
||||
fi
|
||||
echo $ZRECORD|perl -pe 's/^.*PTR\s+//'
|
||||
return 0
|
||||
}
|
||||
|
||||
function removeRDNS () {
|
||||
TARGET_IP=$1
|
||||
ZONEFILE=$(convertIPToDNSZone $TARGET_IP)
|
||||
RECORD=$(getLastOctet $TARGET_IP)
|
||||
CUR_PTR="$(getRDNS $TARGET_IP)"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "rDNS entry doesn't exist for $TARGET_IP!"
|
||||
return 1
|
||||
fi
|
||||
perl -pi.bak -e "s/^($RECORD\s+.*\n)//" $ZONE_LOCATION$ZONEFILE$ZONE_FTAIL
|
||||
}
|
||||
|
||||
function verifyRDNS () {
|
||||
#Check that the rDNS was actually set, using 'host'.
|
||||
HOSTOUT=$($DIG_BIN @$RDNS_QUERY_SERVER +short -x $1|sed 's/^[\s ]+//'|sed 's/[\s ]+$//')
|
||||
if [ "$HOSTOUT" != "$2" ]; then
|
||||
echo $HOSTOUT
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function checkForwardDNS () {
|
||||
#Verify that forward DNS is set properly, using 'dig'. This specifically requests an A record, we won't need to worry about AAAA records for a while.
|
||||
DIGOUT="$($DIG_BIN @$RDNS_QUERY_SERVER +short $1 A)"
|
||||
if [ "$DIGOUT" != "$2" ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#main script
|
||||
MODE=""
|
||||
GOPTS=""
|
||||
IPADDR=""
|
||||
DESTDNS=""
|
||||
ZONE_FILE=""
|
||||
DO_SYNC=0
|
||||
|
||||
#Get options and arguments. I do this old school because I'm too lazy to l2getopts
|
||||
if [ "$1" == "-h" -o "$1" == "-r" -o "$1" == "-v" -o "$1" == "-R" ]; then
|
||||
GOPTS="$1"
|
||||
IPADDR="$2"
|
||||
DESTDNS="$3"
|
||||
else
|
||||
IPADDR="$1"
|
||||
DESTDNS="$2"
|
||||
fi
|
||||
#First, we ensure that DESTDNS ends with a period.
|
||||
#We make sure the new PTR value ends with a period.
|
||||
if [ ! -z "$DESTDNS" ]; then
|
||||
TAILREC="$(echo $DESTDNS|tail -c2)"
|
||||
if [ "$TAILREC" != "." ]; then
|
||||
DESTDNS="$DESTDNS."
|
||||
fi
|
||||
fi
|
||||
#First we get usage out of the way. Usage is shown if there are no options, or if the only option given is -h, or if $IPADDR is empty.
|
||||
if [ -z "$IPADDR" -o "$GOPTS" == "-h" ]; then
|
||||
usage
|
||||
exit
|
||||
fi
|
||||
|
||||
#Then we validate input. $IPADDR should -always- be an IP address, and $DESTDNS should always be a valid DNS address that exists.
|
||||
validateIP $IPADDR
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: IP address given ($IPADDR) was not valid."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
#Now we can be sure the IP address given exists. Get our "mode" and then start working.
|
||||
case $GOPTS in
|
||||
-r)
|
||||
MODE="RESET"
|
||||
;;
|
||||
-v) MODE="SETANDVALIDATE"
|
||||
;;
|
||||
-R)
|
||||
MODE="REMOVE"
|
||||
;;
|
||||
*)
|
||||
if [ ! -z "$DESTDNS" ]; then
|
||||
MODE="SET"
|
||||
elif [ ! -z "$IPADDR" ]; then
|
||||
MODE="GET"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
#We do the work.
|
||||
case $MODE in
|
||||
RESET)
|
||||
setRDNS $IPADDR $DEFAULT_RDNS
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to set rDNS!"
|
||||
exit 1
|
||||
fi
|
||||
echo "rDNS set!"
|
||||
DO_SYNC=1
|
||||
;;
|
||||
GET)
|
||||
RDNS=$(getRDNS $IPADDR)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to get rDNS for '$IPADDR'! Message: $RDNS"
|
||||
exit 1
|
||||
fi
|
||||
echo "rDNS for '$IPADDR': $RDNS"
|
||||
;;
|
||||
SET)
|
||||
checkForwardDNS $DESTDNS $IPADDR
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Forward DNS does not match requested reverse!"
|
||||
exit 1
|
||||
fi
|
||||
setRDNS $IPADDR $DESTDNS
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to set rDNS!"
|
||||
exit 1
|
||||
fi
|
||||
echo "rDNS set!"
|
||||
DO_SYNC=1
|
||||
;;
|
||||
SETANDVALIDATE)
|
||||
checkForwardDNS $DESTDNS $IPADDR
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Forward DNS does not match requested reverse!"
|
||||
exit 1
|
||||
fi
|
||||
setRDNS $IPADDR $DESTDNS
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to set rDNS!"
|
||||
exit 1
|
||||
fi
|
||||
echo "rDNS set!"
|
||||
DO_SYNC=1
|
||||
;;
|
||||
REMOVE)
|
||||
removeRDNS $IPADDR
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to remove rDNS record!"
|
||||
exit 1
|
||||
fi
|
||||
echo "rDNS record removed!"
|
||||
DO_SYNC=1
|
||||
;;
|
||||
*)
|
||||
echo "Clearly, you used this script incorrectly."
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ $DO_SYNC -eq 1 ]; then
|
||||
$SYNC_SCRIPT $(convertIPToDNSZone $IPADDR)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Sync failed!"
|
||||
fi
|
||||
if [ "$MODE" == "SETANDVALIDATE" ]; then
|
||||
sleep 5
|
||||
FORWARDDNS=$(verifyRDNS $IPADDR $DESTDNS)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Current rDNS for $IPADDR ($FORWARDDNS) does not match '$DESTDNS'!"
|
||||
else
|
||||
echo "rDNS was properly synchronised and is set to '$DESTDNS'."
|
||||
fi
|
||||
fi
|
||||
fi
|
Loading…
Reference in New Issue