diff --git a/server/routers/client/createClient.ts b/server/routers/client/createClient.ts index 627f4b1f..dc005700 100644 --- a/server/routers/client/createClient.ts +++ b/server/routers/client/createClient.ts @@ -10,7 +10,8 @@ import { olms, clientSites, exitNodes, - orgs + orgs, + sites } from "@server/db/schema"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; @@ -115,13 +116,28 @@ export async function createClient( const updatedSubnet = `${subnet}/${org.subnet.split("/")[1]}`; // we want the block size of the whole org // make sure the subnet is unique - const subnetExists = await db + const subnetExistsClients = await db .select() .from(clients) .where(eq(clients.subnet, updatedSubnet)) .limit(1); - if (subnetExists.length > 0) { + if (subnetExistsClients.length > 0) { + return next( + createHttpError( + HttpCode.CONFLICT, + `Subnet ${subnet} already exists` + ) + ); + } + + const subnetExistsSites = await db + .select() + .from(sites) + .where(eq(sites.address, updatedSubnet)) + .limit(1); + + if (subnetExistsSites.length > 0) { return next( createHttpError( HttpCode.CONFLICT, diff --git a/server/routers/newt/handleGetConfigMessage.ts b/server/routers/newt/handleGetConfigMessage.ts index 7c15d875..07a598f7 100644 --- a/server/routers/newt/handleGetConfigMessage.ts +++ b/server/routers/newt/handleGetConfigMessage.ts @@ -3,18 +3,9 @@ import { MessageHandler } from "../ws"; import logger from "@server/logger"; import { fromError } from "zod-validation-error"; import db from "@server/db"; -import { - clients, - clientSites, - Newt, - Site, - sites, - olms -} from "@server/db/schema"; +import { clients, clientSites, Newt, sites } from "@server/db/schema"; import { eq } from "drizzle-orm"; -import { getNextAvailableClientSubnet } from "@server/lib/ip"; -import config from "@server/lib/config"; -import { addPeer } from "../olm/peers"; +import { updatePeer } from "../olm/peers"; const inputSchema = z.object({ publicKey: z.string(), @@ -27,7 +18,7 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { const { message, client, sendToClient } = context; const newt = client as Newt; - logger.debug(JSON.stringify(message.data)); + const now = new Date().getTime() / 1000; logger.debug("Handling Newt get config message!"); @@ -63,6 +54,19 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { logger.warn("handleGetConfigMessage: Site not found"); return; } +// todo check if the public key has changed + // we need to wait for hole punch success + if (!existingSite.endpoint) { + logger.warn(`Site ${existingSite.siteId} has no endpoint, skipping`); + return; + } + + if (existingSite.lastHolePunch && now - existingSite.lastHolePunch > 6) { + logger.warn( + `Site ${existingSite.siteId} last hole punch is too old, skipping` + ); + return; + } // update the endpoint and the public key const [site] = await db @@ -106,29 +110,30 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { return true; }) .map(async (client) => { - const peerData = { - publicKey: client.clients.pubKey!, - allowedIps: [client.clients.subnet!], - endpoint: client.clientSites.isRelayed - ? "" - : client.clients.endpoint! // if its relayed it should be localhost - }; - // Add or update this peer on the olm if it is connected try { - await addPeer(client.clients.clientId, { - ...peerData, - siteId: siteId, - serverIP: site.address, - serverPort: site.listenPort - }); + if (site.endpoint && site.publicKey) { + await updatePeer(client.clients.clientId, { + siteId: site.siteId, + endpoint: site.endpoint, + publicKey: site.publicKey, + serverIP: site.address, + serverPort: site.listenPort + }); + } } catch (error) { logger.error( `Failed to add/update peer ${client.clients.pubKey} to newt ${newt.newtId}: ${error}` ); } - return peerData; + return { + publicKey: client.clients.pubKey!, + allowedIps: [client.clients.subnet!], + endpoint: client.clientSites.isRelayed + ? "" + : client.clients.endpoint! // if its relayed it should be localhost + }; }) ); diff --git a/server/routers/olm/handleOlmRelayMessage.ts b/server/routers/olm/handleOlmRelayMessage.ts index 5a00f73f..a6bee3b8 100644 --- a/server/routers/olm/handleOlmRelayMessage.ts +++ b/server/routers/olm/handleOlmRelayMessage.ts @@ -1,6 +1,6 @@ import db from "@server/db"; import { MessageHandler } from "../ws"; -import { clients, clientSites, Olm, olms, sites } from "@server/db/schema"; +import { clients, clientSites, Olm } from "@server/db/schema"; import { eq } from "drizzle-orm"; import { updatePeer } from "../newt/peers"; import logger from "@server/logger"; @@ -42,6 +42,13 @@ export const handleOlmRelayMessage: MessageHandler = async (context) => { const { siteId } = message.data; + await db + .update(clientSites) + .set({ + isRelayed: true + }) + .where(eq(clientSites.clientId, olm.clientId)); + // update the peer on the exit node await updatePeer(siteId, client.pubKey, { endpoint: "" // this removes the endpoint diff --git a/server/routers/olm/peers.ts b/server/routers/olm/peers.ts index 90c91c07..969c71cf 100644 --- a/server/routers/olm/peers.ts +++ b/server/routers/olm/peers.ts @@ -7,7 +7,6 @@ import logger from '@server/logger'; export async function addPeer(clientId: number, peer: { siteId: number, publicKey: string; - allowedIps: string[]; endpoint: string; serverIP: string | null; serverPort: number | null; @@ -20,8 +19,8 @@ export async function addPeer(clientId: number, peer: { sendToClient(olm.olmId, { type: 'olm/wg/peer/add', data: { + siteId: peer.siteId, publicKey: peer.publicKey, - allowedIps: peer.allowedIps, endpoint: peer.endpoint, serverIP: peer.serverIP, serverPort: peer.serverPort @@ -47,11 +46,12 @@ export async function deletePeer(clientId: number, publicKey: string) { logger.info(`Deleted peer ${publicKey} from olm ${olm.olmId}`); } -export async function updatePeer(clientId: number, publicKey: string, peer: { - allowedIps?: string[]; - endpoint?: string; - serverIP?: string; - serverPort?: number; +export async function updatePeer(clientId: number, peer: { + siteId: number, + publicKey: string; + endpoint: string; + serverIP: string | null; + serverPort: number | null; }) { const [olm] = await db.select().from(olms).where(eq(olms.clientId, clientId)).limit(1); if (!olm) { @@ -59,12 +59,15 @@ export async function updatePeer(clientId: number, publicKey: string, peer: { } sendToClient(olm.olmId, { - type: 'olm/wg/peer/update', + type: 'olm/wg/peer/update', data: { - publicKey, - ...peer + siteId: peer.siteId, + publicKey: peer.publicKey, + endpoint: peer.endpoint, + serverIP: peer.serverIP, + serverPort: peer.serverPort } }); - logger.info(`Updated peer ${publicKey} on olm ${olm.olmId}`); + logger.info(`Added peer ${peer.publicKey} to olm ${olm.olmId}`); } \ No newline at end of file diff --git a/server/routers/site/createSite.ts b/server/routers/site/createSite.ts index a2a6c6b1..8f3c9315 100644 --- a/server/routers/site/createSite.ts +++ b/server/routers/site/createSite.ts @@ -128,14 +128,16 @@ export async function createSite( ); } + updatedAddress = `${address}/${org.subnet.split("/")[1]}`; // we want the block size of the whole org + // make sure the subnet is unique - const addressExists = await db + const addressExistsSites = await db .select() .from(sites) - .where(eq(sites.address, address)) + .where(eq(sites.address, updatedAddress)) .limit(1); - if (addressExists.length > 0) { + if (addressExistsSites.length > 0) { return next( createHttpError( HttpCode.CONFLICT, @@ -144,7 +146,19 @@ export async function createSite( ); } - updatedAddress = `${address}/${org.subnet.split("/")[1]}`; // we want the block size of the whole org + const addressExistsClients = await db + .select() + .from(sites) + .where(eq(sites.subnet, updatedAddress)) + .limit(1); + if (addressExistsClients.length > 0) { + return next( + createHttpError( + HttpCode.CONFLICT, + `Subnet ${subnet} already exists` + ) + ); + } } const niceId = await getUniqueSiteName(orgId); diff --git a/src/app/[orgId]/settings/sites/create/page.tsx b/src/app/[orgId]/settings/sites/create/page.tsx index f4df8bb6..b6b5ca57 100644 --- a/src/app/[orgId]/settings/sites/create/page.tsx +++ b/src/app/[orgId]/settings/sites/create/page.tsx @@ -544,6 +544,42 @@ PersistentKeepalive = 5`; )} /> + ( + + + Client Address + + + { + setClientAddress( + e.target + .value + ); + field.onChange( + e.target + .value + ); + }} + /> + + + + Specify the IP + address of the host. + + + )} + /> @@ -662,50 +698,11 @@ PersistentKeepalive = 5`; )} /> - ( - - - Client Address - - - { - setClientAddress( - e - .target - .value - ); - field.onChange( - e - .target - .value - ); - }} - /> - - - - Specify the IP - address of the - host. - - - )} - /> - + Install Newt