12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697 |
- interface IPRange {
- start: bigint;
- end: bigint;
- }
- /**
- * Converts IP address string to BigInt for numerical operations
- */
- function ipToBigInt(ip: string): bigint {
- return ip.split('.')
- .reduce((acc, octet) => BigInt.asUintN(64, (acc << BigInt(8)) + BigInt(parseInt(octet))), BigInt(0));
- }
- /**
- * Converts BigInt to IP address string
- */
- function bigIntToIp(num: bigint): string {
- const octets: number[] = [];
- for (let i = 0; i < 4; i++) {
- octets.unshift(Number(num & BigInt(255)));
- num = num >> BigInt(8);
- }
- return octets.join('.');
- }
- /**
- * Converts CIDR to IP range
- */
- function cidrToRange(cidr: string): IPRange {
- const [ip, prefix] = cidr.split('/');
- const prefixBits = parseInt(prefix);
- const ipBigInt = ipToBigInt(ip);
- const mask = BigInt.asUintN(64, (BigInt(1) << BigInt(32 - prefixBits)) - BigInt(1));
- const start = ipBigInt & ~mask;
- const end = start | mask;
- return { start, end };
- }
- /**
- * Finds the next available CIDR block given existing allocations
- * @param existingCidrs Array of existing CIDR blocks
- * @param blockSize Desired prefix length for the new block (e.g., 24 for /24)
- * @param startCidr Optional CIDR to start searching from (default: "0.0.0.0/0")
- * @returns Next available CIDR block or null if none found
- */
- export function findNextAvailableCidr(
- existingCidrs: string[],
- blockSize: number,
- startCidr: string = "0.0.0.0/0"
- ): string | null {
- // 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 blockSizeBigInt = BigInt(1) << BigInt(32 - blockSize);
- // Start from the beginning of the given CIDR
- let current = cidrToRange(startCidr).start;
- const maxIp = cidrToRange(startCidr).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)}/${blockSize}`;
- }
- // Move current pointer to after the current range
- current = nextRange.end + BigInt(1);
- }
- return null;
- }
- /**
- * Checks if a given IP address is within a CIDR range
- * @param ip IP address to check
- * @param cidr CIDR range to check against
- * @returns boolean indicating if IP is within the CIDR range
- */
- export function isIpInCidr(ip: string, cidr: string): boolean {
- const ipBigInt = ipToBigInt(ip);
- const range = cidrToRange(cidr);
- return ipBigInt >= range.start && ipBigInt <= range.end;
- }
|