#!/bin/sh

# Where is expiration in dig's output?
EXP_FIELD=9

usage() {
   cat <<EOF >&2
Usage: $0 [opts] domain-name
Report if a zone's signatures are near expiration (or expired).
Options:
  -b address    check signature using source IP address (see dig -b).
  -s address    check signature using dns server @address
  -x time       time signature should be valid to avoid report, default='$MAX_DELAY'
EOF
   exit 1
}

while getopts "x:b:s:" switch; do
    if [ "$switch" = '?' ]; then usage ; fi
    eval "opt_$switch=\"$OPTARG\""
done

if [ $OPTIND -gt 1 ]; then shift $((OPTIND-1)) ; fi

# Fatal error if the signature expires in less than ${MAX_DELAY}
MAX_DELAY="$opt_x"
if [ -z "$MAX_DELAY" ]; then MAX_DELAY='5 days' ; fi
if [ -n "$opt_b" ]; then BINDTO="-b $opt_b" ; fi
if [ -n "$opt_s" ]; then SERVER="@$opt_s" ; fi

if [ -z "$1" ]; then
    usage
fi

if ! date --version > /dev/null 2>&1; then
    if ! gdate --version > /dev/null 2>&1; then
        echo "You must use GNU date" >&2
        exit 1
    else
        DATE=gdate
    fi
else
    DATE=date
fi

check_exp() {
    if [ -z "$1" ]; then
        echo "INTERNAL ERROR: check_exp called without arg" >&2
        exit 1
    fi
    exp=$1
    if [ $exp -lt $now ]; then
        echo "Name ${name} has an expired signature (${exp})" >&2
        echo 1
        return
    elif [ $exp -lt $delay ]; then
        echo "Name ${name} has a signature that will expire in less than ${MAX_DELAY} (${exp})" >&2
        echo 1
        return
    fi
    echo 0
}

now=$(${DATE} +"%Y%m%d%H%M%S")
delay=$(${DATE} +"%Y%m%d%H%M%S" -d "${MAX_DELAY}")

name=$1

dig $BINDTO +cd +dnssec +noadditional +noauthority SOA ${name} $SERVER | \
    awk "\$4 == \"RRSIG\" { print \$${EXP_FIELD}}" | (
    total_status=0
    total_lines=0
    while read exp; do
        exp_status=$(check_exp $exp)
        total_status=$(expr $total_status + $exp_status)
        total_lines=$(expr $total_lines + 1)
    done
    if [ $total_lines -eq 0 ]; then
        echo "${name} is apparently not signed (or not a zone; or your resolver is not DNSSEC-enabled)" >&2
        exit 1
    fi
    exit $total_status
)

