261 lines
19 KiB
Markdown
261 lines
19 KiB
Markdown
# RustDesk Client vs OSS Server — Feature Gap Analysis
|
|
|
|
This document compares the RustDesk **client** ([/Users/sn0/Desktop/rustdesk](../)) against the OSS **server** ([/Users/sn0/Desktop/rustdesk-server](../../rustdesk-server/)) and lists every feature the client implements or expects, but that the OSS server (`hbbs` + `hbbr` + `rustdesk-utils`) does **not** provide.
|
|
|
|
The OSS server is, by upstream's own description in its README, deliberately minimal:
|
|
|
|
> Self-host your own RustDesk server, it is free and open source.
|
|
> If you want extra features, **RustDesk Server Pro** might suit you better.
|
|
|
|
Almost every gap below is filled by RustDesk Server Pro (closed source). What follows is the concrete list.
|
|
|
|
---
|
|
|
|
## TL;DR
|
|
|
|
| Area | OSS server | Client expects |
|
|
|-----------------------------------------------------|-----------------|----------------------------------------------|
|
|
| Rendezvous protocol (UDP/TCP/WS) | ✅ implemented | ✅ |
|
|
| Relay protocol (`hbbr`) | ✅ implemented | ✅ |
|
|
| `RegisterPk` over **TCP** | ❌ `NOT_SUPPORT`| Uses UDP — non-issue if UDP reachable |
|
|
| `HttpProxyRequest` / `HttpProxyResponse` (HTTP-via-rendezvous tunnel) | ❌ no handler | Used when `USE_RAW_TCP_FOR_API=Y` |
|
|
| **Entire `/api/*` HTTP surface** (35 endpoints in [CONSOLE_API.md](CONSOLE_API.md)) | ❌ no HTTP server | All login, AB, group, audit, sysinfo, etc. |
|
|
| User / password / token authentication | ❌ | Bearer-token model |
|
|
| Address book (legacy or shared) | ❌ | Personal AB, shared AB, tags, peers |
|
|
| Device groups, users, accessible peers list | ❌ | "Group" tab in UI |
|
|
| Audit logging (conn, file, alarm, note) | ❌ | Background fire-and-forget |
|
|
| Session recording upload | ❌ | Chunked uploader |
|
|
| Sysinfo / heartbeat-based device tracking | ❌ | Every 15 s (3 s when active) |
|
|
| Strategy/policy push via heartbeat | ❌ | `config_options` / `disconnect` / `sysinfo` flag |
|
|
| 2FA, email-code, SMS-code, OIDC/SSO | ❌ | Login challenge variants |
|
|
| Plugin signing (`/lic/web/api/plugin-sign`) | ❌ | Optional, only if signed plugins shipped |
|
|
| CLI bulk device assignment (`rustdesk --assign`) | ❌ | `POST /api/devices/cli` |
|
|
| Per-tenant licensing / Pro status flag | ❌ | Inferred from sysinfo success |
|
|
|
|
---
|
|
|
|
## 1. Rendezvous-protocol gaps
|
|
|
|
The OSS server *does* speak the rendezvous protocol — it accepts and responds to all of the variants the client sends in the normal connection path. There are exactly **two** variant-level gaps:
|
|
|
|
### 1.1 `RegisterPk` over TCP — explicitly rejected
|
|
|
|
[src/rendezvous_server.rs:556-563](../../rustdesk-server/src/rendezvous_server.rs#L556) returns `RegisterPkResponse { result: NOT_SUPPORT }` for any TCP-arriving `RegisterPk`. UDP works fine. The client has UDP `RegisterPk` as the primary path ([src/rendezvous_mediator.rs:685-693](../src/rendezvous_mediator.rs#L685-L693)), so this is only an issue in fully UDP-blocked environments where the client falls back to TCP for everything.
|
|
|
|
### 1.2 `HttpProxyRequest` / `HttpProxyResponse` — no handler
|
|
|
|
When `USE_RAW_TCP_FOR_API` is enabled (and WebSocket is off), the client tunnels its HTTP API calls **as protobuf messages** over the rendezvous server's TCP socket — see [src/common.rs:1188-1250](../src/common.rs#L1188-L1250) (`tcp_proxy_request`).
|
|
|
|
- **Wire format:** an encrypted `KeyExchange` handshake, then a `RendezvousMessage::set_http_proxy_request(HttpProxyRequest { method, path, headers, body })`, expecting `HttpProxyResponse { status_code, headers, body }` back.
|
|
- **OSS handling:** there is no match arm for `HttpProxyRequest` in [/Users/sn0/Desktop/rustdesk-server/src/rendezvous_server.rs](../../rustdesk-server/src/rendezvous_server.rs); it falls into the `_ => {}` catch-all and is silently dropped.
|
|
- **Impact:** any client that has been pushed `OPTION_USE_RAW_TCP_FOR_API=Y` (typical for restricted networks) cannot reach the HTTP API at all on an OSS-only deployment, even if the API itself were implemented.
|
|
|
|
### 1.3 What the OSS server *does* handle (not gaps, for completeness)
|
|
|
|
- UDP: `RegisterPeer`, `RegisterPk`, `PunchHoleRequest`, `PunchHoleSent`, `LocalAddr`, `ConfigureUpdate` (loopback only), `SoftwareUpdate`.
|
|
- TCP: `PunchHoleRequest`, `RequestRelay`, `RelayResponse`, `PunchHoleSent`, `LocalAddr`, `TestNatRequest`.
|
|
- TCP listener2 (`port - 1`): `TestNatRequest`, `OnlineRequest`, plus a loopback admin CLI.
|
|
- WebSocket on `port + 2` (default 21118): same handler set as TCP.
|
|
- The relay (`hbbr`) listens on `port` (default 21117) and `port + 2` (WebSocket, default 21119), and handles `RequestRelay` for tunnelling.
|
|
|
|
So the **rendezvous + relay surface for plain peer-to-peer use is complete in the OSS server.** All the actual gaps are above the rendezvous layer.
|
|
|
|
---
|
|
|
|
## 2. HTTP API — none of it exists in OSS
|
|
|
|
[/Users/sn0/Desktop/rustdesk-server/Cargo.toml](../../rustdesk-server/Cargo.toml) pulls in `axum` and `tower-http`, but they are unused — no `Router::new`, no route definitions, no HTTP listener bound. **All 35 endpoints documented in [CONSOLE_API.md](CONSOLE_API.md) are gaps.**
|
|
|
|
Grouped by feature area:
|
|
|
|
### 2.1 Authentication & session (`/api/login`, `/api/login-options`, `/api/logout`, `/api/currentUser`)
|
|
|
|
- No user table in the OSS schema (which is a single `peer` table — see §4 below). No password storage, hashing, salting.
|
|
- No bearer-token issuance or validation.
|
|
- No `email_check` / `tfa_check` challenge types (no email sender, no TOTP store).
|
|
- No login-options registry — client always gets an empty `oidc/...` list.
|
|
- No OIDC / SSO device flow (`/api/oidc/auth`, `/api/oidc/auth-query`).
|
|
|
|
### 2.2 Address book — both modes missing
|
|
|
|
The client supports two AB modes ([CONSOLE_API.md §4](CONSOLE_API.md)) and the OSS server implements neither:
|
|
|
|
- **Legacy single-blob mode** (`GET/POST /api/ab`) — needs a per-user blob store + gzip handling.
|
|
- **Shared mode** (`/api/ab/settings`, `/api/ab/personal`, `/api/ab/shared/profiles`, `/api/ab/peers`, `/api/ab/tags/{guid}`, plus the per-peer and per-tag CRUD on `{guid}`) — needs a normalized AB / peer / tag / share-rule schema with `read | read/write | full control` ACLs.
|
|
|
|
Without this, the client falls back to its local-only "Recents" / "Favorites" lists; nothing syncs across devices.
|
|
|
|
### 2.3 Device groups, users, accessible peers (`/api/device-group/accessible`, `/api/users`, `/api/peers`)
|
|
|
|
The "Group" tab in the desktop UI populates from these three endpoints. With OSS the tab is empty; the client logs `get accessible device groups: <error>` and silently swallows it.
|
|
|
|
### 2.4 Heartbeat / sysinfo / strategy push (`/api/heartbeat`, `/api/sysinfo`, `/api/sysinfo_ver`)
|
|
|
|
This is the agent-management heartbeat loop ([CONSOLE_API.md §6](CONSOLE_API.md)).
|
|
|
|
OSS gaps:
|
|
|
|
- No device-tracking table (last-seen, OS, hostname, version, IP, online state).
|
|
- No sysinfo cache or version string.
|
|
- No mechanism to **push back** in the heartbeat response:
|
|
- `sysinfo: <truthy>` to force an immediate sysinfo re-upload.
|
|
- `disconnect: [conn_id, ...]` to force a remote session to close.
|
|
- `modified_at` / `strategy.config_options` to push policy.
|
|
- Without strategy push, the operator cannot remotely set:
|
|
- `whitelist`, `relay-server`, `rendezvous-servers`, `direct-access-port`,
|
|
`stop-service`, `OPTION_DISABLE_UDP`, `OPTION_ENABLE_UDP_PUNCH`,
|
|
`OPTION_ENABLE_IPV6_PUNCH`, `OPTION_USE_RAW_TCP_FOR_API`,
|
|
`OPTION_DIRECT_SERVER`, etc.
|
|
- Or any of the `OPTION_PRESET_*` keys that pre-fill the address book / username / device group / strategy on a freshly enrolled client.
|
|
- `is_pro()` is set to `true` only when `/api/sysinfo` returns `SYSINFO_UPDATED` ([src/hbbs_http/sync.rs:219](../src/hbbs_http/sync.rs#L219)) — with OSS, `is_pro()` is permanently `false`, so any client behavior gated on it is disabled.
|
|
|
|
### 2.5 Audit (`/api/audit/conn`, `/api/audit/file`, `/api/audit/alarm`, `PUT /api/audit`)
|
|
|
|
The client emits these fire-and-forget on every:
|
|
|
|
- new remote session ([src/server/connection.rs:1248-1252](../src/server/connection.rs#L1248-L1252)),
|
|
- file send/receive ([src/server/connection.rs:1297-1330](../src/server/connection.rs#L1297-L1330)),
|
|
- security alarm — IP whitelist hit, brute-force thresholds ([src/server/connection.rs:1332-1349](../src/server/connection.rs#L1332-L1349)), and
|
|
- the operator-typed end-of-session note (PUT, [flutter/lib/common/widgets/dialog.dart:1656-1687](../flutter/lib/common/widgets/dialog.dart#L1656-L1687)).
|
|
|
|
Even though the client doesn't *block* on these, OSS silently swallows all of them, so:
|
|
|
|
- No central session log.
|
|
- No file-transfer log (incl. the top-10-by-size summary the client computes).
|
|
- No alarm notifications for IP-whitelist hits or brute-force attempts.
|
|
- No audit-row GUID exists, so the "leave a note when the session ends" dialog has nothing to attach to.
|
|
|
|
### 2.6 Session recording upload (`POST /api/record`)
|
|
|
|
Chunked uploader ([src/hbbs_http/record_upload.rs](../src/hbbs_http/record_upload.rs)) with `?type=new|part|tail|remove`. OSS has no `/api/record` route and no on-disk recording store, so server-side recording is impossible.
|
|
|
|
(Local-only recording on the controlling side still works — that's not a server feature.)
|
|
|
|
### 2.7 OIDC / SSO device flow (`/api/oidc/auth`, `/api/oidc/auth-query`)
|
|
|
|
The polled device-code flow ([src/hbbs_http/account.rs](../src/hbbs_http/account.rs)) requires an OIDC client implementation, browser-flow URL generation, and a poll-for-token side. None of this is in OSS.
|
|
|
|
### 2.8 CLI bulk assign (`POST /api/devices/cli`)
|
|
|
|
[src/core_main.rs:519-616](../src/core_main.rs#L519-L616). Used by `rustdesk --assign --token ...` for mass-deploy scripts to register a freshly-installed agent into a tenant, optionally setting `user_name`, `strategy_name`, `address_book_*`, `device_group_name`, `device_username`, `device_name`, `note`. Requires user/group/AB tables, none of which exist in OSS.
|
|
|
|
### 2.9 Plugin signature service (`POST /lic/web/api/plugin-sign`)
|
|
|
|
[src/plugin/callback_msg.rs:282-296](../src/plugin/callback_msg.rs#L282-L296). Required only if the deployment ships signed plugins. OSS has no plugin infrastructure of any kind.
|
|
|
|
### 2.10 Generic file downloader
|
|
|
|
`HEAD` then `GET` against an arbitrary URL with a required `Content-Length` ([src/hbbs_http/downloader.rs](../src/hbbs_http/downloader.rs)). Works against any static file server — OSS doesn't *need* to serve this, but a complete Pro-replacement backend usually exposes installer/plugin/recording downloads via this.
|
|
|
|
---
|
|
|
|
## 3. Schema gaps
|
|
|
|
The OSS database is a single SQLite table called `peer`:
|
|
|
|
```
|
|
guid (PK), id (UNIQUE), uuid, pk, created_at, user (unused),
|
|
status (unused), note (unused), info (JSON: { ip })
|
|
```
|
|
|
|
[/Users/sn0/Desktop/rustdesk-server/src/database.rs:71-144](../../rustdesk-server/src/database.rs#L71-L144).
|
|
|
|
To support the client's HTTP surface a backend needs at minimum:
|
|
|
|
- `users` (id, name, display_name, avatar, email, note, password_hash, status, is_admin, totp_secret, oidc_subject, …)
|
|
- `tokens` (token_hash, user_id, expires_at)
|
|
- `oidc_sessions` (poll_code, state, created_at, access_token, …)
|
|
- `address_books` (guid, owner_user_id, name, note, kind=personal|shared)
|
|
- `address_book_shares` (ab_guid, user_or_group_id, rule={1,2,3})
|
|
- `address_book_peers` (ab_guid, peer_id, alias, tags[], note, password|hash, username, hostname, platform)
|
|
- `address_book_tags` (ab_guid, name, color)
|
|
- `device_groups` (id, name)
|
|
- `device_group_members` (device_group_id, user_or_group_id)
|
|
- `peers_extended` (peer_id, user_id, device_group_id, last_seen, version, sysinfo_blob, sysinfo_hash, sysinfo_ver, online, …)
|
|
- `audit_conn` (guid, peer_id, conn_id, session_id, action, ip, started_at, ended_at, note)
|
|
- `audit_file` (peer_id, peer_remote, type, path, is_file, info_json)
|
|
- `audit_alarm` (peer_id, typ, info_json)
|
|
- `recordings` (filename, peer_id, size, header_blob, started_at, finished_at)
|
|
- `strategies` (id, name, modified_at, config_options_json, extra_json)
|
|
- `peer_strategy_assignment` / `device_group_strategy_assignment`
|
|
|
|
The OSS schema covers exactly **one row** of one of those tables (`peers_extended.peer_id` plus `pk`/`uuid`). Everything else is a gap.
|
|
|
|
---
|
|
|
|
## 4. Authentication / authorization gaps
|
|
|
|
- **No user/password.** The OSS server identifies a peer entirely by `(id, uuid, pk)`. There is no concept of a logged-in *human user*, no password, no session, no role.
|
|
- **No bearer tokens.** The client adds `Authorization: Bearer <access_token>` to every authenticated HTTP call ([flutter/lib/common.dart:2691-2695](../flutter/lib/common.dart#L2691-L2695)). With no HTTP API and no user store, OSS has nothing to validate against.
|
|
- **No 2FA.** The client supports TOTP challenge (`type: tfa_check`, `tfa_type`, `secret`) and per-device 2FA-trust ([src/ui_session_interface.rs](../src/ui_session_interface.rs)). Not present in OSS.
|
|
- **No email/SMS verification.** The `email_check` challenge type and `verificationCode` field have no sender on the OSS side.
|
|
- **No SSO / OIDC.** No identity-provider integration.
|
|
- **No admin/role concept.** The `UserPayload.is_admin` flag (used to gate the user-management UI) has no source.
|
|
- **No per-AB ACL.** `AbProfile.rule` (read / read-write / full control) has no enforcement layer.
|
|
- **No IP allowlisting / per-IP rate-limiting on HTTP endpoints.** OSS rate-limits `RegisterPk` per source IP ([src/rendezvous_server.rs:891-919](../../rustdesk-server/src/rendezvous_server.rs#L891-L919)) but that's at the rendezvous layer only.
|
|
|
|
What the OSS server *does* offer in this space:
|
|
|
|
- Optional symmetric server key (`-k`) checked against `licence_key` in `PunchHoleRequest` and `RequestRelay`. This is shared-secret deployment lockdown, not user auth.
|
|
- Ed25519 signing of `RelayResponse` payloads using the server's private key.
|
|
|
|
---
|
|
|
|
## 5. Operations / fleet management gaps
|
|
|
|
These are conveniences a Pro server offers via the strategy/heartbeat channel; OSS has no equivalent because heartbeat itself is not implemented.
|
|
|
|
- **Force-disconnect a remote session** from the admin console (heartbeat returns `disconnect: [conn_id]` — [src/hbbs_http/sync.rs:251-254](../src/hbbs_http/sync.rs#L251-L254)).
|
|
- **Force-refresh sysinfo** (`sysinfo` truthy in heartbeat).
|
|
- **Push global config** to all enrolled agents (the `strategy.config_options` map). Without this, every option must be set per-machine.
|
|
- **Pre-seed an agent** at install time with an address-book entry, alias, password, note, strategy, device group, custom hostname/username (`OPTION_PRESET_ADDRESS_BOOK_*`, `OPTION_PRESET_USERNAME`, `OPTION_PRESET_STRATEGY_NAME`, `OPTION_PRESET_DEVICE_GROUP_NAME`, …). Client emits these preset values on every sysinfo, but OSS discards them.
|
|
- **Operator end-of-session notes** (PUT `/api/audit`).
|
|
- **`rustdesk --assign --token …`** for mass deployment.
|
|
- **Brute-force / IP-whitelist alarms** to a central log.
|
|
|
|
What OSS *does* offer for ops:
|
|
|
|
- A loopback-only TCP admin CLI on `port - 1` (default 21115) for hbbs and on `port` for hbbr ([src/rendezvous_server.rs:1102-1116](../../rustdesk-server/src/rendezvous_server.rs#L1102-L1116), [src/relay_server.rs:152-323](../../rustdesk-server/src/relay_server.rs#L152-L323)) — `relay-servers`, `ip-blocker`, `ip-changes`, `punch-requests`, `always-use-relay`, `test-geo`, `blacklist-add`, `blocklist-add`, `total-bandwidth`, `usage`, etc.
|
|
- A `ConfigureUpdate` push *only from loopback* — the operator can update the rendezvous-server list pushed to clients, but only by `nc 127.0.0.1 21115` on the server box itself.
|
|
|
|
---
|
|
|
|
## 6. Client-side features that work fine against OSS
|
|
|
|
For balance — these features in the client need no Pro-server support at all:
|
|
|
|
- All in-session protocol (after the relay/direct connection is established): screen sharing, file transfer, terminal, RDP / VNC tunnel, port forward, voice call, view-only mode, whiteboard, printer, clipboard, multi-monitor, mouse/keyboard injection. These are negotiated on the session stream itself and never touch the management server.
|
|
- LAN discovery (when both ends are reachable on the same LAN, no rendezvous server needed at all).
|
|
- The client's local 2FA on the *controlled* side ("ask the operator for a one-time code"). That's a peer-to-peer protocol negotiation, not a server feature.
|
|
- IP-whitelist enforcement on the controlled side ([src/server/connection.rs:1202-1228](../src/server/connection.rs#L1202-L1228)) — done locally against the `whitelist` config option. (But the *operator UX* of pushing that whitelist to a fleet is missing — see §5.)
|
|
- Self-update — the client checks a hardcoded URL on the public update server, not the configured rendezvous/API server.
|
|
- Custom-server bootstrap via filename (`rustdesk-host=…,key=…,api=…,relay=….exe`, [src/custom_server.rs](../src/custom_server.rs)) — works against OSS as long as the `api=` field is left empty / public.
|
|
|
|
---
|
|
|
|
## 7. What you'd need to build to fully replace Pro
|
|
|
|
Given the analysis above, a full Pro-replacement backend on top of OSS would need:
|
|
|
|
1. **Add an HTTP server** (axum is already in the Cargo.toml of OSS, unused). Implement the 35 routes in [CONSOLE_API.md](CONSOLE_API.md).
|
|
2. **Add a `HttpProxyRequest` handler** in `rendezvous_server.rs` so that locked-down clients can reach the HTTP API through the rendezvous TCP port (decode the protobuf, replay the request internally, wrap the response).
|
|
3. **Extend the schema** along the lines of §3.
|
|
4. **Add user / token / OIDC / 2FA layers**, plus an email sender for `email_check`.
|
|
5. **Implement the strategy / push-config side of `/api/heartbeat`** and the sysinfo cache for `/api/sysinfo*`.
|
|
6. **Add audit + recording stores** with retention and access-control.
|
|
7. (Optional) **Plugin signing service** if you're shipping signed plugins.
|
|
|
|
The rendezvous + relay protocol itself does not need to change — OSS is correct and complete there.
|
|
|
|
---
|
|
|
|
## Source-of-truth references
|
|
|
|
- Client HTTP API the server must serve: [docs/CONSOLE_API.md](CONSOLE_API.md).
|
|
- Client rendezvous receive loop: [src/rendezvous_mediator.rs](../src/rendezvous_mediator.rs).
|
|
- Client HTTP-via-TCP fallback: [src/common.rs:1188-1250](../src/common.rs#L1188-L1250).
|
|
- Client heartbeat loop: [src/hbbs_http/sync.rs](../src/hbbs_http/sync.rs).
|
|
- OSS rendezvous handler: [/Users/sn0/Desktop/rustdesk-server/src/rendezvous_server.rs](../../rustdesk-server/src/rendezvous_server.rs).
|
|
- OSS relay handler: [/Users/sn0/Desktop/rustdesk-server/src/relay_server.rs](../../rustdesk-server/src/relay_server.rs).
|
|
- OSS schema: [/Users/sn0/Desktop/rustdesk-server/src/database.rs](../../rustdesk-server/src/database.rs).
|