mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-24 23:17:04 +00:00
fix: expose jump tunnels to guacd (#1115)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,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",
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user