diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/additionalTab.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/additionalTab.js index 8c42e9f..a95c4ae 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/additionalTab.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/additionalTab.js @@ -50,20 +50,10 @@ function createAdditionalSection(mainSection, network) { return _('DNS server address cannot be empty'); } - const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/; - if (ipRegex.test(value)) { - 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 ipRegex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(:[0-9]{1,5})?$/; + const domainRegex = /^(?:https:\/\/)?([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,63}(:[0-9]{1,5})?(\/[^?#\s]*)?$/; - const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/; - if (!domainRegex.test(value)) { + if (!ipRegex.test(value) && !domainRegex.test(value)) { 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'); } - const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/; - if (ipRegex.test(value)) { - 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 ipRegex = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}(:[0-9]{1,5})?$/; + const domainRegex = /^(?:https:\/\/)?([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,63}(:[0-9]{1,5})?(\/[^?#\s]*)?$/; - const domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/; - if (!domainRegex.test(value)) { + if (!ipRegex.test(value) && !domainRegex.test(value)) { return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com or dns.example.com/nicedns for DoH'); } diff --git a/podkop/files/usr/bin/podkop b/podkop/files/usr/bin/podkop index bd83231..32592a4 100755 --- a/podkop/files/usr/bin/podkop +++ b/podkop/files/usr/bin/podkop @@ -687,14 +687,16 @@ sing_box_configure_dns() { fi 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_server "main" "dns_server" "1.1.1.1" config_get split_dns_type "main" "split_dns_type" "udp" 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 - 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 fi @@ -715,15 +717,12 @@ sing_box_configure_dns() { dns_domain_resolver="$SB_DNS_DOMAIN_RESOLVER_TAG" fi - config=$( - sing_box_cf_add_dns_server "$config" "$dns_type" "$SB_DNS_SERVER_TAG" "$dns_server" "" "" \ - "$dns_domain_resolver" - ) + config=$(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 config=$( 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 diff --git a/podkop/files/usr/lib/helpers.sh b/podkop/files/usr/lib/helpers.sh index 430c771..efaf29a 100644 --- a/podkop/files/usr/lib/helpers.sh +++ b/podkop/files/usr/lib/helpers.sh @@ -26,7 +26,7 @@ is_domain() { is_base64() { 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 fi return 1 @@ -113,19 +113,25 @@ url_decode() { # Extracts the userinfo (username[:password]) part from a URL url_get_userinfo() { 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 url_get_host() { 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 url_get_port() { 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 @@ -157,8 +163,8 @@ url_get_file_extension() { local basename="${url##*/}" case "$basename" in - *.*) echo "${basename##*.}" ;; - *) echo "" ;; + *.*) echo "${basename##*.}" ;; + *) echo "" ;; esac } @@ -167,7 +173,7 @@ base64_decode() { local str="$1" local decoded_url - decoded_url="$(echo "$str" | base64 -d 2>/dev/null)" + decoded_url="$(echo "$str" | base64 -d 2 > /dev/null)" echo "$decoded_url" } @@ -288,22 +294,22 @@ parse_domain_or_subnet_string_to_commas_string() { local result for item in $string; do case "$type" in - domains) - if ! is_domain "$item"; then - log "'$item' is not a valid domain" "debug" - continue - fi - ;; - subnets) - if ! is_ipv4_ip_or_ipv4_cidr "$item"; then - log "'$item' is not IPv4 or IPv4 CIDR" "debug" - continue - fi - ;; - *) - log "Unknown type: $type" "error" - return 1 - ;; + domains) + if ! is_domain "$item"; then + log "'$item' is not a valid domain" "debug" + continue + fi + ;; + subnets) + if ! is_ipv4_ip_or_ipv4_cidr "$item"; then + log "'$item' is not IPv4 or IPv4 CIDR" "debug" + continue + fi + ;; + *) + log "Unknown type: $type" "error" + return 1 + ;; esac if [ -z "$result" ]; then @@ -334,22 +340,22 @@ parse_domain_or_subnet_file_to_comma_string() { [ -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 - ;; + 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 @@ -360,4 +366,4 @@ parse_domain_or_subnet_file_to_comma_string() { done < "$filepath" echo "$result" -} \ No newline at end of file +} diff --git a/podkop/files/usr/lib/sing_box_config_facade.sh b/podkop/files/usr/lib/sing_box_config_facade.sh index 63a590c..657ca7e 100644 --- a/podkop/files/usr/lib/sing_box_config_facade.sh +++ b/podkop/files/usr/lib/sing_box_config_facade.sh @@ -6,24 +6,32 @@ sing_box_cf_add_dns_server() { local config="$1" local type="$2" local tag="$3" - local server_address="$4" - local path="$5" - local headers="$6" - local domain_resolver="$7" - local detour="$8" + local server="$4" + local domain_resolver="$5" + local detour="$6" + + local server_address server_port + server_address=$(url_get_host "$server") + server_port=$(url_get_port "$server") case "$type" in 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) - 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) - config=$( - sing_box_cm_add_https_dns_server "$config" "$tag" "$server_address" 443 "$path" "$headers" \ - "$domain_resolver" "$detour" - ) + [ -z "$server_port" ] && server_port=443 + local path headers + 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"