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.

This commit is contained in:
Ivan K
2025-05-01 17:18:07 +03:00
parent f29b97e495
commit 48716e7156
4 changed files with 391 additions and 183 deletions

View File

@@ -63,20 +63,20 @@ function getNetworkInterfaces(o, section_id, excludeInterfaces = []) {
} }
function getNetworkNetworks(o, section_id, excludeInterfaces = []) { function getNetworkNetworks(o, section_id, excludeInterfaces = []) {
return network.getNetworks().then(networks => { return network.getNetworks().then(networks => {
o.keylist = []; o.keylist = [];
o.vallist = []; o.vallist = [];
networks.forEach(net => { networks.forEach(net => {
const name = net.getName(); const name = net.getName();
const ifname = net.getIfname(); const ifname = net.getIfname();
if (name && !excludeInterfaces.includes(name)) { if (name && !excludeInterfaces.includes(name)) {
o.value(name, ifname ? `${name} (${ifname})` : name); o.value(name, ifname ? `${name} (${ifname})` : name);
} }
}); });
}).catch(error => { }).catch(error => {
console.error('Failed to get networks:', error); console.error('Failed to get networks:', error);
}); });
} }
function createConfigSection(section, map, network) { function createConfigSection(section, map, network) {
@@ -623,7 +623,33 @@ const createModalContent = (title, content) => {
const showConfigModal = async (command, title) => { const showConfigModal = async (command, title) => {
const res = await safeExec('/usr/bin/podkop', [command]); 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)); ui.showModal(_(title), createModalContent(_(title), formattedOutput));
}; };
@@ -672,11 +698,18 @@ const createStatusPanel = (title, status, buttons) => {
E('strong', {}, _(title)), E('strong', {}, _(title)),
status && E('br'), status && E('br'),
status && E('span', { 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 ? '✔' : '✘', title === 'Sing-box Status' ?
' ', (status.running && !status.enabled ? '✔ running' : '✘ ' + status.status) :
status.status title === 'Podkop Status' ?
(status.enabled ? '✔ enabled' : '✘ disabled') :
(status.running ? '✔' : '✘') + ' ' + status.status
]) ])
].filter(Boolean); ].filter(Boolean);
@@ -688,7 +721,80 @@ const createStatusPanel = (title, status, buttons) => {
E('div', { E('div', {
'class': 'panel-body', 'class': 'panel-body',
'style': 'display: flex; flex-direction: column; gap: 8px;' '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 reload: true
}), }),
ButtonFactory.createModalButton({ ButtonFactory.createModalButton({
label: 'Show Config', label: _('Global check'),
command: 'show_config', command: 'global_check',
title: 'Podkop Configuration' title: _('Click here for all the info')
}), }),
ButtonFactory.createModalButton({ ButtonFactory.createModalButton({
label: 'View Logs', label: 'View Logs',
@@ -807,12 +913,7 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
bypassStatus.message bypassStatus.message
]) ])
]) ])
]), ])
ButtonFactory.createModalButton({
label: _('Global check'),
command: 'global_check',
title: _('Click here for all the info')
})
]), ]),
// Version Information Panel // Version Information Panel
@@ -1350,32 +1451,67 @@ return view.extend({
async function updateDiagnostics() { async function updateDiagnostics() {
try { try {
const [ const results = {
podkopStatus, podkopStatus: null,
singboxStatus, singboxStatus: null,
podkop, podkop: null,
luci, luci: null,
singbox, singbox: null,
system, system: null,
fakeipStatus, fakeipStatus: null,
fakeipCLIStatus, fakeipCLIStatus: null,
dnsStatus, dnsStatus: null,
bypassStatus bypassStatus: null
] = 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 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'); const container = document.getElementById('diagnostics-status');
if (!container) return; if (!container) return;
@@ -1395,11 +1531,7 @@ return view.extend({
const label = activeConfig.split('#').pop(); const label = activeConfig.split('#').pop();
if (label && label.trim()) { if (label && label.trim()) {
configName = _('Config: ') + decodeURIComponent(label); 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); console.error('Error getting config name from UCI:', e);
} }
// Create a modified statusSection function with the configName const parsedPodkopStatus = JSON.parse(results.podkopStatus.stdout || '{"enabled":0,"status":"error"}');
const statusSection = createStatusSection(parsedPodkopStatus, parsedSingboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus, dnsStatus, bypassStatus, configName); 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.innerHTML = '';
container.appendChild(statusSection); container.appendChild(statusSection);
const fakeipElement = document.getElementById('fakeip-status'); // Обновляем отдельные элементы статуса
if (fakeipElement) { const updateStatusElement = (elementId, status, template) => {
fakeipElement.innerHTML = E('span', { 'style': `color: ${fakeipStatus.color}` }, [ const element = document.getElementById(elementId);
fakeipStatus.state === 'working' ? '✔ ' : fakeipStatus.state === 'not_working' ? '✘ ' : '! ', if (element) {
fakeipStatus.message element.innerHTML = template(status);
]).outerHTML; }
} };
const fakeipCLIElement = document.getElementById('fakeip-cli-status'); updateStatusElement('fakeip-status', results.fakeipStatus,
if (fakeipCLIElement) { status => E('span', { 'style': `color: ${status.color}` }, [
fakeipCLIElement.innerHTML = E('span', { 'style': `color: ${fakeipCLIStatus.color}` }, [ status.state === 'working' ? '✔ ' : status.state === 'not_working' ? '✘ ' : '! ',
fakeipCLIStatus.state === 'working' ? '✔ ' : fakeipCLIStatus.state === 'not_working' ? '✘ ' : '! ', status.message
fakeipCLIStatus.message ]).outerHTML
]).outerHTML; );
}
const dnsRemoteElement = document.getElementById('dns-remote-status'); updateStatusElement('fakeip-cli-status', results.fakeipCLIStatus,
if (dnsRemoteElement) { status => E('span', { 'style': `color: ${status.color}` }, [
dnsRemoteElement.innerHTML = E('span', { 'style': `color: ${dnsStatus.remote.color}` }, [ status.state === 'working' ? '✔ ' : status.state === 'not_working' ? '✘ ' : '! ',
dnsStatus.remote.state === 'available' ? '✔ ' : dnsStatus.remote.state === 'unavailable' ? '✘ ' : '! ', status.message
dnsStatus.remote.message ]).outerHTML
]).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) { } catch (e) {
const container = document.getElementById('diagnostics-status'); const container = document.getElementById('diagnostics-status');
if (container) { if (container) {

View File

@@ -819,3 +819,27 @@ msgstr "недоступен"
msgid "Apply for SS2022" msgid "Apply for SS2022"
msgstr "Применить для 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 "Глобальная проверка"

View File

@@ -1170,3 +1170,27 @@ msgstr ""
msgid "unavailable" msgid "unavailable"
msgstr "" 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 ""

View File

@@ -1954,8 +1954,6 @@ show_sing_box_config() {
} }
show_config() { show_config() {
nolog "📄 Current podkop configuration:"
if [ ! -f /etc/config/podkop ]; then if [ ! -f /etc/config/podkop ]; then
nolog "Configuration file not found" nolog "Configuration file not found"
return 1 return 1
@@ -2046,36 +2044,18 @@ get_sing_box_status() {
} }
get_status() { get_status() {
local running=0
local enabled=0 local enabled=0
local status="" local status=""
# Check if service is enabled # Check if service is enabled
if [ -x /etc/rc.d/S99podkop ]; then if [ -x /etc/rc.d/S99podkop ]; then
enabled=1 enabled=1
fi status="enabled"
# 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
else else
if [ $enabled -eq 1 ]; then status="disabled"
status="stopped but enabled"
else
status="stopped & disabled"
fi
fi fi
echo "{\"running\":$running,\"enabled\":$enabled,\"status\":\"$status\"}" echo "{\"enabled\":$enabled,\"status\":\"$status\"}"
} }
check_dns_available() { 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}" log "DNS probe domain ${domain} configured with override to port ${override_port}"
} }
print_global() {
local message="$1"
echo "$message"
}
global_check() { 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}')" print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
nolog "LuCi App $(opkg list-installed luci-app-podkop | awk '{print $3}')" print_global " PODKOP CONFIGURATION"
nolog "Sing-box $(sing-box version | head -n 1 | awk '{print $3}')" print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
nolog "$(grep OPENWRT_RELEASE /etc/os-release | cut -d'"' -f2)"
nolog "Device: $(cat /tmp/sysinfo/model)"
printf "\n"
show_config show_config
printf "\n" print_global ""
nolog "Checking fakeip functionality..." print_global ""
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
nolog "➡️ DNS resolution: system DNS server" print_global " SYSTEM CHECKS"
nslookup -timeout=2 $TEST_DOMAIN print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
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"
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 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:" print_global "❌ /etc/resolv.conf contains external nameserver:"
cat /etc/resolv.conf cat /etc/resolv.conf | sed 's/^/ /'
echo "" echo ""
else else
nolog "✅ /etc/resolv.conf OK" print_global "✅ /etc/resolv.conf - OK"
fi fi
cachesize="$(uci get dhcp.@dnsmasq[0].cachesize 2>/dev/null)" 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)" server="$(uci get dhcp.@dnsmasq[0].server 2>/dev/null)"
if [ "$cachesize" != "0" ] || [ "$noresolv" != "1" ] || [ "$server" != "127.0.0.42" ]; then if [ "$cachesize" != "0" ] || [ "$noresolv" != "1" ] || [ "$server" != "127.0.0.42" ]; then
nolog "❌ The configuration differs from the template. 📄 DHCP config:" print_global "❌ DHCP configuration differs from template:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp | sed 's/^/ /'
elif [ "$(uci get podkop.main.dont_touch_dhcp 2>/dev/null)" = "1" ]; then elif [ "$(uci get podkop.main.dont_touch_dhcp 2>/dev/null)" = "1" ]; then
nolog "⚠️ Enable dont_touch_dhcp. 📄 DHCP config:" print_global "⚠️ dont_touch_dhcp is enabled:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp | sed 's/^/ /'
else else
nolog "✅ /etc/config/dhcp" print_global "✅ DHCP configuration - OK"
fi fi
if ! pgrep -f "sing-box" >/dev/null; then if ! pgrep -f "sing-box" >/dev/null; then
nolog "❌ sing-box is not running" print_global "❌ sing-box process - not running"
else else
nolog "✅ sing-box is running" print_global "✅ sing-box process - running"
fi 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 if ! nft list table inet PodkopTable >/dev/null 2>&1; then
nolog "PodkopTable not found" print_global "❌ PodkopTable not found"
else else
nft list table inet PodkopTable nft list table inet PodkopTable | sed 's/^/ /'
fi fi
nolog "📄 WAN config" print_global ""
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global " WAN CONFIG"
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
if uci show network.wan >/dev/null 2>&1; then if uci show network.wan >/dev/null 2>&1; then
awk ' awk '
/^config / { /^config / {
@@ -2284,28 +2238,82 @@ global_check() {
print print
} }
} }
' /etc/config/network ' /etc/config/network | sed 's/^/ /'
else else
nolog "WAN not exists" print_global "❌ WAN configuration not found"
fi 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 \ 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 \ 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" 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 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 uci show network | grep endpoint_host | cut -d'=' -f2 | tr -d "'\" " | while read -r host; do
if [ "$host" = "engage.cloudflareclient.com" ]; then if [ "$host" = "engage.cloudflareclient.com" ]; then
nolog "⚠️ WARP detected ($host)" print_global "⚠️ WARP detected: $host"
warp_found=1
continue continue
fi fi
ip_prefix=$(echo "$host" | cut -d'.' -f1,2) ip_prefix=$(echo "$host" | cut -d'.' -f1,2)
if echo "$CLOUDFLARE_OCTETS" | grep -wq "$ip_prefix"; then if echo "$CLOUDFLARE_OCTETS" | grep -wq "$ip_prefix"; then
nolog "⚠️ WARP detected ($host)" print_global "⚠️ WARP detected: $host"
warp_found=1
fi fi
done done
fi 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 case "$1" in