mirror of
https://github.com/therealaleph/MasterHttpRelayVPN-RUST.git
synced 2026-05-18 05:44:35 +03:00
feat: block QUIC by default + UI toggle (Android & desktop) (#805)
QUIC over the TCP-based tunnel causes TCP-over-TCP meltdown — users see <1 Mbps where HTTPS/TCP would do >50. The existing `block_quic` config option was off by default and had no UI on either platform, so most users suffered QUIC degradation without knowing why. Changes: - Default `block_quic` to `true` (was `false`). Browsers detect the silent UDP/443 drop and fall back to TCP/HTTPS within seconds. - Add "Block QUIC" toggle in Android Advanced UI. - Add "Block QUIC (UDP/443)" checkbox in desktop UI (was config-only, issue #213). - Android: always emit `block_quic` in JSON so the Rust default doesn't silently override the user's choice. Closes #793. Co-authored-by: yyoyoian-pixel <279225925+yyoyoian-pixel@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -98,6 +98,8 @@ data class MhrvConfig(
|
||||
val parallelRelay: Int = 1,
|
||||
val coalesceStepMs: Int = 10,
|
||||
val coalesceMaxMs: Int = 1000,
|
||||
/** Block QUIC (UDP/443). QUIC over TCP tunnel causes meltdown. */
|
||||
val blockQuic: Boolean = true,
|
||||
val upstreamSocks5: String = "",
|
||||
|
||||
/**
|
||||
@@ -219,6 +221,7 @@ data class MhrvConfig(
|
||||
put("parallel_relay", parallelRelay)
|
||||
if (coalesceStepMs != 10) put("coalesce_step_ms", coalesceStepMs)
|
||||
if (coalesceMaxMs != 1000) put("coalesce_max_ms", coalesceMaxMs)
|
||||
put("block_quic", blockQuic)
|
||||
if (upstreamSocks5.isNotBlank()) {
|
||||
put("upstream_socks5", upstreamSocks5.trim())
|
||||
}
|
||||
@@ -330,6 +333,7 @@ object ConfigStore {
|
||||
if (cfg.parallelRelay != defaults.parallelRelay) obj.put("parallel_relay", cfg.parallelRelay)
|
||||
if (cfg.coalesceStepMs != defaults.coalesceStepMs) obj.put("coalesce_step_ms", cfg.coalesceStepMs)
|
||||
if (cfg.coalesceMaxMs != defaults.coalesceMaxMs) obj.put("coalesce_max_ms", cfg.coalesceMaxMs)
|
||||
if (cfg.blockQuic != defaults.blockQuic) obj.put("block_quic", cfg.blockQuic)
|
||||
if (cfg.upstreamSocks5.isNotBlank()) obj.put("upstream_socks5", cfg.upstreamSocks5)
|
||||
if (cfg.passthroughHosts.isNotEmpty()) obj.put("passthrough_hosts", JSONArray().apply { cfg.passthroughHosts.forEach { put(it) } })
|
||||
if (cfg.tunnelDoh != defaults.tunnelDoh) obj.put("tunnel_doh", cfg.tunnelDoh)
|
||||
@@ -433,6 +437,7 @@ object ConfigStore {
|
||||
parallelRelay = obj.optInt("parallel_relay", 1),
|
||||
coalesceStepMs = obj.optInt("coalesce_step_ms", 10),
|
||||
coalesceMaxMs = obj.optInt("coalesce_max_ms", 1000),
|
||||
blockQuic = obj.optBoolean("block_quic", true),
|
||||
upstreamSocks5 = obj.optString("upstream_socks5", ""),
|
||||
passthroughHosts = obj.optJSONArray("passthrough_hosts")?.let { arr ->
|
||||
buildList { for (i in 0 until arr.length()) add(arr.optString(i)) }
|
||||
|
||||
@@ -1265,6 +1265,28 @@ private fun AdvancedSettings(
|
||||
)
|
||||
}
|
||||
|
||||
// Block QUIC toggle
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
"Block QUIC",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
Text(
|
||||
"Drop UDP/443 so browsers use TCP/HTTPS. QUIC over TCP tunnel causes meltdown.",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = cfg.blockQuic,
|
||||
onCheckedChange = { onChange(cfg.copy(blockQuic = it)) },
|
||||
)
|
||||
}
|
||||
|
||||
// Block DoH toggle
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
|
||||
+11
-1
@@ -420,7 +420,7 @@ fn load_form() -> (FormState, Option<String>) {
|
||||
normalize_x_graphql: false,
|
||||
youtube_via_relay: false,
|
||||
passthrough_hosts: Vec::new(),
|
||||
block_quic: false,
|
||||
block_quic: true,
|
||||
disable_padding: false,
|
||||
tunnel_doh: true,
|
||||
bypass_doh_hosts: Vec::new(),
|
||||
@@ -1239,6 +1239,16 @@ impl eframe::App for App {
|
||||
Script relay instead — slower for video, but the visible SNI matches the site.",
|
||||
);
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_space(120.0 + 8.0);
|
||||
ui.checkbox(&mut self.form.block_quic, "Block QUIC (UDP/443)")
|
||||
.on_hover_text(
|
||||
"Drop QUIC (UDP port 443) so browsers fall back to TCP/HTTPS. \
|
||||
QUIC over the TCP-based tunnel causes TCP-over-TCP meltdown \
|
||||
(<1 Mbps). Browsers detect the drop and switch to TCP within seconds. \
|
||||
Issue #213, #793.",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+6
-1
@@ -202,7 +202,7 @@ pub struct Config {
|
||||
/// flag lets users who care about consistency over peak speed
|
||||
/// opt out of QUIC at the source rather than discovering its
|
||||
/// failure modes later. Issue #213.
|
||||
#[serde(default)]
|
||||
#[serde(default = "default_block_quic")]
|
||||
pub block_quic: bool,
|
||||
/// When true, suppress the random `_pad` field that v1.8.0+ adds
|
||||
/// to outbound Apps Script requests for DPI evasion. Default off
|
||||
@@ -481,6 +481,11 @@ fn default_google_ip_validation() -> bool {true}
|
||||
/// opt back in with `tunnel_doh: false`.
|
||||
fn default_tunnel_doh() -> bool { true }
|
||||
|
||||
/// Default for `block_quic`: `true`. QUIC over the TCP-based tunnel
|
||||
/// causes TCP-over-TCP meltdown (<1 Mbps). Browsers fall back to
|
||||
/// HTTPS/TCP within seconds of the silent UDP drop. Issue #793.
|
||||
fn default_block_quic() -> bool { true }
|
||||
|
||||
/// Default for `block_doh`: `true` (browser DoH is rejected so the
|
||||
/// browser falls back to system DNS, which `tun2proxy` resolves
|
||||
/// instantly via virtual DNS — saves the ~1.5s tunnel round-trip per
|
||||
|
||||
Reference in New Issue
Block a user