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;
|
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 {
|
try {
|
||||||
// 1. Select protocol
|
// 1. Select protocol
|
||||||
@@ -158,6 +180,8 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
|||||||
'create-drive-path': 'false',
|
'create-drive-path': 'false',
|
||||||
'enable-printing': 'false',
|
'enable-printing': 'false',
|
||||||
'disable-glyph-caching': 'true',
|
'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',
|
'resize-method': 'display-update',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -188,8 +212,9 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
|||||||
socket.send(buildInstruction('', guacdUUID));
|
socket.send(buildInstruction('', guacdUUID));
|
||||||
|
|
||||||
// 6. Flush any buffered bytes that arrived after 'ready'
|
// 6. Flush any buffered bytes that arrived after 'ready'
|
||||||
if (tcpBuf.value.length > 0 && socket.readyState === WebSocket.OPEN) {
|
if (tcpBuf.value.length > 0) {
|
||||||
socket.send(tcpBuf.value);
|
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 = '';
|
tcpBuf.value = '';
|
||||||
}
|
}
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
@@ -205,10 +230,7 @@ export async function rdpWebsocket(fastify: FastifyInstance) {
|
|||||||
// --- Proxy mode ---
|
// --- Proxy mode ---
|
||||||
guacd.on('data', (data: Buffer) => {
|
guacd.on('data', (data: Buffer) => {
|
||||||
const text = data.toString('utf8');
|
const text = data.toString('utf8');
|
||||||
// Log the first message from guacd (usually an error or first instruction)
|
fastify.log.debug({ guacdData: text.substring(0, 300) }, 'RDP: data from guacd');
|
||||||
if (text.startsWith('5.error') || text.startsWith('10.disconnect')) {
|
|
||||||
fastify.log.warn({ guacdMsg: text.substring(0, 200) }, 'RDP: guacd sent error/disconnect');
|
|
||||||
}
|
|
||||||
if (socket.readyState === WebSocket.OPEN) socket.send(text);
|
if (socket.readyState === WebSocket.OPEN) socket.send(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user