#!/bin/bash

# check_dns_replication - check DNS zone replication by comparing zone serials
#
# Version 1.0, latest version, documentation and bugtracker available at:
#               https://gitlab.lindenaar.net/scripts/nagios-plugins
#
# Copyright (c) 2021 Frederik Lindenaar
#
# This script is free software: you can redistribute and/or modify it under the
# terms of version 3 of the GNU General Public License as published by the Free
# Software Foundation, or (at your option) any later version of the license.
#
# This script 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.
#
# You should have received a copy of the GNU General Public License along with
# this program.  If not, visit <http://www.gnu.org/licenses/> to download it.

# Usage: check_dns_replication [-n] dns_zone[,dns_zone...] [dns_server...]

if [ "$#" -eq 0 -o "$1" == "-n" -a "$#" -eq 1 ]; then
    echo "DNSREPLICATION: UNKNOWN | missing parameter dns_zone"
    exit 3
elif [ "$1" == "-n" ]; then
    DNS_SERVER_LOOKUP=$1
    shift
elif [ $1 == '-h' -o $1 == '--help' ]; then
    cat << EOT
`basename $0` - check DNS zone replication by comparing SOA serial(s)

usage: $0 [-n] dns_zone[,dns_zone...] [dns_server...]

parameters:
    -n    when specified (or no dns_server provided) check domain's NS records
    -h    this help
    dns_zone[,dns_zone...]  list of DNS zones to check (comma separated!)
    [dns_server...]         DNS server(s) to compare with authoratative server

EOT
    exit 3
elif [[ "$1" = -* ]]; then
    echo "DNSREPLICATION: UNKNOWN | invalid parameter, for help run $0 -h"
    exit 3
fi

DNS_ZONES=${1//,/ }
shift
DNS_SERVERS=${*//,/ }

n="
"
NAGIOS_STATE=OK
NAGIOS_RESULT=0
NAGIOS_DETAILS=

for DNS_ZONE in $DNS_ZONES; do
  AUTH_NAMESERVER=$(host -t soa $DNS_ZONE ${DNS_SERVERS// .*/} | tail -1 | cut -d\  -f5 | sed "s/.$//")
  [ -n "$AUTH_NAMESERVER" ] && AUTH_SOA_SERIAL=$(host -t soa $DNS_ZONE $AUTH_NAMESERVER | tail -1 | cut -d\  -f7)
  if [ -z "$AUTH_SOA_SERIAL" ]; then
    NAGIOS_STATE=CRITICAL
    NAGIOS_RESULT=2
    NAGIOS_DETAILS="$NAGIOS_DETAILS$n$DNS_ZONE: unknown domain (unable to resolve)"
  else
    NAMESERVER_OK=
    NAMESERVER_HIGHER=
    NAMESERVER_LOWER=
    NAMESERVER_EMPTY=
    NAMESERVERS=$DNS_SERVERS
    if [ -z "$DNS_SERVERS" -o "$DNS_SERVER_LOOKUP" == '-n' -o "$DNS_SERVERS" == "$AUTH_NAMESERVER" ]; then
      NAMESERVERS="$NAMESERVERS $(host -t ns $DNS_ZONE $AUTH_NAMESERVER | fgrep -v : |  sed "s/.* //;s/\.$//")"
    fi
    NAMESERVERS=$(echo $NAMESERVERS | tr ' ' '\n' | sort -u)
    for NAMESERVER in $NAMESERVERS; do
      if [ "$NAMESERVER" != "$AUTH_NAMESERVER" ]; then
        SOA_SERIAL=$(host -t soa $DNS_ZONE $NAMESERVER | tail -1 | cut -d\  -f 7)
        if [ -z "$SOA_SERIAL" ]; then
          NAMESERVER_EMPTY="$NAMESERVER_EMPTY$NAMESERVER,"
        elif [ "$SOA_SERIAL" -lt "$AUTH_SOA_SERIAL" ]; then
          NAMESERVER_LOWER="$NAMESERVER_LOWER$NAMESERVER,"
        elif [ "$SOA_SERIAL" -gt "$AUTH_SOA_SERIAL" ]; then
          NAMESERVER_HIGHER="$NAMESERVER_HIGHER$NAMESERVER,"
        else
          NAMESERVER_OK="$NAMESERVER_OK$NAMESERVER,"
        fi
      fi
    done
    NAGIOS_DETAILS="$NAGIOS_DETAILS$n$DNS_ZONE: $AUTH_NAMESERVER($AUTH_SOA_SERIAL)"
    [ -n "$NAMESERVER_OK" ] && NAGIOS_DETAILS="$NAGIOS_DETAILS ok:$NAMESERVER_OK"
    [ -n "$NAMESERVER_HIGHER" ] && NAGIOS_DETAILS="$NAGIOS_DETAILS higher:$NAMESERVER_HIGHER"
    [ -n "$NAMESERVER_LOWER" ] && NAGIOS_DETAILS="$NAGIOS_DETAILS lower:$NAMESERVER_LOWER"
    [ -n "$NAMESERVER_EMPTY" ] && NAGIOS_DETAILS="$NAGIOS_DETAILS error:$NAMESERVER_EMPTY"
    if [ -n "$NAMESERVER_HIGHER$NAMESERVER_LOWER$NAMESERVER_EMPTY" ]; then
      NAGIOS_STATE=CRITICAL
      NAGIOS_RESULT=2
    fi
    NAGIOS_DETAILS="${NAGIOS_DETAILS%,}"
  fi
done

echo "DNSREPLICATION: $NAGIOS_STATE$NAGIOS_DETAILS"
exit $NAGIOS_RESULT