From 787350eefb8180a557ea962c5cc6f75fd1b84bd3 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Mon, 24 Aug 2026 17:30:25 +0800 Subject: [PATCH] feat: make the TCP punch a user option, with TCP as the backstop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCP punching was the one direct transport without a switch, while UDP, IPv6 and WebRTC each had one. Add "Enable TCP hole punching" above the UDP toggle on both desktop and mobile, default on — including on self-hosted servers, since unlike the other three (whose default-off there guards against an hbbs that cannot forward their fields) TCP punching has always been supported by every server. Turning all four off would leave no way to punch at all, so TCP runs regardless in that case. That backstop keys off the switches alone: a transport that is enabled but fails to materialize — no public v6 address, no NAT port, a failed offerer — is already covered by the relay fallback for a round that ends up with no usable direct transport. With the TCP punch off, the fallback request is skipped too: it exists only to carry that punch, and would otherwise reach connect() with nothing to try and merely open a second relay. Known cost, unchanged behavior for the peer: the request carries no field for this choice, so a peer that receives one with no udp_port and no offer still punches a TCP hole and listens for a connection the controller will not make. Representing the transport choice on the wire needs a proto field and the server forwarding it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_016HV43uh1ztv6Wm5qi3Y1ne --- flutter/lib/consts.dart | 1 + .../desktop/pages/desktop_setting_page.dart | 6 ++ flutter/lib/mobile/pages/settings_page.dart | 70 +++++++++++++------ libs/hbb_common | 2 +- src/client.rs | 22 +++++- src/common.rs | 7 ++ src/lang/ar.rs | 1 + src/lang/be.rs | 1 + src/lang/bg.rs | 1 + src/lang/ca.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/el.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/et.rs | 1 + src/lang/eu.rs | 1 + src/lang/fa.rs | 1 + src/lang/fi.rs | 1 + src/lang/fr.rs | 1 + src/lang/ge.rs | 1 + src/lang/gu.rs | 1 + src/lang/he.rs | 1 + src/lang/hi.rs | 1 + src/lang/hr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 1 + src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/lt.rs | 1 + src/lang/lv.rs | 1 + src/lang/ml.rs | 1 + src/lang/nb.rs | 1 + src/lang/nl.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ro.rs | 1 + src/lang/ru.rs | 1 + src/lang/sc.rs | 1 + src/lang/sk.rs | 1 + src/lang/sl.rs | 1 + src/lang/sq.rs | 1 + src/lang/sr.rs | 1 + src/lang/sv.rs | 1 + src/lang/ta.rs | 1 + src/lang/template.rs | 1 + src/lang/th.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/uk.rs | 1 + src/lang/vi.rs | 1 + 56 files changed, 132 insertions(+), 26 deletions(-) diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index fd1b59190..c63100bae 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -166,6 +166,7 @@ const String kOptionAllowRemoveWallpaper = "allow-remove-wallpaper"; const String kOptionStopService = "stop-service"; const String kOptionDirectxCapture = "enable-directx-capture"; const String kOptionAllowRemoteCmModification = "allow-remote-cm-modification"; +const String kOptionEnableTcpPunch = "enable-tcp-punch"; const String kOptionEnableUdpPunch = "enable-udp-punch"; const String kOptionEnableIpv6Punch = "enable-ipv6-punch"; const String kOptionEnableWebrtc = "enable-webrtc"; diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 915ba1993..57f7f6ff4 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -563,6 +563,12 @@ class _GeneralState extends State<_General> { kOptionDirectxCapture, ), if (!isWeb && !incomingOnly) ...[ + _OptionCheckBox( + context, + 'Enable TCP hole punching', + kOptionEnableTcpPunch, + isServer: false, + ), _OptionCheckBox( context, 'Enable UDP hole punching', diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart index d42818637..e630d161e 100644 --- a/flutter/lib/mobile/pages/settings_page.dart +++ b/flutter/lib/mobile/pages/settings_page.dart @@ -97,6 +97,7 @@ class _SettingsState extends State with WidgetsBindingObserver { var _hideNetwork = false; var _hideWebSocket = false; var _enableTrustedDevices = false; + var _enableTcpPunch = false; var _enableUdpPunch = false; var _allowInsecureTlsFallback = false; var _disableUdp = false; @@ -142,6 +143,7 @@ class _SettingsState extends State with WidgetsBindingObserver { bind.mainGetBuildinOption(key: kOptionHideWebSocketSetting) == 'Y' || isWeb; _enableTrustedDevices = mainGetBoolOptionSync(kOptionEnableTrustedDevices); + _enableTcpPunch = mainGetLocalBoolOptionSync(kOptionEnableTcpPunch); _enableUdpPunch = mainGetLocalBoolOptionSync(kOptionEnableUdpPunch); _enableIpv6Punch = mainGetLocalBoolOptionSync(kOptionEnableIpv6Punch); _enableWebrtc = mainGetLocalBoolOptionSync(kOptionEnableWebrtc); @@ -817,43 +819,65 @@ class _SettingsState extends State with WidgetsBindingObserver { }); }, ), + if (!incomingOnly) + SettingsTile.switchTile( + title: Text(translate('Enable TCP hole punching')), + initialValue: _enableTcpPunch, + onToggle: isOptionFixed(kOptionEnableTcpPunch) + ? null + : (v) async { + await mainSetLocalBoolOption(kOptionEnableTcpPunch, v); + final newValue = + mainGetLocalBoolOptionSync(kOptionEnableTcpPunch); + setState(() { + _enableTcpPunch = newValue; + }); + }, + ), if (!incomingOnly) SettingsTile.switchTile( title: Text(translate('Enable UDP hole punching')), initialValue: _enableUdpPunch, - onToggle: (v) async { - await mainSetLocalBoolOption(kOptionEnableUdpPunch, v); - final newValue = - mainGetLocalBoolOptionSync(kOptionEnableUdpPunch); - setState(() { - _enableUdpPunch = newValue; - }); - }, + onToggle: isOptionFixed(kOptionEnableUdpPunch) + ? null + : (v) async { + await mainSetLocalBoolOption(kOptionEnableUdpPunch, v); + final newValue = + mainGetLocalBoolOptionSync(kOptionEnableUdpPunch); + setState(() { + _enableUdpPunch = newValue; + }); + }, ), if (!incomingOnly) SettingsTile.switchTile( title: Text(translate('Enable IPv6 P2P connection')), initialValue: _enableIpv6Punch, - onToggle: (v) async { - await mainSetLocalBoolOption(kOptionEnableIpv6Punch, v); - final newValue = - mainGetLocalBoolOptionSync(kOptionEnableIpv6Punch); - setState(() { - _enableIpv6Punch = newValue; - }); - }, + onToggle: isOptionFixed(kOptionEnableIpv6Punch) + ? null + : (v) async { + await mainSetLocalBoolOption(kOptionEnableIpv6Punch, v); + final newValue = + mainGetLocalBoolOptionSync(kOptionEnableIpv6Punch); + setState(() { + _enableIpv6Punch = newValue; + }); + }, ), if (!incomingOnly) SettingsTile.switchTile( title: Text(translate('Enable WebRTC P2P connection')), initialValue: _enableWebrtc, - onToggle: (v) async { - await mainSetLocalBoolOption(kOptionEnableWebrtc, v); - final newValue = mainGetLocalBoolOptionSync(kOptionEnableWebrtc); - setState(() { - _enableWebrtc = newValue; - }); - }, + onToggle: isOptionFixed(kOptionEnableWebrtc) + ? null + : (v) async { + await mainSetLocalBoolOption(kOptionEnableWebrtc, v); + final newValue = + mainGetLocalBoolOptionSync(kOptionEnableWebrtc); + setState(() { + _enableWebrtc = newValue; + }); + }, ), SettingsTile( title: Text(translate('Language')), diff --git a/libs/hbb_common b/libs/hbb_common index 01ee2f46e..db7723efa 160000 --- a/libs/hbb_common +++ b/libs/hbb_common @@ -1 +1 @@ -Subproject commit 01ee2f46ece493110510b8d8b5ca019488f33f7a +Subproject commit db7723efa1021fcba6fb78e23799242d5dd1f804 diff --git a/src/client.rs b/src/client.rs index bd0c82a36..53d64ac1a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -334,6 +334,18 @@ fn request_allows_tcp_punch(webrtc_sdp_offer: &str) -> bool { webrtc_sdp_offer.is_empty() } +/// TCP punch is a user option like the other direct transports, but it is also the backstop: +/// with every direct transport switched off there would be nothing left to punch with, so it +/// runs regardless. Only the switches decide that — a transport that is enabled but fails to +/// materialize (no public v6 address, offerer setup error) leaves this alone, because the +/// relay fallback already covers a round that ends up with no usable direct transport. +fn tcp_punch_allowed() -> bool { + crate::get_tcp_punch_enabled() + || !(crate::get_udp_punch_enabled() + || crate::get_ipv6_punch_enabled() + || crate::get_webrtc_enabled()) +} + impl Client { const CLIENT_CLIPBOARD_NAME: &'static str = "client-clipboard"; @@ -521,7 +533,13 @@ impl Client { servers.clone(), contained, ); - if interface.is_force_relay() || (udp.0.is_none() && !has_webrtc_offerer) { + // The fallback request exists only to carry a TCP punch, so it is pointless once TCP + // punch is off — it would reach `connect()` with nothing to try and just open a second + // relay. + if interface.is_force_relay() + || (udp.0.is_none() && !has_webrtc_offerer) + || !tcp_punch_allowed() + { return fut.await; } let preferred_fut = fut.boxed(); @@ -849,7 +867,7 @@ impl Client { } else { String::new() }; - let allow_tcp_punch = request_allows_tcp_punch(&webrtc_sdp_offer); + let allow_tcp_punch = tcp_punch_allowed() && request_allows_tcp_punch(&webrtc_sdp_offer); let punch_type = if udp_nat_port > 0 { "UDP" } else if allow_tcp_punch { diff --git a/src/common.rs b/src/common.rs index 4024c835f..4bc37c1d3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1098,6 +1098,13 @@ pub fn is_public(url: &str) -> bool { host == "rustdesk.com" || host.ends_with(".rustdesk.com") } +pub fn get_tcp_punch_enabled() -> bool { + config::option2bool( + keys::OPTION_ENABLE_TCP_PUNCH, + &get_local_option(keys::OPTION_ENABLE_TCP_PUNCH), + ) +} + pub fn get_udp_punch_enabled() -> bool { config::option2bool( keys::OPTION_ENABLE_UDP_PUNCH, diff --git a/src/lang/ar.rs b/src/lang/ar.rs index 742124ee9..3729c29e1 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "لم يفتح المتصفح؟ استخدم الرابط أدناه لتسجيل الدخول."), ("Lock canvas", "قفل اللوحة"), ("Enable WebRTC P2P connection", "تمكين اتصال نظير إلى نظير عبر WebRTC"), + ("Enable TCP hole punching", "تمكين تقنية حفر الثغرات عبر TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/be.rs b/src/lang/be.rs index 2d49048d2..01ef4c872 100644 --- a/src/lang/be.rs +++ b/src/lang/be.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Браўзер не адкрыўся? Скарыстайцеся спасылкай ніжэй, каб увайсці."), ("Lock canvas", "Заблакіраваць палатно"), ("Enable WebRTC P2P connection", "Выкарыстоўваць падключэнне WebRTC P2P"), + ("Enable TCP hole punching", "Выкарыстоўваць TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/bg.rs b/src/lang/bg.rs index 683c4b250..760790c95 100644 --- a/src/lang/bg.rs +++ b/src/lang/bg.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Браузърът не се отвори? Използвайте URL адреса по-долу, за да се впишете."), ("Lock canvas", "Заключване на платното"), ("Enable WebRTC P2P connection", "Позволяване на WebRTC P2P връзка"), + ("Enable TCP hole punching", "Позволяване на TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 18acedbb7..734197826 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "No s'ha obert el navegador? Utilitzeu l'URL de sota per iniciar la sessió."), ("Lock canvas", "Bloca el llenç"), ("Enable WebRTC P2P connection", "Habilita la connexió WebRTC P2P"), + ("Enable TCP hole punching", "Activa la perforació TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index b68f960df..fd4d7d9cb 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "浏览器未打开?请使用下方网址登录。"), ("Lock canvas", "锁定画布"), ("Enable WebRTC P2P connection", "启用 WebRTC P2P 连接"), + ("Enable TCP hole punching", "启用 TCP 打洞"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index e1314cb60..0c7602b82 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Neotevřel se prohlížeč? Pro přihlášení použijte URL níže."), ("Lock canvas", "Zamknout zobrazení"), ("Enable WebRTC P2P connection", "Povolit připojení WebRTC P2P"), + ("Enable TCP hole punching", "Povolit TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index f756ac27c..49f41fe57 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Åbnede browseren ikke? Brug URL'en nedenfor til at logge ind."), ("Lock canvas", "Lås lærred"), ("Enable WebRTC P2P connection", "Aktivér WebRTC P2P-forbindelse"), + ("Enable TCP hole punching", "Aktivér TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 10315cf5b..1459a850e 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Hat sich der Browser nicht geöffnet? Melden Sie sich über die untenstehende URL an."), ("Lock canvas", "Sichtfeld sperren"), ("Enable WebRTC P2P connection", "WebRTC-P2P-Verbindung aktivieren"), + ("Enable TCP hole punching", "TCP-Hole-Punching aktivieren"), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index db0e390d2..2ad772b26 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Δεν άνοιξε το πρόγραμμα περιήγησης; Χρησιμοποιήστε τον παρακάτω σύνδεσμο για να συνδεθείτε."), ("Lock canvas", "Κλείδωμα καμβά"), ("Enable WebRTC P2P connection", "Ενεργοποίηση σύνδεσης WebRTC P2P"), + ("Enable TCP hole punching", "Ενεργοποίηση διάτρησης οπών TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 009227b3e..a9c41223f 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Ĉu la retumilo ne malfermiĝis? Uzu la suban ligilon por ensaluti."), ("Lock canvas", "Ŝlosi kanvason"), ("Enable WebRTC P2P connection", "Ebligi WebRTC P2P-konekton"), + ("Enable TCP hole punching", "Ebligi TCP-trapikadon"), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 2da839310..03cea92e2 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "¿No se abrió el navegador? Usa la URL de abajo para iniciar sesión."), ("Lock canvas", "Bloquear lienzo"), ("Enable WebRTC P2P connection", "Habilitar conexión WebRTC P2P"), + ("Enable TCP hole punching", "Habilitar perforación de agujero TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/et.rs b/src/lang/et.rs index 2c7b1d4ac..7499099ac 100644 --- a/src/lang/et.rs +++ b/src/lang/et.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Brauser ei avanenud? Sisselogimiseks kasuta allolevat URL-i."), ("Lock canvas", "Lukusta lõuend"), ("Enable WebRTC P2P connection", "Luba WebRTC P2P-ühendus"), + ("Enable TCP hole punching", "Luba TCP-augustamine"), ].iter().cloned().collect(); } diff --git a/src/lang/eu.rs b/src/lang/eu.rs index 479592353..4310c2a50 100644 --- a/src/lang/eu.rs +++ b/src/lang/eu.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Nabigatzailea ez da ireki? Erabili beheko URLa saioa hasteko."), ("Lock canvas", "Blokeatu oihala"), ("Enable WebRTC P2P connection", "Gaitu WebRTC P2P konexioa"), + ("Enable TCP hole punching", "Gaitu TCP zulo-egitea"), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index ec1a946f3..5ce2ea9f5 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "مرورگر باز نشد؟ برای ورود از نشانی زیر استفاده کنید."), ("Lock canvas", "قفل کردن صفحه"), ("Enable WebRTC P2P connection", "فعال‌سازی اتصال همتا‌به‌همتای WebRTC"), + ("Enable TCP hole punching", "فعال‌سازی تکنیک TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/fi.rs b/src/lang/fi.rs index 880aa0201..12730b2c7 100644 --- a/src/lang/fi.rs +++ b/src/lang/fi.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Eikö selain avautunut? Kirjaudu sisään alla olevan osoitteen kautta."), ("Lock canvas", "Lukitse näkymä"), ("Enable WebRTC P2P connection", "Ota WebRTC P2P yhteys käyttöön"), + ("Enable TCP hole punching", "Ota käyttöön TCP hole punching tekniikka"), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index fa8efcb42..a77ceb3e0 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Le navigateur ne s’est pas ouvert ? Utilisez l’URL ci-dessous pour vous connecter."), ("Lock canvas", "Verrouiller la vue"), ("Enable WebRTC P2P connection", "Activer la connexion P2P WebRTC"), + ("Enable TCP hole punching", "Activer le « hole punching » TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/ge.rs b/src/lang/ge.rs index e644eb363..8cc220702 100644 --- a/src/lang/ge.rs +++ b/src/lang/ge.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "ბრაუზერი არ გაიხსნა? შესასვლელად გამოიყენეთ ქვემოთ მოცემული ბმული."), ("Lock canvas", "ტილოს დაბლოკვა"), ("Enable WebRTC P2P connection", "WebRTC P2P კავშირის ჩართვა"), + ("Enable TCP hole punching", "TCP hole punching-ის ჩართვა"), ].iter().cloned().collect(); } diff --git a/src/lang/gu.rs b/src/lang/gu.rs index ee2001725..5752d2ee1 100644 --- a/src/lang/gu.rs +++ b/src/lang/gu.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "બ્રાઉઝર ખૂલ્યું નથી? લોગિન કરવા માટે નીચે આપેલ URL નો ઉપયોગ કરો."), ("Lock canvas", "કેનવાસ લોક કરો"), ("Enable WebRTC P2P connection", "WebRTC P2P કનેક્શન સક્ષમ કરો"), + ("Enable TCP hole punching", "TCP હોલ પંચિંગ સક્ષમ કરો"), ].iter().cloned().collect(); } diff --git a/src/lang/he.rs b/src/lang/he.rs index 22d184dfc..dc5827b90 100644 --- a/src/lang/he.rs +++ b/src/lang/he.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "הדפדפן לא נפתח? השתמש בכתובת שלמטה כדי להתחבר."), ("Lock canvas", "נעל לוח ציור"), ("Enable WebRTC P2P connection", "אפשר חיבור WebRTC P2P"), + ("Enable TCP hole punching", "אפשר TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/hi.rs b/src/lang/hi.rs index 75077849e..528f12ab6 100644 --- a/src/lang/hi.rs +++ b/src/lang/hi.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "ब्राउज़र नहीं खुला? लॉगिन करने के लिए नीचे दिए गए URL का उपयोग करें।"), ("Lock canvas", "कैनवास लॉक करें"), ("Enable WebRTC P2P connection", "WebRTC P2P कनेक्शन सक्षम करें"), + ("Enable TCP hole punching", "TCP होल पंचिंग सक्षम करें"), ].iter().cloned().collect(); } diff --git a/src/lang/hr.rs b/src/lang/hr.rs index b9d9fed49..d178dcebf 100644 --- a/src/lang/hr.rs +++ b/src/lang/hr.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Preglednik se nije otvorio? Za prijavu upotrijebite URL u nastavku."), ("Lock canvas", "Zaključaj pozadinu"), ("Enable WebRTC P2P connection", "Omogući WebRTC P2P vezu"), + ("Enable TCP hole punching", "Omogući TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 4072aaded..bf6e76925 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Nem nyílt meg a böngésző? A belépéshez használja az alábbi URL-címet."), ("Lock canvas", "Nézet zárolása"), ("Enable WebRTC P2P connection", "WebRTC P2P kapcsolat engedélyezése"), + ("Enable TCP hole punching", "TCP résszűrés engedélyezése"), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 8da15ef24..bc5a219bd 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Browser tidak terbuka? Gunakan URL di bawah ini untuk masuk."), ("Lock canvas", "Kunci kanvas"), ("Enable WebRTC P2P connection", "Aktifkan koneksi P2P WebRTC"), + ("Enable TCP hole punching", "Aktifkan TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 555d432e0..18adaf7ae 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Il browser non si è aperto? Usa l'URL qui sotto per accedere."), ("Lock canvas", "Blocca tela"), ("Enable WebRTC P2P connection", "Abilita connessione P2P WebRTC"), + ("Enable TCP hole punching", "Abilita hole punching TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index cb20f3483..8aba71753 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "ブラウザが開きませんでしたか?下記の URL からログインしてください。"), ("Lock canvas", "キャンバスをロック"), ("Enable WebRTC P2P connection", "WebRTC P2P 接続を有効化する"), + ("Enable TCP hole punching", "TCP ホールパンチを有効化する"), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index d41b9ae1d..7f7e9b33b 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "브라우저가 열리지 않았나요? 아래 URL로 로그인하세요."), ("Lock canvas", "캔버스 잠금"), ("Enable WebRTC P2P connection", "WebRTC P2P 연결 사용"), + ("Enable TCP hole punching", "TCP 홀 펀칭 사용"), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index e6643e653..6d73b59bc 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Браузер ашылмады ма? Кіру үшін төмендегі сілтемені пайдаланыңыз."), ("Lock canvas", "Кенепті құлыптау"), ("Enable WebRTC P2P connection", "WebRTC P2P қосылымын іске қосу"), + ("Enable TCP hole punching", "TCP hole punching'ті іске қосу"), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 20ca418f2..ebe131670 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Naršyklė neatsidarė? Prisijunkite naudodami toliau pateiktą URL."), ("Lock canvas", "Užrakinti drobę"), ("Enable WebRTC P2P connection", "Įgalinti WebRTC P2P ryšį"), + ("Enable TCP hole punching", "Įgalinti TCP gręžimą (hole punching)"), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 3c773c8c0..55b12d8f9 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Pārlūkprogramma neatvērās? Izmantojiet tālāk norādīto URL, lai pieslēgtos."), ("Lock canvas", "Bloķēt audeklu"), ("Enable WebRTC P2P connection", "Iespējot WebRTC P2P savienojumu"), + ("Enable TCP hole punching", "Iespējot TCP caurumu veidošanu"), ].iter().cloned().collect(); } diff --git a/src/lang/ml.rs b/src/lang/ml.rs index 1fc05a20e..34dcd00a3 100644 --- a/src/lang/ml.rs +++ b/src/lang/ml.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "ബ്രൗസർ തുറന്നില്ലേ? ലോഗിൻ ചെയ്യാൻ താഴെയുള്ള URL ഉപയോഗിക്കുക."), ("Lock canvas", "ക്യാൻവാസ് ലോക്ക് ചെയ്യുക"), ("Enable WebRTC P2P connection", "WebRTC P2P കണക്ഷൻ അനുവദിക്കുക"), + ("Enable TCP hole punching", "TCP ഹോൾ പഞ്ചിംഗ് അനുവദിക്കുക"), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index af862b12d..2793b151c 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Åpnet ikke nettleseren? Bruk URL-en nedenfor for å logge inn."), ("Lock canvas", "Lås lerret"), ("Enable WebRTC P2P connection", "Aktiver WebRTC P2P-tilkobling"), + ("Enable TCP hole punching", "Aktiver TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 013e08912..80f038cfd 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Is de browser niet geopend? Gebruik onderstaande URL om in te loggen."), ("Lock canvas", "Canvas vergrendelen"), ("Enable WebRTC P2P connection", "WebRTC P2P-verbinding inschakelen"), + ("Enable TCP hole punching", "TCP-hole punching inschakelen"), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index da0826a88..4c1a2f526 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Przeglądarka się nie otworzyła? Użyj poniższego adresu URL, aby się zalogować."), ("Lock canvas", "Zablokuj ekran"), ("Enable WebRTC P2P connection", "Włącz połączenie P2P WebRTC"), + ("Enable TCP hole punching", "Włącz tworzenie tunelu TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index d687d6676..412f61235 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "O navegador não abriu? Utilize o URL abaixo para iniciar sessão."), ("Lock canvas", "Bloquear tela"), ("Enable WebRTC P2P connection", "Ativar ligação P2P por WebRTC"), + ("Enable TCP hole punching", "Ativar TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index da4fdaae3..d13ebac3a 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "O navegador não foi aberto? Use a URL abaixo para fazer login."), ("Lock canvas", "Bloquear tela"), ("Enable WebRTC P2P connection", "Habilitar conexão WebRTC P2P"), + ("Enable TCP hole punching", "Habilitar TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 76dafbaa3..aa4bf0db6 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Browserul nu s-a deschis? Folosește URL-ul de mai jos pentru a te conecta."), ("Lock canvas", "Blochează ecranul"), ("Enable WebRTC P2P connection", "Activează conexiunea P2P prin WebRTC"), + ("Enable TCP hole punching", "Activează traversarea TCP (hole punching)"), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 8bbb5aaf4..d944312b4 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Браузер не открылся? Используйте ссылку ниже для входа."), ("Lock canvas", "Заблокировать холст"), ("Enable WebRTC P2P connection", "Использовать подключение WebRTC P2P"), + ("Enable TCP hole punching", "Использовать TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/sc.rs b/src/lang/sc.rs index 0df3f5e64..844913e0f 100644 --- a/src/lang/sc.rs +++ b/src/lang/sc.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Non s'est abertu su navigadore? Imprea s'URL inoghe in suta pro intrare."), ("Lock canvas", "Bloca sa tela"), ("Enable WebRTC P2P connection", "Abìlita connessione P2P WebRTC"), + ("Enable TCP hole punching", "Abìlita s'istampadura TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 4e32aacc5..e8782843e 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Neotvoril sa prehliadač? Na prihlásenie použite URL nižšie."), ("Lock canvas", "Uzamknúť zobrazenie"), ("Enable WebRTC P2P connection", "Povoliť pripojenie WebRTC P2P"), + ("Enable TCP hole punching", "Povoliť TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 8e034775c..ab425c835 100644 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Brskalnik se ni odprl? Za prijavo uporabite spodnji URL."), ("Lock canvas", "Zakleni platno"), ("Enable WebRTC P2P connection", "Omogoči povezavo WebRTC P2P"), + ("Enable TCP hole punching", "Omogoči preboj lukenj TCP"), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index f428d7d72..5b6774bca 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Shfletuesi nuk u hap? Përdorni URL-në më poshtë për të hyrë."), ("Lock canvas", "Kyç canvas"), ("Enable WebRTC P2P connection", "Aktivizo lidhjen WebRTC P2P"), + ("Enable TCP hole punching", "Aktivizo TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index d14281c18..564d87c75 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Pregledač se nije otvorio? Za prijavu koristite URL ispod."), ("Lock canvas", "Zaključaj pozadinu"), ("Enable WebRTC P2P connection", "Omogući WebRTC P2P konekciju"), + ("Enable TCP hole punching", "Omogući TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index ebb7a310b..b2e8e7ca9 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Öppnades inte webbläsaren? Använd URL:en nedan för att logga in."), ("Lock canvas", "Lås canvas"), ("Enable WebRTC P2P connection", "Aktivera WebRTC P2P anslutning"), + ("Enable TCP hole punching", "Aktivera TCP hålslagning"), ].iter().cloned().collect(); } diff --git a/src/lang/ta.rs b/src/lang/ta.rs index 1914aa6ab..90584b280 100644 --- a/src/lang/ta.rs +++ b/src/lang/ta.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "உலாவி திறக்கவில்லையா? உள்நுழைய கீழே உள்ள URL ஐப் பயன்படுத்தவும்."), ("Lock canvas", "கேன்வாஸைப் பூட்டு"), ("Enable WebRTC P2P connection", "WebRTC P2P இணைப்பு இயக்கு"), + ("Enable TCP hole punching", "TCP hole punching இயக்கு"), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 27fa1ee21..1786ba3fe 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", ""), ("Lock canvas", ""), ("Enable WebRTC P2P connection", ""), + ("Enable TCP hole punching", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 8802b6fbf..db87313dd 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "เบราว์เซอร์ไม่เปิดใช่ไหม? ใช้ URL ด้านล่างเพื่อเข้าสู่ระบบ"), ("Lock canvas", "ล็อคแคนวาส"), ("Enable WebRTC P2P connection", "เปิดใช้งานการเชื่อมต่อ P2P แบบ WebRTC"), + ("Enable TCP hole punching", "เปิดใช้งาน TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 8a5a6d1ea..790569e96 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Tarayıcı açılmadı mı? Giriş yapmak için aşağıdaki URL'yi kullanın."), ("Lock canvas", "Tuvali kilitle"), ("Enable WebRTC P2P connection", "WebRTC P2P bağlantısını etkinleştir"), + ("Enable TCP hole punching", "TCP delik açmayı etkinleştir"), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index b4d37d9a6..1e0c607f6 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "瀏覽器未開啟?請使用下方網址登入。"), ("Lock canvas", "鎖定畫布"), ("Enable WebRTC P2P connection", "啟用 WebRTC P2P 連線"), + ("Enable TCP hole punching", "啟用 TCP 打洞"), ].iter().cloned().collect(); } diff --git a/src/lang/uk.rs b/src/lang/uk.rs index 2fbf18f04..7ef8c7be0 100644 --- a/src/lang/uk.rs +++ b/src/lang/uk.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Браузер не відкрився? Скористайтеся посиланням нижче, щоб увійти."), ("Lock canvas", "Блокування полотна"), ("Enable WebRTC P2P connection", "Увімкнути P2P-підключення через WebRTC"), + ("Enable TCP hole punching", "Увімкнути TCP hole punching"), ].iter().cloned().collect(); } diff --git a/src/lang/vi.rs b/src/lang/vi.rs index 352113817..db3e24970 100644 --- a/src/lang/vi.rs +++ b/src/lang/vi.rs @@ -759,5 +759,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Browser didn't open? Use the url below to sign in.", "Trình duyệt không mở được? Hãy dùng URL bên dưới để đăng nhập."), ("Lock canvas", "Khóa khung hình"), ("Enable WebRTC P2P connection", "Cho phép kết nối WebRTC P2P"), + ("Enable TCP hole punching", "Bật TCP Hole Punching"), ].iter().cloned().collect(); }