Skip to content

feat(acceptor): negotiate the MCS message channel#1347

Open
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/acceptor-mcs-message-channel
Open

feat(acceptor): negotiate the MCS message channel#1347
Greg Lamberson (glamberson) wants to merge 1 commit into
Devolutions:masterfrom
lamco-admin:feat/acceptor-mcs-message-channel

Conversation

@glamberson
Copy link
Copy Markdown
Contributor

The acceptor never advertised support for Extended Client Data Blocks, so a
spec-compliant client withheld its Client Message Channel Data and the MCS
message channel was never negotiated. Server-initiated PDUs that must ride the
message channel per MS-RDPBCGR (network auto-detect in section 2.2.14,
multitransport bootstrap, heartbeat) therefore had no transport.

This change:

  • Sets the EXTENDED_CLIENT_DATA_SUPPORTED flag in the RDP Negotiation Response
    so the client sends Client Message Channel Data (section 2.2.1.3.7).
  • When the client requests the message channel, allocates an MCS channel ID for
    it after the I/O channel and any static virtual channels, and returns it in
    Server Message Channel Data (section 2.2.1.4.5).
  • Joins the message channel during the MCS channel join phase (skipped when the
    client advertises SUPPORT_SKIP_CHANNELJOIN).
  • Surfaces the allocated ID on AcceptorResult so a server can route the PDUs
    that ride this channel.

The immediate consumer is server-side network auto-detect, which a follow-up
will frame correctly and route over this channel. AcceptorResult gains a
message_channel_id field, mirroring the additive shape of the credentials field
added in #1155.

Tested in crates/ironrdp-testsuite-core/tests/server/acceptor.rs: the test
drives the acceptor to the ConnectResponse and asserts Server Message Channel
Data is advertised with the allocated ID, plus the EXTENDED_CLIENT_DATA_SUPPORTED
flag on the connection confirm.

Set the EXTENDED_CLIENT_DATA_SUPPORTED flag in the RDP Negotiation
Response so the client sends Client Message Channel Data (section
2.2.1.3.7). When the client requests the message channel, allocate an MCS
channel ID for it after the I/O channel and any static virtual channels,
return it in Server Message Channel Data (section 2.2.1.4.5), and add it
to the set of channels joined during the MCS channel join phase.

The allocated ID is surfaced on AcceptorResult so the server can route
PDUs that ride the message channel. The immediate consumer is server
network auto-detect (section 2.2.14); the channel is also the transport
for multitransport bootstrap and heartbeat. Previously the acceptor never
advertised the channel, so a spec-compliant client withheld its Client
Message Channel Data and these features had no transport.
Copy link
Copy Markdown
Member

@CBenoit Benoît Cortier (CBenoit) left a comment

Choose a reason for hiding this comment

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

LGTM!

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the server-side acceptor handshake to properly negotiate the MCS message channel by advertising Extended Client Data Blocks support and, when requested by the client, allocating/joining the message channel and surfacing its ID in AcceptorResult. This enables server-initiated PDUs that must use the message channel (e.g., network auto-detect) to have a valid transport.

Changes:

  • Set EXTENDED_CLIENT_DATA_SUPPORTED in the RDP Negotiation Response so clients send Client Message Channel Data.
  • Allocate an MCS message channel ID when requested, advertise it via Server Message Channel Data, and join it during channel join (unless skip-join is negotiated).
  • Add tests asserting the extended-client-data flag and the presence of server message channel data with the allocated ID.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
crates/ironrdp-acceptor/src/connection.rs Advertises extended client data support, allocates/joins message channel, and exposes message_channel_id on AcceptorResult.
crates/ironrdp-testsuite-core/tests/server/acceptor.rs Adds coverage for negotiation flags and Server Message Channel Data advertisement/ID allocation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +476 to +479
let channel_count = u16::try_from(channels.len()).ok();
self.message_channel_id =
channel_count.and_then(|n| self.io_channel_id.checked_add(n)?.checked_add(1));
}
Comment on lines +142 to +147
let message_channel = server_blocks
.message_channel
.as_ref()
.expect("acceptor must advertise Server Message Channel Data");
assert_eq!(message_channel.mcs_message_channel_id, 1004);
}
Comment on lines 42 to 56
#[derive(Debug)]
pub struct AcceptorResult {
pub static_channels: StaticChannelSet,
pub capabilities: Vec<CapabilitySet>,
pub input_events: Vec<Vec<u8>>,
pub user_channel_id: u16,
pub io_channel_id: u16,
/// MCS channel ID of the message channel, present when the client requested
/// one via Client Message Channel Data (section 2.2.1.3.7).
///
/// Server-initiated PDUs that ride the message channel (network auto-detect
/// per section 2.2.14, multitransport bootstrap, heartbeat) are sent on this
/// channel. `None` when the client did not request it.
pub message_channel_id: Option<u16>,
pub reactivation: bool,
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.

3 participants