Merge pull request #67 from itdoginfo/feature/no-more-cache
Feature/add DNS and bypass status checks to diagnostics
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
'require ui';
|
'require ui';
|
||||||
'require network';
|
'require network';
|
||||||
'require fs';
|
'require fs';
|
||||||
|
'require uci';
|
||||||
|
|
||||||
const STATUS_COLORS = {
|
const STATUS_COLORS = {
|
||||||
SUCCESS: '#4caf50',
|
SUCCESS: '#4caf50',
|
||||||
@@ -90,20 +91,29 @@ function createConfigSection(section, map, network) {
|
|||||||
|
|
||||||
if (cfgvalue) {
|
if (cfgvalue) {
|
||||||
try {
|
try {
|
||||||
// Extract only the active configuration (first non-comment line)
|
|
||||||
const activeConfig = cfgvalue.split('\n')
|
const activeConfig = cfgvalue.split('\n')
|
||||||
.map(line => line.trim())
|
.map(line => line.trim())
|
||||||
.find(line => line && !line.startsWith('//'));
|
.find(line => line && !line.startsWith('//'));
|
||||||
|
|
||||||
if (activeConfig) {
|
if (activeConfig) {
|
||||||
const label = activeConfig.split('#').pop() || 'unnamed';
|
if (activeConfig.includes('#')) {
|
||||||
const decodedLabel = decodeURIComponent(label);
|
const label = activeConfig.split('#').pop();
|
||||||
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Current config: ') + decodedLabel);
|
if (label && label.trim()) {
|
||||||
container.appendChild(descDiv);
|
const decodedLabel = decodeURIComponent(label);
|
||||||
|
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Current config: ') + decodedLabel);
|
||||||
|
container.appendChild(descDiv);
|
||||||
|
} else {
|
||||||
|
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Config without description'));
|
||||||
|
container.appendChild(descDiv);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Config without description'));
|
||||||
|
container.appendChild(descDiv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error parsing config label:', e);
|
console.error('Error parsing config label:', e);
|
||||||
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Current config: ') + (cfgvalue.split('#').pop() || 'unnamed'));
|
const descDiv = E('div', { 'class': 'cbi-value-description' }, _('Config without description'));
|
||||||
container.appendChild(descDiv);
|
container.appendChild(descDiv);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -121,7 +131,6 @@ function createConfigSection(section, map, network) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the first non-comment line as the active configuration
|
|
||||||
const activeConfig = value.split('\n')
|
const activeConfig = value.split('\n')
|
||||||
.map(line => line.trim())
|
.map(line => line.trim())
|
||||||
.find(line => line && !line.startsWith('//'));
|
.find(line => line && !line.startsWith('//'));
|
||||||
@@ -663,9 +672,8 @@ const createStatusPanel = (title, status, buttons) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Update the status section creation
|
// Update the status section creation
|
||||||
let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus) {
|
let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus, dnsStatus, bypassStatus, configName) {
|
||||||
return E('div', { 'class': 'cbi-section' }, [
|
return E('div', { 'class': 'cbi-section' }, [
|
||||||
E('h3', {}, _('Service Status')),
|
|
||||||
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, [
|
||||||
@@ -696,6 +704,11 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
|
|||||||
label: 'View Logs',
|
label: 'View Logs',
|
||||||
command: 'check_logs',
|
command: 'check_logs',
|
||||||
title: 'Podkop Logs'
|
title: 'Podkop Logs'
|
||||||
|
}),
|
||||||
|
ButtonFactory.createModalButton({
|
||||||
|
label: _('Update Lists'),
|
||||||
|
command: 'list_update',
|
||||||
|
title: _('Lists Update Results')
|
||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -715,6 +728,16 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
|
|||||||
label: 'Check Connections',
|
label: 'Check Connections',
|
||||||
command: 'check_sing_box_connections',
|
command: 'check_sing_box_connections',
|
||||||
title: 'Active Connections'
|
title: 'Active Connections'
|
||||||
|
}),
|
||||||
|
ButtonFactory.createModalButton({
|
||||||
|
label: _('Check NFT Rules'),
|
||||||
|
command: 'check_nft',
|
||||||
|
title: _('NFT Rules')
|
||||||
|
}),
|
||||||
|
ButtonFactory.createModalButton({
|
||||||
|
label: _('Check DNSMasq'),
|
||||||
|
command: 'check_dnsmasq',
|
||||||
|
title: _('DNSMasq Configuration')
|
||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
|
|
||||||
@@ -736,26 +759,34 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
ButtonFactory.createModalButton({
|
E('div', { style: 'margin-bottom: 10px;' }, [
|
||||||
label: _('Check NFT Rules'),
|
E('div', { style: 'margin-bottom: 5px;' }, [
|
||||||
command: 'check_nft',
|
E('strong', {}, _('DNS Status')),
|
||||||
title: _('NFT Rules')
|
E('br'),
|
||||||
}),
|
E('span', { style: `color: ${dnsStatus.remote.color}` }, [
|
||||||
ButtonFactory.createModalButton({
|
dnsStatus.remote.state === 'available' ? '✔' : dnsStatus.remote.state === 'unavailable' ? '✘' : '!',
|
||||||
label: _('Check DNSMasq'),
|
' ',
|
||||||
command: 'check_dnsmasq',
|
dnsStatus.remote.message
|
||||||
title: _('DNSMasq Configuration')
|
]),
|
||||||
}),
|
E('br'),
|
||||||
ButtonFactory.createModalButton({
|
E('span', { style: `color: ${dnsStatus.local.color}` }, [
|
||||||
label: _('Update Lists'),
|
dnsStatus.local.state === 'available' ? '✔' : dnsStatus.local.state === 'unavailable' ? '✘' : '!',
|
||||||
command: 'list_update',
|
' ',
|
||||||
title: _('Lists Update Results')
|
dnsStatus.local.message
|
||||||
}),
|
])
|
||||||
ButtonFactory.createModalButton({
|
])
|
||||||
label: _('Check Router FakeIP'),
|
]),
|
||||||
command: 'check_fakeip',
|
E('div', { style: 'margin-bottom: 10px;' }, [
|
||||||
title: _('FakeIP Router Check')
|
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
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Version Information Panel
|
// Version Information Panel
|
||||||
@@ -772,6 +803,39 @@ let createStatusSection = function (podkopStatus, singboxStatus, podkop, luci, s
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function checkDNSAvailability() {
|
||||||
|
const createStatus = (state, message, color) => ({
|
||||||
|
state,
|
||||||
|
message: _(message),
|
||||||
|
color: STATUS_COLORS[color]
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
try {
|
||||||
|
const dnsStatusResult = await safeExec('/usr/bin/podkop', ['check_dns_available']);
|
||||||
|
const dnsStatus = JSON.parse(dnsStatusResult.stdout || '{"dns_type":"unknown","dns_server":"unknown","is_available":0,"status":"unknown","local_dns_working":0,"local_dns_status":"unknown"}');
|
||||||
|
|
||||||
|
const remoteStatus = dnsStatus.is_available ?
|
||||||
|
createStatus('available', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) available`, 'SUCCESS') :
|
||||||
|
createStatus('unavailable', `${dnsStatus.dns_type.toUpperCase()} (${dnsStatus.dns_server}) unavailable`, 'ERROR');
|
||||||
|
|
||||||
|
const localStatus = dnsStatus.local_dns_working ?
|
||||||
|
createStatus('available', 'Router DNS working', 'SUCCESS') :
|
||||||
|
createStatus('unavailable', 'Router DNS not working', 'ERROR');
|
||||||
|
|
||||||
|
return resolve({
|
||||||
|
remote: remoteStatus,
|
||||||
|
local: localStatus
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return resolve({
|
||||||
|
remote: createStatus('error', 'DNS check error', 'WARNING'),
|
||||||
|
local: createStatus('error', 'DNS check error', 'WARNING')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return view.extend({
|
return view.extend({
|
||||||
async render() {
|
async render() {
|
||||||
document.head.insertAdjacentHTML('beforeend', `
|
document.head.insertAdjacentHTML('beforeend', `
|
||||||
@@ -1071,6 +1135,82 @@ return view.extend({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkBypass() {
|
||||||
|
const createStatus = (state, message, color) => ({
|
||||||
|
state,
|
||||||
|
message: _(message),
|
||||||
|
color: STATUS_COLORS[color]
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
try {
|
||||||
|
let configMode = 'proxy'; // Default fallback
|
||||||
|
try {
|
||||||
|
const formData = document.querySelector('form.map-podkop');
|
||||||
|
if (formData) {
|
||||||
|
const modeSelect = formData.querySelector('select[name="cbid.podkop.main.mode"]');
|
||||||
|
if (modeSelect && modeSelect.value) {
|
||||||
|
configMode = modeSelect.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (formError) {
|
||||||
|
console.error('Error getting mode from form:', formError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if sing-box is running
|
||||||
|
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', `${configMode} not running`, 'ERROR'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch IP from first endpoint
|
||||||
|
let ip1 = null;
|
||||||
|
try {
|
||||||
|
const controller1 = new AbortController();
|
||||||
|
const timeoutId1 = setTimeout(() => controller1.abort(), 10000);
|
||||||
|
|
||||||
|
const response1 = await fetch('https://fakeip.tech-domain.club/check', { signal: controller1.signal });
|
||||||
|
const data1 = await response1.json();
|
||||||
|
clearTimeout(timeoutId1);
|
||||||
|
|
||||||
|
ip1 = data1.IP;
|
||||||
|
} catch (error) {
|
||||||
|
return resolve(createStatus('error', 'First endpoint check failed', 'WARNING'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch IP from second endpoint
|
||||||
|
let ip2 = null;
|
||||||
|
try {
|
||||||
|
const controller2 = new AbortController();
|
||||||
|
const timeoutId2 = setTimeout(() => controller2.abort(), 10000);
|
||||||
|
|
||||||
|
const response2 = await fetch('https://ip.tech-domain.club/check', { signal: controller2.signal });
|
||||||
|
const data2 = await response2.json();
|
||||||
|
clearTimeout(timeoutId2);
|
||||||
|
|
||||||
|
ip2 = data2.IP;
|
||||||
|
} catch (error) {
|
||||||
|
return resolve(createStatus('not_working', `${configMode} not working`, 'ERROR'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare IPs
|
||||||
|
if (ip1 && ip2) {
|
||||||
|
if (ip1 !== ip2) {
|
||||||
|
return resolve(createStatus('working', `${configMode} working correctly`, 'SUCCESS'));
|
||||||
|
} else {
|
||||||
|
return resolve(createStatus('not_working', `${configMode} routing incorrect`, 'ERROR'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return resolve(createStatus('error', 'IP comparison failed', 'WARNING'));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return resolve(createStatus('error', 'Bypass check error', 'WARNING'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function updateDiagnostics() {
|
async function updateDiagnostics() {
|
||||||
try {
|
try {
|
||||||
const [
|
const [
|
||||||
@@ -1081,7 +1221,9 @@ return view.extend({
|
|||||||
singbox,
|
singbox,
|
||||||
system,
|
system,
|
||||||
fakeipStatus,
|
fakeipStatus,
|
||||||
fakeipCLIStatus
|
fakeipCLIStatus,
|
||||||
|
dnsStatus,
|
||||||
|
bypassStatus
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
safeExec('/usr/bin/podkop', ['get_status']),
|
safeExec('/usr/bin/podkop', ['get_status']),
|
||||||
safeExec('/usr/bin/podkop', ['get_sing_box_status']),
|
safeExec('/usr/bin/podkop', ['get_sing_box_status']),
|
||||||
@@ -1090,7 +1232,9 @@ return view.extend({
|
|||||||
safeExec('/usr/bin/podkop', ['show_sing_box_version']),
|
safeExec('/usr/bin/podkop', ['show_sing_box_version']),
|
||||||
safeExec('/usr/bin/podkop', ['show_system_info']),
|
safeExec('/usr/bin/podkop', ['show_system_info']),
|
||||||
checkFakeIP(),
|
checkFakeIP(),
|
||||||
checkFakeIPCLI()
|
checkFakeIPCLI(),
|
||||||
|
checkDNSAvailability(),
|
||||||
|
checkBypass()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const parsedPodkopStatus = JSON.parse(podkopStatus.stdout || '{"running":0,"enabled":0,"status":"unknown"}');
|
const parsedPodkopStatus = JSON.parse(podkopStatus.stdout || '{"running":0,"enabled":0,"status":"unknown"}');
|
||||||
@@ -1099,7 +1243,35 @@ return view.extend({
|
|||||||
const container = document.getElementById('diagnostics-status');
|
const container = document.getElementById('diagnostics-status');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const statusSection = createStatusSection(parsedPodkopStatus, parsedSingboxStatus, podkop, luci, singbox, system, fakeipStatus, fakeipCLIStatus);
|
let configName = _('Main config');
|
||||||
|
try {
|
||||||
|
const data = await uci.load('podkop');
|
||||||
|
const proxyString = uci.get('podkop', 'main', 'proxy_string');
|
||||||
|
|
||||||
|
if (proxyString) {
|
||||||
|
const activeConfig = proxyString.split('\n')
|
||||||
|
.map(line => line.trim())
|
||||||
|
.find(line => line && !line.startsWith('//'));
|
||||||
|
|
||||||
|
if (activeConfig) {
|
||||||
|
if (activeConfig.includes('#')) {
|
||||||
|
const label = activeConfig.split('#').pop();
|
||||||
|
if (label && label.trim()) {
|
||||||
|
configName = _('Config: ') + decodeURIComponent(label);
|
||||||
|
} else {
|
||||||
|
configName = _('Main config');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
configName = _('Main config');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
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);
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
container.appendChild(statusSection);
|
container.appendChild(statusSection);
|
||||||
|
|
||||||
@@ -1118,6 +1290,22 @@ return view.extend({
|
|||||||
fakeipCLIStatus.message
|
fakeipCLIStatus.message
|
||||||
]).outerHTML;
|
]).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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
@@ -1142,6 +1330,15 @@ return view.extend({
|
|||||||
const titleDiv = E('h2', { 'class': 'cbi-map-title' }, _('Podkop'));
|
const titleDiv = E('h2', { 'class': 'cbi-map-title' }, _('Podkop'));
|
||||||
node.insertBefore(titleDiv, node.firstChild);
|
node.insertBefore(titleDiv, node.firstChild);
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', function () {
|
||||||
|
const diagnosticsContainer = document.getElementById('diagnostics-status');
|
||||||
|
if (document.hidden) {
|
||||||
|
stopDiagnosticsUpdates();
|
||||||
|
} else if (diagnosticsContainer && diagnosticsContainer.hasAttribute('data-loading')) {
|
||||||
|
startDiagnosticsUpdates();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const diagnosticsContainer = document.getElementById('diagnostics-status');
|
const diagnosticsContainer = document.getElementById('diagnostics-status');
|
||||||
if (diagnosticsContainer) {
|
if (diagnosticsContainer) {
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ msgstr "Конфигурация Outbound"
|
|||||||
msgid "Proxy Configuration URL"
|
msgid "Proxy Configuration URL"
|
||||||
msgstr "URL конфигурации прокси"
|
msgstr "URL конфигурации прокси"
|
||||||
|
|
||||||
msgid "Enter connection string starting with vless:// or ss:// for proxy configuration"
|
msgid "Enter connection string starting with vless:// or ss:// for proxy configuration. Add comments with // for saving other configs"
|
||||||
msgstr "Введите строку подключения, начинающуюся с vless:// или ss:// для настройки прокси"
|
msgstr "Введите строку подключения, начинающуюся с vless:// или ss:// для настройки прокси. Добавляйте комментарии с // для сохранения других конфигураций"
|
||||||
|
|
||||||
msgid "Outbound Configuration"
|
msgid "Outbound Configuration"
|
||||||
msgstr "Конфигурация исходящего соединения"
|
msgstr "Конфигурация исходящего соединения"
|
||||||
@@ -749,4 +749,67 @@ msgid "not works on router"
|
|||||||
msgstr "не работает на роутере"
|
msgstr "не работает на роутере"
|
||||||
|
|
||||||
msgid "Diagnostics"
|
msgid "Diagnostics"
|
||||||
msgstr "Диагностика"
|
msgstr "Диагностика"
|
||||||
|
|
||||||
|
msgid "DNS Status"
|
||||||
|
msgstr "Статус DNS"
|
||||||
|
|
||||||
|
msgid "Bypass Status"
|
||||||
|
msgstr "Статус обхода"
|
||||||
|
|
||||||
|
msgid "proxy working correctly"
|
||||||
|
msgstr "прокси работает корректно"
|
||||||
|
|
||||||
|
msgid "vpn working correctly"
|
||||||
|
msgstr "vpn работает корректно"
|
||||||
|
|
||||||
|
msgid "proxy not working"
|
||||||
|
msgstr "прокси не работает"
|
||||||
|
|
||||||
|
msgid "vpn not working"
|
||||||
|
msgstr "vpn не работает"
|
||||||
|
|
||||||
|
msgid "proxy not running"
|
||||||
|
msgstr "прокси не запущен"
|
||||||
|
|
||||||
|
msgid "vpn not running"
|
||||||
|
msgstr "vpn не запущен"
|
||||||
|
|
||||||
|
msgid "proxy routing incorrect"
|
||||||
|
msgstr "маршрутизация прокси некорректна"
|
||||||
|
|
||||||
|
msgid "vpn routing incorrect"
|
||||||
|
msgstr "маршрутизация vpn некорректна"
|
||||||
|
|
||||||
|
msgid "First endpoint check failed"
|
||||||
|
msgstr "Проверка первой конечной точки не удалась"
|
||||||
|
|
||||||
|
msgid "IP comparison failed"
|
||||||
|
msgstr "Сравнение IP-адресов не удалось"
|
||||||
|
|
||||||
|
msgid "Bypass check error"
|
||||||
|
msgstr "Ошибка проверки обхода"
|
||||||
|
|
||||||
|
msgid "Main config"
|
||||||
|
msgstr "Основная конфигурация"
|
||||||
|
|
||||||
|
msgid "Config without description"
|
||||||
|
msgstr "Конфигурация без описания"
|
||||||
|
|
||||||
|
msgid "DNS working"
|
||||||
|
msgstr "DNS работает"
|
||||||
|
|
||||||
|
msgid "Router DNS working"
|
||||||
|
msgstr "DNS роутера работает"
|
||||||
|
|
||||||
|
msgid "Router DNS not working"
|
||||||
|
msgstr "DNS роутера не работает"
|
||||||
|
|
||||||
|
msgid "DNS check error"
|
||||||
|
msgstr "Ошибка проверки DNS"
|
||||||
|
|
||||||
|
msgid "available"
|
||||||
|
msgstr "доступен"
|
||||||
|
|
||||||
|
msgid "unavailable"
|
||||||
|
msgstr "недоступен"
|
||||||
@@ -1103,4 +1103,70 @@ msgid "not works on router"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Diagnostics"
|
msgid "Diagnostics"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DNS Status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bypass Status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "proxy working correctly"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "vpn working correctly"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "proxy not working"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "vpn not working"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "proxy not running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "vpn not running"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "proxy routing incorrect"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "vpn routing incorrect"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "First endpoint check failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "IP comparison failed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Bypass check error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Main config"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enter connection string starting with vless:// or ss:// for proxy configuration. Add comments with // for backup configs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Config without description"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DNS working"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Router DNS working"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Router DNS not working"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "DNS check error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "available"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "unavailable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -63,6 +63,7 @@ start() {
|
|||||||
sing_box_dns
|
sing_box_dns
|
||||||
sing_box_dns_rule_fakeip
|
sing_box_dns_rule_fakeip
|
||||||
sing_box_rule_dns
|
sing_box_rule_dns
|
||||||
|
sing_box_create_bypass_ruleset
|
||||||
sing_box_add_secure_dns_probe_domain
|
sing_box_add_secure_dns_probe_domain
|
||||||
sing_box_cache_file
|
sing_box_cache_file
|
||||||
process_socks5
|
process_socks5
|
||||||
@@ -726,6 +727,42 @@ sing_box_dns() {
|
|||||||
}' $SING_BOX_CONFIG > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
|
}' $SING_BOX_CONFIG > /tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sing_box_create_bypass_ruleset() {
|
||||||
|
log "Creating bypass ruleset for direct access"
|
||||||
|
|
||||||
|
jq '
|
||||||
|
.route.rule_set += [{
|
||||||
|
"tag": "bypass",
|
||||||
|
"type": "inline",
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"domain_suffix": [
|
||||||
|
"ip.tech-domain.club"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
|
||||||
|
|
||||||
|
# Add a rule to route bypass domains to direct-out outbound
|
||||||
|
jq '
|
||||||
|
.route.rules += [{
|
||||||
|
"inbound": ["tproxy-in"],
|
||||||
|
"rule_set": ["bypass"],
|
||||||
|
"outbound": "main",
|
||||||
|
"action": "route"
|
||||||
|
}]' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
|
||||||
|
|
||||||
|
# Make sure the bypass ruleset is in the fakeip DNS rule
|
||||||
|
jq '
|
||||||
|
.dns.rules = (.dns.rules | map(
|
||||||
|
if .server == "fakeip-server" then
|
||||||
|
.rule_set += ["bypass"]
|
||||||
|
else
|
||||||
|
.
|
||||||
|
end
|
||||||
|
))' $SING_BOX_CONFIG >/tmp/sing-box-config-tmp.json && mv /tmp/sing-box-config-tmp.json $SING_BOX_CONFIG
|
||||||
|
}
|
||||||
|
|
||||||
sing_box_dns_rule_fakeip() {
|
sing_box_dns_rule_fakeip() {
|
||||||
local rewrite_ttl
|
local rewrite_ttl
|
||||||
config_get rewrite_ttl "main" "dns_rewrite_ttl" "600"
|
config_get rewrite_ttl "main" "dns_rewrite_ttl" "600"
|
||||||
@@ -1985,6 +2022,57 @@ get_status() {
|
|||||||
echo "{\"running\":$running,\"enabled\":$enabled,\"status\":\"$status\"}"
|
echo "{\"running\":$running,\"enabled\":$enabled,\"status\":\"$status\"}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_dns_available() {
|
||||||
|
local dns_type=$(uci get podkop.main.dns_type 2>/dev/null)
|
||||||
|
local dns_server=$(uci get podkop.main.dns_server 2>/dev/null)
|
||||||
|
local is_available=0
|
||||||
|
local status="unavailable"
|
||||||
|
local local_dns_working=0
|
||||||
|
local local_dns_status="unavailable"
|
||||||
|
|
||||||
|
if [ "$dns_type" = "doh" ]; then
|
||||||
|
# Different DoH providers use different endpoints and formats
|
||||||
|
local result=""
|
||||||
|
|
||||||
|
# Try common DoH endpoints and check for valid responses
|
||||||
|
# First try /dns-query endpoint (Cloudflare, AdGuard DNS, etc.)
|
||||||
|
result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/dns-query?name=itdog.info&type=A")
|
||||||
|
if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then
|
||||||
|
is_available=1
|
||||||
|
status="available"
|
||||||
|
else
|
||||||
|
# If that fails, try /resolve endpoint (Google DNS)
|
||||||
|
result=$(curl --connect-timeout 5 -s -H "accept: application/dns-json" "https://$dns_server/resolve?name=itdog.info&type=A")
|
||||||
|
if [ $? -eq 0 ] && echo "$result" | grep -q "data"; then
|
||||||
|
is_available=1
|
||||||
|
status="available"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
elif [ "$dns_type" = "dot" ]; then
|
||||||
|
nc $dns_server 853 </dev/null >/dev/null 2>&1 & pid=$!
|
||||||
|
(sleep 3; kill $pid 2>/dev/null) & killpid=$!
|
||||||
|
wait $pid >/dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
is_available=1
|
||||||
|
status="available"
|
||||||
|
fi
|
||||||
|
kill $killpid 2>/dev/null
|
||||||
|
elif [ "$dns_type" = "udp" ]; then
|
||||||
|
if nslookup -timeout=2 itdog.info $dns_server >/dev/null 2>&1; then
|
||||||
|
is_available=1
|
||||||
|
status="available"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if local DNS resolver is working
|
||||||
|
if nslookup -timeout=2 $TEST_DOMAIN 127.0.0.1 >/dev/null 2>&1; then
|
||||||
|
local_dns_working=1
|
||||||
|
local_dns_status="available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "{\"dns_type\":\"$dns_type\",\"dns_server\":\"$dns_server\",\"is_available\":$is_available,\"status\":\"$status\",\"local_dns_working\":$local_dns_working,\"local_dns_status\":\"$local_dns_status\"}"
|
||||||
|
}
|
||||||
|
|
||||||
sing_box_add_secure_dns_probe_domain() {
|
sing_box_add_secure_dns_probe_domain() {
|
||||||
local domain="$TEST_DOMAIN"
|
local domain="$TEST_DOMAIN"
|
||||||
local override_port=8443
|
local override_port=8443
|
||||||
@@ -2079,8 +2167,11 @@ case "$1" in
|
|||||||
get_sing_box_status)
|
get_sing_box_status)
|
||||||
get_sing_box_status
|
get_sing_box_status
|
||||||
;;
|
;;
|
||||||
|
check_dns_available)
|
||||||
|
check_dns_available
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
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}"
|
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|check_dns_available}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
Reference in New Issue
Block a user