#!/bin/bash # Watches tor's ControlPort for bootstrap progress. If it stalls past # STALL_TIMEOUT without reaching 100%, it disables the currently-failing # Bridge line in torrc and restarts tor on the next one, up to MAX_TRIES. set -uo pipefail CONTROL_PORT=9051 STALL_TIMEOUT=150 # seconds to wait per bridge attempt (snowflake's WebRTC/ # broker handshake routinely needs >90s on a cold start) MAX_TRIES=3 TORRC=/etc/tor/torrc COOKIE=/var/lib/tor/control_auth_cookie authenticate_and_query() { # Uses the cookie file tor writes on startup; returns raw GETINFO output local cookie_hex cookie_hex=$(xxd -p "$COOKIE" | tr -d '\n') printf 'AUTHENTICATE %s\r\nGETINFO status/bootstrap-phase\r\nQUIT\r\n' "$cookie_hex" \ | timeout 5 nc 127.0.0.1 "$CONTROL_PORT" 2>/dev/null } wait_for_bootstrap() { local waited=0 while (( waited < STALL_TIMEOUT )); do [[ -r "$COOKIE" ]] || { sleep 1; ((waited++)); continue; } local out out=$(authenticate_and_query || true) if echo "$out" | grep -q 'PROGRESS=100'; then return 0 fi if echo "$out" | grep -qi 'BOOTSTRAP'; then local progress progress=$(echo "$out" | grep -oP 'PROGRESS=\K[0-9]+' || echo "?") echo "[bootstrap-test] progress: ${progress}% (${waited}s/${STALL_TIMEOUT}s)" fi sleep 3 ((waited+=3)) done return 1 } disable_current_bridge_line() { # Comments out the first still-active `Bridge ` line so the next # restart falls through to the next configured transport. local line line=$(grep -n '^Bridge ' "$TORRC" | head -1 | cut -d: -f1) if [[ -n "$line" ]]; then sed -i "${line}s/^Bridge /# FAILED-Bridge /" "$TORRC" echo "[bootstrap-test] disabled bridge on line ${line}, will retry with next transport" fi } for attempt in $(seq 1 "$MAX_TRIES"); do echo "[bootstrap-test] attempt ${attempt}/${MAX_TRIES}" if wait_for_bootstrap; then echo "[bootstrap-test] SUCCESS: bootstrapped to 100%" exit 0 fi echo "[bootstrap-test] stalled after ${STALL_TIMEOUT}s, rotating bridge and restarting tor" disable_current_bridge_line pkill -HUP -x tor 2>/dev/null || true # ask tor to reload torrc sleep 3 pkill -x tor 2>/dev/null || true tor -f "$TORRC" & done echo "[bootstrap-test] FAILURE: exhausted all configured bridges" exit 1