From 4b6985718a1f7afeb622a842872f80097c3f2972 Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 27 Mar 2025 22:13:39 -0400 Subject: [PATCH 1/3] Fix ip picking from subnet in exclusion --- server/lib/ip.test.ts | 15 ++++++++++++++- server/lib/ip.ts | 32 +++++++++++++++++++------------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/server/lib/ip.test.ts b/server/lib/ip.test.ts index 2c2dd057..67a2faaa 100644 --- a/server/lib/ip.test.ts +++ b/server/lib/ip.test.ts @@ -4,7 +4,14 @@ import { assertEquals } from "@test/assert"; // Test cases function testFindNextAvailableCidr() { console.log("Running findNextAvailableCidr tests..."); - + + // Test 0: Basic IPv4 allocation with a subnet in the wrong range + { + const existing = ["100.90.130.1/30", "100.90.128.4/30"]; + const result = findNextAvailableCidr(existing, 30, "100.90.130.1/24"); + assertEquals(result, "100.90.130.4/30", "Basic IPv4 allocation failed"); + } + // Test 1: Basic IPv4 allocation { const existing = ["10.0.0.0/16", "10.1.0.0/16"]; @@ -26,6 +33,12 @@ function testFindNextAvailableCidr() { assertEquals(result, null, "No available space test failed"); } + // Test 4: Empty existing + { + const existing: string[] = []; + const result = findNextAvailableCidr(existing, 30, "10.0.0.0/8"); + assertEquals(result, "10.0.0.0/30", "Empty existing test failed"); + } // // Test 4: IPv6 allocation // { // const existing = ["2001:db8::/32", "2001:db8:1::/32"]; diff --git a/server/lib/ip.ts b/server/lib/ip.ts index 86fe1169..a4f05126 100644 --- a/server/lib/ip.ts +++ b/server/lib/ip.ts @@ -132,7 +132,6 @@ export function findNextAvailableCidr( blockSize: number, startCidr?: string ): string | null { - if (!startCidr && existingCidrs.length === 0) { return null; } @@ -150,40 +149,47 @@ export function findNextAvailableCidr( existingCidrs.some(cidr => detectIpVersion(cidr.split('/')[0]) !== version)) { throw new Error('All CIDRs must be of the same IP version'); } - + + // Extract the network part from startCidr to ensure we stay in the right subnet + const startCidrRange = cidrToRange(startCidr); + // Convert existing CIDRs to ranges and sort them const existingRanges = existingCidrs .map(cidr => cidrToRange(cidr)) .sort((a, b) => (a.start < b.start ? -1 : 1)); - + // Calculate block size const maxPrefix = version === 4 ? 32 : 128; const blockSizeBigInt = BigInt(1) << BigInt(maxPrefix - blockSize); - + // Start from the beginning of the given CIDR - let current = cidrToRange(startCidr).start; - const maxIp = cidrToRange(startCidr).end; - + let current = startCidrRange.start; + const maxIp = startCidrRange.end; + // Iterate through existing ranges for (let i = 0; i <= existingRanges.length; i++) { const nextRange = existingRanges[i]; + // Align current to block size const alignedCurrent = current + ((blockSizeBigInt - (current % blockSizeBigInt)) % blockSizeBigInt); - + // Check if we've gone beyond the maximum allowed IP if (alignedCurrent + blockSizeBigInt - BigInt(1) > maxIp) { return null; } - + // If we're at the end of existing ranges or found a gap if (!nextRange || alignedCurrent + blockSizeBigInt - BigInt(1) < nextRange.start) { return `${bigIntToIp(alignedCurrent, version)}/${blockSize}`; } - - // Move current pointer to after the current range - current = nextRange.end + BigInt(1); + + // If next range overlaps with our search space, move past it + if (nextRange.end >= startCidrRange.start && nextRange.start <= maxIp) { + // Move current pointer to after the current range + current = nextRange.end + BigInt(1); + } } - + return null; } From a665e3aae9aa65f4e77492a89397468b5326f7a0 Mon Sep 17 00:00:00 2001 From: Owen Date: Thu, 27 Mar 2025 22:13:57 -0400 Subject: [PATCH 2/3] Fix issues with relaying and holepunching --- server/routers/client/pickClientDefaults.ts | 2 +- server/routers/gerbil/updateHolePunch.ts | 2 +- server/routers/newt/handleGetConfigMessage.ts | 10 +++++----- server/routers/olm/handleOlmRelayMessage.ts | 9 ++------- src/app/[orgId]/settings/sites/create/page.tsx | 2 +- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/server/routers/client/pickClientDefaults.ts b/server/routers/client/pickClientDefaults.ts index d77ae3bb..b51004f3 100644 --- a/server/routers/client/pickClientDefaults.ts +++ b/server/routers/client/pickClientDefaults.ts @@ -97,7 +97,7 @@ export async function pickClientDefaults( let subnets = clientsQuery.map((client) => client.subnet); - // exclude the exit node address by replacing after the / with a site block size + // exclude the newt address by replacing after the / with a site block size subnets.push( address.replace( /\/\d+$/, diff --git a/server/routers/gerbil/updateHolePunch.ts b/server/routers/gerbil/updateHolePunch.ts index 26608345..e2ba01c6 100644 --- a/server/routers/gerbil/updateHolePunch.ts +++ b/server/routers/gerbil/updateHolePunch.ts @@ -133,7 +133,7 @@ export async function updateHolePunch( return res.status(HttpCode.OK).send({ destinationIp: site.subnet.split("/")[0], - destinationPort: parseInt(site.endpoint.split(":")[1]) + destinationPort: site.listenPort }); } catch (error) { logger.error(error); diff --git a/server/routers/newt/handleGetConfigMessage.ts b/server/routers/newt/handleGetConfigMessage.ts index 62934d2f..3c1d7bd6 100644 --- a/server/routers/newt/handleGetConfigMessage.ts +++ b/server/routers/newt/handleGetConfigMessage.ts @@ -10,6 +10,7 @@ import config from "@server/lib/config"; const inputSchema = z.object({ publicKey: z.string(), + port: z.number().int().positive(), }); type Input = z.infer; @@ -41,7 +42,7 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { return; } - const { publicKey } = message.data as Input; + const { publicKey, port } = message.data as Input; const siteId = newt.siteId; @@ -58,7 +59,6 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { let site: Site | undefined; if (!siteRes.address) { const address = await getNextAvailableSubnet(); - const listenPort = await getNextAvailablePort(); // create a new exit node const [updateRes] = await db @@ -66,7 +66,7 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { .set({ publicKey, address, - listenPort + listenPort: port, }) .where(eq(sites.siteId, siteId)) .returning(); @@ -79,7 +79,8 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { const [siteRes] = await db .update(sites) .set({ - publicKey + publicKey, + listenPort: port, }) .where(eq(sites.siteId, siteId)) .returning(); @@ -116,7 +117,6 @@ export const handleGetConfigMessage: MessageHandler = async (context) => { ); const configResponse = { - listenPort: site.listenPort, ipAddress: site.address, peers }; diff --git a/server/routers/olm/handleOlmRelayMessage.ts b/server/routers/olm/handleOlmRelayMessage.ts index 9cf0ceb2..ef42e05a 100644 --- a/server/routers/olm/handleOlmRelayMessage.ts +++ b/server/routers/olm/handleOlmRelayMessage.ts @@ -67,13 +67,8 @@ export const handleOlmRelayMessage: MessageHandler = async (context) => { return { message: { - type: "olm/wg/connect", - data: { - endpoint: site.endpoint, - publicKey: site.publicKey, - serverIP: site.address!.split("/")[0], - tunnelIP: client.subnet - } + type: "olm/wg/relay-success", + data: {} }, broadcast: false, // Send to all olms excludeSender: false // Include sender in broadcast diff --git a/src/app/[orgId]/settings/sites/create/page.tsx b/src/app/[orgId]/settings/sites/create/page.tsx index a8002705..acafd5bb 100644 --- a/src/app/[orgId]/settings/sites/create/page.tsx +++ b/src/app/[orgId]/settings/sites/create/page.tsx @@ -324,7 +324,7 @@ PersistentKeepalive = 5`; let payload: CreateSiteBody = { name: data.name, - type: data.method + type: data.method as any, }; if (data.method == "wireguard") { From 81c7954e0c1b14eba394c66cae3d97f883c65363 Mon Sep 17 00:00:00 2001 From: Owen Date: Mon, 31 Mar 2025 15:19:37 -0400 Subject: [PATCH 3/3] Remove unused argon --- server/routers/site/createSite.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/routers/site/createSite.ts b/server/routers/site/createSite.ts index a1d1876f..f79149cc 100644 --- a/server/routers/site/createSite.ts +++ b/server/routers/site/createSite.ts @@ -10,7 +10,6 @@ import { eq, and } from "drizzle-orm"; import { getUniqueSiteName } from "@server/db/names"; import { addPeer } from "../gerbil/peers"; import { fromError } from "zod-validation-error"; -import { hash } from "@node-rs/argon2"; import { newts } from "@server/db/schema"; import moment from "moment"; import { hashPassword } from "@server/auth/password";