Skip to content

Commit 709fed7

Browse files
committed
Merge branch 'feat/ipv6-subnet-calculator' into chore/all-my-stuffs
# Conflicts: # components.d.ts # package.json # pnpm-lock.yaml # src/tools/index.ts # src/utils/ip.test.ts
2 parents b3969d3 + 700d835 commit 709fed7

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,12 @@
187187
"ip-regex": "^5.0.0",
188188
"jks-js": "^1.1.3",
189189
"javastack.js": "^1.0.2",
190+
"ip-address": "^9.0.5",
191+
"ip-bigint": "^8.0.2",
192+
"ip-cidr": "^4.0.0",
193+
"ip-matching": "^2.1.2",
194+
"is-cidr": "^5.0.3",
195+
"is-ip": "^5.0.1",
190196
"js-base64": "^3.7.6",
191197
"image-in-browser": "^3.1.0",
192198
"js-base64": "^3.7.7",

src/tools/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ import { tool as ed25519KeyPairGenerator } from './ed25519-key-pair-generator';
117117
import { tool as fileType } from './file-type';
118118
import { tool as htmlCleaner } from './html-cleaner';
119119
import { tool as imageToAsciiArt } from './image-to-ascii-art';
120+
import { tool as ipv6SubnetCalculator } from './ipv6-subnet-calculator';
120121
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
121122
import { tool as numeronymGenerator } from './numeronym-generator';
122123
import { tool as macAddressGenerator } from './mac-address-generator';
@@ -409,6 +410,8 @@ export const toolsByCategory: ToolCategory[] = [
409410
// ipv6AddressConverter,
410411
ipInRange,
411412
ipv6AddressConverter,
413+
ipv6SubnetCalculator,
414+
ipv4AddressConverter,
412415
ipv4RangeExpander,
413416
macAddressLookup,
414417
macAddressGenerator,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { RouterOutlined } from '@vicons/material';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'Ipv6 subnet calculator',
6+
path: '/ipv6-subnet-calculator',
7+
description: 'Parse your IPv6 CIDR blocks and get all the info you need about your sub network.',
8+
keywords: ['ipv6', 'subnet', 'calculator', 'mask', 'network', 'cidr', 'netmask', 'bitmask', 'broadcast', 'address'],
9+
component: () => import('./ipv6-subnet-calculator.vue'),
10+
icon: RouterOutlined,
11+
createdAt: new Date('2024-02-25'),
12+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<script setup lang="ts">
2+
import { useStorage } from '@vueuse/core';
3+
import { Address6 } from 'ip-address';
4+
import { getIPNetworkType, parseAsCIDR } from '@/utils/ip';
5+
import { withDefaultOnError } from '@/utils/defaults';
6+
import SpanCopyable from '@/components/SpanCopyable.vue';
7+
import { isNotThrowing } from '@/utils/boolean';
8+
9+
const ip = useStorage('ipv6-subnet-calculator:ip', '2001:db8:0:85a3:0:0:ac1f:8001/32'); // NOSONAR
10+
11+
const getNetworkInfo = (address: string) => new Address6(parseAsCIDR(address.trim()) || address.trim());
12+
const networkInfo = computed(() => withDefaultOnError(() => getNetworkInfo(ip.value), undefined));
13+
14+
const ipValidationRules = [
15+
{
16+
message: 'We cannot parse this address, check the format',
17+
validator: (value: string) => isNotThrowing(() => getNetworkInfo(value)),
18+
},
19+
];
20+
21+
const sections: {
22+
label: string
23+
getValue: (blocks: Address6) => string | undefined
24+
undefinedFallback?: string
25+
}[] = [
26+
{
27+
label: 'Full address',
28+
getValue: (block: Address6) => block.canonicalForm(),
29+
},
30+
{
31+
label: 'Short address',
32+
getValue: (block: Address6) => block.correctForm(),
33+
},
34+
{
35+
label: 'Address as binary',
36+
getValue: (block: Address6) => (block.binaryZeroPad()).match(/.{8}/g)?.join(':') ?? '',
37+
},
38+
{
39+
label: 'Address as integer',
40+
getValue: (block: Address6) => BigInt(`0x${block.getBitsBase16(0, 128)}`).toString(),
41+
},
42+
{
43+
label: 'Address as decimal',
44+
getValue: (block: Address6) => block.decimal(),
45+
},
46+
{
47+
label: 'Address as hex',
48+
getValue: (block: Address6) => (block.getBitsBase16(0, 128)),
49+
},
50+
{
51+
label: 'Network mask size',
52+
getValue: (block: Address6) => block.subnetMask.toString(),
53+
},
54+
{
55+
label: 'Network mask',
56+
getValue: (block: Address6) => BigInt(`0b${'1'.repeat(block.subnetMask).padEnd(128, '0')}`).toString(16).match(/.{4}/g)?.join(':') ?? '',
57+
},
58+
{
59+
label: 'Network mask as integer',
60+
getValue: (block: Address6) => BigInt(`0b${'1'.repeat(block.subnetMask).padEnd(128, '0')}`).toString(),
61+
},
62+
{
63+
label: 'Network mask as binary',
64+
getValue: (block: Address6) => '1'.repeat(block.subnetMask).padEnd(128, '0').match(/.{8}/g)?.join(':') ?? '',
65+
},
66+
{
67+
label: 'Total IP addresses',
68+
getValue: (block: Address6) => {
69+
const totalAddresses = BigInt(2) ** BigInt(128 - block.subnetMask);
70+
return totalAddresses.toString();
71+
},
72+
},
73+
{
74+
label: 'Total networks',
75+
getValue: ({ subnetMask }) => subnetMask <= 64 ? (BigInt(2) ** BigInt(64 - subnetMask)).toString() : '',
76+
},
77+
{
78+
label: 'First address',
79+
getValue: (block: Address6) => block.startAddress().correctForm(),
80+
},
81+
{
82+
label: 'Last address',
83+
getValue: (block: Address6) => block.endAddress().correctForm(),
84+
},
85+
{
86+
label: 'Scope',
87+
getValue: (block: Address6) => block.getScope(),
88+
},
89+
{
90+
label: '6to4 Properties',
91+
getValue: (block: Address6) => JSON.stringify(block.inspect6to4()),
92+
},
93+
{
94+
label: 'Teredo Properties',
95+
getValue: (block: Address6) => JSON.stringify(block.inspectTeredo()),
96+
},
97+
{
98+
label: 'ARPA',
99+
getValue: (block: Address6) => block.reverseForm(),
100+
},
101+
{
102+
label: 'Microsoft UNC Transcription',
103+
getValue: (block: Address6) => block.microsoftTranscription(),
104+
},
105+
{
106+
label: 'Type',
107+
getValue: (block: Address6) => getIPNetworkType(block.correctForm()),
108+
},
109+
];
110+
</script>
111+
112+
<template>
113+
<div w-600>
114+
<c-input-text
115+
v-model:value="ip"
116+
label="An IPv6 address with or without mask"
117+
placeholder="The ipv6 address..."
118+
:validation-rules="ipValidationRules"
119+
mb-4
120+
/>
121+
122+
<div v-if="networkInfo">
123+
<n-table>
124+
<tbody>
125+
<tr v-for="{ getValue, label, undefinedFallback } in sections" :key="label">
126+
<td font-bold>
127+
{{ label }}
128+
</td>
129+
<td>
130+
<SpanCopyable v-if="networkInfo" :value="getValue(networkInfo)" />
131+
<span v-else op-70>
132+
{{ undefinedFallback }}
133+
</span>
134+
</td>
135+
</tr>
136+
</tbody>
137+
</n-table>
138+
</div>
139+
</div>
140+
</template>

0 commit comments

Comments
 (0)