From aa5383d8265106b22dc35ee987a587c8d29349a5 Mon Sep 17 00:00:00 2001 From: ARIA Date: Mon, 6 Jul 2026 21:46:07 +0200 Subject: [PATCH] Fix SPICE proxy tunnel: proxy URL was written into host= instead of a real proxy= line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Proxmox's spiceproxy API returns proxy as a ready-made "http://:3128" URL and host as the real (often cluster-internal) SPICE target. buildVVFile picked params.proxy first and wrote that whole URL into the .vv file's host= field, and never emitted a proxy= line at all — so virt-viewer tried to dial "http://:3128" as a literal hostname instead of tunneling through the proxy, and every connection failed. Bump to 1.0.7. --- package.json | 2 +- src/main.js | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f062d05..f08b7ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "proxmox-spice-client", - "version": "1.0.6", + "version": "1.0.7", "description": "VDI SPICE Client f\u00fcr Proxmox", "main": "src/main.js", "scripts": { diff --git a/src/main.js b/src/main.js index d282e05..90499e1 100644 --- a/src/main.js +++ b/src/main.js @@ -266,12 +266,19 @@ ipcMain.handle('settings:setAutoConnect', (_e, target) => { function buildVVFile(params, vmid, client) { const lines = ['[virt-viewer]', `type=${params.type || 'spice'}`]; - const host = params.proxy || params.host || client.host.split(':')[0]; + // params.host = the real SPICE target (often a cluster-internal node + // address) and params.proxy = a ready-made "http://:3128" + // URL that virt-viewer tunnels through via HTTP CONNECT. They are two + // different .vv fields — writing params.proxy into host= (as before) + // handed virt-viewer a full URL as a hostname and never opened the + // tunnel, so it tried (and failed) to dial the internal address directly. + const host = params.host || client.host.split(':')[0]; lines.push(`host=${host}`); if (params['tls-port']) lines.push(`tls-port=${params['tls-port']}`); if (params.port) lines.push(`port=${params.port}`); if (params.password) lines.push(`password=${params.password}`); + if (params.proxy) lines.push(`proxy=${params.proxy}`); if (params.ca) { const caPath = path.join(os.tmpdir(), 'proxmox-spice-ca.pem'); @@ -291,11 +298,11 @@ function buildVVFile(params, vmid, client) { const vvPath = path.join(os.tmpdir(), `spice-${vmid}-${Date.now()}.vv`); fs.writeFileSync(vvPath, lines.join('\n') + '\n', { mode: 0o600 }); - // Surfaced to the renderer so a failed connection (e.g. Proxmox handing out - // a cluster-internal node address the client can't route to) is diagnosable - // without having to catch the .vv file before remote-viewer deletes it. + // Surfaced to the renderer so a failed connection is diagnosable without + // having to catch the .vv file before remote-viewer deletes it. const port = params['tls-port'] || params.port || '?'; - return { vvPath, target: `${host}:${port}` }; + const target = params.proxy ? `${host}:${port} via ${params.proxy}` : `${host}:${port}`; + return { vvPath, target }; } // VirtViewer's Windows installer names its folder after the bundled version