Skip to content

ohttp: websocket tunneling with relayed handshakes and opaque frames - #314

Open
imlk0 wants to merge 6 commits into
masterfrom
ohttp-ws
Open

imlk0 wants to merge 6 commits into
masterfrom
ohttp-ws

Conversation

@imlk0

@imlk0 imlk0 commented Nov 5, 2026

Copy link
Copy Markdown
Collaborator

Adds WebSocket tunneling to the ohttp mode.

The app's WebSocket upgrade is relayed hop by hop: the ingress appends the reserved tng-ohttp-ws subprotocol marker and forwards the request with its original Sec-WebSocket-Key, the egress strips only the marker and relays the same handshake to its mapped backend, and the backend's 101 comes back verbatim, so the app verifies the backend's own accept. Dispatch happens on the marker inside the egress's single header-dispatch handler; no URL path, query parameter, or new header value is introduced.

After the protocol switch the app's and backend's WebSocket frames are opaque bytes: the app hop and the backend hop are plain byte pipes, so client and backend may negotiate extensions (including compression) end to end, and the app's pings cross the tunnel like any other frame. Only the middle hop is a WebSocket connection of TNG's own, carrying the frame stream sealed with the fork's chunked record machinery (16 KiB chunks, the chunked body's AAD values, a final terminating chunk on stream end). Keys come from the tunnel's existing key-config and attestation flow: the request direction seals with the HPKE sender context, the response direction with the OHTTP response derivation from an in-stream nonce. The backend dial goes through the connection's upstream connector like every other protocol.

No new configuration. The middle hop can be TLS-protected with the existing ohttp.tls.

Docs: a new WebSocket over ohttp section in docs/protocols.md and its Chinese counterpart, plus the changelog entry. Tests: unit tests for the wire helpers, negotiation and relay paths, and e2e scenarios covering echo plus a plain-HTTP regression on the same listener, subprotocol passthrough, marker dispatch and the marker-less 403, backend- and app-initiated close, the RA (passport) rerun, and the TLS-protected middle hop.

Requires the ohttp fork's chunk session API (inclavare-containers/ohttp#2, merged into its tng branch at 99e254f).

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

imlk0 added 6 commits November 5, 2026 20:34
Dependency lines and lock entries (async-tungstenite with the rustls manual-roots feature for the tunnel's TLS hop, and the ohttp pin at the fork revision that carries the chunk session API), the WebSocket error variants, and the shared upgrade-detection helper. No behavior.

Assisted-by: Claude:glm-5.3
The tng-ohttp-ws marker helpers, backend-target resolution from the relayed request, and the hop-by-hop header filters both relay ends share. Pure helpers, no I/O.

Assisted-by: Claude:glm-5.3
Dispatch on the tng-ohttp-ws marker inside the single fallback handler, relay the app's handshake to the backend verbatim (only the marker is stripped), answer the backend's 101 as relayed, and negotiate the session keys from the first in-stream control message after the same AEAD suite allowlist check the body path applies. The app's raw frame bytes then cross the fork's chunked record stream, and the backend dial goes through the connection's upstream connector like every other protocol; any failure tears both hops down.

Assisted-by: Claude:glm-5.3
Relay the app's websocket upgrade with the tng-ohttp-ws marker appended, build the session crypto from the key store's policy-selected config and suite, and carry the app's raw frame bytes both ways over the fork's chunked record stream: the uplink seals immediately, the downlink keys only after the response nonce arrives. The ws client cache entry is keyed by a fixed path so one endpoint shares a single OHTTP client.

Assisted-by: Claude:glm-5.3
The proxy-capable ws test client and echo server, and the e2e scenarios: echo plus the plain-HTTP regression on the same listener, subprotocol passthrough, marker dispatch and the marker-less 403, backend-initiated and app-initiated close, the RA (passport) rerun, and the TLS-protected middle hop.

Assisted-by: Claude:glm-5.3
Add a WebSocket over ohttp section to both language versions of docs/protocols.md: the hop-by-hop relayed handshake and the tng-ohttp-ws marker semantics, the in-stream key negotiation, the opaque frame data plane carried in chunked record streams, the state machines, and the lifecycle and usage budget. Record the WebSocket exception in the roles section and add the changelog entry.

Assisted-by: Claude:glm-5.3
@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,您的请求已接收,请耐心等待结果。

@ostest-bot

Copy link
Copy Markdown

@imlk0 ,您好,未检测到有镜像需要构建,如需重新检测请评论 /start 。

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants