mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 18:31:33 +00:00
fix: expose jump tunnels to guacd (#1115)
This commit is contained in:
@@ -13,6 +13,7 @@ services:
|
|||||||
PORT: "8080"
|
PORT: "8080"
|
||||||
NODE_ENV: development
|
NODE_ENV: development
|
||||||
GUACD_HOST: "guacd-dev"
|
GUACD_HOST: "guacd-dev"
|
||||||
|
GUACD_TUNNEL_HOST: "termix-dev"
|
||||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||||
depends_on:
|
depends_on:
|
||||||
- guacd-dev
|
- guacd-dev
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
PORT: "8080"
|
PORT: "8080"
|
||||||
GUACD_HOST: "guacd"
|
GUACD_HOST: "guacd"
|
||||||
|
GUACD_TUNNEL_HOST: "termix"
|
||||||
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
GUACD_RECORDING_PATH: "/termix-data/session_recordings/guacamole"
|
||||||
depends_on:
|
depends_on:
|
||||||
- guacd
|
- 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 { createJumpHostChain } from "../jump-host-chain.js";
|
||||||
import type { SOCKS5Config } from "../../utils/socks5-helper.js";
|
import type { SOCKS5Config } from "../../utils/socks5-helper.js";
|
||||||
import { waitForGuacdOpen } from "./guacamole-server.js";
|
import { waitForGuacdOpen } from "./guacamole-server.js";
|
||||||
|
import { resolveJumpTunnelEndpoint } from "./jump-tunnel-endpoint.js";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const tokenService = GuacamoleTokenService.getInstance();
|
const tokenService = GuacamoleTokenService.getInstance();
|
||||||
@@ -485,6 +486,18 @@ router.post(
|
|||||||
|
|
||||||
if (jumpHosts.length > 0) {
|
if (jumpHosts.length > 0) {
|
||||||
try {
|
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[] = [];
|
let socks5ProxyChain: ProxyNode[] = [];
|
||||||
if (hostRecord.socks5ProxyChain) {
|
if (hostRecord.socks5ProxyChain) {
|
||||||
try {
|
try {
|
||||||
@@ -550,7 +563,7 @@ router.post(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
server.on("error", reject);
|
server.on("error", reject);
|
||||||
server.listen(0, "127.0.0.1", () => {
|
server.listen(0, tunnelEndpoint.bindHost, () => {
|
||||||
const addr = server.address() as net.AddressInfo;
|
const addr = server.address() as net.AddressInfo;
|
||||||
// Auto-cleanup after 1 hour
|
// Auto-cleanup after 1 hour
|
||||||
setTimeout(
|
setTimeout(
|
||||||
@@ -563,7 +576,7 @@ router.post(
|
|||||||
resolve(addr.port);
|
resolve(addr.port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
hostname = "127.0.0.1";
|
hostname = tunnelEndpoint.advertisedHost;
|
||||||
port = tunnelPort;
|
port = tunnelPort;
|
||||||
guacLogger.info("SSH tunnel established for guacamole", {
|
guacLogger.info("SSH tunnel established for guacamole", {
|
||||||
operation: "guac_ssh_tunnel",
|
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