IronRDP: A Sans-I/O Rust RDP Stack for Clients, Servers, and Proxies
Rust implementation of the Microsoft Remote Desktop Protocol (RDP).
At a glance
- What is it?
- IronRDP is a modular Rust implementation of the Remote Desktop Protocol with a sans-I/O core. It targets client, server, and proxy builders who need protocol fidelity without being locked into a transport or runtime.
- Who is it for?
- Adopt IronRDP if you are building an RDP client, server, or proxy in Rust and need a protocol core that does not dictate your I/O model. It is also a strong fit for non-Rust targets through its WebAssembly and .NET bindings.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The Problem IronRDP Solves
Implementing RDP from scratch is a large, error-prone task. The protocol spans connection negotiation, security layers, graphics codecs, and virtual channels. Most existing implementations are monolithic clients, which makes them hard to embed in a server or a proxy. IronRDP addresses this by splitting the protocol into composable crates, each handling a slice of the stack. The intended audience is not end users who want to click a remote desktop icon. It is developers building RDP-capable products: gateway vendors, browser-based access tools, automation agents, or custom servers. The README lists Devolutions Gateway, Cloudflare Access, Teleport, and several community servers as adopters, which confirms that the design targets integration rather than standalone use.
The Sans-I/O Core and What It Means
The central design choice is the sans-I/O core. The protocol state machines perform no I/O themselves. They accept bytes and produce bytes, leaving the transport to the caller. The README says the core is no_std-compatible and can be driven with blocking I/O, tokio, futures, or a custom event loop. This is a significant departure from typical RDP libraries that assume a socket. For a proxy or a gateway, this is a practical advantage: the same protocol logic can sit behind a TCP socket, a WebSocket, or a named pipe without modification. The trade-off is that you must write the I/O glue yourself. The examples show a blocking screenshot tool and a minimal server, but for production you need to integrate the state machines into your runtime. The documentation does not provide a ready-made async runtime adapter, so expect to build that layer.
Running the Prebuilt Binaries
Two binaries ship with each release: ironrdp-viewer and ironrdp-agent. The viewer is a windowed client with asynchronous I/O and software rendering. You run it with a hostname and credentials, or load a .rdp file. The command is straightforward: ironrdp-viewer <HOSTNAME> --username <USERNAME> --password <PASSWORD>. Omitted credentials are prompted interactively. The agent is a daemon-backed CLI for automation. It splits a long-lived daemon from short-lived commands. You start the daemon with ironrdp-agent daemon-start --overlay ./credentials.rdp, then connect with ironrdp-agent connect --server <HOSTNAME> --username <USER>. The connect command fails with missing required fields unless credentials are available, which is a deliberate safety measure to keep secrets out of the IPC caller's hands. Both binaries link native audio, so Linux builds require ALSA development headers and Windows builds require NASM. Prebuilt archives are checksummed and attached to each release, which simplifies deployment.
The Crate Layout and Feature Selection
As a library, IronRDP is a meta crate that re-exports standalone crates. The README shows a dependency on ironrdp with features like connector, session, and graphics. Each feature maps to a crate, so you can depend on ironrdp-pdu, ironrdp-connector, ironrdp-session directly. This modularity is the core of the project's design. You do not pull in the graphics stack if you only need a connection sequence. The feature list is broad: PDU codecs, connection and session state machines, virtual channels, and image codecs. The graphics side includes client-side decoding for raw bitmaps, Interleaved RLE, RDP 6.0 compression, and RemoteFX. Server-side encoding includes RDP 6.0, RemoteFX, and optional NSCodec, QOI, and QOI+zstd. Bulk compression covers MPPC, NCRUSH, and XCRUSH. The virtual channel list includes clipboard, audio, device redirection, and display control. This is a wide surface, and the README claims the core is continuously fuzzed. Still, the sheer number of codecs means you should verify which ones are fuzzed before relying on them in a security-sensitive context.
Security Features and Their Boundaries
The README emphasizes security first. Core crates are fuzzed, unsafe is heavily linted, and the workspace enforces strict correctness lints. The protocol support includes TLS 1.2 and 1.3, Network Level Authentication via CredSSP with NTLM and Kerberos, KDC proxy, and RDCleanPath for gateway-mediated connections. It also supports the Terminal Services Gateway transport. These are the mechanisms you need to connect to modern Windows hosts. The security posture is credible, but the README does not specify which fuzzing targets exist or how long they have run. Fuzzing is not a guarantee of correctness, and RDP has a history of subtle parsing bugs. For a production gateway, you should treat the fuzzing claim as a starting point, not a certification. The no_std compatibility of the core is a plus for embedded or minimal environments, but it also means the core excludes any I/O or platform-specific code, which you must supply.
Server-Side Support and Its Current Limits
IronRDP is not just a client. The README describes a server skeleton and an acceptor, and the example server binds to 127.0.0.1:3389. The server side includes encoding for RDP 6.0 and RemoteFX, and the list of adopters includes several server projects: Lamco RDP Server for Wayland, MacRDP for macOS, and qemu-rdp for QEMU displays. This shows that the server path is usable, but the README does not describe a full RDP server implementation. There is no mention of session management, multiple monitors, or advanced licensing beyond the connection sequence. The server example is minimal, and the agent is a client-side automation tool, not a server. If you need a complete RDP server with user management and session lifecycle, you will likely need to build a substantial layer on top of the crate. The acceptor and server skeleton are a foundation, not a finished product.
Bindings and Cross-Language Use
The protocol core also targets WebAssembly and .NET. The README mentions a protocol-agnostic web component called @devolutions/iron-remote-desktop and C#/.NET bindings generated with Diplomat, named Devolutions.IronRdp. This is a differentiator. Most RDP libraries are tied to a single language or platform. IronRDP's core is language-agnostic, so the same protocol logic can power a browser client and a .NET server. The Diplomat binding generation is a concrete mechanism: it produces C# APIs from the Rust code, which reduces the cost of maintaining two implementations. However, the README does not detail the maturity of these bindings. The .NET binding is listed as a feature, but there is no API documentation or example in the README. You should evaluate the bindings on their own merits before committing to them. The web component is also mentioned without specifics, so its feature set and limitations are unclear.
Alternatives and the Difference in Approach
The closest alternative is FreeRDP, a C-based RDP implementation with a long history. FreeRDP uses a traditional architecture where the library manages its own I/O and provides a client and server API. It is mature, widely deployed, and has extensive codec support. The difference is architectural: FreeRDP is not sans-I/O. You integrate it by calling its API, and it handles sockets and threads internally. IronRDP's sans-I/O core is a deliberate contrast. It gives you control over the transport, which is valuable for proxies and gateways that need to multiplex or tunnel connections. The trade-off is that you must write the I/O loop and integrate it with your runtime. FreeRDP also has a larger community and more production history. For a Rust-native project, IronRDP is the obvious choice, but for a C or C++ codebase, FreeRDP is more practical. The choice depends on whether you value control over the I/O layer or maturity of the overall stack.
Maintenance, Licensing, and Upgrade Considerations
IronRDP is licensed under Apache-2.0, which is permissive and suitable for commercial use. The repository is active, with recent releases for the viewer and agent in July 2026. The README does not specify a release cadence or a deprecation policy. The MSRV is defined as the oldest of three versions, but the README is truncated before listing them. You will need to check the repository for the current MSRV before adopting. The modular crate structure means upgrades can be incremental: you can update individual crates without touching the whole stack. However, the feature flags and crate names may change between versions, as the meta crate version 0.17 suggests. The README does not provide a migration guide for major version bumps. The fuzzing and linting practices are a positive sign for long-term maintenance, but the project is still young, and the API may shift. Budget time for keeping up with releases.
Editorial conclusion
Adopt IronRDP if you are building an RDP client, server, or proxy in Rust and need a protocol core that does not dictate your I/O model. It is also a strong fit for non-Rust targets through its WebAssembly and .NET bindings. Skip it if you want a turnkey client with a GUI or if you need production-grade server features like full session management, which are not yet complete. Before adopting, verify the current MSRV, confirm the fuzzing coverage for the specific codecs you plan to enable, and test interoperability against the exact Windows versions you must support, especially for NLA and RemoteFX.
Community notes