Skip to content

id: design: ID transport fallback for UDP-denied networks v1 #5671

Open

Description

@dezren39

Summary

ID servers should be reachable from networks where UDP is denied. Today ID's native transport assumes UDP (QUIC/iroh-style reachability). Many real networks — corporate egress, locked-down sandboxes, some cloud and CI environments, captive Wi-Fi — allow only TCP, and often only outbound HTTP/HTTPS through a proxy. This design expands #785 (the UDP-denied SSH fallback design) from "SSH still works" into a general transport-fallback feature set for ID itself: any ID traffic, not just SSH, should degrade gracefully to TCP/HTTP transports without giving up end-to-end encryption.

Relates: #785 (extends it — #785 is the SSH-specific case; this is the general ID transport), the serverless/rendezvous direction in #2046 (Cloudflare Workers edition — a Workers rendezvous/relay is one candidate component here).

Motivating case

Our own fleet sandbox: no direct UDP egress; outbound traffic goes through an HTTP CONNECT proxy only. We need, from inside that sandbox:

  • Access to ID servers (data, queries, sync) with no UDP path available.
  • SSH-class reachability through the same constrained egress — ideally locally terminated, so tools on the sandbox side see a local endpoint rather than a fragile chain of tunnels.
  • The same pattern the fleet already uses for sandbox→laptop proxying, generalized so it is a property of ID, not a one-off fleet workaround.

If ID works from our sandbox, it works from most restricted networks.

Feature set (expanded)

1. Fallback ordering and transport negotiation

  • Defined attempt order: direct UDP → relay-assisted UDP (hole-punch / relay) → TCP → HTTP/HTTPS proxy (CONNECT, and where necessary plain HTTP/WebSocket-style framing).
  • Negotiation is automatic by default, with per-peer and per-network memory: remember which transport last worked for a peer/network and try it first next time, re-probing periodically.
  • Explicit override surface: config and CLI flags to pin a transport, forbid a transport, or force proxy use (for testing and for networks where probing is noisy/slow).
  • Failure classification: distinguish "UDP blocked" from "peer offline" from "proxy auth required" so error messages and retries are correct, and so fallback does not mask real outages.
  • Connection migration: when a better transport becomes available (e.g. the client moves to an unrestricted network), upgrade in place where the protocol allows, without dropping sessions.

2. Broker / relay role

  • A broker that proxies ID traffic over HTTP/TCP for clients that cannot use UDP: clients connect out to the broker over TCP/443 (directly or via their HTTP proxy); the broker forwards to the target ID server (or to a rendezvous point the server also connects out to, for servers themselves behind UDP-denied or NAT-only egress).
  • Ideally native to ID itself: a serve/proxy role inside the id binary (id serve-adjacent mode) so any ID node can act as a broker for peers it is authorized to help — no separate daemon to deploy.
  • Fleet-side surface (future): a fleet id subcommand that stands up/configures this broker role for fleet machines, mirroring the existing fleet sandbox→laptop proxy pattern.
  • Broker is a dumb pipe by design: it routes opaque, end-to-end-encrypted traffic (see trust model). It must not need, hold, or be able to derive session/content keys.

3. Discovery and rendezvous

  • How a UDP-denied client finds its server and a usable broker: rendezvous records (signed, verifiable) advertising a server's available transports, broker endpoints, and priority.
  • Candidate rendezvous substrates to evaluate, with a recommendation: DNS-based records, a well-known HTTPS endpoint, and a Cloudflare Workers rendezvous/relay component (cheap, globally reachable over 443, no server to run) — including when Workers is the right shape vs. when a self-hosted id broker is required (sovereignty, cost, data-residency).
  • Rendezvous must itself be reachable over plain HTTPS, or the fallback is circular.
  • Stale/spoofed rendezvous handling: signature verification, TTLs, and fallback to last-known-good endpoints.

4. Relay trust model

  • What the broker/relay can see: connection metadata (endpoints, timing, volume) — state this honestly and minimize it (no logging defaults, padding/batching options if cheap).
  • What it cannot see: payload contents. ID payloads stay end-to-end encrypted between the true endpoints; the broker forwards ciphertext. SSH through the broker likewise stays end-to-end (broker never terminates SSH).
  • Broker authorization: who may use a given broker (open, allowlist by identity/key, capability token), and who a broker will forward for — an open relay is an abuse magnet; default to authenticated.
  • Compromised-broker analysis: worst case is metadata exposure + denial of service, never content exposure; design must keep it that way (no key escrow, no TLS termination of ID payloads at the broker).
  • Local termination option: where the client side runs a local id proxy endpoint, applications (including SSH) connect to localhost and the encryption boundary is the local process — document exactly where plaintext exists in each topology.

5. Latency and performance budget

  • Stated budgets per fallback tier (e.g. interactive SSH and ID queries must stay usable on the HTTP-proxy path; bulk sync may be slower but must complete).
  • Overhead sources to measure: proxy CONNECT setup, TLS-in-TLS, framing, broker hop latency, head-of-line blocking on a single TCP stream (and whether multiple streams / multiplexing are needed).
  • Keepalive and idle-timeout behavior for long-lived connections through proxies that kill idle TCP.
  • Reconnection/resumption: dropped proxy connections resume sessions rather than restarting sync from zero.

6. What stays end-to-end encrypted (explicit list)

  • ID data/sync payloads: E2E, broker-blind.
  • ID queries and results (see the ID query design): E2E.
  • SSH sessions tunneled through the fallback: E2E, broker is a pipe.
  • Control/rendezvous traffic: authenticated and integrity-protected; confidentiality requirements stated per message type.
  • Anything that is not E2E (if any) must be named in the design with justification — silence is not acceptable here.

Non-goals (v1)

  • Defeating deliberate, policy-enforced egress restrictions the user is not authorized to bypass — this is for reaching your own ID servers from restrictive networks, with the broker as an authorized endpoint.
  • A public, open relay network.
  • Replacing the native UDP transport; fallback is additive.

Acceptance for this design

A follow-on reader can break this into the decomposition tickets below without re-deciding: fallback order, broker role shape (in-id vs Workers vs both), trust model, or the E2E boundary.

Decomposition sketch

  1. Design: transport negotiation & fallback ordering (probing, per-peer memory, overrides, failure classification).
  2. Design: id broker/serve-proxy role — protocol, framing over TCP/HTTP(S), multiplexing, keepalive/resumption.
  3. Design: rendezvous & discovery for UDP-denied clients (signed transport advertisements; substrate selection).
  4. Design: Cloudflare Workers rendezvous/relay component — when it is the right shape, limits, self-host parity.
  5. Design: relay trust model & broker authorization (capabilities/allowlist, metadata minimization, compromised-broker analysis).
  6. Design: HTTP CONNECT proxy traversal (proxy auth, corporate proxies, locally terminated endpoint for SSH-class traffic).
  7. Design: latency budget & measurement plan per fallback tier (interactive vs bulk).
  8. Design: fleet surface — future fleet id subcommand wiring the broker role into fleet sandbox→laptop patterns.

Open questions

  • Broker in id itself, a Workers component, or both — and which ships first?
  • What rendezvous substrate is authoritative when several disagree?
  • How are brokers discovered by strangers vs. only by pre-configured peers (sovereignty vs. convenience)?
  • Proxy-auth credentials: where stored, and how are they kept out of logs/config dumps?
  • Is multiplexing over one TCP connection sufficient, or is head-of-line blocking disqualifying for mixed interactive+bulk traffic?
  • Cost/ownership model for a hosted relay (who runs it, who pays, what are the abuse controls)?
  • How does fallback interact with id: Phase 13 F13.3 SSH-over-iroh reachability (and iroh-over-SSH fallback) #785's SSH-specific design — supersede, wrap, or coexist?

Activity

  1. added
    source/creatorFiled by the new-issue-creator job
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Nov 4, 2026
  2. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    Gap pass (WS-F, 2026-11-04): this issue's decomposition sketch is now filed.

    Each follow-on design ticket named in the sketch above was filed as its own issue (label app/id), so the acceptance item “Follow-on design tickets filed from the Decomposition sketch” can now be checked:

    Exception, where applicable: any sketch item already answered by a later filing is noted in the pass worklog rather than duplicated. Design prioritisation is now independent per ticket; implementation timing is a separate decision.

  3. added
    work/assignedQueue worker lifecycle state
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    on Nov 5, 2026
  4. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: queue worker (repo-worker-code), lane code-g
    • Session / ID: task 10105
    • Found via: queue claim
    • Task: Triage issue id: design: ID transport fallback for UDP-denied networks v1 #5671 — assigned to the opencode execution lane; handing off to the opencode claimant, which launches the bound session. This lane did not work the task directly.
  5. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  6. developing-today commented on Nov 5, 2026

    @developing-today
    Contributor

    🤖 Agent note · handed off

  7. 5 remaining items

  8. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: handed off

  9. added
    source/queue-workerFiled or worked by the queue/worker pilot
    queue/claimedQueue worker lifecycle state
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 5, 2026
  10. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: picked up

  11. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    Triage findings — task 10105 (verified against current main, 2026-11-05)

    1. Keep id: design: ID transport fallback for UDP-denied networks v1 #5671 open. It is still the umbrella design for general ID transport fallback, not a duplicate of the SSH-specific id: Phase 13 F13.3 SSH-over-iroh reachability (and iroh-over-SSH fallback) #785 (now closed) or serverless-edition id: design: ID serverless edition v1 (Cloudflare Workers) #2046 (now closed). No parent-level PR supersedes it.
    2. The decomposition acceptance is met. All eight children id: design: transport negotiation & fallback ordering (from #5671) #5791–id: design: fleet surface for the broker role (from #5671) #5798 are filed. Two decision records have landed: id: design: transport negotiation & fallback ordering (from #5671) #5791 is closed after PR doc: transport negotiation & fallback ordering decision record (#5791) #6234 merged; id: design: Cloudflare Workers rendezvous/relay component (from #5671) #5794 is closed after PR doc: decision record for Cloudflare Workers rendezvous/relay component (#5794) #6260 merged (freshly merged 2026-11-05T15:55Z).
    3. Remaining child work is not done, so the parent synthesis must wait. id: design: id broker / serve-proxy role (from #5671) #5792, id: design: rendezvous & discovery for UDP-denied clients (from #5671) #5793, id: design: relay trust model & broker authorization (from #5671) #5795, id: design: HTTP CONNECT proxy traversal (from #5671) #5796, id: design: latency budget & measurement plan per fallback tier (from #5671) #5797, and id: design: fleet surface for the broker role (from #5671) #5798 remain open. In the fresh issue state, id: design: relay trust model & broker authorization (from #5671) #5795 and id: design: latency budget & measurement plan per fallback tier (from #5671) #5797 are parked and id: design: HTTP CONNECT proxy traversal (from #5671) #5796 is blocked; id: design: id broker / serve-proxy role (from #5671) #5792 and id: design: fleet surface for the broker role (from #5671) #5798 are triaged, while id: design: rendezvous & discovery for UDP-denied clients (from #5671) #5793 still needs its first triage. Preserve those child owners/states; do not create a competing parent PR or duplicate child tasks.
    4. Next ordering: let the child decision records resolve fallback negotiation, broker/relay shape, rendezvous, trust, CONNECT traversal, latency, and fleet surface; then synthesize their decisions into id: design: ID transport fallback for UDP-denied networks v1 #5671 against its existing acceptance. The existing child tickets are the follow-up work, so this triage does not enqueue another duplicate queue task.
    5. No source changes or code tests were applicable. The parent is waiting on its decomposed design inputs, not on a new Drew-only decision.
  12. dezren39 commented on Nov 5, 2026

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

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)kind/designA design proposal (design-architect): multi-step, phased, decision-bearingsource/creatorFiled by the new-issue-creator jobsource/queue-workerFiled or worked by the queue/worker pilotstatus/waiting-dependencyWaiting on a dependencytask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions