Skip to content

Transparent-tunneling consumer shape (wasi:sockets@0.3 virtualizer): resumption surface and wire-order notes #14

Description

@lann

Exploratory design analysis, recorded so the pattern and its two enhancement candidates aren't rediscovered. The consumer shape: a component virtualizing wasi:sockets@0.3, adding TLS transparently to apps that speak plain TCP —

  • hostname resolution is interposed; on the return path the (address, hostname) pair goes into a table and the app receives a handle encoded as a reserved IP address;
  • on connect to a reserved address, the virtualizer connects to the real address via host sockets and drives a TLS handshake with the real hostname (SNI + verification);
  • traffic is tunneled through the TLS connection.

What already fits (no changes needed)

  • The transform-pair shape makes the virtualizer a plumber, not a pumper: real receive stream → connector.receive → cleartext stream → app, and connector.send → ciphertext stream → real send, are all direct handle passes. Same p3 substrate as wasi:sockets@0.3 — this consumer is what the component-model-async substrate ruling bought.
  • The resolve-table trick is fully outside lann:tls: its product (the real hostname) is exactly what connect(server-name, …) consumes. Trust stays deployment-configured via constructor roots; algorithms stay non-configurable.
  • Close semantics map with fidelity: app-side stream drop → close_notify → real send closes, and the direction futures distinguish clean TLS close from transport truncation, so the virtualizer can surface RST-vs-FIN honestly.
  • The acceptor side is symmetric if inbound termination is ever wanted.

Candidate 1 (real): a session-resumption / shared-context surface

A connector is per-connection with a fresh config, so a consumer tunneling many connections to the same host performs a full handshake every time (and re-parses roots per connector). Any high-fan-out consumer hits this, virtualizer or not. The enhancement is a shared-session-context surface — a connector factory or an explicit resumption-cache resource — designed so it adds no algorithm-configuration surface. Needs a WIT design ruling (resource lifecycle, cache scoping/isolation between trust domains, and what a ticket-reuse contract promises about verification).

  • Design ruling recorded in wit/README
  • Implementation + composed smoke coverage

Candidate 2 (maybe): relax the wire-before-handshake contract

Sockets call-order (connect first, streams later, possibly only one direction) vs. the package contract (send/receive wired exactly once, before the handshake call) forces the virtualizer to wire connector.send with a self-owned pipe and splice the app's stream in when it arrives — one small pump task per connection, send direction only. Relaxing the contract (allow wiring after connect, with component-internal buffering) would remove that task at the cost of buffering complexity and a weaker lifecycle story. The pipe pattern is adequate; revisit only if a second consumer hits the same seam.

Deliberately not asked for

  • The virtualizer itself (a consumer, not this package).
  • Transparent mTLS: client identity is not on the WIT surface (raw-public-key mutual auth is curated-Rust-only per the Raw-public-key (RFC 7250) identities and mutual authentication for the profile #12 ruling); a virtualizer needing client certificates is a separate design conversation.
  • TLS-failure→socket-error-code vocabulary narrowing: inherent to transparent virtualization.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions