Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "",

/**
Expand Down Expand Up @@ -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())
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)) }
Expand Down
22 changes: 22 additions & 0 deletions android/app/src/main/java/com/therealaleph/mhrv/ui/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 11 additions & 1 deletion src/bin/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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.",
);
});
});
});

Expand Down
7 changes: 6 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading