fix: expose jump tunnels to guacd (#1115)

This commit is contained in:
ZacharyZcR
2026-07-28 01:48:40 +08:00
committed by GitHub
parent 066d7e77b3
commit 760c7b86c3
5 changed files with 59 additions and 2 deletions
+1
View File
@@ -13,6 +13,7 @@ services:
PORT: "8080"
NODE_ENV: development
GUACD_HOST: "guacd-dev"
GUACD_TUNNEL_HOST: "termix-dev"
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
depends_on:
- guacd-dev
+1
View File
@@ -10,6 +10,7 @@ services:
environment:
PORT: "8080"
GUACD_HOST: "guacd"
GUACD_TUNNEL_HOST: "termix"
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
depends_on:
- guacd
@@ -0,0 +1,15 @@
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "::1"]);
export function resolveJumpTunnelEndpoint(
guacdHost: string,
tunnelHost = process.env.GUACD_TUNNEL_HOST,
): { bindHost: string; advertisedHost: string } {
if (LOOPBACK_HOSTS.has(guacdHost.toLowerCase())) {
return { bindHost: "127.0.0.1", advertisedHost: "127.0.0.1" };
}
return {
bindHost: "0.0.0.0",
advertisedHost: tunnelHost?.trim() || "termix",
};
}
+15 -2
View File
@@ -15,6 +15,7 @@ import { resolveGuacdOptions } from "../../utils/guacd-config.js";
import { createJumpHostChain } from "../jump-host-chain.js";
import type { SOCKS5Config } from "../../utils/socks5-helper.js";
import { waitForGuacdOpen } from "./guacamole-server.js";
import { resolveJumpTunnelEndpoint } from "./jump-tunnel-endpoint.js";
const router = express.Router();
const tokenService = GuacamoleTokenService.getInstance();
@@ -485,6 +486,18 @@ router.post(
if (jumpHosts.length > 0) {
try {
let guacdUrl: string | undefined;
try {
guacdUrl =
(await createCurrentSettingsRepository().get("guac_url")) ??
undefined;
} catch {
// Environment/default guacd configuration remains available.
}
const guacdHost =
perConnectionGuacdHost || resolveGuacdOptions(guacdUrl).host;
const tunnelEndpoint = resolveJumpTunnelEndpoint(guacdHost);
let socks5ProxyChain: ProxyNode[] = [];
if (hostRecord.socks5ProxyChain) {
try {
@@ -550,7 +563,7 @@ router.post(
);
});
server.on("error", reject);
server.listen(0, "127.0.0.1", () => {
server.listen(0, tunnelEndpoint.bindHost, () => {
const addr = server.address() as net.AddressInfo;
// Auto-cleanup after 1 hour
setTimeout(
@@ -563,7 +576,7 @@ router.post(
resolve(addr.port);
});
});
hostname = "127.0.0.1";
hostname = tunnelEndpoint.advertisedHost;
port = tunnelPort;
guacLogger.info("SSH tunnel established for guacamole", {
operation: "guac_ssh_tunnel",
@@ -0,0 +1,27 @@
import { describe, expect, it } from "vitest";
import { resolveJumpTunnelEndpoint } from "../../../hosts/guacamole/jump-tunnel-endpoint.js";
describe("resolveJumpTunnelEndpoint", () => {
it("keeps an in-process guacd tunnel on loopback", () => {
expect(resolveJumpTunnelEndpoint("localhost")).toEqual({
bindHost: "127.0.0.1",
advertisedHost: "127.0.0.1",
});
});
it("exposes the tunnel to a separate guacd container", () => {
expect(resolveJumpTunnelEndpoint("guacd")).toEqual({
bindHost: "0.0.0.0",
advertisedHost: "termix",
});
});
it("supports a custom backend hostname for external guacd", () => {
expect(
resolveJumpTunnelEndpoint("guacd.example", "termix-backend"),
).toEqual({
bindHost: "0.0.0.0",
advertisedHost: "termix-backend",
});
});
});