230 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			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() : '';
 | |
|   }
 | |
| }
 |