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 4abf53a..5790a63 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 @@ -442,18 +442,17 @@ return view.extend({ `: ${status === 'available' ? '✓' : '✗'}`); } - // Check All - full diagnostic - o = s.taboption('diagnostics', form.Button, '_check_all'); - o.title = _('Main Check'); - o.description = _('Run a comprehensive diagnostic check of all components'); - o.inputtitle = _('Run Check'); + // Connection Checks Section + o = s.taboption('diagnostics', form.Button, '_check_nft'); + o.title = _('NFT Rules'); + o.description = _('Show current nftables rules and statistics'); + o.inputtitle = _('Check Rules'); o.inputstyle = 'apply'; o.onclick = function () { - return fs.exec('/etc/init.d/podkop', ['check_three']) + return fs.exec('/etc/init.d/podkop', ['check_nft']) .then(function (res) { const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); - - const modalElement = ui.showModal(_('Full Diagnostic Results'), [ + ui.showModal(_('NFT Rules'), [ E('div', { style: 'max-height: 70vh;' + @@ -478,7 +477,7 @@ return view.extend({ 'class': 'btn', 'click': function () { const textarea = document.createElement('textarea'); - textarea.value = '```txt\n' + formattedOutput + '\n```'; + textarea.value = formattedOutput; document.body.appendChild(textarea); textarea.select(); try { @@ -494,27 +493,77 @@ return view.extend({ 'click': ui.hideModal }, _('Close')) ]) - ], 'large'); + ]); + }); + }; - if (modalElement && modalElement.parentElement) { - modalElement.parentElement.style.width = '90%'; - modalElement.parentElement.style.maxWidth = '1200px'; - modalElement.parentElement.style.margin = '2rem auto'; - } + + + // Logs Section + o = s.taboption('diagnostics', form.Button, '_check_sing_box_logs'); + o.title = _('Sing-Box Logs'); + o.description = _('View recent sing-box logs from system journal'); + o.inputtitle = _('View Sing-Box Logs'); + o.inputstyle = 'apply'; + o.onclick = function () { + return fs.exec('/etc/init.d/podkop', ['check_sing_box_logs']) + .then(function (res) { + const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + ui.showModal(_('Sing-Box Logs'), [ + E('div', { + style: + 'max-height: 70vh;' + + 'overflow-y: auto;' + + 'margin: 1em 0;' + + 'padding: 1.5em;' + + 'background: #f8f9fa;' + + 'border: 1px solid #e9ecef;' + + 'border-radius: 4px;' + + 'font-family: monospace;' + + 'white-space: pre-wrap;' + + 'word-wrap: break-word;' + + 'line-height: 1.5;' + + 'font-size: 14px;' + }, [ + E('pre', { style: 'margin: 0;' }, formattedOutput) + ]), + E('div', { + style: 'display: flex; justify-content: space-between; margin-top: 1em;' + }, [ + E('button', { + 'class': 'btn', + 'click': function () { + const textarea = document.createElement('textarea'); + textarea.value = formattedOutput; + document.body.appendChild(textarea); + textarea.select(); + try { + document.execCommand('copy'); + } catch (err) { + ui.addNotification(null, E('p', {}, _('Failed to copy: ') + err.message)); + } + document.body.removeChild(textarea); + } + }, _('Copy to Clipboard')), + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Close')) + ]) + ]); }); }; o = s.taboption('diagnostics', form.Button, '_check_logs'); - o.title = _('System Logs'); - o.description = _('View recent system logs related to Podkop'); - o.inputtitle = _('View Logs'); + o.title = _('Podkop Logs'); + o.description = _('View recent podkop logs from system journal'); + o.inputtitle = _('View Podkop Logs'); o.inputstyle = 'apply'; o.onclick = function () { return fs.exec('/etc/init.d/podkop', ['check_logs']) .then(function (res) { const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); - - const modalElement = ui.showModal(_('System Logs'), [ + ui.showModal(_('Podkop Logs'), [ E('div', { style: 'max-height: 70vh;' + @@ -539,7 +588,7 @@ return view.extend({ 'class': 'btn', 'click': function () { const textarea = document.createElement('textarea'); - textarea.value = '```txt\n' + formattedOutput + '\n```'; + textarea.value = formattedOutput; document.body.appendChild(textarea); textarea.select(); try { @@ -555,18 +604,175 @@ return view.extend({ 'click': ui.hideModal }, _('Close')) ]) - ], 'large'); + ]); + }); + }; - if (modalElement && modalElement.parentElement) { - modalElement.parentElement.style.width = '90%'; - modalElement.parentElement.style.maxWidth = '1200px'; - modalElement.parentElement.style.margin = '2rem auto'; - } + // Configurations Section + o = s.taboption('diagnostics', form.Button, '_check_sing_box_connections'); + o.title = _('Active Connections'); + o.description = _('View active sing-box network connections'); + o.inputtitle = _('Check Connections'); + o.inputstyle = 'apply'; + o.onclick = function () { + return fs.exec('/etc/init.d/podkop', ['check_sing_box_connections']) + .then(function (res) { + const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + ui.showModal(_('Active Connections'), [ + E('div', { + style: + 'max-height: 70vh;' + + 'overflow-y: auto;' + + 'margin: 1em 0;' + + 'padding: 1.5em;' + + 'background: #f8f9fa;' + + 'border: 1px solid #e9ecef;' + + 'border-radius: 4px;' + + 'font-family: monospace;' + + 'white-space: pre-wrap;' + + 'word-wrap: break-word;' + + 'line-height: 1.5;' + + 'font-size: 14px;' + }, [ + E('pre', { style: 'margin: 0;' }, formattedOutput) + ]), + E('div', { + style: 'display: flex; justify-content: space-between; margin-top: 1em;' + }, [ + E('button', { + 'class': 'btn', + 'click': function () { + const textarea = document.createElement('textarea'); + textarea.value = formattedOutput; + document.body.appendChild(textarea); + textarea.select(); + try { + document.execCommand('copy'); + } catch (err) { + ui.addNotification(null, E('p', {}, _('Failed to copy: ') + err.message)); + } + document.body.removeChild(textarea); + } + }, _('Copy to Clipboard')), + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Close')) + ]) + ]); + }); + }; + + o = s.taboption('diagnostics', form.Button, '_check_dnsmasq'); + o.title = _('DNSMasq Configuration'); + o.description = _('View current DNSMasq configuration settings'); + o.inputtitle = _('Check DNSMasq'); + o.inputstyle = 'apply'; + o.onclick = function () { + return fs.exec('/etc/init.d/podkop', ['check_dnsmasq']) + .then(function (res) { + const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + ui.showModal(_('DNSMasq Configuration'), [ + E('div', { + style: + 'max-height: 70vh;' + + 'overflow-y: auto;' + + 'margin: 1em 0;' + + 'padding: 1.5em;' + + 'background: #f8f9fa;' + + 'border: 1px solid #e9ecef;' + + 'border-radius: 4px;' + + 'font-family: monospace;' + + 'white-space: pre-wrap;' + + 'word-wrap: break-word;' + + 'line-height: 1.5;' + + 'font-size: 14px;' + }, [ + E('pre', { style: 'margin: 0;' }, formattedOutput) + ]), + E('div', { + style: 'display: flex; justify-content: space-between; margin-top: 1em;' + }, [ + E('button', { + 'class': 'btn', + 'click': function () { + const textarea = document.createElement('textarea'); + textarea.value = formattedOutput; + document.body.appendChild(textarea); + textarea.select(); + try { + document.execCommand('copy'); + } catch (err) { + ui.addNotification(null, E('p', {}, _('Failed to copy: ') + err.message)); + } + document.body.removeChild(textarea); + } + }, _('Copy to Clipboard')), + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Close')) + ]) + ]); + }); + }; + + o = s.taboption('diagnostics', form.Button, '_show_sing_box_config'); + o.title = _('Sing-Box Configuration'); + o.description = _('Show current sing-box configuration'); + o.inputtitle = _('Show Sing-Box Config'); + o.inputstyle = 'apply'; + o.onclick = function () { + return fs.exec('/etc/init.d/podkop', ['show_sing_box_config']) + .then(function (res) { + const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + ui.showModal(_('Sing-Box Configuration'), [ + E('div', { + style: + 'max-height: 70vh;' + + 'overflow-y: auto;' + + 'margin: 1em 0;' + + 'padding: 1.5em;' + + 'background: #f8f9fa;' + + 'border: 1px solid #e9ecef;' + + 'border-radius: 4px;' + + 'font-family: monospace;' + + 'white-space: pre-wrap;' + + 'word-wrap: break-word;' + + 'line-height: 1.5;' + + 'font-size: 14px;' + }, [ + E('pre', { style: 'margin: 0;' }, formattedOutput) + ]), + E('div', { + style: 'display: flex; justify-content: space-between; margin-top: 1em;' + }, [ + E('button', { + 'class': 'btn', + 'click': function () { + const textarea = document.createElement('textarea'); + textarea.value = '```json\n' + formattedOutput + '\n```'; + document.body.appendChild(textarea); + textarea.select(); + try { + document.execCommand('copy'); + } catch (err) { + ui.addNotification(null, E('p', {}, _('Failed to copy: ') + err.message)); + } + document.body.removeChild(textarea); + } + }, _('Copy to Clipboard')), + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Close')) + ]) + ]); }); }; o = s.taboption('diagnostics', form.Button, '_show_config'); - o.title = _('Show Config'); + o.title = _('Podkop Configuration'); o.description = _('Show current podkop configuration with masked sensitive data'); o.inputtitle = _('Show Config'); o.inputstyle = 'apply'; @@ -574,58 +780,33 @@ return view.extend({ return fs.exec('/etc/init.d/podkop', ['show_config']) .then(function (res) { const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); - - const modalElement = ui.showModal(_('Podkop Configuration'), [ - E('div', { class: 'cbi-section' }, [ - E('pre', { class: 'cbi-value-field' }, formattedOutput) - ]), - E('div', { style: 'display: flex; justify-content: space-between; margin-top: 1em;' }, [ - E('button', { - 'class': 'btn cbi-button-save', - 'click': function () { - const textarea = document.createElement('textarea'); - textarea.value = '```\n' + formattedOutput + '\n```'; - document.body.appendChild(textarea); - textarea.select(); - try { - document.execCommand('copy'); - ui.hideModal(); - } catch (err) { - ui.addNotification(null, E('p', {}, _('Failed to copy: ') + err.message)); - } - document.body.removeChild(textarea); - } - }, _('Copy to Clipboard')), - E('button', { - 'class': 'btn cbi-button-neutral', - 'click': ui.hideModal - }, _('Close')) - ]) - ], 'large'); - - if (modalElement && modalElement.parentElement) { - modalElement.parentElement.classList.add('modal-overlay-large'); - } + ui.showModal(_('Podkop Configuration'), [ + E('div', { style: 'white-space:pre-wrap;padding:5px' }, formattedOutput), + E('div', { class: 'right' }, E('button', { + class: 'btn', + click: ui.hideModal + }, _('Close'))) + ]); }); }; o = s.taboption('diagnostics', form.Button, '_list_update'); - o.title = _('Update lists'); + o.title = _('Update Lists'); o.description = _('Update all lists in config'); - o.inputtitle = _('Update lists'); + o.inputtitle = _('Update Lists'); o.inputstyle = 'apply'; o.onclick = function () { - fs.exec('/etc/init.d/podkop', ['list_update']); - - ui.showModal(_('List Update'), [ - E('p', {}, _('Lists will be updated in background. You can check the progress in system logs.')), - E('div', { class: 'right' }, [ - E('button', { - 'class': 'btn', - 'click': ui.hideModal - }, _('Close')) - ]) - ]); + return fs.exec('/etc/init.d/podkop', ['list_update']) + .then(function (res) { + const formattedOutput = formatDiagnosticOutput(res.stdout || _('No output')); + ui.showModal(_('Lists Update Results'), [ + E('div', { style: 'white-space:pre-wrap;padding:5px' }, formattedOutput), + E('div', { class: 'right' }, E('button', { + class: 'btn', + click: ui.hideModal + }, _('Close'))) + ]); + }); }; diff --git a/luci-app-podkop/po/ru/podkop.po b/luci-app-podkop/po/ru/podkop.po index 32a4fa1..b7a5360 100644 --- a/luci-app-podkop/po/ru/podkop.po +++ b/luci-app-podkop/po/ru/podkop.po @@ -380,4 +380,85 @@ msgid "Local Domain Lists Path" msgstr "Путь к локальным спискам доменов" msgid "Enter to the list file path" -msgstr "Введите путь к файлу списка" \ No newline at end of file +msgstr "Введите путь к файлу списка" + +msgid "Proxy Check" +msgstr "Проверка прокси" + +msgid "Check if sing-box proxy works correctly" +msgstr "Проверить корректность работы прокси sing-box" + +msgid "Check Proxy" +msgstr "Проверить прокси" + +msgid "Proxy Check Results" +msgstr "Результаты проверки прокси" + +msgid "NFT Rules" +msgstr "Правила NFT" + +msgid "Show current nftables rules and statistics" +msgstr "Показать текущие правила и статистику nftables" + +msgid "Check Rules" +msgstr "Проверить правила" + +msgid "GitHub Connectivity" +msgstr "Подключение к GitHub" + +msgid "Check GitHub connectivity and lists availability" +msgstr "Проверить подключение к GitHub и доступность списков" + +msgid "Check GitHub" +msgstr "Проверить GitHub" + +msgid "GitHub Connectivity Results" +msgstr "Результаты проверки подключения к GitHub" + +msgid "Sing-Box Logs" +msgstr "Логи Sing-Box" + +msgid "View recent sing-box logs from system journal" +msgstr "Просмотр последних логов sing-box из системного журнала" + +msgid "View Sing-Box Logs" +msgstr "Просмотр логов Sing-Box" + +msgid "Podkop Logs" +msgstr "Логи Podkop" + +msgid "View recent podkop logs from system journal" +msgstr "Просмотр последних логов podkop из системного журнала" + +msgid "View Podkop Logs" +msgstr "Просмотр логов Podkop" + +msgid "Active Connections" +msgstr "Активные соединения" + +msgid "View active sing-box network connections" +msgstr "Просмотр активных сетевых соединений sing-box" + +msgid "Check Connections" +msgstr "Проверить соединения" + +msgid "DNSMasq Configuration" +msgstr "Конфигурация DNSMasq" + +msgid "View current DNSMasq configuration settings" +msgstr "Просмотр текущих настроек конфигурации DNSMasq" + +msgid "Check DNSMasq" +msgstr "Проверить DNSMasq" + +msgid "Sing-Box Configuration" +msgstr "Конфигурация Sing-Box" + +msgid "Show current sing-box configuration" +msgstr "Показать текущую конфигурацию sing-box" + +msgid "Show Sing-Box Config" +msgstr "Показать конфигурацию Sing-Box" + +msgid "Lists Update Results" +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 b35355e..87e78e4 100644 --- a/luci-app-podkop/po/templates/podkop.pot +++ b/luci-app-podkop/po/templates/podkop.pot @@ -380,4 +380,85 @@ msgid "Local Domain Lists Path" msgstr "" msgid "Enter to the list file path" +msgstr "" + +msgid "Proxy Check" +msgstr "" + +msgid "Check if sing-box proxy works correctly" +msgstr "" + +msgid "Check Proxy" +msgstr "" + +msgid "Proxy Check Results" +msgstr "" + +msgid "NFT Rules" +msgstr "" + +msgid "Show current nftables rules and statistics" +msgstr "" + +msgid "Check Rules" +msgstr "" + +msgid "GitHub Connectivity" +msgstr "" + +msgid "Check GitHub connectivity and lists availability" +msgstr "" + +msgid "Check GitHub" +msgstr "" + +msgid "GitHub Connectivity Results" +msgstr "" + +msgid "Sing-Box Logs" +msgstr "" + +msgid "View recent sing-box logs from system journal" +msgstr "" + +msgid "View Sing-Box Logs" +msgstr "" + +msgid "Podkop Logs" +msgstr "" + +msgid "View recent podkop logs from system journal" +msgstr "" + +msgid "View Podkop Logs" +msgstr "" + +msgid "Active Connections" +msgstr "" + +msgid "View active sing-box network connections" +msgstr "" + +msgid "Check Connections" +msgstr "" + +msgid "DNSMasq Configuration" +msgstr "" + +msgid "View current DNSMasq configuration settings" +msgstr "" + +msgid "Check DNSMasq" +msgstr "" + +msgid "Sing-Box Configuration" +msgstr "" + +msgid "Show current sing-box configuration" +msgstr "" + +msgid "Show Sing-Box Config" +msgstr "" + +msgid "Lists Update Results" msgstr "" \ No newline at end of file diff --git a/podkop/files/etc/init.d/podkop b/podkop/files/etc/init.d/podkop index d75c06d..5a3b99c 100755 --- a/podkop/files/etc/init.d/podkop +++ b/podkop/files/etc/init.d/podkop @@ -7,18 +7,18 @@ script=$(readlink "$initscript") NAME="$(basename ${script:-$initscript})" config_load "$NAME" -EXTRA_COMMANDS="list_update check_proxy check_nft check_github check_logs check_all check_three main show_config show_version" +EXTRA_COMMANDS="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" EXTRA_HELP=" list_update Updating domain and subnet lists - sing_box_config_vless For test vless string check_proxy Check if sing-box proxy works correctly check_nft Show PodkopTable nftables rules check_github Check GitHub connectivity and lists availability check_logs Show podkop logs from system journal - check_all Run all checks - check_three Run check_proxy, check_nft and check_github - main Main function + check_sing_box_connections Show active sing-box network connections + check_sing_box_logs Show recent sing-box logs + check_dnsmasq Show current DNSMasq configuration show_config Show current configuration with masked sensitive data - show_version Show current version" + show_version Show current version + show_sing_box_config Show current sing-box configuration" [ ! -L /usr/sbin/podkop ] && ln -s /etc/init.d/podkop /usr/sbin/podkop @@ -1390,15 +1390,29 @@ check_proxy() { fi jq ' - walk( - if type == "object" then - with_entries( - if [.key] | inside(["uuid", "server", "server_name", "password", "public_key", "short_id"]) then - .value = "MASKED" - else . end - ) - else . end - )' $SING_BOX_CONFIG + walk( + if type == "object" then + with_entries( + if .key == "uuid" then + .value = "MASKED" + elif .key == "server" then + .value = "MASKED" + elif .key == "server_name" then + .value = "MASKED" + elif .key == "password" then + .value = "MASKED" + elif .key == "public_key" then + .value = "MASKED" + elif .key == "short_id" then + .value = "MASKED" + elif .key == "fingerprint" then + .value = "MASKED" + elif .key == "server_port" then + .value = "MASKED" + else . end + ) + else . end + )' $SING_BOX_CONFIG nolog "Checking proxy connection..." @@ -1437,22 +1451,18 @@ check_nft() { nolog "Checking PodkopTable rules..." - local sets="podkop_domains podkop_subnets podkop_subnets_discord localv4" - - nolog "Sets statistics:" - for set_name in $sets; do - if nft list set inet PodkopTable $set_name >/dev/null 2>&1; then - local count=$(nft list set inet PodkopTable $set_name 2>/dev/null | grep -c ",") - nolog "- $set_name: $count elements" - else - nolog "- $set_name: not found" - fi - done + # Check if table exists + if ! nft list table inet PodkopTable >/dev/null 2>&1; then + nolog "PodkopTable not found" + return 1 + fi - nolog "Current chains and rules:" - nft list table inet PodkopTable | grep "chain\|counter" + # Get all sets + nolog "\nSets configuration:" - nolog "NFT check completed" + nft list table inet PodkopTable + + nolog "\nNFT check completed" } check_github() { @@ -1477,37 +1487,94 @@ check_github() { done } +check_dnsmasq() { + nolog "Checking dnsmasq configuration..." + + local config=$(uci show dhcp.@dnsmasq[0]) + if [ -z "$config" ]; then + nolog "No dnsmasq configuration found" + return 1 + fi + + echo "$config" | while IFS='=' read -r key value; do + nolog "$key = $value" + done +} + +check_sing_box_connections() { + nolog "Checking sing-box connections..." + + if ! command -v netstat >/dev/null 2>&1; then + nolog "netstat is not installed" + return 1 + fi + + local connections=$(netstat -tuanp | grep sing-box) + if [ -z "$connections" ]; then + nolog "No active sing-box connections found" + return 1 + fi + + echo "$connections" | while read -r line; do + nolog "$line" + done +} + +check_sing_box_logs() { + nolog "Showing sing-box logs from system journal..." + + local logs=$(logread -e sing-box | tail -n 50) + if [ -z "$logs" ]; then + nolog "No sing-box logs found" + return 1 + fi + + echo "$logs" +} + check_logs() { nolog "Showing podkop logs from system journal..." if command -v logread >/dev/null 2>&1; then - logread -e "podkop" | tail -n 50 + logread -e podkop | tail -n 50 else nolog "Error: logread command not found" return 1 fi } -check_three() { - nolog "\n=== Checking GitHub connectivity ===" - check_github +show_sing_box_config() { + nolog "Current sing-box configuration:" - nolog "\n=== Checking proxy settings ===" - check_proxy - - nolog "\n=== Checking NFT rules ===" - check_nft - - nolog "\nFull diagnostic check completed" -} + if [ ! -f "$SING_BOX_CONFIG" ]; then + nolog "Configuration file not found" + return 1 + fi -check_all() { - nolog "Starting full diagnostic check..." - - nolog "\n=== Checking recent logs ===" - check_logs - - check_three + jq ' + walk( + if type == "object" then + with_entries( + if .key == "uuid" then + .value = "MASKED" + elif .key == "server" then + .value = "MASKED" + elif .key == "server_name" then + .value = "MASKED" + elif .key == "password" then + .value = "MASKED" + elif .key == "public_key" then + .value = "MASKED" + elif .key == "short_id" then + .value = "MASKED" + elif .key == "fingerprint" then + .value = "MASKED" + elif .key == "server_port" then + .value = "MASKED" + else . end + ) + else . end + )' "$SING_BOX_CONFIG" } show_config() {