fix
This commit is contained in:
331
RDP_Diagnose_Phase16.md
Normal file
331
RDP_Diagnose_Phase16.md
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
# Warum eine Windows-RDP-Sitzung nicht funktioniert — vollstaendige Fehlersuche
|
||||||
|
|
||||||
|
Stand: 2026-08-21 · Untersucht: `app/rdp_proxy/*`, `static/js/rdp.js`,
|
||||||
|
`templates/rdp.html`, `app/recordings/recorder.py`, Migrationen 0003/0009/0010/0012,
|
||||||
|
`ansible/roles/{guacd,jumphost_app,nginx_proxy,firewall_nftables,sqlite_init,python_runtime}`.
|
||||||
|
|
||||||
|
Alle mit **[nachgewiesen]** markierten Punkte wurden in der Sandbox gegen den
|
||||||
|
ECHTEN Anwendungscode reproduziert: Fake-guacd ueber eine echte TCP-Verbindung
|
||||||
|
mit der Argumentliste eines guacd 1.5, echtes starlette-WebSocket ueber ein
|
||||||
|
ASGI-Nachrichtenpaar, echte SQLite-DB mit allen Migrationen. Die dafuer noetigen
|
||||||
|
Sandbox-Attrappen (fastapi/aiosqlite/asyncssh/argon2) liegen unter `/tmp/work/stubs`
|
||||||
|
und sind NICHT Teil des Auslieferungsstands.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kurzfassung
|
||||||
|
|
||||||
|
Es gibt nicht *einen* Fehler, sondern drei Gruppen:
|
||||||
|
|
||||||
|
1. **Die Bruecke ist zu langsam und hat kein Timeout** (A1–A3). Selbst bei
|
||||||
|
perfekter Konfiguration bricht die Sitzung ab oder wirkt eingefroren.
|
||||||
|
2. **Die Umgebung liefert guacd/RDP gar nicht aus bzw. blockiert es** (B1–B6).
|
||||||
|
Dann kommt nie ein Bild — meist ohne verwertbare Meldung.
|
||||||
|
3. **Parameter- und Datenfehler in der connect-Instruktion** (C1–C4). Windows
|
||||||
|
lehnt die Anmeldung ab oder guacd faellt auf ein Uraltprotokoll zurueck.
|
||||||
|
|
||||||
|
Reihenfolge zum Abarbeiten steht am Ende unter *Pruefreihenfolge*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A. Sitzung kommt zustande, ist aber unbrauchbar / bricht ab
|
||||||
|
|
||||||
|
### A1 — Der guacd-Leser liest BYTEWEISE: ca. 1 MB/s Obergrenze, blockiert dabei den ganzen Dienst **[nachgewiesen]**
|
||||||
|
|
||||||
|
`app/rdp_proxy/guacd_client.py:44-66` — `_read_until()` und `_read_chars()` holen
|
||||||
|
sich jedes einzelne Byte mit `await reader.readexactly(1)`. Fuer eine
|
||||||
|
RDP-Sitzung, deren Datenstrom fast nur aus base64-kodierten PNG-Kacheln besteht,
|
||||||
|
sind das zehntausende `await`s pro Bildschirmaktualisierung.
|
||||||
|
|
||||||
|
Messung (5,01 MB realistischer `blob`-Strom, 6-KB-Kacheln):
|
||||||
|
|
||||||
|
| Variante | Zeit | Durchsatz |
|
||||||
|
|---|---|---|
|
||||||
|
| aktuell (`readexactly(1)` je Byte) | 4,7 s | **1,05 MB/s** |
|
||||||
|
| gepuffert (`readuntil(b".")` + `readexactly(len)`) | 0,01 s | 690 MB/s |
|
||||||
|
|
||||||
|
Faktor **644x**. Ein erster Bildschirmaufbau von 3 MB braucht im echten Pfad
|
||||||
|
(`rdp_tunnel` end-to-end gemessen) **3,14 s** — und zwar 3,14 s reine CPU-Zeit im
|
||||||
|
Event-Loop, in denen der gesamte Dienst steht: alle anderen RDP-Sitzungen, alle
|
||||||
|
SSH-Sitzungen, die Admin-Oberflaeche, das Verbindungslog.
|
||||||
|
|
||||||
|
Interaktive RDP-Nutzung (Fenster verschieben, scrollen, Video) erzeugt dauerhaft
|
||||||
|
mehrere MB/s. Der Tunnel kommt nicht hinterher, der Rueckstand waechst
|
||||||
|
unbegrenzt: Bild friert ein, Maus reagiert Sekunden spaeter, irgendwann greift
|
||||||
|
der Browser-Timeout. **Das ist die wahrscheinlichste Ursache fuer "verbindet,
|
||||||
|
aber es tut sich nichts".**
|
||||||
|
|
||||||
|
*Behebung:* `_read_until`/`_read_chars` durch `reader.readuntil(b".")` +
|
||||||
|
`readexactly(length)` ersetzen (die Zeichen-statt-Byte-Semantik aus Phase 10
|
||||||
|
bleibt erhalten: nur die noch fehlenden Zeichen einzeln nachdekodieren, siehe
|
||||||
|
Prototyp in der Messung — Ergebnis war fuer ASCII wie fuer Umlaute identisch zur
|
||||||
|
bisherigen Implementierung). Zusaetzlich `asyncio.open_connection(..., limit=1<<20)`
|
||||||
|
setzen, damit `readuntil` bei grossen Elementen nicht in `LimitOverrunError` laeuft.
|
||||||
|
|
||||||
|
### A2 — Waehrend des guacd-/RDP-Verbindungsaufbaus schweigt der Server: Browser bricht nach 15 s ab **[nachgewiesen]**
|
||||||
|
|
||||||
|
`app/rdp_proxy/ws_tunnel.py:235-244`: erst `await open_tunnel(...)`, und **danach**
|
||||||
|
werden die beiden Pumpen-Tasks gestartet. Solange guacd noch mit dem Windows-Ziel
|
||||||
|
verhandelt, liest niemand vom WebSocket — die Pings von guacamole-common-js
|
||||||
|
(alle 5 s) landen in der Queue und werden **nicht** beantwortet.
|
||||||
|
|
||||||
|
guacamole-common-js bricht nach `tunnel.receiveTimeout = 15000` ohne EINEN
|
||||||
|
empfangenen Frame mit "Server timeout." ab (`static/js/vendor/guacamole-common.js:14605,15448`).
|
||||||
|
Der Timer startet mit `socket.onopen`; die Tunnel-UUID zu Beginn setzt ihn genau
|
||||||
|
einmal zurueck. Effektives Budget: **15 Sekunden fuer den kompletten
|
||||||
|
RDP-Verbindungsaufbau.**
|
||||||
|
|
||||||
|
Nachweis (echter `rdp_tunnel`, Fake-guacd mit 6 s bis `ready`, Browser sendet
|
||||||
|
sekuendlich Pings):
|
||||||
|
|
||||||
|
```
|
||||||
|
t= 0.00s websocket.accept
|
||||||
|
t= 0.00s websocket.send '0.,36.919c58ab-...;' <- Tunnel-UUID
|
||||||
|
t= 6.01s websocket.send '4.blob,...' <- erst nach ready
|
||||||
|
t= 6.01s websocket.send '0.,4.ping,...' x6 <- ALLE Pings auf einen Schlag
|
||||||
|
```
|
||||||
|
|
||||||
|
Sechs Sekunden lang ging kein einziger Frame an den Browser. Ueberschreitet der
|
||||||
|
RDP-Handshake 15 s — nicht erreichbares Ziel (TCP-Timeout!), NLA/CredSSP-Aushandlung,
|
||||||
|
langsame DC-Anmeldung, Zertifikatspruefung — sieht der Benutzer "Fehler: Server
|
||||||
|
timeout", waehrend serverseitig alles "normal" aussieht.
|
||||||
|
|
||||||
|
*Behebung:* die WS-Leseschleife VOR `open_tunnel()` starten (Pings sofort
|
||||||
|
spiegeln, restliche Client-Instruktionen bis zum offenen Tunnel puffern oder
|
||||||
|
verwerfen), oder waehrend des Aufbaus einen eigenen Keepalive-Task laufen lassen,
|
||||||
|
der eintreffende Pings beantwortet.
|
||||||
|
|
||||||
|
### A3 — `open_tunnel()` hat kein einziges Timeout **[nachgewiesen]**
|
||||||
|
|
||||||
|
`app/rdp_proxy/guacd_client.py:134-160`: weder `asyncio.open_connection` noch die
|
||||||
|
`read_instruction`-Aufrufe (args, ready) sind zeitbegrenzt. Antwortet guacd nach
|
||||||
|
dem TCP-Accept nicht mehr (haengendes guacd, blockierender FreeRDP-Aufruf),
|
||||||
|
haengt die Coroutine **unbegrenzt**: der `sessions`-Datensatz bleibt ohne
|
||||||
|
`ended_at` offen, die Aufzeichnungsdatei bleibt offen, `active_sessions` behaelt
|
||||||
|
den Eintrag, das Websocket bleibt belegt. Reproduziert mit einem guacd, das
|
||||||
|
nichts sendet — der Aufruf lief bis zum kuenstlichen Abbruch nach 3 s weiter.
|
||||||
|
|
||||||
|
*Behebung:* `asyncio.wait_for(...)` um Verbindungsaufbau (z.B. 5 s) und um den
|
||||||
|
gesamten Handshake bis `ready` (z.B. 60 s, konfigurierbar), mit einer eigenen
|
||||||
|
Klartextmeldung.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## B. Umgebung: guacd fehlt, ist unerreichbar oder darf nicht raus
|
||||||
|
|
||||||
|
### B1 — Auf Debian 13 (trixie) wird guacd ueberhaupt nicht gebaut
|
||||||
|
|
||||||
|
`ansible/roles/guacd/tasks/main.yml` dokumentiert es selbst: weder der
|
||||||
|
1.6.0-Release noch `git main` bauen gegen das FreeRDP 3.15 von trixie
|
||||||
|
(GUACAMOLE-2146). Der Playbook-Lauf laesst dann entweder einen kaputten Build
|
||||||
|
zurueck oder gar kein `/usr/local/sbin/guacd`. Ergebnis im Browser:
|
||||||
|
`Fehler: [Errno 111] Connect call failed ('127.0.0.1', 4822)` **[nachgewiesen]**.
|
||||||
|
Auf Ubuntu greift der apt-Pfad (guacd 1.3.0 aus *universe*) und funktioniert.
|
||||||
|
|
||||||
|
**Erste Frage bei jeder RDP-Fehlersuche: `systemctl status guacd` und
|
||||||
|
`ss -ltnp | grep 4822` auf dem Jumphost.**
|
||||||
|
|
||||||
|
### B2 — Die Rolle stellt weder "guacd laeuft" noch "RDP-Plugin vorhanden" sicher
|
||||||
|
|
||||||
|
Es gibt keinen Task `service: name=guacd state=started enabled=true`; gestartet
|
||||||
|
wird nur ueber den Handler, also **nur wenn sich guacd.conf geaendert hat**. Und:
|
||||||
|
`./configure` erkennt FreeRDP selbst — fehlen die Header, baut es klaglos ein
|
||||||
|
guacd **ohne** RDP-Plugin. guacd antwortet dann mit
|
||||||
|
`error: Support for protocol "rdp" is not installed` **[nachgewiesen]**, was der
|
||||||
|
Benutzer als kryptische Meldung im Browser sieht.
|
||||||
|
|
||||||
|
*Behebung:* expliziter start/enable-Task; nach `make install` pruefen, dass
|
||||||
|
`libguac-client-rdp.so` existiert, sonst hart abbrechen.
|
||||||
|
|
||||||
|
### B3 — Beim Quellcode-Build liest guacd die geschriebene Konfiguration gar nicht
|
||||||
|
|
||||||
|
Die Rolle schreibt `/etc/guacamole/guacd.conf`. Ein mit `./configure` ohne
|
||||||
|
`--sysconfdir` gebautes guacd liegt unter `/usr/local` und liest
|
||||||
|
`/usr/local/etc/guacamole/guacd.conf`. `bind_host`/`bind_port` bleiben also
|
||||||
|
wirkungslos. Solange alles auf den Vorgaben (localhost:4822) steht, faellt das
|
||||||
|
nicht auf — **sobald jemand `guacd_port` aendert, ist RDP still tot**, weil die
|
||||||
|
App auf dem neuen Port sucht und guacd weiter auf 4822 lauscht.
|
||||||
|
|
||||||
|
*Behebung:* `./configure --sysconfdir=/etc` ergaenzen (oder die Datei an beide
|
||||||
|
Orte schreiben).
|
||||||
|
|
||||||
|
### B4 — `lineinfile` legt `/etc/guacamole` nicht an
|
||||||
|
|
||||||
|
`ansible.builtin.lineinfile` mit `create: true` legt die *Datei*, nicht das
|
||||||
|
Verzeichnis an. Auf dem Debian-Quellcode-Pfad existiert `/etc/guacamole` nicht →
|
||||||
|
Task schlaegt fehl → Rolle bricht ab → guacd bleibt unkonfiguriert/ungestartet.
|
||||||
|
Fehlt ein `file: path=/etc/guacamole state=directory` davor.
|
||||||
|
|
||||||
|
### B5 — nftables verwirft ausgehendes RDP, wenn das Ziel nicht in `target_networks` liegt
|
||||||
|
|
||||||
|
`ansible/roles/firewall_nftables/templates/jumphost.nft.j2`: die output-Chain hat
|
||||||
|
`policy drop` und erlaubt ausgehend nur `ip daddr {{ target_networks }}` (Default
|
||||||
|
`10.20.0.0/16`), DNS, NTP, 80/443. Steht das Windows-Ziel in einem anderen Netz
|
||||||
|
(z.B. 192.168.x.x oder 10.0.x.x), werden die Pakete **still verworfen** — kein
|
||||||
|
Log, kein Reject. guacd wartet dann bis zum TCP-Timeout, und wegen **A2** sieht
|
||||||
|
der Benutzer "Server timeout" statt "Ziel nicht erreichbar".
|
||||||
|
|
||||||
|
*Pruefen:* `nft list ruleset | grep daddr` und die Zieladresse vergleichen.
|
||||||
|
|
||||||
|
### B6 — guacd darf nicht in sein eigenes Laufwerksverzeichnis
|
||||||
|
|
||||||
|
`build_rdp_params()` setzt `enable-drive=true` und
|
||||||
|
`drive-path=/var/lib/jumphost/rdp-drives/<host-id>`, sobald am Host
|
||||||
|
`file_transfer_enabled` gesetzt ist. Die Rolle legt `rdp-drives` korrekt fuer den
|
||||||
|
User `guacd` an — **aber das Elternverzeichnis `/var/lib/jumphost` ist
|
||||||
|
0700 `jumphost:jumphost`** (`roles/sqlite_init`, zusaetzlich `app/db.py:init_db()`
|
||||||
|
mit `mode=0o700`). Der User `guacd` kann es nicht durchqueren (EACCES).
|
||||||
|
Laufwerksumleitung schlaegt damit immer fehl; je nach guacd-Version endet das bei
|
||||||
|
einer Fehlermeldung im guacd-Log — im schlechteren Fall bricht die Sitzung ab.
|
||||||
|
|
||||||
|
*Behebung:* Laufwerke aus dem App-Datenverzeichnis herausnehmen (z.B.
|
||||||
|
`/var/lib/guacd-drives`) oder `/var/lib/jumphost` auf 0750 mit gemeinsamer Gruppe
|
||||||
|
setzen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## C. Parameter- und Datenfehler in der connect-Instruktion
|
||||||
|
|
||||||
|
### C1 — Der Versions-Slot wird leer gesendet: guacd faellt auf Protokoll 1.0.0 zurueck **[nachgewiesen]**
|
||||||
|
|
||||||
|
Ein echtes guacd 1.5 sendet als ERSTES Element seiner `args`-Instruktion das
|
||||||
|
Versions-Token `VERSION_1_5_0`; der Client muss an derselben Position die von ihm
|
||||||
|
gesprochene Version zuruecksenden. `guacd_client.py:153`
|
||||||
|
(`values = [params.get(name, "") for name in arg_names]`) kennt den Namen nicht
|
||||||
|
und schickt dort einen Leerstring:
|
||||||
|
|
||||||
|
```
|
||||||
|
-- Anzahl args: 85 Anzahl connect-Werte: 85
|
||||||
|
VERSION_1_5_0 = ''
|
||||||
|
hostname = '10.0.0.5'
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
guacd stuft die Verbindung damit auf 1.0.0 zurueck. Verloren gehen u.a.
|
||||||
|
`timezone`, die `required`-Instruktion (Nachfordern von Zugangsdaten) und
|
||||||
|
`msg`-Meldungen. Kein sofortiger Abbruch, aber ein latenter Fehler, der bei
|
||||||
|
neueren guacd-Versionen weiter aufmacht.
|
||||||
|
|
||||||
|
*Behebung:* Elemente, die auf `VERSION_` passen, erkennen und die hoechste
|
||||||
|
gemeinsam unterstuetzte Version zuruecksenden (Verhalten des offiziellen
|
||||||
|
guacamole-client).
|
||||||
|
|
||||||
|
### C2 — Migration 0012 schreibt den Platzhalter `(kein Benutzername)` als echten Benutzernamen **[nachgewiesen]**
|
||||||
|
|
||||||
|
`0012_rdp_credential_sets.sql`:
|
||||||
|
`COALESCE(NULLIF(TRIM(rcl.username), ''), '(kein Benutzername)')`.
|
||||||
|
|
||||||
|
Fuer jeden vor Migration 0010 angelegten Datensatz ohne Benutzernamen steht damit
|
||||||
|
buchstaeblich `(kein Benutzername)` in `rdp_credentials.username`. Die
|
||||||
|
Schutzpruefung in `build_rdp_params()` greift nicht (der Wert ist ja nicht leer),
|
||||||
|
und dieser String wird als Anmeldename an Windows geschickt:
|
||||||
|
|
||||||
|
```
|
||||||
|
connect-Parameter username = '(kein Benutzername)'
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Benutzer bekommt "Anmeldung fehlgeschlagen" statt des klaren Hinweises, dass
|
||||||
|
am Zugangsdatensatz kein Benutzername hinterlegt ist. Beim leeren String
|
||||||
|
funktioniert die Pruefung dagegen einwandfrei.
|
||||||
|
|
||||||
|
*Behebung:* Migration nachziehen (`UPDATE rdp_credentials SET username='' WHERE
|
||||||
|
username='(kein Benutzername)'`) oder den Platzhalter in `build_rdp_params()` /
|
||||||
|
im Admin-UI wie "leer" behandeln.
|
||||||
|
|
||||||
|
### C3 — `width`/`height`/`dpi` stehen nicht in der connect-Instruktion
|
||||||
|
|
||||||
|
Sie werden nur ueber die `size`-Handshake-Instruktion uebergeben. Das
|
||||||
|
funktioniert, weil guacd bei leeren Werten auf die "optimale" Groesse des Users
|
||||||
|
zurueckfaellt — es ist aber Zufall, kein Design. Ebenso fehlen `timezone` (Windows
|
||||||
|
uebernimmt sonst die Serverzeitzone) und `client-name`.
|
||||||
|
|
||||||
|
### C4 — Fehlermeldungen erreichen den Browser als Python-Repr **[nachgewiesen]**
|
||||||
|
|
||||||
|
Was der Benutzer aktuell sieht:
|
||||||
|
|
||||||
|
```
|
||||||
|
Fehler: Verbindungsaufbau fehlgeschlagen: ['error', 'Login failed', '769']
|
||||||
|
Fehler: Verbindungsaufbau fehlgeschlagen: ['error', 'Support for protocol "rdp" is not installed', '512']
|
||||||
|
Fehler: [Errno 111] Connect call failed ('127.0.0.1', 4822)
|
||||||
|
```
|
||||||
|
|
||||||
|
Der guacd-Statuscode (769 = Anmeldung fehlgeschlagen, 512 = Serverfehler,
|
||||||
|
519 = Ziel nicht erreichbar) wird nicht uebersetzt, und der Text wird zusaetzlich
|
||||||
|
auf 123 Byte gekuerzt (RFC 6455). Fuer Bedienbarkeit und Fehlersuche: Codes auf
|
||||||
|
deutsche Klartexte abbilden und den vollstaendigen Text zusaetzlich als
|
||||||
|
`error`-Instruktion ueber den bereits offenen Tunnel senden, bevor geschlossen wird.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D. Kleinere Befunde
|
||||||
|
|
||||||
|
* **D1 — Falsche Hosts im Dashboard.** `app/catalog/routes.py:48,56` filtert auf
|
||||||
|
`r.name IN ('ssh_connect','rdp_connect')` ohne das Protokoll des Hosts zu
|
||||||
|
beruecksichtigen. Ein Benutzer mit nur `ssh_connect` sieht Windows-Hosts inkl.
|
||||||
|
"Verbinden"-Knopf und faellt dann in die Ablehnung 4403.
|
||||||
|
* **D2 — Die Aufzeichnung schreibt den kompletten Bildstrom, synchron.**
|
||||||
|
`recorder.py:41` flusht bei JEDER Instruktion, aus dem Event-Loop heraus.
|
||||||
|
Gemessen: 5 MB RDP-Bildstrom → 5,14 MB JSONL. Eine halbe Stunde normales
|
||||||
|
Arbeiten fuellt so schnell mehrere GB unter `/var/lib/jumphost/recordings`;
|
||||||
|
laeuft die Partition voll, sterben auch die SSH-Sitzungen und die Datenbank.
|
||||||
|
Fuer RDP eher `blob`-Instruktionen ausklammern oder das guacamole-eigene
|
||||||
|
Aufzeichnungsformat (`recording-path`) von guacd schreiben lassen.
|
||||||
|
* **D3 — CSP kennt kein `blob:` fuer Bilder.** `app/main.py` setzt
|
||||||
|
`img-src 'self' data:`. guacamole-common-js nutzt bevorzugt
|
||||||
|
`createImageBitmap()` (davon nicht betroffen), faellt aber auf
|
||||||
|
`URL.createObjectURL()` zurueck — auf einem Browser ohne `createImageBitmap`
|
||||||
|
bleibt das Bild dann schwarz. `blob:` ergaenzen.
|
||||||
|
* **D4 — Kein Resize.** `client.sendSize()` wird nie aufgerufen; die Aufloesung
|
||||||
|
steht auf dem Fenstermass beim Verbindungsaufbau fest, obwohl
|
||||||
|
`resize-method=display-update` gesetzt ist.
|
||||||
|
* **D5 — Clipboard-Filter greift nur auf die erste Instruktion** einer
|
||||||
|
WebSocket-Nachricht (`_ws_to_guacd`). guacamole-common-js sendet zwar eine
|
||||||
|
Instruktion je Nachricht, verlassen sollte man sich darauf aber nicht.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Was nachweislich in Ordnung ist
|
||||||
|
|
||||||
|
Damit die Fehlersuche nicht dort weitergeht:
|
||||||
|
|
||||||
|
* Handshake-Reihenfolge `select → args → size/audio/video/image → connect → ready`
|
||||||
|
ist korrekt, alle Parameter (hostname, port, username, password, domain,
|
||||||
|
security=nla, ignore-cert, disable-copy/paste, resize-method) landen an der
|
||||||
|
richtigen Position **[nachgewiesen]**.
|
||||||
|
* Subprotokoll `guacamole` wird im Handshake bestaetigt **[nachgewiesen:
|
||||||
|
`accept(subprotocol='guacamole')`]** — der Fix aus Phase 10 haelt.
|
||||||
|
* Tunnel-URL enthaelt keine Query-Parameter mehr, `client.connect(connectParams)`
|
||||||
|
ist richtig — der Phase-10-Fix haelt.
|
||||||
|
* Zeichen- statt Bytelaengen im Guacamole-Protokoll: korrekt, inkl. Umlauten
|
||||||
|
**[nachgewiesen]**.
|
||||||
|
* Tunnel-UUID als erste Instruktion, ping-Spiegelung, Clipboard-Sperre,
|
||||||
|
RBAC-Pruefung `rdp_connect`, Entschluesselung des Passworts innerhalb des
|
||||||
|
try/finally: alles wie vorgesehen **[end-to-end nachgewiesen]**.
|
||||||
|
* nginx reicht `/ws/` korrekt mit `Upgrade`/`Connection` und 3600 s Read-Timeout
|
||||||
|
durch; das Subprotokoll geht als normaler Header mit.
|
||||||
|
* Admin-Oberflaeche und API fuer RDP-Zugangsdaten (anlegen, zuweisen, loesen)
|
||||||
|
sind vollstaendig.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pruefreihenfolge fuer den konkreten Fall
|
||||||
|
|
||||||
|
1. `systemctl status guacd; ss -ltnp | grep 4822` → laeuft guacd ueberhaupt? (B1/B2)
|
||||||
|
2. `ls /usr/lib/*/libguac-client-rdp.so* /usr/local/lib/libguac-client-rdp.so*` → RDP-Plugin gebaut? (B2)
|
||||||
|
3. `journalctl -u guacd -f` waehrend eines Verbindungsversuchs → sagt guacd etwas? (B5: gar nichts = Pakete gehen nicht raus)
|
||||||
|
4. Vom Jumphost aus: `nc -vz <windows-ip> 3389` → Firewall/Routing (B5)
|
||||||
|
5. Im Adminbereich: Zugangsdaten des Hosts pruefen — steht dort `(kein Benutzername)`? (C2)
|
||||||
|
6. Erst wenn 1–5 sauber sind: A1–A3 beheben, sonst bleibt die Sitzung langsam bzw. bricht nach 15 s ab.
|
||||||
|
|
||||||
|
## Empfohlene Reihenfolge der Behebung
|
||||||
|
|
||||||
|
| # | Aufwand | Wirkung |
|
||||||
|
|---|---|---|
|
||||||
|
| A1 gepufferter Leser | klein (~20 Zeilen) | macht RDP ueberhaupt erst benutzbar |
|
||||||
|
| A2 Leseschleife vor `open_tunnel` | mittel | beseitigt "Server timeout" beim Aufbau |
|
||||||
|
| A3 Timeouts | klein | keine haengenden Sitzungen mehr |
|
||||||
|
| C4 Fehlertexte | klein | jede weitere Fehlersuche wird billiger |
|
||||||
|
| C2 Platzhalter-Benutzername | klein (Migration 0013) | falsche Anmeldung → klare Meldung |
|
||||||
|
| B2/B3/B4/B6 Ansible | mittel | Deployment liefert wirklich ein funktionierendes guacd |
|
||||||
|
| C1 Versionsaushandlung | klein | Zukunftssicherheit gegen neuere guacd |
|
||||||
|
| D1–D5 | klein | Bedienbarkeit, Plattenplatz |
|
||||||
BIN
_to_delete/appsrc.tgz
Normal file
BIN
_to_delete/appsrc.tgz
Normal file
Binary file not shown.
Reference in New Issue
Block a user