Skip to content

feat(server): send the Server Auto-Reconnect Cookie during logon#1405

Open
clintcan wants to merge 2 commits into
Devolutions:masterfrom
clintcan:feat/server-auto-reconnect-cookie
Open

feat(server): send the Server Auto-Reconnect Cookie during logon#1405
clintcan wants to merge 2 commits into
Devolutions:masterfrom
clintcan:feat/server-auto-reconnect-cookie

Conversation

@clintcan

@clintcan clintcan commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What

Adds an optional Server Auto-Reconnect Cookie (MS-RDPBCGR 2.2.4.3 ARC_SC_PRIVATE_PACKET) to ironrdp-server. When set, RdpServer sends a Save Session Info PDU (LogonExtended + AUTO_RECONNECT_COOKIE) carrying it once per connection, right after activation (Confirm Active processed, encoder built), on the IO channel.

Why

A client only enters its automatic reconnection sequence (MS-RDPBCGR 1.3.1.5) on an ungraceful disconnect if it was handed this cookie during logon. Without it, a dropped connection just reports as disconnected — mstsc in particular won't auto-reconnect at all. Today ironrdp-server never sends the cookie, so there's no way for a server to opt into that behavior.

The concrete use case: a server that intentionally drops a connection and expects the client to come straight back — e.g. a recovery path that cycles the session — currently forces the user to reconnect by hand. With the cookie provisioned, the client re-establishes on its own (re-authenticating via NLA/CredSSP from cached credentials). It's also just standard behavior a real RDP server provides.

API

Mirrors the existing credential_validator pattern exactly — a builder method plus a runtime setter:

// build time
RdpServer::builder()
    .with_auto_reconnect_cookie(Some(ServerAutoReconnect { logon_id, random_bits }))
    // ...

// or dynamically
server.set_auto_reconnect_cookie(Some(cookie));

ServerAutoReconnect (already public in ironrdp-pdu::rdp::session_info) carries a logon_id and a 16-byte random_bits (generate from a CSPRNG). A per-connection guard (auto_reconnect_sent, reset in run_connection_with) sends it exactly once — not again on a Deactivation-Reactivation.

Scope / additive

  • Additive, non-breaking. Default is None (send nothing); existing servers are byte-for-byte unaffected.
  • All PDU types already exist in ironrdp-pdu (rdp::session_info::{SaveSessionInfoPdu, LogonInfoExtended, LogonExFlags, ServerAutoReconnect, InfoType, InfoData}) — this is purely wiring the server-side send.
  • Reuses the existing encode_share_data_pdu helper.

Design point for review — the returning cookie

This PR implements the send side only: it enables the client's automatic reconnection. It does not validate the ARC_CS_PRIVATE_PACKET the client sends back on reconnect (MS-RDPBCGR 2.2.4.4). For a server that re-authenticates every connection by other means (NLA/CredSSP) that's sufficient and safe, and it's documented as such on the setter. If you'd prefer the crate to also offer validation of the returning cookie (so it can be an authentication factor — the server would store issued (logon_id, random_bits) and verify the client's SecurityData/ARC_CS on the next connect), I'm happy to do that as a follow-up, or fold it in here — it's a larger, stateful feature so I kept this PR to the send path. Let me know which you'd prefer.

Built + clippy --features egfx -D warnings clean; tests compile.

Copilot AI left a comment

Copy link
Copy Markdown

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 adds optional support in ironrdp-server for sending a Server Auto-Reconnect Cookie (MS-RDPBCGR 2.2.4.3 ARC_SC_PRIVATE_PACKET) to the client via a Save Session Info PDU immediately after activation, enabling clients (notably mstsc) to perform the automatic reconnection sequence after an ungraceful disconnect.

Changes:

  • Add auto_reconnect_cookie configuration (builder + runtime setter) to RdpServer.
  • Send SaveSessionInfoPdu(LogonExtended + AUTO_RECONNECT_COOKIE) once per connection after activation, guarded to avoid re-sending on Deactivation–Reactivation.
  • Wire the new builder option through RdpServerBuilder::build().

Reviewed changes

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

File Description
crates/ironrdp-server/src/server.rs Stores an optional cookie and emits the Save Session Info PDU once per connection after activation.
crates/ironrdp-server/src/builder.rs Adds a builder option to provision the cookie and applies it during build.

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

Comment thread crates/ironrdp-server/src/server.rs Outdated
Comment on lines +618 to +620
/// Most callers should configure this at construction time via the builder's
/// [`with_auto_reconnect_cookie`](RdpServerBuilder::with_auto_reconnect_cookie);
/// this setter exists for dynamic post-construction reconfiguration.
Comment thread crates/ironrdp-server/src/server.rs Outdated
Comment on lines +480 to +484
/// disconnected. `None` (the default) sends nothing. Configure via
/// [`RdpServerBuilder::with_auto_reconnect_cookie`] or
/// [`Self::set_auto_reconnect_cookie`].
///
/// [`RdpServerBuilder::with_auto_reconnect_cookie`]: crate::RdpServerBuilder::with_auto_reconnect_cookie
Add an optional Server Auto-Reconnect Cookie (MS-RDPBCGR 2.2.4.3
ARC_SC_PRIVATE_PACKET). When set, `RdpServer` sends a Save Session Info PDU
carrying it once per connection, right after activation.

A client only enters its automatic reconnection sequence (MS-RDPBCGR
1.3.1.5) on an *ungraceful* disconnect if it was handed this cookie during
logon; without it a dropped connection simply reports as disconnected (mstsc
will not auto-reconnect at all). This lets a server that intentionally drops
a connection and expects the client back — e.g. a recovery path — have the
reconnect happen automatically instead of requiring a manual reconnect.

Configure via `RdpServerBuilder::with_auto_reconnect_cookie` or the runtime
`RdpServer::set_auto_reconnect_cookie` setter, mirroring the existing
credential_validator pattern. A per-connection guard sends the cookie exactly
once (after the first activation), not again on a Deactivation-Reactivation.
All the PDU types already exist in ironrdp-pdu (`rdp::session_info`); only the
server-side send is new.

Additive: the default is `None` (send nothing), so existing servers are
unaffected. The returning ARC_CS_PRIVATE_PACKET is intentionally not validated
here — documented in the setter.
…erBuilder

Copilot review: the doc links to RdpServerBuilder::with_auto_reconnect_cookie
don't resolve because RdpServerBuilder is a private-module type not re-exported
from the crate root. Link the reachable RdpServer::builder and name the builder
method in code formatting instead, so the intra-doc links resolve.
@clintcan

clintcan commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the Copilot review in c1cf3186: the doc links now point at the reachable RdpServer::builder (and name with_auto_reconnect_cookie in code formatting) instead of crate::RdpServerBuilder::…, which doesn't resolve.

Root cause aside, in case it's of interest: RdpServerBuilder isn't re-exported from the crate root (lib.rs exports RdpServer/RdpServerOptions but not the builder type), so every crate::RdpServerBuilder::… intra-doc link in server.rs is currently broken. A one-line pub use builder::RdpServerBuilder; would fix them all at once, but that's a public-API surface change I left out of this PR — happy to send it separately if you'd want it.

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.

2 participants