Skip to content

Instantly share code, notes, and snippets.

@groundcat
Created March 13, 2026 00:34
Show Gist options
  • Select an option

  • Save groundcat/193b3b163e1a734811d7a7b356fb21e6 to your computer and use it in GitHub Desktop.

Select an option

Save groundcat/193b3b163e1a734811d7a7b356fb21e6 to your computer and use it in GitHub Desktop.
Check and compare ping times for all Hurricane Electric (tunnelbroker.net) IPv6 tunnel servers.
#!/bin/bash
# Hurricane Electric Tunnel Server Latency Tester
# https://tunnelbroker.net — tests all available HE.net PoPs
# Servers marked "Not Available (Full)" are excluded.
# ── Colours ──────────────────────────────────────────────────────────────────
RED='\033[0;31m'; YELLOW='\033[1;33m'; GREEN='\033[0;32m'
BOLD='\033[1m'; DIM='\033[2m'; RESET='\033[0m'
# ── Server list: "Region|Display name|IP" ────────────────────────────────────
# Two locations share a city; they are labelled (1)/(2) to avoid ambiguity.
SERVERS=(
# North America
"North America|Ashburn, VA, US|216.66.22.2"
"North America|Calgary, AB, CA|216.218.200.58"
"North America|Chicago, IL, US|184.105.253.14"
"North America|Dallas, TX, US|184.105.253.10"
"North America|Denver, CO, US|184.105.250.46"
"North America|Fremont, CA, US (1)|72.52.104.74"
"North America|Fremont, CA, US (2)|64.62.134.130"
"North America|Honolulu, HI, US|64.71.156.86"
"North America|Kansas City, MO, US|216.66.77.230"
"North America|Los Angeles, CA, US|66.220.18.42"
"North America|Miami, FL, US|209.51.161.58"
"North America|New York, NY, US|209.51.161.14"
"North America|Phoenix, AZ, US|66.220.7.82"
"North America|Seattle, WA, US|216.218.226.238"
"North America|Toronto, ON, CA|216.66.38.58"
"North America|Winnipeg, MB, CA|184.105.255.26"
# Europe
"Europe|Berlin, DE|216.66.86.114"
"Europe|Budapest, HU|216.66.87.14"
"Europe|Frankfurt, DE|216.66.80.30"
"Europe|Lisbon, PT|216.66.87.102"
"Europe|London, UK (1)|216.66.80.26"
"Europe|London, UK (2)|216.66.88.98"
"Europe|Paris, FR|216.66.84.42"
"Europe|Prague, CZ|216.66.86.122"
"Europe|Stockholm, SE|216.66.80.90"
"Europe|Zurich, CH|216.66.80.98"
# Asia
"Asia|Hong Kong, HK|216.218.221.6"
# Africa
"Africa|Djibouti City, DJ|216.66.87.98"
"Africa|Johannesburg, ZA|216.66.87.134"
# South America
"South America|Bogota, CO|216.66.64.154"
# Oceania
"Oceania|Sydney, NSW, AU|216.218.142.50"
# Middle East
"Middle East|Dubai, AE|216.66.90.30"
)
TOTAL=${#SERVERS[@]}
PING_COUNT=5
WORK_DIR=$(mktemp -d)
trap 'rm -rf "$WORK_DIR"' EXIT
# ── Helpers ───────────────────────────────────────────────────────────────────
# Emit the ANSI colour code appropriate for a latency value.
lat_color() {
local val="$1"
if [[ "$val" == "N/A" ]]; then
printf '%b' "$RED"; return
fi
local i=${val%%.*}
(( i < 50 )) && { printf '%b' "$GREEN"; return; }
(( i < 150 )) && { printf '%b' "$YELLOW"; return; }
printf '%b' "$RED"
}
# Right-align $2 in a field of width $1, wrapped in its latency colour.
colored_field() {
local width="$1" val="$2"
printf '%b%*s%b' "$(lat_color "$val")" "$width" "$val" "$RESET"
}
# ── Parallel ping worker ──────────────────────────────────────────────────────
ping_server() {
local idx="$1" region="$2" location="$3" ip="$4"
local result min avg max mdev
result=$(ping -nq -c"$PING_COUNT" -i0.3 -w"$PING_COUNT" "$ip" 2>/dev/null \
| tail -n1 | cut -d' ' -f4)
if [[ "$result" =~ ^[0-9] ]]; then
IFS='/' read -r min avg max mdev <<< "$result"
else
min="N/A"; avg="N/A"; max="N/A"; mdev="N/A"
fi
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$region" "$location" "$ip" "$min" "$avg" "$max" "$mdev" \
> "$WORK_DIR/$idx"
}
# ── Main ──────────────────────────────────────────────────────────────────────
printf '\n%bHurricane Electric — Tunnel Server Latency Test%b\n' "$BOLD" "$RESET"
printf '%bPinging %d servers · %d packets each · all parallel%b\n\n' \
"$DIM" "$TOTAL" "$PING_COUNT" "$RESET"
# Launch all pings simultaneously
for i in "${!SERVERS[@]}"; do
IFS='|' read -r region location ip <<< "${SERVERS[$i]}"
ping_server "$i" "$region" "$location" "$ip" &
done
# Live progress bar (updates every 0.2 s)
BAR_LEN=40
while true; do
done_n=$(find "$WORK_DIR" -maxdepth 1 -type f | wc -l | tr -d ' ')
filled=$(( done_n * BAR_LEN / TOTAL ))
empty=$(( BAR_LEN - filled ))
bar=$(printf '%*s' "$filled" | tr ' ' '█')
gap=$(printf '%*s' "$empty" | tr ' ' '░')
printf '\r [%b%s%b%s] %d / %d' \
"$GREEN" "$bar" "$RESET" "$gap" "$done_n" "$TOTAL"
(( done_n >= TOTAL )) && break
sleep 0.2
done
wait
printf '\r%60s\r' "" # erase progress line
# Collect result files in index order, then sort by avg latency (N/A last)
mapfile -t sorted < <(
for i in "${!SERVERS[@]}"; do cat "$WORK_DIR/$i"; done \
| awk -F'\t' '{
key = ($5 == "N/A") ? 99999 : $5 + 0
printf "%010.3f\t%s\n", key, $0
}' \
| sort -n \
| cut -f2-
)
# ── Table ─────────────────────────────────────────────────────────────────────
SEP=$(printf '%.0s─' {1..97})
printf '\n%b%-16s %-25s %-17s %8s %8s %8s %8s%b\n' \
"$BOLD" "Region" "Location" "IP" "Min" "Avg" "Max" "Mdev" "$RESET"
printf '%b%s%b\n' "$DIM" "$SEP" "$RESET"
# Colour guide legend
printf '%b < 50 ms ' "$GREEN"; printf '%b 50–150 ms ' "$YELLOW"; printf '%b > 150 ms / unreachable%b\n\n' "$RED" "$RESET"
best_loc="" best_ip="" best_avg=""
for row in "${sorted[@]}"; do
IFS=$'\t' read -r region location ip min avg max mdev <<< "$row"
# Fixed-width text columns
printf '%-16s %-25s %-17s ' "$region" "$location" "$ip"
# Colour-coded numeric columns
colored_field 8 "$min"; printf ' '
colored_field 8 "$avg"; printf ' '
colored_field 8 "$max"; printf ' '
printf '%8s\n' "$mdev"
# First non-N/A row (already sorted) is the best
[[ -z "$best_loc" && "$avg" != "N/A" ]] && {
best_loc="$location"; best_ip="$ip"; best_avg="$avg"
}
done
printf '%b%s%b\n' "$DIM" "$SEP" "$RESET"
if [[ -n "$best_loc" ]]; then
printf '\n%bLowest avg latency:%b %b%s%b %b%s%b → avg %b%s ms%b\n\n' \
"$BOLD" "$RESET" \
"$GREEN" "$best_loc" "$RESET" \
"$DIM" "$best_ip" "$RESET" \
"$GREEN" "$best_avg" "$RESET"
else
printf '\n%bNo servers responded.%b\n\n' "$RED" "$RESET"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment