feat: per-section MAC/DNS exclusions, boot latency sweep, WDTT/OlcRTC providers, DNS hijack socket collision fix
Features: - Per-Section MAC Exclusions: nft, generator_routes, section.js, i18n - Per-Section Routed DNS: connections, generator_routes, nft, validator, types.ts, section.js, state.uc, reload.uc - Boot Latency Sweep: ui.uc latency boot sweep with fixture dispatchers - WDTT provider: full backend (common, validator, runtime), sing-box outbound, diagnostics, component install, updater, i18n, section.js UI - OlcRTC provider: full backend (common, validator, runtime), sing-box outbound, diagnostics, component install, updater, i18n, section.js UI - WireGuard-over-TURN tunnel (WDTT) and TCP-over-WebRTC tunnel (OlcRTC) as sidecar processes with local SOCKS5, routed through sing-box outbound Bug fixes: - route.uc: restrict hijack-dns to local DNS inbounds only (dns-in, source-dns-in, dns-health-*) — fixes socket collision between sing-box and dnsmasq on port 53 via SO_REUSEADDR transparent write-back sockets - runtime.uc: add Port 53 socket collision diagnostic with auto-fix (sing-box restart to clear parasitic UNCONN sockets with Recv-Q) - runtime.uc: add dnsmasq dns_redirect check with auto-fix — disables firewall4 DNAT that causes TProxy to rewrite destination to router :53 - failover.uc: add wdtt/olcrtc to failover candidate actions - telegram.uc: show WDTT/OlcRTC installed status in /info Tests: 135/155 shell + 591/591 frontend
This commit is contained in:
@@ -3407,6 +3407,8 @@ var Tachyon;
|
||||
AvailableMethods2["GET_TAILSCALE_PEERS"] = "get_tailscale_peers";
|
||||
AvailableMethods2["GET_ZAPRET2_STATUS"] = "get_zapret2_status";
|
||||
AvailableMethods2["GET_BYEDPI_STATUS"] = "get_byedpi_status";
|
||||
AvailableMethods2["GET_WDTT_STATUS"] = "get_wdtt_status";
|
||||
AvailableMethods2["GET_OLCRTC_STATUS"] = "get_olcrtc_status";
|
||||
AvailableMethods2["CLASH_API"] = "clash_api";
|
||||
AvailableMethods2["ENABLE"] = "enable";
|
||||
AvailableMethods2["DISABLE"] = "disable";
|
||||
@@ -3734,6 +3736,18 @@ var TachyonShellMethods = {
|
||||
"/usr/bin/tachyon",
|
||||
{ allowNonZeroWithStdout: true }
|
||||
),
|
||||
getWdttStatus: async () => callBaseMethod(
|
||||
Tachyon.AvailableMethods.GET_WDTT_STATUS,
|
||||
[],
|
||||
"/usr/bin/tachyon",
|
||||
{ allowNonZeroWithStdout: true }
|
||||
),
|
||||
getOlcrtcStatus: async () => callBaseMethod(
|
||||
Tachyon.AvailableMethods.GET_OLCRTC_STATUS,
|
||||
[],
|
||||
"/usr/bin/tachyon",
|
||||
{ allowNonZeroWithStdout: true }
|
||||
),
|
||||
getClashApiProxies: async () => callBaseMethod(Tachyon.AvailableMethods.CLASH_API, [
|
||||
Tachyon.AvailableClashAPIMethods.GET_PROXIES
|
||||
]),
|
||||
@@ -5045,7 +5059,9 @@ function isConnectionAction(action) {
|
||||
);
|
||||
}
|
||||
function isServiceAction(action) {
|
||||
return Boolean(action && ["zapret", "zapret2", "byedpi"].includes(action));
|
||||
return Boolean(
|
||||
action && ["zapret", "zapret2", "byedpi", "wdtt", "olcrtc"].includes(action)
|
||||
);
|
||||
}
|
||||
function hasSubscriptionSources(section) {
|
||||
return getSubscriptionSourceCount(section) > 0;
|
||||
@@ -5826,6 +5842,38 @@ async function getDashboardSections(options = {}) {
|
||||
statusMessage: s.status_message
|
||||
};
|
||||
}
|
||||
} else if (serviceType === "wdtt") {
|
||||
const result = await TachyonShellMethods.getWdttStatus();
|
||||
if (result.success && result.data) {
|
||||
const s = result.data;
|
||||
return {
|
||||
serviceType: "wdtt",
|
||||
configured: Boolean(s.configured),
|
||||
ready: Boolean(s.ready),
|
||||
conflict: Boolean(s.conflict),
|
||||
runningProcesses: s.running_process_count,
|
||||
expectedProcesses: s.expected_process_count,
|
||||
restartCount: s.restart_count,
|
||||
unstable: Boolean(s.runtime_unstable),
|
||||
statusMessage: s.status_message
|
||||
};
|
||||
}
|
||||
} else if (serviceType === "olcrtc") {
|
||||
const result = await TachyonShellMethods.getOlcrtcStatus();
|
||||
if (result.success && result.data) {
|
||||
const s = result.data;
|
||||
return {
|
||||
serviceType: "olcrtc",
|
||||
configured: Boolean(s.configured),
|
||||
ready: Boolean(s.ready),
|
||||
conflict: Boolean(s.conflict),
|
||||
runningProcesses: s.running_process_count,
|
||||
expectedProcesses: s.expected_process_count,
|
||||
restartCount: s.restart_count,
|
||||
unstable: Boolean(s.runtime_unstable),
|
||||
statusMessage: s.status_message
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (_error) {
|
||||
}
|
||||
@@ -6227,6 +6275,14 @@ var initialDiagnosticStore = {
|
||||
byedpi_installed: 0,
|
||||
byedpi_backup_version: "",
|
||||
byedpi_backup_time: 0,
|
||||
wdtt_version: "loading",
|
||||
wdtt_installed: 0,
|
||||
wdtt_backup_version: "",
|
||||
wdtt_backup_time: 0,
|
||||
olcrtc_version: "loading",
|
||||
olcrtc_installed: 0,
|
||||
olcrtc_backup_version: "",
|
||||
olcrtc_backup_time: 0,
|
||||
tailscale_version: "loading",
|
||||
tailscale_installed: 0,
|
||||
tailscale_backup_version: "",
|
||||
@@ -6307,6 +6363,14 @@ var initialDiagnosticStore = {
|
||||
byedpiInstall: { loading: false },
|
||||
byedpiRemove: { loading: false },
|
||||
byedpiRollback: { loading: false },
|
||||
wdttCheck: { loading: false },
|
||||
wdttInstall: { loading: false },
|
||||
wdttRemove: { loading: false },
|
||||
wdttRollback: { loading: false },
|
||||
olcrtcCheck: { loading: false },
|
||||
olcrtcInstall: { loading: false },
|
||||
olcrtcRemove: { loading: false },
|
||||
olcrtcRollback: { loading: false },
|
||||
tailscaleCheck: { loading: false },
|
||||
tailscaleInstall: { loading: false },
|
||||
tailscaleRemove: { loading: false },
|
||||
@@ -6632,7 +6696,7 @@ function getTachyonLogNotification(line) {
|
||||
return { kind: "error", line };
|
||||
}
|
||||
const update = line.match(
|
||||
/\[component-update\]\s+(tachyon|sing_box|zapret|zapret2|byedpi)\s+(\S+)/i
|
||||
/\[component-update\]\s+(tachyon|sing_box|zapret|zapret2|byedpi|wdtt|olcrtc)\s+(\S+)/i
|
||||
);
|
||||
if (!update) {
|
||||
return null;
|
||||
@@ -6697,6 +6761,16 @@ var componentActionKeyMap = {
|
||||
"byedpi:install_version": "byedpiInstall",
|
||||
"byedpi:remove": "byedpiRemove",
|
||||
"byedpi:rollback": "byedpiRollback",
|
||||
"wdtt:check_update": "wdttCheck",
|
||||
"wdtt:install": "wdttInstall",
|
||||
"wdtt:install_version": "wdttInstall",
|
||||
"wdtt:remove": "wdttRemove",
|
||||
"wdtt:rollback": "wdttRollback",
|
||||
"olcrtc:check_update": "olcrtcCheck",
|
||||
"olcrtc:install": "olcrtcInstall",
|
||||
"olcrtc:install_version": "olcrtcInstall",
|
||||
"olcrtc:remove": "olcrtcRemove",
|
||||
"olcrtc:rollback": "olcrtcRollback",
|
||||
"tailscale:check_update": "tailscaleCheck",
|
||||
"tailscale:install": "tailscaleInstall",
|
||||
"tailscale:install_version": "tailscaleInstall",
|
||||
@@ -6872,6 +6946,14 @@ function getEmptyUpdatesActions() {
|
||||
byedpiInstall: { loading: false },
|
||||
byedpiRemove: { loading: false },
|
||||
byedpiRollback: { loading: false },
|
||||
wdttCheck: { loading: false },
|
||||
wdttInstall: { loading: false },
|
||||
wdttRemove: { loading: false },
|
||||
wdttRollback: { loading: false },
|
||||
olcrtcCheck: { loading: false },
|
||||
olcrtcInstall: { loading: false },
|
||||
olcrtcRemove: { loading: false },
|
||||
olcrtcRollback: { loading: false },
|
||||
tailscaleCheck: { loading: false },
|
||||
tailscaleInstall: { loading: false },
|
||||
tailscaleRemove: { loading: false },
|
||||
@@ -6913,6 +6995,8 @@ function applyServiceState(uiState) {
|
||||
zapret_installed: uiState.capabilities.zapret_installed,
|
||||
zapret2_installed: uiState.capabilities.zapret2_installed,
|
||||
byedpi_installed: uiState.capabilities.byedpi_installed,
|
||||
wdtt_installed: uiState.capabilities.wdtt_installed,
|
||||
olcrtc_installed: uiState.capabilities.olcrtc_installed,
|
||||
server_inbounds_enabled_count: uiState.capabilities.server_inbounds_enabled_count
|
||||
};
|
||||
nextSystemInfo.sing_box_extended = uiState.capabilities.sing_box_extended;
|
||||
@@ -7146,7 +7230,9 @@ function componentDisplayName(component) {
|
||||
sing_box: "sing-box",
|
||||
zapret: "Zapret",
|
||||
zapret2: "Zapret2",
|
||||
byedpi: "ByeDPI"
|
||||
byedpi: "ByeDPI",
|
||||
wdtt: "WDTT",
|
||||
olcrtc: "OlcRTC"
|
||||
};
|
||||
return names[component] || component;
|
||||
}
|
||||
@@ -10767,6 +10853,7 @@ async function runZapret2Check() {
|
||||
const tachyonRuntimeReady = !hasZapret2Rules || runningProcesses === expectedProcesses && supervisorProcesses === expectedProcesses;
|
||||
const unexpectedRuntime = !hasZapret2Rules && (runningProcesses > 0 || supervisorProcesses > 0);
|
||||
const outboundsConfigured = Boolean(data.outbounds_configured);
|
||||
const routesConfigured = Boolean(data.routes_configured);
|
||||
const standaloneServiceEnabled = Boolean(data.standalone_service_enabled);
|
||||
const standaloneServiceRunning = Boolean(data.standalone_service_running);
|
||||
const standaloneConflict = hasZapret2Rules && standaloneServiceRunning;
|
||||
@@ -10802,6 +10889,11 @@ async function runZapret2Check() {
|
||||
key: outboundsConfigured ? _("Zapret2 sing-box outbound is configured") : _("Zapret2 sing-box outbound is not configured"),
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
state: !hasZapret2Rules || routesConfigured ? "success" : "error",
|
||||
key: routesConfigured ? _("Zapret2 sing-box route rules are configured") : _("Zapret2 sing-box route rules are not configured"),
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
state: standaloneConflict ? "error" : standaloneAutostartRisk ? "warning" : "success",
|
||||
key: standaloneServiceRunning ? hasZapret2Rules ? _(
|
||||
@@ -10925,6 +11017,10 @@ var UNKNOWN_SYSTEM_INFO = {
|
||||
zapret2_installed: 0,
|
||||
byedpi_version: _("unknown"),
|
||||
byedpi_installed: 0,
|
||||
wdtt_version: _("unknown"),
|
||||
wdtt_installed: 0,
|
||||
olcrtc_version: _("unknown"),
|
||||
olcrtc_installed: 0,
|
||||
tailscale_version: _("unknown"),
|
||||
tailscale_installed: 0,
|
||||
server_inbounds_enabled_count: -1,
|
||||
@@ -10990,6 +11086,8 @@ async function ensureSystemInfo({
|
||||
zapret_installed: latestSystemInfo.zapret_installed,
|
||||
zapret2_installed: latestSystemInfo.zapret2_installed,
|
||||
byedpi_installed: latestSystemInfo.byedpi_installed,
|
||||
wdtt_installed: latestSystemInfo.wdtt_installed,
|
||||
olcrtc_installed: latestSystemInfo.olcrtc_installed,
|
||||
server_inbounds_enabled_count: latestSystemInfo.server_inbounds_enabled_count
|
||||
};
|
||||
store.set({
|
||||
|
||||
@@ -23,6 +23,8 @@ const ROUTING_ACTIONS = [
|
||||
"zapret",
|
||||
"zapret2",
|
||||
"byedpi",
|
||||
"wdtt",
|
||||
"olcrtc",
|
||||
"awg",
|
||||
"warp",
|
||||
"anytls",
|
||||
@@ -487,6 +489,8 @@ const actionProvidersAvailabilityState = {
|
||||
zapretInstalled: false,
|
||||
zapret2Installed: false,
|
||||
byedpiInstalled: false,
|
||||
wdttInstalled: false,
|
||||
olcrtcInstalled: false,
|
||||
torInstalled: false,
|
||||
singBoxExtended: false,
|
||||
};
|
||||
@@ -669,6 +673,18 @@ function updateActionProvidersAvailabilityState(nextState) {
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof nextState.wdttInstalled !== "undefined") {
|
||||
actionProvidersAvailabilityState.wdttInstalled = Boolean(
|
||||
nextState.wdttInstalled,
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof nextState.olcrtcInstalled !== "undefined") {
|
||||
actionProvidersAvailabilityState.olcrtcInstalled = Boolean(
|
||||
nextState.olcrtcInstalled,
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof nextState.singBoxExtended !== "undefined") {
|
||||
actionProvidersAvailabilityState.singBoxExtended = Boolean(
|
||||
nextState.singBoxExtended,
|
||||
@@ -693,6 +709,8 @@ function updateActionProvidersAvailabilityFromSystemInfo(systemInfo) {
|
||||
zapretInstalled: Boolean(systemInfo.zapret_installed),
|
||||
zapret2Installed: Boolean(systemInfo.zapret2_installed),
|
||||
byedpiInstalled: Boolean(systemInfo.byedpi_installed),
|
||||
wdttInstalled: Boolean(systemInfo.wdtt_installed),
|
||||
olcrtcInstalled: Boolean(systemInfo.olcrtc_installed),
|
||||
singBoxExtended: Boolean(systemInfo.sing_box_extended),
|
||||
torInstalled: Boolean(systemInfo.tor_installed),
|
||||
});
|
||||
@@ -2102,6 +2120,14 @@ function isDownloadThroughTargetSection(section, currentSectionId) {
|
||||
return isByedpiInstalledForUi();
|
||||
}
|
||||
|
||||
if (action === "wdtt") {
|
||||
return isWdttInstalledForUi();
|
||||
}
|
||||
|
||||
if (action === "olcrtc") {
|
||||
return isOlcrtcInstalledForUi();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4534,6 +4560,14 @@ function isByedpiInstalledForUi() {
|
||||
return actionProvidersAvailabilityState.byedpiInstalled;
|
||||
}
|
||||
|
||||
function isWdttInstalledForUi() {
|
||||
return actionProvidersAvailabilityState.wdttInstalled;
|
||||
}
|
||||
|
||||
function isOlcrtcInstalledForUi() {
|
||||
return actionProvidersAvailabilityState.olcrtcInstalled;
|
||||
}
|
||||
|
||||
function isSingBoxExtendedForUi() {
|
||||
return actionProvidersAvailabilityState.singBoxExtended;
|
||||
}
|
||||
@@ -4565,6 +4599,10 @@ function getActionOptionLabel(action) {
|
||||
return "Zapret2";
|
||||
case "byedpi":
|
||||
return "ByeDPI";
|
||||
case "wdtt":
|
||||
return "WDTT";
|
||||
case "olcrtc":
|
||||
return "OlcRTC";
|
||||
|
||||
case "awg":
|
||||
return "AmneziaWG";
|
||||
@@ -4607,6 +4645,14 @@ function getRuleActionDisplayValue(section_id) {
|
||||
return "ByeDPI";
|
||||
}
|
||||
|
||||
if (action === "wdtt") {
|
||||
return "WDTT";
|
||||
}
|
||||
|
||||
if (action === "olcrtc") {
|
||||
return "OlcRTC";
|
||||
}
|
||||
|
||||
if (action === "awg") {
|
||||
return "AmneziaWG";
|
||||
}
|
||||
@@ -4673,6 +4719,12 @@ function populateActionOptionValues(option) {
|
||||
if (isByedpiInstalledForUi()) {
|
||||
option.value("byedpi", getActionOptionLabel("byedpi"));
|
||||
}
|
||||
if (isWdttInstalledForUi()) {
|
||||
option.value("wdtt", getActionOptionLabel("wdtt"));
|
||||
}
|
||||
if (isOlcrtcInstalledForUi()) {
|
||||
option.value("olcrtc", getActionOptionLabel("olcrtc"));
|
||||
}
|
||||
option.value("hosts", getActionOptionLabel("hosts"));
|
||||
}
|
||||
|
||||
@@ -7819,6 +7871,227 @@ function createSectionContent(section) {
|
||||
};
|
||||
configureTextareaOption(o, analyzeByedpiStrategy);
|
||||
|
||||
// ─── WDTT Fields ──────────────────────────────────────────────────────
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_uri",
|
||||
_("WDTT URI"),
|
||||
_("WDTT connection URI (wdtt://...)"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.ListValue,
|
||||
"warp_flow_mode",
|
||||
_("WDTT Mode"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.value("", _("Default"));
|
||||
o.value("freedom", _("Freedom"));
|
||||
o.value("captive", _("Captive"));
|
||||
o.value("camou", _("Camou"));
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_device_id",
|
||||
_("WDTT Device ID"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_workers",
|
||||
_("WDTT Workers"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_max_hashes",
|
||||
_("WDTT Max Hashes"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_mtu",
|
||||
_("WDTT MTU"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"warp_flow_refresh",
|
||||
_("WDTT Refresh"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Flag,
|
||||
"warp_flow_auto_update",
|
||||
_("WDTT Auto Update"),
|
||||
);
|
||||
o.default = "1";
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Flag,
|
||||
"warp_flow_block_doh",
|
||||
_("WDTT Block DoH"),
|
||||
);
|
||||
o.default = "0";
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Flag,
|
||||
"warp_flow_block_ipv6",
|
||||
_("WDTT Block IPv6"),
|
||||
);
|
||||
o.default = "0";
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.ListValue,
|
||||
"warp_flow_qwdtt_mode",
|
||||
_("WDTT QWDTT Mode"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.value("", _("Default"));
|
||||
o.value("client", _("Client"));
|
||||
o.value("server", _("Server"));
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.DynamicList,
|
||||
"warp_flow_subscription_links",
|
||||
_("WDTT Subscription Links"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.DynamicList,
|
||||
"warp_flow_community_lists",
|
||||
_("WDTT Community Lists"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.DynamicList,
|
||||
"warp_flow_remote_domain_list",
|
||||
_("WDTT Remote Domain List"),
|
||||
);
|
||||
o.depends("action", "wdtt");
|
||||
o.modalonly = true;
|
||||
|
||||
// ─── OlcRTC Fields ────────────────────────────────────────────────────
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.ListValue,
|
||||
"olcrtc_provider",
|
||||
_("OlcRTC Provider"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.value("jitsi", _("Jitsi"));
|
||||
o.value("wrt", _("WRT"));
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.ListValue,
|
||||
"olcrtc_transport",
|
||||
_("OlcRTC Transport"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.value("whep", _("WHEP"));
|
||||
o.value("whip", _("WHIP"));
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"olcrtc_room_id",
|
||||
_("OlcRTC Room ID"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"olcrtc_crypto_key",
|
||||
_("OlcRTC Crypto Key"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.password = true;
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"olcrtc_socks_host",
|
||||
_("OlcRTC SOCKS Host"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.default = "127.0.0.1";
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"olcrtc_socks_port",
|
||||
_("OlcRTC SOCKS Port"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.default = "1082";
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.Value,
|
||||
"olcrtc_dns_server",
|
||||
_("OlcRTC DNS Server"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.default = "8.8.8.8:53";
|
||||
o.modalonly = true;
|
||||
|
||||
o = section.taboption(
|
||||
"settings",
|
||||
form.DynamicList,
|
||||
"olcrtc_subscription_links",
|
||||
_("OlcRTC Subscription Links"),
|
||||
);
|
||||
o.depends("action", "olcrtc");
|
||||
o.modalonly = true;
|
||||
|
||||
// ─── Hosts Import Helpers ──────────────────────────────────────────────
|
||||
|
||||
function parseHostsFile(text, options) {
|
||||
@@ -10333,6 +10606,8 @@ function createSectionContent(section) {
|
||||
o.depends("action", "connection");
|
||||
o.depends("action", "awg");
|
||||
o.depends("action", "byedpi");
|
||||
o.depends("action", "wdtt");
|
||||
o.depends("action", "olcrtc");
|
||||
o.depends("action", "zapret");
|
||||
o.depends("action", "zapret2");
|
||||
o.modalonly = true;
|
||||
@@ -10814,11 +11089,47 @@ function createSectionContent(section) {
|
||||
key: "excluded_ips",
|
||||
label: _("Excluded devices"),
|
||||
description: _(
|
||||
"Traffic from these IP addresses will never be routed through this section, even if other conditions match.",
|
||||
"Traffic from these IP addresses, CIDRs, or MAC addresses will never be routed through this section, even if other conditions match.",
|
||||
),
|
||||
});
|
||||
dependsOnRoutingAction(excludedIpsOption);
|
||||
|
||||
const routedDnsEnabledOption = section.taboption(
|
||||
"conditions",
|
||||
form.Flag,
|
||||
"routed_dns_enabled",
|
||||
_("Routed DNS"),
|
||||
_("Resolve matched domains through an encrypted DNS server of this section instead of FakeIP. DNS queries traverse the same proxy as the section's outbound."),
|
||||
);
|
||||
dependsOnRoutingAction(routedDnsEnabledOption);
|
||||
routedDnsEnabledOption.default = "0";
|
||||
routedDnsEnabledOption.rmempty = false;
|
||||
routedDnsEnabledOption.modalonly = true;
|
||||
|
||||
const routedDnsTypeOption = section.taboption(
|
||||
"conditions",
|
||||
form.ListValue,
|
||||
"routed_dns_type",
|
||||
_("Routed DNS Protocol"),
|
||||
_("Protocol for the routed DNS resolver."),
|
||||
);
|
||||
routedDnsTypeOption.depends({ routed_dns_enabled: "1" });
|
||||
routedDnsTypeOption.rmempty = false;
|
||||
routedDnsTypeOption.modalonly = true;
|
||||
routedDnsTypeOption.value("udp", "UDP");
|
||||
routedDnsTypeOption.value("dot", "DNS over TLS");
|
||||
routedDnsTypeOption.value("doh", "DNS over HTTPS");
|
||||
routedDnsTypeOption.value("doq", "DNS over QUIC");
|
||||
|
||||
const routedDnsServerOption = addDynamicConditionField(section, {
|
||||
key: "routed_dns_server",
|
||||
label: _("Routed DNS Servers"),
|
||||
description: _(
|
||||
"DNS server addresses for domain resolution in this section (e.g. 1.1.1.1, https://cloudflare-dns.com/dns-query).",
|
||||
),
|
||||
});
|
||||
routedDnsServerOption.depends({ routed_dns_enabled: "1" });
|
||||
|
||||
const portsOption = addDynamicConditionField(section, {
|
||||
key: "ports",
|
||||
label: _("Ports"),
|
||||
@@ -10914,6 +11225,8 @@ const ACTION_COLORS = {
|
||||
zapret: "#8e44ad",
|
||||
zapret2: "#9b59b6",
|
||||
byedpi: "#d35400",
|
||||
wdtt: "#27ae60",
|
||||
olcrtc: "#2980b9",
|
||||
awg: "#008080",
|
||||
warp: "#e67e22",
|
||||
anytls: "#16a085",
|
||||
|
||||
@@ -839,6 +839,81 @@ msgstr "Стратегия ByeDPI"
|
||||
msgid "ByeDPI strategy cannot be empty"
|
||||
msgstr "Стратегия ByeDPI не может быть пустой"
|
||||
|
||||
msgid "WDTT"
|
||||
msgstr "WDTT"
|
||||
|
||||
msgid "WDTT URI"
|
||||
msgstr "URI WDTT"
|
||||
|
||||
msgid "WDTT connection URI (wdtt://...)"
|
||||
msgstr "URI подключения WDTT (wdtt://...)"
|
||||
|
||||
msgid "WDTT Mode"
|
||||
msgstr "Режим WDTT"
|
||||
|
||||
msgid "WDTT Device ID"
|
||||
msgstr "ID устройства WDTT"
|
||||
|
||||
msgid "WDTT Workers"
|
||||
msgstr "Рабочие процессы WDTT"
|
||||
|
||||
msgid "WDTT Max Hashes"
|
||||
msgstr "Максимум хешей WDTT"
|
||||
|
||||
msgid "WDTT MTU"
|
||||
msgstr "MTU WDTT"
|
||||
|
||||
msgid "WDTT Refresh"
|
||||
msgstr "Обновление WDTT"
|
||||
|
||||
msgid "WDTT Auto Update"
|
||||
msgstr "Автообновление WDTT"
|
||||
|
||||
msgid "WDTT Block DoH"
|
||||
msgstr "Блокировка DoH в WDTT"
|
||||
|
||||
msgid "WDTT Block IPv6"
|
||||
msgstr "Блокировка IPv6 в WDTT"
|
||||
|
||||
msgid "WDTT QWDTT Mode"
|
||||
msgstr "Режим QWDTT"
|
||||
|
||||
msgid "WDTT Subscription Links"
|
||||
msgstr "Ссылки подписок WDTT"
|
||||
|
||||
msgid "WDTT Community Lists"
|
||||
msgstr "Списки сообществ WDTT"
|
||||
|
||||
msgid "WDTT Remote Domain List"
|
||||
msgstr "Удалённый список доменов WDTT"
|
||||
|
||||
msgid "OlcRTC"
|
||||
msgstr "OlcRTC"
|
||||
|
||||
msgid "OlcRTC Provider"
|
||||
msgstr "Провайдер OlcRTC"
|
||||
|
||||
msgid "OlcRTC Transport"
|
||||
msgstr "Транспорт OlcRTC"
|
||||
|
||||
msgid "OlcRTC Room ID"
|
||||
msgstr "ID комнаты OlcRTC"
|
||||
|
||||
msgid "OlcRTC Crypto Key"
|
||||
msgstr "Ключ шифрования OlcRTC"
|
||||
|
||||
msgid "OlcRTC SOCKS Host"
|
||||
msgstr "Хост SOCKS OlcRTC"
|
||||
|
||||
msgid "OlcRTC SOCKS Port"
|
||||
msgstr "Порт SOCKS OlcRTC"
|
||||
|
||||
msgid "OlcRTC DNS Server"
|
||||
msgstr "DNS-сервер OlcRTC"
|
||||
|
||||
msgid "OlcRTC Subscription Links"
|
||||
msgstr "Ссылки подписок OlcRTC"
|
||||
|
||||
msgid "Bypasses proxy (SO_MARK 0x08000000)"
|
||||
msgstr "В обход прокси (SO_MARK 0x08000000)"
|
||||
|
||||
@@ -1445,6 +1520,24 @@ msgstr "DNS через прокси"
|
||||
msgid "DNS through section"
|
||||
msgstr "DNS через секцию"
|
||||
|
||||
msgid "Routed DNS"
|
||||
msgstr "Маршрутизированный DNS"
|
||||
|
||||
msgid "Resolve matched domains through an encrypted DNS server of this section instead of FakeIP. DNS queries traverse the same proxy as the section's outbound."
|
||||
msgstr "Резолвить совпавшие домены через зашифрованный DNS-сервер этой секции вместо FakeIP. DNS-запросы проходят через тот же прокси, что и исходящий трафик секции."
|
||||
|
||||
msgid "Routed DNS Protocol"
|
||||
msgstr "Протокол маршрутизированного DNS"
|
||||
|
||||
msgid "Protocol for the routed DNS resolver."
|
||||
msgstr "Протокол для DNS-резолвера маршрутизации."
|
||||
|
||||
msgid "Routed DNS Servers"
|
||||
msgstr "Серверы маршрутизированного DNS"
|
||||
|
||||
msgid "DNS server addresses for domain resolution in this section (e.g. 1.1.1.1, https://cloudflare-dns.com/dns-query)."
|
||||
msgstr "Адреса DNS-серверов для резолвинга доменов в этой секции (напр. 1.1.1.1, https://cloudflare-dns.com/dns-query)."
|
||||
|
||||
msgid "DNS Turbo Cache"
|
||||
msgstr "Быстрый DNS-кэш"
|
||||
|
||||
@@ -5096,8 +5189,8 @@ msgstr "Трафик"
|
||||
msgid "Traffic for this level goes directly."
|
||||
msgstr "Трафик этого уровня идёт напрямую."
|
||||
|
||||
msgid "Traffic from these IP addresses will never be routed through this section, even if other conditions match."
|
||||
msgstr "Трафик от этих IP-адресов никогда не будет маршрутизирован через эту секцию, даже если другие условия совпадают."
|
||||
msgid "Traffic from these IP addresses, CIDRs, or MAC addresses will never be routed through this section, even if other conditions match."
|
||||
msgstr "Трафик от этих IP-адресов, CIDR или MAC-адресов никогда не будет маршрутизирован через эту секцию, даже если другие условия совпадают."
|
||||
|
||||
msgid "Traffic of specified protocols (e.g. BitTorrent, QUIC, STUN) will bypass this section."
|
||||
msgstr "Трафик указанных протоколов (например BitTorrent, QUIC, STUN) будет обходить эту секцию."
|
||||
|
||||
@@ -1329,6 +1329,81 @@ msgstr ""
|
||||
msgid "ByeDPI strategy cannot be empty"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT URI"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT connection URI (wdtt://...)"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Device ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Workers"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Max Hashes"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT MTU"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Refresh"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Auto Update"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Block DoH"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Block IPv6"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT QWDTT Mode"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Subscription Links"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Community Lists"
|
||||
msgstr ""
|
||||
|
||||
msgid "WDTT Remote Domain List"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC Provider"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC Transport"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC Room ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC Crypto Key"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC SOCKS Host"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC SOCKS Port"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC DNS Server"
|
||||
msgstr ""
|
||||
|
||||
msgid "OlcRTC Subscription Links"
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/main.js:14975
|
||||
#: src/tachyon/tabs/diagnostic/partials/renderLeakCheckModal.ts:170
|
||||
msgid "Bypasses proxy (SO_MARK 0x08000000)"
|
||||
@@ -2355,6 +2430,24 @@ msgstr ""
|
||||
msgid "DNS through section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Routed DNS"
|
||||
msgstr ""
|
||||
|
||||
msgid "Resolve matched domains through an encrypted DNS server of this section instead of FakeIP. DNS queries traverse the same proxy as the section's outbound."
|
||||
msgstr ""
|
||||
|
||||
msgid "Routed DNS Protocol"
|
||||
msgstr ""
|
||||
|
||||
msgid "Protocol for the routed DNS resolver."
|
||||
msgstr ""
|
||||
|
||||
msgid "Routed DNS Servers"
|
||||
msgstr ""
|
||||
|
||||
msgid "DNS server addresses for domain resolution in this section (e.g. 1.1.1.1, https://cloudflare-dns.com/dns-query)."
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/settings.js:1615
|
||||
msgid "DNS Turbo Cache"
|
||||
msgstr ""
|
||||
@@ -8155,7 +8248,7 @@ msgid "Traffic for this level goes directly."
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:10821
|
||||
msgid "Traffic from these IP addresses will never be routed through this section, even if other conditions match."
|
||||
msgid "Traffic from these IP addresses, CIDRs, or MAC addresses will never be routed through this section, even if other conditions match."
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js:10849
|
||||
|
||||
Reference in New Issue
Block a user