Improve local IP routing settings

This commit is contained in:
ushan0v
2026-05-23 07:45:04 +03:00
parent 91ce2412aa
commit c3db2503be
10 changed files with 1275 additions and 1069 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+29 -17
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PODKOP PLUS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 17:44+0300\n"
"PO-Revision-Date: 2026-05-21 17:44+0300\n"
"POT-Creation-Date: 2026-05-23 07:37+0300\n"
"PO-Revision-Date: 2026-05-23 07:37+0300\n"
"Last-Translator: ushan0v\n"
"Language-Team: none\n"
"Language: ru\n"
@@ -50,6 +50,9 @@ msgstr "Найдены дополнительные правила маркир
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
msgid "Allows limiting the list of servers for URLTest"
msgstr ""
msgid "Applicable for SOCKS and Shadowsocks links"
msgstr "Применимо для ссылок SOCKS и Shadowsocks"
@@ -74,11 +77,8 @@ msgstr "Backend-проверка завершилась ошибкой: %s"
msgid "Binary file"
msgstr "Бинарный файл"
msgid "Blacklist (Exclude)"
msgstr "Черный список (Исключить)"
msgid "Blacklist: test all servers except selected ones. Whitelist: test only selected servers."
msgstr "Черный список: проверять все серверы, кроме указанных. Белый список: проверять только указанные серверы."
msgid "Blacklist"
msgstr ""
msgid "Bootsrap DNS"
msgstr "Bootstrap DNS"
@@ -233,6 +233,9 @@ msgstr "Отключить QUIC"
msgid "Disable the QUIC protocol to improve compatibility or fix issues with video streaming"
msgstr "Отключить QUIC протокол для улучшения совместимости или исправления видео стриминга"
msgid "Disabled"
msgstr ""
msgid "DNS on router"
msgstr "DNS на роутере"
@@ -314,12 +317,18 @@ msgstr "Изменить"
msgid "Enable"
msgstr "Включить"
msgid "Enable automatic updates for remote lists and rule sets"
msgstr "Включить автоматическое обновление удалённых списков и наборов правил"
msgid "Enable autostart"
msgstr "Включить автостарт"
msgid "Enable built-in DNS resolver for domains handled by this section"
msgstr "Включить встроенный DNS-резолвер для доменов, обрабатываемых в этой секции"
msgid "Enable list updates"
msgstr "Включить обновление списков"
msgid "Enable Mixed Proxy"
msgstr "Включить смешанный прокси"
@@ -398,6 +407,9 @@ msgstr "Как часто обновлять этот удалённый наб
msgid "HTTP error"
msgstr "Ошибка HTTP"
msgid "Include country in URLTest"
msgstr ""
msgid "Include server by regular expression in URLTest"
msgstr "Включить сервер по регулярному выражению в URLTest"
@@ -650,6 +662,9 @@ msgstr "Не отвечает"
msgid "Not running"
msgstr "Не запущено"
msgid "Only servers from selected countries will be tested by URLTest"
msgstr ""
msgid "Only servers whose names match these regular expressions will be checked through URLTest"
msgstr "Только те серверы, имена которых совпадают с этими регулярными выражениями, будут проверяться через URLTest"
@@ -842,6 +857,9 @@ msgstr "Выберите предустановленный набор прав
msgid "Select DNS protocol to use"
msgstr "Выберите протокол DNS"
msgid "Select local devices or enter IP addresses/subnets to be excluded from routing"
msgstr "Выберите локальные устройства или введите IP-адреса/подсети для исключения из маршрутизации"
msgid "Select network interface for VPN connection"
msgstr "Выберите сетевой интерфейс для VPN-подключения"
@@ -920,9 +938,6 @@ msgstr "Исходные IP-адреса"
msgid "Source Network Interface"
msgstr "Сетевой интерфейс источника"
msgid "Specify a local IP address to be excluded from routing"
msgstr "Укажите локальный IP-адрес, который следует исключить из маршрутизации."
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
msgstr "Укажите локальные IP-адреса или подсети, трафик которых всегда будет маршрутизироваться через маршрут этой секции"
@@ -1103,8 +1118,8 @@ msgstr "URL должен использовать один из следующи
msgid "URLTest interval"
msgstr "Интервал URLTest"
msgid "URLTest server filter mode"
msgstr "Режим фильтра серверов URLTest"
msgid "URLTest server filtering"
msgstr ""
msgid "URLTest tolerance"
msgstr "Допуск URLTest"
@@ -1118,9 +1133,6 @@ msgstr "Используйте формат: URL | User-Agent"
msgid "Use sing-box duration format like 1d, 12h or 30m"
msgstr "Используйте формат длительности sing-box, например 1d, 12h или 30m"
msgid "Use sing-box duration format. Leave empty to disable automatic updates."
msgstr "Используйте формат длительности sing-box. Оставьте поле пустым, чтобы отключить автоматическое обновление."
msgid "Valid"
msgstr "Валидно"
@@ -1145,8 +1157,8 @@ msgstr "Предупреждение: Russia inside может быть испо
msgid "What Podkop Plus should do when this section matches"
msgstr "Что Podkop Plus должен делать при совпадении этой секции"
msgid "Whitelist (Only include)"
msgstr "Белый список (Только включить)"
msgid "Whitelist"
msgstr ""
msgid "YACD Secret Key"
msgstr "Секретный ключ YACD"
@@ -0,0 +1,248 @@
"use strict";
"require baseclass";
"require rpc";
"require ui";
"require view.podkop_plus.main as main";
const callHostHints = rpc.declare({
object: "luci-rpc",
method: "getHostHints",
expect: { "": {} },
});
const callDHCPLeases = rpc.declare({
object: "luci-rpc",
method: "getDHCPLeases",
expect: { "": {} },
});
const callNetworkInterfaceDump = rpc.declare({
object: "network.interface",
method: "dump",
expect: { interface: [] },
});
let localDeviceChoicesCache = null;
let localDeviceChoicesPromise = null;
function normalizeOptionValues(value) {
if (!value) {
return [];
}
if (Array.isArray(value)) {
return value
.filter(Boolean)
.map((item) => `${item}`.trim())
.filter(Boolean);
}
return `${value}`
.split(/\s+/)
.map((item) => item.trim())
.filter(Boolean);
}
function normalizeLocalDeviceName(name) {
return `${name || ""}`.trim().replace(/\.lan$/i, "");
}
function addLocalDeviceChoice(choices, ip, name) {
const normalizedIp = `${ip || ""}`.trim();
const normalizedName = normalizeLocalDeviceName(name);
if (!normalizedIp || !normalizedName) {
return;
}
if (!main.validateIPV4(normalizedIp).valid) {
return;
}
choices[normalizedIp] = normalizedName;
}
function addRouterIp(routerIps, ip) {
const normalizedIp = `${ip || ""}`.trim();
if (!normalizedIp || !main.validateIPV4(normalizedIp).valid) {
return;
}
routerIps[normalizedIp] = true;
}
function buildRouterIpMap(networkInterfaces) {
const routerIps = {};
if (!Array.isArray(networkInterfaces)) {
return routerIps;
}
networkInterfaces.forEach((networkInterface) => {
const ipv4Addresses =
networkInterface &&
typeof networkInterface === "object" &&
Array.isArray(networkInterface["ipv4-address"])
? networkInterface["ipv4-address"]
: [];
ipv4Addresses.forEach((address) => {
addRouterIp(
routerIps,
address && typeof address === "object" ? address.address : address,
);
});
});
return routerIps;
}
function buildLocalDeviceChoices(hostHints, dhcpLeases, networkInterfaces) {
const choices = {};
const routerIps = buildRouterIpMap(networkInterfaces);
if (hostHints && typeof hostHints === "object") {
Object.values(hostHints).forEach((hint) => {
if (!hint || typeof hint !== "object") {
return;
}
normalizeOptionValues(hint.ipaddrs || hint.ipv4).forEach((ip) => {
addLocalDeviceChoice(choices, ip, hint.name);
});
});
}
if (dhcpLeases && Array.isArray(dhcpLeases.dhcp_leases)) {
dhcpLeases.dhcp_leases.forEach((lease) => {
if (!lease || typeof lease !== "object") {
return;
}
addLocalDeviceChoice(choices, lease.ipaddr, lease.hostname);
});
}
Object.keys(routerIps).forEach((ip) => {
delete choices[ip];
});
return choices;
}
function loadLocalDeviceChoices() {
if (localDeviceChoicesCache) {
return Promise.resolve(localDeviceChoicesCache);
}
if (localDeviceChoicesPromise) {
return localDeviceChoicesPromise;
}
localDeviceChoicesPromise = Promise.all([
callHostHints().catch(() => ({})),
callDHCPLeases().catch(() => ({})),
callNetworkInterfaceDump().catch(() => []),
])
.then(([hostHints, dhcpLeases, networkInterfaces]) => {
localDeviceChoicesCache = buildLocalDeviceChoices(
hostHints,
dhcpLeases,
networkInterfaces,
);
return localDeviceChoicesCache;
})
.finally(() => {
localDeviceChoicesPromise = null;
});
return localDeviceChoicesPromise;
}
function sortLocalDeviceChoiceValues(choices) {
return Object.keys(choices).sort((a, b) => {
const byName = `${choices[a]}`.localeCompare(`${choices[b]}`);
return byName || a.localeCompare(b);
});
}
function hasSingleIpValue(values) {
return normalizeOptionValues(values).some(
(value) => main.validateIPV4(value).valid,
);
}
function preloadLocalDeviceChoicesForValues(values) {
return hasSingleIpValue(values)
? loadLocalDeviceChoices()
: Promise.resolve(null);
}
function createLocalDeviceDynamicListWidget(option, section_id, cfgvalue) {
const values = normalizeOptionValues(
cfgvalue != null ? cfgvalue : option.default,
);
const shouldResolveExistingLabels = hasSingleIpValue(values);
return (
shouldResolveExistingLabels ? loadLocalDeviceChoices() : Promise.resolve({})
).then((initialChoices) => {
const choices = localDeviceChoicesCache || initialChoices || {};
const widget = new ui.DynamicList(values, choices, {
id: option.cbid(section_id),
sort: sortLocalDeviceChoiceValues(choices),
optional: option.optional || option.rmempty,
datatype: option.datatype,
placeholder: option.placeholder,
validate: option.validate.bind(option, section_id),
disabled: option.readonly != null ? option.readonly : option.map.readonly,
});
const node = widget.render();
let choicesLoaded = Boolean(localDeviceChoicesCache);
let choicesLoading = false;
const loadChoices = () => {
if (choicesLoaded || choicesLoading) {
return;
}
choicesLoading = true;
loadLocalDeviceChoices()
.then((loadedChoices) => {
widget.clearChoices();
widget.addChoices(
sortLocalDeviceChoiceValues(loadedChoices),
loadedChoices,
);
choicesLoaded = true;
})
.finally(() => {
choicesLoading = false;
});
};
const maybeLoadChoices = (ev) => {
if (
ev.target &&
typeof ev.target.closest === "function" &&
ev.target.closest(".cbi-dropdown")
) {
loadChoices();
}
};
node.addEventListener("mousedown", maybeLoadChoices, true);
node.addEventListener("focusin", maybeLoadChoices, true);
return node;
});
}
const EntryPoint = {
createLocalDeviceDynamicListWidget,
hasSingleIpValue,
loadLocalDeviceChoices,
normalizeOptionValues,
preloadLocalDeviceChoicesForValues,
};
return baseclass.extend(EntryPoint);
@@ -2,28 +2,13 @@
"require form";
"require baseclass";
"require fs";
"require rpc";
"require ui";
"require tools.widgets as widgets";
"require uci";
"require view.podkop_plus.local_devices as localDevices";
"require view.podkop_plus.main as main";
const UCI_PACKAGE = main.PODKOP_UCI_PACKAGE;
const callHostHints = rpc.declare({
object: "luci-rpc",
method: "getHostHints",
expect: { "": {} },
});
const callDHCPLeases = rpc.declare({
object: "luci-rpc",
method: "getDHCPLeases",
expect: { "": {} },
});
const callNetworkInterfaceDump = rpc.declare({
object: "network.interface",
method: "dump",
expect: { interface: [] },
});
function valuesToText(values) {
if (!values) {
@@ -556,193 +541,6 @@ function writeListOption(section_id, key, values) {
}
}
let localDeviceChoicesCache = null;
let localDeviceChoicesPromise = null;
function normalizeLocalDeviceName(name) {
return `${name || ""}`.trim().replace(/\.lan$/i, "");
}
function addLocalDeviceChoice(choices, ip, name) {
const normalizedIp = `${ip || ""}`.trim();
const normalizedName = normalizeLocalDeviceName(name);
if (!normalizedIp || !normalizedName) {
return;
}
if (!main.validateIPV4(normalizedIp).valid) {
return;
}
choices[normalizedIp] = normalizedName;
}
function addRouterIp(routerIps, ip) {
const normalizedIp = `${ip || ""}`.trim();
if (!normalizedIp || !main.validateIPV4(normalizedIp).valid) {
return;
}
routerIps[normalizedIp] = true;
}
function buildRouterIpMap(networkInterfaces) {
const routerIps = {};
if (!Array.isArray(networkInterfaces)) {
return routerIps;
}
networkInterfaces.forEach((networkInterface) => {
const ipv4Addresses =
networkInterface &&
typeof networkInterface === "object" &&
Array.isArray(networkInterface["ipv4-address"])
? networkInterface["ipv4-address"]
: [];
ipv4Addresses.forEach((address) => {
addRouterIp(
routerIps,
address && typeof address === "object" ? address.address : address,
);
});
});
return routerIps;
}
function buildLocalDeviceChoices(hostHints, dhcpLeases, networkInterfaces) {
const choices = {};
const routerIps = buildRouterIpMap(networkInterfaces);
if (hostHints && typeof hostHints === "object") {
Object.values(hostHints).forEach((hint) => {
if (!hint || typeof hint !== "object") {
return;
}
normalizeOptionValues(hint.ipaddrs || hint.ipv4).forEach((ip) => {
addLocalDeviceChoice(choices, ip, hint.name);
});
});
}
if (dhcpLeases && Array.isArray(dhcpLeases.dhcp_leases)) {
dhcpLeases.dhcp_leases.forEach((lease) => {
if (!lease || typeof lease !== "object") {
return;
}
addLocalDeviceChoice(choices, lease.ipaddr, lease.hostname);
});
}
Object.keys(routerIps).forEach((ip) => {
delete choices[ip];
});
return choices;
}
function loadLocalDeviceChoices(refresh) {
if (!refresh && localDeviceChoicesCache) {
return Promise.resolve(localDeviceChoicesCache);
}
if (!refresh && localDeviceChoicesPromise) {
return localDeviceChoicesPromise;
}
localDeviceChoicesPromise = Promise.all([
callHostHints().catch(() => ({})),
callDHCPLeases().catch(() => ({})),
callNetworkInterfaceDump().catch(() => []),
])
.then(([hostHints, dhcpLeases, networkInterfaces]) => {
localDeviceChoicesCache = buildLocalDeviceChoices(
hostHints,
dhcpLeases,
networkInterfaces,
);
return localDeviceChoicesCache;
})
.finally(() => {
localDeviceChoicesPromise = null;
});
return localDeviceChoicesPromise;
}
function sortLocalDeviceChoiceValues(choices) {
return Object.keys(choices).sort((a, b) => {
const byName = `${choices[a]}`.localeCompare(`${choices[b]}`);
return byName || a.localeCompare(b);
});
}
function hasSingleIpValue(values) {
return values.some((value) => main.validateIPV4(value).valid);
}
function createLocalDeviceDynamicListWidget(option, section_id, cfgvalue) {
const values = normalizeOptionValues(
cfgvalue != null ? cfgvalue : option.default,
);
const shouldResolveExistingLabels = hasSingleIpValue(values);
return (
shouldResolveExistingLabels ? loadLocalDeviceChoices() : Promise.resolve({})
).then((initialChoices) => {
const widget = new ui.DynamicList(values, initialChoices || {}, {
id: option.cbid(section_id),
sort: sortLocalDeviceChoiceValues(initialChoices || {}),
optional: option.optional || option.rmempty,
datatype: option.datatype,
placeholder: option.placeholder,
validate: option.validate.bind(option, section_id),
disabled: option.readonly != null ? option.readonly : option.map.readonly,
});
const node = widget.render();
let choicesLoaded = shouldResolveExistingLabels;
let choicesLoading = false;
const loadChoices = () => {
if (choicesLoaded || choicesLoading) {
return;
}
choicesLoading = true;
loadLocalDeviceChoices(true)
.then((choices) => {
widget.clearChoices();
widget.addChoices(sortLocalDeviceChoiceValues(choices), choices);
choicesLoaded = true;
})
.finally(() => {
choicesLoading = false;
});
};
const maybeLoadChoices = (ev) => {
if (
ev.target &&
typeof ev.target.closest === "function" &&
ev.target.closest(".cbi-dropdown")
) {
loadChoices();
}
};
node.addEventListener("mousedown", maybeLoadChoices, true);
node.addEventListener("focusin", maybeLoadChoices, true);
return node;
});
}
function validateRegex(_section_id, value) {
if (!value || !value.length) {
return true;
@@ -2441,7 +2239,11 @@ function addLocalDeviceSubnetDynamicField(section, config) {
uci.unset(UCI_PACKAGE, section_id, `${config.key}_text_mode`);
};
o.renderWidget = function (section_id, _option_index, cfgvalue) {
return createLocalDeviceDynamicListWidget(this, section_id, cfgvalue);
return localDevices.createLocalDeviceDynamicListWidget(
this,
section_id,
cfgvalue,
);
};
return o;
@@ -3,6 +3,7 @@
"require uci";
"require baseclass";
"require tools.widgets as widgets";
"require view.podkop_plus.local_devices as localDevices";
"require view.podkop_plus.main as main";
const UCI_PACKAGE = main.PODKOP_UCI_PACKAGE;
@@ -154,9 +155,7 @@ function createSettingsContent(section) {
}
// Reject lan*
if (
value.startsWith("lan")
) {
if (value.startsWith("lan")) {
return false;
}
@@ -250,7 +249,9 @@ function createSettingsContent(section) {
form.Flag,
"enable_yacd_wan_access",
_("Enable YACD WAN Access"),
_("Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."),
_(
"Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall.",
),
);
o.depends("enable_yacd", "1");
o.default = "0";
@@ -260,7 +261,9 @@ function createSettingsContent(section) {
form.Value,
"yacd_secret_key",
_("YACD Secret Key"),
_("Secret key for authenticating remote access to YACD when WAN access is enabled."),
_(
"Secret key for authenticating remote access to YACD when WAN access is enabled.",
),
);
o.depends("enable_yacd_wan_access", "1");
o.rmempty = false;
@@ -276,18 +279,27 @@ function createSettingsContent(section) {
o.default = "0";
o.rmempty = false;
o = section.option(
form.Flag,
"list_update_enabled",
_("Enable list updates"),
_("Enable automatic updates for remote lists and rule sets"),
);
o.default = "1";
o.rmempty = false;
o = section.option(
form.Value,
"update_interval",
_("List Update Frequency"),
_(
"Use sing-box duration format. Leave empty to disable automatic updates.",
),
_("Use sing-box duration format like 1d, 12h or 30m"),
);
o.depends("list_update_enabled", "1");
o.placeholder = "1d";
o.rmempty = true;
o.default = "1d";
o.rmempty = false;
o.cfgvalue = function (section_id) {
return uci.get(UCI_PACKAGE, section_id, "update_interval") || "";
return uci.get(UCI_PACKAGE, section_id, "update_interval") || "1d";
};
o.write = function (section_id, value) {
const normalized = value ? `${value}`.trim() : "";
@@ -295,14 +307,14 @@ function createSettingsContent(section) {
if (normalized.length) {
uci.set(UCI_PACKAGE, section_id, "update_interval", normalized);
} else {
uci.unset(UCI_PACKAGE, section_id, "update_interval");
uci.set(UCI_PACKAGE, section_id, "update_interval", "1d");
}
};
o.validate = function (_section_id, value) {
const normalized = value ? `${value}`.trim() : "";
if (!normalized.length) {
return true;
return _("Use sing-box duration format like 1d, 12h or 30m");
}
if (isSingBoxDuration(normalized)) {
@@ -420,9 +432,7 @@ function createSettingsContent(section) {
form.ListValue,
"log_level",
_("Log Level"),
_(
"Select the log level for sing-box",
),
_("Select the log level for sing-box"),
);
o.value("trace", "Trace");
o.value("debug", "Debug");
@@ -449,9 +459,11 @@ function createSettingsContent(section) {
form.DynamicList,
"routing_excluded_ips",
_("Routing Excluded IPs"),
_("Specify a local IP address to be excluded from routing"),
_(
"Select local devices or enter IP addresses/subnets to be excluded from routing",
),
);
o.placeholder = "IP";
o.placeholder = _("Device, IP, or subnet");
o.rmempty = true;
o.validate = function (section_id, value) {
// Optional
@@ -459,7 +471,7 @@ function createSettingsContent(section) {
return true;
}
const validation = main.validateIPV4(value);
const validation = main.validateSubnet(value);
if (validation.valid) {
return true;
@@ -467,6 +479,22 @@ function createSettingsContent(section) {
return validation.message;
};
o.load = function (section_id) {
const values = localDevices.normalizeOptionValues(
uci.get(UCI_PACKAGE, section_id, "routing_excluded_ips"),
);
return localDevices
.preloadLocalDeviceChoicesForValues(values)
.then(() => values);
};
o.renderWidget = function (section_id, _option_index, cfgvalue) {
return localDevices.createLocalDeviceDynamicListWidget(
this,
section_id,
cfgvalue,
);
};
}
const EntryPoint = {
+24 -21
View File
@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PODKOP PLUS\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 17:44+0300\n"
"PO-Revision-Date: 2026-05-21 17:44+0300\n"
"POT-Creation-Date: 2026-05-23 07:37+0300\n"
"PO-Revision-Date: 2026-05-23 07:37+0300\n"
"Last-Translator: ushan0v\n"
"Language-Team: none\n"
"Language: ru\n"
@@ -50,6 +50,9 @@ msgstr "Найдены дополнительные правила маркир
msgid "Allows access to YACD from the WAN. Make sure to open the appropriate port in your firewall."
msgstr "Обеспечивает доступ к YACD из WAN. Убедитесь, что в брандмауэре открыт соответствующий порт."
msgid "Allows limiting the list of servers for URLTest"
msgstr ""
msgid "Applicable for SOCKS and Shadowsocks links"
msgstr "Применимо для ссылок SOCKS и Shadowsocks"
@@ -74,11 +77,8 @@ msgstr "Backend-проверка завершилась ошибкой: %s"
msgid "Binary file"
msgstr "Бинарный файл"
msgid "Allows limiting the list of servers for URLTest"
msgstr "Позволяет ограничить список серверов для URLTest"
msgid "Blacklist"
msgstr "Черный список"
msgstr ""
msgid "Bootsrap DNS"
msgstr "Bootstrap DNS"
@@ -234,7 +234,7 @@ msgid "Disable the QUIC protocol to improve compatibility or fix issues with vid
msgstr "Отключить QUIC протокол для улучшения совместимости или исправления видео стриминга"
msgid "Disabled"
msgstr "Отключено"
msgstr ""
msgid "DNS on router"
msgstr "DNS на роутере"
@@ -317,12 +317,18 @@ msgstr "Изменить"
msgid "Enable"
msgstr "Включить"
msgid "Enable automatic updates for remote lists and rule sets"
msgstr "Включить автоматическое обновление удалённых списков и наборов правил"
msgid "Enable autostart"
msgstr "Включить автостарт"
msgid "Enable built-in DNS resolver for domains handled by this section"
msgstr "Включить встроенный DNS-резолвер для доменов, обрабатываемых в этой секции"
msgid "Enable list updates"
msgstr "Включить обновление списков"
msgid "Enable Mixed Proxy"
msgstr "Включить смешанный прокси"
@@ -401,6 +407,9 @@ msgstr "Как часто обновлять этот удалённый наб
msgid "HTTP error"
msgstr "Ошибка HTTP"
msgid "Include country in URLTest"
msgstr ""
msgid "Include server by regular expression in URLTest"
msgstr "Включить сервер по регулярному выражению в URLTest"
@@ -653,6 +662,9 @@ msgstr "Не отвечает"
msgid "Not running"
msgstr "Не запущено"
msgid "Only servers from selected countries will be tested by URLTest"
msgstr ""
msgid "Only servers whose names match these regular expressions will be checked through URLTest"
msgstr "Только те серверы, имена которых совпадают с этими регулярными выражениями, будут проверяться через URLTest"
@@ -845,6 +857,9 @@ msgstr "Выберите предустановленный набор прав
msgid "Select DNS protocol to use"
msgstr "Выберите протокол DNS"
msgid "Select local devices or enter IP addresses/subnets to be excluded from routing"
msgstr "Выберите локальные устройства или введите IP-адреса/подсети для исключения из маршрутизации"
msgid "Select network interface for VPN connection"
msgstr "Выберите сетевой интерфейс для VPN-подключения"
@@ -923,9 +938,6 @@ msgstr "Исходные IP-адреса"
msgid "Source Network Interface"
msgstr "Сетевой интерфейс источника"
msgid "Specify a local IP address to be excluded from routing"
msgstr "Укажите локальный IP-адрес, который следует исключить из маршрутизации."
msgid "Specify local IP addresses or subnets whose traffic will always be routed through the configured route"
msgstr "Укажите локальные IP-адреса или подсети, трафик которых всегда будет маршрутизироваться через маршрут этой секции"
@@ -1107,7 +1119,7 @@ msgid "URLTest interval"
msgstr "Интервал URLTest"
msgid "URLTest server filtering"
msgstr "Фильтрация серверов URLTest"
msgstr ""
msgid "URLTest tolerance"
msgstr "Допуск URLTest"
@@ -1121,9 +1133,6 @@ msgstr "Используйте формат: URL | User-Agent"
msgid "Use sing-box duration format like 1d, 12h or 30m"
msgstr "Используйте формат длительности sing-box, например 1d, 12h или 30m"
msgid "Use sing-box duration format. Leave empty to disable automatic updates."
msgstr "Используйте формат длительности sing-box. Оставьте поле пустым, чтобы отключить автоматическое обновление."
msgid "Valid"
msgstr "Валидно"
@@ -1149,7 +1158,7 @@ msgid "What Podkop Plus should do when this section matches"
msgstr "Что Podkop Plus должен делать при совпадении этой секции"
msgid "Whitelist"
msgstr "Белый список"
msgstr ""
msgid "YACD Secret Key"
msgstr "Секретный ключ YACD"
@@ -1171,9 +1180,3 @@ msgstr "Бинарник провайдера Zapret доступен"
msgid "Zapret provider binary is not available"
msgstr "Бинарник провайдера Zapret недоступен"
msgid "Include country in URLTest"
msgstr "Включить страну в URLTest"
msgid "Only servers from selected countries will be tested by URLTest"
msgstr "Только серверы из выбранных стран будут проверяться через URLTest"
File diff suppressed because it is too large Load Diff
+1
View File
@@ -11,6 +11,7 @@ config settings 'settings'
#option badwan_reload_delay '2000'
option enable_yacd '0'
option disable_quic '0'
option list_update_enabled '1'
option update_interval '1d'
option download_lists_via_proxy '0'
#option download_lists_via_proxy_section 'main'
+50 -6
View File
@@ -1095,7 +1095,7 @@ build_sing_box_signature() {
config_get output_network_interface "settings" "output_network_interface"
config_get_bool disable_quic "settings" "disable_quic" 0
config_get routing_excluded_ips "settings" "routing_excluded_ips"
config_get update_interval "settings" "update_interval"
update_interval="$(get_settings_update_interval)"
config_get cache_path "settings" "cache_path" "/tmp/sing-box/cache.db"
config_get config_path "settings" "config_path"
config_get log_level "settings" "log_level" "warn"
@@ -1288,7 +1288,7 @@ build_cron_signature() {
local update_interval
signature_begin
config_get update_interval "settings" "update_interval"
update_interval="$(get_settings_update_interval)"
signature_add "settings.update_interval" "$update_interval"
config_foreach append_list_update_signature "section"
config_foreach append_subscription_update_cron_signature "section"
@@ -1389,10 +1389,20 @@ has_remote_sing_box_ruleset_sources() {
}
get_settings_update_interval() {
local update_interval
local enabled update_interval
config_get update_interval "settings" "update_interval"
printf '%s\n' "$update_interval"
config_get_bool enabled "settings" "list_update_enabled" 1
if [ "$enabled" -eq 0 ]; then
printf '\n'
return 0
fi
config_get update_interval "settings" "update_interval" "1d"
if [ -n "$update_interval" ]; then
printf '%s\n' "$update_interval"
else
printf '1d\n'
fi
}
get_duration_option_with_default_if_unset() {
@@ -1700,7 +1710,19 @@ validate_download_lists_via_proxy_section() {
fi
}
validate_list_update_settings() {
local enabled update_interval
config_get_bool enabled "settings" "list_update_enabled" 1
[ "$enabled" -eq 1 ] || return 0
config_get update_interval "settings" "update_interval" "1d"
[ -n "$update_interval" ] || update_interval="1d"
validate_required_sing_box_duration_option "$update_interval" "settings.update_interval"
}
validate_runtime_settings() {
validate_list_update_settings
validate_download_lists_via_proxy_section
}
@@ -2078,6 +2100,27 @@ migrate_0_7_17_8_rule_section() {
migrate_0_7_17_8_rule "$section" 1
}
migrate_list_update_enabled() {
local list_update_enabled update_interval
if podkop_uci_option_exists "settings" "list_update_enabled"; then
config_get_bool list_update_enabled "settings" "list_update_enabled" 1
if [ "$list_update_enabled" -eq 1 ]; then
config_get update_interval "settings" "update_interval"
[ -n "$update_interval" ] || podkop_uci_set_option "settings" "update_interval" "1d"
fi
return 0
fi
config_get update_interval "settings" "update_interval"
if [ -n "$update_interval" ]; then
podkop_uci_set_option "settings" "list_update_enabled" "1"
else
podkop_uci_set_option "settings" "list_update_enabled" "0"
podkop_uci_set_option "settings" "update_interval" "1d"
fi
}
check_requirements() {
log "Check Requirements"
@@ -2596,12 +2639,13 @@ migration() {
podkop_config_migration_added_lists=""
ensure_runtime_cache_format
migrate_list_update_enabled
config_foreach migrate_0_7_17_8_rule_section "rule"
config_foreach migrate_0_7_17_8_rule "section"
if [ "$podkop_config_migration_changed" -eq 1 ]; then
log "Migrated Podkop Plus UCI config from 0.7.17-8 schema"
log "Migrated Podkop Plus UCI config"
commit_podkop_config
fi
}