mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-09 21:17:03 +03:00
refactor: Refactoring list_update function
This commit is contained in:
@@ -33,7 +33,8 @@ TEST_DOMAIN="fakeip.podkop.fyi"
|
||||
INTERFACES_LIST=""
|
||||
SRC_INTERFACE=""
|
||||
RESOLV_CONF="/etc/resolv.conf"
|
||||
TMP_FOLDER="/tmp/podkop"
|
||||
TMP_SING_BOX_FOLDER="/tmp/sing-box"
|
||||
TMP_RULESET_FOLDER="$TMP_SING_BOX_FOLDER/rulesets"
|
||||
|
||||
# Endpoints https://github.com/ampetelin/warp-endpoint-checker
|
||||
CLOUDFLARE_OCTETS="8.47 162.159 188.114"
|
||||
@@ -97,8 +98,8 @@ start_main() {
|
||||
|
||||
sleep 1
|
||||
|
||||
mkdir -p /tmp/podkop
|
||||
mkdir -p /tmp/sing-box
|
||||
mkdir -p "$TMP_SING_BOX_FOLDER"
|
||||
mkdir -p "$TMP_RULESET_FOLDER"
|
||||
|
||||
# base
|
||||
route_table_rule_mark
|
||||
@@ -110,25 +111,7 @@ start_main() {
|
||||
sing_box_config_check
|
||||
config_foreach add_cron_job
|
||||
/etc/init.d/sing-box start
|
||||
# sing_box_inbound_proxy 1602 #refactored
|
||||
# sing_box_dns #refactored
|
||||
# sing_box_dns_rule_fakeip #refactored
|
||||
# sing_box_rule_dns #refactored
|
||||
# sing_box_create_bypass_ruleset #refactored
|
||||
# sing_box_add_secure_dns_probe_domain #refactored
|
||||
# sing_box_cache_file #refactored
|
||||
# process_socks5 #refactored
|
||||
#
|
||||
# # sing-box outbounds and rules
|
||||
# config_foreach sing_box_outdound #refactored
|
||||
# config_foreach process_domains_for_section #refactored, implementation is needed
|
||||
# config_foreach sing_box_rule_preset #refactored
|
||||
# config_foreach process_domains_list_local #refactored, implementation is needed
|
||||
# config_foreach process_subnet_for_section #refactored, implementation is needed
|
||||
# config_foreach configure_community_lists #refactored
|
||||
# config_foreach configure_remote_domain_lists #refactored
|
||||
# config_foreach configure_remote_subnet_lists #refactored
|
||||
# config_foreach process_all_traffic_for_section #refactored
|
||||
|
||||
local exclude_ntp
|
||||
config_get_bool exclude_ntp "main" "exclude_ntp" "0"
|
||||
if [ "$exclude_ntp" -eq 1 ]; then
|
||||
@@ -136,10 +119,10 @@ start_main() {
|
||||
nft insert rule inet PodkopTable mangle udp dport 123 return
|
||||
fi
|
||||
|
||||
# TODO(ampetelin): refactoring is needed
|
||||
# list_update &
|
||||
# echo $! > /var/run/podkop_list_update.pid
|
||||
log "Nice"
|
||||
# TODO(ampetelin): refactoring is needed
|
||||
list_update &
|
||||
echo $! > /var/run/podkop_list_update.pid
|
||||
}
|
||||
|
||||
start() {
|
||||
@@ -171,7 +154,7 @@ stop_main() {
|
||||
|
||||
remove_cron_job
|
||||
|
||||
rm -rf /tmp/podkop/*.lst
|
||||
rm "$TMP_RULESET_FOLDER"/*
|
||||
|
||||
log "Flush nft"
|
||||
if nft list table inet PodkopTable >/dev/null 2>&1; then
|
||||
@@ -190,7 +173,6 @@ stop_main() {
|
||||
|
||||
log "Stop sing-box"
|
||||
/etc/init.d/sing-box stop
|
||||
#/etc/init.d/sing-box disable
|
||||
}
|
||||
|
||||
stop() {
|
||||
@@ -554,7 +536,6 @@ remove_cron_job() {
|
||||
log "The cron job removed"
|
||||
}
|
||||
|
||||
# TODO(ampetelin): refactoring is needed
|
||||
list_update() {
|
||||
echolog "🔄 Starting lists update..."
|
||||
|
||||
@@ -849,6 +830,7 @@ sing_box_configure_route() {
|
||||
config=$(sing_box_cf_override_domain_port "$config" "$TEST_DOMAIN" 8443)
|
||||
|
||||
config_foreach include_source_ips_in_routing_handler
|
||||
|
||||
# TODO(ampetelin): Add block rules
|
||||
|
||||
local exclude_from_ip_enabled
|
||||
@@ -937,6 +919,7 @@ configure_routing_for_section_lists() {
|
||||
|
||||
if [ "$remote_domain_lists_enabled" -eq 1 ]; then
|
||||
log "Processing remote domains routing rules for $section section"
|
||||
prepare_common_ruleset "$section" "domains" "route_rule_tag"
|
||||
config_list_foreach "$section" "remote_domain_lists" configure_remote_domain_or_subnet_list_handler \
|
||||
"domains" "$section" "$route_rule_tag"
|
||||
fi
|
||||
@@ -954,11 +937,30 @@ configure_routing_for_section_lists() {
|
||||
|
||||
if [ "$remote_subnet_lists_enabled" -eq 1 ]; then
|
||||
log "Processing remote subnets routing rules for $section section"
|
||||
prepare_common_ruleset "$section" "subnets" "route_rule_tag"
|
||||
config_list_foreach "$section" "remote_subnet_lists" configure_remote_domain_or_subnet_list_handler \
|
||||
"subnets" "$section" "$route_rule_tag"
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_common_ruleset() {
|
||||
local section="$1"
|
||||
local type="$2"
|
||||
local route_rule_tag="$3"
|
||||
|
||||
log "Preparing a common $type ruleset for $section section" "debug"
|
||||
ruleset_tag=$(get_ruleset_tag "$section" "common" "remote-$type")
|
||||
ruleset_filename="$ruleset_tag.json"
|
||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
||||
if file_exists "$ruleset_filepath"; then
|
||||
log "Ruleset $ruleset_filepath already exists. Skipping." "debug"
|
||||
else
|
||||
sing_box_cm_create_local_source_ruleset "$ruleset_filepath"
|
||||
config=$(sing_box_cm_add_local_ruleset "$config" "$ruleset_tag" "source" "$ruleset_filepath")
|
||||
config=$(sing_box_cm_patch_route_rule "$config" "$route_rule_tag" "rule_set" "$ruleset_tag")
|
||||
fi
|
||||
}
|
||||
|
||||
configure_community_list_handler() {
|
||||
local tag="$1"
|
||||
local section="$2"
|
||||
@@ -989,7 +991,7 @@ configure_local_domain_or_subnet_lists() {
|
||||
local ruleset_tag ruleset_filename ruleset_filepath
|
||||
ruleset_tag="$(get_ruleset_tag "$section" "local" "$type")"
|
||||
ruleset_filename="$ruleset_tag.json"
|
||||
ruleset_filepath="$TMP_FOLDER/$ruleset_filename"
|
||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
||||
|
||||
sing_box_cm_create_local_source_ruleset "$ruleset_filepath"
|
||||
config=$(sing_box_cm_add_local_ruleset "$config" "$ruleset_tag" "source" "$ruleset_filepath")
|
||||
@@ -1018,44 +1020,19 @@ import_local_domain_or_subnet_list() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
local items=""
|
||||
while IFS= read -r item; do
|
||||
if [ -z "$item" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
case "$type" in
|
||||
domains)
|
||||
if ! is_domain "$item"; then
|
||||
log "$item is not domain" "debug"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
subnets)
|
||||
if ! is_ipv4 "$item" && ! is_ipv4_cidr "$item"; then
|
||||
log "$item is not IPv4 IP or CIDR" "debug"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$items" ]; then
|
||||
items="$item"
|
||||
else
|
||||
items="$items,$item"
|
||||
fi
|
||||
done < "$filepath"
|
||||
local items json_array
|
||||
items="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "domains")"
|
||||
|
||||
if [ -z "$items" ]; then
|
||||
log "No valid $type found in $filepath"
|
||||
return 0
|
||||
fi
|
||||
|
||||
items_json="$(comma_string_to_json_array "$items")"
|
||||
json_array="$(comma_string_to_json_array "$items")"
|
||||
case "$type" in
|
||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$items_json" ;;
|
||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array" ;;
|
||||
subnets)
|
||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$items_json"
|
||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_GENERAL_SET_NAME" "$items"
|
||||
;;
|
||||
esac
|
||||
@@ -1068,11 +1045,10 @@ configure_remote_domain_or_subnet_list_handler() {
|
||||
local route_rule_tag="$4"
|
||||
|
||||
local file_extension
|
||||
file_extension=$(get_url_file_extension "$url")
|
||||
file_extension=$(url_get_file_extension "$url")
|
||||
case "$file_extension" in
|
||||
json|srs)
|
||||
log "Detected file extension: .$file_extension → proceeding with processing" "debug"
|
||||
|
||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
||||
local basename ruleset_tag format detour update_interval
|
||||
basename=$(url_get_basename "$url")
|
||||
ruleset_tag=$(get_ruleset_tag "$section" "$basename" "remote-$type")
|
||||
@@ -1082,17 +1058,17 @@ configure_remote_domain_or_subnet_list_handler() {
|
||||
|
||||
config=$(sing_box_cm_add_remote_ruleset "$config" "$ruleset_tag" "$format" "$url" "$detour" "$update_interval")
|
||||
config=$(sing_box_cm_patch_route_rule "$config" "$route_rule_tag" "rule_set" "$ruleset_tag")
|
||||
;;
|
||||
*)
|
||||
log "Detected file extension: '$file_extension' → no processing needed, managed on list_update" "debug"
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$type" in
|
||||
domains) _add_ruleset_to_dns_rules "$ruleset_tag" "$route_rule_tag" ;;
|
||||
subnets) ;;
|
||||
*) log "Unsupported remote rule set type: $type" "warn" ;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
log "Detected file extension: .$file_extension → no processing needed, managed on list_update" "debug"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
configure_user_subnet_list_handler() {
|
||||
@@ -1191,48 +1167,23 @@ sing_box_config_check() {
|
||||
local sing_box_config_path
|
||||
config_get sing_box_config_path "main" "config_path"
|
||||
if ! sing-box -c "$sing_box_config_path" check >/dev/null 2>&1; then
|
||||
log "Sing-box configuration is invalid" "[fatal]"
|
||||
log "Sing-box configuration is invalid" "fatal"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
sing_box_ruleset_domains_json() {
|
||||
local domain="$1"
|
||||
local section="$2"
|
||||
|
||||
local file="/tmp/podkop/$section-custom-domains-subnets.json"
|
||||
|
||||
jq --arg domain "$domain" '
|
||||
.rules[0].domain_suffix += if .rules[0].domain_suffix | index($domain) then [] else [$domain] end
|
||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
|
||||
log "$domain added to $section-custom-domains-subnets.json"
|
||||
}
|
||||
|
||||
sing_box_ruleset_subnets_json() {
|
||||
local subnet="$1"
|
||||
local section="$2"
|
||||
|
||||
local file="/tmp/podkop/$section-custom-domains-subnets.json"
|
||||
|
||||
jq --arg subnet "$subnet" '
|
||||
.rules[0].ip_cidr += if .rules[0].ip_cidr | index($subnet) then [] else [$subnet] end
|
||||
' "$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||
|
||||
log "$subnet added to $section-custom-domains-subnets.json"
|
||||
}
|
||||
|
||||
import_community_subnet_lists() {
|
||||
config_get_bool domain_list_enabled "$section" "domain_list_enabled" "0"
|
||||
if [ "$domain_list_enabled" -eq 1 ]; then
|
||||
local section="$1"
|
||||
local community_lists_enabled
|
||||
config_get_bool community_lists_enabled "$section" "community_lists_enabled" 0
|
||||
if [ "$community_lists_enabled" -eq 1 ]; then
|
||||
log "Importing community subnet lists for $section section"
|
||||
config_list_foreach "$section" domain_list import_community_service_subnet_list_handler
|
||||
config_list_foreach "$section" "community_lists" import_community_service_subnet_list_handler
|
||||
fi
|
||||
}
|
||||
|
||||
import_community_service_subnet_list_handler() {
|
||||
local service="$1"
|
||||
local table="PodkopTable"
|
||||
|
||||
case "$service" in
|
||||
"twitter")
|
||||
@@ -1261,39 +1212,41 @@ import_community_service_subnet_list_handler() {
|
||||
;;
|
||||
"discord")
|
||||
URL=$SUBNETS_DISCORD
|
||||
nft add set inet $table podkop_discord_subnets { type ipv4_addr\; flags interval\; auto-merge\; }
|
||||
nft add rule inet $table mangle iifname "$SRC_INTERFACE" ip daddr @podkop_discord_subnets udp dport { 50000-65535 } meta mark set 0x105 counter
|
||||
;;
|
||||
*)
|
||||
return
|
||||
nft_create_ipv4_set "$NFT_TABLE_NAME" "$NFT_DISCORD_SET_NAME"
|
||||
nft add rule inet "$NFT_TABLE_NAME" mangle iifname "$SRC_INTERFACE" ip daddr @podkop_discord_subnets \
|
||||
udp dport '{ 50000-65535 }' meta mark set 0x105 counter
|
||||
;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
|
||||
local filename=$(basename "$URL")
|
||||
local tmpfile detour http_proxy_address subnets
|
||||
tmpfile=$(mktemp)
|
||||
http_proxy_address="$(get_service_proxy_address)"
|
||||
|
||||
config_get_bool detour "main" "detour" "0"
|
||||
if [ "$detour" -eq 1 ]; then
|
||||
http_proxy="http://127.0.0.1:4534" https_proxy="http://127.0.0.1:4534" wget -O "/tmp/podkop/$filename" "$URL"
|
||||
else
|
||||
wget -O "/tmp/podkop/$filename" "$URL"
|
||||
download_to_tempfile "$URL" "$tmpfile" "$http_proxy_address"
|
||||
|
||||
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
||||
log "Download $service list failed" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
while IFS= read -r subnet; do
|
||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "subnets")"
|
||||
rm -f "$tmpfile"
|
||||
|
||||
if [ "$service" = "discord" ]; then
|
||||
nft add element inet $table podkop_discord_subnets { $subnet }
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_DISCORD_SET_NAME" "$subnets"
|
||||
else
|
||||
nft add element inet $table podkop_subnets { $subnet }
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_GENERAL_SET_NAME" "$subnets"
|
||||
fi
|
||||
done <"/tmp/podkop/$filename"
|
||||
}
|
||||
|
||||
import_domains_from_remote_domain_lists() {
|
||||
local section="$1"
|
||||
|
||||
config_get custom_download_domains_list_enabled "$section" custom_download_domains_list_enabled
|
||||
if [ "$custom_download_domains_list_enabled" -eq 1 ]; then
|
||||
local remote_domain_lists_enabled
|
||||
config_get remote_domain_lists_enabled "$section" "remote_domain_lists_enabled"
|
||||
if [ "$remote_domain_lists_enabled" -eq 1 ]; then
|
||||
log "Importing domains from remote domain lists for $section section"
|
||||
config_list_foreach "$section" custom_download_domains import_domains_from_remote_domain_list_handler "$section"
|
||||
config_list_foreach "$section" "remote_domain_lists" import_domains_from_remote_domain_list_handler "$section"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1304,42 +1257,25 @@ import_domains_from_remote_domain_list_handler() {
|
||||
log "Importing domains from URL: $url"
|
||||
|
||||
local file_extension
|
||||
file_extension=$(get_url_file_extension "$url")
|
||||
file_extension=$(url_get_file_extension "$url")
|
||||
case "$file_extension" in
|
||||
json|srs)
|
||||
log "Detected file extension: .$file_extension → no update needed, sing-box manages updates"
|
||||
log "Detected file extension: '$file_extension' → no update needed, sing-box manages updates" "debug"
|
||||
;;
|
||||
*)
|
||||
log "Detected file extension: .$file_extension → proceeding with processing"
|
||||
import_domains_from_remote_lst_file "$url" "$section"
|
||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
||||
import_domains_or_subnets_from_remote_file "$url" "$section" "domains"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
import_domains_from_remote_lst_file() {
|
||||
local url="$1"
|
||||
local section="$2"
|
||||
|
||||
local filename
|
||||
filename=$(basename "$url")
|
||||
local filepath="/tmp/podkop/${filename}"
|
||||
|
||||
download_to_tempfile "$url" "$filepath"
|
||||
|
||||
while IFS= read -r domain; do
|
||||
sing_box_ruleset_domains_json $domain $section
|
||||
done <"$filepath"
|
||||
|
||||
rm -f "$filepath"
|
||||
}
|
||||
|
||||
import_subnets_from_remote_subnet_lists() {
|
||||
local section="$1"
|
||||
|
||||
config_get custom_download_subnets_list_enabled "$section" custom_download_subnets_list_enabled disabled
|
||||
if [ "$custom_download_subnets_list_enabled" -eq "1" ]; then
|
||||
config_get remote_subnet_lists_enabled "$section" "remote_subnet_lists_enabled"
|
||||
if [ "$remote_subnet_lists_enabled" -eq 1 ]; then
|
||||
log "Importing subnets from remote subnet lists for $section section"
|
||||
config_list_foreach "$section" custom_download_subnets import_subnets_from_remote_subnet_list_handler "$section"
|
||||
config_list_foreach "$section" "remote_subnet_lists" import_subnets_from_remote_subnet_list_handler "$section"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1350,91 +1286,111 @@ import_subnets_from_remote_subnet_list_handler() {
|
||||
log "Importing subnets from URL: $url"
|
||||
|
||||
local file_extension
|
||||
file_extension=$(get_url_file_extension "$url")
|
||||
file_extension="$(url_get_file_extension "$url")"
|
||||
case "$file_extension" in
|
||||
lst)
|
||||
log "Detected file extension: .$file_extension → proceeding with processing"
|
||||
import_subnets_from_remote_lst_file "$url" "$section"
|
||||
;;
|
||||
json)
|
||||
log "Detected file extension: .$file_extension → proceeding with processing"
|
||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
||||
import_subnets_from_remote_json_file "$url"
|
||||
;;
|
||||
srs)
|
||||
log "Detected file extension: .$file_extension → proceeding with processing"
|
||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
||||
import_subnets_from_remote_srs_file "$url"
|
||||
;;
|
||||
*)
|
||||
log "Detected file extension: .$file_extension → unsupported, skipping"
|
||||
return 1
|
||||
log "Detected file extension: '$file_extension' → proceeding with processing" "debug"
|
||||
import_domains_or_subnets_from_remote_file "$url" "$section" "subnets"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
import_subnets_from_remote_lst_file() {
|
||||
import_domains_or_subnets_from_remote_file() {
|
||||
local url="$1"
|
||||
local section="$2"
|
||||
local type="$3"
|
||||
|
||||
local filename
|
||||
filename=$(basename "$url")
|
||||
local filepath="/tmp/podkop/${filename}"
|
||||
local tmpfile http_proxy_address items json_array
|
||||
tmpfile=$(mktemp)
|
||||
http_proxy_address="$(get_service_proxy_address)"
|
||||
|
||||
download_to_tempfile "$url" "$filepath"
|
||||
download_to_tempfile "$url" "$tmpfile" "$http_proxy_address"
|
||||
|
||||
while IFS= read -r subnet; do
|
||||
sing_box_ruleset_subnets_json "$subnet" "$section"
|
||||
nft_add_podkop_subnet "$subnet"
|
||||
done <"$filepath"
|
||||
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
||||
log "Download $url list failed" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -f "$filepath"
|
||||
items="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "$type")"
|
||||
rm -f "$tmpfile"
|
||||
|
||||
if [ -z "$items" ]; then
|
||||
log "No valid $type found in $url"
|
||||
return 0
|
||||
fi
|
||||
|
||||
ruleset_tag=$(get_ruleset_tag "$section" "common" "remote-$type")
|
||||
ruleset_filename="$ruleset_tag.json"
|
||||
ruleset_filepath="$TMP_RULESET_FOLDER/$ruleset_filename"
|
||||
json_array="$(comma_string_to_json_array "$items")"
|
||||
case "$type" in
|
||||
domains) sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "domain_suffix" "$json_array";;
|
||||
subnets)
|
||||
sing_box_cm_patch_local_source_ruleset_rules "$ruleset_filepath" "ip_cidr" "$json_array"
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_GENERAL_SET_NAME" "$items"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
import_subnets_from_remote_json_file() {
|
||||
local url="$1"
|
||||
local tmpfile subnets
|
||||
tmpfile="$(mktemp)"
|
||||
|
||||
download_to_stream "$url" | jq -r '.rules[].ip_cidr[]?' | while read -r subnet; do
|
||||
nft_add_podkop_subnet "$subnet"
|
||||
done
|
||||
download_to_stream "$url" | jq -r '.rules[].ip_cidr[]?' > "$tmpfile"
|
||||
|
||||
if [ $? -ne 0 ] || [ ! -s "$tmpfile" ]; then
|
||||
log "Download $url list failed" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$tmpfile" "subnets")"
|
||||
rm -f "$tmpfile"
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_GENERAL_SET_NAME" "$subnets"
|
||||
}
|
||||
|
||||
import_subnets_from_remote_srs_file() {
|
||||
local url="$1"
|
||||
|
||||
local filename
|
||||
filename=$(basename "$url")
|
||||
local binary_filepath="/tmp/podkop/${filename}"
|
||||
local json_filepath="/tmp/podkop/decompiled-${filename%%.*}.json"
|
||||
local binary_tmpfile json_tmpfile subnets_tmpfile subnets
|
||||
binary_tmpfile="$(mktemp)"
|
||||
json_tmpfile="$(mktemp)"
|
||||
subnets_tmpfile="$(mktemp)"
|
||||
|
||||
download_to_tempfile "$url" "$binary_filepath"
|
||||
download_to_tempfile "$url" "$binary_tmpfile"
|
||||
|
||||
if ! decompile_srs_file "$binary_filepath" "$json_filepath"; then
|
||||
if [ $? -ne 0 ] || [ ! -s "$binary_tmpfile" ]; then
|
||||
log "Download $url list failed" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
jq -r '.rules[].ip_cidr[]' "$json_filepath" | while read -r subnet; do
|
||||
nft_add_podkop_subnet "$subnet"
|
||||
done
|
||||
if ! decompile_srs_file "$binary_tmpfile" "$json_tmpfile"; then
|
||||
log "Failed to decompile SRS file" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -f "$binary_filepath" "$json_filepath"
|
||||
jq -r '.rules[].ip_cidr[]' "$json_tmpfile" > "$subnets_tmpfile"
|
||||
subnets="$(parse_domain_or_subnet_file_to_comma_string "$subnets_tmpfile" "subnets")"
|
||||
rm -f "$binary_tmpfile" "$json_tmpfile" "$subnets_tmpfile"
|
||||
nft_add_set_elements "$NFT_TABLE_NAME" "$NFT_GENERAL_SET_NAME" "$subnets"
|
||||
}
|
||||
|
||||
## Support functions
|
||||
# Decompiles a sing-box SRS binary file into a JSON ruleset file
|
||||
decompile_srs_file() {
|
||||
local binary_filepath="$1"
|
||||
local output_filepath="$2"
|
||||
|
||||
log "Decompiling $binary_filepath to $output_filepath"
|
||||
|
||||
if ! file_exists "$binary_filepath"; then
|
||||
log "File $binary_filepath not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "Decompilation command failed for $binary_filepath"
|
||||
return 1
|
||||
get_service_proxy_address() {
|
||||
local detour
|
||||
config_get_bool detour "main" "detour" 0
|
||||
if [ "$detour" -eq 1 ]; then
|
||||
echo "$SB_SERVICE_MIXED_INBOUND_TAG:$SB_SERVICE_MIXED_INBOUND_PORT"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1449,17 +1405,6 @@ nft_list_all_traffic_from_ip() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Adds an IPv4 subnet to nftables firewall set
|
||||
nft_add_podkop_subnet() {
|
||||
local subnet="$1"
|
||||
|
||||
if is_ipv4_cidr "$subnet"; then
|
||||
nft add element inet PodkopTable podkop_subnets { "$subnet" }
|
||||
else
|
||||
log "Invalid subnet format. $subnet is not a valid IPv4 CIDR"
|
||||
fi
|
||||
}
|
||||
|
||||
# Diagnotics
|
||||
check_proxy() {
|
||||
local sing_box_config_path
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
## nft
|
||||
NFT_TABLE_NAME="PodkopTable"
|
||||
NFT_GENERAL_SET_NAME="podkop_subnets"
|
||||
NFT_DISCORD_SET_NAME="podkop_discord_subnets"
|
||||
|
||||
## sing-box
|
||||
# Log
|
||||
|
||||
@@ -12,6 +12,10 @@ is_ipv4_cidr() {
|
||||
[[ "$ip" =~ $regex ]]
|
||||
}
|
||||
|
||||
is_ipv4_ip_or_ipv4_cidr() {
|
||||
is_ipv4 "$1" || is_ipv4_cidr "$1"
|
||||
}
|
||||
|
||||
# Check if string is valid domain
|
||||
is_domain() {
|
||||
local str="$1"
|
||||
@@ -39,14 +43,6 @@ file_exists() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Extracts and returns the file extension from the given URL
|
||||
get_url_file_extension() {
|
||||
local url="$1"
|
||||
local file_extension="${url##*.}"
|
||||
|
||||
echo "$file_extension"
|
||||
}
|
||||
|
||||
# Returns the inbound tag name by appending the postfix to the given section
|
||||
get_inbound_tag_by_section() {
|
||||
local section="$1"
|
||||
@@ -155,6 +151,17 @@ url_get_basename() {
|
||||
echo "$basename"
|
||||
}
|
||||
|
||||
# Extracts and returns the file extension from the given URL
|
||||
url_get_file_extension() {
|
||||
local url="$1"
|
||||
|
||||
local basename="${url##*/}"
|
||||
case "$basename" in
|
||||
*.*) echo "${basename##*.}" ;;
|
||||
*) echo "" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Decodes and returns a base64-encoded string
|
||||
base64_decode() {
|
||||
local str="$1"
|
||||
@@ -205,29 +212,108 @@ migration_rename_config_key() {
|
||||
# Download URL content directly
|
||||
download_to_stream() {
|
||||
local url="$1"
|
||||
local http_proxy_url="$2"
|
||||
local http_proxy_address="$2"
|
||||
local retries="${3:-3}"
|
||||
local wait="${4:-2}"
|
||||
|
||||
for attempt in $(seq 1 "$retries"); do
|
||||
if [ -n "$http_proxy_url" ]; then
|
||||
http_proxy="$http_proxy_url" https_proxy="$http_proxy_url" wget -qO- "$url" | sed 's/\r$//'
|
||||
http_proxy="http://$http_proxy_address" https_proxy="http://$http_proxy_address" wget -qO- "$url" | sed 's/\r$//' && break
|
||||
else
|
||||
wget -qO- "$url" | sed 's/\r$//'
|
||||
wget -qO- "$url" | sed 's/\r$//' && break
|
||||
fi
|
||||
|
||||
log "Attempt $attempt/$retries to download $url failed" "warn"
|
||||
sleep "$wait"
|
||||
done
|
||||
}
|
||||
|
||||
# Download URL to temporary file
|
||||
download_to_tempfile() {
|
||||
local url="$1"
|
||||
local filepath="$2"
|
||||
local http_proxy_url="$3"
|
||||
local http_proxy_address="$3"
|
||||
local retries="${4:-3}"
|
||||
local wait="${5:-2}"
|
||||
|
||||
for attempt in $(seq 1 "$retries"); do
|
||||
if [ -n "$http_proxy_url" ]; then
|
||||
http_proxy="$http_proxy_url" https_proxy="$http_proxy_url" wget -O "$filepath" "$url"
|
||||
http_proxy="http://$http_proxy_address" https_proxy="http://$http_proxy_url" wget -O "$filepath" "$url" && break
|
||||
else
|
||||
wget -O "$filepath" "$url"
|
||||
wget -O "$filepath" "$url" && break
|
||||
fi
|
||||
|
||||
log "Attempt $attempt/$retries to download $url failed" "warn"
|
||||
sleep "$wait"
|
||||
done
|
||||
|
||||
if grep -q $'\r' "$filepath"; then
|
||||
log "$filename has Windows line endings (CRLF). Converting to Unix (LF)"
|
||||
sed -i 's/\r$//' "$filepath"
|
||||
fi
|
||||
}
|
||||
|
||||
# Decompiles a sing-box SRS binary file into a JSON ruleset file
|
||||
decompile_srs_file() {
|
||||
local binary_filepath="$1"
|
||||
local output_filepath="$2"
|
||||
|
||||
log "Decompiling $binary_filepath to $output_filepath" "debug"
|
||||
|
||||
if ! file_exists "$binary_filepath"; then
|
||||
log "File $binary_filepath not found" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sing-box rule-set decompile "$binary_filepath" -o "$output_filepath"
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "Decompilation command failed for $binary_filepath" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#######################################
|
||||
# Parses a file line by line, validates entries as either domains or subnets,
|
||||
# and returns a single comma-separated string of valid items.
|
||||
# Arguments:
|
||||
# $1 - Path to the input file
|
||||
# $2 - Type of validation ("domains" or "subnets")
|
||||
# Outputs:
|
||||
# Comma-separated string of valid domains or subnets
|
||||
#######################################
|
||||
parse_domain_or_subnet_file_to_comma_string() {
|
||||
local filepath="$1"
|
||||
local type="$2"
|
||||
|
||||
local result
|
||||
while IFS= read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
|
||||
case "$type" in
|
||||
domains)
|
||||
if ! is_domain "$line"; then
|
||||
log "'$line' is not a valid domain" "debug"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
subnets)
|
||||
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
|
||||
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log "Unknown type: $type" "error"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$result" ]; then
|
||||
result="$line"
|
||||
else
|
||||
result="$result,$line"
|
||||
fi
|
||||
done < "$filepath"
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
Reference in New Issue
Block a user