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 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-28 13:41:07 +01:00
parent e079014dfb
commit 70187a7c45
2 changed files with 136 additions and 2 deletions

View File

@ -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

View File

@ -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"}'
;;