feat(tailscale): нативный режим tailscaled и компонент Tailscale

- новый компонент Tailscale: установка пакета из фида, карточка в Обновлениях
- режим native для секций Tailscale: системный tailscaled вместо sing-box endpoint
- доступ к тейлнету с LAN без клиента: маршруты 100.64.0.0/10 и MagicDNS через dnsmasq
- masquerade и exit-node (opt-in) с обходом tproxy по зарезервированной маске
- validator: требование tailscaled и auth-key для native; bypass-правила в mangle
- тесты: генерация конфига, смоук рантайма с моками, обновлена сигнатура состояния
This commit is contained in:
Dushnilin
2026-08-26 11:30:52 +03:00
parent 3532fa4280
commit 7f0b085a07
27 changed files with 1138 additions and 22 deletions
+7 -1
View File
@@ -119,6 +119,7 @@ const DIAGNOSTICS_UC = LIB_DIR + "/diagnostics/runtime.uc";
const ZAPRET_UC = LIB_DIR + "/providers/zapret/runtime.uc";
const ZAPRET2_UC = LIB_DIR + "/providers/zapret2/runtime.uc";
const BYEDPI_UC = LIB_DIR + "/providers/byedpi/runtime.uc";
const TAILSCALE_UC = LIB_DIR + "/providers/tailscale/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";
@@ -891,6 +892,8 @@ function stop_main() {
log_message("Zapret2 stop failed (non-fatal)", "warn");
if (!module_success(BYEDPI_UC, [ "stop-runtime" ]))
log_message("ByeDPI stop failed (non-fatal)", "warn");
if (!module_success(TAILSCALE_UC, [ "stop-runtime" ]))
log_message("Tailscale stop failed (non-fatal)", "warn");
if (command_success_from_args([ "nft", "list", "table", "inet", NFT_TABLE_NAME ])) {
if (!command_success_from_args([ "nft", "delete", "table", "inet", NFT_TABLE_NAME ]))
@@ -1370,7 +1373,10 @@ function reload(reason) {
if (plan.needs_zapret2_restart == 1)
module_success(ZAPRET2_UC, [ "start-runtime" ]);
if (plan.needs_byedpi_restart == 1)
module_success(BYEDPI_UC, [ "start-runtime" ]);
module_success(BYEDPI_UC, [ "start-runtime" ]);
// Native Tailscale must be up before sing-box so tailnet routes win over
// policy routing from the very first packet.
module_success(TAILSCALE_UC, [ "start-runtime" ]);
if (plan.needs_dnsmasq_configure == 1) {
status = dnsmasq_configure(true);
+3
View File
@@ -1492,6 +1492,9 @@ function append_sing_box_server_signature_body(body, server) {
[ "tailscale_auth_key", "" ],
[ "tailscale_control_url", "" ],
[ "tailscale_hostname", "" ],
[ "tailscale_mode", "singbox" ],
[ "tailscale_masquerade", "1" ],
[ "tailscale_use_exit_node", "0" ],
[ "tailscale_accept_routes", "" ],
[ "tailscale_advertise_routes", "" ],
[ "tailscale_advertise_exit_node", "" ]