From 48716e71562d6659a6e4d11bad75fb2afc181f6e Mon Sep 17 00:00:00 2001 From: Ivan K Date: Thu, 1 May 2025 17:18:07 +0300 Subject: [PATCH] Enhance Podkop functionality with global check feature and improved diagnostics. Added support for FakeIP tests in both browser and router contexts. Updated UI elements for better status reporting and added localization for new messages. --- .../resources/view/podkop/podkop.js | 326 +++++++++++++----- luci-app-podkop/po/ru/podkop.po | 24 ++ luci-app-podkop/po/templates/podkop.pot | 24 ++ podkop/files/usr/bin/podkop | 200 +++++------ 4 files changed, 391 insertions(+), 183 deletions(-) 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 5fe0886..27f6a67 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 @@ -63,20 +63,20 @@ function getNetworkInterfaces(o, section_id, excludeInterfaces = []) { } function getNetworkNetworks(o, section_id, excludeInterfaces = []) { - return network.getNetworks().then(networks => { - o.keylist = []; - o.vallist = []; + return network.getNetworks().then(networks => { + o.keylist = []; + o.vallist = []; - networks.forEach(net => { - const name = net.getName(); - const ifname = net.getIfname(); - if (name && !excludeInterfaces.includes(name)) { - o.value(name, ifname ? `${name} (${ifname})` : name); - } - }); - }).catch(error => { - console.error('Failed to get networks:', error); - }); + networks.forEach(net => { + const name = net.getName(); + const ifname = net.getIfname(); + if (name && !excludeInterfaces.includes(name)) { + o.value(name, ifname ? `${name} (${ifname})` : name); + } + }); + }).catch(error => { + console.error('Failed to get networks:', error); + }); } function createConfigSection(section, map, network) { @@ -623,7 +623,33 @@ const createModalContent = (title, content) => { const showConfigModal = async (command, title) => { const res = await safeExec('/usr/bin/podkop', [command]); - const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + let formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + + if (command === 'global_check') { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 10000); + + const response = await fetch('https://fakeip.tech-domain.club/check', { signal: controller.signal }); + const data = await response.json(); + clearTimeout(timeoutId); + + formattedOutput += '\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'; + formattedOutput += ' ' + _('FAKEIP BROWSER TEST') + '\n'; + formattedOutput += '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n'; + + if (data.fakeip === true) { + formattedOutput += '✅ ' + _('FakeIP is working in browser!') + '\n'; + } else { + formattedOutput += '❌ ' + _('FakeIP is not working in browser') + '\n'; + formattedOutput += _('Check DNS server on current device (PC, phone)') + '\n'; + formattedOutput += _('Its must be router!') + '\n'; + } + } catch (error) { + formattedOutput += '\n❌ ' + _('Check failed: ') + (error.name === 'AbortError' ? _('timeout') : error.message) + '\n'; + } + } + ui.showModal(_(title), createModalContent(_(title), formattedOutput)); }; @@ -672,11 +698,18 @@ const createStatusPanel = (title, status, buttons) => { E('strong', {}, _(title)), status && E('br'), status && E('span', { - 'style': `color: ${status.running ? STATUS_COLORS.SUCCESS : STATUS_COLORS.ERROR}` + 'style': `color: ${title === 'Sing-box Status' ? + (status.running && !status.enabled ? STATUS_COLORS.SUCCESS : STATUS_COLORS.ERROR) : + title === 'Podkop Status' ? + (status.enabled ? STATUS_COLORS.SUCCESS : STATUS_COLORS.ERROR) : + (status.running ? STATUS_COLORS.SUCCESS : STATUS_COLORS.ERROR) + }` }, [ - status.running ? '✔' : '✘', - ' ', - status.status + title === 'Sing-box Status' ? + (status.running && !status.enabled ? '✔ running' : '✘ ' + status.status) : + title === 'Podkop Status' ? + (status.enabled ? '✔ enabled' : '✘ disabled') : + (status.running ? '✔' : '✘') + ' ' + status.status ]) ].filter(Boolean); @@ -688,7 +721,80 @@ const createStatusPanel = (title, status, buttons) => { E('div', { 'class': 'panel-body', 'style': 'display: flex; flex-direction: column; gap: 8px;' - }, buttons) + }, title === 'Podkop Status' ? [ + ButtonFactory.createActionButton({ + label: 'Restart Podkop', + type: 'apply', + action: 'restart', + reload: true + }), + ButtonFactory.createInitActionButton({ + label: status.enabled ? 'Disable Podkop' : 'Enable Podkop', + type: status.enabled ? 'remove' : 'apply', + action: status.enabled ? 'disable' : 'enable', + reload: true + }), + ButtonFactory.createModalButton({ + label: _('Global check'), + command: 'global_check', + title: _('Click here for all the info') + }), + ButtonFactory.createModalButton({ + label: 'View Logs', + command: 'check_logs', + title: 'Podkop Logs' + }), + ButtonFactory.createModalButton({ + label: _('Update Lists'), + command: 'list_update', + title: _('Lists Update Results') + }) + ] : title === 'FakeIP Status' ? [ + E('div', { style: 'margin-bottom: 10px;' }, [ + E('div', { style: 'margin-bottom: 5px;' }, [ + E('span', { style: `color: ${fakeipStatus.color}` }, [ + fakeipStatus.state === 'working' ? '✔' : fakeipStatus.state === 'not_working' ? '✘' : '!', + ' ', + fakeipStatus.state === 'working' ? _('works in browser') : _('not works in browser') + ]) + ]), + E('div', {}, [ + E('span', { style: `color: ${fakeipCLIStatus.color}` }, [ + fakeipCLIStatus.state === 'working' ? '✔' : fakeipCLIStatus.state === 'not_working' ? '✘' : '!', + ' ', + fakeipCLIStatus.state === 'working' ? _('works on router') : _('not works on router') + ]) + ]) + ]), + E('div', { style: 'margin-bottom: 10px;' }, [ + E('div', { style: 'margin-bottom: 5px;' }, [ + E('strong', {}, _('DNS Status')), + E('br'), + E('span', { style: `color: ${dnsStatus.remote.color}` }, [ + dnsStatus.remote.state === 'available' ? '✔' : dnsStatus.remote.state === 'unavailable' ? '✘' : '!', + ' ', + dnsStatus.remote.message + ]), + E('br'), + E('span', { style: `color: ${dnsStatus.local.color}` }, [ + dnsStatus.local.state === 'available' ? '✔' : dnsStatus.local.state === 'unavailable' ? '✘' : '!', + ' ', + dnsStatus.local.message + ]) + ]) + ]), + E('div', { style: 'margin-bottom: 10px;' }, [ + E('div', { style: 'margin-bottom: 5px;' }, [ + E('strong', {}, configName), + E('br'), + E('span', { style: `color: ${bypassStatus.color}` }, [ + bypassStatus.state === 'working' ? '✔' : bypassStatus.state === 'not_working' ? '✘' : '!', + ' ', + bypassStatus.message + ]) + ]) + ]) + ] : buttons) ]); }; @@ -717,9 +823,9 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s reload: true }), ButtonFactory.createModalButton({ - label: 'Show Config', - command: 'show_config', - title: 'Podkop Configuration' + label: _('Global check'), + command: 'global_check', + title: _('Click here for all the info') }), ButtonFactory.createModalButton({ label: 'View Logs', @@ -807,12 +913,7 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s bypassStatus.message ]) ]) - ]), - ButtonFactory.createModalButton({ - label: _('Global check'), - command: 'global_check', - title: _('Click here for all the info') - }) + ]) ]), // Version Information Panel @@ -1350,32 +1451,67 @@ return view.extend({ async function updateDiagnostics() { try { - const [ - podkopStatus, - singboxStatus, - podkop, - luci, - singbox, - system, - fakeipStatus, - fakeipCLIStatus, - dnsStatus, - bypassStatus - ] = await Promise.all([ - safeExec('/usr/bin/podkop', ['get_status']), - safeExec('/usr/bin/podkop', ['get_sing_box_status']), - safeExec('/usr/bin/podkop', ['show_version']), - safeExec('/usr/bin/podkop', ['show_luci_version']), - safeExec('/usr/bin/podkop', ['show_sing_box_version']), - safeExec('/usr/bin/podkop', ['show_system_info']), - checkFakeIP(), - checkFakeIPCLI(), - checkDNSAvailability(), - checkBypass() - ]); + const results = { + podkopStatus: null, + singboxStatus: null, + podkop: null, + luci: null, + singbox: null, + system: null, + fakeipStatus: null, + fakeipCLIStatus: null, + dnsStatus: null, + bypassStatus: null + }; - const parsedPodkopStatus = JSON.parse(podkopStatus.stdout || '{"running":0,"enabled":0,"status":"unknown"}'); - const parsedSingboxStatus = JSON.parse(singboxStatus.stdout || '{"running":0,"enabled":0,"status":"unknown"}'); + // Выполняем все проверки независимо друг от друга + const checks = [ + safeExec('/usr/bin/podkop', ['get_status']) + .then(result => results.podkopStatus = result) + .catch(() => results.podkopStatus = { stdout: '{"enabled":0,"status":"error"}' }), + + safeExec('/usr/bin/podkop', ['get_sing_box_status']) + .then(result => results.singboxStatus = result) + .catch(() => results.singboxStatus = { stdout: '{"running":0,"enabled":0,"status":"error"}' }), + + safeExec('/usr/bin/podkop', ['show_version']) + .then(result => results.podkop = result) + .catch(() => results.podkop = { stdout: 'error' }), + + safeExec('/usr/bin/podkop', ['show_luci_version']) + .then(result => results.luci = result) + .catch(() => results.luci = { stdout: 'error' }), + + safeExec('/usr/bin/podkop', ['show_sing_box_version']) + .then(result => results.singbox = result) + .catch(() => results.singbox = { stdout: 'error' }), + + safeExec('/usr/bin/podkop', ['show_system_info']) + .then(result => results.system = result) + .catch(() => results.system = { stdout: 'error' }), + + checkFakeIP() + .then(result => results.fakeipStatus = result) + .catch(() => results.fakeipStatus = { state: 'error', message: 'check error', color: STATUS_COLORS.WARNING }), + + checkFakeIPCLI() + .then(result => results.fakeipCLIStatus = result) + .catch(() => results.fakeipCLIStatus = { state: 'error', message: 'check error', color: STATUS_COLORS.WARNING }), + + checkDNSAvailability() + .then(result => results.dnsStatus = result) + .catch(() => results.dnsStatus = { + remote: { state: 'error', message: 'check error', color: STATUS_COLORS.WARNING }, + local: { state: 'error', message: 'check error', color: STATUS_COLORS.WARNING } + }), + + checkBypass() + .then(result => results.bypassStatus = result) + .catch(() => results.bypassStatus = { state: 'error', message: 'check error', color: STATUS_COLORS.WARNING }) + ]; + + // Ждем завершения всех проверок + await Promise.allSettled(checks); const container = document.getElementById('diagnostics-status'); if (!container) return; @@ -1395,11 +1531,7 @@ return view.extend({ const label = activeConfig.split('#').pop(); if (label && label.trim()) { configName = _('Config: ') + decodeURIComponent(label); - } else { - configName = _('Main config'); } - } else { - configName = _('Main config'); } } } @@ -1407,42 +1539,62 @@ return view.extend({ console.error('Error getting config name from UCI:', e); } - // Create a modified statusSection function with the configName - const statusSection = createStatusSection(parsedPodkopStatus, parsedSingboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus, dnsStatus, bypassStatus, configName); + const parsedPodkopStatus = JSON.parse(results.podkopStatus.stdout || '{"enabled":0,"status":"error"}'); + const parsedSingboxStatus = JSON.parse(results.singboxStatus.stdout || '{"running":0,"enabled":0,"status":"error"}'); + + const statusSection = createStatusSection( + parsedPodkopStatus, + parsedSingboxStatus, + results.podkop, + results.luci, + results.singbox, + results.system, + results.fakeipStatus, + results.fakeipCLIStatus, + results.dnsStatus, + results.bypassStatus, + configName + ); + container.innerHTML = ''; container.appendChild(statusSection); - const fakeipElement = document.getElementById('fakeip-status'); - if (fakeipElement) { - fakeipElement.innerHTML = E('span', { 'style': `color: ${fakeipStatus.color}` }, [ - fakeipStatus.state === 'working' ? '✔ ' : fakeipStatus.state === 'not_working' ? '✘ ' : '! ', - fakeipStatus.message - ]).outerHTML; - } + // Обновляем отдельные элементы статуса + const updateStatusElement = (elementId, status, template) => { + const element = document.getElementById(elementId); + if (element) { + element.innerHTML = template(status); + } + }; - const fakeipCLIElement = document.getElementById('fakeip-cli-status'); - if (fakeipCLIElement) { - fakeipCLIElement.innerHTML = E('span', { 'style': `color: ${fakeipCLIStatus.color}` }, [ - fakeipCLIStatus.state === 'working' ? '✔ ' : fakeipCLIStatus.state === 'not_working' ? '✘ ' : '! ', - fakeipCLIStatus.message - ]).outerHTML; - } + updateStatusElement('fakeip-status', results.fakeipStatus, + status => E('span', { 'style': `color: ${status.color}` }, [ + status.state === 'working' ? '✔ ' : status.state === 'not_working' ? '✘ ' : '! ', + status.message + ]).outerHTML + ); - const dnsRemoteElement = document.getElementById('dns-remote-status'); - if (dnsRemoteElement) { - dnsRemoteElement.innerHTML = E('span', { 'style': `color: ${dnsStatus.remote.color}` }, [ - dnsStatus.remote.state === 'available' ? '✔ ' : dnsStatus.remote.state === 'unavailable' ? '✘ ' : '! ', - dnsStatus.remote.message - ]).outerHTML; - } + updateStatusElement('fakeip-cli-status', results.fakeipCLIStatus, + status => E('span', { 'style': `color: ${status.color}` }, [ + status.state === 'working' ? '✔ ' : status.state === 'not_working' ? '✘ ' : '! ', + status.message + ]).outerHTML + ); + + updateStatusElement('dns-remote-status', results.dnsStatus.remote, + status => E('span', { 'style': `color: ${status.color}` }, [ + status.state === 'available' ? '✔ ' : status.state === 'unavailable' ? '✘ ' : '! ', + status.message + ]).outerHTML + ); + + updateStatusElement('dns-local-status', results.dnsStatus.local, + status => E('span', { 'style': `color: ${status.color}` }, [ + status.state === 'available' ? '✔ ' : status.state === 'unavailable' ? '✘ ' : '! ', + status.message + ]).outerHTML + ); - const dnsLocalElement = document.getElementById('dns-local-status'); - if (dnsLocalElement) { - dnsLocalElement.innerHTML = E('span', { 'style': `color: ${dnsStatus.local.color}` }, [ - dnsStatus.local.state === 'available' ? '✔ ' : dnsStatus.local.state === 'unavailable' ? '✘ ' : '! ', - dnsStatus.local.message - ]).outerHTML; - } } catch (e) { const container = document.getElementById('diagnostics-status'); if (container) { diff --git a/luci-app-podkop/po/ru/podkop.po b/luci-app-podkop/po/ru/podkop.po index 6b1ff8e..b1ba065 100644 --- a/luci-app-podkop/po/ru/podkop.po +++ b/luci-app-podkop/po/ru/podkop.po @@ -819,3 +819,27 @@ msgstr "недоступен" msgid "Apply for SS2022" msgstr "Применить для SS2022" + +msgid "PODKOP CONFIGURATION" +msgstr "КОНФИГУРАЦИЯ PODKOP" + +msgid "FAKEIP ROUTER TEST" +msgstr "ПРОВЕРКА FAKEIP НА РОУТЕРЕ" + +msgid "FAKEIP BROWSER TEST" +msgstr "ПРОВЕРКА FAKEIP В БРАУЗЕРЕ" + +msgid "FakeIP is working correctly on router (198.18.x.x)" +msgstr "FakeIP работает корректно на роутере (198.18.x.x)" + +msgid "Click here for all the info" +msgstr "Нажмите для просмотра всей информации" + +msgid "Check DNS server on current device (PC, phone)" +msgstr "Проверьте DNS сервер на текущем устройстве (ПК, телефон)" + +msgid "Its must be router!" +msgstr "Это должен быть роутер!" + +msgid "Global check" +msgstr "Глобальная проверка" \ 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 c017151..f668555 100644 --- a/luci-app-podkop/po/templates/podkop.pot +++ b/luci-app-podkop/po/templates/podkop.pot @@ -1169,4 +1169,28 @@ msgid "available" msgstr "" msgid "unavailable" +msgstr "" + +msgid "PODKOP CONFIGURATION" +msgstr "" + +msgid "FAKEIP ROUTER TEST" +msgstr "" + +msgid "FAKEIP BROWSER TEST" +msgstr "" + +msgid "FakeIP is working correctly on router (198.18.x.x)" +msgstr "" + +msgid "Click here for all the info" +msgstr "" + +msgid "Check DNS server on current device (PC, phone)" +msgstr "" + +msgid "Its must be router!" +msgstr "" + +msgid "Global check" msgstr "" \ No newline at end of file diff --git a/podkop/files/usr/bin/podkop b/podkop/files/usr/bin/podkop index 52f2779..c4953f6 100755 --- a/podkop/files/usr/bin/podkop +++ b/podkop/files/usr/bin/podkop @@ -1953,9 +1953,7 @@ show_sing_box_config() { )' "$SING_BOX_CONFIG" } -show_config() { - nolog "📄 Current podkop configuration:" - +show_config() { if [ ! -f /etc/config/podkop ]; then nolog "Configuration file not found" return 1 @@ -2046,36 +2044,18 @@ get_sing_box_status() { } get_status() { - local running=0 local enabled=0 local status="" # Check if service is enabled if [ -x /etc/rc.d/S99podkop ]; then enabled=1 - fi - - # Check if service is running - if pgrep -f "sing-box" >/dev/null; then - running=1 - fi - - # Format status message - if [ $running -eq 1 ]; then - if [ $enabled -eq 1 ]; then - status="running & enabled" - else - status="running but disabled" - fi + status="enabled" else - if [ $enabled -eq 1 ]; then - status="stopped but enabled" - else - status="stopped & disabled" - fi + status="disabled" fi - echo "{\"running\":$running,\"enabled\":$enabled,\"status\":\"$status\"}" + echo "{\"enabled\":$enabled,\"status\":\"$status\"}" } check_dns_available() { @@ -2171,71 +2151,39 @@ sing_box_add_secure_dns_probe_domain() { log "DNS probe domain ${domain} configured with override to port ${override_port}" } +print_global() { + local message="$1" + echo "$message" +} + global_check() { - nolog "📡 Global check run!" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " SYSTEM INFO" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global "📦 Podkop: $(opkg list-installed podkop | awk '{print $3}')" + print_global "📦 LuCI App: $(opkg list-installed luci-app-podkop | awk '{print $3}')" + print_global "📦 Sing-box: $(sing-box version | head -n 1 | awk '{print $3}')" + print_global "🔧 OpenWrt: $(grep OPENWRT_RELEASE /etc/os-release | cut -d'"' -f2)" + print_global "💻 Device: $(cat /tmp/sysinfo/model)" + print_global "" - nolog "Podkop $(opkg list-installed podkop | awk '{print $3}')" - nolog "LuCi App $(opkg list-installed luci-app-podkop | awk '{print $3}')" - nolog "Sing-box $(sing-box version | head -n 1 | awk '{print $3}')" - nolog "$(grep OPENWRT_RELEASE /etc/os-release | cut -d'"' -f2)" - nolog "Device: $(cat /tmp/sysinfo/model)" - - printf "\n" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " PODKOP CONFIGURATION" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" show_config - printf "\n" + print_global "" - nolog "Checking fakeip functionality..." - - nolog "➡️ DNS resolution: system DNS server" - nslookup -timeout=2 $TEST_DOMAIN - - local working_resolver=$(find_working_resolver) - if [ -z "$working_resolver" ]; then - nolog "❌ No working resolver found, skipping resolver check" - else - nolog "➡️ DNS resolution: external resolver ($working_resolver)" - nslookup -timeout=2 $TEST_DOMAIN $working_resolver - fi - - # Main FakeIP check - nolog "➡️ DNS resolution: sing-box DNS server (127.0.0.42)" - local result=$(nslookup -timeout=2 $TEST_DOMAIN 127.0.0.42 2>&1) - echo "$result" - - if echo "$result" | grep -q "198.18"; then - nolog "✅ FakeIP is working correctly! Domain resolved to FakeIP range (198.18.x.x)" - else - nolog "❌ FakeIP test failed. Domain did not resolve to FakeIP range" - nolog "Checking if sing-box is running..." - - if ! pgrep -f "sing-box" >/dev/null; then - nolog "sing-box is not running" - else - nolog "sing-box is running, but FakeIP might not be configured correctly" - nolog "Checking DNS configuration in sing-box..." - - if [ -f "$SING_BOX_CONFIG" ]; then - local fakeip_enabled=$(jq -r '.dns.fakeip.enabled' "$SING_BOX_CONFIG") - local fakeip_range=$(jq -r '.dns.fakeip.inet4_range' "$SING_BOX_CONFIG") - - nolog "FakeIP enabled: $fakeip_enabled" - nolog "FakeIP range: $fakeip_range" - - local dns_rules=$(jq -r '.dns.rules[] | select(.server == "fakeip-server") | .domain' "$SING_BOX_CONFIG") - nolog "FakeIP domain: $dns_rules" - else - nolog "sing-box config file not found" - fi - fi - fi - printf "\n" + print_global "" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " SYSTEM CHECKS" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if grep -E "^nameserver\s+([0-9]{1,3}\.){3}[0-9]{1,3}" "$RESOLV_CONF" | grep -vqE "127\.0\.0\.1|0\.0\.0\.0"; then - nolog "❌ /etc/resolv.conf contains an external nameserver:" - cat /etc/resolv.conf + print_global "❌ /etc/resolv.conf contains external nameserver:" + cat /etc/resolv.conf | sed 's/^/ /' echo "" else - nolog "✅ /etc/resolv.conf OK" + print_global "✅ /etc/resolv.conf - OK" fi cachesize="$(uci get dhcp.@dnsmasq[0].cachesize 2>/dev/null)" @@ -2243,29 +2191,35 @@ global_check() { server="$(uci get dhcp.@dnsmasq[0].server 2>/dev/null)" if [ "$cachesize" != "0" ] || [ "$noresolv" != "1" ] || [ "$server" != "127.0.0.42" ]; then - nolog "❌ The configuration differs from the template. 📄 DHCP config:" - awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp + print_global "❌ DHCP configuration differs from template:" + awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp | sed 's/^/ /' elif [ "$(uci get podkop.main.dont_touch_dhcp 2>/dev/null)" = "1" ]; then - nolog "⚠️ Enable dont_touch_dhcp. 📄 DHCP config:" - awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp + print_global "⚠️ dont_touch_dhcp is enabled:" + awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp | sed 's/^/ /' else - nolog "✅ /etc/config/dhcp" + print_global "✅ DHCP configuration - OK" fi if ! pgrep -f "sing-box" >/dev/null; then - nolog "❌ sing-box is not running" + print_global "❌ sing-box process - not running" else - nolog "✅ sing-box is running" + print_global "✅ sing-box process - running" fi - nolog "📄 NFT Table Podkop" + print_global "" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " NFT RULES" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if ! nft list table inet PodkopTable >/dev/null 2>&1; then - nolog "PodkopTable not found" + print_global "❌ PodkopTable not found" else - nft list table inet PodkopTable + nft list table inet PodkopTable | sed 's/^/ /' fi - nolog "📄 WAN config" + print_global "" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " WAN CONFIG" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" if uci show network.wan >/dev/null 2>&1; then awk ' /^config / { @@ -2284,28 +2238,82 @@ global_check() { print } } - ' /etc/config/network + ' /etc/config/network | sed 's/^/ /' else - nolog "WAN not exists" + print_global "❌ WAN configuration not found" fi + print_global "" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " WARP DETECTION" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + CLOUDFLARE_OCTETS="103.21 103.22 103.31 104.16 104.17 104.18 104.19 104.20 104.21 104.22 104.23 \ 104.24 104.25 104.26 104.27 104.28 108.162 131.0 141.101 162.158 162.159 172.64 172.65 172.66 \ 172.67 172.68 172.69 172.70 172.71 173.245 188.114 190.93 197.234 198.41" + local warp_found=0 if uci show network | grep -q endpoint_host; then uci show network | grep endpoint_host | cut -d'=' -f2 | tr -d "'\" " | while read -r host; do if [ "$host" = "engage.cloudflareclient.com" ]; then - nolog "⚠️ WARP detected ($host)" + print_global "⚠️ WARP detected: $host" + warp_found=1 continue fi ip_prefix=$(echo "$host" | cut -d'.' -f1,2) if echo "$CLOUDFLARE_OCTETS" | grep -wq "$ip_prefix"; then - nolog "⚠️ WARP detected ($host)" + print_global "⚠️ WARP detected: $host" + warp_found=1 fi done fi + + if [ "$warp_found" -eq 0 ]; then + print_global "✅ No WARP configurations detected" + fi + + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + print_global " FAKEIP ROUTER TEST" + print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + print_global "🔍 Testing system DNS resolver..." + nslookup -timeout=2 $TEST_DOMAIN + + local working_resolver=$(find_working_resolver) + if [ -z "$working_resolver" ]; then + print_global "❌ No working external resolver found" + else + print_global "🔍 Testing external resolver ($working_resolver)..." + nslookup -timeout=2 $TEST_DOMAIN $working_resolver + fi + + print_global "🔍 Testing sing-box DNS server (127.0.0.42)..." + local result=$(nslookup -timeout=2 $TEST_DOMAIN 127.0.0.42 2>&1) + echo "$result" + + if echo "$result" | grep -q "198.18"; then + print_global "✅ FakeIP is working correctly on router (198.18.x.x)" + else + print_global "❌ FakeIP test failed - domain did not resolve to FakeIP range" + if ! pgrep -f "sing-box" >/dev/null; then + print_global " └─ sing-box is not running" + else + print_global " └─ sing-box is running, checking configuration..." + + if [ -f "$SING_BOX_CONFIG" ]; then + local fakeip_enabled=$(jq -r '.dns.fakeip.enabled' "$SING_BOX_CONFIG") + local fakeip_range=$(jq -r '.dns.fakeip.inet4_range' "$SING_BOX_CONFIG") + local dns_rules=$(jq -r '.dns.rules[] | select(.server == "fakeip-server") | .domain' "$SING_BOX_CONFIG") + + print_global " ├─ FakeIP enabled: $fakeip_enabled" + print_global " ├─ FakeIP range: $fakeip_range" + print_global " └─ FakeIP domain: $dns_rules" + else + print_global " └─ sing-box config file not found" + fi + fi + fi } case "$1" in