feat(tunnel): land the -R listen flow + the forwarded-tcpip data leg (w3-tunnel-listen)
The tunnel branch's other half is served for real against published alktunnels 0.4.1 / alkcall 0.10.1, with POC-3 §C.4 as the template: - tcpip_forward/streamlocal_forward (+ both cancel forms) map the vanilla listen request family-ward through TunnelListener::open on the held ChannelClient (bounded inline dial — the global request's reply + the &mut u32 bound-port out-param are the hook's); the wire bind endpoint rides as the resource string verbatim (OpenSSH client-side normalization parity). A reply without the minted listen token/bound report declines and reaps its fabric listener. - the door serves the fabric's inbound tunnel/forwarded opens: the serve config gains TunnelListenSeam (the seam-config second course-correction — the shared ServingConfig registry the assembly wired at from_connection_with_serving); alkssh registers the forwarded openable (ChannelCore over a clone of the held client's manager) at SshAdapter::new — a failed registration is a failed construction (AdapterError::ListenRegistration). - the forwarded-tcpip data leg: token correlation through the shared ListenRouter → the in-crate per-session channel cap at the accept surface (the acceptor vocabulary) → Handle:: channel_open_forwarded_tcpip streaming the listen request's own args + the actually-bound port (sshd parity) with TunnelForwardedParams.peer as the originator → pump_bidi(ssh, fabric). Correlation-miss → teardown-at-birth, never a half-open SSH channel. Unix arrivals ride forwarded-streamlocal@openssh.com. - bounded bookkeeping: the per-session listener map packet-loop-only with a dedicated max_concurrent_channels-ceiling counter; the route map bounded by construction (mints at accepted listens, removed at cancels + session teardown — the handler's Drop). - the harness grew the client-side accept hook (server_channel_open_forwarded_tcpip/_streamlocal, acceptor-driven) + a hand-rolled tracing subscriber; 18 contract rows + both real-tool smokes (ssh -L, ssh -R + curl) green in tests/tunnel_mapping.rs; the wave-2 stub listen rows migrated per build (unfeatured / seam-unconfigured). Verified: cargo test across default/git/session/sftp/tunnel and all combos + --all-features; clippy -D warnings (default, all-features, combos); cargo fmt --check; cargo doc --no-deps clean; taskgraph validate (26 tasks).
This commit is contained in:
1 parent
6443feac3e
commit
3d0253d981
15 files changed
+2839
-236
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: w3-tunnel-listen
|
||||
name: Wave 3 — tunnel leg 2 (the -R listen flow + the forwarded-tcpip data leg)
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: [w3-tunnel-direct]
|
||||
scope: moderate
|
||||
risk: high
|
||||
@@ -87,24 +87,24 @@ target):
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `tcpip_forward` / `streamlocal_forward` (+ cancel forms) carry
|
||||
- [x] `tcpip_forward` / `streamlocal_forward` (+ cancel forms) carry
|
||||
the real mapped flow under `tunnel` (+ the runtime-Unix gate
|
||||
where it binds); decline classes keep their wire shapes
|
||||
- [ ] The family-ward listen composition decided against alktunnels
|
||||
- [x] The family-ward listen composition decided against alktunnels
|
||||
0.4.1's actual surfaces and recorded; the door-side inbound-open
|
||||
mechanics closed (or a serve-config amendment landed + recorded;
|
||||
or stopped-and-booked for the gate — nothing silent)
|
||||
- [ ] The `forwarded-tcpip` data leg serves per the handler shape
|
||||
- [x] The `forwarded-tcpip` data leg serves per the handler shape
|
||||
(target-arg echo per pending listen, cap-gated acceptor, the
|
||||
pump, teardown-at-birth on correlation-miss)
|
||||
- [ ] The per-session listener bookkeeping bounded; the bound-port
|
||||
- [x] The per-session listener bookkeeping bounded; the bound-port
|
||||
out-param returns the actually-bound number
|
||||
- [ ] The per-build decline-matrix rows green through the harness with
|
||||
- [x] The per-build decline-matrix rows green through the harness with
|
||||
the client-side accept hook in place (the wave-2 gate's booked
|
||||
harness item discharged)
|
||||
- [ ] The real-tool smoke posture decided + recorded; the wave-2 stub
|
||||
- [x] The real-tool smoke posture decided + recorded; the wave-2 stub
|
||||
listen rows migrated
|
||||
- [ ] `cargo test` (+ per-feature + `--all-features` rows), clippy ×2
|
||||
- [x] `cargo test` (+ per-feature + `--all-features` rows), clippy ×2
|
||||
(`-D warnings`), fmt, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
@@ -132,4 +132,128 @@ target):
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
**Landed.** The `-R` leg is served for real: the listen flow
|
||||
(`tcpip_forward`/`streamlocal_forward` + cancel forms under `tunnel`)
|
||||
and the `forwarded-tcpip`/`forwarded-streamlocal` data leg, verified
|
||||
against the published alktunnels 0.4.1 / alkcall 0.10.1 surfaces
|
||||
through the harness and (tooling present) a real OpenSSH `ssh -R`
|
||||
smoke. 18 server-direction rows + 2 real-tool smokes green in
|
||||
`tests/tunnel_mapping.rs`.
|
||||
|
||||
- **The composition decisions (recorded in `src/tunnel_map.rs`'s
|
||||
module doc + `mapping.md` §Global-request rows):**
|
||||
- *Who dials `tunnel/forwarded`*: the fabric (not the door) —
|
||||
alktunnels' bind-first accept dispatcher
|
||||
(`make_bindfirst_accept_handler` + the `ForwardedOpener` closure)
|
||||
dials the op on the channel-0 call plane toward the listen opener
|
||||
per arrival; the door reply carries the door-allocated channel id
|
||||
the producer adopts (alkcall's odd/even split keeps the two open
|
||||
directions collision-free: the door allocates odd as the connect
|
||||
side, the fabric even as the accept side).
|
||||
- *The door-side inbound-open mechanics*: closed over the published
|
||||
surfaces — the `Arc<ChannelClient>` alone cannot carry them (a
|
||||
client serves inbound ops on its channel-0 loop only when built
|
||||
with `from_connection_with_serving` against an `OperationRegistry`
|
||||
the assembly owns; no post-construction way in) — so the
|
||||
serve-config's tunnel handle gained `tunnel_listen_seam`
|
||||
(`TunnelListenSeam`, the wave-3 seam-config's second
|
||||
course-correction): the same `Arc<OperationRegistry>` the assembly
|
||||
wired into the leg's `ServingConfig`. alkssh registers the
|
||||
forwarded openable itself (`register_tunnel_forwarded_openable`
|
||||
over a `ChannelCore` wrapping a clone of the held client's
|
||||
manager, alkcall's secure default per-identity policy) at
|
||||
`SshAdapter::new` — a registration failure is a failed
|
||||
construction (`AdapterError::ListenRegistration`), never a
|
||||
half-configured adapter. A scratch probe (published crates only,
|
||||
no `alktunnels/local`) proved the topology end to end before any
|
||||
of this landed: door-side registration → fabric bind-first
|
||||
producer → arrival → `ForwardedHandler` (params + `BiStream`) →
|
||||
pump round trip, with the door's own pending calls still resolving
|
||||
while serving is enabled.
|
||||
- *The resource-naming convention (the flow's one open surface)*:
|
||||
the vanilla wire bind endpoint rides family-ward as the resource
|
||||
string verbatim (`"localhost:9200"` / `"0.0.0.0:9200"` / the
|
||||
socket path) — the OpenSSH client normalizes the no-address case
|
||||
to `"localhost"` before sending (sshd `channel_rfwd_bind_host`
|
||||
parity), the door passes through, and the fabric's
|
||||
establisher/bind closure (assembly policy — the dynamic-address
|
||||
producer opt-in the door's convention fronts) treats it as the
|
||||
bind endpoint. ADR-001's "resource is not an address" discipline
|
||||
stays a producer-side naming rule; this is a recorded door-to-
|
||||
fabric convention, not a wire change.
|
||||
- **The `forwarded-tcpip` data leg** (the row the POC only exercised
|
||||
as refusal): per arrival → token correlation through the shared
|
||||
`ListenRouter` (one route serves unboundedly many arrivals;
|
||||
removed only at the cancel forms/session teardown) → the in-crate
|
||||
per-session channel cap admits at the accept surface — the acceptor
|
||||
vocabulary's first shape, the wave-2 gate's booked item now
|
||||
discharged (never-established arrival paths release inside the
|
||||
arrival pump; established closes release through the packet loop's
|
||||
`channel_close` as ever) → `Handle::channel_open_forwarded_tcpip`
|
||||
echoing the listen request's own args: the wire address string
|
||||
verbatim + the actually-bound port (sshd `c->path` +
|
||||
`get_local_port` parity — the OpenSSH client matches that exact
|
||||
string + port and dials its own target), the
|
||||
`TunnelForwardedParams.peer` arrival mapped to the originator
|
||||
fields (HostPort → address/port; Path → path + 0,
|
||||
degenerate-but-typed) → `pump_bidi(ssh, fabric)` (half-close
|
||||
semantics: EOF-shutdown in the completed direction; the vanilla
|
||||
client closes its half when its target socket dies — the row's
|
||||
stand-in — and the cap release follows through the normal close).
|
||||
Correlation-miss → teardown-at-birth (drop the fabric half; the
|
||||
open op's channel reaps — never a half-open SSH channel). Unix
|
||||
arrivals (`streamlocal_forward` mints) open
|
||||
`forwarded-streamlocal@openssh.com` with the path echoed (russh's
|
||||
server `Handle` carries that channel-open at this pin; the client
|
||||
hook exists) — the "no russh hook" concern in the wave-2 stub notes
|
||||
was about the door's *inbound* handlers of that type, not the
|
||||
server-initiated direction.
|
||||
- **Bounded bookkeeping** (convention 9): the per-session listener
|
||||
map is packet-loop-only (like the `channels`/`ptys` stores); its
|
||||
bound is a dedicated counter against the same
|
||||
`max_concurrent_channels` ceiling — a listen is at least one future
|
||||
channel's potential; the listener/channels mix stays unconstrained
|
||||
while both stay bounded (no unbound listener map). The route map is
|
||||
bounded by construction: entries minted exactly at accepted listens,
|
||||
removed 1:1 at the cancels and at the owning session's teardown (the
|
||||
handler's `Drop`); a route to a dead handle only ever costs one
|
||||
failed open → teardown-at-birth. `cancel` of an unknown
|
||||
(endpoint, bound-port) pair answers `false` (sshd
|
||||
cancel-of-unknown parity). Admissions have two sites and releases
|
||||
three since this task — the cap's recorded single-writer reasoning
|
||||
updated in `channel_cap.rs` (mutex-guarded, saturating, both).
|
||||
- **The real-tool smoke**: implemented and green here (tooling
|
||||
check-gated like the -L smoke's posture): a real `ssh -R
|
||||
127.0.0.1:PORT:HTTP` (OpenSSH client) through the TCP-mounted
|
||||
adapter → the fabric double with a real bind → arrival → the
|
||||
forwarded-tcpip open → the client dials its own endpoint → curled
|
||||
body parity. Never silently dropped.
|
||||
- **The decline matrix** per build, all through the harness with the
|
||||
client-side accept hook in place (the harness handler's
|
||||
`server_channel_open_forwarded_tcpip` /
|
||||
`server_channel_open_forwarded_streamlocal`, acceptor-driven — no
|
||||
acceptor → clean decline, the family's client-side contract): the
|
||||
wave-2 stub listen rows migrated (`tcpip_forward_decline_emits_*`
|
||||
split per build: `unfeatured` vs `seam-unconfigured`); the
|
||||
featured + configured rows serve/arrive/cancel (incl. the port-0
|
||||
mint resolving into the `&mut u32` out-param and the echo); the
|
||||
unset listen seam declines while the egress bridge still routes
|
||||
(the row's control leg); the listener cap and the per-arrival
|
||||
channel cap rows (refusal + release proof); the composed-identity
|
||||
rows (the fabric-scope gate on the listen dial, the door-side ACL
|
||||
gate on arrivals); the OQ-11 off-Unix rows; the correlation-miss
|
||||
row; the unvanilla inbound `forwarded-tcpip` open declined
|
||||
(event-level contract — russh's client has no arbitrary-type open
|
||||
to drive that row on the wire).
|
||||
- **`tests/common` grew**: the forwarding acceptor
|
||||
(`ForwardedAcceptor` + `ForwardedOpen` + `drive_with_acceptor`)
|
||||
and a minimal hand-rolled tracing subscriber (`trace_global` — the
|
||||
family posture: no `tracing-subscriber` dependency; opted in per
|
||||
row) as the leg-2 rows' failure-triage vehicle.
|
||||
- **Verification (all green)**: `cargo test` across default /
|
||||
`tunnel` / `git` / `session` / `sftp` / `tunnel,git` /
|
||||
`tunnel,session` / `git,session` / `tunnel,sftp` / `git,sftp` /
|
||||
`--all-features`; `cargo clippy --all-targets -- -D warnings` ×2
|
||||
(default + `--all-features`) plus the combo builds (`tunnel,git` /
|
||||
`tunnel,session` / `tunnel,sftp`); `cargo fmt --check`; `cargo doc
|
||||
--no-deps` (0 warnings); `taskgraph validate` (26 tasks).
|
||||
Reference in new issue
Block a user