Skip to content

feat(connector): Hyper-V vmconnect support#1475

Draft
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 5 commits into
fix/bulk-compression-reactivationfrom
feat/vmconnect
Draft

feat(connector): Hyper-V vmconnect support#1475
irvingouj@Devolutions (irvingoujAtDevolution) wants to merge 5 commits into
fix/bulk-compression-reactivationfrom
feat/vmconnect

Conversation

@irvingoujAtDevolution

Copy link
Copy Markdown
Contributor

Stacked on #1474 — review that one first, this diff is only the vmconnect part.

Lets you connect to a Hyper-V VM console. Same RDP steps as usual, the host just wants the front in a different order: Preconnection Blob with the VM id → TLS → CredSSP → X.224 last. That's the Direct Approach, and since NLA already ran by then the host has to select exactly PROTOCOL_HYBRID.

ClientConnector::new_vmconnect(..) picks the ordering, ConfigBuilder::with_vmconnect(vm_id) on the client side.

The bit I'd like eyes on: the whole difference between the two orderings sits in one Front enum — where we start, what X.224 advertises, what selected protocol we accept, and where negotiation/NLA each hand over. after_initiation and after_credssp are mirrors of each other, because whichever runs last is the one handing over to Basic Settings. Only one new state (SendPreconnectionBlob); both orderings share the existing X.224 initiation states. Tail is untouched and the existing drivers run it as-is.

No API break — ClientConnectorState is already #[non_exhaustive] and the FFI getters all have catch-all arms.

Still missing (why it's a draft)

  • no unit test for the new ordering yet
  • nothing in-tree can trigger it (no --vm-id on ironrdp-viewer, not wired to .rdp props), so today only a library embedder like RDM can reach it

Testing

Ran the real RdpClient against my local Hyper-V host, all 7 running lab VMs, default config (compression on) — every one negotiated HYBRID and rendered. Also drove Ctrl+Alt+Del in and watched the VM's own console change from the host side, so input round-trips.

Standard RDP to a Windows Server VM still fine (both orderings share the X.224 states now, so that was the thing to not break).

clippy/check clean on connector, client, web wasm32, ffi. fmt clean. testsuite-core 949, testsuite-extra 21.

A Hyper-V VM console speaks plain RDP, but the host expects the front of the
connection in a different order: a Preconnection Blob carrying the VM id first,
then TLS, then CredSSP, and the X.224 negotiation last. This is the Direct
Approach, where the host must select exactly PROTOCOL_HYBRID because NLA has
already run by the time X.224 happens.

`ClientConnector::new_vmconnect(..)` selects that ordering. The whole difference
between the two orderings lives in one place, the `Front` enum: where the
sequence starts, what X.224 advertises, which selected protocol is acceptable,
and where the negotiation and NLA each hand over. `after_initiation` and
`after_credssp` are mirror images, since whichever of the two runs last is the
one that hands over to the Basic Settings Exchange.

Only one state is added, `SendPreconnectionBlob`; both orderings share the
existing X.224 initiation states. Everything from the Basic Settings Exchange
onward is untouched, so the async and blocking drivers run the new ordering
exactly like a standard connection.
`ConfigBuilder::with_vmconnect(vm_id)` points the client at a Hyper-V VM console
instead of a normal RDP host. The Direct transport builds the connector with
`new_vmconnect(..)` when a VM id is set, so the connection runs the Hyper-V
ordering and then rejoins the shared sequence; no transport-specific plumbing is
needed.
Address review feedback on the reactivation fix: link the spec section from
`reactivate`, stop `set_share_id` from claiming it must be called during a
Deactivation-Reactivation Sequence (it no longer does), and warn on
`set_fastpath_processor` that a hand-built processor is how bulk decompression
gets silently dropped. The FFI method keeps its name for ABI compatibility, so
say what it actually does now.
…eview

A gateway or RDCleanPath proxy performs the X.224 connection initiation itself,
which the Hyper-V ordering moves to after authentication. Combining them left
RDCleanPath failing deep in the handshake with "invalid connector state"; the
builder now rejects it up front.

Review fixes: lowercase error messages per STYLE.md, "VM ID" casing,
`PreconnectionBlobSendRequest` to match the `<Phase><Action>` naming of the
sibling states, `HYPERV_SECURITY_PROTOCOL` made private (nothing outside the
crate consumes it), a spec section number on its doc link, the stale "shared by"
doc on `decode_connection_confirm` corrected along with its unused return
component, and the trimmed comments now say why rather than what.
Pins the Hyper-V ordering (preconnection blob carrying the VM ID, then TLS and
NLA, then the X.224 negotiation, then the shared tail) and the requirement that
the host select plain HYBRID. Both orderings share the X.224 initiation states
now, so the standard path is covered here too: negotiation first, and a protocol
the client never advertised is refused.

Also document that a Hyper-V console ignores the TLS and NLA config flags, and
why the preconnection blob names a protocol before anything is negotiated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant