mirror of
https://github.com/r3bo0tbx1/tor-guard-relay.git
synced 2026-04-06 00:32:04 +02:00
🔧 New tool: gen-family - generate/view Happy Family keys - Supports --force flag to overwrite existing keys without backup prompt 🐳 Dockerfiles: gen-family in both Dockerfile and Dockerfile.edge 🔧 Entrypoint: - Phase 2: detect *.secret_family_key, log found keys (informational only) - Guard/exit config gen: append FamilyId + MyFamily from ENV vars - Bridge intentionally excluded 📊 Status tool: show family key count + Happy Family config state 📚 Docs: - README: Happy Family section (generate / import), persistence table, flowchart - ARCHITECTURE: all mermaid diagrams updated (Phase 2, config gen, tools, dirs) - TOOLS: full gen-family reference with examples and exit codes - DEPLOYMENT, MIGRATION, MIGRATION-V1.1.X, TROUBLESHOOTING: 5 -> 6 tools - FAQ, example configs: version bump + FamilyId/MyFamily placeholders - Directory authority voting: how 9 dirauths vote on relay flags (5/9 consensus) - CIISS v2 ContactInfo: field reference, generator link, proof:uri-rsa verification - All TOR_CONTACT_INFO examples updated to CIISS v2 format across templates and docs 📋 Templates: - Guard/exit/multi-relay compose: TOR_FAMILY_ID + TOR_MY_FAMILY env vars - All cosmos-compose + docker-compose versions -> 1.1.7 👷 CI: validate.yml gen-family in 8 spots (threshold 6), security tests, quick-test 🛡️ SECURITY.md: 1.1.7 active, 1.1.6 maintenance, gen-family in tools list 🔖 Version bump 1.1.6 -> 1.1.7 across 30+ files, tool count 5 -> 6, CHANGELOG entry No breaking changes. TOR_FAMILY_ID and TOR_MY_FAMILY are optional.
450 lines
15 KiB
Bash
450 lines
15 KiB
Bash
#!/bin/sh
|
||
# docker-entrypoint.sh - Tor Guard Relay initialization and process management
|
||
set -e
|
||
|
||
[ -n "${NICKNAME:-}" ] && TOR_NICKNAME="$NICKNAME"
|
||
[ -n "${EMAIL:-}" ] && TOR_CONTACT_INFO="$EMAIL"
|
||
[ -n "${OR_PORT:-}" ] && TOR_ORPORT="$OR_PORT"
|
||
[ -n "${PT_PORT:-}" ] && TOR_OBFS4_PORT="$PT_PORT"
|
||
|
||
if [ -n "${PT_PORT:-}" ] && [ "${TOR_RELAY_MODE:-guard}" = "guard" ]; then
|
||
TOR_RELAY_MODE="bridge"
|
||
fi
|
||
|
||
readonly TOR_CONFIG="${TOR_CONFIG:-/etc/tor/torrc}"
|
||
readonly TOR_DATA_DIR="${TOR_DATA_DIR:-/var/lib/tor}"
|
||
readonly TOR_LOG_DIR="${TOR_LOG_DIR:-/var/log/tor}"
|
||
readonly TOR_RELAY_MODE="${TOR_RELAY_MODE:-guard}"
|
||
|
||
TOR_PID=""
|
||
TAIL_PID=""
|
||
|
||
log() { printf "%s\n" "$1"; }
|
||
info() { printf " ℹ️ %s\n" "$1"; }
|
||
success() { printf "✅ %s\n" "$1"; }
|
||
warn() { printf "🛑 %s\n" "$1"; }
|
||
die() { printf "🛑 ERROR: %s\n" "$1"; exit 1; }
|
||
|
||
trap 'cleanup_and_exit' TERM INT
|
||
|
||
cleanup_and_exit() {
|
||
log ""
|
||
warn "Shutdown signal received. Stopping Tor relay..."
|
||
|
||
if [ -n "$TAIL_PID" ] && kill -0 "$TAIL_PID" 2>/dev/null; then
|
||
kill -TERM "$TAIL_PID" 2>/dev/null || true
|
||
fi
|
||
|
||
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
|
||
log " Sending SIGTERM to Tor (PID: $TOR_PID)..."
|
||
kill -TERM "$TOR_PID" 2>/dev/null || true
|
||
wait "$TOR_PID" 2>/dev/null || true
|
||
fi
|
||
|
||
success "Tor relay stopped cleanly."
|
||
log ""
|
||
log " Relay stopped at $(date -u '+%Y-%m-%d %H:%M:%S') UTC"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
exit 0
|
||
}
|
||
|
||
startup_banner() {
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log "🧅 Tor Guard Relay v1.1.7 - Initialization"
|
||
log "https://github.com/r3bo0tbx1/tor-guard-relay"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
}
|
||
|
||
phase_1_directories() {
|
||
log "🗂️ Phase 1: Directory Structure"
|
||
mkdir -p "$TOR_DATA_DIR" "$TOR_LOG_DIR" /run/tor /tmp
|
||
|
||
log " Created directories:"
|
||
log " • Data: $TOR_DATA_DIR"
|
||
log " • Logs: $TOR_LOG_DIR"
|
||
log " • Run: /run/tor"
|
||
|
||
if command -v df >/dev/null 2>&1; then
|
||
available=$(df -h "$TOR_DATA_DIR" 2>/dev/null | tail -n 1 | awk '{print $4}' || echo "unknown")
|
||
log " 💽 Available disk space: $available"
|
||
fi
|
||
log ""
|
||
}
|
||
|
||
phase_2_permissions() {
|
||
log "🔐 Phase 2: Permission Hardening"
|
||
|
||
chmod 700 "$TOR_DATA_DIR" 2>/dev/null || warn "Failed to set data directory permissions (may be read-only mount)"
|
||
chmod 755 "$TOR_LOG_DIR" 2>/dev/null || warn "Failed to set log directory permissions (may be read-only mount)"
|
||
|
||
CURRENT_UID=$(id -u)
|
||
CURRENT_GID=$(id -g)
|
||
|
||
if [ ! -w "$TOR_DATA_DIR" ]; then
|
||
warn "Data directory $TOR_DATA_DIR is not writable by tor user (UID $CURRENT_UID)"
|
||
warn "If using host bind mounts, fix ownership on the host:"
|
||
warn " chown -R $CURRENT_UID:$CURRENT_GID <host-path>"
|
||
fi
|
||
|
||
if [ -d "$TOR_DATA_DIR/keys" ] && [ ! -w "$TOR_DATA_DIR/keys" ]; then
|
||
warn "Keys directory $TOR_DATA_DIR/keys has wrong ownership!"
|
||
KEYS_OWNER=$(stat -c '%u:%g' "$TOR_DATA_DIR/keys" 2>/dev/null || echo "unknown")
|
||
warn " Current owner: $KEYS_OWNER - Expected: $CURRENT_UID:$CURRENT_GID"
|
||
warn " Fix on the host: chown -R $CURRENT_UID:$CURRENT_GID <host-keys-path>"
|
||
fi
|
||
|
||
# Check for Happy Family key files
|
||
FAMILY_KEY_COUNT=0
|
||
if [ -d "$TOR_DATA_DIR/keys" ]; then
|
||
for fk in "$TOR_DATA_DIR/keys"/*.secret_family_key; do
|
||
[ -f "$fk" ] || continue
|
||
FAMILY_KEY_COUNT=$((FAMILY_KEY_COUNT + 1))
|
||
FK_NAME=$(basename "$fk" .secret_family_key)
|
||
info "Found Happy Family key: $FK_NAME"
|
||
done
|
||
fi
|
||
if [ "$FAMILY_KEY_COUNT" -gt 0 ]; then
|
||
success "$FAMILY_KEY_COUNT family key(s) detected in keys directory"
|
||
fi
|
||
|
||
success "Permissions configured securely"
|
||
log ""
|
||
}
|
||
|
||
validate_relay_config() {
|
||
if [ -n "${TOR_RELAY_MODE:-}" ]; then
|
||
case "$TOR_RELAY_MODE" in
|
||
guard|middle|exit|bridge)
|
||
:
|
||
;;
|
||
*)
|
||
die "TOR_RELAY_MODE must be: guard, middle, exit, or bridge (got: $TOR_RELAY_MODE)"
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
if [ -n "${TOR_NICKNAME:-}" ]; then
|
||
nickname_len=$(printf "%s" "$TOR_NICKNAME" | wc -c)
|
||
if [ "$nickname_len" -lt 1 ] || [ "$nickname_len" -gt 19 ]; then
|
||
die "TOR_NICKNAME must be 1-19 characters (got: $nickname_len)"
|
||
fi
|
||
if ! printf "%s" "$TOR_NICKNAME" | grep -qE '^[a-zA-Z0-9]+$'; then
|
||
die "TOR_NICKNAME must contain only alphanumeric characters"
|
||
fi
|
||
case "$(printf "%s" "$TOR_NICKNAME" | tr '[:upper:]' '[:lower:]')" in
|
||
unnamed|noname|default|tor|relay|bridge|exit)
|
||
die "TOR_NICKNAME cannot use reserved name: $TOR_NICKNAME"
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
if [ -n "${TOR_CONTACT_INFO:-}" ]; then
|
||
TOR_CONTACT_INFO="$(printf "%s" "$TOR_CONTACT_INFO" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
||
|
||
contact_len=$(printf "%s" "$TOR_CONTACT_INFO" | wc -c)
|
||
if [ "$contact_len" -lt 3 ]; then
|
||
die "TOR_CONTACT_INFO must be at least 3 characters"
|
||
fi
|
||
line_count=$(printf "%s" "$TOR_CONTACT_INFO" | wc -l)
|
||
if [ "$line_count" -gt 0 ]; then
|
||
die "TOR_CONTACT_INFO cannot contain newlines (got $line_count lines)"
|
||
fi
|
||
fi
|
||
|
||
for port_var in TOR_ORPORT TOR_DIRPORT TOR_OBFS4_PORT; do
|
||
eval "port_val=\${$port_var:-}"
|
||
if [ -n "$port_val" ]; then
|
||
if ! printf "%s" "$port_val" | grep -qE '^[0-9]+$'; then
|
||
die "$port_var must be a valid port number (got: $port_val)"
|
||
fi
|
||
if [ "$port_var" = "TOR_DIRPORT" ] && [ "$port_val" -eq 0 ]; then
|
||
:
|
||
elif [ "$port_val" -lt 1 ] || [ "$port_val" -gt 65535 ]; then
|
||
die "$port_var must be between 1-65535 (got: $port_val)"
|
||
fi
|
||
if [ "$port_val" -lt 1024 ] && [ "$port_val" -ne 0 ]; then
|
||
warn "$port_var using privileged port $port_val (may require CAP_NET_BIND_SERVICE)"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
for bw_var in TOR_BANDWIDTH_RATE TOR_BANDWIDTH_BURST; do
|
||
eval "bw_val=\${$bw_var:-}"
|
||
if [ -n "$bw_val" ]; then
|
||
if ! printf "%s" "$bw_val" | grep -qE '^[0-9]+ ?(Bytes?|KBytes?|MBytes?|GBytes?|TBytes?|KB?|MB?|GB?|TB?)$'; then
|
||
die "$bw_var has invalid format (got: $bw_val, expected: '10 MB' or '1 GB')"
|
||
fi
|
||
fi
|
||
done
|
||
}
|
||
|
||
phase_3_configuration() {
|
||
log "🔧 Phase 3: Configuration Setup"
|
||
|
||
if [ -f "$TOR_CONFIG" ] && [ -s "$TOR_CONFIG" ]; then
|
||
success "Using mounted configuration: $TOR_CONFIG"
|
||
CONFIG_SOURCE="mounted"
|
||
elif [ -n "${TOR_NICKNAME:-}" ] && [ -n "${TOR_CONTACT_INFO:-}" ]; then
|
||
log " Generating configuration from environment variables..."
|
||
validate_relay_config
|
||
generate_config_from_env
|
||
CONFIG_SOURCE="environment"
|
||
success "Configuration generated from ENV vars"
|
||
else
|
||
die "No configuration found. Mount a torrc file or provide TOR_NICKNAME and TOR_CONTACT_INFO environment variables."
|
||
fi
|
||
|
||
log ""
|
||
}
|
||
|
||
generate_config_from_env() {
|
||
cat > "$TOR_CONFIG" << EOF
|
||
# Generated Tor configuration for ${TOR_RELAY_MODE} relay
|
||
# Generated at: $(date -u '+%Y-%m-%d %H:%M:%S') UTC
|
||
|
||
# Basic relay information
|
||
Nickname ${TOR_NICKNAME}
|
||
ContactInfo ${TOR_CONTACT_INFO}
|
||
|
||
# Network configuration
|
||
ORPort ${TOR_ORPORT:-9001}
|
||
SocksPort 0
|
||
|
||
# Data directories
|
||
DataDirectory ${TOR_DATA_DIR}
|
||
|
||
# Logging (file + stdout for container logs)
|
||
Log notice file ${TOR_LOG_DIR}/notices.log
|
||
Log notice stdout
|
||
|
||
EOF
|
||
|
||
case "$TOR_RELAY_MODE" in
|
||
guard|middle)
|
||
cat >> "$TOR_CONFIG" << EOF
|
||
# Guard/Middle relay configuration
|
||
DirPort ${TOR_DIRPORT:-9030}
|
||
ExitRelay 0
|
||
BridgeRelay 0
|
||
|
||
# Bandwidth (optional)
|
||
EOF
|
||
[ -n "${TOR_BANDWIDTH_RATE:-}" ] && echo "RelayBandwidthRate ${TOR_BANDWIDTH_RATE}" >> "$TOR_CONFIG"
|
||
[ -n "${TOR_BANDWIDTH_BURST:-}" ] && echo "RelayBandwidthBurst ${TOR_BANDWIDTH_BURST}" >> "$TOR_CONFIG"
|
||
|
||
# Happy Family (Tor 0.4.9+)
|
||
[ -n "${TOR_FAMILY_ID:-}" ] && echo "" >> "$TOR_CONFIG" && echo "# Happy Family (Tor 0.4.9+)" >> "$TOR_CONFIG" && echo "FamilyId ${TOR_FAMILY_ID}" >> "$TOR_CONFIG"
|
||
|
||
# MyFamily (legacy, keep during transition)
|
||
if [ -n "${TOR_MY_FAMILY:-}" ]; then
|
||
echo "" >> "$TOR_CONFIG"
|
||
echo "# MyFamily (legacy - keep during transition to Happy Family)" >> "$TOR_CONFIG"
|
||
echo "$TOR_MY_FAMILY" | tr ',' '\n' | while IFS= read -r fp; do
|
||
fp=$(printf "%s" "$fp" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||
[ -n "$fp" ] && echo "MyFamily $fp" >> "$TOR_CONFIG"
|
||
done
|
||
fi
|
||
;;
|
||
|
||
exit)
|
||
cat >> "$TOR_CONFIG" << EOF
|
||
# Exit relay configuration
|
||
DirPort ${TOR_DIRPORT:-9030}
|
||
ExitRelay 1
|
||
BridgeRelay 0
|
||
|
||
# Exit policy (default: reduced exit)
|
||
${TOR_EXIT_POLICY:-ExitPolicy reject *:*}
|
||
|
||
# Bandwidth (optional)
|
||
EOF
|
||
[ -n "${TOR_BANDWIDTH_RATE:-}" ] && echo "RelayBandwidthRate ${TOR_BANDWIDTH_RATE}" >> "$TOR_CONFIG"
|
||
[ -n "${TOR_BANDWIDTH_BURST:-}" ] && echo "RelayBandwidthBurst ${TOR_BANDWIDTH_BURST}" >> "$TOR_CONFIG"
|
||
|
||
# Happy Family (Tor 0.4.9+)
|
||
[ -n "${TOR_FAMILY_ID:-}" ] && echo "" >> "$TOR_CONFIG" && echo "# Happy Family (Tor 0.4.9+)" >> "$TOR_CONFIG" && echo "FamilyId ${TOR_FAMILY_ID}" >> "$TOR_CONFIG"
|
||
|
||
# MyFamily (legacy, keep during transition)
|
||
if [ -n "${TOR_MY_FAMILY:-}" ]; then
|
||
echo "" >> "$TOR_CONFIG"
|
||
echo "# MyFamily (legacy - keep during transition to Happy Family)" >> "$TOR_CONFIG"
|
||
echo "$TOR_MY_FAMILY" | tr ',' '\n' | while IFS= read -r fp; do
|
||
fp=$(printf "%s" "$fp" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
||
[ -n "$fp" ] && echo "MyFamily $fp" >> "$TOR_CONFIG"
|
||
done
|
||
fi
|
||
;;
|
||
|
||
bridge)
|
||
cat >> "$TOR_CONFIG" << EOF
|
||
# Bridge relay configuration
|
||
BridgeRelay 1
|
||
PublishServerDescriptor bridge
|
||
|
||
# obfs4 pluggable transport
|
||
ServerTransportPlugin obfs4 exec /usr/bin/lyrebird
|
||
ServerTransportListenAddr obfs4 0.0.0.0:${TOR_OBFS4_PORT:-9002}
|
||
ExtORPort auto
|
||
|
||
# Bandwidth (optional)
|
||
EOF
|
||
[ -n "${TOR_BANDWIDTH_RATE:-}" ] && echo "RelayBandwidthRate ${TOR_BANDWIDTH_RATE}" >> "$TOR_CONFIG"
|
||
[ -n "${TOR_BANDWIDTH_BURST:-}" ] && echo "RelayBandwidthBurst ${TOR_BANDWIDTH_BURST}" >> "$TOR_CONFIG"
|
||
|
||
if [ "${OBFS4_ENABLE_ADDITIONAL_VARIABLES:-0}" = "1" ]; then
|
||
echo "" >> "$TOR_CONFIG"
|
||
echo "# Additional torrc options from OBFS4V_* environment variables" >> "$TOR_CONFIG"
|
||
|
||
env | grep '^OBFS4V_' | sort | while IFS='=' read -r key value; do
|
||
torrc_key="${key#OBFS4V_}"
|
||
if ! printf "%s" "$torrc_key" | grep -qE '^[a-zA-Z][a-zA-Z0-9_]*$'; then
|
||
warn "Skipping invalid OBFS4V variable name: $key (must be alphanumeric)"
|
||
continue
|
||
fi
|
||
line_count=$(printf "%s" "$value" | wc -l)
|
||
if [ "$line_count" -gt 0 ]; then
|
||
warn "Skipping $key: value contains newlines ($line_count lines)"
|
||
continue
|
||
fi
|
||
if printf "%s" "$value" | tr -d '[ -~]' | grep -q .; then
|
||
warn "Skipping $key: value contains control characters"
|
||
continue
|
||
fi
|
||
case "$torrc_key" in
|
||
AccountingMax|AccountingStart|Address|AddressDisableIPv6|\
|
||
BandwidthBurst|BandwidthRate|RelayBandwidthBurst|RelayBandwidthRate|\
|
||
ContactInfo|DirPort|MaxMemInQueues|NumCPUs|ORPort|\
|
||
OutboundBindAddress|OutboundBindAddressOR|Nickname|\
|
||
ServerDNSAllowBrokenConfig|ServerDNSDetectHijacking)
|
||
printf "%s %s\n" "$torrc_key" "$value" >> "$TOR_CONFIG"
|
||
;;
|
||
*)
|
||
warn "Skipping $key: torrc option '$torrc_key' not in whitelist"
|
||
warn " If you need this option, mount a custom torrc file instead"
|
||
;;
|
||
esac
|
||
done
|
||
fi
|
||
;;
|
||
|
||
*)
|
||
die "Invalid TOR_RELAY_MODE: $TOR_RELAY_MODE (must be: guard, exit, or bridge)"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
phase_4_validation() {
|
||
log "🔎 Phase 4: Configuration Validation"
|
||
|
||
if ! command -v tor >/dev/null 2>&1; then
|
||
die "Tor binary not found in PATH"
|
||
fi
|
||
|
||
TOR_VERSION=$(tor --version 2>/dev/null | head -n1 || echo "unknown")
|
||
log " 📦 Tor version: $TOR_VERSION"
|
||
|
||
log " Validating torrc syntax..."
|
||
|
||
VERIFY_TMP=""
|
||
cleanup_verify_tmp() {
|
||
[ -n "$VERIFY_TMP" ] && rm -f "$VERIFY_TMP"
|
||
}
|
||
trap cleanup_verify_tmp EXIT
|
||
|
||
VERIFY_TMP=$(mktemp -t tor-verify.XXXXXX)
|
||
|
||
if ! tor --verify-config -f "$TOR_CONFIG" >"$VERIFY_TMP" 2>&1; then
|
||
warn "Configuration validation failed!"
|
||
DEBUG_LOWER=$(printf "%s" "${DEBUG:-false}" | tr '[:upper:]' '[:lower:]')
|
||
if [ "$DEBUG_LOWER" = "true" ] || [ "$DEBUG_LOWER" = "1" ] || [ "$DEBUG_LOWER" = "yes" ]; then
|
||
log " Error output:"
|
||
head -n 10 "$VERIFY_TMP" | sed 's/^/ /'
|
||
fi
|
||
cleanup_verify_tmp
|
||
die "Invalid Tor configuration. Set DEBUG=true for details."
|
||
fi
|
||
|
||
cleanup_verify_tmp
|
||
success "Configuration is valid"
|
||
log ""
|
||
}
|
||
|
||
phase_5_build_info() {
|
||
log "📊 Phase 5: Build Information"
|
||
|
||
if [ -f /build-info.txt ]; then
|
||
log " Build metadata:"
|
||
cat /build-info.txt | sed 's/^/ /'
|
||
else
|
||
warn "No build-info.txt found"
|
||
fi
|
||
|
||
log ""
|
||
log " 🌐 Relay mode: $TOR_RELAY_MODE"
|
||
log " 🔧 Config source: $CONFIG_SOURCE"
|
||
log ""
|
||
}
|
||
|
||
phase_6_diagnostics() {
|
||
log "🧩 Phase 6: Available Diagnostic Tools"
|
||
log ""
|
||
log " Once Tor is running, use these commands:"
|
||
log " • docker exec <container> status - Full health report"
|
||
log " • docker exec <container> health - JSON health check"
|
||
log " • docker exec <container> fingerprint - Relay fingerprint"
|
||
[ "$TOR_RELAY_MODE" = "bridge" ] && log " • docker exec <container> bridge-line - obfs4 bridge line"
|
||
log ""
|
||
}
|
||
|
||
launch_tor() {
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
success "Starting Tor relay..."
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
tor -f "$TOR_CONFIG" &
|
||
TOR_PID=$!
|
||
|
||
log "🚀 Tor relay started (PID: $TOR_PID)"
|
||
log ""
|
||
log "📋 Tor bootstrap logs:"
|
||
log ""
|
||
|
||
log_wait=0
|
||
while [ ! -f "$TOR_LOG_DIR/notices.log" ] && [ $log_wait -lt 50 ]; do
|
||
sleep 0.1
|
||
log_wait=$((log_wait + 1))
|
||
done
|
||
|
||
if [ -f "$TOR_LOG_DIR/notices.log" ]; then
|
||
tail -F "$TOR_LOG_DIR/notices.log" 2>/dev/null &
|
||
TAIL_PID=$!
|
||
else
|
||
warn "Log file not created yet, bootstrap messages will not be shown"
|
||
fi
|
||
|
||
wait "$TOR_PID"
|
||
TOR_EXIT_CODE=$?
|
||
|
||
if [ -n "$TAIL_PID" ] && kill -0 "$TAIL_PID" 2>/dev/null; then
|
||
kill -TERM "$TAIL_PID" 2>/dev/null || true
|
||
fi
|
||
|
||
log ""
|
||
warn "Tor process exited with code: $TOR_EXIT_CODE"
|
||
cleanup_and_exit
|
||
}
|
||
|
||
main() {
|
||
startup_banner
|
||
phase_1_directories
|
||
phase_2_permissions
|
||
phase_3_configuration
|
||
phase_4_validation
|
||
phase_5_build_info
|
||
phase_6_diagnostics
|
||
launch_tor
|
||
}
|
||
|
||
main "$@" |