From 070ec0b36ef615715f8fc84d6da9b7b447ce5a05 Mon Sep 17 00:00:00 2001 From: sharevb Date: Wed, 3 Apr 2024 23:36:17 +0200 Subject: [PATCH] feat(IPv4 Subnet/Address Calculator): add more ip info Add IPv4 range info (ie, private use, apipa...) Add ARPA, Ipv6, 6to4 and class for both tools --- components.d.ts | 2 + src/libs/ip_calculator/ip.ts | 452 ++++++++++++++++++ src/libs/ip_calculator/ipv4registry.json | 26 + src/libs/ip_calculator/ipv6registry.json | 24 + src/libs/ip_calculator/network.ts | 249 ++++++++++ .../ipv4-address-converter.vue | 27 ++ .../ipv4-subnet-calculator.vue | 26 + 7 files changed, 806 insertions(+) create mode 100644 src/libs/ip_calculator/ip.ts create mode 100644 src/libs/ip_calculator/ipv4registry.json create mode 100644 src/libs/ip_calculator/ipv6registry.json create mode 100644 src/libs/ip_calculator/network.ts diff --git a/components.d.ts b/components.d.ts index e31119b3..46523322 100644 --- a/components.d.ts +++ b/components.d.ts @@ -145,6 +145,7 @@ declare module '@vue/runtime-core' { NMenu: typeof import('naive-ui')['NMenu'] NScrollbar: typeof import('naive-ui')['NScrollbar'] NSpin: typeof import('naive-ui')['NSpin'] + NTable: typeof import('naive-ui')['NTable'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] PasswordStrengthAnalyser: typeof import('./src/tools/password-strength-analyser/password-strength-analyser.vue')['default'] @@ -159,6 +160,7 @@ declare module '@vue/runtime-core' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] RsaKeyPairGenerator: typeof import('./src/tools/rsa-key-pair-generator/rsa-key-pair-generator.vue')['default'] + SafelinkDecoder: typeof import('./src/tools/safelink-decoder/safelink-decoder.vue')['default'] SlugifyString: typeof import('./src/tools/slugify-string/slugify-string.vue')['default'] SpanCopyable: typeof import('./src/components/SpanCopyable.vue')['default'] SqlPrettify: typeof import('./src/tools/sql-prettify/sql-prettify.vue')['default'] diff --git a/src/libs/ip_calculator/ip.ts b/src/libs/ip_calculator/ip.ts new file mode 100644 index 00000000..a013d7ac --- /dev/null +++ b/src/libs/ip_calculator/ip.ts @@ -0,0 +1,452 @@ +/* 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 { + integer: bigint; + short: string; + version: number; + address: string; + /** + * @constructor + */ + constructor(address: string) { + this.integer = 0n; + this.short = ''; + this.version = this._checkVersion(address); + this.address = this._checkAddress(address, this.version); + this.toInteger(); + } + + // 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 (Number(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: 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(':'); + } + } + + toARPA() { + if (this.version === 6) { + return ''; + } + + const bigInt = this.integer; + const reverseIP = ( + [(bigInt & BigInt(255)), (bigInt >> BigInt(8) & BigInt(255)), + (bigInt >> BigInt(16) & BigInt(255)), + (bigInt >> BigInt(24) & BigInt(255)), + ].join('.') + ); + return `${reverseIP}.in-addr.arpa`; + } + + toIPv4MappedAddress() { + if (this.version === 6) { + return ''; + } + + const hexIP = this.toHEX(true); + return `::ffff:${hexIP.substring(0, 4)}:${hexIP.substring(4)}`; + } + + toIPv4MappedAddressDecimal() { + if (this.version === 6) { + return ''; + } + + return `::ffff:${this.toDottedNotation(this.integer)}`; + } + + to6to4Prefix() { + if (this.version === 6) { + return ''; + } + + const hexIP = this.toHEX(true); + return `2002:${hexIP.substring(0, 4)}:${hexIP.substring(4)}::/48`; + } + + /** + * toBinary - Converts decimal IP to full-length binary representation. + * @return {string} -> 01111111000000000000000000000001 + */ + toBinary() { + let binary = this.integer.toString(2); + const markLen = this.version === 4 ? 32 : 128; + + if (binary.length < markLen) { + while (binary.length < markLen) { + binary = `0${binary}`; + } + } + return binary; + } + + /** + * toHEX - Converts both IP versions to hexadecimal representation. + * @return {string} -> 7f000001 + */ + toHEX(pad: boolean = false) { + let hex = this.integer.toString(16); + if (!pad) { + return hex; + } + const markLen = this.version === 4 ? 8 : 24; + + if (hex.length < markLen) { + while (hex.length < markLen) { + hex = `0${hex}`; + } + } + return hex; + } + + /** + * toCompressed - Compress an IP address to its shortest possible form. + * IP('127.1.0.0').toCompressed + * @return {string} -> "127.1" + */ + toCompressed(addr: string, ver: number) { + 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(Number(startOfLongest), Number(longestLength), ''); + if (startOfLongest === 0) { + splitted.unshift(''); + } + if (Number(startOfLongest) + Number(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: string) { + // 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)) { + const parsedAddr = BigInt(addr); + if (parsedAddr > IPv6MAX || parsedAddr <= 0) { + throw new Error('Tips: IP address cant be bigger than 2 to the 128-th power or negative number'); + } + else if (parsedAddr <= IPv4MAX) { + return 4; + } + else if (parsedAddr > 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: string, v: number) { + const reNum = /^[0-9]+$/; + if (reNum.test(addr)) { + this.integer = BigInt(addr); + return this.toDottedNotation(this.integer); + } + + const splittedAddr = addr.split(v === 4 ? '.' : ':'); + + 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 ((v === 4 ? this._isIPv4 : this._isIPv6).call(this, splittedAddr)) { // TODO: make ifs more readable + if (splittedAddr.length === (v === 4 ? 4 : 8) && this.short === '') { + 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: string[]) { + 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: string) { + return regex.test(hextet); + }; + checked = (cleanedAddr as string[]).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: string[]) { + if (splittedAddr.length <= 4) { + if (splittedAddr.length < 4) { + this.short = splittedAddr.join('.'); + } + const isValid = function (octet: string) { + return (!!((Number(octet) <= 255 && Number(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: string[]) { + 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: string[]) { + 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: string[]) { + 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']; +} diff --git a/src/libs/ip_calculator/ipv4registry.json b/src/libs/ip_calculator/ipv4registry.json new file mode 100644 index 00000000..91b262c7 --- /dev/null +++ b/src/libs/ip_calculator/ipv4registry.json @@ -0,0 +1,26 @@ +[ + ["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"]] +] \ No newline at end of file diff --git a/src/libs/ip_calculator/ipv6registry.json b/src/libs/ip_calculator/ipv6registry.json new file mode 100644 index 00000000..c419b4d1 --- /dev/null +++ b/src/libs/ip_calculator/ipv6registry.json @@ -0,0 +1,24 @@ +[ + ["::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"]] + ] \ No newline at end of file diff --git a/src/libs/ip_calculator/network.ts b/src/libs/ip_calculator/network.ts new file mode 100644 index 00000000..9f340e18 --- /dev/null +++ b/src/libs/ip_calculator/network.ts @@ -0,0 +1,249 @@ +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() : ''; + } +} diff --git a/src/tools/ipv4-address-converter/ipv4-address-converter.vue b/src/tools/ipv4-address-converter/ipv4-address-converter.vue index 40b1890e..30e4b723 100644 --- a/src/tools/ipv4-address-converter/ipv4-address-converter.vue +++ b/src/tools/ipv4-address-converter/ipv4-address-converter.vue @@ -1,12 +1,15 @@