it-tools/src/libs/ip_calculator/network.ts
sharevb 1f67ba15e9 feat(new tool): IPv6 Subnet Calculator
IPv6 Subnet Calculator
Fix #354 and #924
2024-04-07 17:56:37 +02:00

230 lines
6.3 KiB
TypeScript

import IP from './ip';
import ipv4registry from './ipv4registry.json';
import ipv6registry from './ipv6registry.json';
const IPv4MAX = (BigInt(2) ** BigInt(32)) - BigInt(1);
const IPv6MAX = (BigInt(2) ** BigInt(128)) - BigInt(1);
// IP range specific information, see IANA allocations.
// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
const _ipv4Registry = new Map(ipv4registry.map(v => [v[0] as string, v[1]]));
// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
const _ipv6Registry = new Map(ipv6registry.map(v => [v[0] as string, v[1]]));
/**
* Network slice calculations.
* @class Network
* @param {string} address
* @param {integer} prefix
* host = new IP("127.128.99.3",8)
* @return {object} -> IP{address:"127.128.99.3", prefix: 8}
*/
export default class Network extends IP {
prefix: bigint;
/**
* Extends IP class. Calls the parent class IP with the parameters passed to Network.
* @constructor
*/
constructor(address: string, prefix: number) {
super(address);
this.prefix = this._checkPrefix(prefix);
}
// Private methods
/**
* _checkPrefix - Returns this IP prefix and validates it
* @private
* @return {integer} -> prefix: 25n
*/
_checkPrefix(prefix: number) {
if (this.version === 4) {
if (prefix > 0 && prefix <= 32) {
return BigInt(prefix);
}
}
else {
if (prefix > 0 && prefix <= 128) {
return BigInt(prefix);
}
}
throw new Error('Tips: Invalid prefix');
}
// Public methods
/**
* printInfo - Shows IANA allocation information for the current IP address.
* @return {string} ->LOOPBACK
*/
printInfo() {
const results = [];
for (const [addr, info] of (this.version === 4 ? _ipv4Registry : _ipv6Registry).entries()) {
const found = this.contains(this.address, addr, Number(info[0]));
if (found) {
results.unshift(info[1]);
}
}
return results.length === 0 ? 'Unknown' : results[0];
}
/**
* maskToInteger - Returns network mask as bigInt
* @return {BigInt} -> 4278190080n
*/
maskToInteger() {
if (this.version === 4) {
return (IPv4MAX >> (BigInt(32) - this.prefix)) << (BigInt(32) - this.prefix);
}
else {
return (IPv6MAX >> (BigInt(128) - this.prefix)) << (BigInt(128) - this.prefix);
}
}
/**
* getMask - Returns mask from the prefix
* @return {string} -> 255.255.0.0
*/
getMask() {
return this.toDottedNotation(this.maskToInteger());
}
/**
* networkToInteger - Returns network as bigInt.
* @return {BigInt} -> 21307064320
*/
networkToInteger() {
return this.toInteger() & this.maskToInteger();
}
/**
* getNetwork - Returns network part of the address
* @return {string} -> 127
*/
getNetwork() {
return this.toDottedNotation(this.networkToInteger());
}
/**
* getBroadcast - Calculates broadcast.IPv6 doesn't have a broadcast
* address, but it's used for other calculations such as Network.hostLast.
* @return {string} -> 127.255.255.255
*/
getBroadcast() {
return this.version === 4
? this.toDottedNotation(this.broadcastToLong())
: 'IPv6 doesnt have broadcast address';
}
/**
* broadcastToLong - Returns broadcast as long.
* @return {BigInt} ->2147483647
*/
broadcastToLong() {
if (this.version === 4) {
return this.networkToInteger() | (IPv4MAX - this.maskToInteger());
}
else {
return this.networkToInteger() | (IPv6MAX - this.maskToInteger());
}
}
/**
* hostFirst - Calculates first available host in this subnet.
* @return {string} ->127.0.0.1
*/
hostFirst() {
const isSmall4 = this.version === 4 && this.prefix > BigInt(30);
let first;
if (this.version === 6) {
first = this.getNetwork();
}
else if (isSmall4) {
return 'N/A';
}
else {
first = this.toDottedNotation(this.networkToInteger() + BigInt(1));
}
return this.toCompressed(first, this.version);
}
/**
* hostLast - Calculates last available host in this subnet.
* @return {string} ->127.255.255.255
*/
hostLast() {
const isLast4 = this.version === 4 && this.prefix === BigInt(32);
const isLast6 = this.version === 6 && this.prefix === BigInt(128);
const isPrev4 = this.version === 4 && this.prefix === BigInt(31);
const isPrev6 = this.version === 6 && this.prefix === BigInt(127);
let last;
if (isLast4 || isLast6 || isPrev4) {
return 'N/A';
}
else if (isPrev6) {
last = this.address;
}
else if (this.version === 4) {
last = this.toDottedNotation(this.broadcastToLong() - BigInt(1));
}
else {
last = this.toDottedNotation(this.broadcastToLong());
}
return this.toCompressed(last, this.version);
}
/**
* contains - Check if thisIP is part of the network
* @param {string} thisIP
* @param {string} otherIP
* @param {number} prefix
* @return {boolean}
*/
contains(thisIP: string, otherIP: string, prefix: number) {
const other = new Network(otherIP, prefix);
const thisNetwork = this.networkToInteger();
const otherNetwork = other.networkToInteger();
const smaller = (thisNetwork <= otherNetwork)
&& (otherNetwork <= this.broadcastToLong());
const bigger = (otherNetwork <= thisNetwork)
&& (thisNetwork <= other.broadcastToLong());
return smaller || bigger;
}
/**
* hostRange - Generates a range of usable host IP addresses within the network.
* @return {array} -> ['127.0.0.1','127.255.255.255']
*/
hostRange() {
const range = [];
range.push(this.hostFirst());
range.push(this.hostLast());
return range;
}
/**
* networkSize - Returns number of ips within the network.
* @return {number} -> 16777214
*/
networkSize() {
const size = BigInt(2) ** ((this.version === 4 ? BigInt(32) : BigInt(128)) - this.prefix);
if (this.version === 4 && this.prefix < BigInt(30)) {
return size - BigInt(2);
}
return size;
}
/**
* networkCount - Returns number of network fo the prefix.
* @return {number} -> 16777214
*/
networkCount() {
return this.prefix <= 64 ? (BigInt(2) ** BigInt(64n - this.prefix)).toString() : '';
}
}