mirror of
https://github.com/CorentinTh/it-tools.git
synced 2025-05-05 05:47:10 -04:00
feat(new tool): IPv6 Subnet Calculator
IPv6 Subnet Calculator Fix #354 and #924
This commit is contained in:
parent
d7a8c65067
commit
1f67ba15e9
10 changed files with 285 additions and 111 deletions
12
components.d.ts
vendored
12
components.d.ts
vendored
|
@ -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']
|
||||
|
|
|
@ -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",
|
||||
|
|
34
pnpm-lock.yaml
generated
34
pnpm-lock.yaml
generated
|
@ -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
|
||||
|
|
|
@ -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;
|
26
src/libs/ip_calculator/ipv4registry.json
Normal file
26
src/libs/ip_calculator/ipv4registry.json
Normal file
|
@ -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"]]
|
||||
]
|
24
src/libs/ip_calculator/ipv6registry.json
Normal file
24
src/libs/ip_calculator/ipv6registry.json
Normal file
|
@ -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"]]
|
||||
]
|
|
@ -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() : '';
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
|
|
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
12
src/tools/ipv6-subnet-calculator/index.ts
Normal file
|
@ -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'),
|
||||
});
|
126
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
126
src/tools/ipv6-subnet-calculator/ipv6-subnet-calculator.vue
Normal file
|
@ -0,0 +1,126 @@
|
|||
<script setup lang="ts">
|
||||
import isCidr from 'is-cidr';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import Network from '@/libs/ip_calculator/network';
|
||||
import { withDefaultOnError } from '@/utils/defaults';
|
||||
import SpanCopyable from '@/components/SpanCopyable.vue';
|
||||
|
||||
const ip = useStorage('ipv6-subnet-calculator:ip', '2001:db8:0:85a3:0:0:ac1f:8001/32');
|
||||
|
||||
function getNetworkInfo(address: string) {
|
||||
const [ip, mask] = address.split('/');
|
||||
return new Network(ip.trim(), Number(mask?.trim() || '32'));
|
||||
}
|
||||
|
||||
const networkInfo = computed(() => withDefaultOnError(() =>
|
||||
isCidr(ip.value.trim()) === 6 ? getNetworkInfo(ip.value) : undefined, undefined));
|
||||
|
||||
const ipValidationRules = [
|
||||
{
|
||||
message: 'We cannot parse this address, check the format',
|
||||
validator: (value: string) => isCidr(value.trim()) === 6,
|
||||
},
|
||||
];
|
||||
|
||||
const sections: {
|
||||
label: string
|
||||
getValue: (net: Network) => string | undefined
|
||||
undefinedFallback?: string
|
||||
}[] = [
|
||||
{
|
||||
label: 'Full address',
|
||||
getValue: net => net.address.toString(),
|
||||
},
|
||||
{
|
||||
label: 'Short address',
|
||||
getValue: net => net.toCompressed(net.address || '', net.version || 4)?.toString(),
|
||||
},
|
||||
{
|
||||
label: 'Address as binary',
|
||||
getValue: (net) => {
|
||||
const binary = net.toBinary();
|
||||
const hBin = binary.length / 2;
|
||||
return `${binary.substring(0, hBin)} ${
|
||||
binary.substring(hBin, binary.length)}`;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Address as integer',
|
||||
getValue: net => net.toInteger().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Address as hex',
|
||||
getValue: net => net.toHEX().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network address',
|
||||
getValue: net => net.getNetwork().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network address as integer',
|
||||
getValue: net => net.networkToInteger().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network mask size',
|
||||
getValue: net => net.prefix.toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network mask',
|
||||
getValue: net => net.getMask().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network mask as integer',
|
||||
getValue: net => net.maskToInteger().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Network size',
|
||||
getValue: net => net.networkSize().toString(),
|
||||
},
|
||||
{
|
||||
label: 'Networks count',
|
||||
getValue: net => net.networkCount().toString(),
|
||||
},
|
||||
{
|
||||
label: 'First address',
|
||||
getValue: net => net.hostRange()[0],
|
||||
},
|
||||
{
|
||||
label: 'Last address',
|
||||
getValue: net => net.hostRange()[1],
|
||||
},
|
||||
{
|
||||
label: 'Type',
|
||||
getValue: net => net.printInfo()?.toString(),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<c-input-text
|
||||
v-model:value="ip"
|
||||
label="An IPv6 address with or without mask"
|
||||
placeholder="The ipv6 address..."
|
||||
:validation-rules="ipValidationRules"
|
||||
mb-4
|
||||
/>
|
||||
|
||||
<div v-if="networkInfo">
|
||||
<n-table>
|
||||
<tbody>
|
||||
<tr v-for="{ getValue, label, undefinedFallback } in sections" :key="label">
|
||||
<td font-bold>
|
||||
{{ label }}
|
||||
</td>
|
||||
<td>
|
||||
<SpanCopyable v-if="networkInfo" :value="getValue(networkInfo)" />
|
||||
<span v-else op-70>
|
||||
{{ undefinedFallback }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
Loading…
Add table
Add a link
Reference in a new issue