#!/usr/bin/env bash
set -euo pipefail

# dnssec-validate.sh
#
# Purpose:
#   Perform practical DNSSEC readiness and validation checks for a zone.
#   This script is intentionally read-only and makes no changes to DNS data.
#
# What it checks:
#   - Required command availability
#   - Optional authoritative and validating resolver queries
#   - DNSKEY presence at the zone apex
#   - DS presence in the parent zone
#   - End-to-end validation hints using dig +dnssec output
#
# Notes:
#   - This script does not assume a specific DNS provider.
#   - For best results, run from a host with network access to your resolvers.
#   - Replace placeholders with your own zone and optional resolver IPs.

usage() {
  cat <<'EOF'
Usage:
  dnssec-validate.sh -z <zone> [options]

Required:
  -z, --zone <name>         DNS zone to check, e.g. example.com

Optional:
  -a, --authoritative <ip>  Authoritative nameserver IP to query
  -r, --resolver <ip>       Validating recursive resolver IP to query
  -p, --parent <zone>       Parent zone name, e.g. com
  -t, --type <rrtype>       RRtype to validate (default: A)
  -h, --help                Show this help

Examples:
  ./dnssec-validate.sh -z example.com -a 192.0.2.53 -r 1.1.1.1 -p com
  ./dnssec-validate.sh -z example.com
EOF
}

ZONE=""
AUTH_NS_IP=""
RESOLVER_IP=""
PARENT_ZONE=""
RRTYPE="A"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -z|--zone)
      ZONE="${2:-}"
      shift 2
      ;;
    -a|--authoritative)
      AUTH_NS_IP="${2:-}"
      shift 2
      ;;
    -r|--resolver)
      RESOLVER_IP="${2:-}"
      shift 2
      ;;
    -p|--parent)
      PARENT_ZONE="${2:-}"
      shift 2
      ;;
    -t|--type)
      RRTYPE="${2:-A}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$ZONE" ]]; then
  echo "Error: zone is required." >&2
  usage
  exit 1
fi

require_cmd() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "Error: required command not found: $1" >&2
    exit 1
  fi
}

require_cmd dig

if command -v awk >/dev/null 2>&1; then :; else
  echo "Warning: awk not found; output parsing will be limited." >&2
fi

echo "== DNSSEC validation checklist for: $ZONE =="

# 1) Check NS delegation

echo
echo "[1/6] NS delegation"
dig +short NS "$ZONE" || true

# 2) Check DNSKEY at zone apex

echo
echo "[2/6] DNSKEY at apex (signed zone should publish DNSKEY)"
if [[ -n "$AUTH_NS_IP" ]]; then
  dig +dnssec +multi "@$AUTH_NS_IP" "$ZONE" DNSKEY
else
  dig +dnssec +multi "$ZONE" DNSKEY
fi

# 3) Check DS at parent if provided
if [[ -n "$PARENT_ZONE" ]]; then
  echo
echo "[3/6] DS at parent ($PARENT_ZONE)"
  dig +dnssec +short DS "$ZONE" "@$PARENT_ZONE" || true
  echo "Note: If querying the parent zone directly is not supported in your environment,"
  echo "      validate DS at the registrar or parent authoritative server separately."
else
  echo
echo "[3/6] DS at parent"
  echo "Skipped: parent zone not provided. Use -p <parent-zone> to compare DS records."
fi

# 4) Validate a record via recursive resolver
if [[ -n "$RESOLVER_IP" ]]; then
  echo
echo "[4/6] Recursive validation using resolver $RESOLVER_IP"
  dig +dnssec +multi "@$RESOLVER_IP" "$ZONE" "$RRTYPE"
else
  echo
echo "[4/6] Recursive validation"
  echo "Skipped: resolver not provided. Use -r <resolver-ip> to test a validating path."
fi

# 5) Check for RRSIG presence on apex RRsets

echo
echo "[5/6] RRSIG presence on apex records"
if [[ -n "$AUTH_NS_IP" ]]; then
  dig +dnssec +multi "@$AUTH_NS_IP" "$ZONE" SOA
  dig +dnssec +multi "@$AUTH_NS_IP" "$ZONE" NS
else
  dig +dnssec +multi "$ZONE" SOA
  dig +dnssec +multi "$ZONE" NS
fi

# 6) Quick operational notes

echo
echo "[6/6] Operational reminders"
cat <<EOF
- Confirm the parent DS matches the current DNSKEY digest.
- After any key rollover, re-run this script and confirm validating resolvers return answers.
- Watch for SERVFAIL on validating clients, which can indicate a broken chain of trust.
- Verify TTLs and propagation before switching traffic to the signed zone.
EOF

echo
echo "Done. Review the outputs above for DNSKEY, DS, and RRSIG consistency."