RDP diagnostics: TCP pre-check, disable-gfx, better logging
- Add TCP connectivity pre-test before guacd handshake — gives a clear error message if the RDP host is unreachable from the Docker network - Add disable-gfx:true (disables GFX Pipeline Extension, known FreeRDP 2.x crash source on Windows 10/11) and cert-tofu:true - Log tcpBuf flush content and all guacd data at debug level so we can see exactly what guacd sends after the ready instruction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -128,7 +128,29 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
fastify.log.info({ host: conn.host, port: conn.port, user: conn.username }, 'RDP: starting guacd handshake');
|
||||
// Pre-check: verify the RDP server is TCP-reachable from this container.
|
||||
// The backend is on the same Docker network as guacd, so same reachability.
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const test = createConnection(conn.port, conn.host);
|
||||
const timer = setTimeout(() => {
|
||||
test.destroy();
|
||||
reject(new Error(`Cannot reach ${conn.host}:${conn.port} — connection timed out`));
|
||||
}, 5000);
|
||||
test.once('connect', () => { clearTimeout(timer); test.destroy(); resolve(); });
|
||||
test.once('error', (err) => {
|
||||
clearTimeout(timer);
|
||||
reject(new Error(`Cannot reach ${conn.host}:${conn.port} — ${err.message}`));
|
||||
});
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : 'Cannot reach RDP host';
|
||||
fastify.log.warn({ host: conn.host, port: conn.port }, msg);
|
||||
socket.close(1011, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
fastify.log.info({ host: conn.host, port: conn.port, user: conn.username }, 'RDP: TCP reachable, starting guacd handshake');
|
||||
|
||||
try {
|
||||
// 1. Select protocol
|
||||
@@ -158,6 +180,8 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
||||
'create-drive-path': 'false',
|
||||
'enable-printing': 'false',
|
||||
'disable-glyph-caching': 'true',
|
||||
'disable-gfx': 'true', // disable GFX Pipeline Extension (known FreeRDP 2.x crash source)
|
||||
'cert-tofu': 'true', // trust certificate on first use
|
||||
'resize-method': 'display-update',
|
||||
};
|
||||
|
||||
@@ -188,8 +212,9 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
||||
socket.send(buildInstruction('', guacdUUID));
|
||||
|
||||
// 6. Flush any buffered bytes that arrived after 'ready'
|
||||
if (tcpBuf.value.length > 0 && socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(tcpBuf.value);
|
||||
if (tcpBuf.value.length > 0) {
|
||||
fastify.log.info({ flushed: tcpBuf.value.substring(0, 300) }, 'RDP: flushing buffered data after ready');
|
||||
if (socket.readyState === WebSocket.OPEN) socket.send(tcpBuf.value);
|
||||
tcpBuf.value = '';
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
@@ -205,10 +230,7 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
||||
// --- Proxy mode ---
|
||||
guacd.on('data', (data: Buffer) => {
|
||||
const text = data.toString('utf8');
|
||||
// Log the first message from guacd (usually an error or first instruction)
|
||||
if (text.startsWith('5.error') || text.startsWith('10.disconnect')) {
|
||||
fastify.log.warn({ guacdMsg: text.substring(0, 200) }, 'RDP: guacd sent error/disconnect');
|
||||
}
|
||||
fastify.log.debug({ guacdData: text.substring(0, 300) }, 'RDP: data from guacd');
|
||||
if (socket.readyState === WebSocket.OPEN) socket.send(text);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user