Skip to content

Fix/wss port0 reverse proxy - #693

Closed
HanGYvv wants to merge 7 commits into
rustdesk:masterfrom
HanGYvv:fix/wss-port0-reverse-proxy
Closed

Fix/wss port0 reverse proxy#693
HanGYvv wants to merge 7 commits into
rustdesk:masterfrom
HanGYvv:fix/wss-port0-reverse-proxy

Conversation

@HanGYvv

@HanGYvv HanGYvv commented Aug 9, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Added optional login enforcement for client connections.
    • Added JWT-based authentication and validation for protected requests.
    • Improved WebSocket message delivery and peer online-status reporting.
    • Added a release-notes command for generating changelog-formatted Markdown.
    • Added support for Debian packages, Windows installers, and multi-architecture Docker images.
  • Bug Fixes

    • Improved peer address handling and punch-request processing.
    • Prevented UDP processing errors from unnecessarily restarting the socket.
  • Documentation

    • Added usage guides for the classic and S6 container images.
    • Updated download links and project status badges.

Greptile Summary

The PR extends rendezvous registration and routing for WebSocket clients behind reverse proxies, adds optional JWT login enforcement, and substantially restructures CI and release automation.

  • Preserves an existing nonzero peer endpoint when proxied WebSocket registration reports source port zero.
  • Adds TCP/WebSocket peer registration, WebSocket sink routing, and online-state handling.
  • Introduces optional HS256 token validation for connection requests.
  • Replaces the combined build workflow with CI, Debian, Docker, and release workflows plus reusable actions.
  • Adds release-note generation and container documentation.

Confidence Score: 2/5

The PR is not safe to merge until the release-input command injection and incorrect personal container-registry destinations are fixed.

Manual version values are parsed as Bash code in privileged release workflows, and every Docker release is directed to the contributor's personal Docker Hub and GHCR namespaces rather than the project's release channels.

Files Needing Attention: .github/workflows/release.yaml, .github/workflows/debian.yaml, .github/workflows/docker.yaml

Security Review

The manual release workflows interpolate the supplied version directly into Bash source before validation, allowing shell syntax in that input to execute in privileged workflow jobs. How this was verified: The expression is embedded at the assignment line and the regex check occurs only in subsequent shell statements.

Important Files Changed

Filename Overview
src/rendezvous_server.rs Adds WebSocket registration/routing and optional JWT login enforcement; no independently publishable runtime defect was established in these paths.
src/peer.rs Preserves a known nonzero peer endpoint when a reverse-proxied WebSocket registration supplies port zero.
src/jwt.rs Adds fail-closed HS256 JWT validation for the optional login requirement.
.github/workflows/release.yaml Adds release automation but embeds manual version input directly in privileged Bash source.
.github/workflows/docker.yaml Adds multi-architecture image publishing but contains shell-input injection and publishes to personal image namespaces.
.github/workflows/debian.yaml Adds cross-architecture Debian packaging while repeating the unsafe manual-version interpolation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Client[Client] -->|UDP/TCP registration| HBBS[HBBS rendezvous server]
  Proxy[WSS reverse proxy] -->|WebSocket registration<br/>forwarded IP, port 0| HBBS
  HBBS --> PeerMap[Peer map]
  HBBS --> UDP[UDP peer delivery]
  HBBS --> WS[WebSocket sink map]
  Requester[Connection requester] -->|PunchHoleRequest + optional JWT| HBBS
  HBBS -->|Route request| UDP
  HBBS -->|Route request| WS
Loading

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
### Issue 1
.github/workflows/release.yaml:38
**Version input executes as shell**

When a manual run supplies shell syntax in `inputs.version`, GitHub inserts it directly into the Bash assignment, so it executes before the subsequent regex validation and can run commands with the release workflow's write-capable token. Pass the value through an environment variable or positional argument instead; the same unsafe interpolation occurs in the Debian and Docker workflows. **How this was verified:** The input expression is embedded in the assignment on line 38, while validation begins only on line 43.

### Issue 2
.github/workflows/docker.yaml:32-35
**Releases target personal registries**

On every tagged or manually dispatched Docker release, these global destinations route all architecture images and manifests to the contributor's `hangyvv` namespaces instead of RustDesk's release channels, so the project's Docker Hub and GHCR images do not receive the release.

```suggestion
  DOCKER_IMAGE: rustdesk/rustdesk-server-s6
  DOCKER_IMAGE_CLASSIC: rustdesk/rustdesk-server
  GHCR_IMAGE: ghcr.io/rustdesk/rustdesk-server-s6
  GHCR_IMAGE_CLASSIC: ghcr.io/rustdesk/rustdesk-server
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(hbbs): don't clobber real peer addr ..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

HanGYvv added 7 commits August 9, 2026 11:08
Split the monolithic build workflow into separate ci, debian, docker, and
release workflows backed by reusable composite actions, and add a
release-notes helper binary.
Add Docker Hub README files for the s6 and classic images, consumed by the
docker workflow's description-sync step. Update the main README badges and
links to point at the new workflows and repository.
Ported and adapted from lejianwen/forapi:
- MUST_LOGIN / JWT login enforcement
- RegisterPk / OnlineRequest handling
- WebSocket peer forwarding

Adjusted for the current codebase and stricter JWT secret enforcement.
hbb_common now pulls in native-tls -> openssl-sys on all platforms, but
the cross musl images have no system OpenSSL, so every Linux target
(amd64/arm64v8/armv7/i386) failed to compile in the release/docker/debian
workflows.

Build OpenSSL from source (vendored) on non-macOS/Windows targets, both
as a normal dependency and as a build-dependency (build.rs also compiles
hbb_common for the host).
UDP send errors (e.g. EINVAL when the destination port is 0, hit by the
self-test heartbeat) only drop one datagram; the socket is still healthy.
Treating them as fatal made the io_loop drop and recreate the socket in a
crash loop. Keep recreation for receive-side failures only, and drop UDP
packets from source port 0 outright (no legitimate client sends from port 0).
Clients behind a reverse proxy register with an `IP:0` address that has no
reachable UDP port, so RequestRelay (and punch retries) sent over UDP were
silently dropped with EINVAL and relay could never be established. Route peer
messages through the peer's registered WebSocket/TCP sink first via a shared
send_to_peer helper, falling back to UDP only when no sink exists.
A register_pk / register_peer over WebSocket behind a reverse proxy arrives
with an address rewritten from X-Real-IP to `IP:0` (port 0 is a marker, not a
reachable endpoint). Accepting it overwrote the peer's real UDP socket address
that punching/relay depend on. Only update the stored address when the new one
is non-zero, or when no real address is held yet.
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a0222ac3-f500-481a-a975-5e7eefb83e9f

📥 Commits

Reviewing files that changed from the base of the PR and between a7736be and 5e1c586.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • .github/actions/build-rust-target/action.yml
  • .github/actions/docker-build-and-push/action.yml
  • .github/actions/docker-manifest/action.yml
  • .github/workflows/build.yaml
  • .github/workflows/ci.yaml
  • .github/workflows/debian.yaml
  • .github/workflows/docker.yaml
  • .github/workflows/release.yaml
  • Cargo.toml
  • README.md
  • docker-classic/README.md
  • docker/README.md
  • src/bin/release-notes.rs
  • src/jwt.rs
  • src/lib.rs
  • src/main.rs
  • src/peer.rs
  • src/rendezvous_server.rs

📝 Walkthrough

Walkthrough

Changes

Release automation

Layer / File(s) Summary
Shared build and container actions
.github/actions/*
Reusable actions build Rust targets, publish architecture-specific images, and create multi-architecture manifests.
Validation and release artifact builds
.github/workflows/ci.yaml, .github/workflows/debian.yaml, .github/workflows/docker.yaml, .github/workflows/release.yaml
CI validates Rust and Docker builds. Release workflows validate versions and build Linux and Windows artifacts.
Packaging and registry publication
.github/workflows/debian.yaml, .github/workflows/docker.yaml, .github/workflows/release.yaml, Cargo.toml
The workflows package Debian and Windows releases, publish Docker images and manifests, update Docker Hub descriptions, and add vendored OpenSSL dependencies.
Release notes and image documentation
src/bin/release-notes.rs, README.md, docker/README.md, docker-classic/README.md
The new CLI generates categorized release notes. Documentation describes release links and container deployment details.

Rendezvous authentication and peer delivery

Layer / File(s) Summary
JWT login configuration and command controls
src/jwt.rs, src/lib.rs, src/main.rs, src/rendezvous_server.rs
JWT verification and mandatory-login controls are available through startup configuration, command-line arguments, and console commands.
Peer registration and transport handling
src/rendezvous_server.rs, src/peer.rs
UDP, TCP, and WebSocket registration use shared validation, tracked sinks, safer address updates, and improved UDP error handling.
Login enforcement and peer message delivery
src/rendezvous_server.rs
Punch-hole and online requests validate tokens. Peer delivery prefers WebSocket and TCP sinks before UDP fallback.
Connection cleanup and request state
src/rendezvous_server.rs
Closed WebSocket sinks are removed, and punch-request pagination uses an immutable starting index.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RendezvousServer
  participant JWT
  participant Peer
  participant Transport
  Client->>RendezvousServer: send authenticated peer request
  RendezvousServer->>JWT: verify token
  JWT-->>RendezvousServer: return claims
  RendezvousServer->>Peer: resolve peer state
  RendezvousServer->>Transport: send through WebSocket or TCP sink
  Transport-->>Client: forward peer message
Loading

Possibly related PRs

  • rustdesk/rustdesk-server#689: Both changes modify TCP rendezvous handling, but this PR does not add the other PR’s TCP encryption or key exchange logic.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (description_diff_mismatch). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

@HanGYvv

HanGYvv commented Aug 9, 2026

Copy link
Copy Markdown
Author

Sorry, I submitted it to the wrong place.

shell: bash
run: |
if [ "${GITHUB_EVENT_NAME}" = "workflow_dispatch" ]; then
tag="${{ inputs.version }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 security Version input executes as shell

When a manual run supplies shell syntax in inputs.version, GitHub inserts it directly into the Bash assignment, so it executes before the subsequent regex validation and can run commands with the release workflow's write-capable token. Pass the value through an environment variable or positional argument instead; the same unsafe interpolation occurs in the Debian and Docker workflows. How this was verified: The input expression is embedded in the assignment on line 38, while validation begins only on line 43.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/release.yaml
Line: 38

Comment:
**Version input executes as shell**

When a manual run supplies shell syntax in `inputs.version`, GitHub inserts it directly into the Bash assignment, so it executes before the subsequent regex validation and can run commands with the release workflow's write-capable token. Pass the value through an environment variable or positional argument instead; the same unsafe interpolation occurs in the Debian and Docker workflows. **How this was verified:** The input expression is embedded in the assignment on line 38, while validation begins only on line 43.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

Comment on lines +32 to +35
DOCKER_IMAGE: hangyvv/rustdesk-server-s6
DOCKER_IMAGE_CLASSIC: hangyvv/rustdesk-server
GHCR_IMAGE: ghcr.io/hangyvv/rustdesk-server-s6
GHCR_IMAGE_CLASSIC: ghcr.io/hangyvv/rustdesk-server

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Releases target personal registries

On every tagged or manually dispatched Docker release, these global destinations route all architecture images and manifests to the contributor's hangyvv namespaces instead of RustDesk's release channels, so the project's Docker Hub and GHCR images do not receive the release.

Suggested change
DOCKER_IMAGE: hangyvv/rustdesk-server-s6
DOCKER_IMAGE_CLASSIC: hangyvv/rustdesk-server
GHCR_IMAGE: ghcr.io/hangyvv/rustdesk-server-s6
GHCR_IMAGE_CLASSIC: ghcr.io/hangyvv/rustdesk-server
DOCKER_IMAGE: rustdesk/rustdesk-server-s6
DOCKER_IMAGE_CLASSIC: rustdesk/rustdesk-server
GHCR_IMAGE: ghcr.io/rustdesk/rustdesk-server-s6
GHCR_IMAGE_CLASSIC: ghcr.io/rustdesk/rustdesk-server
Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/docker.yaml
Line: 32-35

Comment:
**Releases target personal registries**

On every tagged or manually dispatched Docker release, these global destinations route all architecture images and manifests to the contributor's `hangyvv` namespaces instead of RustDesk's release channels, so the project's Docker Hub and GHCR images do not receive the release.

```suggestion
  DOCKER_IMAGE: rustdesk/rustdesk-server-s6
  DOCKER_IMAGE_CLASSIC: rustdesk/rustdesk-server
  GHCR_IMAGE: ghcr.io/rustdesk/rustdesk-server-s6
  GHCR_IMAGE_CLASSIC: ghcr.io/rustdesk/rustdesk-server
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant