From ad8d25256d4c1c636ed454ff298368e2cd7e2762 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Wed, 28 Jan 2026 13:41:07 +0100 Subject: [PATCH] feat(tor-shield): Add excluded destinations for direct/CDN access - Add get_excluded_destinations() method to list bypassed destinations - Add add_excluded_destination() to exclude IPs/CIDRs/domains from Tor - Add remove_excluded_destination() to remove exclusions - Add apply_exclusions() to restart tor-shield with new rules - Domain resolution attempts to get IP for iptables compatibility - Existing private network CIDRs (192.168/10/172.16/127) are default excluded Also includes metablogizer fixes: - reload_haproxy() helper function - Server address uses 127.0.0.1 for uhttpd backends - fix_permissions() on file uploads PKG_RELEASE: tor-shield=3, metablogizer=3 Co-Authored-By: Claude Opus 4.5 --- package/secubox/luci-app-tor-shield/Makefile | 2 +- .../root/usr/libexec/rpcd/luci.tor-shield | 136 +++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/package/secubox/luci-app-tor-shield/Makefile b/package/secubox/luci-app-tor-shield/Makefile index f7e9b9fc..2abea598 100644 --- a/package/secubox/luci-app-tor-shield/Makefile +++ b/package/secubox/luci-app-tor-shield/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-tor-shield PKG_VERSION:=1.0.0 -PKG_RELEASE:=2 +PKG_RELEASE:=3 PKG_ARCH:=all PKG_LICENSE:=MIT diff --git a/package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield b/package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield index 04a04d05..a154e47c 100755 --- a/package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield +++ b/package/secubox/luci-app-tor-shield/root/usr/libexec/rpcd/luci.tor-shield @@ -696,6 +696,128 @@ add_excluded_ip_json() { json_add_string "" "$1" } +# Get excluded destinations (bypasses Tor, served directly or via CDN) +get_excluded_destinations() { + json_init + json_add_array "destinations" + + config_load "$CONFIG" + + # Get excluded IPs/CIDRs + local idx=0 + add_excluded_dest_json() { + local dest="$1" + json_add_object + json_add_int "id" "$idx" + json_add_string "destination" "$dest" + # Detect type + if echo "$dest" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$'; then + json_add_string "type" "cidr" + elif echo "$dest" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then + json_add_string "type" "ip" + else + json_add_string "type" "domain" + fi + json_close_object + idx=$((idx + 1)) + } + + config_list_foreach trans excluded_ips add_excluded_dest_json + + json_close_array + json_dump +} + +# Add excluded destination +add_excluded_destination() { + read input + json_load "$input" + + local destination + json_get_var destination destination + + json_init + + if [ -z "$destination" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Destination is required" + json_dump + return + fi + + # Ensure trans section exists + uci -q get tor-shield.trans >/dev/null 2>&1 || { + uci set tor-shield.trans=transparent + uci set tor-shield.trans.port='9040' + uci set tor-shield.trans.dns_port='9053' + } + + # Resolve domain to IP if it's a domain (not an IP or CIDR) + local resolved="" + if ! echo "$destination" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'; then + # It's a domain, try to resolve it to IP for better iptables compatibility + # nslookup output varies, try multiple patterns + local nslookup_out=$(nslookup "$destination" 2>/dev/null) + resolved=$(echo "$nslookup_out" | grep -E "^Address.*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | grep -v "127.0.0.1" | grep -v "#53" | head -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+') + fi + + # Add to excluded list + uci add_list tor-shield.trans.excluded_ips="$destination" + + # Also add resolved IP if domain was given and valid IP was resolved + if [ -n "$resolved" ] && echo "$resolved" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then + uci add_list tor-shield.trans.excluded_ips="$resolved" + fi + + uci commit tor-shield + + json_add_boolean "success" 1 + json_add_string "destination" "$destination" + [ -n "$resolved" ] && json_add_string "resolved_ip" "$resolved" + json_add_string "message" "Destination excluded from Tor" + + json_dump +} + +# Remove excluded destination +remove_excluded_destination() { + read input + json_load "$input" + + local destination + json_get_var destination destination + + json_init + + if [ -z "$destination" ]; then + json_add_boolean "success" 0 + json_add_string "error" "Destination is required" + json_dump + return + fi + + uci del_list tor-shield.trans.excluded_ips="$destination" 2>/dev/null + uci commit tor-shield + + json_add_boolean "success" 1 + json_add_string "message" "Destination removed from exclusion list" + + json_dump +} + +# Apply exclusions (restart iptables rules) +apply_exclusions() { + json_init + + # Restart tor-shield to apply new iptables rules + /etc/init.d/tor-shield restart >/dev/null 2>&1 & + + json_add_boolean "success" 1 + json_add_string "message" "Exclusions applied, Tor Shield restarting" + + json_dump +} + # Save settings save_settings() { read input @@ -773,7 +895,7 @@ do_restart() { case "$1" in list) - echo '{"status":{},"enable":{"preset":"str"},"disable":{},"restart":{},"circuits":{},"new_identity":{},"check_leaks":{},"hidden_services":{},"add_hidden_service":{"name":"str","local_port":"int","virtual_port":"int"},"remove_hidden_service":{"name":"str"},"exit_ip":{},"refresh_ips":{},"bandwidth":{},"presets":{},"bridges":{},"set_bridges":{"enabled":"bool","type":"str"},"settings":{},"save_settings":{"mode":"str","dns_over_tor":"bool","kill_switch":"bool","socks_port":"int","trans_port":"int","dns_port":"int","exit_nodes":"str","exclude_exit_nodes":"str","strict_nodes":"bool"}}' + echo '{"status":{},"enable":{"preset":"str"},"disable":{},"restart":{},"circuits":{},"new_identity":{},"check_leaks":{},"hidden_services":{},"add_hidden_service":{"name":"str","local_port":"int","virtual_port":"int"},"remove_hidden_service":{"name":"str"},"exit_ip":{},"refresh_ips":{},"bandwidth":{},"presets":{},"bridges":{},"set_bridges":{"enabled":"bool","type":"str"},"settings":{},"save_settings":{"mode":"str","dns_over_tor":"bool","kill_switch":"bool","socks_port":"int","trans_port":"int","dns_port":"int","exit_nodes":"str","exclude_exit_nodes":"str","strict_nodes":"bool"},"excluded_destinations":{},"add_excluded_destination":{"destination":"str"},"remove_excluded_destination":{"destination":"str"},"apply_exclusions":{}}' ;; call) case "$2" in @@ -831,6 +953,18 @@ case "$1" in save_settings) save_settings ;; + excluded_destinations) + get_excluded_destinations + ;; + add_excluded_destination) + add_excluded_destination + ;; + remove_excluded_destination) + remove_excluded_destination + ;; + apply_exclusions) + apply_exclusions + ;; *) echo '{"error": "Unknown method"}' ;;