mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-26 14:56:39 +00:00
Start changes for multi site clients
- Org subnet and assign sites and clients out of the same subnet group on each org - Add join table for client on multiple sites - Start to handle websocket endpoints for these multiple connections
This commit is contained in:
@@ -3,13 +3,12 @@ import { MessageHandler } from "../ws";
|
||||
import logger from "@server/logger";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import db from "@server/db";
|
||||
import { clients, Newt, Site, sites } from "@server/db/schema";
|
||||
import { eq, isNotNull } from "drizzle-orm";
|
||||
import { findNextAvailableCidr } from "@server/lib/ip";
|
||||
import config from "@server/lib/config";
|
||||
import { clients, clientSites, Newt, Site, sites } from "@server/db/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { getNextAvailableClientSubnet } from "@server/lib/ip";
|
||||
|
||||
const inputSchema = z.object({
|
||||
publicKey: z.string(),
|
||||
publicKey: z.string()
|
||||
});
|
||||
|
||||
type Input = z.infer<typeof inputSchema>;
|
||||
@@ -57,16 +56,15 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
|
||||
|
||||
let site: Site | undefined;
|
||||
if (!siteRes.address) {
|
||||
const address = await getNextAvailableSubnet();
|
||||
const listenPort = await getNextAvailablePort();
|
||||
let address = await getNextAvailableClientSubnet(siteRes.orgId);
|
||||
address = address.split("/")[0]; // get the first part of the CIDR
|
||||
|
||||
// create a new exit node
|
||||
const [updateRes] = await db
|
||||
.update(sites)
|
||||
.set({
|
||||
publicKey,
|
||||
address,
|
||||
listenPort
|
||||
address
|
||||
})
|
||||
.where(eq(sites.siteId, siteId))
|
||||
.returning();
|
||||
@@ -95,28 +93,33 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
|
||||
const clientsRes = await db
|
||||
.select()
|
||||
.from(clients)
|
||||
.where(eq(clients.siteId, siteId));
|
||||
.innerJoin(clientSites, eq(clients.clientId, clientSites.clientId))
|
||||
.where(eq(clientSites.siteId, siteId));
|
||||
|
||||
const now = new Date().getTime() / 1000;
|
||||
const peers = await Promise.all(
|
||||
clientsRes
|
||||
.filter((client) => {
|
||||
if (client.lastHolePunch && now - client.lastHolePunch > 6) {
|
||||
// This filter wasn't returning anything - fixed to properly filter clients
|
||||
if (
|
||||
!client.clients.lastHolePunch ||
|
||||
now - client.clients.lastHolePunch > 6
|
||||
) {
|
||||
logger.warn("Client last hole punch is too old");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(async (client) => {
|
||||
return {
|
||||
publicKey: client.pubKey,
|
||||
allowedIps: [client.subnet],
|
||||
endpoint: client.endpoint
|
||||
publicKey: client.clients.pubKey,
|
||||
allowedIps: [client.clients.subnet],
|
||||
endpoint: client.clients.endpoint
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const configResponse = {
|
||||
listenPort: site.listenPort,
|
||||
ipAddress: site.address,
|
||||
peers
|
||||
};
|
||||
@@ -133,57 +136,4 @@ export const handleGetConfigMessage: MessageHandler = async (context) => {
|
||||
broadcast: false, // Send to all clients
|
||||
excludeSender: false // Include sender in broadcast
|
||||
};
|
||||
};
|
||||
|
||||
async function getNextAvailableSubnet(): Promise<string> {
|
||||
const existingAddresses = await db
|
||||
.select({
|
||||
address: sites.address
|
||||
})
|
||||
.from(sites)
|
||||
.where(isNotNull(sites.address));
|
||||
|
||||
const addresses = existingAddresses
|
||||
.map((a) => a.address)
|
||||
.filter((a) => a) as string[];
|
||||
|
||||
let subnet = findNextAvailableCidr(
|
||||
addresses,
|
||||
config.getRawConfig().newt.block_size,
|
||||
config.getRawConfig().newt.subnet_group
|
||||
);
|
||||
if (!subnet) {
|
||||
throw new Error("No available subnets remaining in space");
|
||||
}
|
||||
|
||||
// replace the last octet with 1
|
||||
subnet =
|
||||
subnet.split(".").slice(0, 3).join(".") +
|
||||
".1" +
|
||||
"/" +
|
||||
subnet.split("/")[1];
|
||||
return subnet;
|
||||
}
|
||||
|
||||
async function getNextAvailablePort(): Promise<number> {
|
||||
// Get all existing ports from exitNodes table
|
||||
const existingPorts = await db
|
||||
.select({
|
||||
listenPort: sites.listenPort
|
||||
})
|
||||
.from(sites);
|
||||
|
||||
// Find the first available port between 1024 and 65535
|
||||
let nextPort = config.getRawConfig().newt.start_port;
|
||||
for (const port of existingPorts) {
|
||||
if (port.listenPort && port.listenPort > nextPort) {
|
||||
break;
|
||||
}
|
||||
nextPort++;
|
||||
if (nextPort > 65535) {
|
||||
throw new Error("No available ports remaining in space");
|
||||
}
|
||||
}
|
||||
|
||||
return nextPort;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user