-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdns_failover_switch_detector.sh
More file actions
executable file
·98 lines (79 loc) · 2.67 KB
/
dns_failover_switch_detector.sh
File metadata and controls
executable file
·98 lines (79 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env bash
set -euo pipefail
# dns_failover_switch_detector.sh
# Detects resolver selection/order changes over time from resolv.conf and optional live query checks.
usage() {
cat <<'EOF'
Usage: ./dns_failover_switch_detector.sh [options]
Options:
--rounds N Number of sampling rounds (default: 5)
--interval SEC Seconds between rounds (default: 3)
--domain NAME Optional domain for per-resolver live checks (default: example.com)
--probe Enable per-resolver dig probe each round
--strict Exit non-zero if resolver order/set changes detected
-h, --help Show help
Exit codes:
0 = no resolver switch observed (or switch in non-strict mode)
2 = strict mode and resolver switch observed
EOF
}
ROUNDS=5
INTERVAL=3
DOMAIN="example.com"
DO_PROBE=false
STRICT=false
while [[ $# -gt 0 ]]; do
case "$1" in
--rounds) ROUNDS="$2"; shift 2 ;;
--interval) INTERVAL="$2"; shift 2 ;;
--domain) DOMAIN="$2"; shift 2 ;;
--probe) DO_PROBE=true; shift ;;
--strict) STRICT=true; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1"; usage; exit 1 ;;
esac
done
if [[ ! -r /etc/resolv.conf ]]; then
echo "/etc/resolv.conf not readable"
exit 1
fi
if [[ "$DO_PROBE" == true && ! $(command -v dig >/dev/null 2>&1; echo $?) -eq 0 ]]; then
echo "dig command not found; disabling --probe"
DO_PROBE=false
fi
echo "DNS failover switch detector timestamp: $(date -Iseconds)"
echo "rounds=$ROUNDS interval=${INTERVAL}s domain=$DOMAIN probe=$DO_PROBE strict_mode=$STRICT"
echo
switch_count=0
prev_resolvers=""
for ((round=1; round<=ROUNDS; round++)); do
echo "=== Round $round/$ROUNDS ==="
resolvers=$(awk '/^nameserver[[:space:]]+/ {print $2}' /etc/resolv.conf | paste -sd ',' -)
[[ -z "$resolvers" ]] && resolvers="NONE"
status="UNCHANGED"
if [[ -n "$prev_resolvers" && "$resolvers" != "$prev_resolvers" ]]; then
status="SWITCHED"
((switch_count+=1))
fi
echo "resolvers=$resolvers"
echo "status=$status"
if [[ "$DO_PROBE" == true && "$resolvers" != "NONE" ]]; then
IFS=',' read -r -a resolver_arr <<< "$resolvers"
for resolver in "${resolver_arr[@]}"; do
q=$(dig @"$resolver" "$DOMAIN" A +time=2 +tries=1 +stats +short 2>/dev/null || true)
ans=$(printf '%s\n' "$q" | sed '/^$/d' | paste -sd ';' -)
[[ -z "$ans" ]] && ans="NO_ANSWER"
echo "probe resolver=$resolver answer=$ans"
done
fi
prev_resolvers="$resolvers"
echo
if [[ "$round" -lt "$ROUNDS" ]]; then
sleep "$INTERVAL"
fi
done
echo "Summary: switch_count=$switch_count strict_mode=$STRICT"
if [[ "$STRICT" == true && "$switch_count" -gt 0 ]]; then
exit 2
fi
exit 0