mirror of
https://github.com/itdoginfo/podkop.git
synced 2025-12-14 07:26:51 +03:00
feat: Add support for DoH URLs with paths and UDP port specification
This commit is contained in:
@@ -50,20 +50,10 @@ function createAdditionalSection(mainSection, network) {
|
|||||||
return _('DNS server address cannot be empty');
|
return _('DNS server address cannot be empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
const ipRegex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(:[0-9]{1,5})?$/;
|
||||||
if (ipRegex.test(value)) {
|
const domainRegex = /^(?:https:\/\/)?([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,63}(:[0-9]{1,5})?(\/[^?#\s]*)?$/;
|
||||||
const parts = value.split('.');
|
|
||||||
for (const part of parts) {
|
|
||||||
const num = parseInt(part);
|
|
||||||
if (num < 0 || num > 255) {
|
|
||||||
return _('IP address parts must be between 0 and 255');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/;
|
if (!ipRegex.test(value) && !domainRegex.test(value)) {
|
||||||
if (!domainRegex.test(value)) {
|
|
||||||
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
|
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,20 +87,10 @@ function createAdditionalSection(mainSection, network) {
|
|||||||
return _('DNS server address cannot be empty');
|
return _('DNS server address cannot be empty');
|
||||||
}
|
}
|
||||||
|
|
||||||
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
const ipRegex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(:[0-9]{1,5})?$/;
|
||||||
if (ipRegex.test(value)) {
|
const domainRegex = /^(?:https:\/\/)?([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,63}(:[0-9]{1,5})?(\/[^?#\s]*)?$/;
|
||||||
const parts = value.split('.');
|
|
||||||
for (const part of parts) {
|
|
||||||
const num = parseInt(part);
|
|
||||||
if (num < 0 || num > 255) {
|
|
||||||
return _('IP address parts must be between 0 and 255');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/;
|
if (!ipRegex.test(value) && !domainRegex.test(value)) {
|
||||||
if (!domainRegex.test(value)) {
|
|
||||||
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
|
return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -687,14 +687,16 @@ sing_box_configure_dns() {
|
|||||||
fi
|
fi
|
||||||
config=$(sing_box_cm_configure_dns "$config" "$final_dns_server" "ipv4_only" true)
|
config=$(sing_box_cm_configure_dns "$config" "$final_dns_server" "ipv4_only" true)
|
||||||
|
|
||||||
local dns_type dns_server split_dns_type split_dns_server
|
local dns_type dns_server split_dns_type split_dns_server dns_server_address split_dns_server_address
|
||||||
config_get dns_type "main" "dns_type" "doh"
|
config_get dns_type "main" "dns_type" "doh"
|
||||||
config_get dns_server "main" "dns_server" "1.1.1.1"
|
config_get dns_server "main" "dns_server" "1.1.1.1"
|
||||||
config_get split_dns_type "main" "split_dns_type" "udp"
|
config_get split_dns_type "main" "split_dns_type" "udp"
|
||||||
config_get split_dns_server "main" "split_dns_server" "1.1.1.1"
|
config_get split_dns_server "main" "split_dns_server" "1.1.1.1"
|
||||||
|
dns_server_address=$(url_get_host "$dns_server")
|
||||||
|
split_dns_server_address=$(url_get_host "$split_dns_server")
|
||||||
|
|
||||||
local need_dns_domain_resolver=0
|
local need_dns_domain_resolver=0
|
||||||
if ! is_ipv4 "$dns_server" || ! is_ipv4 "$split_dns_server"; then
|
if ! is_ipv4 "$dns_server_address" || ! is_ipv4 "$split_dns_server_address"; then
|
||||||
need_dns_domain_resolver=1
|
need_dns_domain_resolver=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -715,15 +717,12 @@ sing_box_configure_dns() {
|
|||||||
dns_domain_resolver="$SB_DNS_DOMAIN_RESOLVER_TAG"
|
dns_domain_resolver="$SB_DNS_DOMAIN_RESOLVER_TAG"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
config=$(
|
config=$(sing_box_cf_add_dns_server "$config" "$dns_type" "$SB_DNS_SERVER_TAG" "$dns_server" "$dns_domain_resolver")
|
||||||
sing_box_cf_add_dns_server "$config" "$dns_type" "$SB_DNS_SERVER_TAG" "$dns_server" "" "" \
|
|
||||||
"$dns_domain_resolver"
|
|
||||||
)
|
|
||||||
|
|
||||||
if [ "$split_dns_enabled" -eq 1 ]; then
|
if [ "$split_dns_enabled" -eq 1 ]; then
|
||||||
config=$(
|
config=$(
|
||||||
sing_box_cf_add_dns_server "$config" "$split_dns_type" "$SB_SPLIT_DNS_SERVER_TAG" "$split_dns_server" \
|
sing_box_cf_add_dns_server "$config" "$split_dns_type" "$SB_SPLIT_DNS_SERVER_TAG" "$split_dns_server" \
|
||||||
"" "" "$dns_domain_resolver" "$SB_MAIN_OUTBOUND_TAG"
|
"$dns_domain_resolver" "$SB_MAIN_OUTBOUND_TAG"
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ is_domain() {
|
|||||||
is_base64() {
|
is_base64() {
|
||||||
local str="$1"
|
local str="$1"
|
||||||
|
|
||||||
if echo "$str" | base64 -d >/dev/null 2>&1; then
|
if echo "$str" | base64 -d > /dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
@@ -113,19 +113,25 @@ url_decode() {
|
|||||||
# Extracts the userinfo (username[:password]) part from a URL
|
# Extracts the userinfo (username[:password]) part from a URL
|
||||||
url_get_userinfo() {
|
url_get_userinfo() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
echo "$url" | sed -n 's#^[^:]*://\([^@]*\)@.*#\1#p'
|
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e '/@/!d' -e 's/@.*//p'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extracts the host part from a URL
|
# Extracts the host part from a URL
|
||||||
url_get_host() {
|
url_get_host() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
echo "$url" | sed -n 's#^[^:]*://[^@]*@\([^:/?#]*\).*#\1#p'
|
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#\([:/].*\|$\)##p'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extracts the port number from a URL
|
# Extracts the port number from a URL
|
||||||
url_get_port() {
|
url_get_port() {
|
||||||
local url="$1"
|
local url="$1"
|
||||||
echo "$url" | sed -n 's#^[^:]*://[^@]*@[^:/?#]*:\([0-9]*\).*#\1#p'
|
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*@##' -e 's#^[^/]*:\([0-9][0-9]*\).*#\1#p'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extracts the path from a URL (without query or fragment; returns "/" if empty)
|
||||||
|
url_get_path() {
|
||||||
|
local url="$1"
|
||||||
|
echo "$url" | sed -n -e 's#^[^:/?]*://##' -e 's#^[^/]*##' -e 's#\([^?]*\).*#\1#p'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extracts the value of a specific query parameter from a URL
|
# Extracts the value of a specific query parameter from a URL
|
||||||
@@ -157,8 +163,8 @@ url_get_file_extension() {
|
|||||||
|
|
||||||
local basename="${url##*/}"
|
local basename="${url##*/}"
|
||||||
case "$basename" in
|
case "$basename" in
|
||||||
*.*) echo "${basename##*.}" ;;
|
*.*) echo "${basename##*.}" ;;
|
||||||
*) echo "" ;;
|
*) echo "" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +173,7 @@ base64_decode() {
|
|||||||
local str="$1"
|
local str="$1"
|
||||||
local decoded_url
|
local decoded_url
|
||||||
|
|
||||||
decoded_url="$(echo "$str" | base64 -d 2>/dev/null)"
|
decoded_url="$(echo "$str" | base64 -d 2 > /dev/null)"
|
||||||
|
|
||||||
echo "$decoded_url"
|
echo "$decoded_url"
|
||||||
}
|
}
|
||||||
@@ -288,22 +294,22 @@ parse_domain_or_subnet_string_to_commas_string() {
|
|||||||
local result
|
local result
|
||||||
for item in $string; do
|
for item in $string; do
|
||||||
case "$type" in
|
case "$type" in
|
||||||
domains)
|
domains)
|
||||||
if ! is_domain "$item"; then
|
if ! is_domain "$item"; then
|
||||||
log "'$item' is not a valid domain" "debug"
|
log "'$item' is not a valid domain" "debug"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
subnets)
|
subnets)
|
||||||
if ! is_ipv4_ip_or_ipv4_cidr "$item"; then
|
if ! is_ipv4_ip_or_ipv4_cidr "$item"; then
|
||||||
log "'$item' is not IPv4 or IPv4 CIDR" "debug"
|
log "'$item' is not IPv4 or IPv4 CIDR" "debug"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Unknown type: $type" "error"
|
log "Unknown type: $type" "error"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -z "$result" ]; then
|
if [ -z "$result" ]; then
|
||||||
@@ -334,22 +340,22 @@ parse_domain_or_subnet_file_to_comma_string() {
|
|||||||
[ -z "$line" ] && continue
|
[ -z "$line" ] && continue
|
||||||
|
|
||||||
case "$type" in
|
case "$type" in
|
||||||
domains)
|
domains)
|
||||||
if ! is_domain "$line"; then
|
if ! is_domain "$line"; then
|
||||||
log "'$line' is not a valid domain" "debug"
|
log "'$line' is not a valid domain" "debug"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
subnets)
|
subnets)
|
||||||
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
|
if ! is_ipv4 "$line" && ! is_ipv4_cidr "$line"; then
|
||||||
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
|
log "'$line' is not IPv4 or IPv4 CIDR" "debug"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Unknown type: $type" "error"
|
log "Unknown type: $type" "error"
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -z "$result" ]; then
|
if [ -z "$result" ]; then
|
||||||
@@ -360,4 +366,4 @@ parse_domain_or_subnet_file_to_comma_string() {
|
|||||||
done < "$filepath"
|
done < "$filepath"
|
||||||
|
|
||||||
echo "$result"
|
echo "$result"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,32 @@ sing_box_cf_add_dns_server() {
|
|||||||
local config="$1"
|
local config="$1"
|
||||||
local type="$2"
|
local type="$2"
|
||||||
local tag="$3"
|
local tag="$3"
|
||||||
local server_address="$4"
|
local server="$4"
|
||||||
local path="$5"
|
local domain_resolver="$5"
|
||||||
local headers="$6"
|
local detour="$6"
|
||||||
local domain_resolver="$7"
|
|
||||||
local detour="$8"
|
local server_address server_port
|
||||||
|
server_address=$(url_get_host "$server")
|
||||||
|
server_port=$(url_get_port "$server")
|
||||||
|
|
||||||
case "$type" in
|
case "$type" in
|
||||||
udp)
|
udp)
|
||||||
config=$(sing_box_cm_add_udp_dns_server "$config" "$tag" "$server_address" 53 "$domain_resolver" "$detour")
|
[ -z "$server_port" ] && server_port=53
|
||||||
|
config=$(sing_box_cm_add_udp_dns_server "$config" "$tag" "$server_address" "$server_port" "$domain_resolver" \
|
||||||
|
"$detour")
|
||||||
;;
|
;;
|
||||||
dot)
|
dot)
|
||||||
config=$(sing_box_cm_add_tls_dns_server "$config" "$tag" "$server_address" 853 "$domain_resolver" "$detour")
|
[ -z "$server_port" ] && server_port=853
|
||||||
|
config=$(sing_box_cm_add_tls_dns_server "$config" "$tag" "$server_address" "$server_port" "$domain_resolver" \
|
||||||
|
"$detour")
|
||||||
;;
|
;;
|
||||||
doh)
|
doh)
|
||||||
config=$(
|
[ -z "$server_port" ] && server_port=443
|
||||||
sing_box_cm_add_https_dns_server "$config" "$tag" "$server_address" 443 "$path" "$headers" \
|
local path headers
|
||||||
"$domain_resolver" "$detour"
|
path=$(url_get_path "$server")
|
||||||
)
|
headers="" # TODO(ampetelin): implement it if necessary
|
||||||
|
config=$(sing_box_cm_add_https_dns_server "$config" "$tag" "$server_address" "$server_port" "$path" "$headers" \
|
||||||
|
"$domain_resolver" "$detour")
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log "Unsupported DNS server type: $type"
|
log "Unsupported DNS server type: $type"
|
||||||
|
|||||||
Reference in New Issue
Block a user