fix(runtime): устранение сбоев запуска sing-box, исправление правил nftables и защита от гонок вочдога
- Восстановление кэша правил: восстановление .srs, .lst, .json файлов из постоянного каталога /etc/tachyon/rulesets/ при старте; защита от удаления кэша при остановке; добавление фоллбэка пустых ruleset в runtime.uc перед валидацией - nftables: удаление невалидного auto-merge для интервальных составных сетов (ipv4_addr/ipv6_addr . inet_service) - core/ip: исправление нормализации IPv6-адреса и порта для TPROXY без дублирования скобок - dns block: исправление возвращаемого статуса nft_add_dns_block_rules_from_schedules при отсутствии правил блокировки - watchdog & lifecycle: добавление флага блокировки /var/run/tachyon/starting для исключения сброса правил вочдогом во время старта - ui & i18n: форматирование бейджей устройств в родительском контроле и обновление переводов
This commit is contained in:
@@ -1628,9 +1628,9 @@
|
|||||||
"../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803",
|
"../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803",
|
||||||
"src/partials/modal/renderModal.ts:263",
|
"src/partials/modal/renderModal.ts:263",
|
||||||
"src/tachyon/tabs/dashboard/initController.ts:1262",
|
"src/tachyon/tabs/dashboard/initController.ts:1262",
|
||||||
"src/tachyon/tabs/diagnostic/initController.ts:1542",
|
|
||||||
"src/tachyon/tabs/monitoring/initController.ts:884",
|
"src/tachyon/tabs/monitoring/initController.ts:884",
|
||||||
"src/tachyon/tabs/monitoring/initController.ts:934",
|
"src/tachyon/tabs/monitoring/initController.ts:934",
|
||||||
|
"src/tachyon/tabs/diagnostic/initController.ts:1542",
|
||||||
"src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213",
|
"src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213",
|
||||||
"src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439",
|
"src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439",
|
||||||
"src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485"
|
"src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485"
|
||||||
@@ -8106,8 +8106,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"call": "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually.",
|
"call": "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease.",
|
||||||
"key": "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually.",
|
"key": "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease.",
|
||||||
"places": [
|
"places": [
|
||||||
"../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390"
|
"../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-08-21 04:11+0300\n"
|
"POT-Creation-Date: 2026-08-21 04:51+0300\n"
|
||||||
"PO-Revision-Date: 2026-08-21 04:11+0300\n"
|
"PO-Revision-Date: 2026-08-21 04:51+0300\n"
|
||||||
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
@@ -1023,9 +1023,9 @@ msgstr ""
|
|||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803
|
||||||
#: src/partials/modal/renderModal.ts:263
|
#: src/partials/modal/renderModal.ts:263
|
||||||
#: src/tachyon/tabs/dashboard/initController.ts:1262
|
#: src/tachyon/tabs/dashboard/initController.ts:1262
|
||||||
#: src/tachyon/tabs/diagnostic/initController.ts:1542
|
|
||||||
#: src/tachyon/tabs/monitoring/initController.ts:884
|
#: src/tachyon/tabs/monitoring/initController.ts:884
|
||||||
#: src/tachyon/tabs/monitoring/initController.ts:934
|
#: src/tachyon/tabs/monitoring/initController.ts:934
|
||||||
|
#: src/tachyon/tabs/diagnostic/initController.ts:1542
|
||||||
#: src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213
|
#: src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213
|
||||||
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439
|
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439
|
||||||
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485
|
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485
|
||||||
@@ -4976,7 +4976,7 @@ msgid "Select DNS protocol to use"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390
|
||||||
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:8828
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:8828
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-08-21 07:11+0300\n"
|
"POT-Creation-Date: 2026-08-21 07:51+0300\n"
|
||||||
"PO-Revision-Date: 2026-08-21 07:11+0300\n"
|
"PO-Revision-Date: 2026-08-21 07:51+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -3164,8 +3164,8 @@ msgstr "Выберите и упорядочите секции, через ко
|
|||||||
msgid "Select DNS protocol to use"
|
msgid "Select DNS protocol to use"
|
||||||
msgstr "Выберите протокол DNS"
|
msgstr "Выберите протокол DNS"
|
||||||
|
|
||||||
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease."
|
||||||
msgstr "Выберите устройства из локальной сети для применения расписания, либо укажите IP или MAC-адреса вручную."
|
msgstr "Выберите устройства из локальной сети, либо укажите IP или MAC-адреса вручную. MAC-адреса (например AA:BB:CC:DD:EE:FF) работают даже если IP устройства меняется. IP-адреса (например 192.168.1.150) используются для блокировки на уровне DNS и требуют стабильного адреса."
|
||||||
|
|
||||||
msgid "Select network interface for VPN connection"
|
msgid "Select network interface for VPN connection"
|
||||||
msgstr "Выберите интерфейс для VPN-подключения"
|
msgstr "Выберите интерфейс для VPN-подключения"
|
||||||
@@ -4256,6 +4256,9 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
|||||||
msgid "Zapret2 sing-box outbound is not configured"
|
msgid "Zapret2 sing-box outbound is not configured"
|
||||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||||
|
|
||||||
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
||||||
|
msgstr "Выберите устройства из локальной сети для применения расписания, либо укажите IP или MAC-адреса вручную."
|
||||||
|
|
||||||
msgid "API returned error — token may be invalid"
|
msgid "API returned error — token may be invalid"
|
||||||
msgstr "API вернул ошибку — возможно, токен недействителен"
|
msgstr "API вернул ошибку — возможно, токен недействителен"
|
||||||
|
|
||||||
|
|||||||
@@ -54,22 +54,22 @@ function addLocalDeviceChoice(choices, ip, name, mac) {
|
|||||||
|
|
||||||
if (normalizedIp && main.validateIP(normalizedIp).valid) {
|
if (normalizedIp && main.validateIP(normalizedIp).valid) {
|
||||||
if (normalizedName) {
|
if (normalizedName) {
|
||||||
choices[normalizedIp] = `${normalizedName} (${normalizedIp})`;
|
choices[normalizedIp] = `IP: ${normalizedIp} — ${normalizedName}`;
|
||||||
} else if (normalizedMac) {
|
} else if (normalizedMac) {
|
||||||
choices[normalizedIp] = `${normalizedIp} [${normalizedMac}]`;
|
choices[normalizedIp] = `IP: ${normalizedIp} — ${normalizedMac}`;
|
||||||
} else if (!choices[normalizedIp]) {
|
} else if (!choices[normalizedIp]) {
|
||||||
choices[normalizedIp] = `${normalizedIp}`;
|
choices[normalizedIp] = `IP: ${normalizedIp}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalizedMac && /^([0-9a-f]{2}[:-]){5}[0-9a-f]{2}$/.test(normalizedMac)) {
|
if (normalizedMac && /^([0-9a-f]{2}[:-]){5}[0-9a-f]{2}$/.test(normalizedMac)) {
|
||||||
const formattedMac = normalizedMac.replace(/-/g, ":");
|
const formattedMac = normalizedMac.replace(/-/g, ":");
|
||||||
if (normalizedName) {
|
if (normalizedName) {
|
||||||
choices[formattedMac] = `${normalizedName} [MAC: ${formattedMac}]`;
|
choices[formattedMac] = `MAC: ${formattedMac} — ${normalizedName}`;
|
||||||
} else if (normalizedIp) {
|
} else if (normalizedIp) {
|
||||||
choices[formattedMac] = `${normalizedIp} [MAC: ${formattedMac}]`;
|
choices[formattedMac] = `MAC: ${formattedMac} — ${normalizedIp}`;
|
||||||
} else if (!choices[formattedMac]) {
|
} else if (!choices[formattedMac]) {
|
||||||
choices[formattedMac] = `${formattedMac}`;
|
choices[formattedMac] = `MAC: ${formattedMac}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,15 +200,19 @@ function createParentalContent(section) {
|
|||||||
if (devs.length === 0) {
|
if (devs.length === 0) {
|
||||||
return '<span style="opacity:0.5;">' + _("All devices") + "</span>";
|
return '<span style="opacity:0.5;">' + _("All devices") + "</span>";
|
||||||
}
|
}
|
||||||
const badges = devs
|
const isMacAddr = (dev) =>
|
||||||
|
/^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/.test(dev);
|
||||||
|
const macs = devs.filter(isMacAddr);
|
||||||
|
const ips = devs.filter((d) => !isMacAddr(d));
|
||||||
|
const badges = [...macs, ...ips]
|
||||||
.map((dev) => {
|
.map((dev) => {
|
||||||
const isMac = /^([0-9a-fA-F]{2}[:-]){5}[0-9a-fA-F]{2}$/.test(dev);
|
const isMac = isMacAddr(dev);
|
||||||
const bg = isMac ? "#2d3748" : "#2a3441";
|
const bg = isMac ? "#2d3748" : "#2a3441";
|
||||||
const color = isMac ? "#b794f4" : "#63b3ed";
|
const color = isMac ? "#b794f4" : "#63b3ed";
|
||||||
const icon = isMac ? "🏷 " : "🖥 ";
|
const label = isMac ? "MAC" : "IP";
|
||||||
return (
|
return (
|
||||||
`<span class="badge" style="background:${bg};color:${color};padding:3px 8px;border-radius:6px;font-size:11px;font-family:monospace;margin-right:4px;font-weight:600;display:inline-block;margin-bottom:2px;">` +
|
`<span class="badge" style="background:${bg};color:${color};padding:3px 8px;border-radius:6px;font-size:11px;font-family:monospace;margin-right:4px;font-weight:600;display:inline-block;margin-bottom:2px;border:1px solid ${color}44;">` +
|
||||||
icon +
|
`<span style="opacity:0.75;font-weight:700;margin-right:3px;">${label}:</span>` +
|
||||||
dev +
|
dev +
|
||||||
"</span>"
|
"</span>"
|
||||||
);
|
);
|
||||||
@@ -387,7 +391,7 @@ function createParentalContent(section) {
|
|||||||
form.DynamicList,
|
form.DynamicList,
|
||||||
"device_ip",
|
"device_ip",
|
||||||
_("Target Devices (IP / MAC)"),
|
_("Target Devices (IP / MAC)"),
|
||||||
_("Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."),
|
_("Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease."),
|
||||||
);
|
);
|
||||||
o.modalonly = true;
|
o.modalonly = true;
|
||||||
o.rmempty = false;
|
o.rmempty = false;
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-08-21 07:11+0300\n"
|
"POT-Creation-Date: 2026-08-21 07:51+0300\n"
|
||||||
"PO-Revision-Date: 2026-08-21 07:11+0300\n"
|
"PO-Revision-Date: 2026-08-21 07:51+0300\n"
|
||||||
"Last-Translator: Dushnilin\n"
|
"Last-Translator: Dushnilin\n"
|
||||||
"Language-Team: none\n"
|
"Language-Team: none\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
@@ -3164,8 +3164,8 @@ msgstr "Выберите и упорядочите секции, через ко
|
|||||||
msgid "Select DNS protocol to use"
|
msgid "Select DNS protocol to use"
|
||||||
msgstr "Выберите протокол DNS"
|
msgstr "Выберите протокол DNS"
|
||||||
|
|
||||||
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease."
|
||||||
msgstr "Выберите устройства из локальной сети для применения расписания, либо укажите IP или MAC-адреса вручную."
|
msgstr "Выберите устройства из локальной сети, либо укажите IP или MAC-адреса вручную. MAC-адреса (например AA:BB:CC:DD:EE:FF) работают даже если IP устройства меняется. IP-адреса (например 192.168.1.150) используются для блокировки на уровне DNS и требуют стабильного адреса."
|
||||||
|
|
||||||
msgid "Select network interface for VPN connection"
|
msgid "Select network interface for VPN connection"
|
||||||
msgstr "Выберите интерфейс для VPN-подключения"
|
msgstr "Выберите интерфейс для VPN-подключения"
|
||||||
@@ -4256,6 +4256,9 @@ msgstr "sing-box outbound для Zapret2 настроен"
|
|||||||
msgid "Zapret2 sing-box outbound is not configured"
|
msgid "Zapret2 sing-box outbound is not configured"
|
||||||
msgstr "sing-box outbound для Zapret2 не настроен"
|
msgstr "sing-box outbound для Zapret2 не настроен"
|
||||||
|
|
||||||
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
||||||
|
msgstr "Выберите устройства из локальной сети для применения расписания, либо укажите IP или MAC-адреса вручную."
|
||||||
|
|
||||||
msgid "API returned error — token may be invalid"
|
msgid "API returned error — token may be invalid"
|
||||||
msgstr "API вернул ошибку — возможно, токен недействителен"
|
msgstr "API вернул ошибку — возможно, токен недействителен"
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TACHYON\n"
|
"Project-Id-Version: TACHYON\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-08-21 04:11+0300\n"
|
"POT-Creation-Date: 2026-08-21 04:51+0300\n"
|
||||||
"PO-Revision-Date: 2026-08-21 04:11+0300\n"
|
"PO-Revision-Date: 2026-08-21 04:51+0300\n"
|
||||||
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
"Last-Translator: Dushnilin <dushnilin@gmail.com>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"Language: \n"
|
"Language: \n"
|
||||||
@@ -1023,9 +1023,9 @@ msgstr ""
|
|||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/server.js:1803
|
||||||
#: src/partials/modal/renderModal.ts:263
|
#: src/partials/modal/renderModal.ts:263
|
||||||
#: src/tachyon/tabs/dashboard/initController.ts:1262
|
#: src/tachyon/tabs/dashboard/initController.ts:1262
|
||||||
#: src/tachyon/tabs/diagnostic/initController.ts:1542
|
|
||||||
#: src/tachyon/tabs/monitoring/initController.ts:884
|
#: src/tachyon/tabs/monitoring/initController.ts:884
|
||||||
#: src/tachyon/tabs/monitoring/initController.ts:934
|
#: src/tachyon/tabs/monitoring/initController.ts:934
|
||||||
|
#: src/tachyon/tabs/diagnostic/initController.ts:1542
|
||||||
#: src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213
|
#: src/tachyon/tabs/diagnostic/partials/renderAiChatModal.ts:213
|
||||||
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439
|
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:439
|
||||||
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485
|
#: src/tachyon/tabs/updates/partials/renderUpdateProgressModal.ts:485
|
||||||
@@ -4976,7 +4976,7 @@ msgid "Select DNS protocol to use"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/parental.js:390
|
||||||
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually."
|
msgid "Select LAN devices to apply this schedule to, or enter IP or MAC addresses manually. MAC addresses (e.g. AA:BB:CC:DD:EE:FF) work even if the device's IP changes. IP addresses (e.g. 192.168.1.150) are used for DNS-level blocking and require a stable lease."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:8828
|
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:8828
|
||||||
|
|||||||
@@ -132,6 +132,8 @@ function ip_family(value) {
|
|||||||
|
|
||||||
function format_ipv6_tproxy_target(address, port) {
|
function format_ipv6_tproxy_target(address, port) {
|
||||||
address = as_string(address);
|
address = as_string(address);
|
||||||
|
if (index(address, "]:") >= 0)
|
||||||
|
return address;
|
||||||
if (substr(address, 0, 1) == "[" && substr(address, length(address) - 1, 1) == "]")
|
if (substr(address, 0, 1) == "[" && substr(address, length(address) - 1, 1) == "]")
|
||||||
return address + ":" + as_string(port);
|
return address + ":" + as_string(port);
|
||||||
return "[" + address + "]:" + as_string(port);
|
return "[" + address + "]:" + as_string(port);
|
||||||
|
|||||||
@@ -411,11 +411,11 @@ function nft_create_inet_service_set(table, name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function nft_create_ipv4_port_set(table, name) {
|
function nft_create_ipv4_port_set(table, name) {
|
||||||
return nft_create_set(table, name, "{ type ipv4_addr . inet_service; flags interval; auto-merge; }");
|
return nft_create_set(table, name, "{ type ipv4_addr . inet_service; flags interval; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
function nft_create_ipv6_port_set(table, name) {
|
function nft_create_ipv6_port_set(table, name) {
|
||||||
return nft_create_set(table, name, "{ type ipv6_addr . inet_service; flags interval; auto-merge; }");
|
return nft_create_set(table, name, "{ type ipv6_addr . inet_service; flags interval; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
function nft_create_ifname_set(table, name) {
|
function nft_create_ifname_set(table, name) {
|
||||||
@@ -1053,7 +1053,7 @@ function nft_add_dns_block_rules_from_schedules(schedules, table) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return added;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nft_add_dns_block_rules_from_uci(table) {
|
function nft_add_dns_block_rules_from_uci(table) {
|
||||||
@@ -2166,7 +2166,22 @@ function nft_populate_runtime_sets_from_uci(populate_enabled, deferred_section_n
|
|||||||
|
|
||||||
if (!nft_table_present(table)) {
|
if (!nft_table_present(table)) {
|
||||||
log_warn("nft_populate_runtime_sets_from_uci: Table " + table + " does not exist. Rebuilding firewall rules dynamically.");
|
log_warn("nft_populate_runtime_sets_from_uci: Table " + table + " does not exist. Rebuilding firewall rules dynamically.");
|
||||||
system(common.background_command("/usr/bin/tachyon reload_firewall"));
|
let rt_table = getenv("RT_TABLE_NAME") || "tachyon";
|
||||||
|
let localv4 = default_arg(localv4_set, "localv4");
|
||||||
|
let common = default_arg(common_set, "tachyon_subnets");
|
||||||
|
let port = default_arg(port_set, "tachyon_ports");
|
||||||
|
let ip_port = default_arg(ip_port_set, "tachyon_ip_ports");
|
||||||
|
let iface = default_arg(interface_set, "tachyon_interfaces");
|
||||||
|
let fmark = default_arg(mark, "0x04000000");
|
||||||
|
let omark = "0x08000000";
|
||||||
|
let frange4 = "198.18.0.0/15";
|
||||||
|
let tport = "1602";
|
||||||
|
let localv6 = default_arg(localv6_set, "localv6");
|
||||||
|
let common6 = default_arg(common6_set, "tachyon_subnets6");
|
||||||
|
let ip_port6 = default_arg(ip_port6_set, "tachyon_ip6_ports");
|
||||||
|
let frange6 = "fc00::/18";
|
||||||
|
let taddr6 = "[::1]:1602";
|
||||||
|
nft_rebuild_runtime_from_uci(rt_table, table, localv4, common, port, ip_port, iface, fmark, omark, frange4, tport, "", "", "", "", "", "/opt/zapret2/bin/nfqws2", "0x02000000", "200", "0x00000002", "0x00000004", localv6, common6, ip_port6, frange6, taddr6);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nft_populate_runtime_sets_from_sections(uci_sections("section"), populate_enabled, deferred_section_names, table, common_set, port_set, ip_port_set, interface_set, localv4_set, mark, common6_set, ip_port6_set, localv6_set);
|
return nft_populate_runtime_sets_from_sections(uci_sections("section"), populate_enabled, deferred_section_names, table, common_set, port_set, ip_port_set, interface_set, localv4_set, mark, common6_set, ip_port6_set, localv6_set);
|
||||||
|
|||||||
@@ -701,6 +701,31 @@ function prepare_subscription_caches(mode) {
|
|||||||
return result.status;
|
return result.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function restore_rulesets_from_cache() {
|
||||||
|
let etc_dir = "/etc/tachyon/rulesets";
|
||||||
|
let tmp_dir = TMP_RULESET_FOLDER;
|
||||||
|
|
||||||
|
command_success_from_args(["mkdir", "-p", tmp_dir]);
|
||||||
|
let dir = fs.opendir(etc_dir);
|
||||||
|
if (!dir) return;
|
||||||
|
|
||||||
|
let entry;
|
||||||
|
while ((entry = dir.read()) != null) {
|
||||||
|
if (!match(entry, /\.(srs|lst|json)$/)) continue;
|
||||||
|
let tmp_path = tmp_dir + "/" + entry;
|
||||||
|
let etc_path = etc_dir + "/" + entry;
|
||||||
|
let tmp_st = fs.stat(tmp_path);
|
||||||
|
let etc_st = fs.stat(etc_path);
|
||||||
|
if (etc_st && etc_st.size > 0 && (!tmp_st || tmp_st.size == 0)) {
|
||||||
|
let content = fs.readfile(etc_path);
|
||||||
|
if (content)
|
||||||
|
fs.writefile(tmp_path, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
|
|
||||||
function start_main() {
|
function start_main() {
|
||||||
let status;
|
let status;
|
||||||
|
|
||||||
@@ -719,6 +744,7 @@ function start_main() {
|
|||||||
module_success(STATE_UC, [ "sync-time-if-needed" ]);
|
module_success(STATE_UC, [ "sync-time-if-needed" ]);
|
||||||
|
|
||||||
status = module_status(SUBSCRIPTION_CACHE_UC, [ "ensure-runtime-dirs" ]);
|
status = module_status(SUBSCRIPTION_CACHE_UC, [ "ensure-runtime-dirs" ]);
|
||||||
|
restore_rulesets_from_cache();
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
@@ -751,7 +777,8 @@ function start_main() {
|
|||||||
|
|
||||||
module_success(BYEDPI_UC, [ "start-runtime" ]);
|
module_success(BYEDPI_UC, [ "start-runtime" ]);
|
||||||
|
|
||||||
if (!command_success_from_args([ "/etc/init.d/sing-box", "start" ])) {
|
let sb_start = command_success_from_args([ "/etc/init.d/sing-box", "start" ]);
|
||||||
|
if (!sb_start) {
|
||||||
log_message("Failed to start sing-box. Aborted.", "fatal");
|
log_message("Failed to start sing-box. Aborted.", "fatal");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -790,6 +817,7 @@ function start_main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function start_impl() {
|
function start_impl() {
|
||||||
|
fs.writefile("/var/run/tachyon/starting", as_string(time()));
|
||||||
// (e.g. config generator killed during restart). 30-min threshold is safe since
|
// (e.g. config generator killed during restart). 30-min threshold is safe since
|
||||||
// all tachyon temp files are created and deleted within seconds under normal operation.
|
// all tachyon temp files are created and deleted within seconds under normal operation.
|
||||||
command_status("find /tmp -maxdepth 1 -name 'tachyon-*' -mmin +30 -delete 2>/dev/null; true");
|
command_status("find /tmp -maxdepth 1 -name 'tachyon-*' -mmin +30 -delete 2>/dev/null; true");
|
||||||
@@ -840,6 +868,7 @@ function start_impl() {
|
|||||||
|
|
||||||
module_background(DIAGNOSTICS_UC, [ "get-system-info" ]);
|
module_background(DIAGNOSTICS_UC, [ "get-system-info" ]);
|
||||||
module_background(TELEGRAM_UC, [ "start-runtime" ]);
|
module_background(TELEGRAM_UC, [ "start-runtime" ]);
|
||||||
|
fs.unlink("/var/run/tachyon/starting");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -854,7 +883,7 @@ function stop_main() {
|
|||||||
module_success(SUBSCRIPTION_CACHE_UC, [ "stop-deferred-bootstrap-worker" ]);
|
module_success(SUBSCRIPTION_CACHE_UC, [ "stop-deferred-bootstrap-worker" ]);
|
||||||
module_success(UPDATES_UC, [ "stop-list-update" ]);
|
module_success(UPDATES_UC, [ "stop-list-update" ]);
|
||||||
remove_cron_jobs();
|
remove_cron_jobs();
|
||||||
command_success_from_args([ "find", TMP_RULESET_FOLDER, "-mindepth", "1", "-maxdepth", "1", "-type", "f", "-delete" ]);
|
// command_success_from_args([ "find", TMP_RULESET_FOLDER, "-mindepth", "1", "-maxdepth", "1", "-type", "f", "-delete" ]);
|
||||||
|
|
||||||
if (!module_success(ZAPRET_UC, [ "stop-runtime" ]))
|
if (!module_success(ZAPRET_UC, [ "stop-runtime" ]))
|
||||||
log_message("Zapret stop failed (non-fatal)", "warn");
|
log_message("Zapret stop failed (non-fatal)", "warn");
|
||||||
@@ -887,6 +916,8 @@ function stop_main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cleanup_failed_runtime() {
|
function cleanup_failed_runtime() {
|
||||||
|
fs.unlink("/var/run/tachyon/starting");
|
||||||
|
fs.unlink("/var/run/tachyon/reloading");
|
||||||
let status = 0;
|
let status = 0;
|
||||||
|
|
||||||
log_message("Cleaning up Tachyon runtime after failed start/reload", "info");
|
log_message("Cleaning up Tachyon runtime after failed start/reload", "info");
|
||||||
|
|||||||
@@ -708,6 +708,8 @@ function safe_proxy_restart(reason, force_level) {
|
|||||||
|
|
||||||
// ─── Reload dedup: prevent multiple reload_firewall per cycle ─────────────────
|
// ─── Reload dedup: prevent multiple reload_firewall per cycle ─────────────────
|
||||||
function safe_reload_firewall() {
|
function safe_reload_firewall() {
|
||||||
|
if (fs.stat("/var/run/tachyon/starting") != null || fs.stat("/var/run/tachyon/reloading") != null)
|
||||||
|
return;
|
||||||
let now = time();
|
let now = time();
|
||||||
let min_interval = 120;
|
let min_interval = 120;
|
||||||
if (now - last_reload_time < min_interval) return;
|
if (now - last_reload_time < min_interval) return;
|
||||||
@@ -810,7 +812,7 @@ function ai_heal_subnet_cache() {
|
|||||||
let restored = [];
|
let restored = [];
|
||||||
let entry;
|
let entry;
|
||||||
while ((entry = dir.read()) != null) {
|
while ((entry = dir.read()) != null) {
|
||||||
if (!match(entry, /^community-subnets-.+\.lst$/)) continue;
|
if (!match(entry, /\.(srs|lst|json)$/)) continue;
|
||||||
let tmp_path = tmp_dir + "/" + entry;
|
let tmp_path = tmp_dir + "/" + entry;
|
||||||
let etc_path = etc_dir + "/" + entry;
|
let etc_path = etc_dir + "/" + entry;
|
||||||
let tmp_st = fs.stat(tmp_path);
|
let tmp_st = fs.stat(tmp_path);
|
||||||
|
|||||||
@@ -771,6 +771,33 @@ function restore_dns_config(backup_path) {
|
|||||||
return command_success_from_args([ "mv", "-f", backup_path, config_path ]);
|
return command_success_from_args([ "mv", "-f", backup_path, config_path ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ensure_local_rulesets_exist(temp_config) {
|
||||||
|
try {
|
||||||
|
let cfg_raw = as_string(fs.readfile(temp_config) || "");
|
||||||
|
let cfg_obj = length(cfg_raw) > 0 ? json(cfg_raw) : null;
|
||||||
|
if (type(cfg_obj) == "object" && type(cfg_obj.route) == "object" && type(cfg_obj.route.rule_set) == "array") {
|
||||||
|
command_success_from_args(["mkdir", "-p", TMP_RULESET_FOLDER]);
|
||||||
|
for (let rs in cfg_obj.route.rule_set) {
|
||||||
|
if (type(rs) == "object" && rs.type == "local" && rs.path) {
|
||||||
|
let st = fs.stat(rs.path);
|
||||||
|
if (!st || st.size == 0) {
|
||||||
|
let bname = replace(rs.path, /^.*\//, "");
|
||||||
|
let etc_file = "/etc/tachyon/rulesets/" + bname;
|
||||||
|
let etc_st = fs.stat(etc_file);
|
||||||
|
if (etc_st && etc_st.size > 0) {
|
||||||
|
let content = fs.readfile(etc_file);
|
||||||
|
if (content) fs.writefile(rs.path, content);
|
||||||
|
} else if (rs.format == "source" || match(rs.path, /\.json$/)) {
|
||||||
|
fs.writefile(rs.path, sprintf("%J", { version: 3, rules: [] }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
function init_config(populate_nft, caches_prepared, no_refresh) {
|
function init_config(populate_nft, caches_prepared, no_refresh) {
|
||||||
let settings = uci_settings();
|
let settings = uci_settings();
|
||||||
let config_path = option(settings, "config_path", "");
|
let config_path = option(settings, "config_path", "");
|
||||||
@@ -827,6 +854,7 @@ function init_config(populate_nft, caches_prepared, no_refresh) {
|
|||||||
}
|
}
|
||||||
log_file_lines(runtime_log, "warn", "sing-box config generator: ");
|
log_file_lines(runtime_log, "warn", "sing-box config generator: ");
|
||||||
|
|
||||||
|
ensure_local_rulesets_exist(temp_config);
|
||||||
let check_result = sing_box_check(temp_config, runtime_log);
|
let check_result = sing_box_check(temp_config, runtime_log);
|
||||||
while (check_result.status != 0) {
|
while (check_result.status != 0) {
|
||||||
// Graceful degradation: if the installed sing-box does not support an inbound
|
// Graceful degradation: if the installed sing-box does not support an inbound
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
UNINSTALLER_VERSION="1.2.86"
|
UNINSTALLER_VERSION="1.2.88"
|
||||||
|
|
||||||
# ─── TUI helpers & Color detection ───────────────────────────────────────────
|
# ─── TUI helpers & Color detection ───────────────────────────────────────────
|
||||||
ESC="$(printf '\033')"
|
ESC="$(printf '\033')"
|
||||||
|
|||||||
Reference in New Issue
Block a user