Created
March 13, 2026 00:34
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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