feat: DNS Turbo Cache - persistent FakeIP + startup domain prefetch
- singbox/dns_prefetch.uc: new module, resolves ~70 popular blocked domains after startup to warm sing-box FakeIP cache (sleep 10s, then nslookup each) - lifecycle.uc: DNS_PREFETCH_UC constant + module_background call in start_main - generator.uc: when dns_turbo_cache=1 use /etc/sing-box/cache.db (persistent) - settings.js (LuCI): Flag toggle for dns_turbo_cache in DNS settings block - renderAdvancedSettings.ts: DNS Turbo Cache section with toggle + save - tachyon.pot / tachyon.po / tachyon.ru.po: translations RU - constants.uc: bump 1.2.30 -> 1.2.31 - package.json: bump 1.2.30 -> 1.2.31
This commit is contained in:
@@ -3061,3 +3061,15 @@ msgstr "🇺🇸 Только США (United States)"
|
||||
|
||||
msgid "🇨🇳 CN Only (China)"
|
||||
msgstr "🇨🇳 Только Китай (China)"
|
||||
|
||||
msgid "DNS Turbo Cache"
|
||||
msgstr "Быстрый DNS-кэш"
|
||||
|
||||
msgid "Enable DNS Turbo Cache"
|
||||
msgstr "Включить быстрый DNS-кэш"
|
||||
|
||||
msgid "Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0u00a0ms."
|
||||
msgstr "Сохраняет FakeIP-кэш между перезагрузками и заранее резолвит популярные заблокированные домены при старте — задержка при первом визите 0u00a0мс."
|
||||
|
||||
msgid "Savingu2026"
|
||||
msgstr "Сохранениеu2026"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
{
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.2.30",
|
||||
"version": "1.2.31",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -13,6 +13,7 @@ interface AdvancedSettingsState {
|
||||
smartDetectSections: string[];
|
||||
allSectionNames: string[];
|
||||
deviceIpsPerSection: Record<string, string[]>;
|
||||
dnsTurboCache: boolean;
|
||||
saving: boolean;
|
||||
loaded: boolean;
|
||||
}
|
||||
@@ -24,6 +25,7 @@ let _state: AdvancedSettingsState = {
|
||||
smartDetectSections: [],
|
||||
allSectionNames: [],
|
||||
deviceIpsPerSection: {},
|
||||
dnsTurboCache: false,
|
||||
saving: false,
|
||||
loaded: false,
|
||||
};
|
||||
@@ -84,6 +86,7 @@ export async function loadAdvancedSettingsState() {
|
||||
smartDetectSections.length > 0 ? smartDetectSections : allSectionNames.slice(0, 1),
|
||||
allSectionNames,
|
||||
deviceIpsPerSection,
|
||||
dnsTurboCache: settingsSec?.dns_turbo_cache === '1',
|
||||
loaded: true,
|
||||
};
|
||||
rerender();
|
||||
@@ -163,6 +166,24 @@ async function saveDeviceIps(sectionName: string, ipsText: string) {
|
||||
rerender();
|
||||
}
|
||||
|
||||
async function saveDnsTurboCache(enabled: boolean) {
|
||||
_state = { ..._state, saving: true };
|
||||
rerender();
|
||||
try {
|
||||
await TachyonShellMethods.uciRunCommand([
|
||||
'set',
|
||||
`${TACHYON_UCI_PACKAGE}.settings.dns_turbo_cache=${enabled ? '1' : '0'}`,
|
||||
]);
|
||||
await TachyonShellMethods.uciRunCommand(['commit', TACHYON_UCI_PACKAGE]);
|
||||
_state = { ..._state, dnsTurboCache: enabled };
|
||||
showToast(_('DNS Turbo Cache saved'), 'success');
|
||||
} catch {
|
||||
showToast(_('Failed to save DNS Turbo Cache'), 'error');
|
||||
}
|
||||
_state = { ..._state, saving: false };
|
||||
rerender();
|
||||
}
|
||||
|
||||
function moveSectionUp(idx: number) {
|
||||
if (idx <= 0) return;
|
||||
const arr = [..._state.smartDetectSections];
|
||||
@@ -225,6 +246,34 @@ function renderWatchdogSection(state: AdvancedSettingsState) {
|
||||
]);
|
||||
}
|
||||
|
||||
function renderDnsTurboCacheSection(state: AdvancedSettingsState) {
|
||||
const { dnsTurboCache, saving } = state;
|
||||
|
||||
return E('div', { class: 'tachyon_adv__section' }, [
|
||||
E('div', { class: 'tachyon_adv__section-header' }, [
|
||||
E('span', { class: 'tachyon_adv__section-icon' }, '⚡'),
|
||||
E('h3', { class: 'tachyon_adv__section-title' }, _('DNS Turbo Cache')),
|
||||
]),
|
||||
E('p', { class: 'tachyon_adv__hint' }, _(
|
||||
'Keeps FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup so first-visit latency is 0\u00a0ms.',
|
||||
)),
|
||||
E('div', { class: 'tachyon_adv__row' }, [
|
||||
E('label', { class: 'tachyon_adv__toggle' }, [
|
||||
E('input', {
|
||||
type: 'checkbox',
|
||||
checked: dnsTurboCache,
|
||||
onchange: (e: Event) => {
|
||||
const enabled = (e.target as HTMLInputElement).checked;
|
||||
void saveDnsTurboCache(enabled);
|
||||
},
|
||||
}),
|
||||
E('span', {}, _('Enable DNS Turbo Cache')),
|
||||
]),
|
||||
]),
|
||||
saving ? E('span', { class: 'tachyon_adv__hint' }, _('Saving…')) : E('span', {}),
|
||||
]);
|
||||
}
|
||||
|
||||
function renderSmartDetectSection(state: AdvancedSettingsState) {
|
||||
const { smartDetectEnabled, smartDetectSections, allSectionNames, saving } = state;
|
||||
const unselected = allSectionNames.filter(s => !smartDetectSections.includes(s));
|
||||
@@ -375,6 +424,8 @@ function renderAdvancedSettingsBody(state: AdvancedSettingsState) {
|
||||
return E('div', { class: 'tachyon_adv__body' }, [
|
||||
renderWatchdogSection(state),
|
||||
E('hr', { class: 'tachyon_adv__divider' }),
|
||||
renderDnsTurboCacheSection(state),
|
||||
E('hr', { class: 'tachyon_adv__divider' }),
|
||||
renderSmartDetectSection(state),
|
||||
E('hr', { class: 'tachyon_adv__divider' }),
|
||||
renderDeviceRoutingSection(state),
|
||||
|
||||
@@ -966,6 +966,17 @@ function createSettingsContent(section, capabilities) {
|
||||
return true;
|
||||
};
|
||||
|
||||
o = section.option(
|
||||
form.Flag,
|
||||
"dns_turbo_cache",
|
||||
_("DNS Turbo Cache"),
|
||||
_(
|
||||
"Keeps the FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup, reducing first-visit latency to 0\u00a0ms.",
|
||||
),
|
||||
);
|
||||
o.default = "0";
|
||||
o.rmempty = false;
|
||||
|
||||
const dnsHostsOpt = section.option(
|
||||
form.TextValue,
|
||||
"dns_hosts",
|
||||
|
||||
@@ -3061,3 +3061,9 @@ msgstr "🇺🇸 Только США (United States)"
|
||||
|
||||
msgid "🇨🇳 CN Only (China)"
|
||||
msgstr "🇨🇳 Только Китай (China)"
|
||||
|
||||
msgid "DNS Turbo Cache"
|
||||
msgstr "u0411u044bu0441u0442u0440u044bu0439 DNS-u043au044du0448"
|
||||
|
||||
msgid "Keeps the FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup, reducing first-visit latency to 0u00a0ms."
|
||||
msgstr "u0421u043eu0445u0440u0430u043du044fu0435u0442 FakeIP-u043au044du0448 u043cu0435u0436u0434u0443 u043fu0435u0440u0435u0437u0430u0433u0440u0443u0437u043au0430u043cu0438 u0438 u0437u0430u0440u0430u043du0435u0435 u0440u0435u0437u043eu043bu0432u0438u0442 u043fu043eu043fu0443u043bu044fu0440u043du044bu0435 u0437u0430u0431u043bu043eu043au0438u0440u043eu0432u0430u043du043du044bu0435 u0434u043eu043cu0435u043du044b u043fu0440u0438 u0441u0442u0430u0440u0442u0435 u2014 u0437u0430u0434u0435u0440u0436u043au0430 u043fu0440u0438 u043fu0435u0440u0432u043eu043c u0432u0438u0437u0438u0442u0435 0u00a0u043cu0441."
|
||||
|
||||
@@ -4229,3 +4229,11 @@ msgstr ""
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/section.js
|
||||
msgid "🇨🇳 CN Only (China)"
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/settings.js
|
||||
msgid "DNS Turbo Cache"
|
||||
msgstr ""
|
||||
|
||||
#: ../luci-app-tachyon/htdocs/luci-static/resources/view/tachyon/settings.js
|
||||
msgid "Keeps the FakeIP cache persistent across reboots and pre-resolves popular blocked domains on startup, reducing first-visit latency to 0u00a0ms."
|
||||
msgstr ""
|
||||
|
||||
@@ -31,7 +31,7 @@ function detect_installed_version() {
|
||||
}
|
||||
}
|
||||
|
||||
return "1.2.30";
|
||||
return "1.2.31";
|
||||
}
|
||||
|
||||
function constants_map() {
|
||||
|
||||
@@ -112,6 +112,7 @@ const BYEDPI_UC = LIB_DIR + "/providers/byedpi/runtime.uc";
|
||||
const PACKAGES_UC = LIB_DIR + "/core/packages.uc";
|
||||
const WATCHDOG_UC = LIB_DIR + "/service/watchdog.uc";
|
||||
const TELEGRAM_UC = LIB_DIR + "/service/telegram.uc";
|
||||
const DNS_PREFETCH_UC = LIB_DIR + "/singbox/dns_prefetch.uc";
|
||||
|
||||
let start_subscription_update_lock_held = false;
|
||||
let subscription_caches_prepared = getenv("TACHYON_SUBSCRIPTION_CACHES_PREPARED") || "0";
|
||||
@@ -786,6 +787,7 @@ function start_main() {
|
||||
module_success(ZAPRET2_UC, [ "start-runtime" ]);
|
||||
|
||||
module_background(UPDATES_UC, [ "list-update" ]);
|
||||
module_background(DNS_PREFETCH_UC, [ "prefetch" ]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env ucode
|
||||
|
||||
// DNS Turbo Cache prefetch worker.
|
||||
// Resolves popular blocked domains through the local DNS (127.0.0.1) to
|
||||
// pre-populate the sing-box FakeIP cache so first-visit latency is 0 ms.
|
||||
|
||||
let common = require("core.common");
|
||||
let uci_core = require("core.uci");
|
||||
|
||||
const CONFIG_NAME = getenv("TACHYON_CONFIG_NAME") || "tachyon";
|
||||
|
||||
// Popular blocked domains – resolved once at startup to warm FakeIP cache.
|
||||
const PREFETCH_DOMAINS = [
|
||||
// Telegram
|
||||
"t.me", "telegram.org", "web.telegram.org", "desktop.telegram.org",
|
||||
// YouTube
|
||||
"youtube.com", "www.youtube.com", "youtu.be", "ytimg.com",
|
||||
"yt3.ggpht.com", "googlevideo.com", "youtubei.googleapis.com",
|
||||
// Instagram / Meta
|
||||
"instagram.com", "www.instagram.com", "cdninstagram.com",
|
||||
"facebook.com", "www.facebook.com", "static.xx.fbcdn.net",
|
||||
"messenger.com", "fbcdn.net",
|
||||
// Twitter / X
|
||||
"twitter.com", "x.com", "t.co", "twimg.com", "abs.twimg.com",
|
||||
// Discord
|
||||
"discord.com", "discordapp.com", "discord.gg", "cdn.discordapp.com",
|
||||
// Reddit
|
||||
"reddit.com", "www.reddit.com", "redd.it", "redditmedia.com",
|
||||
// GitHub
|
||||
"github.com", "api.github.com", "raw.githubusercontent.com",
|
||||
"objects.githubusercontent.com", "codeload.github.com",
|
||||
// Google
|
||||
"google.com", "www.google.com", "google.ru",
|
||||
"gmail.com", "mail.google.com", "drive.google.com",
|
||||
"docs.google.com", "meet.google.com",
|
||||
// Netflix
|
||||
"netflix.com", "www.netflix.com", "nflxvideo.net", "nflximg.net",
|
||||
// Spotify
|
||||
"spotify.com", "open.spotify.com", "scdn.co",
|
||||
// TikTok
|
||||
"tiktok.com", "www.tiktok.com", "tiktokcdn.com", "tiktokcdn-us.com",
|
||||
// Twitch
|
||||
"twitch.tv", "www.twitch.tv", "static-cdn.jtvnw.net",
|
||||
// Wikipedia
|
||||
"wikipedia.org", "ru.wikipedia.org", "en.wikipedia.org",
|
||||
// Gaming
|
||||
"steampowered.com", "store.steampowered.com", "steamcommunity.com",
|
||||
"steamcdn.com", "epicgames.com",
|
||||
// Messaging
|
||||
"whatsapp.com", "www.whatsapp.com", "signal.org",
|
||||
// LinkedIn
|
||||
"linkedin.com", "www.linkedin.com",
|
||||
// News
|
||||
"bbc.com", "bbc.co.uk", "reuters.com",
|
||||
// Privacy / ProtonMail
|
||||
"proton.me", "protonmail.com",
|
||||
// Medium / Substack
|
||||
"medium.com", "substack.com",
|
||||
// Pinterest / Snapchat
|
||||
"pinterest.com", "snapchat.com",
|
||||
];
|
||||
|
||||
function prefetch() {
|
||||
let settings = common.object_or_empty(uci_core.get_all(CONFIG_NAME, "settings"));
|
||||
if (!common.bool_option(settings, "dns_turbo_cache", true))
|
||||
return;
|
||||
|
||||
// Give sing-box time to fully initialize before issuing queries.
|
||||
common.command_success_from_args([ "sleep", "10" ]);
|
||||
|
||||
for (let domain in PREFETCH_DOMAINS)
|
||||
common.command_success_from_args([ "nslookup", domain, "127.0.0.1" ]);
|
||||
}
|
||||
|
||||
let mode = ARGV[0];
|
||||
if (mode == "prefetch")
|
||||
prefetch();
|
||||
@@ -388,7 +388,8 @@ function tproxy_inbound_matcher() {
|
||||
function base_config(settings, service_address, runtime_context) {
|
||||
let log_level = option(settings, "log_level", "warn");
|
||||
let rewrite_ttl = int_option(settings, "dns_rewrite_ttl", "60");
|
||||
let cache_path = option(settings, "cache_path", "/tmp/sing-box/cache.db");
|
||||
let turbo_cache = bool_option(settings, "dns_turbo_cache", false);
|
||||
let cache_path = option(settings, "cache_path", turbo_cache ? "/etc/sing-box/cache.db" : "/tmp/sing-box/cache.db");
|
||||
let dns_config = runtime_dns.config(settings);
|
||||
if (dns_config.unsupported)
|
||||
runtime_generate_unsupported(dns_config.unsupported);
|
||||
|
||||
Reference in New Issue
Block a user