#!/bin/sh /etc/rc.common # SecuBox Tor Shield - Tor anonymization service # Copyright (C) 2025 CyberMind.fr START=95 STOP=10 USE_PROCD=1 PROG=/usr/sbin/torctl CONFIG=tor-shield TORRC=/var/run/tor/torrc TOR_DATA=/var/lib/tor TOR_RUN=/var/run/tor . /lib/functions.sh generate_torrc() { local enabled mode dns_over_tor socks_port socks_addr trans_port dns_port local bridges_enabled bridge_type exit_nodes exclude_exit_nodes strict_nodes config_load "$CONFIG" config_get enabled main enabled '0' config_get mode main mode 'transparent' config_get dns_over_tor main dns_over_tor '1' config_get socks_port socks port '9050' config_get socks_addr socks address '127.0.0.1' config_get trans_port trans port '9040' config_get dns_port trans dns_port '9053' config_get bridges_enabled bridges enabled '0' config_get bridge_type bridges type 'obfs4' config_get exit_nodes security exit_nodes '' config_get exclude_exit_nodes security exclude_exit_nodes '' config_get strict_nodes security strict_nodes '0' mkdir -p "$TOR_RUN" "$TOR_DATA" # Clean up stale files that may have wrong ownership rm -f "$TOR_RUN/tor.pid" "$TOR_RUN/control" "$TOR_RUN/control_auth_cookie" 2>/dev/null rm -f "$TOR_DATA/lock" 2>/dev/null chown tor:tor "$TOR_RUN" "$TOR_DATA" chmod 700 "$TOR_RUN" "$TOR_DATA" cat > "$TORRC" << EOF # SecuBox Tor Shield - Auto-generated config # Do not edit - managed by tor-shield User tor DataDirectory $TOR_DATA Log notice syslog ControlSocket $TOR_RUN/control ControlSocketsGroupWritable 1 CookieAuthentication 1 CookieAuthFile $TOR_RUN/control_auth_cookie CookieAuthFileGroupReadable 1 # SOCKS proxy SocksPort $socks_addr:$socks_port SocksPolicy accept 127.0.0.1 SocksPolicy accept 192.168.0.0/16 SocksPolicy accept 10.0.0.0/8 SocksPolicy reject * EOF # Transparent proxy mode if [ "$mode" = "transparent" ]; then cat >> "$TORRC" << EOF # Transparent proxy TransPort 0.0.0.0:$trans_port EOF fi # DNS over Tor if [ "$dns_over_tor" = "1" ]; then cat >> "$TORRC" << EOF # DNS over Tor DNSPort 0.0.0.0:$dns_port AutomapHostsOnResolve 1 AutomapHostsSuffixes .onion,.exit VirtualAddrNetworkIPv4 10.192.0.0/10 EOF fi # Bridge configuration - only enable if bridges are configured if [ "$bridges_enabled" = "1" ]; then # Count bridge lines first BRIDGE_COUNT=0 count_bridge() { BRIDGE_COUNT=$((BRIDGE_COUNT + 1)); } config_list_foreach bridges bridge_lines count_bridge # Only add UseBridges if there are actual bridges configured if [ "$BRIDGE_COUNT" -gt 0 ]; then cat >> "$TORRC" << EOF # Bridge mode UseBridges 1 EOF # Add bridge lines from config config_list_foreach bridges bridge_lines add_bridge_line fi fi # Exit node restrictions if [ -n "$exit_nodes" ]; then echo "ExitNodes $exit_nodes" >> "$TORRC" fi if [ -n "$exclude_exit_nodes" ]; then echo "ExcludeExitNodes $exclude_exit_nodes" >> "$TORRC" fi if [ "$strict_nodes" = "1" ]; then echo "StrictNodes 1" >> "$TORRC" fi # Hidden services config_foreach add_hidden_service hidden_service # GeoIP files if [ -f /usr/share/tor/geoip ]; then echo "GeoIPFile /usr/share/tor/geoip" >> "$TORRC" fi if [ -f /usr/share/tor/geoip6 ]; then echo "GeoIPv6File /usr/share/tor/geoip6" >> "$TORRC" fi # Ensure torrc is readable by tor user chown tor:tor "$TORRC" } add_bridge_line() { echo "Bridge $1" >> "$TORRC" } add_hidden_service() { local cfg="$1" local enabled name local_port virtual_port config_get enabled "$cfg" enabled '0' [ "$enabled" = "1" ] || return config_get name "$cfg" name "hidden_$cfg" config_get local_port "$cfg" local_port '80' config_get virtual_port "$cfg" virtual_port '80' local hs_dir="$TOR_DATA/hidden_service_$name" mkdir -p "$hs_dir" chown tor:tor "$hs_dir" chmod 700 "$hs_dir" cat >> "$TORRC" << EOF # Hidden Service: $name HiddenServiceDir $hs_dir HiddenServicePort $virtual_port 127.0.0.1:$local_port EOF } setup_iptables() { local mode trans_port dns_port dns_over_tor kill_switch config_load "$CONFIG" config_get mode main mode 'transparent' config_get kill_switch main kill_switch '1' config_get dns_over_tor main dns_over_tor '1' config_get trans_port trans port '9040' config_get dns_port trans dns_port '9053' # Get Tor user ID local tor_uid=$(id -u tor 2>/dev/null || echo "tor") # Remove from chains first (to allow chain deletion) iptables -t nat -D OUTPUT -j TOR_SHIELD 2>/dev/null iptables -t filter -D OUTPUT -j TOR_SHIELD 2>/dev/null iptables -t nat -D PREROUTING -i br-lan -j TOR_SHIELD_LAN 2>/dev/null # Clear existing Tor rules for chain in TOR_SHIELD TOR_SHIELD_LAN; do iptables -t nat -F $chain 2>/dev/null iptables -t nat -X $chain 2>/dev/null done iptables -t filter -F TOR_SHIELD 2>/dev/null iptables -t filter -X TOR_SHIELD 2>/dev/null [ "$mode" = "transparent" ] || return 0 # Create chains (ignore "already exists" errors) iptables -t nat -N TOR_SHIELD 2>/dev/null || true iptables -t filter -N TOR_SHIELD 2>/dev/null || true # Exclude Tor traffic iptables -t nat -A TOR_SHIELD -m owner --uid-owner $tor_uid -j RETURN # Exclude local networks config_list_foreach trans excluded_ips add_excluded_ip # Redirect DNS if enabled if [ "$dns_over_tor" = "1" ]; then iptables -t nat -A TOR_SHIELD -p udp --dport 53 -j REDIRECT --to-ports $dns_port iptables -t nat -A TOR_SHIELD -p tcp --dport 53 -j REDIRECT --to-ports $dns_port fi # Redirect TCP to transparent proxy iptables -t nat -A TOR_SHIELD -p tcp -j REDIRECT --to-ports $trans_port # Add to OUTPUT chain iptables -t nat -A OUTPUT -j TOR_SHIELD # Kill switch - block non-Tor traffic if [ "$kill_switch" = "1" ]; then iptables -t filter -A TOR_SHIELD -m owner --uid-owner $tor_uid -j ACCEPT iptables -t filter -A TOR_SHIELD -d 127.0.0.0/8 -j ACCEPT config_list_foreach trans excluded_ips add_excluded_filter_ip # Allow response packets for inbound connections (HAProxy, etc) iptables -t filter -A TOR_SHIELD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -t filter -A TOR_SHIELD -j REJECT iptables -t filter -A OUTPUT -j TOR_SHIELD fi # LAN client Tor routing via PREROUTING setup_lan_proxy } add_excluded_ip() { iptables -t nat -A TOR_SHIELD -d "$1" -j RETURN } add_excluded_filter_ip() { iptables -t filter -A TOR_SHIELD -d "$1" -j ACCEPT } add_excluded_lan_ip() { iptables -t nat -A TOR_SHIELD_LAN -d "$1" -j RETURN } setup_lan_proxy() { local lan_proxy config_get lan_proxy trans lan_proxy '0' [ "$lan_proxy" = "1" ] || return 0 local trans_port dns_port dns_over_tor config_get trans_port trans port '9040' config_get dns_port trans dns_port '9053' config_get dns_over_tor main dns_over_tor '1' # Create PREROUTING chain iptables -t nat -N TOR_SHIELD_LAN 2>/dev/null || true # Exclude local destinations config_list_foreach trans excluded_ips add_excluded_lan_ip # Redirect DNS if [ "$dns_over_tor" = "1" ]; then iptables -t nat -A TOR_SHIELD_LAN -p udp --dport 53 -j REDIRECT --to-ports $dns_port iptables -t nat -A TOR_SHIELD_LAN -p tcp --dport 53 -j REDIRECT --to-ports $dns_port fi # Redirect TCP to Tor iptables -t nat -A TOR_SHIELD_LAN -p tcp -j REDIRECT --to-ports $trans_port # Apply to LAN interface iptables -t nat -A PREROUTING -i br-lan -j TOR_SHIELD_LAN } remove_iptables() { # Remove from chains iptables -t nat -D OUTPUT -j TOR_SHIELD 2>/dev/null iptables -t filter -D OUTPUT -j TOR_SHIELD 2>/dev/null iptables -t nat -D PREROUTING -i br-lan -j TOR_SHIELD_LAN 2>/dev/null # Flush and remove all chains for chain in TOR_SHIELD TOR_SHIELD_LAN; do iptables -t nat -F $chain 2>/dev/null iptables -t nat -X $chain 2>/dev/null done iptables -t filter -F TOR_SHIELD 2>/dev/null iptables -t filter -X TOR_SHIELD 2>/dev/null } start_service() { local enabled config_load "$CONFIG" config_get enabled main enabled '0' [ "$enabled" = "1" ] || { echo "Tor Shield is disabled. Enable with: uci set tor-shield.main.enabled=1" return 0 } # Generate torrc generate_torrc # Setup iptables rules setup_iptables # Start Tor via procd procd_open_instance tor procd_set_param command /usr/sbin/tor -f "$TORRC" procd_set_param respawn 3600 5 5 procd_set_param stdout 1 procd_set_param stderr 1 procd_set_param pidfile "$TOR_RUN/tor.pid" procd_close_instance } stop_service() { # Remove iptables rules remove_iptables # Kill tor process if [ -f "$TOR_RUN/tor.pid" ]; then kill $(cat "$TOR_RUN/tor.pid") 2>/dev/null rm -f "$TOR_RUN/tor.pid" fi } service_triggers() { procd_add_reload_trigger "$CONFIG" } reload_service() { stop start } restart_service() { stop start } status() { "$PROG" status }