mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-05 12:10:52 +02:00
Handle the alias create and update special case exit nodes
This commit is contained in:
@@ -1137,7 +1137,9 @@ async function syncClientExitNodeConnections(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const needsConnectSet = new Set(requiresExitNodeRows.map((r) => r.clientId));
|
const needsConnectSet = new Set(
|
||||||
|
requiresExitNodeRows.map((r) => r.clientId)
|
||||||
|
);
|
||||||
|
|
||||||
const exitNodeIds = Array.from(
|
const exitNodeIds = Array.from(
|
||||||
new Set(
|
new Set(
|
||||||
@@ -1249,6 +1251,61 @@ async function syncClientExitNodeConnections(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notifies the olms of every given client that the alias of the site resource
|
||||||
|
// they're using an exit node connection for has changed, via the dedicated
|
||||||
|
// exit node data-update message. Unlike syncClientExitNodeConnections, this
|
||||||
|
// doesn't touch connect/disconnect state - it's purely a rename for clients
|
||||||
|
// that are (and remain) connected to the exit node for this resource.
|
||||||
|
async function syncClientExitNodeAliasUpdate(
|
||||||
|
clientIds: number[],
|
||||||
|
oldAlias: string | null,
|
||||||
|
newAlias: string | null,
|
||||||
|
trx: Transaction | typeof db = db
|
||||||
|
): Promise<void> {
|
||||||
|
const uniqueClientIds = Array.from(new Set(clientIds));
|
||||||
|
if (uniqueClientIds.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldAliases = oldAlias ? [oldAlias] : [];
|
||||||
|
const newAliases = newAlias ? [newAlias] : [];
|
||||||
|
if (oldAliases.length === 0 && newAliases.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const olmRows = await trx
|
||||||
|
.select({
|
||||||
|
clientId: olms.clientId,
|
||||||
|
olmId: olms.olmId,
|
||||||
|
version: olms.version
|
||||||
|
})
|
||||||
|
.from(olms)
|
||||||
|
.where(inArray(olms.clientId, uniqueClientIds));
|
||||||
|
|
||||||
|
const updatePayloads = olmRows
|
||||||
|
.filter((r) => r.clientId !== null)
|
||||||
|
.map((olm) => ({
|
||||||
|
clientId: olm.olmId,
|
||||||
|
message: {
|
||||||
|
type: "olm/wg/exitnode/data/update",
|
||||||
|
data: {
|
||||||
|
oldAliases,
|
||||||
|
newAliases
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: { compress: canCompress(olm.version, "olm") }
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (updatePayloads.length > 0) {
|
||||||
|
await sendToClientsBatch(updatePayloads).catch((error) => {
|
||||||
|
logger.error(
|
||||||
|
`rebuildClientAssociations: Error sending exit node alias update messages:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubnetProxyTargetUpdates(
|
async function handleSubnetProxyTargetUpdates(
|
||||||
siteResource: SiteResource,
|
siteResource: SiteResource,
|
||||||
sitesList: Site[],
|
sitesList: Site[],
|
||||||
@@ -1479,7 +1536,7 @@ export async function handleMessagingForUpdatedSiteResource(
|
|||||||
`handleMessagingForUpdatedSiteResource: fetched newts for ${newtsForSites.length}/${allSiteIds.length} site(s)`
|
`handleMessagingForUpdatedSiteResource: fetched newts for ${newtsForSites.length}/${allSiteIds.length} site(s)`
|
||||||
);
|
);
|
||||||
|
|
||||||
// WARNING: THIS RELIES ON THE CACHE TABLES BEING UP TO DATE, SO CALL THIS AFTER THE ASSOCIATION CACHE IS UPDATED
|
// !!!!!!!!!!!!!!!!!! WARNING: THIS RELIES ON THE CACHE TABLES BEING UP TO DATE, SO CALL THIS AFTER THE ASSOCIATION CACHE IS UPDATED !!!!!!!!!!!!!!!!!!
|
||||||
const mergedAllClients = await trx
|
const mergedAllClients = await trx
|
||||||
.select({
|
.select({
|
||||||
clientId: clientSiteResourcesAssociationsCache.clientId,
|
clientId: clientSiteResourcesAssociationsCache.clientId,
|
||||||
@@ -1906,6 +1963,24 @@ export async function handleMessagingForUpdatedSiteResource(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For a resource that stays on an exit node connection across the update,
|
||||||
|
// the alias is the only field that affects already-connected clients (the
|
||||||
|
// exit node itself, its endpoint, etc. are not per-resource). Tell those
|
||||||
|
// clients' olms about the rename directly via the exit node data-update
|
||||||
|
// message rather than a full connect/disconnect cycle.
|
||||||
|
if (
|
||||||
|
existingSiteResource?.requiresExitNodeConnection &&
|
||||||
|
updatedSiteResource.requiresExitNodeConnection &&
|
||||||
|
aliasChanged
|
||||||
|
) {
|
||||||
|
await syncClientExitNodeAliasUpdate(
|
||||||
|
mergedAllClients.map((c) => c.clientId),
|
||||||
|
existingSiteResource.alias,
|
||||||
|
updatedSiteResource.alias,
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If this resource requires (or required) clients to be connected to the
|
// If this resource requires (or required) clients to be connected to the
|
||||||
// exit node (e.g. an inference resource), re-sync connect/disconnect
|
// exit node (e.g. an inference resource), re-sync connect/disconnect
|
||||||
// state for every client currently associated with it - covers toggling
|
// state for every client currently associated with it - covers toggling
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import response from "@server/lib/response";
|
|||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
import HttpCode from "@server/types/HttpCode";
|
import HttpCode from "@server/types/HttpCode";
|
||||||
import { and, eq, inArray } from "drizzle-orm";
|
import { and, eq, inArray, ne } from "drizzle-orm";
|
||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@@ -490,7 +490,11 @@ export async function createSiteResource(
|
|||||||
.where(
|
.where(
|
||||||
and(
|
and(
|
||||||
eq(siteResources.orgId, orgId),
|
eq(siteResources.orgId, orgId),
|
||||||
eq(siteResources.alias, alias.trim())
|
eq(siteResources.alias, alias.trim()),
|
||||||
|
ne(
|
||||||
|
siteResources.requiresExitNodeConnection,
|
||||||
|
mode == "inference"
|
||||||
|
) // exclude looking at the ones on exit nodes if this is an inference resource
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
@@ -527,6 +531,7 @@ export async function createSiteResource(
|
|||||||
let aliasAddress: string | null = null;
|
let aliasAddress: string | null = null;
|
||||||
let releaseAliasLock: (() => Promise<void>) | null = null;
|
let releaseAliasLock: (() => Promise<void>) | null = null;
|
||||||
if (mode === "host" || mode === "http" || mode === "ssh") {
|
if (mode === "host" || mode === "http" || mode === "ssh") {
|
||||||
|
// no alias address but we do have an alias for inference
|
||||||
const { value, release } =
|
const { value, release } =
|
||||||
await getNextAvailableAliasAddress(orgId);
|
await getNextAvailableAliasAddress(orgId);
|
||||||
aliasAddress = value;
|
aliasAddress = value;
|
||||||
|
|||||||
@@ -507,7 +507,11 @@ export async function updateSiteResource(
|
|||||||
and(
|
and(
|
||||||
eq(siteResources.orgId, existingSiteResource.orgId),
|
eq(siteResources.orgId, existingSiteResource.orgId),
|
||||||
eq(siteResources.alias, alias.trim()),
|
eq(siteResources.alias, alias.trim()),
|
||||||
ne(siteResources.siteResourceId, siteResourceId) // exclude self
|
ne(siteResources.siteResourceId, siteResourceId), // exclude self
|
||||||
|
ne(
|
||||||
|
siteResources.requiresExitNodeConnection,
|
||||||
|
mode == "inference"
|
||||||
|
) // exclude looking at the ones on exit nodes if this is an inference resource
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
@@ -587,8 +591,7 @@ export async function updateSiteResource(
|
|||||||
domainId,
|
domainId,
|
||||||
subdomain: finalSubdomain,
|
subdomain: finalSubdomain,
|
||||||
fullDomain,
|
fullDomain,
|
||||||
networkId:
|
networkId: mode === "inference" ? null : undefined,
|
||||||
mode === "inference" ? null : undefined,
|
|
||||||
requiresExitNodeConnection:
|
requiresExitNodeConnection:
|
||||||
mode !== undefined ? mode === "inference" : undefined,
|
mode !== undefined ? mode === "inference" : undefined,
|
||||||
...sshPamSet
|
...sshPamSet
|
||||||
|
|||||||
Reference in New Issue
Block a user