-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathipv6_path_drift_watch.sh
More file actions
executable file
·114 lines (93 loc) · 2.93 KB
/
ipv6_path_drift_watch.sh
File metadata and controls
executable file
·114 lines (93 loc) · 2.93 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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env bash
set -euo pipefail
# ipv6_path_drift_watch.sh
# Watches IPv6 path changes to one or more targets across repeated trace samples.
usage() {
cat <<'EOF'
Usage: ./ipv6_path_drift_watch.sh [options]
Options:
--target HOST IPv6 host/address to trace (repeatable)
--samples N Number of trace rounds (default: 5)
--interval SEC Seconds between rounds (default: 3)
--max-hops N Maximum hops (default: 20)
--wait SEC Per-probe wait seconds (default: 2)
--strict Exit non-zero when path drift is detected
-h, --help Show help
Exit codes:
0 = no drift (or drift in non-strict mode)
2 = strict mode and path drift detected
EOF
}
TARGETS=("2606:4700:4700::1111" "2001:4860:4860::8888")
SAMPLES=5
INTERVAL=3
MAX_HOPS=20
WAIT=2
STRICT=false
while [[ $# -gt 0 ]]; do
case "$1" in
--target) TARGETS+=("$2"); shift 2 ;;
--samples) SAMPLES="$2"; shift 2 ;;
--interval) INTERVAL="$2"; shift 2 ;;
--max-hops) MAX_HOPS="$2"; shift 2 ;;
--wait) WAIT="$2"; shift 2 ;;
--strict) STRICT=true; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1"; usage; exit 1 ;;
esac
done
if [[ "${#TARGETS[@]}" -gt 2 ]]; then
TARGETS=("${TARGETS[@]:2}")
fi
trace_once() {
local target="$1"
local raw
if command -v traceroute >/dev/null 2>&1; then
raw=$(traceroute -6 -n -q 1 -w "$WAIT" -m "$MAX_HOPS" "$target" 2>/dev/null || true)
printf '%s\n' "$raw" | awk '/^[[:space:]]*[0-9]+[[:space:]]/ {print $2}' | sed '/^$/d'
return
fi
if command -v tracepath >/dev/null 2>&1; then
raw=$(tracepath -6 -n -m "$MAX_HOPS" "$target" 2>/dev/null || true)
printf '%s\n' "$raw" | awk '/^[[:space:]]*[0-9]+:/ {print $2}' | sed '/^$/d'
return
fi
echo "NO_TRACE_TOOL"
}
echo "IPv6 path drift watch timestamp: $(date -Iseconds)"
echo "targets=${TARGETS[*]} samples=$SAMPLES interval=${INTERVAL}s max_hops=$MAX_HOPS strict_mode=$STRICT"
echo
if ! command -v traceroute >/dev/null 2>&1 && ! command -v tracepath >/dev/null 2>&1; then
echo "Neither traceroute nor tracepath is installed"
exit 1
fi
declare -A baseline_path
drift_count=0
for ((sample=1; sample<=SAMPLES; sample++)); do
echo "=== Sample $sample/$SAMPLES ==="
for target in "${TARGETS[@]}"; do
hops=$(trace_once "$target")
path=$(printf '%s\n' "$hops" | paste -sd '>' -)
[[ -z "$path" ]] && path="NO_PATH"
if [[ -z "${baseline_path[$target]:-}" ]]; then
baseline_path[$target]="$path"
status="BASELINE"
elif [[ "${baseline_path[$target]}" == "$path" ]]; then
status="STABLE"
else
status="DRIFT"
((drift_count+=1))
fi
echo "target=$target status=$status"
echo "path=$path"
echo
done
if [[ "$sample" -lt "$SAMPLES" ]]; then
sleep "$INTERVAL"
fi
done
echo "Summary: drift_count=$drift_count strict_mode=$STRICT"
if [[ "$STRICT" == true && "$drift_count" -gt 0 ]]; then
exit 2
fi
exit 0