mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 13:57:10 -04:00
feat: ipv4/6 calculator lib
This commit is contained in:
parent
d3b32cc14e
commit
d7a8c65067
2 changed files with 674 additions and 0 deletions
406
src/libs/ip_calculator/ip.js
Normal file
406
src/libs/ip_calculator/ip.js
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
/* eslint-disable no-labels */
|
||||||
|
/* eslint-disable no-restricted-syntax */
|
||||||
|
|
||||||
|
const IPv4MAX = (BigInt(2) ** BigInt(32)) - BigInt(1);
|
||||||
|
const IPv6MAX = (BigInt(2) ** BigInt(128)) - BigInt(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single IP address v4 or v6.
|
||||||
|
* @class IP
|
||||||
|
* @param {string} address
|
||||||
|
* host = new IP("184.170.96.196");
|
||||||
|
* @return {object} -> IP{address:"184.170.96.196", version: 4, integer: 0, short: 0}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class IP {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(address) {
|
||||||
|
this.integer = 0;
|
||||||
|
this.short = 0;
|
||||||
|
this.version = this._checkVersion(address);
|
||||||
|
this.address = this._checkAddress(address, this.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toInteger - Converts dotquad or hextet IP to integer
|
||||||
|
* @return {BigInt} -> 2130706432
|
||||||
|
*/
|
||||||
|
toInteger() {
|
||||||
|
let bigInt;
|
||||||
|
if (this.version === 4) {
|
||||||
|
const splittedAddr = this.address.split('.').reverse();
|
||||||
|
bigInt = splittedAddr.reduce((bigInt, octet, index) => {
|
||||||
|
return (octet * 256 ** index + bigInt
|
||||||
|
);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const joinedAddr = this.address.split(':').join('');
|
||||||
|
bigInt = BigInt(`0x${joinedAddr}`);
|
||||||
|
}
|
||||||
|
this.integer = BigInt(bigInt);
|
||||||
|
return BigInt(bigInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toDottedNotation - Converts big integer IP to full dotquad or hextet representation
|
||||||
|
* @param {bigint} bigInt
|
||||||
|
* @return {string} -> "184.170.96.196"
|
||||||
|
*/
|
||||||
|
toDottedNotation(bigInt) {
|
||||||
|
if (this.version === 4) {
|
||||||
|
return (
|
||||||
|
[(bigInt >> BigInt(24) & BigInt(255)), (bigInt >> BigInt(16) & BigInt(255)),
|
||||||
|
(bigInt >> BigInt(8) & BigInt(255)),
|
||||||
|
(bigInt & BigInt(255)),
|
||||||
|
].join('.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let hex = bigInt.toString(16);
|
||||||
|
const groups = [];
|
||||||
|
while (hex.length < 32) {
|
||||||
|
hex = `0${hex}`;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
groups.push(hex.slice(i * 4, (i + 1) * 4));
|
||||||
|
}
|
||||||
|
return groups.join(':');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toBinary - Converts decimal IP to full-length binary representation.
|
||||||
|
* @return {string} -> 01111111000000000000000000000001
|
||||||
|
*/
|
||||||
|
toBinary() {
|
||||||
|
if (this.integer === 0) {
|
||||||
|
this.toInteger();
|
||||||
|
}
|
||||||
|
let binary = this.integer.toString(2);
|
||||||
|
const v = this.version;
|
||||||
|
const marks = { 4: 32, 6: 128 };
|
||||||
|
|
||||||
|
if (binary.length < marks[v]) {
|
||||||
|
while (binary.length < marks[v]) {
|
||||||
|
binary = `0${binary}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return binary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toHEX - Converts both IP versions to hexadecimal representation.
|
||||||
|
* @return {string} -> 7f000001
|
||||||
|
*/
|
||||||
|
toHEX() {
|
||||||
|
if (this.integer === 0) {
|
||||||
|
this.toInteger();
|
||||||
|
}
|
||||||
|
return this.integer.toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toCompressed - Compress an IP address to its shortest possible form.
|
||||||
|
* IP('127.1.0.0').toCompressed
|
||||||
|
* @return {string} -> "127.1"
|
||||||
|
*/
|
||||||
|
toCompressed(addr, ver) {
|
||||||
|
if (ver === 4) {
|
||||||
|
const splittedAddr = addr.split('.');
|
||||||
|
const sRange = [[1, 3], [2, 2], [3, 1], [0, 0]];
|
||||||
|
|
||||||
|
for (let i = splittedAddr.length - 1; i >= 0; i--) {
|
||||||
|
if (splittedAddr[i] === '0') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
splittedAddr.splice(sRange[i][0], sRange[i][1]);
|
||||||
|
this.short = splittedAddr.join('.');
|
||||||
|
return this.short;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const splitted = addr.split(':');
|
||||||
|
// finding longest zero group
|
||||||
|
const [startOfLongest, longestLength] = _longestZerosGroup(splitted);
|
||||||
|
// 'N/A' - _longestZerosGroup fn return in case if there is NO
|
||||||
|
// '0000' blocks in address
|
||||||
|
if (startOfLongest !== 'N/A' || longestLength !== 'N/A') {
|
||||||
|
splitted.splice(startOfLongest, longestLength, '');
|
||||||
|
if (startOfLongest === 0) {
|
||||||
|
splitted.unshift('');
|
||||||
|
}
|
||||||
|
if (startOfLongest + longestLength === 8) {
|
||||||
|
splitted.push('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removing single '0000' blocks and leading zeros
|
||||||
|
for (let i = 0; i < splitted.length; i++) {
|
||||||
|
if (splitted[i] === '0000') {
|
||||||
|
splitted.splice(i, 1, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
loopStr:
|
||||||
|
for (let j = 0; j < splitted[i].length; j++) {
|
||||||
|
if (splitted[i][j] === '0' && splitted[i] !== '0') {
|
||||||
|
splitted[i] = splitted[i].substring(j + 1);
|
||||||
|
j--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break loopStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.short = splitted.join(':');
|
||||||
|
return this.short;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkVersion - Determins this IP version.
|
||||||
|
* @private
|
||||||
|
* @param {string} addr
|
||||||
|
* @return {number} -> 4 or 6
|
||||||
|
*/
|
||||||
|
_checkVersion(addr) {
|
||||||
|
// matches all possible chars in both versions of IP
|
||||||
|
const reGen = /^[0-9a-f.:]+$/i;
|
||||||
|
if (reGen.test(addr)) {
|
||||||
|
// checks if there is .. and more or whole IP is just a dot
|
||||||
|
const reDots = /\.{2,}|^\.{1}$/;
|
||||||
|
// checks if there is ::: and more or whole IP is just a colon
|
||||||
|
const reColon = /:{3,}|^:{1}$/;
|
||||||
|
// checks if there is only digits in integer IP
|
||||||
|
const reNum = /^[0-9]+$/;
|
||||||
|
|
||||||
|
if (reNum.test(addr)) {
|
||||||
|
addr = BigInt(addr);
|
||||||
|
if (addr > IPv6MAX || addr <= 0) {
|
||||||
|
throw new Error('Tips: IP address cant be bigger than 2 to the 128-th power or negative number');
|
||||||
|
}
|
||||||
|
else if (addr <= IPv4MAX) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else if (addr > IPv4MAX) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr.includes('.') && !reDots.test(addr)) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
else if (addr.includes(':') && !reColon.test(addr)) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('Tips: Please, enter a valid IP address (Like "127.1.0.0", long integer, short or long IPv6)');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkAddress - Validates this IP address.
|
||||||
|
* @private
|
||||||
|
* @return {string} as a valid address
|
||||||
|
*/
|
||||||
|
_checkAddress(addr, v) {
|
||||||
|
const reNum = /^[0-9]+$/;
|
||||||
|
if (reNum.test(addr)) {
|
||||||
|
this.integer = BigInt(addr);
|
||||||
|
return this.toDottedNotation(this.integer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const marks = {
|
||||||
|
4: ['.', this._isIPv4, 4],
|
||||||
|
6: [':', this._isIPv6, 8],
|
||||||
|
};
|
||||||
|
const splittedAddr = addr.split(marks[v][0]);
|
||||||
|
|
||||||
|
if (v === 6 && splittedAddr.length < 8) {
|
||||||
|
const dbColon = (addr.match(/::/g) || []).length;
|
||||||
|
if (dbColon !== 1) {
|
||||||
|
throw new Error('Tips: Please, enter a valid IP address (Like "127.1.0.0", long integer, short or long IPv6)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (marks[v][1].call(this, splittedAddr)) { // TODO: make ifs more readable
|
||||||
|
if (splittedAddr.length === marks[v][2] && this.short === 0) {
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return this._toRepresentation(splittedAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('Tips: Please, enter a valid IP address (Like "127.1.0.0", long integer, short or long IPv6)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _isIPv6 - Validates IPv6.
|
||||||
|
* @private
|
||||||
|
* @return {boolean} whether splitted address is valid IPv6 or not
|
||||||
|
*/
|
||||||
|
_isIPv6(splittedAddr) {
|
||||||
|
if (splittedAddr.length <= 8) {
|
||||||
|
let checked = false;
|
||||||
|
const [isShort, cleanedAddr] = this._isShort(splittedAddr);
|
||||||
|
|
||||||
|
const regex = /^[0-9a-f]{1,4}$/i;
|
||||||
|
const isValid = function (hextet) {
|
||||||
|
return regex.test(hextet);
|
||||||
|
};
|
||||||
|
checked = cleanedAddr.every(isValid);
|
||||||
|
|
||||||
|
if (checked && isShort) {
|
||||||
|
this.short = splittedAddr.join(':');
|
||||||
|
}
|
||||||
|
return checked;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('Tips: IPv6 cannot contain more than 8 bytes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _isIPv4 - Validates IPv4.
|
||||||
|
* @private
|
||||||
|
* @return {boolean} whether splitted address is valid IPv4 or not
|
||||||
|
*/
|
||||||
|
_isIPv4(splittedAddr) {
|
||||||
|
if (splittedAddr.length <= 4) {
|
||||||
|
if (splittedAddr.length < 4) {
|
||||||
|
this.short = splittedAddr.join('.');
|
||||||
|
}
|
||||||
|
const isValid = function (octet) {
|
||||||
|
return (!!((octet <= 255 && octet >= 0)));
|
||||||
|
};
|
||||||
|
return splittedAddr.every(isValid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error('Tips: IPv4 cannot contain more than 4 bytes');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _isShort - checks if IPv6 addres was compressed like this "234:f:34:34:1:1:2:2" or like "1234::1234:1234" and removes empty strings for future validation
|
||||||
|
* @private
|
||||||
|
* @param {array} splittedAddr
|
||||||
|
* @return {array} with both results boolean and cleaned array
|
||||||
|
*/
|
||||||
|
_isShort(splittedAddr) {
|
||||||
|
let isShort = false;
|
||||||
|
const cleanedAddr = [...splittedAddr];
|
||||||
|
for (let i = 0; i < cleanedAddr.length; i++) {
|
||||||
|
if (cleanedAddr[i].length === 0) {
|
||||||
|
cleanedAddr.splice(i, 1);
|
||||||
|
isShort = true;
|
||||||
|
i--; // code chunk similar to toCompressed method
|
||||||
|
// for addr '::1' can happen that there are 2 empty strings
|
||||||
|
// together, so by i-- we check every el of array but not next but one
|
||||||
|
}
|
||||||
|
else if (cleanedAddr[i].length < 4) {
|
||||||
|
isShort = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [isShort, cleanedAddr];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toRepresentation - Converts short version to canonical representation of IP.
|
||||||
|
* IP('::1').address
|
||||||
|
* @private
|
||||||
|
* @param {array} splittedAddr
|
||||||
|
* @return {string} -> "0000:0000:0000:0000:0000:0000:0000:0001"
|
||||||
|
*/
|
||||||
|
_toRepresentation(splittedAddr) {
|
||||||
|
if (this.version === 4) {
|
||||||
|
for (let i = 0; i <= 4; i++) {
|
||||||
|
if (splittedAddr[i] === '') {
|
||||||
|
let missOcts = 5 - splittedAddr.length;
|
||||||
|
let flag = true;
|
||||||
|
while (missOcts > 0) {
|
||||||
|
if (flag) {
|
||||||
|
splittedAddr.splice(i, 1, '0');
|
||||||
|
missOcts--;
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
splittedAddr.splice(i, 0, '0');
|
||||||
|
missOcts--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (splittedAddr.length < 4) {
|
||||||
|
splittedAddr.push('0');
|
||||||
|
}
|
||||||
|
return splittedAddr.join('.');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let i = 0; i <= 8; i++) {
|
||||||
|
if (splittedAddr[i] === '') {
|
||||||
|
let missHex = 9 - splittedAddr.length;
|
||||||
|
let flag = true;
|
||||||
|
while (missHex > 0) {
|
||||||
|
if (flag) {
|
||||||
|
splittedAddr.splice(i, 1, '0000');
|
||||||
|
missHex--;
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
splittedAddr.splice(i, 0, '0000');
|
||||||
|
missHex--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < splittedAddr.length; i++) {
|
||||||
|
if (splittedAddr[i].length < 4) {
|
||||||
|
let missNum = 4 - splittedAddr[i].length;
|
||||||
|
while (missNum > 0) {
|
||||||
|
splittedAddr[i] = `0${splittedAddr[i]}`;
|
||||||
|
missNum--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return splittedAddr.join(':');
|
||||||
|
}
|
||||||
|
}// IP class end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* longestZerosGroup - Helper fn counting longest consecutive zeros for shortening IPv6
|
||||||
|
* "0000:0000:0000:0000:0000:0000:0000:0001"
|
||||||
|
* @private
|
||||||
|
* @param {array} zeros
|
||||||
|
* @return {array} -> [0, 7]
|
||||||
|
*/
|
||||||
|
function _longestZerosGroup(splittedAddr) {
|
||||||
|
let curr = 0;
|
||||||
|
let currLongest = 0;
|
||||||
|
let startOfLongest = 0;
|
||||||
|
let hasZeros = false;
|
||||||
|
|
||||||
|
while (curr < splittedAddr.length - 2) {
|
||||||
|
const startOfRun = curr;
|
||||||
|
while (curr < splittedAddr.length && splittedAddr[curr] === '0000') {
|
||||||
|
hasZeros = true;
|
||||||
|
curr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((curr - startOfRun) > currLongest) {
|
||||||
|
startOfLongest = startOfRun;
|
||||||
|
currLongest = curr - startOfRun;
|
||||||
|
}
|
||||||
|
curr++;
|
||||||
|
}
|
||||||
|
return hasZeros ? [startOfLongest, currLongest] : ['N/A', 'N/A'];
|
||||||
|
}
|
268
src/libs/ip_calculator/network.js
Normal file
268
src/libs/ip_calculator/network.js
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
import IP from './ip.js';
|
||||||
|
|
||||||
|
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([
|
||||||
|
['0.0.0.0', [8, 'This host on this network']],
|
||||||
|
['10.0.0.0', [8, 'Private-Use']],
|
||||||
|
['100.64.0.0', [10, 'Shared Address Space']],
|
||||||
|
['127.0.0.0', [8, 'Loopback']],
|
||||||
|
['169.254.0.0', [16, 'Link Local']],
|
||||||
|
['172.16.0.0', [12, 'Private-Use']],
|
||||||
|
['192.0.0.0', [24, 'IETF Protocol Assignments']],
|
||||||
|
['192.0.0.0', [29, 'IPv4 Service Continuity Prefix']],
|
||||||
|
['192.0.0.8', [32, 'IPv4 dummy address']],
|
||||||
|
['192.0.0.9', [32, 'Port Control Protocol Anycast']],
|
||||||
|
['192.0.0.10', [32, 'Traversal Using Relays around NAT Anycast']],
|
||||||
|
['192.0.0.170', [32, 'NAT64/DNS64 Discovery']],
|
||||||
|
['192.0.0.171', [32, 'NAT64/DNS64 Discovery']],
|
||||||
|
['192.0.2.0', [24, 'Documentation (TEST-NET-1)']],
|
||||||
|
['192.31.196.0', [24, 'AS112-v4']],
|
||||||
|
['192.52.193.0', [24, 'AMT']],
|
||||||
|
['192.88.99.0', [24, 'Deprecated (6to4 Relay Anycast)']],
|
||||||
|
['192.168.0.0', [16, 'Private Use']],
|
||||||
|
['192.175.48.0', [24, 'Direct Delegation AS112 Service']],
|
||||||
|
['198.18.0.0', [15, 'Benchmarking']],
|
||||||
|
['198.51.100.0', [24, 'Documentation (TEST-NET-2)']],
|
||||||
|
['203.0.113.0', [24, 'Documentation (TEST-NET-3)']],
|
||||||
|
['240.0.0.0', [4, 'Reserved']],
|
||||||
|
['255.255.255.255', [32, 'Limited Broadcast']],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
|
||||||
|
const _ipv6Registry = new Map([
|
||||||
|
['::1', [128, 'Loopback Address']],
|
||||||
|
['::', [128, 'Unspecified Address']],
|
||||||
|
['::', [128, 'Unspecified Address']],
|
||||||
|
['::ffff:0:0', [98, 'IPv4-mapped Address']],
|
||||||
|
['64:ff9b::', [96, 'IPv4-IPv6 Translat.']],
|
||||||
|
['64:ff9b:1::', [48, 'IPv4-IPv6 Translat.']],
|
||||||
|
['100::', [64, 'Discard-Only Address Block']],
|
||||||
|
['2001::', [23, 'IETF Protocol Assignments']],
|
||||||
|
['2001::', [32, 'TEREDO']],
|
||||||
|
['2001:1::1', [128, 'Port Control Protocol Anycast']],
|
||||||
|
['2001:1::2', [128, 'Traversal Using Relays around NAT Anycast']],
|
||||||
|
['2001:2::', [48, 'Benchmarking']],
|
||||||
|
['2001:3::', [32, 'AMT']],
|
||||||
|
['2001:4:112::', [48, 'AS112-v6']],
|
||||||
|
['2001:5::', [32, 'EID Space for LISP (Managed by RIPE NCC)']],
|
||||||
|
['2001:10::', [28, 'Deprecated (previously ORCHID)']],
|
||||||
|
['2001:20::', [28, 'ORCHIDv2']],
|
||||||
|
['2001:db8::', [32, 'Documentation']],
|
||||||
|
['2002::', [16, '6to4']],
|
||||||
|
['2620:4f:8000::', [48, 'Direct Delegation AS112 Service']],
|
||||||
|
['fc00::', [7, 'Unique-Local']],
|
||||||
|
['fe80::', [10, 'Link-Local Unicast']],
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
/**
|
||||||
|
* Extends IP class. Calls the parent class IP with the parameters passed to Network.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(address, prefix) {
|
||||||
|
super(address);
|
||||||
|
this.prefix = this._checkPrefix(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private methods
|
||||||
|
|
||||||
|
/**
|
||||||
|
* _checkPrefix - Returns this IP prefix and validates it
|
||||||
|
* @private
|
||||||
|
* @return {integer} -> prefix: 25n
|
||||||
|
*/
|
||||||
|
_checkPrefix(prefix) {
|
||||||
|
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 registry = { 4: _ipv4Registry, 6: _ipv6Registry };
|
||||||
|
const results = [];
|
||||||
|
for (const [addr, info] of registry[this.version].entries()) {
|
||||||
|
const found = this.contains(this.address, addr, 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, otherIP, prefix) {
|
||||||
|
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 marks = { 4: BigInt(32), 6: BigInt(128) };
|
||||||
|
const size = BigInt(2) ** (marks[this.version] - this.prefix);
|
||||||
|
|
||||||
|
if (this.version === 4 && this.prefix < BigInt(30)) {
|
||||||
|
return size - BigInt(2);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue