Skip to content

feat: bypass Apps Script tunnel for DoH endpoints on TCP/443#439

Merged
therealaleph merged 1 commit intotherealaleph:mainfrom
dazzling-no-more:feature/doh-bypass
Apr 28, 2026
Merged

feat: bypass Apps Script tunnel for DoH endpoints on TCP/443#439
therealaleph merged 1 commit intotherealaleph:mainfrom
dazzling-no-more:feature/doh-bypass

Conversation

@dazzling-no-more
Copy link
Copy Markdown
Contributor

In Full mode every browser DNS lookup over DoH was riding through the
Apps Script tunnel — chrome.cloudflare-dns.com:443, dns.google:443
and friends each paid the ~2 s UrlFetchApp round-trip per name. Logs
showed this was the dominant per-flow overhead during page loads, yet
the tunnel adds no real privacy on top of DoH (queries are already
encrypted; the only marginal property is hiding the fact-of-DoH from
the local network). Route CONNECTs to known DoH hosts around the
tunnel via plain TCP instead.

  • src/proxy_server.rs: new DEFAULT_DOH_HOSTS covering Cloudflare
    (incl. browser-pinned chrome. / mozilla. / 1dot1dot1dot1.
    variants), Google, Quad9, AdGuard, NextDNS, OpenDNS, CleanBrowsing,
    dns.sb, dns0.eu, AliDNS, doh.pub, Mullvad. matches_doh_host() is
    case-insensitive and matches exactly OR as a dot-anchored suffix
    unconditionally — symmetric for both the default list and user
    extras. Hook in dispatch_tunnel between passthrough_hosts
    (which still wins) and the Full / AppsScript mode branches; gated
    to TCP/443 so a CONNECT to e.g. dns.google:80 doesn't get
    diverted off-tunnel. RewriteCtx carries bypass_doh and
    bypass_doh_hosts. ProxyServer::new warns at startup when
    tunnel_doh: true is paired with non-empty bypass_doh_hosts so
    the otherwise-silent inert combo is visible.

  • src/config.rs: tunnel_doh: bool (default false = bypass
    active) is the opt-out, and bypass_doh_hosts: Vec<String> adds
    user-supplied entries to the built-in list. Both #[serde(default)]
    so existing configs keep working unchanged. Doc comments call out
    the default direction, the TCP/443 gate (private DoH on :8443
    should use passthrough_hosts), and the inert combo.

  • src/bin/ui.rs: round-trip both fields through FormState and
    ConfigWire so Save doesn't drop user opt-outs / extras.

  • android/.../ConfigStore.kt: mirror across MhrvConfig, toJson(),
    encode(), and loadFromJson(). Write paths normalize entries
    (trim → drop empty → distinct) symmetric with the read path so
    saved JSON and mhrv-rs:// hashes stay canonical.

  • 6 unit tests for matches_doh_host covering exact, case /
    trailing-dot, suffix tenant subdomains, unrelated negatives,
    extras extending the default, and the asymmetric-matching
    footgun guard (user entries match subdomains without leading dot).

@github-actions github-actions Bot added the type: feature feat: PR — auto-applied by release-drafter label Apr 28, 2026
@therealaleph therealaleph merged commit 554e51f into therealaleph:main Apr 28, 2026
1 check passed
therealaleph added a commit that referenced this pull request Apr 28, 2026
…er errors

Three substantive PRs from contributors landed for this release:

- #443 by @euvel: optional spreadsheet-backed response cache in Code.gs.
  Implements all 5 review suggestions from the design discussion (#400):
  TTL-aware caching, 35 KB body-size gate, header rewriting on hit,
  circular buffer for O(1) writes, Vary-aware compound keys.

- #439 by @dazzling-no-more: bypass Apps Script tunnel for known DoH
  endpoints on TCP/443. Cloudflare/Google/Quad9/AdGuard/NextDNS/OpenDNS/
  CleanBrowsing/dns.sb/dns0.eu/AliDNS/doh.pub/Mullvad. Saves the ~2s
  UrlFetchApp roundtrip per name without losing privacy (DoH is
  already encrypted). Default on; users can opt out via tunnel_doh: true
  or extend the list via bypass_doh_hosts.

- #438 by @dazzling-no-more: H1 container keepalive + 431 oversized-
  headers + clearer port-collision message. Cherry-picks from upstream
  Python (Apr 23-26 window). Keepalive prevents Apps Script V8 cold
  starts (visible as YouTube stalls after pause); 431 replaces silent
  socket drops on >64 KB headers (which caused browser retry loops).
@therealaleph
Copy link
Copy Markdown
Owner

Merged + included in v1.8.3 (just tagged). Builds clean, all 160 tests pass on main. Thanks for shipping this — exactly the kind of contribution that scales the project beyond what one maintainer can ship alone.

v1.8.3 release page: https://github.com/therealaleph/MasterHttpRelayVPN-RUST/releases/tag/v1.8.3

Telegram channel announcement: https://t.me/mhrv_rs (will fire once release CI completes)

Will tag you on the v1.9.0 xmux design issue when drafted (~1-2 weeks).


[reply via Anthropic Claude | reviewed by @therealaleph]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature feat: PR — auto-applied by release-drafter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants