Add IPv4 range info (ie, private use, apipa...) Add ARPA, Ipv6, 6to4 and class for both tools
250 lines
6.7 KiB
TypeScript
250 lines
6.7 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() {
|
|
if (this.version === 4) {
|
|
const [firstOctet] = this.address.split('.').map(Number);
|
|
|
|
if (firstOctet < 128) {
|
|
return 2 ** 7;
|
|
}
|
|
if (firstOctet > 127 && firstOctet < 192) {
|
|
return 2 ** 14;
|
|
}
|
|
if (firstOctet > 191 && firstOctet < 224) {
|
|
return 2 ** 21;
|
|
}
|
|
if (firstOctet > 223 && firstOctet < 240) {
|
|
return -1;
|
|
}
|
|
if (firstOctet > 239 && firstOctet < 256) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return this.prefix <= 64 ? (BigInt(2) ** BigInt(64n - this.prefix)).toString() : '';
|
|
}
|
|
}
|