mirror of
https://github.com/UNITRONIX/BetterDesk.git
synced 2026-09-10 01:27:11 +00:00
Fix ForceRelay UUID mismatch; add GHCR notes
Change ForceRelay TCP path to return a PunchHoleResponse with NatType=SYMMETRIC instead of sending a server-generated RelayResponse, so clients will send RequestRelay with their own UUIDs and both sides use the same UUID (resolves relay pairing mismatch, Issue #66). Add diagnostic log.Printf calls in handleRequestRelay (UDP) and handleRequestRelayTCP to aid relay pairing debugging. Update docs and CI: add GHCR "pull access denied" troubleshooting and package visibility guidance to DOCKER_QUICKSTART.md, docker-compose.quick.yml, and the docker-publish workflow summary (addresses Issue #67). Also update changelog entry in .github/copilot-instructions.md and add related files to .gitignore.
This commit is contained in:
@@ -536,6 +536,11 @@ sudo apt-get install -y build-essential libsqlite3-dev pkg-config libssl-dev git
|
||||
153. [x] **PS1 `RandomNumberGenerator::Fill` crash (Issue #38)**: `[System.Security.Cryptography.RandomNumberGenerator]::Fill()` is a .NET 6+ static method unavailable in Windows PowerShell 5.1 (.NET Framework 4.x). Changed to `RNGCryptoServiceProvider.GetBytes()` instance method which works on both .NET Framework 4.x and .NET 6+. Fixes API key generation failure → 0 devices in panel on fresh Windows install.
|
||||
154. [x] **Rust→Go upgrade detection (Issues #66, #38)**: `Do-Update` (PS1) and `do_update()` (bash) now detect `SERVER_TYPE=rust` (legacy hbbs/hbbr) and warn user that Rust→Go is a major architecture change requiring fresh installation. In auto mode, redirects to `Do-Install`/`do_install` automatically. In interactive mode, prompts user to confirm fresh install (recommended) or continue with partial update. Prevents broken upgrade path from v1.5.0 (Rust) to v2.3.0+ (Go).
|
||||
|
||||
#### Go Server — ForceRelay UUID Fix & Docker GHCR (Phase 27) ✅ COMPLETED 2026-03-19
|
||||
155. [x] **ForceRelay TCP UUID mismatch (Issue #66)**: `handlePunchHoleRequestTCP` ForceRelay path returned `RelayResponse{uuid=SERVER_UUID}` directly to TCP initiator. Some RustDesk client versions ignore the UUID from `RelayResponse` received in response to `PunchHoleRequest`, generate their own UUID, and connect to relay with it — while the target connects with the server's UUID. Relay pairing always failed (different UUIDs). **Fix**: ForceRelay TCP now returns `PunchHoleResponse{nat_type=SYMMETRIC}` instead of `RelayResponse`. Client sees SYMMETRIC NAT → sends `RequestRelay{uuid=CLIENT_UUID}` on same TCP connection → `handleRequestRelayTCP` forwards CLIENT_UUID to target → both sides use same UUID → relay pairing succeeds.
|
||||
156. [x] **Relay diagnostic logging**: Added `log.Printf` with UUID and relay server in `handleRequestRelayTCP` and `handleRequestRelay` (UDP) return paths for better relay pairing diagnostics.
|
||||
157. [x] **Docker GHCR "denied" error (Issue #67)**: Pre-built images on `ghcr.io/unitronix/betterdesk-*:latest` not available — workflow never triggered or packages are private. Added troubleshooting section to `DOCKER_QUICKSTART.md` (3 solutions: build locally, trigger workflow, authenticate). Added fallback comment to `docker-compose.quick.yml`. Added package visibility reminder to CI workflow summary step.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 System Statusu v3.0
|
||||
@@ -805,4 +810,4 @@ All code changes MUST include a security review as part of the implementation pr
|
||||
|
||||
---
|
||||
|
||||
*Ostatnia aktualizacja: 2026-03-19 (ALL-IN-ONE Scripts — PS1 Compatibility & Upgrade Detection — Phase 26) przez GitHub Copilot*
|
||||
*Ostatnia aktualizacja: 2026-03-19 (Go Server — ForceRelay UUID Fix & Docker GHCR — Phase 27) przez GitHub Copilot*
|
||||
|
||||
@@ -209,3 +209,8 @@ jobs:
|
||||
echo "curl -fsSL https://raw.githubusercontent.com/${{ github.repository }}/main/docker-compose.quick.yml -o docker-compose.yml" >> $GITHUB_STEP_SUMMARY
|
||||
echo "docker compose up -d" >> $GITHUB_STEP_SUMMARY
|
||||
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### ⚠️ Package Visibility" >> $GITHUB_STEP_SUMMARY
|
||||
echo "If packages are newly created, they default to **private**." >> $GITHUB_STEP_SUMMARY
|
||||
echo "To allow unauthenticated pulls, change visibility to **Public**:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "GitHub repo → Packages → (each package) → Package settings → Change visibility → Public" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -174,3 +174,6 @@ package-lock.json
|
||||
hbbs-patch/
|
||||
hbbs-patch-v2/
|
||||
tasks/todo.md
|
||||
docs/SECURITY_AUDIT_FULL_2026-03-19.md
|
||||
.github/copilot-instructions.md
|
||||
.github/copilot-instructions.md
|
||||
|
||||
@@ -115,6 +115,33 @@ curl http://localhost:21114/api/health
|
||||
|
||||
## ❓ Troubleshooting
|
||||
|
||||
### "denied" or "pull access denied" when starting
|
||||
|
||||
This means the pre-built images are not yet published to GitHub Container Registry.
|
||||
|
||||
**Solution A — Build locally (recommended):**
|
||||
```bash
|
||||
# Use the full docker-compose.yml which builds images from source
|
||||
git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git
|
||||
cd Rustdesk-FreeConsole
|
||||
docker compose -f docker-compose.yml up -d --build
|
||||
```
|
||||
|
||||
**Solution B — Wait for images to be published:**
|
||||
|
||||
The repository maintainer needs to trigger the Docker publish workflow:
|
||||
1. Go to: GitHub repo → Actions → "Build & Publish Docker Images"
|
||||
2. Click "Run workflow" → Branch: main → Click "Run workflow"
|
||||
3. Wait ~10 minutes for images to build
|
||||
4. Once images are published, retry `docker compose up -d`
|
||||
|
||||
**Solution C — Authenticate (if repo is private):**
|
||||
```bash
|
||||
# Create a GitHub Personal Access Token with 'read:packages' scope
|
||||
docker login ghcr.io -u YOUR_GITHUB_USERNAME -p YOUR_GITHUB_TOKEN
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### "Cannot connect to devices"
|
||||
|
||||
1. Check firewall allows ports 21116-21117
|
||||
|
||||
@@ -574,13 +574,23 @@ func (s *Server) handlePunchHoleRequestTCP(msg *pb.PunchHoleRequest, raddr *net.
|
||||
log.Printf("[signal] PunchHole (TCP): target %s found (addr=%s, status=%s), relay=%s",
|
||||
targetID, target.UDPAddr, target.StatusTier, relayServer)
|
||||
|
||||
// ForceRelay or AlwaysUseRelay: send RelayResponse (NOT PunchHoleResponse)
|
||||
// with a generated UUID, matching the UDP path's sendRelayResponse behavior.
|
||||
// RelayResponse contains the uuid field required by hbbr for session pairing.
|
||||
// ForceRelay or AlwaysUseRelay: return PunchHoleResponse with SYMMETRIC NAT
|
||||
// type instead of RelayResponse. This tells the client that direct P2P is
|
||||
// impossible and it should fall back to relay via RequestRelay.
|
||||
//
|
||||
// The client will then send RequestRelay (with its own UUID) on this same
|
||||
// TCP connection. handleRequestRelayTCP will forward it to the target and
|
||||
// return RelayResponse to the initiator. Both sides connect to relay with
|
||||
// the SAME client-generated UUID, ensuring relay pairing succeeds.
|
||||
//
|
||||
// Previously, returning RelayResponse directly with a server-generated UUID
|
||||
// caused UUID mismatch: some RustDesk client versions ignore the UUID from
|
||||
// a RelayResponse received in response to PunchHoleRequest (they expect
|
||||
// PunchHoleResponse), generate their own UUID, and connect to relay with it
|
||||
// — while the target connects with the server's UUID. This broke relay
|
||||
// pairing every time (Issue #66).
|
||||
if msg.ForceRelay || s.cfg.AlwaysUseRelay {
|
||||
log.Printf("[signal] PunchHole (TCP): force relay for %s", targetID)
|
||||
|
||||
relayUUID := uuid.New().String()
|
||||
log.Printf("[signal] PunchHole (TCP): force relay for %s (returning SYMMETRIC to let client drive relay UUID)", targetID)
|
||||
|
||||
var signedPk []byte
|
||||
if len(target.PK) > 0 {
|
||||
@@ -592,32 +602,18 @@ func (s *Server) handlePunchHoleRequestTCP(msg *pb.PunchHoleRequest, raddr *net.
|
||||
}
|
||||
}
|
||||
|
||||
// Forward RequestRelay to target so it connects to hbbr with the same UUID.
|
||||
reqRelay := &pb.RendezvousMessage{
|
||||
Union: &pb.RendezvousMessage_RequestRelay{
|
||||
RequestRelay: &pb.RequestRelay{
|
||||
Id: msg.Id,
|
||||
Uuid: relayUUID,
|
||||
SocketAddr: crypto.EncodeAddr(raddr),
|
||||
RelayServer: relayServer,
|
||||
Secure: false,
|
||||
ConnType: msg.ConnType,
|
||||
},
|
||||
},
|
||||
}
|
||||
var targetAddr []byte
|
||||
if target.UDPAddr != nil {
|
||||
// Store the UUID so we can recover it if target responds with empty UUID.
|
||||
s.storePendingUUID(targetID, relayUUID)
|
||||
s.sendUDP(reqRelay, target.UDPAddr)
|
||||
log.Printf("[signal] PunchHole (TCP): forwarded RequestRelay to target %s (uuid=%s)", targetID, relayUUID[:8])
|
||||
targetAddr = crypto.EncodeAddr(target.UDPAddr)
|
||||
}
|
||||
|
||||
return &pb.RendezvousMessage{
|
||||
Union: &pb.RendezvousMessage_RelayResponse{
|
||||
RelayResponse: &pb.RelayResponse{
|
||||
Uuid: relayUUID,
|
||||
Union: &pb.RendezvousMessage_PunchHoleResponse{
|
||||
PunchHoleResponse: &pb.PunchHoleResponse{
|
||||
SocketAddr: targetAddr,
|
||||
Pk: signedPk,
|
||||
RelayServer: relayServer,
|
||||
Union: &pb.RelayResponse_Pk{Pk: signedPk},
|
||||
Union: &pb.PunchHoleResponse_NatType{NatType: pb.NatType_SYMMETRIC},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -892,6 +888,7 @@ func (s *Server) handleRequestRelay(msg *pb.RequestRelay, raddr *net.UDPAddr) {
|
||||
}
|
||||
|
||||
// Confirm to initiator with SIGNED public key
|
||||
log.Printf("[signal] RequestRelay (UDP): returning RelayResponse to initiator %s (uuid=%s, relay=%s)", raddr, relayUUID[:8], relayServer)
|
||||
resp := &pb.RendezvousMessage{
|
||||
Union: &pb.RendezvousMessage_RelayResponse{
|
||||
RelayResponse: &pb.RelayResponse{
|
||||
@@ -997,6 +994,7 @@ func (s *Server) handleRequestRelayTCP(msg *pb.RequestRelay, raddr *net.UDPAddr)
|
||||
}
|
||||
|
||||
// Immediate RelayResponse to TCP initiator — matching the UDP handler's behavior.
|
||||
log.Printf("[signal] RequestRelay (TCP): returning RelayResponse to initiator %s (uuid=%s, relay=%s)", raddr, relayUUID[:8], relayServer)
|
||||
return &pb.RendezvousMessage{
|
||||
Union: &pb.RendezvousMessage_RelayResponse{
|
||||
RelayResponse: &pb.RelayResponse{
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
# Web Console: http://localhost:5000
|
||||
# Default credentials shown on first startup in logs:
|
||||
# docker compose logs console | grep -i password
|
||||
#
|
||||
# TROUBLESHOOTING: If you get "denied" or "pull access denied" error,
|
||||
# images may not be published yet. Build from source instead:
|
||||
# git clone https://github.com/UNITRONIX/Rustdesk-FreeConsole.git
|
||||
# cd Rustdesk-FreeConsole && docker compose -f docker-compose.yml up -d --build
|
||||
# =============================================================================
|
||||
|
||||
services:
|
||||
|
||||
Reference in New Issue
Block a user