130 lines
4.4 KiB
Bash
Executable file
130 lines
4.4 KiB
Bash
Executable file
#!/bin/sh
|
|
set -e
|
|
|
|
# --- Configuration ---
|
|
# If the first argument is 'vanguards', skip Tor setup and just run vanguards
|
|
if [ "$1" = "vanguards" ]; then
|
|
echo "Starting Vanguards Sidecar Mode..."
|
|
shift # remove 'vanguards' from the arguments
|
|
|
|
# Extract the hostname from the arguments?
|
|
# For now, we assume 'tor-service' as per the standard docker-compose setup
|
|
TARGET_HOST="tor-service"
|
|
TARGET_PORT=9051
|
|
|
|
echo "Waiting for Tor Control Port at $TARGET_HOST:$TARGET_PORT..."
|
|
# Use Python to wait for the port (more reliable than Alpine's nc)
|
|
python3 -c "import socket, time;
|
|
while True:
|
|
try:
|
|
with socket.create_connection(('$TARGET_HOST', $TARGET_PORT), timeout=1):
|
|
break
|
|
except (OSError, ConnectionRefusedError):
|
|
time.sleep(1)"
|
|
|
|
echo "Tor is awake! Resolving IP..."
|
|
|
|
# Fix for ValueError: Invalid IP address
|
|
# stem/vanguards requires a valid IP, not a hostname
|
|
TARGET_IP=$(python3 -c "import socket; print(socket.gethostbyname('$TARGET_HOST'))")
|
|
echo "Resolved $TARGET_HOST to $TARGET_IP"
|
|
|
|
# Replace hostname with IP in arguments
|
|
# Note: This crude replacement assumes 'tor-service' is passed as an arg
|
|
args=""
|
|
for arg in "$@"; do
|
|
if [ "$arg" = "$TARGET_HOST" ]; then
|
|
args="$args $TARGET_IP"
|
|
else
|
|
args="$args $arg"
|
|
fi
|
|
done
|
|
|
|
# Execute with new args (unquoted expansion nicely splits args here,
|
|
# safe enough for this specific use case of rigid flags)
|
|
exec vanguards $args
|
|
fi
|
|
|
|
# If other arguments are passed, exec them (fallback)
|
|
if [ "$#" -gt 0 ]; then
|
|
exec "$@"
|
|
fi
|
|
|
|
# --- Tor Configuration (Only runs if no command passed) ---
|
|
TOR_CONFIG="/etc/tor/torrc"
|
|
# Default to /var/lib/tor if not set
|
|
DATA_DIR="${TOR_DATA_DIR:-/var/lib/tor}"
|
|
|
|
echo "Starting Tor Configuration..."
|
|
|
|
# 1. Reset the Config File
|
|
echo "DataDirectory $DATA_DIR" > "$TOR_CONFIG"
|
|
echo "User tor" >> "$TOR_CONFIG"
|
|
|
|
# 2. Handle Control Password (The Magic Hashing)
|
|
if [ -n "$TOR_CONTROL_PASSWORD" ]; then
|
|
echo "Hashing provided control password..."
|
|
# Generate the hash using Tor itself
|
|
HASHED_PASSWORD=$(tor --quiet --hash-password "$TOR_CONTROL_PASSWORD" | tail -n 1)
|
|
|
|
if [ -z "$HASHED_PASSWORD" ]; then
|
|
echo "Error: Failed to hash password."
|
|
exit 1
|
|
fi
|
|
|
|
echo "ControlPort 0.0.0.0:9051" >> "$TOR_CONFIG"
|
|
echo "HashedControlPassword $HASHED_PASSWORD" >> "$TOR_CONFIG"
|
|
echo "Control Password set."
|
|
else
|
|
echo "Warning: No TOR_CONTROL_PASSWORD set. Control port disabled."
|
|
fi
|
|
|
|
# 3. Handle Hidden Services (The Magic Parsing)
|
|
# Expected Format: "80:container_name:80 22:container_name:22"
|
|
if [ -n "$HIDDEN_SERVICE_HOSTS" ]; then
|
|
echo "HiddenServiceDir $DATA_DIR/hidden_service/" >> "$TOR_CONFIG"
|
|
echo "HiddenServiceVersion 3" >> "$TOR_CONFIG"
|
|
|
|
# Split the string by spaces
|
|
for rule in $HIDDEN_SERVICE_HOSTS; do
|
|
# Validate format: Port:Host:Port (using grep regex)
|
|
if ! echo "$rule" | grep -qE '^[0-9]+:[a-zA-Z0-9.-]+:[0-9]+$'; then
|
|
echo "CRITICAL ERROR: Invalid format in HIDDEN_SERVICE_HOSTS: '$rule'"
|
|
echo "Expected format: ExternalPort:ContainerHost:InternalPort (e.g., 80:my-web:80)"
|
|
exit 1
|
|
fi
|
|
|
|
# Extract parts
|
|
EXT_PORT=$(echo "$rule" | cut -d: -f1)
|
|
HOST=$(echo "$rule" | cut -d: -f2)
|
|
INT_PORT=$(echo "$rule" | cut -d: -f3)
|
|
|
|
# Sanitize HOST
|
|
HOST_CLEAN=$(echo "$HOST" | tr -d '\r')
|
|
|
|
# RESOLVE HOST TO IP FOR TOR
|
|
# Tor is picky about hostnames in HiddenServicePort configs sometimes.
|
|
# We pre-resolve it to be safe.
|
|
echo "Resolving $HOST_CLEAN..."
|
|
if ! HOST_IP=$(python3 -c "import socket; print(socket.gethostbyname('$HOST_CLEAN'))" 2>/dev/null); then
|
|
echo "Warning: Could not resolve '$HOST_CLEAN'. Using hostname directly."
|
|
HOST_IP=$HOST_CLEAN
|
|
else
|
|
echo "Resolved $HOST_CLEAN to $HOST_IP"
|
|
fi
|
|
|
|
echo "Adding Hidden Service Rule: Onion:$EXT_PORT -> $HOST_IP:$INT_PORT"
|
|
echo "HiddenServicePort $EXT_PORT $HOST_IP:$INT_PORT" >> "$TOR_CONFIG"
|
|
done
|
|
else
|
|
echo "Warning: HIDDEN_SERVICE_HOSTS is empty. Tor will run but host nothing."
|
|
fi
|
|
|
|
# 4. Ownership Fix (Crucial for Docker volumes)
|
|
mkdir -p "$DATA_DIR/hidden_service/"
|
|
chown -R tor:root "$DATA_DIR"
|
|
chmod 700 "$DATA_DIR"
|
|
chmod 700 "$DATA_DIR/hidden_service/"
|
|
|
|
echo "Configuration successful. Starting Tor..."
|
|
exec tor -f "$TOR_CONFIG"
|