UNPKG

@eryldor/cidr

Version:

A javascript library to manipulate CIDR blocks

147 lines 5.98 kB
"use strict"; /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ Object.defineProperty(exports, "__esModule", { value: true }); class CIDRBlock { constructor(networkAddr, prefix) { this.innerNetworkAddr = networkAddr; this.networkPrefix = prefix; } /** * Construct a [[CIDRBlock]] object from four IP component numbers (eg: a.b.c.d) and a prefix. The network * address is sanitized by zeroing all the bits after the prefix. * @throws If any IP component number is invalid or if the prefix is invalid. */ static fromNumbers(a, b, c, d, prefix) { const { addr, prefix: netPrefix } = CIDRBlock.fromNumbersInner(a, b, c, d, prefix); return new CIDRBlock(addr, netPrefix); } /** * Parse a string into a CIDR block. * @throws If the stirng is not a valid CIDR block */ static fromString(cidr) { const { addr, prefix } = CIDRBlock.fromStringInner(cidr); return new CIDRBlock(addr, prefix); } static fromNumbersInner(a, b, c, d, prefix) { if (![a, b, c, d].every((n) => CIDRBlock.checkIPBoundaries(n))) { throw new Error(`Invalid network address for ${a}.${b}.${c}.${d}/${prefix}`); } if (!CIDRBlock.checkPrefix(prefix)) { throw new Error(`Invalid prefix address for ${a}.${b}.${c}.${d}/${prefix}`); } let addr = ((a << 24) | (b << 16) | (c << 8) | d) >>> 0; // Sanitize the network address const sanitizer = (0xFFFFFFFF << (32 - prefix) >>> 0); addr = (addr & sanitizer) >>> 0; return { addr, prefix, }; } static fromStringInner(cidr) { const splittedCidr = cidr.split("/"); if (splittedCidr.length !== 2) { throw new Error(`"${cidr} is not a valid CIDR`); } const prefix = Number.parseInt(splittedCidr[1], 10); if (prefix === null || !CIDRBlock.checkPrefix(prefix)) { throw new Error(`"${prefix}" is not a valid prefix in CIDR "${cidr}"`); } const splittedNetworkAddr = splittedCidr[0].split(".") .map((i) => Number.parseInt(i, 10)) .filter((n) => !Number.isNaN(n)); if (splittedNetworkAddr.length !== 4) { throw new Error(`"${splittedCidr[0]}" is not a valid network address in CIDR "${cidr}"`); } return CIDRBlock.fromNumbersInner(splittedNetworkAddr[0], splittedNetworkAddr[1], splittedNetworkAddr[2], splittedNetworkAddr[3], prefix); } static checkIPBoundaries(n) { return Number.isInteger(n) && n >= 0 && n <= 255; } static checkPrefix(prefix) { return Number.isInteger(prefix) && prefix >= 0 && prefix <= 32; } static networkAddressToString(netAddr) { const a = netAddr >> 24; const b = netAddr >> 16 & 0xFF; const c = netAddr >> 8 & 0xFF; const d = netAddr & 0xFF; const networkAddr = new Uint8Array([a, b, c, d]); return `${networkAddr[0]}.${networkAddr[1]}.${networkAddr[2]}.${networkAddr[3]}`; } get networkAddress() { return CIDRBlock.networkAddressToString(this.innerNetworkAddr); } /** * Return the broadcast address of this CIDR block. */ get broadcastAddress() { const broadcastAddress = this.innerNetworkAddr | (0xFFFFFFFF >>> this.networkPrefix); return CIDRBlock.networkAddressToString(broadcastAddress); } /** * Return a generator yielding all the IP address this block can contain. It doesn't yield the network address and * the broadcast address. */ *ipAddress() { for (let i = 1; i < this.maxAddressIndex; i++) { yield this.getAddress(i); } } /** * Return the CIDR notation of this block */ toString() { return `${this.networkAddress}/${this.networkPrefix}`; } /** * Split the CIDR block into at least `requiredSubnetAmount`. * @returns The new CIDR blocks generated from the split * @throws If the block can't be divided by at least `requiredSubnetAmount` or if `requiredSubnetAmount` is negative */ split(requiredSubnetAmount) { if (requiredSubnetAmount <= 0) { throw new Error("The required subnet amount must be positive"); } const prefixDiff = Math.ceil(Math.log2(requiredSubnetAmount)); const newPrefix = this.networkPrefix + prefixDiff; if (!CIDRBlock.checkPrefix(newPrefix)) { throw new Error(`Can't divide "${this.toString()}" into ${requiredSubnetAmount}`); } const resultLength = Math.pow(2, prefixDiff); const result = []; for (let i = 0; i < resultLength; i++) { const networkAddr = this.innerNetworkAddr + (i << (32 - newPrefix)); result.push(new CIDRBlock(networkAddr, newPrefix)); } return result; } /** * Return the maximum address index usable with {@link CIDRBlock.getAddress} */ get maxAddressIndex() { return 0xFFFFFFFF >>> this.networkPrefix; } /** * Return the i-th address inside this CIDR Block. * * Note that `getAddress(0)` is equivalent [[CIDRBlock.networkAddress]], * `this.getAddress(this.maxAddressIndex)` is equivaent to [[CIDRBlock.broadcastAddress]] * * @throws if `i` is not an integer between 0 and [[CIDRBlock.maxAddressIndex]] */ getAddress(i) { if (!Number.isInteger(i) || i < 0 || i > this.maxAddressIndex) { throw new Error(`${i} is not a valid address index for "${this.toString()}"`); } const addr = this.innerNetworkAddr + i; return CIDRBlock.networkAddressToString(addr); } } exports.CIDRBlock = CIDRBlock; //# sourceMappingURL=cidrBlock.js.map