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
This commit is contained in:
sharevb 2024-04-03 23:36:17 +02:00
parent 23f82d956a
commit 070ec0b36e
7 changed files with 806 additions and 0 deletions

2
components.d.ts vendored
View file

@ -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']

View file

@ -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'];
}

View 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"]]
]

View 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"]]
]

View file

@ -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() : '';
}
}

View file

@ -1,12 +1,15 @@
<script setup lang="ts">
import { convertBase } from '../integer-base-converter/integer-base-converter.model';
import { getIPClass } from '../ipv4-subnet-calculator/ipv4-subnet-calculator.models';
import { ipv4ToInt, ipv4ToIpv6, isValidIpv4 } from './ipv4-address-converter.service';
import { useValidation } from '@/composable/validation';
import Network from '@/libs/ip_calculator/network';
const rawIpAddress = useStorage('ipv4-converter:ip', '192.168.1.1');
const convertedSections = computed(() => {
const ipInDecimal = ipv4ToInt({ ip: rawIpAddress.value });
const networkInfo = new Network(rawIpAddress.value || '', 32);
return [
{
@ -29,6 +32,30 @@ const convertedSections = computed(() => {
label: 'Ipv6 (short): ',
value: ipv4ToIpv6({ ip: rawIpAddress.value, prefix: '::ffff:' }),
},
{
label: 'Ipv6 (decimal): ',
value: networkInfo.toIPv4MappedAddressDecimal()?.toString() || '',
},
{
label: '6to4 prefix',
value: networkInfo.to6to4Prefix()?.toString() || '',
},
{
label: 'CIDR notation',
value: `${rawIpAddress.value}/32`,
},
{
label: 'ARPA',
value: networkInfo.toARPA()?.toString() || '',
},
{
label: 'IP class',
value: getIPClass({ ip: rawIpAddress.value }),
},
{
label: 'Type',
value: networkInfo.printInfo()?.toString() || '',
},
];
});

View file

@ -5,6 +5,7 @@ import { ArrowLeft, ArrowRight } from '@vicons/tabler';
import { getIPClass } from './ipv4-subnet-calculator.models';
import { withDefaultOnError } from '@/utils/defaults';
import { isNotThrowing } from '@/utils/boolean';
import Network from '@/libs/ip_calculator/network';
import SpanCopyable from '@/components/SpanCopyable.vue';
const ip = useStorage('ipv4-subnet-calculator:ip', '192.168.0.1/24');
@ -12,6 +13,7 @@ const ip = useStorage('ipv4-subnet-calculator:ip', '192.168.0.1/24');
const getNetworkInfo = (address: string) => new Netmask(address.trim());
const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined));
const networkOtherInfo = computed(() => withDefaultOnError(() => new Network(networkInfo.value?.base || '', networkInfo.value?.bitmask || 32), undefined));
const ipValidationRules = [
{
@ -53,6 +55,10 @@ const sections: {
label: 'Network size',
getValue: ({ size }) => String(size),
},
{
label: 'Subnets count',
getValue: () => networkOtherInfo.value?.networkCount()?.toString() || '',
},
{
label: 'First address',
getValue: ({ first }) => first,
@ -66,11 +72,31 @@ const sections: {
getValue: ({ broadcast }) => broadcast,
undefinedFallback: 'No broadcast address with this mask',
},
{
label: 'ARPA',
getValue: () => networkOtherInfo.value?.toARPA()?.toString() || '',
},
{
label: 'IPv4 Mapped Address',
getValue: () => networkOtherInfo.value?.toIPv4MappedAddress()?.toString() || '',
},
{
label: 'IPv4 Mapped Address (decimal)',
getValue: () => networkOtherInfo.value?.toIPv4MappedAddressDecimal()?.toString() || '',
},
{
label: '6to4 prefix',
getValue: () => networkOtherInfo.value?.to6to4Prefix()?.toString() || '',
},
{
label: 'IP class',
getValue: ({ base: ip }) => getIPClass({ ip }),
undefinedFallback: 'Unknown class type',
},
{
label: 'Type',
getValue: ({ base: ip, bitmask }) => withDefaultOnError(() => (new Network(ip, bitmask)).printInfo()?.toString() || '', ''),
},
];
function switchToBlock({ count = 1 }: { count?: number }) {