@corvina/cidr
Version:
CIDR Operation helper
255 lines • 7.73 kB
JavaScript
const invalidChars = /^.*?(?=[\^#%&$\*:<>\?\/\{\|\}\\\s[a-zA-Z]).*$/;
export var ErrorMessages;
(function (ErrorMessages) {
ErrorMessages["INVALID_IP_ILLEGAL_CHARACTER"] = "INVALID_IP_ILLEGAL_CHARACTER";
ErrorMessages["INVALID_ADDRESS_NOT_ENOUGH_QUADS"] = "INVALID_ADDRESS_NOT_ENOUGH_QUADS";
ErrorMessages["INVALID_IP_INVALID_QUAD"] = "INVALID_IP_INVALID_QUAD";
ErrorMessages["INVALID_IP_QUAD_TOO_LARGE"] = "INVALID_IP_QUAD_TOO_LARGE";
ErrorMessages["INVALID_IP_QUAD_TOO_SMALL"] = "INVALID_IP_QUAD_TOO_SMALL";
ErrorMessages["INVALID_BITMASK_VALUE"] = "INVALID_BITMASK_VALUE";
ErrorMessages["INVALID_CIDR_BETTER_EXPRESSION"] = "INVALID_CIDR_BETTER_EXPRESSION";
})(ErrorMessages || (ErrorMessages = {}));
const intCommonCidr = (ips) => {
const ipInt = ips.sort();
let mask = 0;
const range = ipInt[ipInt.length - 1] - ipInt[0];
let baseIp = ipInt[0];
for (let i = 0; i <= 32; i++) {
mask = 32 - i;
const exp = Math.pow(2, (32 - mask));
if (exp - 1 >= range) {
if (ipInt[0] % exp != 0) {
baseIp = ipInt[0] - (ipInt[0] % exp);
}
if (ipInt[ipInt.length - 1] > baseIp + exp) {
mask--;
}
break;
}
}
return `${toString(baseIp)}/${mask}`;
};
const padLeft = (input, char, min) => {
while (input.length < min) {
input = char + input;
}
return input;
};
const toInt = (ipAddress) => ipAddress
.split(".")
.reduce((p, c, i) => p + parseInt(c) * Math.pow(256, (3 - i)), 0);
const toString = (ipInt) => {
let remaining = ipInt;
let address = [];
for (let i = 0; i < 4; i++) {
if (remaining != 0) {
address.push(Math.floor(remaining / Math.pow(256, (3 - i))));
remaining = remaining % Math.pow(256, (3 - i));
}
else {
address.push(0);
}
}
return address.join(".");
};
const ipCommonCidr = (ips) => {
const ipInt = ips.map(toInt);
return intCommonCidr(ipInt);
};
const toOctets = (input) => {
if (typeof input === "number") {
input = toString(input);
}
return input.split(".").map((x) => parseInt(x));
};
const reverse = (ip) => {
if (typeof ip === "number") {
ip = toString(ip);
}
const octets = toOctets(ip);
return `${octets[3]}.${octets[2]}.${octets[1]}.${octets[0]}.in-addr.arpa`;
};
const toBinary = (ip) => {
const octets = toOctets(ip);
let o = [];
for (let i = 0; i < 4; i++) {
o[i] = padLeft((octets[i] >>> 0).toString(2), "0", 8);
}
return `${o[0]}.${o[1]}.${o[2]}.${o[3]}`;
};
const toHex = (ip) => {
if (typeof ip === "string") {
ip = toInt(ip);
}
return ip.toString(16);
};
const next = (ip) => toString(toInt(ip) + 1);
const previous = (ip) => toString(toInt(ip) - 1);
const toCidr = (ip) => {
if (typeof ip === "number") {
ip = toString(ip);
}
return `${ip}/32`;
};
const validateIp = (ip) => {
if (invalidChars.test(ip))
return ErrorMessages.INVALID_IP_ILLEGAL_CHARACTER;
const octets = ip.split(".");
if (octets.length !== 4)
return ErrorMessages.INVALID_ADDRESS_NOT_ENOUGH_QUADS;
for (let i = 0; i < octets.length; i++) {
const int = parseInt(octets[i]);
if (isNaN(int))
return ErrorMessages.INVALID_IP_INVALID_QUAD;
if (int > 255)
return ErrorMessages.INVALID_IP_QUAD_TOO_LARGE;
if (int < 0)
return ErrorMessages.INVALID_IP_QUAD_TOO_SMALL;
}
return null;
};
export const ip = {
toInt,
toString,
commonCidr: ipCommonCidr,
toHex,
toOctets,
toBinary,
reverse,
previous,
next,
toCidr,
validate: validateIp,
};
const address = (ip) => ip.split("/")[0];
const maskString = (ip) => ip.split("/")[1];
const mask = (ip) => parseInt(maskString(ip));
const toIntRange = (cidr) => [
toInt(min(cidr)),
toInt(max(cidr)),
];
const toRange = (cidr) => [min(cidr), max(cidr)];
const cidrCommonCidr = (cidrs) => {
const ipMap = cidrs.map((x) => toIntRange(x));
const ipInt = [].concat.apply([], ipMap).sort();
return intCommonCidr(ipInt);
};
const netmask = (cidr) => toString(Math.pow(2, 32) - Math.pow(2, (32 - mask(cidr))));
const broadcast = (cidr) => max(cidr);
const min = (cidr) => {
const addr = address(cidr);
const addrInt = toInt(addr);
const div = addrInt % Math.pow(2, (32 - mask(cidr)));
return div > 0 ? toString(addrInt - div) : addr;
};
const max = (cidr) => {
let initial = toInt(min(cidr));
let add = Math.pow(2, (32 - mask(cidr)));
return toString(initial + add - 1);
};
const count = (cidr) => Math.pow(2, (32 - mask(cidr)));
const usable = (cidr, options) => {
const { startStopOnly = false } = options || {};
let mask = maskString(cidr);
if (!mask) {
return [];
}
if (mask === '32')
return [address(cidr)];
if (mask === '31')
return ips(cidr);
const result = [];
let start = toInt(min(cidr)) + 1;
const stop = toInt(max(cidr));
if (startStopOnly) {
return [toString(start), toString(stop - 1)];
}
while (start < stop) {
result.push(toString(start));
start += 1;
}
return result;
};
const wildcardmask = (cidr) => toString(Math.pow(2, (32 - mask(cidr))) - 1);
const subnets = (cidr, subMask, limit) => {
const mainMask = mask(cidr);
let count = toInt(address(cidr));
let maxIp = toInt(max(cidr));
let subnets = [];
let step = Math.pow(2, (32 - subMask));
if (limit) {
limit = count + limit * step;
if (limit < maxIp) {
maxIp = limit;
}
}
while (count < maxIp) {
subnets.push(`${toString(count)}/${subMask}`);
count += step;
}
return subnets;
};
const ips = (cidr) => {
let ips = [];
const maxIp = toInt(max(cidr));
let current = address(cidr);
while (toInt(current) <= maxIp) {
ips.push(current);
current = next(current);
}
return ips;
};
const includes = (cidr, ip) => {
const ipInt = toInt(ip);
return ipInt >= toInt(min(cidr)) && ipInt <= toInt(max(cidr));
};
const nextCidr = (cidr) => `${toString(toInt(address(cidr)) + Math.pow(2, (32 - mask(cidr))))}/${mask(cidr)}`;
const previousCidr = (cidr) => `${toString(toInt(address(cidr)) - Math.pow(2, (32 - mask(cidr))))}/${mask(cidr)}`;
const nthCidr = (cidr, nth) => `${toString(toInt(address(cidr)) + Math.pow(2, (32 - mask(cidr))) * nth)}/${mask(cidr)}`;
const random = (cidr) => {
const [minIp, maxIp] = toIntRange(cidr);
return toString(Math.floor(Math.random() * (maxIp - minIp + 1)) + minIp);
};
const VALID_BITMASKS = [
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '10', '11',
'12', '13', '14', '15', '16', '17',
'18', '19', '20', '21', '22', '23',
'24', '25', '26', '27', '28', '29',
'30', '31', '32'
];
const validateCidr = (cidr) => {
const ip = address(cidr);
const ipValid = validateIp(ip);
if (ipValid !== null)
return ipValid;
const cidrMask = maskString(cidr);
if (!VALID_BITMASKS.includes(cidrMask))
return ErrorMessages.INVALID_BITMASK_VALUE;
if (ip !== min(cidr))
return ErrorMessages.INVALID_CIDR_BETTER_EXPRESSION;
return null;
};
export const cidr = {
toRange,
usable,
toIntRange,
commonCidr: cidrCommonCidr,
max,
min,
count,
netmask,
wildcardmask,
broadcast,
subnets,
ips,
includes,
random,
next: nextCidr,
previous: previousCidr,
nth: nthCidr,
address,
mask,
validate: validateCidr,
};
//# sourceMappingURL=cidr.js.map