Skip to content

Commit

Permalink
Merge pull request #276 from sinamics/managed_routes
Browse files Browse the repository at this point in the history
Update manage route when adding custom ip range
  • Loading branch information
sinamics authored Jan 8, 2024
2 parents 672d7d7 + a15d352 commit 218edbf
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 19 deletions.
50 changes: 31 additions & 19 deletions src/server/api/routers/networkRouter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from "zod";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { IPv4gen } from "~/utils/IPv4gen";
import { IPv4gen, getNetworkClassCIDR } from "~/utils/IPv4gen";
import { type Config, adjectives, animals } from "unique-names-generator";
import * as ztController from "~/utils/ztApi";
import {
Expand Down Expand Up @@ -49,7 +49,7 @@ const RouteSchema = z.object({
z
.string()
.optional()
.refine((val) => !val || isValidIP(val), {
.refine((val) => !val || val === "lan" || isValidIP(val), {
message: "Via IP must be a valid IP address!",
}),
z.null(),
Expand Down Expand Up @@ -305,7 +305,7 @@ export const networkRouter = createTRPCRouter({
ipv6: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().optional().default(false),
v6AssignMode: z.object({
"6plane": z.boolean().optional(),
Expand Down Expand Up @@ -374,7 +374,7 @@ export const networkRouter = createTRPCRouter({
enableIpv4AutoAssign: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().optional().default(false),
organizationId: z.string().optional(),
updateParams: z.object({
Expand Down Expand Up @@ -464,6 +464,7 @@ export const networkRouter = createTRPCRouter({
});
}
const { routes } = input.updateParams;

// prepare update params
const updateParams = input.central ? { config: { routes } } : { routes };

Expand Down Expand Up @@ -493,7 +494,7 @@ export const networkRouter = createTRPCRouter({
easyIpAssignment: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().default(false),
organizationId: z.string().optional(),
updateParams: z.object({
Expand Down Expand Up @@ -555,18 +556,16 @@ export const networkRouter = createTRPCRouter({
advancedIpAssignment: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().optional().default(false),
organizationId: z.string().optional(),
updateParams: z.object({
ipAssignmentPools: z
.array(
z.object({
ipRangeStart: z.string(),
ipRangeEnd: z.string(),
}),
)
.optional(),
ipAssignmentPools: z.array(
z.object({
ipRangeStart: z.string(),
ipRangeEnd: z.string(),
}),
),
}),
}),
)
Expand All @@ -590,11 +589,24 @@ export const networkRouter = createTRPCRouter({
requiredRole: Role.USER,
});
}

// validate the ip ranges
for (const ipRange of input.updateParams.ipAssignmentPools) {
if (!isValidIP(ipRange.ipRangeStart) || !isValidIP(ipRange.ipRangeEnd)) {
return throwError("Invalid IP range provided");
}
}

const { ipAssignmentPools } = input.updateParams;

const routes = getNetworkClassCIDR(
ipAssignmentPools as { ipRangeStart: string; ipRangeEnd: string }[],
);

// prepare update params
const updateParams = input.central
? { config: { ipAssignmentPools } }
: { ipAssignmentPools };
? { config: { ipAssignmentPools, routes } }
: { ipAssignmentPools, routes };

try {
// Send webhook
Expand Down Expand Up @@ -910,7 +922,7 @@ export const networkRouter = createTRPCRouter({
multiCast: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().optional().default(false),
organizationId: z.string().optional(),
updateParams: z.object({
Expand Down Expand Up @@ -1113,7 +1125,7 @@ export const networkRouter = createTRPCRouter({
getFlowRule: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
central: z.boolean().default(false),
reset: z.boolean().default(false).optional(),
}),
Expand Down Expand Up @@ -1179,7 +1191,7 @@ accept;`;
inviteUserByMail: protectedProcedure
.input(
z.object({
nwid: z.string().nonempty(),
nwid: z.string(),
email: z.string().email(),
organizationId: z.string().optional(),
}),
Expand Down
47 changes: 47 additions & 0 deletions src/utils/IPv4gen.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// function randomOctet() {
// return Math.floor(Math.random() * 255);

import { throwError } from "~/server/helpers/errorHandler";

// }
const cidrOptions = [
"10.121.15.0/24",
Expand Down Expand Up @@ -51,3 +54,47 @@ function int32toIPv4String(int32: number) {
ipv4 += `.${(int32 & 0x000000ff).toString()}`;
return ipv4;
}

export const getNetworkClassCIDR = (
ipRanges: { ipRangeStart: string; ipRangeEnd: string }[],
): { target: string; via: null }[] => {
const result: { target: string; via: null }[] = [];

const ipToBinary = (ip: string): string =>
ip
.split(".")
.map((octet) => parseInt(octet, 10).toString(2).padStart(8, "0"))
.join("");

const binaryToIp = (binary: string): string =>
binary
.match(/.{1,8}/g)
?.map((bin) => parseInt(bin, 2).toString(10))
.join(".") ?? "";

const countCommonBits = (start: string, end: string): number => {
for (let i = 0; i < start.length; i++) {
if (start[i] !== end[i]) return i;
}
return start.length;
};

const ipToNumber = (ip: string): number =>
ip.split(".").reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0);

for (const range of ipRanges) {
if (ipToNumber(range.ipRangeStart) >= ipToNumber(range.ipRangeEnd)) {
return throwError("Invalid IP range provided");
}

const binaryStart = ipToBinary(range.ipRangeStart);
const binaryEnd = ipToBinary(range.ipRangeEnd);
const commonBits = countCommonBits(binaryStart, binaryEnd);
const networkBinary = binaryStart.substring(0, commonBits).padEnd(32, "0");
const networkIp = binaryToIp(networkBinary);
const cidr = `${networkIp}/${commonBits}`;
result.push({ target: cidr, via: null });
}

return result;
};

0 comments on commit 218edbf

Please sign in to comment.