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 d20b5f8..e940b2d 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 @@ -591,7 +591,7 @@ const createModalContent = (title, content) => { const showConfigModal = async (command, title) => { const res = await safeExec('/usr/bin/podkop', [command]); const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); - ui.showModal(_(title), createModalContent(title, formattedOutput)); + ui.showModal(_(title), createModalContent(_(title), formattedOutput)); }; // Button Factory @@ -650,7 +650,7 @@ const createStatusPanel = (title, status, buttons) => { }; // Update the status section creation -let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, singbox, system, fakeipStatus) { +let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus) { return E('div', { 'class': 'cbi-section' }, [ E('h3', {}, _('Service Status')), E('div', { 'class': 'table', style: 'display: flex; gap: 20px;' }, [ @@ -712,36 +712,54 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s }) ]), - // FakeIP Status Panel with dynamic status - createStatusPanel('FakeIP Status', { - running: fakeipStatus.state === 'working', - status: fakeipStatus.message - }, [ + // FakeIP Status Panel with both browser and router checks + createStatusPanel(_('FakeIP Status'), null, [ + 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') + ]) + ]) + ]), ButtonFactory.createModalButton({ - label: 'Check NFT Rules', + label: _('Check NFT Rules'), command: 'check_nft', - title: 'NFT Rules' + title: _('NFT Rules') }), ButtonFactory.createModalButton({ - label: 'Check DNSMasq', + label: _('Check DNSMasq'), command: 'check_dnsmasq', - title: 'DNSMasq Configuration' + title: _('DNSMasq Configuration') }), ButtonFactory.createModalButton({ - label: 'Update Lists', + label: _('Update Lists'), command: 'list_update', - title: 'Lists Update Results' + title: _('Lists Update Results') + }), + ButtonFactory.createModalButton({ + label: _('Check Router FakeIP'), + command: 'check_fakeip', + title: _('FakeIP Router Check') }) ]), // Version Information Panel - createStatusPanel('Version Information', null, [ + createStatusPanel(_('Version Information'), null, [ E('div', { 'style': 'margin-top: 10px; font-family: monospace; white-space: pre-wrap;' }, [ - E('strong', {}, 'Podkop: '), podkop.stdout ? podkop.stdout.trim() : _('Unknown'), '\n', - E('strong', {}, 'LuCI App: '), luci.stdout ? luci.stdout.trim() : _('Unknown'), '\n', - E('strong', {}, 'Sing-box: '), singbox.stdout ? singbox.stdout.trim() : _('Unknown'), '\n', - E('strong', {}, 'OpenWrt Version: '), system.stdout ? system.stdout.split('\n')[1].trim() : _('Unknown'), '\n', - E('strong', {}, 'Device Model: '), system.stdout ? system.stdout.split('\n')[4].trim() : _('Unknown') + E('strong', {}, _('Podkop: ')), podkop.stdout ? podkop.stdout.trim() : _('Unknown'), '\n', + E('strong', {}, _('LuCI App: ')), luci.stdout ? luci.stdout.trim() : _('Unknown'), '\n', + E('strong', {}, _('Sing-box: ')), singbox.stdout ? singbox.stdout.trim() : _('Unknown'), '\n', + E('strong', {}, _('OpenWrt Version: ')), system.stdout ? system.stdout.split('\n')[1].trim() : _('Unknown'), '\n', + E('strong', {}, _('Device Model: ')), system.stdout ? system.stdout.split('\n')[4].trim() : _('Unknown') ]) ]) ]) @@ -957,17 +975,15 @@ return view.extend({ const timeoutId = setTimeout(() => controller.abort(), 10000); try { - const response = await fetch('http://httpbin.org/ip', { signal: controller.signal }); - const text = await response.text(); + const response = await fetch('https://fakeip.tech-domain.club/check', { signal: controller.signal }); + const data = await response.json(); clearTimeout(timeoutId); - if (text.includes('Cannot GET /ip')) { + if (data.fakeip === true) { return resolve(createStatus('working', 'working', 'SUCCESS')); - } - if (text.includes('"origin":')) { + } else { return resolve(createStatus('not_working', 'not working', 'ERROR')); } - return resolve(createStatus('error', 'check error', 'WARNING')); } catch (fetchError) { clearTimeout(timeoutId); const message = fetchError.name === 'AbortError' ? 'timeout' : 'check error'; @@ -980,6 +996,39 @@ return view.extend({ }); } + function checkFakeIPCLI() { + const createStatus = (state, message, color) => ({ + state, + message: _(message), + color: STATUS_COLORS[color] + }); + + return new Promise(async (resolve) => { + try { + const singboxStatusResult = await safeExec('/usr/bin/podkop', ['get_sing_box_status']); + const singboxStatus = JSON.parse(singboxStatusResult.stdout || '{"running":0,"dns_configured":0}'); + + if (!singboxStatus.running) { + return resolve(createStatus('not_working', 'sing-box not running', 'ERROR')); + } + if (!singboxStatus.dns_configured) { + return resolve(createStatus('not_working', 'DNS not configured', 'ERROR')); + } + + const fakeipResult = await safeExec('/usr/bin/podkop', ['check_fakeip']); + + if (fakeipResult.stdout && fakeipResult.stdout.includes('198.18')) { + return resolve(createStatus('working', 'FakeIP working (CLI)', 'SUCCESS')); + } else { + return resolve(createStatus('not_working', 'FakeIP not working (CLI)', 'ERROR')); + } + } catch (error) { + console.error('Error in checkFakeIPCLI:', error); + return resolve(createStatus('error', 'CLI check error', 'WARNING')); + } + }); + } + async function updateDiagnostics() { try { const [ @@ -989,7 +1038,8 @@ return view.extend({ luci, singbox, system, - fakeipStatus + fakeipStatus, + fakeipCLIStatus ] = await Promise.all([ safeExec('/usr/bin/podkop', ['get_status']), safeExec('/usr/bin/podkop', ['get_sing_box_status']), @@ -997,7 +1047,8 @@ return view.extend({ safeExec('/usr/bin/podkop', ['show_luci_version']), safeExec('/usr/bin/podkop', ['show_sing_box_version']), safeExec('/usr/bin/podkop', ['show_system_info']), - checkFakeIP() + checkFakeIP(), + checkFakeIPCLI() ]); const parsedPodkopStatus = JSON.parse(podkopStatus.stdout || '{"running":0,"enabled":0,"status":"unknown"}'); @@ -1006,7 +1057,7 @@ return view.extend({ const container = document.getElementById('diagnostics-status'); if (!container) return; - const statusSection = createStatusSection(parsedPodkopStatus, parsedSingboxStatus, podkop, luci, singbox, system, fakeipStatus); + const statusSection = createStatusSection(parsedPodkopStatus, parsedSingboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus); container.innerHTML = ''; container.appendChild(statusSection); @@ -1017,6 +1068,14 @@ return view.extend({ fakeipStatus.message ]).outerHTML; } + + 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; + } } catch (e) { console.error('Error updating diagnostics:', e); const container = document.getElementById('diagnostics-status'); @@ -1049,6 +1108,7 @@ return view.extend({ const singboxStatusResult = await safeExec('/usr/bin/podkop', ['get_sing_box_status']); const singboxStatus = JSON.parse(singboxStatusResult.stdout || '{"running":0,"dns_configured":0}'); const fakeipStatus = await checkFakeIP(); + const fakeipCLIStatus = await checkFakeIPCLI(); titleDiv.textContent = versionText + (!singboxStatus.running || !singboxStatus.dns_configured === 'not_working' ? ' (not working)' : ''); diff --git a/luci-app-podkop/po/ru/podkop.po b/luci-app-podkop/po/ru/podkop.po index a3631f3..b4757bb 100644 --- a/luci-app-podkop/po/ru/podkop.po +++ b/luci-app-podkop/po/ru/podkop.po @@ -722,4 +722,28 @@ msgid "stopped but enabled" msgstr "остановлен, но активирован" msgid "stopped & disabled" -msgstr "остановлен и деактивирован" \ No newline at end of file +msgstr "остановлен и деактивирован" + +msgid "works in browser" +msgstr "работает в браузере" + +msgid "works on router" +msgstr "работает на роутере" + +msgid "Check Router FakeIP" +msgstr "Проверить FakeIP на роутере" + +msgid "FakeIP Router Check" +msgstr "Проверка FakeIP на роутере" + +msgid "FakeIP CLI Check" +msgstr "Проверка FakeIP через CLI" + +msgid "FakeIP CLI Check Results" +msgstr "Результаты проверки FakeIP через CLI" + +msgid "not works in browser" +msgstr "не работает в браузере" + +msgid "not works on router" +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 3e8a711..e478bb1 100644 --- a/luci-app-podkop/po/templates/podkop.pot +++ b/luci-app-podkop/po/templates/podkop.pot @@ -1076,4 +1076,28 @@ msgid "stopped but enabled" msgstr "" msgid "stopped & disabled" +msgstr "" + +msgid "works in browser" +msgstr "" + +msgid "works on router" +msgstr "" + +msgid "Check Router FakeIP" +msgstr "" + +msgid "FakeIP Router Check" +msgstr "" + +msgid "FakeIP CLI Check" +msgstr "" + +msgid "FakeIP CLI Check Results" +msgstr "" + +msgid "not works in browser" +msgstr "" + +msgid "not works on router" msgstr "" \ No newline at end of file diff --git a/podkop/files/usr/bin/podkop b/podkop/files/usr/bin/podkop index 1de47d8..d3e50cf 100755 --- a/podkop/files/usr/bin/podkop +++ b/podkop/files/usr/bin/podkop @@ -1709,6 +1709,69 @@ check_sing_box_logs() { echo "$logs" } +check_fakeip() { + nolog "Checking fakeip functionality..." + + if ! command -v nslookup >/dev/null 2>&1; then + nolog "nslookup is not installed" + return 1 + fi + + local test_domain="fakeip.tech-domain.club" + + # Additional DNS checks with different servers + nolog "Testing DNS resolution with default DNS server" + echo "=== Testing with default DNS server ===" + nslookup $test_domain + echo "" + + nolog "Testing DNS resolution with Google DNS (8.8.8.8)" + echo "=== Testing with Google DNS (8.8.8.8) ===" + nslookup $test_domain 8.8.8.8 + echo "" + + nolog "Testing DNS resolution with Cloudflare DNS (1.1.1.1)" + echo "=== Testing with Cloudflare DNS (1.1.1.1) ===" + nslookup $test_domain 1.1.1.1 + echo "" + + # Main FakeIP check + nolog "Testing DNS resolution for $test_domain using 127.0.0.42" + echo "=== Testing with FakeIP DNS (127.0.0.42) ===" + local result=$(nslookup $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)" + return 0 + 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 + + return 1 + fi +} + check_logs() { nolog "Showing podkop logs from system journal..." @@ -1878,19 +1941,14 @@ get_status() { } sing_box_add_secure_dns_probe_domain() { - local domain="httpbin.org" - local override_address="numbersapi.com" - - if [ -z "$override_address" ]; then - log "Error: Could not get br-lan IP address" - return 1 - fi + local domain="fakeip.tech-domain.club" + local override_port=8443 log "Adding DNS probe domain ${domain} to fakeip-server configuration" jq \ --arg domain "$domain" \ - --arg override "$override_address" \ + --argjson override_port "$override_port" \ '.dns.rules |= map( if .server == "fakeip-server" then . + { @@ -1904,11 +1962,11 @@ sing_box_add_secure_dns_probe_domain() { { "domain": $domain, "action": "route-options", - "override_address": $override + "override_port": $override_port } ]' "$SING_BOX_CONFIG" >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json "$SING_BOX_CONFIG" - log "DNS probe domain ${domain} configured with override to ${override_address}" + log "DNS probe domain ${domain} configured with override to port ${override_port}" } case "$1" in @@ -1946,6 +2004,9 @@ case "$1" in check_sing_box_logs) check_sing_box_logs ;; + check_fakeip) + check_fakeip + ;; check_dnsmasq) check_dnsmasq ;; @@ -1974,7 +2035,7 @@ case "$1" in get_sing_box_status ;; *) - echo "Usage: $0 {start|stop|restart|reload|enable|disable|main|list_update|check_proxy|check_nft|check_github|check_logs|check_sing_box_connections|check_sing_box_logs|check_dnsmasq|show_config|show_version|show_sing_box_config|show_luci_version|show_sing_box_version|show_system_info|get_status|get_sing_box_status}" + echo "Usage: $0 {start|stop|restart|reload|enable|disable|main|list_update|check_proxy|check_nft|check_github|check_logs|check_sing_box_connections|check_sing_box_logs|check_fakeip|check_dnsmasq|show_config|show_version|show_sing_box_config|show_luci_version|show_sing_box_version|show_system_info|get_status|get_sing_box_status}" exit 1 ;; esac \ No newline at end of file