Skip to content

fix(server): recognize the Initiate Multitransport Response on the message channel - #1964

Merged
Marc-André Moreau (mamoreau-devolutions) merged 3 commits into
Devolutions:masterfrom
lamco-admin:fix/multitransport-response-dispatch
Sep 28, 2026
Merged

Marc-André Moreau (mamoreau-devolutions) merged 3 commits into
Devolutions:masterfrom
lamco-admin:fix/multitransport-response-dispatch

Conversation

@glamberson

@glamberson Greg Lamberson (glamberson) commented Sep 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

handle_message_channel_data unconditionally decoded every PDU received on the MCS message channel as an AutoDetectRspPdu, per a comment claiming the channel "currently carries only the auto-detect response." That is no longer accurate: once a server sends an Initiate Multitransport Request, the client answers on this same channel with an Initiate Multitransport Response (MS-RDPBCGR 2.2.15.2) to report whether it could establish the sideband transport.

MultitransportResponsePdu already has full Encode/Decode support in ironrdp-pdu (with success()/abort() constructors), but has zero consumers anywhere in ironrdp-server. In practice every such response from a real client failed to decode as AutoDetectRspPdu (its securityHeader carries SEC_TRANSPORT_RSP, not SEC_AUTODETECT_RSP) and was dropped with an "Unhandled MCS message channel PDU" warning: legitimate protocol traffic logged as an error.

Reproduced against a real Windows client (mstsc) that offered UDP multitransport but could not establish it: the raw bytes it sent decode exactly as MultitransportResponsePdu { security_header: TRANSPORT_RSP, request_id, hr_response: E_ABORT }.

Changes

  • Added ironrdp_pdu::rdp::message_channel::ClientMessageChannelPdu, an enum with Encode/Decode covering the two PDUs a client sends on this channel. Decode peeks at the Basic Security Header flags and dispatches: SEC_TRANSPORT_RSP to MultitransportResponsePdu, anything else to AutoDetectRspPdu, so a malformed PDU is reported against the type its header names.
  • handle_message_channel_data decodes that type and has a Multitransport arm that logs the response at debug level (ordinary protocol traffic, not an error), with the same wording the acceptor uses for this PDU, instead of falling through to the warn!.
  • Six tests in ironrdp-testsuite-core (tests/pdu/message_channel.rs): recognition of both PDUs, a round trip, a truncated transport response reported as one, a payload without SEC_TRANSPORT_RSP handed to the auto-detect decoder, and too-short input.

Test plan

cargo xtask check fmt/lints/tests/typos/locks all pass.

@github-actions github-actions Bot added kind/protocol Affects RDP or related protocol behavior risk/medium Behavioral change that does not substantially alter a core public API size/S Size: up to 199 counted lines and 5 files; exceeds XS in either measure triage/overlap Possible overlap with another pull request; advisory only needs-review A human reviewer is the current next actor labels Sep 13, 2026
@glamberson

Greg Lamberson (glamberson) commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Adding detail:

I reproduced this independently today from a different client while testing an unrelated encoder issue. Raw bytes: 04 00 00 00 b9 22 37 e0 00 00 00 00, decoding to MultitransportResponsePdu { security_header: TRANSPORT_RSP, request_id: 0xe03722b9, hr_response: S_OK }. This is the first case I have seen with hr_response=S_OK rather than E_ABORT: the same decode gap drops a successful Initiate Multitransport Response exactly the same way it drops a failed one, so the impact is not limited to the failure path described above.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Malformed multitransport responses currently surface misleading auto-detect decode errors.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Recognizes multitransport responses received on the server’s MCS message channel.

Changes:

  • Adds message-channel PDU dispatch.
  • Handles and logs multitransport outcomes.
  • Adds decoding regression tests.
File Description
crates/​ironrdp-server/​src/​server.rs Adds multitransport response handling and tests.

Comment thread crates/ironrdp-server/src/server.rs Outdated
…ssage channel

handle_message_channel_data unconditionally decoded every PDU on the
MCS message channel as an AutoDetectRspPdu, per a comment claiming the
channel "currently carries only the auto-detect response". That's no
longer accurate: once a server sends an Initiate Multitransport
Request, the client answers on this same channel with an Initiate
Multitransport Response (MS-RDPBCGR 2.2.15.2) if it could not
establish the sideband transport. MultitransportResponsePdu already
has full Encode/Decode support in ironrdp-pdu, but had zero consumers
anywhere in ironrdp-server, so every such response failed to decode
(its securityHeader carries SEC_TRANSPORT_RSP, not SEC_AUTODETECT_RSP)
and was dropped as an "Unhandled MCS message channel PDU" warning
instead of being recognized as the ordinary protocol traffic it is.

Extracted the dispatch into decode_message_channel_pdu, tried against
both PDU types (auto-detect first, since it is by far the more common
one) instead of just one, and given handle_message_channel_data a
proper Multitransport arm that logs success/failure at debug level
instead of warning on legitimate input.
@glamberson
Greg Lamberson (glamberson) force-pushed the fix/multitransport-response-dispatch branch from 51c10be to 05ccafa Compare September 22, 2026 22:30
@github-actions github-actions Bot added risk/low Self-contained change with no cross-crate behavioral effect and removed risk/medium Behavioral change that does not substantially alter a core public API triage/overlap Possible overlap with another pull request; advisory only needs-review A human reviewer is the current next actor labels Sep 22, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR correctly extends MCS message-channel handling to recognize the Client Initiate Multitransport Response alongside auto-detect responses. Independently verified: AutoDetectRspPdu::decode requires flags to contain SEC_AUTODETECT_RSP (0x2000) while MultitransportResponsePdu::decode masks RESET/IGNORE_SEQNO and requires flags to equal SEC_TRANSPORT_RSP (0x0004), so the two decodes are mutually exclusive and the fallback ordering is safe; previously every multitransport response was dropped as an 'Unhandled' warning. Logging-only handling with the session continuing on the main transport matches MS-RDPBCGR 2.2.15.2/3.3.5.15.2, and surfacing the auto-detect error on double failure is sensible and tested. Three new tests cover both decode paths and the error case. Only a low-severity optional cosmetic compression candidate remains; refined before publishing.

Comment thread crates/ironrdp-server/src/server.rs Outdated
@github-actions github-actions Bot added the ai-reviewed/1 One automated review completed label Sep 22, 2026
…dp-pdu

Moves the MCS message-channel demux into ironrdp-pdu as
ClientMessageChannelPdu, which dispatches on the Basic Security Header
flags so a malformed Initiate Multitransport Response is reported as
one rather than as a failed auto-detect decode. Its tests live in
ironrdp-testsuite-core; the ones previously added inline in
ironrdp-server never ran there. The server logs the response once, in
the acceptor's wording.
@github-actions github-actions Bot added risk/high Substantial core public API impact, or fail-closed triage; needs maintainer-level scrutiny scope/core Touches the core architectural tier triage/overlap Possible overlap with another pull request; advisory only and removed risk/low Self-contained change with no cross-crate behavioral effect labels Sep 23, 2026
@github-actions

github-actions Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

This pull request may overlap with #1954.

Both PRs concern the server side of the UDP multitransport exchange on the MCS message channel. This PR decodes the client's Initiate Multitransport Response (MS-RDPBCGR 2.2.15.2) in ironrdp-server's handle_message_channel_data, and #1954 wires UDP multitransport into ironrdp-server, including the Initiate Multitransport Request flow and sideband transport setup. They appear to share the server's handling of that message-channel exchange; a human should assess how the two pieces fit together.

This notice is advisory only. Automated review continues as usual, and how these pull requests relate is for maintainers and authors to decide.

Note

LLM-assisted content (no human feedback).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR correctly fixes the server dropping client Initiate Multitransport Responses: a flag-dispatched ClientMessageChannelPdu is added in ironrdp-pdu and server.rs now handles the new variant, preserving auto-detect behavior; protocol review found no defect. Two low-severity skeptical findings are published: the speculative #[non_exhaustive] on a spec-complete two-variant enum, and the unreachable Ok catch-all warn arm it forces in server.rs. The contains-based dispatch finding was rejected: the inner MultitransportResponsePdu decoder enforces the masked-equality flag check, so dispatch-on-contains cannot mis-accept traffic, the existing decode_io_channel demux uses the same contains idiom, and AutoDetectRspPdu::decode itself uses contains; residual impact is limited to incomplete error attribution on malformed doubly-flagged input. The code-compressor specialist failed and required no dispositions.

Reduced coverage: optional reviewer code-compressor was unavailable.

Comment thread crates/ironrdp-pdu/src/rdp/message_channel.rs
Comment thread crates/ironrdp-server/src/server.rs Outdated
@github-actions github-actions Bot added ai-reviewed/2 Final automated review completed and removed ai-reviewed/1 One automated review completed labels Sep 23, 2026
MS-RDPBCGR fixes the client-to-server message channel to these two
PDUs, and ironrdp-pdu's dispatch enums are exhaustive, so the attribute
only forced an unreachable catch-all arm in the server. Both removed.
@github-actions github-actions Bot added the needs-review A human reviewer is the current next actor label Sep 23, 2026
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 25, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 25, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.
@mamoreau-devolutions
Marc-André Moreau (mamoreau-devolutions) merged commit 6aebe6d into Devolutions:master Sep 28, 2026
41 checks passed
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 28, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 28, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 28, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.
Greg Lamberson (glamberson) added a commit to lamco-admin/IronRDP that referenced this pull request Sep 29, 2026
Windows clients answer the Initiate Multitransport Request with E_ABORT
about 2.7 s after connecting, after finalization has completed, so the
earlier check never saw it and the accept still ran to its 15 s timeout.
Now built on Devolutions#1964, which decodes that late response on the message
channel: keep the pending accept's abort handle and stop the accept when
the response reports failure, and report a cancelled accept as a decline
rather than a panic.

This branch was successfully deployed

1 active deployment
llm-providers — 813bead3 Deployed Sep 23, 2026 by glamberson via Classify pull request #601
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-reviewed/2 Final automated review completed kind/protocol Affects RDP or related protocol behavior needs-review A human reviewer is the current next actor risk/high Substantial core public API impact, or fail-closed triage; needs maintainer-level scrutiny scope/core Touches the core architectural tier size/S Size: up to 199 counted lines and 5 files; exceeds XS in either measure triage/overlap Possible overlap with another pull request; advisory only

Development

Successfully merging this pull request may close these issues.

3 participants