From 1f67ba15e9a8de71290281c5eaf655763a33d617 Mon Sep 17 00:00:00 2001 From: sharevb Date: Wed, 3 Apr 2024 22:47:43 +0200 Subject: [PATCH] feat(new tool): IPv6 Subnet Calculator IPv6 Subnet Calculator Fix #354 and #924 --- components.d.ts | 12 +- package.json | 1 + pnpm-lock.yaml | 34 ++++- src/libs/ip_calculator/{ip.js => ip.ts} | 71 +++++----- src/libs/ip_calculator/ipv4registry.json | 26 ++++ src/libs/ip_calculator/ipv6registry.json | 24 ++++ .../ip_calculator/{network.js => network.ts} | 79 +++-------- src/tools/index.ts | 11 +- src/tools/ipv6-subnet-calculator/index.ts | 12 ++ .../ipv6-subnet-calculator.vue | 126 ++++++++++++++++++ 10 files changed, 285 insertions(+), 111 deletions(-) rename src/libs/ip_calculator/{ip.js => ip.ts} (86%) create mode 100644 src/libs/ip_calculator/ipv4registry.json create mode 100644 src/libs/ip_calculator/ipv6registry.json rename src/libs/ip_calculator/{network.js => network.ts} (67%) create mode 100644 src/tools/ipv6-subnet-calculator/index.ts create mode 100644 src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue diff --git a/components.d.ts b/components.d.ts index e31119b3..cca87d45 100644 --- a/components.d.ts +++ b/components.d.ts @@ -105,6 +105,7 @@ declare module '@vue/runtime-core' { Ipv4AddressConverter: typeof import('./src/tools/ipv4-address-converter/ipv4-address-converter.vue')['default'] Ipv4RangeExpander: typeof import('./src/tools/ipv4-range-expander/ipv4-range-expander.vue')['default'] Ipv4SubnetCalculator: typeof import('./src/tools/ipv4-subnet-calculator/ipv4-subnet-calculator.vue')['default'] + Ipv6SubnetCalculator: typeof import('./src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue')['default'] Ipv6UlaGenerator: typeof import('./src/tools/ipv6-ula-generator/ipv6-ula-generator.vue')['default'] JsonDiff: typeof import('./src/tools/json-diff/json-diff.vue')['default'] JsonMinify: typeof import('./src/tools/json-minify/json-minify.vue')['default'] @@ -127,24 +128,16 @@ declare module '@vue/runtime-core' { MetaTagGenerator: typeof import('./src/tools/meta-tag-generator/meta-tag-generator.vue')['default'] MimeTypes: typeof import('./src/tools/mime-types/mime-types.vue')['default'] NavbarButtons: typeof import('./src/components/NavbarButtons.vue')['default'] - NCode: typeof import('naive-ui')['NCode'] NCollapseTransition: typeof import('naive-ui')['NCollapseTransition'] NConfigProvider: typeof import('naive-ui')['NConfigProvider'] - NDivider: typeof import('naive-ui')['NDivider'] NEllipsis: typeof import('naive-ui')['NEllipsis'] - NFormItem: typeof import('naive-ui')['NFormItem'] - NGi: typeof import('naive-ui')['NGi'] - NGrid: typeof import('naive-ui')['NGrid'] NH1: typeof import('naive-ui')['NH1'] NH3: typeof import('naive-ui')['NH3'] NIcon: typeof import('naive-ui')['NIcon'] - NInputNumber: typeof import('naive-ui')['NInputNumber'] - NLabel: typeof import('naive-ui')['NLabel'] NLayout: typeof import('naive-ui')['NLayout'] NLayoutSider: typeof import('naive-ui')['NLayoutSider'] 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 +152,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/package.json b/package.json index fd6c02e6..fc00ad79 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "highlight.js": "^11.7.0", "iarna-toml-esm": "^3.0.5", "ibantools": "^4.3.3", + "is-cidr": "^5.0.3", "json5": "^2.2.3", "jwt-decode": "^3.1.2", "libphonenumber-js": "^1.10.28", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd6c38c9..cb383786 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,6 +92,9 @@ dependencies: ibantools: specifier: ^4.3.3 version: 4.3.3 + is-cidr: + specifier: ^5.0.3 + version: 5.0.3 json5: specifier: ^2.2.3 version: 2.2.3 @@ -3351,7 +3354,7 @@ packages: dependencies: '@unhead/dom': 0.5.1 '@unhead/schema': 0.5.1 - '@vueuse/shared': 10.7.2(vue@3.3.4) + '@vueuse/shared': 10.9.0(vue@3.3.4) unhead: 0.5.1 vue: 3.3.4 transitivePeerDependencies: @@ -3993,10 +3996,10 @@ packages: - vue dev: false - /@vueuse/shared@10.7.2(vue@3.3.4): - resolution: {integrity: sha512-qFbXoxS44pi2FkgFjPvF4h7c9oMDutpyBdcJdMYIMg9XyXli2meFMuaKn+UMgsClo//Th6+beeCgqweT/79BVA==} + /@vueuse/shared@10.9.0(vue@3.3.4): + resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==} dependencies: - vue-demi: 0.14.6(vue@3.3.4) + vue-demi: 0.14.7(vue@3.3.4) transitivePeerDependencies: - '@vue/composition-api' - vue @@ -4463,6 +4466,13 @@ packages: engines: {node: '>=8'} dev: true + /cidr-regex@4.0.3: + resolution: {integrity: sha512-HOwDIy/rhKeMf6uOzxtv7FAbrz8zPjmVKfSpM+U7/bNBXC5rtOyr758jxcptiSx6ZZn5LOhPJT5WWxPAGDV8dw==} + engines: {node: '>=14'} + dependencies: + ip-regex: 5.0.0 + dev: false + /clean-regexp@1.0.0: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} @@ -6185,6 +6195,11 @@ packages: jsbn: 1.1.0 dev: false + /ip-regex@5.0.0: + resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /is-alphabetical@1.0.4: resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} dev: true @@ -6240,6 +6255,13 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-cidr@5.0.3: + resolution: {integrity: sha512-lKkM0tmz07dAxNsr8Ii9MGreExa9ZR34N9j8mTG5op824kcwBqinZPowNjcVWWc7j+jR8XAMMItOmBkniN0jOA==} + engines: {node: '>=14'} + dependencies: + cidr-regex: 4.0.3 + dev: false + /is-core-module@2.13.0: resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} dependencies: @@ -9151,8 +9173,8 @@ packages: vue: 3.3.4 dev: false - /vue-demi@0.14.6(vue@3.3.4): - resolution: {integrity: sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==} + /vue-demi@0.14.7(vue@3.3.4): + resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==} engines: {node: '>=12'} hasBin: true requiresBuild: true diff --git a/src/libs/ip_calculator/ip.js b/src/libs/ip_calculator/ip.ts similarity index 86% rename from src/libs/ip_calculator/ip.js rename to src/libs/ip_calculator/ip.ts index 14052454..8e7ec106 100644 --- a/src/libs/ip_calculator/ip.js +++ b/src/libs/ip_calculator/ip.ts @@ -13,12 +13,16 @@ const IPv6MAX = (BigInt(2) ** BigInt(128)) - BigInt(1); */ export default class IP { + integer: bigint; + short: string; + version: number; + address: string; /** * @constructor */ - constructor(address) { - this.integer = 0; - this.short = 0; + constructor(address: string) { + this.integer = 0n; + this.short = ''; this.version = this._checkVersion(address); this.address = this._checkAddress(address, this.version); } @@ -34,7 +38,7 @@ export default class IP { if (this.version === 4) { const splittedAddr = this.address.split('.').reverse(); bigInt = splittedAddr.reduce((bigInt, octet, index) => { - return (octet * 256 ** index + bigInt + return (Number(octet) * 256 ** index + bigInt ); }, 0); } @@ -51,7 +55,7 @@ export default class IP { * @param {bigint} bigInt * @return {string} -> "184.170.96.196" */ - toDottedNotation(bigInt) { + toDottedNotation(bigInt: bigint) { if (this.version === 4) { return ( [(bigInt >> BigInt(24) & BigInt(255)), (bigInt >> BigInt(16) & BigInt(255)), @@ -78,15 +82,14 @@ export default class IP { * @return {string} -> 01111111000000000000000000000001 */ toBinary() { - if (this.integer === 0) { + if (this.integer === 0n) { this.toInteger(); } let binary = this.integer.toString(2); - const v = this.version; - const marks = { 4: 32, 6: 128 }; + const markLen = this.version === 4 ? 32 : 128; - if (binary.length < marks[v]) { - while (binary.length < marks[v]) { + if (binary.length < markLen) { + while (binary.length < markLen) { binary = `0${binary}`; } } @@ -98,7 +101,7 @@ export default class IP { * @return {string} -> 7f000001 */ toHEX() { - if (this.integer === 0) { + if (this.integer === 0n) { this.toInteger(); } return this.integer.toString(16); @@ -109,7 +112,7 @@ export default class IP { * IP('127.1.0.0').toCompressed * @return {string} -> "127.1" */ - toCompressed(addr, ver) { + toCompressed(addr: string, ver: number) { if (ver === 4) { const splittedAddr = addr.split('.'); const sRange = [[1, 3], [2, 2], [3, 1], [0, 0]]; @@ -132,11 +135,11 @@ export default class IP { // '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, ''); + splitted.splice(Number(startOfLongest), Number(longestLength), ''); if (startOfLongest === 0) { splitted.unshift(''); } - if (startOfLongest + longestLength === 8) { + if (Number(startOfLongest) + Number(longestLength) === 8) { splitted.push(''); } } @@ -172,7 +175,7 @@ export default class IP { * @param {string} addr * @return {number} -> 4 or 6 */ - _checkVersion(addr) { + _checkVersion(addr: string) { // matches all possible chars in both versions of IP const reGen = /^[0-9a-f.:]+$/i; if (reGen.test(addr)) { @@ -184,14 +187,14 @@ export default class IP { const reNum = /^[0-9]+$/; if (reNum.test(addr)) { - addr = BigInt(addr); - if (addr > IPv6MAX || addr <= 0) { + 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 (addr <= IPv4MAX) { + else if (parsedAddr <= IPv4MAX) { return 4; } - else if (addr > IPv4MAX) { + else if (parsedAddr > IPv4MAX) { return 6; } } @@ -210,18 +213,14 @@ export default class IP { * @private * @return {string} as a valid address */ - _checkAddress(addr, v) { + _checkAddress(addr: string, v: number) { 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]); + const splittedAddr = addr.split(v === 4 ? '.' : ':'); if (v === 6 && splittedAddr.length < 8) { const dbColon = (addr.match(/::/g) || []).length; @@ -230,8 +229,8 @@ export default class IP { } } - if (marks[v][1].call(this, splittedAddr)) { // TODO: make ifs more readable - if (splittedAddr.length === marks[v][2] && this.short === 0) { + 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 { @@ -248,16 +247,16 @@ export default class IP { * @private * @return {boolean} whether splitted address is valid IPv6 or not */ - _isIPv6(splittedAddr) { + _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) { + const isValid = function (hextet: string) { return regex.test(hextet); }; - checked = cleanedAddr.every(isValid); + checked = (cleanedAddr as string[]).every(isValid); if (checked && isShort) { this.short = splittedAddr.join(':'); @@ -274,13 +273,13 @@ export default class IP { * @private * @return {boolean} whether splitted address is valid IPv4 or not */ - _isIPv4(splittedAddr) { + _isIPv4(splittedAddr: string[]) { if (splittedAddr.length <= 4) { if (splittedAddr.length < 4) { this.short = splittedAddr.join('.'); } - const isValid = function (octet) { - return (!!((octet <= 255 && octet >= 0))); + const isValid = function (octet: string) { + return (!!((Number(octet) <= 255 && Number(octet) >= 0))); }; return splittedAddr.every(isValid); } @@ -295,7 +294,7 @@ export default class IP { * @param {array} splittedAddr * @return {array} with both results boolean and cleaned array */ - _isShort(splittedAddr) { + _isShort(splittedAddr: string[]) { let isShort = false; const cleanedAddr = [...splittedAddr]; for (let i = 0; i < cleanedAddr.length; i++) { @@ -320,7 +319,7 @@ export default class IP { * @param {array} splittedAddr * @return {string} -> "0000:0000:0000:0000:0000:0000:0000:0001" */ - _toRepresentation(splittedAddr) { + _toRepresentation(splittedAddr: string[]) { if (this.version === 4) { for (let i = 0; i <= 4; i++) { if (splittedAddr[i] === '') { @@ -383,7 +382,7 @@ export default class IP { * @param {array} zeros * @return {array} -> [0, 7] */ -function _longestZerosGroup(splittedAddr) { +function _longestZerosGroup(splittedAddr: string[]) { let curr = 0; let currLongest = 0; let startOfLongest = 0; 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.js b/src/libs/ip_calculator/network.ts similarity index 67% rename from src/libs/ip_calculator/network.js rename to src/libs/ip_calculator/network.ts index 5f46a61b..9ffcdc74 100644 --- a/src/libs/ip_calculator/network.js +++ b/src/libs/ip_calculator/network.ts @@ -1,62 +1,16 @@ -import IP from './ip.js'; +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([ - ['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']], -]); +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([ - ['::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']], -]); +const _ipv6Registry = new Map(ipv6registry.map(v => [v[0] as string, v[1]])); /** * Network slice calculations. @@ -68,11 +22,12 @@ const _ipv6Registry = new Map([ */ 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, prefix) { + constructor(address: string, prefix: number) { super(address); this.prefix = this._checkPrefix(prefix); } @@ -84,7 +39,7 @@ export default class Network extends IP { * @private * @return {integer} -> prefix: 25n */ - _checkPrefix(prefix) { + _checkPrefix(prefix: number) { if (this.version === 4) { if (prefix > 0 && prefix <= 32) { return BigInt(prefix); @@ -105,10 +60,9 @@ export default class Network extends IP { * @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]); + 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]); } @@ -230,7 +184,7 @@ export default class Network extends IP { * @param {number} prefix * @return {boolean} */ - contains(thisIP, otherIP, prefix) { + contains(thisIP: string, otherIP: string, prefix: number) { const other = new Network(otherIP, prefix); const thisNetwork = this.networkToInteger(); const otherNetwork = other.networkToInteger(); @@ -257,12 +211,19 @@ export default class Network extends IP { * @return {number} -> 16777214 */ networkSize() { - const marks = { 4: BigInt(32), 6: BigInt(128) }; - const size = BigInt(2) ** (marks[this.version] - this.prefix); + 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() : ''; + } } diff --git a/src/tools/index.ts b/src/tools/index.ts index aa861c93..05ecc090 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -6,6 +6,7 @@ import { tool as asciiTextDrawer } from './ascii-text-drawer'; import { tool as textToUnicode } from './text-to-unicode'; import { tool as safelinkDecoder } from './safelink-decoder'; +import { tool as ipv6SubnetCalculator } from './ipv6-subnet-calculator'; import { tool as pdfSignatureChecker } from './pdf-signature-checker'; import { tool as numeronymGenerator } from './numeronym-generator'; import { tool as macAddressGenerator } from './mac-address-generator'; @@ -152,7 +153,15 @@ export const toolsByCategory: ToolCategory[] = [ }, { name: 'Network', - components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator], + components: [ + ipv4SubnetCalculator, + ipv6SubnetCalculator, + ipv4AddressConverter, + ipv4RangeExpander, + macAddressLookup, + macAddressGenerator, + ipv6UlaGenerator, + ], }, { name: 'Math', diff --git a/src/tools/ipv6-subnet-calculator/index.ts b/src/tools/ipv6-subnet-calculator/index.ts new file mode 100644 index 00000000..16db73bb --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/index.ts @@ -0,0 +1,12 @@ +import { RouterOutlined } from '@vicons/material'; +import { defineTool } from '../tool'; + +export const tool = defineTool({ + name: 'Ipv6 subnet calculator', + path: '/ipv6-subnet-calculator', + description: 'Parse your IPv6 CIDR blocks and get all the info you need about your sub network.', + keywords: ['ipv6', 'subnet', 'calculator', 'mask', 'network', 'cidr', 'netmask', 'bitmask', 'broadcast', 'address'], + component: () => import('./ipv6-subnet-calculator.vue'), + icon: RouterOutlined, + createdAt: new Date('2024-02-25'), +}); diff --git a/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue new file mode 100644 index 00000000..e9f1c660 --- /dev/null +++ b/src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue @@ -0,0 +1,126 @@ + + +