diff --git a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js index 4d0d3ff..cdbb3cc 100644 --- a/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js +++ b/luci-app-podkop/htdocs/luci-static/resources/view/podkop/podkop.js @@ -653,6 +653,50 @@ return view.extend({ o.rmempty = false; o.ucisection = 'main'; + o = s.taboption('additional', form.ListValue, 'dns_type', _('DNS Protocol Type'), _('Select DNS protocol to use')); + o.value('doh', _('DNS over HTTPS (DoH)')); + o.value('dot', _('DNS over TLS (DoT)')); + o.value('udp', _('UDP (Unprotected DNS)')); + o.default = 'doh'; + o.rmempty = false; + o.ucisection = 'main'; + + o = s.taboption('additional', form.Value, 'dns_servers', _('DNS Server'), _('Select or enter DNS server address')); + o.value('1.1.1.1', 'Cloudflare (1.1.1.1)'); + o.value('8.8.8.8', 'Google (8.8.8.8)'); + o.value('9.9.9.9', 'Quad9 (9.9.9.9)'); + o.value('dns.adguard-dns.com', 'AdGuard Default (dns.adguard-dns.com)'); + o.value('unfiltered.adguard-dns.com', 'AdGuard Unfiltered (unfiltered.adguard-dns.com)'); + o.value('family.adguard-dns.com', 'AdGuard Family (family.adguard-dns.com)'); + o.default = '1.1.1.1'; + o.rmempty = false; + o.ucisection = 'main'; + + o.validate = function(section_id, value) { + if (!value) { + 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 domainRegex = /^([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$/; + if (!domainRegex.test(value)) { + return _('Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com'); + } + + return true; + }; + // Diagnostics tab o = s.tab('diagnostics', _('Diagnostics')); diff --git a/luci-app-podkop/po/ru/podkop.po b/luci-app-podkop/po/ru/podkop.po index b5afa80..93c6974 100644 --- a/luci-app-podkop/po/ru/podkop.po +++ b/luci-app-podkop/po/ru/podkop.po @@ -494,4 +494,31 @@ msgid "Update Lists" msgstr "Обновить списки" msgid "Lists Update Results" -msgstr "Результаты обновления списков" \ No newline at end of file +msgstr "Результаты обновления списков" + +msgid "DNS Protocol Type" +msgstr "Тип DNS протокола" + +msgid "Select DNS protocol to use" +msgstr "Выберите протокол DNS" + +msgid "DNS over HTTPS (DoH)" +msgstr "DNS через HTTPS (DoH)" + +msgid "DNS over TLS (DoT)" +msgstr "DNS через TLS (DoT)" + +msgid "UDP (Unprotected DNS)" +msgstr "UDP (Незащищённый DNS)" + +msgid "DNS Server" +msgstr "DNS сервер" + +msgid "Select or enter DNS server address" +msgstr "Выберите или введите адрес DNS сервера" + +msgid "DNS server address cannot be empty" +msgstr "Адрес DNS сервера не может быть пустым" + +msgid "Invalid DNS server format. Examples: 8.8.8.8 or dns.example.com" +msgstr "Неверный формат DNS сервера. Примеры: 8.8.8.8 или dns.example.com" \ No newline at end of file diff --git a/luci-app-podkop/po/templates/podkop.pot b/luci-app-podkop/po/templates/podkop.pot index f13ab9a..1506f1b 100644 --- a/luci-app-podkop/po/templates/podkop.pot +++ b/luci-app-podkop/po/templates/podkop.pot @@ -854,4 +854,25 @@ msgid "Check completed" msgstr "" msgid "Check failed" +msgstr "" + +msgid "DNS Protocol Type" +msgstr "" + +msgid "Select DNS protocol to use" +msgstr "" + +msgid "DNS over HTTPS (DoH)" +msgstr "" + +msgid "DNS over TLS (DoT)" +msgstr "" + +msgid "UDP (Unprotected DNS)" +msgstr "" + +msgid "DNS Server" +msgstr "" + +msgid "Select or enter DNS server address" msgstr "" \ No newline at end of file diff --git a/podkop/files/etc/init.d/podkop b/podkop/files/etc/init.d/podkop index 69bbd67..4caf1a7 100755 --- a/podkop/files/etc/init.d/podkop +++ b/podkop/files/etc/init.d/podkop @@ -40,6 +40,8 @@ SING_BOX_CONFIG="/etc/sing-box/config.json" CACHE_FILE_PATH="/tmp/cache.db" FAKEIP="198.18.0.0/15" VALID_SERVICES="russia_inside russia_outside ukraine_inside geoblock block porn news anime youtube discord meta twitter hdrezka tiktok telegram" +DNS_RESOLVERS="1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 9.9.9.9 9.9.9.11 94.140.14.14 94.140.15.15 208.67.220.220 208.67.222.222 77.88.8.1 77.88.8.8" +TEST_DOMAIN="google.com" start_service() { log "Start podkop" @@ -546,6 +548,17 @@ list_update() { config_foreach process_subnet_for_section_remote } +find_working_resolver() { + local resolver_found="" + for resolver in $DNS_RESOLVERS; do + if nslookup $TEST_DOMAIN $resolver >/dev/null 2>&1; then + echo "$resolver" + return 0 + fi + done + echo "8.8.8.8" + return 1 +} # sing-box funcs @@ -623,27 +636,76 @@ sing_box_inbound_proxy() { } sing_box_dns() { + local dns_type + local dns_server + local resolver_tag="resolver" + + config_get dns_type "main" "dns_type" "doh" + config_get dns_server "main" "dns_server" "1.1.1.1" + + local server_json + local is_ip=$(echo "$dns_server" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' && echo "1" || echo "0") + + if [ "$is_ip" = "0" ]; then + log "Finding working DNS resolver" + local dns_resolver=$(find_working_resolver) + log "Found working resolver: $dns_resolver" + fi + log "Configure DNS in sing-box" + + server_json=$(jq -n \ + --arg type "$dns_type" \ + --arg server "$dns_server" \ + --arg resolver "$resolver_tag" \ + --arg is_ip "$is_ip" \ + '{ + "servers": [ + { + "tag": "dns-server", + "address": ( + if $type == "doh" then + "https://" + $server + "/dns-query" + elif $type == "dot" then + "tls://" + $server + else + $server + end + ), + "detour": "direct-out" + } + ( + if $is_ip == "0" then + {"address_resolver": $resolver} + else + {} + end + ) + ] + }') + + if [ "$is_ip" = "0" ]; then + server_json=$(echo "$server_json" | jq \ + --arg resolver "$resolver_tag" \ + --arg address "$dns_resolver" \ + '.servers += [{ + "tag": $resolver, + "address": $address + }]') + fi + + server_json=$(echo "$server_json" | jq '.servers += [{"tag": "fakeip-server", "address": "fakeip"}]') + jq \ - --arg FAKEIP "$FAKEIP" \ - '.dns = { - "strategy": "ipv4_only", - "fakeip": { - "enabled": true, - "inet4_range": $FAKEIP - }, - "servers": [ - { - "tag": "cloudflare-doh-server", - "address": "https://1.1.1.1/dns-query", - "detour": "direct-out" + --argjson dns_config "$server_json" \ + --arg fakeip "$FAKEIP" \ + '.dns = { + "strategy": "ipv4_only", + "fakeip": { + "enabled": true, + "inet4_range": $fakeip }, - { - "tag": "fakeip-server", - "address": "fakeip" - } - ] - }' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG + "servers": $dns_config.servers + }' $SING_BOX_CONFIG > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG } sing_box_dns_rule_fakeip() {