Compare commits

...

14 Commits

Author SHA1 Message Date
itdoginfo
3040ce7286 v0.3.43 2025-05-02 14:53:11 +03:00
itdoginfo
e025271a14 Added to global check: DNS check and proxy check. From VizzleTF 2025-05-02 14:50:06 +03:00
itdoginfo
2b8208186d Fix global check text 2025-05-02 13:55:07 +03:00
itdoginfo
17fb11baf0 Fixed diagnostics from VizzleTF 2025-05-02 13:34:11 +03:00
itdoginfo
3c1b041b52 Edited text from #96 2025-05-01 22:52:41 +03:00
itdoginfo
38acac1a31 Merge pull request #96 from itdoginfo/chore/sing-box-status
Issue #91 , Issue #94
2025-05-01 22:16:38 +03:00
Ivan K
2939229df3 back to the future 2025-05-01 19:30:05 +03:00
Ivan K
26c3d0bc7e ♻️ refactor(podkop): simplify DoH URL determination logic 2025-05-01 19:26:21 +03:00
Ivan K
b364363b1b feat(dns): add DoH URL resolution function 2025-05-01 19:20:36 +03:00
itdoginfo
d85caf0c0c Fix https-dns-proxy i18 2025-05-01 19:10:18 +03:00
Ivan K
65f72e1e04 ♻️ refactor(podkop): update WARP detection logic 2025-05-01 18:29:42 +03:00
Ivan K
e59ef6dd6f 💄 style(podkop): remove unnecessary sed commands in global_check 2025-05-01 17:57:51 +03:00
Ivan K
05272de650 💄 style(podkop): update formatting and messages 2025-05-01 17:48:25 +03:00
Ivan K
48716e7156 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. 2025-05-01 17:18:07 +03:00
7 changed files with 411 additions and 238 deletions

View File

@@ -446,7 +446,7 @@ check_system() {
case $DNSPROXY in case $DNSPROXY in
yes|y|Y|yes) yes|y|Y|yes)
opkg remove --force-depends luci-app-https-dns-proxy https-dns-proxy opkg remove --force-depends luci-app-https-dns-proxy https-dns-proxy luci-i18n-https-dns-proxy*
break break
;; ;;
*) *)

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-podkop PKG_NAME:=luci-app-podkop
PKG_VERSION:=0.3.42 PKG_VERSION:=0.3.43
PKG_RELEASE:=1 PKG_RELEASE:=1
LUCI_TITLE:=LuCI podkop app LUCI_TITLE:=LuCI podkop app

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) {
@@ -621,9 +621,61 @@ const createModalContent = (title, content) => {
]; ];
}; };
// Add IP masking function before showConfigModal
const maskIP = (ip) => {
if (!ip) return '';
const parts = ip.split('.');
if (parts.length !== 4) return ip;
return ['XX', 'XX', 'XX', parts[3]].join('.');
};
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);
if (data.fakeip === true) {
formattedOutput += '\n✅ ' + _('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';
}
// Bypass check
const bypassResponse = await fetch('https://fakeip.tech-domain.club/check', { signal: controller.signal });
const bypassData = await bypassResponse.json();
const bypassResponse2 = await fetch('https://ip.tech-domain.club/check', { signal: controller.signal });
const bypassData2 = await bypassResponse2.json();
formattedOutput += '━━━━━━━━━━━━━━━━━━━━━━━━━━━\n';
if (bypassData.IP && bypassData2.IP && bypassData.IP !== bypassData2.IP) {
formattedOutput += '✅ ' + _('Proxy working correctly') + '\n';
formattedOutput += _('Direct IP: ') + maskIP(bypassData.IP) + '\n';
formattedOutput += _('Proxy IP: ') + maskIP(bypassData2.IP) + '\n';
} else if (bypassData.IP === bypassData2.IP) {
formattedOutput += '❌ ' + _('Proxy is not working - same IP for both domains') + '\n';
formattedOutput += _('IP: ') + maskIP(bypassData.IP) + '\n';
} else {
formattedOutput += '❌ ' + _('Proxy check failed') + '\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));
}; };
@@ -667,16 +719,23 @@ const ButtonFactory = {
}; };
// Status Panel Factory // Status Panel Factory
const createStatusPanel = (title, status, buttons) => { const createStatusPanel = (title, status, buttons, extraData = {}) => {
const headerContent = [ const headerContent = [
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 +747,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: ${extraData.fakeipStatus?.color}` }, [
extraData.fakeipStatus?.state === 'working' ? '✔' : extraData.fakeipStatus?.state === 'not_working' ? '✘' : '!',
' ',
extraData.fakeipStatus?.state === 'working' ? _('works in browser') : _('not works in browser')
])
]),
E('div', {}, [
E('span', { style: `color: ${extraData.fakeipCLIStatus?.color}` }, [
extraData.fakeipCLIStatus?.state === 'working' ? '✔' : extraData.fakeipCLIStatus?.state === 'not_working' ? '✘' : '!',
' ',
extraData.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: ${extraData.dnsStatus?.remote?.color}` }, [
extraData.dnsStatus?.remote?.state === 'available' ? '✔' : extraData.dnsStatus?.remote?.state === 'unavailable' ? '✘' : '!',
' ',
extraData.dnsStatus?.remote?.message
]),
E('br'),
E('span', { style: `color: ${extraData.dnsStatus?.local?.color}` }, [
extraData.dnsStatus?.local?.state === 'available' ? '✔' : extraData.dnsStatus?.local?.state === 'unavailable' ? '✘' : '!',
' ',
extraData.dnsStatus?.local?.message
])
])
]),
E('div', { style: 'margin-bottom: 10px;' }, [
E('div', { style: 'margin-bottom: 5px;' }, [
E('strong', {}, extraData.configName),
E('br'),
E('span', { style: `color: ${extraData.bypassStatus?.color}` }, [
extraData.bypassStatus?.state === 'working' ? '✔' : extraData.bypassStatus?.state === 'not_working' ? '✘' : '!',
' ',
extraData.bypassStatus?.message
])
])
])
] : buttons)
]); ]);
}; };
@@ -698,12 +830,6 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
E('div', { 'class': 'table', style: 'display: flex; gap: 20px;' }, [ E('div', { 'class': 'table', style: 'display: flex; gap: 20px;' }, [
// Podkop Status Panel // Podkop Status Panel
createStatusPanel('Podkop Status', podkopStatus, [ createStatusPanel('Podkop Status', podkopStatus, [
ButtonFactory.createActionButton({
label: podkopStatus.running ? 'Stop Podkop' : 'Start Podkop',
type: podkopStatus.running ? 'remove' : 'apply',
action: podkopStatus.running ? 'stop' : 'start',
reload: true
}),
ButtonFactory.createActionButton({ ButtonFactory.createActionButton({
label: 'Restart Podkop', label: 'Restart Podkop',
type: 'apply', type: 'apply',
@@ -717,9 +843,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',
@@ -762,58 +888,14 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
}) })
]), ]),
// FakeIP Status Panel with both browser and router checks // FakeIP Status Panel
createStatusPanel(_('FakeIP Status'), null, [ createStatusPanel(_('FakeIP Status'), null, null, {
E('div', { style: 'margin-bottom: 10px;' }, [ fakeipStatus,
E('div', { style: 'margin-bottom: 5px;' }, [ fakeipCLIStatus,
E('span', { style: `color: ${fakeipStatus.color}` }, [ dnsStatus,
fakeipStatus.state === 'working' ? '✔' : fakeipStatus.state === 'not_working' ? '✘' : '!', bypassStatus,
' ', configName
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
])
])
]),
ButtonFactory.createModalButton({
label: _('Global check'),
command: 'global_check',
title: _('Click here for all the info')
})
]),
// Version Information Panel // Version Information Panel
createStatusPanel(_('Version Information'), null, [ createStatusPanel(_('Version Information'), null, [
@@ -1350,32 +1432,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"}'); // Perform all checks independently of each other
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 })
];
// Waiting for all the checks to be completed
await Promise.allSettled(checks);
const container = document.getElementById('diagnostics-status'); const container = document.getElementById('diagnostics-status');
if (!container) return; if (!container) return;
@@ -1395,11 +1512,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 +1520,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'); // Updating individual status items
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

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=podkop PKG_NAME:=podkop
PKG_VERSION:=0.3.42 PKG_VERSION:=0.3.43
PKG_RELEASE:=1 PKG_RELEASE:=1
PKG_MAINTAINER:=ITDog <podkop@itdog.info> PKG_MAINTAINER:=ITDog <podkop@itdog.info>

View File

@@ -24,6 +24,7 @@ TEST_DOMAIN="fakeip.tech-domain.club"
INTERFACES_LIST="" INTERFACES_LIST=""
SRC_INTERFACE="" SRC_INTERFACE=""
RESOLV_CONF="/etc/resolv.conf" RESOLV_CONF="/etc/resolv.conf"
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"
log() { log() {
local message="$1" local message="$1"
@@ -1954,8 +1955,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 +2045,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 +2152,34 @@ 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 "📡 Global check run!"
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "🛠️ System info"
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)"
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 config"
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"
show_config show_config
printf "\n"
nolog "Checking fakeip functionality..." print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "🔧 System check"
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"
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
echo "" echo ""
else else
nolog "✅ /etc/resolv.conf OK" print_global "✅ /etc/resolv.conf"
fi fi
cachesize="$(uci get dhcp.@dnsmasq[0].cachesize 2>/dev/null)" cachesize="$(uci get dhcp.@dnsmasq[0].cachesize 2>/dev/null)"
@@ -2243,29 +2187,31 @@ 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. 📄 DHCP config:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp
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. 📄 DHCP config:"
awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp awk '/^config /{p=($2=="dnsmasq")} p' /etc/config/dhcp
else else
nolog "✅ /etc/config/dhcp" print_global "✅ /etc/config/dhcp"
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 is not running"
else else
nolog "✅ sing-box is running" print_global "✅ sing-box is running"
fi fi
nolog "📄 NFT Table Podkop" print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "🧱 NFT table"
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
fi fi
nolog "📄 WAN config" print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "📄 WAN config"
if uci show network.wan >/dev/null 2>&1; then if uci show network.wan >/dev/null 2>&1; then
awk ' awk '
/^config / { /^config / {
@@ -2286,26 +2232,72 @@ global_check() {
} }
' /etc/config/network ' /etc/config/network
else else
nolog "WAN not exists" print_global "❌ WAN configuration not found"
fi fi
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"
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"
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 "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "⚠️ WARP detected: $host"
fi fi
done done
fi fi
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "➡️ DNS status"
dns_info=$(check_dns_available)
dns_type=$(echo "$dns_info" | jq -r '.dns_type')
dns_server=$(echo "$dns_info" | jq -r '.dns_server')
status=$(echo "$dns_info" | jq -r '.status')
print_global "$dns_type ($dns_server) is $status"
print_global "━━━━━━━━━━━━━━━━━━━━━━━━━━━"
print_global "🔁 FakeIP"
print_global "➡️ DNS resolution: system DNS server"
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 "➡️ DNS resolution: external resolver ($working_resolver)"
nslookup -timeout=2 $TEST_DOMAIN $working_resolver
fi
print_global "➡️ 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
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