Gateway: force loopback self-connections for local binds

This commit is contained in:
Tyler Yust
2026-02-20 13:08:26 -08:00
parent c378439246
commit 47f3979758
3 changed files with 28 additions and 34 deletions

View File

@@ -7,7 +7,6 @@ import {
resolveStateDir,
} from "../config/config.js";
import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js";
import { pickPrimaryTailnetIPv4 } from "../infra/tailnet.js";
import { loadGatewayTlsRuntime } from "../infra/tls/gateway.js";
import {
GATEWAY_CLIENT_MODES,
@@ -21,7 +20,7 @@ import {
resolveLeastPrivilegeOperatorScopesForMethod,
type OperatorScope,
} from "./method-scopes.js";
import { isSecureWebSocketUrl, pickPrimaryLanIPv4 } from "./net.js";
import { isSecureWebSocketUrl } from "./net.js";
import { PROTOCOL_VERSION } from "./protocol/index.js";
type CallGatewayBaseOptions = {
@@ -116,18 +115,10 @@ export function buildGatewayConnectionDetails(
const remote = isRemoteMode ? config.gateway?.remote : undefined;
const tlsEnabled = config.gateway?.tls?.enabled === true;
const localPort = resolveGatewayPort(config);
const tailnetIPv4 = pickPrimaryTailnetIPv4();
const bindMode = config.gateway?.bind ?? "loopback";
const preferTailnet = bindMode === "tailnet" && !!tailnetIPv4;
const preferLan = bindMode === "lan";
const lanIPv4 = preferLan ? pickPrimaryLanIPv4() : undefined;
const scheme = tlsEnabled ? "wss" : "ws";
const localUrl =
preferTailnet && tailnetIPv4
? `${scheme}://${tailnetIPv4}:${localPort}`
: preferLan && lanIPv4
? `${scheme}://${lanIPv4}:${localPort}`
: `${scheme}://127.0.0.1:${localPort}`;
// Self-connections should always target loopback; bind mode only controls listener exposure.
const localUrl = `${scheme}://127.0.0.1:${localPort}`;
const urlOverride =
typeof options.url === "string" && options.url.trim().length > 0
? options.url.trim()
@@ -142,11 +133,7 @@ export function buildGatewayConnectionDetails(
? "config gateway.remote.url"
: remoteMisconfigured
? "missing gateway.remote.url (fallback local)"
: preferTailnet && tailnetIPv4
? `local tailnet ${tailnetIPv4}`
: preferLan && lanIPv4
? `local lan ${lanIPv4}`
: "local loopback";
: "local loopback";
const remoteFallbackNote = remoteMisconfigured
? "Warn: gateway.mode=remote but gateway.remote.url is missing; set gateway.remote.url or switch gateway.mode=local."
: undefined;