From 1d1a1ea5af451f6da39543ee84f783a8e2d96990 Mon Sep 17 00:00:00 2001 From: ospab Date: Fri, 10 Jul 2026 01:04:56 +0300 Subject: [PATCH] refactor: remove dead stealth_sni config field across the whole stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stealth_sni was never actually consumed to construct any wire bytes — verified dead in bridge.rs (only stored, never read). It implied TLS/HTTP SNI mimicry that this project deliberately does not do (zapret-like: packet-level DPI obfuscation only, no protocol mimicry). Removed from the runtime schema (config.rs, bridge.rs), both CLI/GUI local config shapes and their JSON templates, the Flutter profile model/UI/share-link logic, and README feature docs. migrate.rs now drops the field from legacy configs with a note instead of carrying it forward. --- README.md | 4 +-- README.ru.md | 5 ++- ostp-client/src/bridge.rs | 3 -- ostp-client/src/config.rs | 10 ++---- ostp-client/src/migrate.rs | 43 ++++++++++++++++------- ostp-flutter/lib/models/ostp_profile.dart | 4 --- ostp-flutter/lib/ui/home_screen.dart | 1 - ostp-flutter/lib/ui/settings_screen.dart | 32 +---------------- ostp-gui/src-tauri/src/lib.rs | 2 -- ostp/src/main.rs | 20 ++++------- 10 files changed, 43 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index db28189..cac0206 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Download pre-built binaries for your platform from [GitHub Releases](https://git | **Fallback Server** | TCP fallback proxy to a web server - makes OSTP indistinguishable from nginx during active probing. | | **Multi-Listener** | Bind to multiple addresses simultaneously (dual-stack IPv4/IPv6, multi-port). | | **TUN Mode** | Full-system VPN via native `smoltcp` network stack without external dependencies. All traffic transparently routed through the tunnel. | -| **xHTTP Stealth (UoT)** | UDP-over-TCP tunnel that completely hides traffic. Since all data is fully encrypted and length-prefixed, it bypasses DPI filters that block unknown UDP traffic by riding over a plain TCP connection. | +| **UoT (UDP-over-TCP)** | Bare UDP-over-TCP tunnel, no protocol mimicry. Since all data is fully encrypted and length-prefixed, it bypasses DPI filters that block unknown UDP traffic by riding over a plain TCP connection. | | **Mobile & Web Apps** | Beautiful cross-platform mobile client (Flutter) and a modern Web Control Panel (React/Vite) for effortless server and client management. | | **TURN Relay** | RFC 5766 TURN support for environments where direct UDP is blocked. | | **Hot-Reload** | Runtime config reload without restart (access keys, exclusions, mux settings). | @@ -121,7 +121,7 @@ graph TD "server": "YOUR_SERVER_IP:50000", "access_key": "YOUR_SECRET_KEY", "socks5_bind": "127.0.0.1:1088", - "transport": { "mode": "udp", "stealth_sni": "vk.com" }, + "transport": { "mode": "udp" }, "tun": { "enable": false, "dns": "1.1.1.1" } } ``` diff --git a/README.ru.md b/README.ru.md index 7cf8669..85e4a08 100644 --- a/README.ru.md +++ b/README.ru.md @@ -24,7 +24,7 @@ | **Мультиплексирование** | Несколько логических TCP-потоков поверх одной зашифрованной UDP-сессии с per-stream flow control. | | **Бесшовный роуминг** | Клиент может менять сети (WiFi ↔ 4G) без разрыва сессии - сервер отслеживает session-ID, а не IP-адрес. | | **TUN-режим** | Полносистемный VPN без внешних зависимостей (встроенный network stack на базе `smoltcp`). | -| **xHTTP Стелс (UoT)** | Туннель UDP-over-TCP, который полностью скрывает трафик. Поскольку все данные полностью зашифрованы и имеют префикс длины, он обходит DPI фильтры, блокирующие неизвестный UDP трафик, передавая всё по обычному TCP соединению. | +| **UoT (UDP-over-TCP)** | Голый туннель UDP-over-TCP, без имитации протоколов. Поскольку все данные полностью зашифрованы и имеют префикс длины, он обходит DPI фильтры, блокирующие неизвестный UDP трафик, передавая всё по обычному TCP соединению. | | **Мобильные и Web приложения** | Красивый кроссплатформенный мобильный клиент (Flutter) и современная Web панель управления (React/Vite) для удобного администрирования. | | **TURN Relay** | RFC 5766 TURN для окружений, где прямой UDP заблокирован. | | **Hot-Reload** | Перезагрузка конфига в рантайме без перезапуска (ключи, исключения, mux, TURN). | @@ -116,8 +116,7 @@ irm https://raw.githubusercontent.com/ospab/ostp/master/scripts/install.ps1 | ie "debug": false, // Настройки транспорта (udp или uot) "transport": { - "mode": "udp", - "stealth_sni": "vk.com" + "mode": "udp" }, // TUN-режим (полносистемный VPN) "tun": { diff --git a/ostp-client/src/bridge.rs b/ostp-client/src/bridge.rs index 0bbf873..30259bf 100644 --- a/ostp-client/src/bridge.rs +++ b/ostp-client/src/bridge.rs @@ -65,7 +65,6 @@ pub struct Bridge { pub mux_sessions: usize, pub transport_mode: String, - pub stealth_sni: String, pub tcp_fragmentation: bool, pub frag_chunk: usize, pub frag_sleep: u64, @@ -102,7 +101,6 @@ impl Bridge { mux_sessions: config.multiplex.sessions.max(1), transport_mode: config.transport.mode.clone(), - stealth_sni: config.transport.stealth_sni.clone(), tcp_fragmentation: config.transport.tcp_fragmentation, frag_chunk: config.transport.frag_chunk, frag_sleep: config.transport.frag_sleep, @@ -1033,7 +1031,6 @@ impl Bridge { self.mux_enabled = cfg.multiplex.enabled; self.mux_sessions = cfg.multiplex.sessions.max(1); self.transport_mode = cfg.transport.mode.clone(); - self.stealth_sni = cfg.transport.stealth_sni.clone(); self.tcp_fragmentation = cfg.transport.tcp_fragmentation; self.frag_chunk = cfg.transport.frag_chunk.max(1); self.frag_sleep = cfg.transport.frag_sleep; diff --git a/ostp-client/src/config.rs b/ostp-client/src/config.rs index 06a65e8..796cdde 100644 --- a/ostp-client/src/config.rs +++ b/ostp-client/src/config.rs @@ -70,15 +70,13 @@ pub struct LocalProxyConfig { } /// Transport layer configuration. -/// `mode` = "udp" (default) or "uot" (UDP over TCP с xHTTP-транспортом). +/// `mode` = "udp" (default) or "uot" (UDP over TCP, no protocol mimicry — +/// zapret-like: no recognizable header at all, not a fake TLS/HTTP shell). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TransportConfig { /// "udp" or "uot" #[serde(default = "default_transport_mode")] pub mode: String, - /// TLS SNI and HTTP Host for xHTTP routing - #[serde(default)] - pub stealth_sni: String, /// Split the first UoT/TCP packet (handshake) into tiny TCP segments to /// break DPI that inspects the first packet. UoT/TCP only; ignored for UDP. pub tcp_fragmentation: bool, @@ -106,7 +104,6 @@ impl Default for TransportConfig { fn default() -> Self { Self { mode: default_transport_mode(), - stealth_sni: String::new(), tcp_fragmentation: false, frag_chunk: default_frag_chunk(), frag_sleep: default_frag_sleep(), @@ -192,7 +189,6 @@ struct RawUnifiedConfig { #[derive(Debug, Deserialize)] struct RawTransportSection { mode: Option, - stealth_sni: Option, tcp_fragmentation: Option, frag_chunk: Option, frag_sleep: Option, @@ -270,7 +266,6 @@ impl ClientConfig { }, transport: TransportConfig { mode: raw.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(default_transport_mode), - stealth_sni: raw.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_default(), tcp_fragmentation: raw.transport.as_ref().and_then(|t| t.tcp_fragmentation).unwrap_or(false), frag_chunk: raw.transport.as_ref().and_then(|t| t.frag_chunk).unwrap_or_else(default_frag_chunk), frag_sleep: raw.transport.as_ref().and_then(|t| t.frag_sleep).unwrap_or_else(default_frag_sleep), @@ -495,7 +490,6 @@ pub struct ClientFileConfig { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct TransportConfigRaw { pub mode: Option, - pub stealth_sni: Option, pub tcp_fragmentation: Option, } diff --git a/ostp-client/src/migrate.rs b/ostp-client/src/migrate.rs index 431bf1f..2ea5e87 100644 --- a/ostp-client/src/migrate.rs +++ b/ostp-client/src/migrate.rs @@ -71,6 +71,11 @@ pub fn detect_kind(json: &Value) -> Option { /// never user-meaningful data) and `transport.wss` (the WSS framing /// feature removed entirely in the 0.4.0 rebuild) — both dropped with an /// explicit note; everything else maps 1:1, nothing to convert. +/// - **configs carrying a leftover `transport.stealth_sni`**: dropped with a +/// note, same reasoning as `wss` — it never fed into anything on the wire +/// (no TLS/HTTP mimicry exists in this project), so there is no successor +/// field. Not tied to a specific version: it lingered in the schema well +/// past when the mimicry work it was meant for got removed. /// - **current flat schema**: no-op, `changed = false`. pub fn migrate_client_json(json: Value) -> (Value, MigrationReport) { let mut report = MigrationReport::default(); @@ -106,6 +111,14 @@ pub fn migrate_client_json(json: Value) -> (Value, MigrationReport) { .to_string(), ); } + if transport.remove("stealth_sni").is_some() { + report.note( + "Dropped transport.stealth_sni — never actually used to construct any wire \ + bytes (no TLS/HTTP mimicry exists in this project — same zapret-like \ + reasoning as transport.wss), so it was unused config plumbing with no effect." + .to_string(), + ); + } } (out, report) @@ -199,12 +212,14 @@ fn migrate_client_from_modular(json: Value, mut report: MigrationReport) -> (Val .and_then(|v| v.as_str()) .unwrap_or("udp") .to_string(); - let stealth_sni = primary - .get("transport") - .and_then(|t| t.get("stealth_sni")) - .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string(); + if let Some(sni) = primary.get("transport").and_then(|t| t.get("stealth_sni")).and_then(|v| v.as_str()) { + if !sni.is_empty() { + report.note(format!( + "Dropped transport.stealth_sni ({sni:?}) — never actually used to construct \ + any wire bytes; unused config plumbing with no successor field." + )); + } + } let tcp_fragmentation = primary .get("transport") .and_then(|t| t.get("tcp_fragmentation")) @@ -287,7 +302,6 @@ fn migrate_client_from_modular(json: Value, mut report: MigrationReport) -> (Val }, "transport": { "mode": transport_type, - "stealth_sni": stealth_sni, "tcp_fragmentation": tcp_fragmentation, }, }); @@ -388,13 +402,15 @@ mod tests { assert_eq!(new["debug"], true); assert_eq!(new["tun"]["enable"], true); assert_eq!(new["transport"]["mode"], "uot"); - assert_eq!(new["transport"]["stealth_sni"], "vk.com"); assert_eq!(new["transport"]["tcp_fragmentation"], true); assert_eq!(new["mux"]["enabled"], true); assert_eq!(new["mux"]["sessions"], 4); assert_eq!(new["exclude"]["domains"], json!(["local.lan", "internal.corp"])); assert_eq!(new["exclude"]["ips"], json!(["192.168.0.0/16"])); assert_eq!(new["exclude"]["processes"], json!(["steam.exe"])); + // stealth_sni never fed into any wire bytes — dropped, not carried forward. + assert!(new["transport"].get("stealth_sni").is_none()); + assert!(report.notes.iter().any(|n| n.contains("stealth_sni") && n.contains("vk.com"))); } /// Old modular configs that had MULTIPLE ostp outbounds (multi-server) — @@ -423,9 +439,9 @@ mod tests { } /// Pre-0.3.1 flat config carrying fields that no longer exist - /// (tun.wintun_path, tun.ipv4_address, transport.wss) — those get - /// dropped with a note; every field that's still meaningful passes - /// through untouched, byte for byte. + /// (tun.wintun_path, tun.ipv4_address, transport.wss, transport.stealth_sni) + /// — those get dropped with a note; every field that's still meaningful + /// passes through untouched, byte for byte. #[test] fn flat_legacy_drops_only_dead_fields() { let old = json!({ @@ -455,15 +471,16 @@ mod tests { assert_eq!(new["tun"]["dns"], "1.1.1.1"); assert_eq!(new["tun"]["kill_switch"], true); assert_eq!(new["exclude"]["domains"], json!(["a.com"])); - assert_eq!(new["transport"]["stealth_sni"], "bing.com"); // Dead fields are gone... assert!(new["tun"].get("wintun_path").is_none()); assert!(new["tun"].get("ipv4_address").is_none()); assert!(new["transport"].get("wss").is_none()); + assert!(new["transport"].get("stealth_sni").is_none()); // ...and their removal was reported, not silent. assert!(report.notes.iter().any(|n| n.contains("wintun_path"))); assert!(report.notes.iter().any(|n| n.contains("ipv4_address"))); assert!(report.notes.iter().any(|n| n.contains("wss"))); + assert!(report.notes.iter().any(|n| n.contains("stealth_sni"))); } /// A config already in the current shape must be a true no-op: report @@ -476,7 +493,7 @@ mod tests { "tun": { "enable": false, "dns": null, "kill_switch": false }, "exclude": { "domains": [], "ips": [], "processes": [] }, "mux": { "enabled": false, "sessions": 1 }, - "transport": { "mode": "udp", "stealth_sni": "", "tcp_fragmentation": false } + "transport": { "mode": "udp", "tcp_fragmentation": false } }); let (new, report) = migrate_client_json(current.clone()); assert!(!report.changed); diff --git a/ostp-flutter/lib/models/ostp_profile.dart b/ostp-flutter/lib/models/ostp_profile.dart index d1e130b..80bc3e8 100644 --- a/ostp-flutter/lib/models/ostp_profile.dart +++ b/ostp-flutter/lib/models/ostp_profile.dart @@ -11,7 +11,6 @@ class OstpProfile { String serverAddr; String accessKey; String transportMode; // 'udp' | 'uot' - String stealthSni; bool active; // Junk packets + TCP fragmentation — per-profile, exactly like ostp-gui's @@ -31,7 +30,6 @@ class OstpProfile { required this.serverAddr, required this.accessKey, this.transportMode = 'udp', - this.stealthSni = '', this.active = false, this.tcpFragmentation = false, this.fragChunk = 2, @@ -49,7 +47,6 @@ class OstpProfile { 'serverAddr': serverAddr, 'accessKey': accessKey, 'transportMode': transportMode, - 'stealthSni': stealthSni, 'active': active, 'tcpFragmentation': tcpFragmentation, 'fragChunk': fragChunk, @@ -68,7 +65,6 @@ class OstpProfile { serverAddr: json['serverAddr'] as String? ?? '', accessKey: json['accessKey'] as String? ?? '', transportMode: json['transportMode'] as String? ?? 'udp', - stealthSni: json['stealthSni'] as String? ?? '', active: json['active'] as bool? ?? false, tcpFragmentation: json['tcpFragmentation'] as bool? ?? false, fragChunk: json['fragChunk'] as int? ?? 2, diff --git a/ostp-flutter/lib/ui/home_screen.dart b/ostp-flutter/lib/ui/home_screen.dart index 4088184..5316415 100644 --- a/ostp-flutter/lib/ui/home_screen.dart +++ b/ostp-flutter/lib/ui/home_screen.dart @@ -115,7 +115,6 @@ class _HomeScreenState extends State with TickerProviderStateMixin { // shape as the desktop GUI's profile object — not global toggles. "transport": { "mode": p?.transportMode ?? 'udp', - "stealth_sni": (p?.stealthSni.isNotEmpty ?? false) ? p!.stealthSni : 'vk.com', "tcp_fragmentation": p?.tcpFragmentation ?? false, "frag_chunk": p?.fragChunk ?? 2, "frag_sleep": p?.fragSleep ?? 2, diff --git a/ostp-flutter/lib/ui/settings_screen.dart b/ostp-flutter/lib/ui/settings_screen.dart index b17f3da..48a1578 100644 --- a/ostp-flutter/lib/ui/settings_screen.dart +++ b/ostp-flutter/lib/ui/settings_screen.dart @@ -115,7 +115,6 @@ class _SettingsScreenState extends State { final type = uri.queryParameters['type']; final transportMode = (type == 'tcp' || type == 'http') ? 'uot' : 'udp'; final name = uri.queryParameters['name'] ?? host; - final stealthSni = uri.queryParameters['sni'] ?? ''; final wasEmpty = _profiles.isEmpty; setState(() { @@ -125,7 +124,6 @@ class _SettingsScreenState extends State { serverAddr: host, accessKey: key, transportMode: transportMode, - stealthSni: stealthSni, active: wasEmpty, )); _saveProfiles(); @@ -207,15 +205,6 @@ class _SettingsScreenState extends State { ); } - static const List _stealthDomains = [ - 'yastatic.net', 'mc.yandex.ru', 'st.mycdn.me', - 'top-fwz1.mail.ru', 'sso.passport.yandex.ru', - 'sberbank.ru', 'ad.mail.ru', 'ads.vk.com', - 'login.vk.com', 'api.sberbank.ru', 'ok.ru', - 'rostelecom.ru', 'rt.ru', 'tinkoff.ru', - 'x5.ru', 'ozon.ru', 'wildberries.ru', 'gosuslugi.ru', 'vk.com', - ]; - void _showEditProfileDialog(OstpProfile? profile) { final isNew = profile == null; final nameCtrl = TextEditingController(text: profile?.name ?? ''); @@ -229,7 +218,6 @@ class _SettingsScreenState extends State { final junkPsMaxCtrl = TextEditingController(text: (profile?.junkPsMax ?? 1000).toString()); String transportMode = profile?.transportMode ?? 'udp'; bool tcpFragmentation = profile?.tcpFragmentation ?? false; - String stealthSni = (profile?.stealthSni.isNotEmpty ?? false) ? profile!.stealthSni : 'vk.com'; bool obscureKey = true; showDialog( @@ -265,27 +253,12 @@ class _SettingsScreenState extends State { decoration: const InputDecoration(labelText: 'Transport'), items: const [ DropdownMenuItem(value: 'udp', child: Text('UDP')), - DropdownMenuItem(value: 'uot', child: Text('TCP (UoT) — xHTTP stealth')), + DropdownMenuItem(value: 'uot', child: Text('TCP (UoT)')), ], onChanged: (v) { if (v != null) setDialogState(() => transportMode = v); }, ), - if (transportMode == 'uot') ...[ - const SizedBox(height: 12), - Builder(builder: (context) { - final domains = [..._stealthDomains]; - if (!domains.contains(stealthSni)) domains.add(stealthSni); - return DropdownButtonFormField( - value: stealthSni, - decoration: const InputDecoration(labelText: 'Stealth SNI domain'), - items: domains.map((d) => DropdownMenuItem(value: d, child: Text(d))).toList(), - onChanged: (v) { - if (v != null) setDialogState(() => stealthSni = v); - }, - ); - }), - ], const Divider(height: 32), // Junk packets + TCP fragmentation moved into their own // modals (tap to configure) — this dialog was carrying too @@ -358,7 +331,6 @@ class _SettingsScreenState extends State { serverAddr: server, accessKey: key, transportMode: transportMode, - stealthSni: stealthSni, active: wasEmpty, tcpFragmentation: tcpFragmentation, fragChunk: int.tryParse(fragChunkCtrl.text) ?? 2, @@ -373,7 +345,6 @@ class _SettingsScreenState extends State { profile.serverAddr = server; profile.accessKey = key; profile.transportMode = transportMode; - profile.stealthSni = stealthSni; profile.tcpFragmentation = tcpFragmentation; profile.fragChunk = int.tryParse(fragChunkCtrl.text) ?? 2; profile.fragSleep = int.tryParse(fragSleepCtrl.text) ?? 2; @@ -503,7 +474,6 @@ class _SettingsScreenState extends State { final key = Uri.encodeComponent(p.accessKey); if (p.serverAddr.isEmpty || p.accessKey.isEmpty) return; final queryParams = []; - if (p.stealthSni.isNotEmpty) queryParams.add('sni=${Uri.encodeComponent(p.stealthSni)}'); if (p.transportMode != 'udp') queryParams.add('type=${p.transportMode}'); final queryString = queryParams.isEmpty ? '' : '?${queryParams.join('&')}'; final url = 'ostp://$key@${p.serverAddr}$queryString'; diff --git a/ostp-gui/src-tauri/src/lib.rs b/ostp-gui/src-tauri/src/lib.rs index b979a49..5690a0f 100644 --- a/ostp-gui/src-tauri/src/lib.rs +++ b/ostp-gui/src-tauri/src/lib.rs @@ -56,7 +56,6 @@ struct TunConfig { #[derive(Debug, Deserialize, Serialize, Clone)] struct TransportConfigRaw { mode: Option, - stealth_sni: Option, tcp_fragmentation: Option, frag_chunk: Option, frag_sleep: Option, @@ -167,7 +166,6 @@ fn map_to_client_config(raw: &ClientConfigRaw, mode: &str) -> ostp_client::confi transport: ostp_client::config::TransportConfig { mode: raw.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(|| "udp".to_string()), - stealth_sni: raw.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_else(|| "microsoft.com".to_string()), tcp_fragmentation: raw.transport.as_ref().and_then(|t| t.tcp_fragmentation).unwrap_or(false), frag_chunk: raw.transport.as_ref().and_then(|t| t.frag_chunk).unwrap_or(2), frag_sleep: raw.transport.as_ref().and_then(|t| t.frag_sleep).unwrap_or(2), diff --git a/ostp/src/main.rs b/ostp/src/main.rs index 1878533..85df0cb 100644 --- a/ostp/src/main.rs +++ b/ostp/src/main.rs @@ -169,14 +169,12 @@ fn parse_ostp_link(link: &str) -> Result { let host = parsed.host_str().ok_or_else(|| anyhow!("Missing host in share link"))?; let port = parsed.port().ok_or_else(|| anyhow!("Missing port in share link"))?; let server = format!("{host}:{port}"); - let mut sni = String::new(); let mut transport_mode = String::from("udp"); let mut tun_enabled = false; let mut tun_dns = None; for (k, v) in parsed.query_pairs() { match &*k { - "sni" => sni = v.into_owned(), "type" => transport_mode = v.into_owned(), "tun" => tun_enabled = v == "true", "dns" => tun_dns = Some(v.into_owned()), @@ -190,7 +188,6 @@ fn parse_ostp_link(link: &str) -> Result { mtu: None, transport: Some(TransportConfigRaw { mode: Some(transport_mode), - stealth_sni: Some(sni.clone()), tcp_fragmentation: None, }), socks5_bind: Some("127.0.0.1:1088".to_string()), @@ -503,15 +500,14 @@ fn run_setup_wizard(config_path: &std::path::Path) -> Result<()> { // Try import from link first let use_link = wizard_yn("Do you have a share link (ostp://...)?", false); - let (server, access_key, sni, transport_mode) = if use_link { + let (server, access_key, transport_mode) = if use_link { let link_str = wizard_prompt("Paste link", ""); let parsed = url::Url::parse(&link_str).unwrap(); let mut p = parsed.query_pairs(); - let sni = p.find(|(k, _)| k == "sni").map(|(_, v)| v.to_string()).unwrap_or_default(); let tm = p.find(|(k, _)| k == "type").map(|(_, v)| v.to_string()).unwrap_or("udp".to_string()); - (parsed.host_str().unwrap().to_string() + ":" + &parsed.port().unwrap_or(50000).to_string(), parsed.username().to_string(), sni, tm) + (parsed.host_str().unwrap().to_string() + ":" + &parsed.port().unwrap_or(50000).to_string(), parsed.username().to_string(), tm) } else { - ("127.0.0.1:50000".to_string(), "".to_string(), "".to_string(), "udp".to_string()) + ("127.0.0.1:50000".to_string(), "".to_string(), "udp".to_string()) }; wizard_step(2, TOTAL, "Local proxy"); @@ -564,7 +560,6 @@ fn run_setup_wizard(config_path: &std::path::Path) -> Result<()> { // Build and save config let key_for_gen = generate_secure_key("hex"); let _ = key_for_gen; - let _ = &sni; let client_json = serde_json::json!({ "mode": "client", @@ -585,8 +580,7 @@ fn run_setup_wizard(config_path: &std::path::Path) -> Result<()> { "processes": [] }, "transport": { - "mode": transport_mode, - "stealth_sni": "www.microsoft.com" + "mode": transport_mode }, "mux": { "enabled": mux_enable, @@ -1222,10 +1216,9 @@ async fn run_app() -> Result<()> { "processes": [] }}, - // Transport Mode: "udp" (default WebRTC masquerade) or "uot" (TCP UoT) + // Transport Mode: "udp" (default) or "uot" (UDP over TCP, no mimicry) "transport": {{ - "mode": "udp", - "stealth_sni": "www.microsoft.com" + "mode": "udp" }}, "mux": {{ @@ -1679,7 +1672,6 @@ async fn run_client_directly(client_cfg: ClientConfig) -> Result<()> { }, transport: ostp_client::config::TransportConfig { mode: client_cfg.transport.as_ref().and_then(|t| t.mode.clone()).unwrap_or_else(|| "udp".to_string()), - stealth_sni: client_cfg.transport.as_ref().and_then(|t| t.stealth_sni.clone()).unwrap_or_else(|| "microsoft.com".to_string()), tcp_fragmentation: client_cfg.transport.as_ref().and_then(|t| t.tcp_fragmentation).unwrap_or(false), frag_chunk: 2, frag_sleep: 2,