diff --git a/server/lib/ip.ts b/server/lib/ip.ts index 055820dc..d530e2f0 100644 --- a/server/lib/ip.ts +++ b/server/lib/ip.ts @@ -3,7 +3,6 @@ import { clients, orgs, sites } from "@server/db"; import { and, eq, isNotNull } from "drizzle-orm"; import config from "@server/lib/config"; import z from "zod"; -import { getClientSiteResourceAccess } from "./rebuildClientAssociations"; import logger from "@server/logger"; interface IPRange { diff --git a/server/lib/rebuildClientAssociations.ts b/server/lib/rebuildClientAssociations.ts index 8a9e2de3..f26ce060 100644 --- a/server/lib/rebuildClientAssociations.ts +++ b/server/lib/rebuildClientAssociations.ts @@ -36,6 +36,7 @@ import { SubnetProxyTarget } from "@server/lib/ip"; import { + addRemoteSubnets, addTargets as addSubnetProxyTargets, removeTargets as removeSubnetProxyTargets } from "@server/routers/client/targets"; @@ -644,6 +645,8 @@ async function handleSubnetProxyTargetUpdates( return; } + let proxyJobs = []; + let olmJobs = []; // Generate targets for added associations if (clientSiteResourcesToAdd.length > 0) { const addedClients = allClients.filter((client) => @@ -660,11 +663,21 @@ async function handleSubnetProxyTargetUpdates( logger.info( `Adding ${targetsToAdd.length} subnet proxy targets for siteResource ${siteResource.siteResourceId}` ); - await addSubnetProxyTargets(newt.newtId, targetsToAdd); + proxyJobs.push( + addSubnetProxyTargets(newt.newtId, targetsToAdd) + ); + } + + for (const client of addedClients) { + olmJobs.push( + addRemoteSubnets(client.clientId, siteResource.siteId, generateRemoteSubnets([siteResource])) + ); } } } + // here we use the existingSiteResource from BEFORE we updated the destination so we dont need to worry about updating destinations here + // Generate targets for removed associations if (clientSiteResourcesToRemove.length > 0) { const removedClients = existingClients.filter((client) => @@ -681,8 +694,18 @@ async function handleSubnetProxyTargetUpdates( logger.info( `Removing ${targetsToRemove.length} subnet proxy targets for siteResource ${siteResource.siteResourceId}` ); - await removeSubnetProxyTargets(newt.newtId, targetsToRemove); + proxyJobs.push( + removeSubnetProxyTargets(newt.newtId, targetsToRemove) + ); + } + + for (const client of removedClients) { + olmJobs.push( + addRemoteSubnets(client.clientId, siteResource.siteId, generateRemoteSubnets([siteResource])) + ); } } } -} + + await Promise.all(proxyJobs); +} \ No newline at end of file diff --git a/server/routers/client/targets.ts b/server/routers/client/targets.ts index c3e2613c..29380010 100644 --- a/server/routers/client/targets.ts +++ b/server/routers/client/targets.ts @@ -1,5 +1,7 @@ import { sendToClient } from "#dynamic/routers/ws"; +import { db, olms } from "@server/db"; import { SubnetProxyTarget } from "@server/lib/ip"; +import { eq } from "drizzle-orm"; export async function addTargets(newtId: string, targets: SubnetProxyTarget[]) { await sendToClient(newtId, { @@ -21,8 +23,8 @@ export async function removeTargets( export async function updateTargets( newtId: string, targets: { - oldTargets: SubnetProxyTarget[], - newTargets: SubnetProxyTarget[] + oldTargets: SubnetProxyTarget[]; + newTargets: SubnetProxyTarget[]; } ) { await sendToClient(newtId, { @@ -30,3 +32,57 @@ export async function updateTargets( data: targets }); } + +export async function addRemoteSubnets( + clientId: number, + siteId: number, + remoteSubnets: string[], + olmId?: string +) { + if (!olmId) { + const [olm] = await db + .select() + .from(olms) + .where(eq(olms.clientId, clientId)) + .limit(1); + if (!olm) { + throw new Error(`Olm with ID ${clientId} not found`); + } + olmId = olm.olmId; + } + + await sendToClient(olmId, { + type: `olm/wg/peer/add-remote-subnets`, + data: { + siteId: siteId, + remoteSubnets: remoteSubnets + } + }); +} + +export async function removeRemoteSubnets( + clientId: number, + siteId: number, + remoteSubnets: string[], + olmId?: string +) { + if (!olmId) { + const [olm] = await db + .select() + .from(olms) + .where(eq(olms.clientId, clientId)) + .limit(1); + if (!olm) { + throw new Error(`Olm with ID ${clientId} not found`); + } + olmId = olm.olmId; + } + + await sendToClient(olmId, { + type: `olm/wg/peer/remove-remote-subnets`, + data: { + siteId: siteId, + remoteSubnets: remoteSubnets + } + }); +} diff --git a/server/routers/siteResource/updateSiteResource.ts b/server/routers/siteResource/updateSiteResource.ts index 00fc0f44..70f0d712 100644 --- a/server/routers/siteResource/updateSiteResource.ts +++ b/server/routers/siteResource/updateSiteResource.ts @@ -17,8 +17,12 @@ import { eq, and, ne } from "drizzle-orm"; import { fromError } from "zod-validation-error"; import logger from "@server/logger"; import { OpenAPITags, registry } from "@server/openApi"; -import { updateTargets } from "@server/routers/client/targets"; -import { generateSubnetProxyTargets } from "@server/lib/ip"; +import { + addRemoteSubnets, + removeRemoteSubnets, + updateTargets +} from "@server/routers/client/targets"; +import { generateRemoteSubnets, generateSubnetProxyTargets } from "@server/lib/ip"; import { getClientSiteResourceAccess, rebuildClientAssociations @@ -221,11 +225,11 @@ export async function updateSiteResource( } const { mergedAllClients } = await rebuildClientAssociations( - updatedSiteResource, + existingSiteResource, // we want to rebuild based on the existing resource then we will apply the change to the destination below trx - ); // we need to call this because we added to the admin role + ); - // after everything is rebuilt above we still need to update the targets if the destination changed + // after everything is rebuilt above we still need to update the targets and remote subnets if the destination changed if ( existingSiteResource.destination !== updatedSiteResource.destination @@ -255,6 +259,26 @@ export async function updateSiteResource( oldTargets: oldTargets, newTargets: newTargets }); + + let olmJobs: Promise[] = []; + for (const client of mergedAllClients) { // we also need to update the remote subnets on the olms for each client that has access to this site + olmJobs.push( + removeRemoteSubnets( + client.clientId, + updatedSiteResource.siteId, + generateRemoteSubnets([existingSiteResource]) + ) + ); + olmJobs.push( + addRemoteSubnets( + client.clientId, + updatedSiteResource.siteId, + generateRemoteSubnets([updatedSiteResource]) + ) + ); + } + + await Promise.all(olmJobs); } logger.info(