diff --git a/components.d.ts b/components.d.ts
index f2c3146f..ea319331 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -117,6 +117,7 @@ declare module '@vue/runtime-core' {
ListConverter: typeof import('./src/tools/list-converter/list-converter.vue')['default']
LocaleSelector: typeof import('./src/modules/i18n/components/locale-selector.vue')['default']
LoremIpsumGenerator: typeof import('./src/tools/lorem-ipsum-generator/lorem-ipsum-generator.vue')['default']
+ MacAddressConverter: typeof import('./src/tools/mac-address-converter/mac-address-converter.vue')['default']
MacAddressGenerator: typeof import('./src/tools/mac-address-generator/mac-address-generator.vue')['default']
MacAddressLookup: typeof import('./src/tools/mac-address-lookup/mac-address-lookup.vue')['default']
MathEvaluator: typeof import('./src/tools/math-evaluator/math-evaluator.vue')['default']
diff --git a/src/tools/index.ts b/src/tools/index.ts
index aa861c93..ebf49f55 100644
--- a/src/tools/index.ts
+++ b/src/tools/index.ts
@@ -1,9 +1,8 @@
import { tool as base64FileConverter } from './base64-file-converter';
import { tool as base64StringConverter } from './base64-string-converter';
import { tool as basicAuthGenerator } from './basic-auth-generator';
-
+import { tool as macAddressConverter } from './mac-address-converter';
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 pdfSignatureChecker } from './pdf-signature-checker';
@@ -152,7 +151,15 @@ export const toolsByCategory: ToolCategory[] = [
},
{
name: 'Network',
- components: [ipv4SubnetCalculator, ipv4AddressConverter, ipv4RangeExpander, macAddressLookup, macAddressGenerator, ipv6UlaGenerator],
+ components: [
+ ipv4SubnetCalculator,
+ ipv4AddressConverter,
+ ipv4RangeExpander,
+ macAddressLookup,
+ macAddressGenerator,
+ macAddressConverter,
+ ipv6UlaGenerator,
+ ],
},
{
name: 'Math',
diff --git a/src/tools/mac-address-converter/index.ts b/src/tools/mac-address-converter/index.ts
new file mode 100644
index 00000000..fa971345
--- /dev/null
+++ b/src/tools/mac-address-converter/index.ts
@@ -0,0 +1,20 @@
+import { Devices } from '@vicons/tabler';
+import { defineTool } from '../tool';
+
+export const tool = defineTool({
+ name: 'MAC Address Converter',
+ path: '/mac-address-converter',
+ description: 'Change the format of a MAC address and chose between different formats (EUI-48, EUI-64, IPv6)',
+ keywords: [
+ 'converter',
+ 'mac',
+ 'address',
+ 'format',
+ 'link-local',
+ 'ipv6',
+ 'eui-48',
+ 'eui-64',
+ ],
+ component: () => import('./mac-address-converter.vue'),
+ icon: Devices,
+});
diff --git a/src/tools/mac-address-converter/mac-address-converter.service.test.ts b/src/tools/mac-address-converter/mac-address-converter.service.test.ts
new file mode 100644
index 00000000..f449d6c6
--- /dev/null
+++ b/src/tools/mac-address-converter/mac-address-converter.service.test.ts
@@ -0,0 +1,30 @@
+import { describe, expect, it } from 'vitest';
+import {
+ convertMacCISCO, convertMacCanonical,
+ convertMacCanonicalIEEE, convertMacCanonicalIETF,
+ convertMacToEUI64CISCO, convertMacToEUI64CanonicalIEEE,
+ convertMacToEUI64CanonicalIETF, convertMacToLinkLocalIPv6,
+ convertMacToNumber,
+} from './mac-address-converter.service';
+
+describe('mac-address-converter', () => {
+ it('Convert MAC Address to given format', async () => {
+ expect(convertMacCanonical('')).to.equal('');
+
+ const macValue = '00:0a:95:9d:68:16';
+
+ expect(convertMacCanonicalIETF(macValue)).to.equal('00:0a:95:9d:68:16');
+ expect(convertMacCanonical(macValue)).to.equal('00.0a.95.9d.68.16');
+ expect(convertMacCanonicalIEEE(macValue)).to.equal('00-0A-95-9D-68-16');
+ expect(convertMacCISCO(macValue)).to.equal('000a.959d.6816');
+
+ expect(convertMacToEUI64CanonicalIETF(macValue, true)).to.equal('02:0a:95:ff:fe:9d:68:16'); // NOSONAR
+ expect(convertMacToEUI64CanonicalIETF(macValue, false)).to.equal('00:0a:95:ff:fe:9d:68:16'); // NOSONAR
+ expect(convertMacToEUI64CanonicalIEEE(macValue, true)).to.equal('02-0A-95-FF-FE-9D-68-16');
+ expect(convertMacToEUI64CanonicalIEEE(macValue, false)).to.equal('00-0A-95-FF-FE-9D-68-16');
+ expect(convertMacToEUI64CISCO(macValue, true)).to.equal('020a.95ff.fe9d.6816');
+ expect(convertMacToEUI64CISCO(macValue, false)).to.equal('000a.95ff.fe9d.6816');
+ expect(convertMacToNumber(macValue)).to.equal(45459793942);
+ expect(convertMacToLinkLocalIPv6(macValue)).to.equal(':fe80::20a:95ff:fe9d:6816');
+ });
+});
diff --git a/src/tools/mac-address-converter/mac-address-converter.service.ts b/src/tools/mac-address-converter/mac-address-converter.service.ts
new file mode 100644
index 00000000..3783126d
--- /dev/null
+++ b/src/tools/mac-address-converter/mac-address-converter.service.ts
@@ -0,0 +1,59 @@
+function convertMac(mac: string, group: number = 2, char: string = ':'): string {
+ mac = mac.replace(/[\W_]+/g, '');
+ return mac.match(new RegExp(`.{1,${group}}`, 'g'))?.join(char) || '';
+}
+
+function convertMacToEUI64(mac: string, ipv6: boolean) {
+ const macIETF = convertMac(mac);
+ // Split the MAC address into an array of hex values
+ const macArray = macIETF.split(':').map(hex => Number.parseInt(hex, 16));
+
+ // For IPv6, invert the 7th bit of the first byte
+ if (ipv6) {
+ macArray[0] ^= 0x02;
+ }
+
+ // Insert FFFE in the middle
+ const eui64Array = [
+ macArray[0], macArray[1], macArray[2],
+ 0xFF, 0xFE,
+ macArray[3], macArray[4], macArray[5],
+ ];
+
+ // Convert the array to a colon-separated string
+ const eui64 = eui64Array.map(byte => byte.toString(16).padStart(2, '0')).join(':');
+
+ // Group into IPv6 EUI-64 format (XXXX:XXFF:FEXX:XXXX)
+ return eui64.replace(/:/g, '').match(/.{1,4}/g)!.join(':');
+}
+
+export function convertMacToEUI64CanonicalIETF(mac: string, ipv6: boolean) {
+ return convertMac(convertMacToEUI64(mac, ipv6).toLocaleLowerCase());
+}
+export function convertMacToEUI64CanonicalIEEE(mac: string, ipv6: boolean) {
+ return convertMac(convertMacToEUI64(mac, ipv6).toLocaleUpperCase(), 2, '-');
+}
+export function convertMacToEUI64CISCO(mac: string, ipv6: boolean) {
+ return convertMac(convertMacToEUI64(mac, ipv6).toLocaleLowerCase(), 4, '.');
+}
+export function convertMacToLinkLocalIPv6(mac: string) {
+ return `:fe80::${convertMac(convertMacToEUI64(mac, true).toLocaleLowerCase(), 4, ':').replace(/^0/g, '')}`;
+}
+
+export function convertMacToNumber(mac: string) {
+ mac = mac.replace(/[\W_]+/g, '');
+ return Number.parseInt(mac, 16);
+}
+
+export function convertMacCanonicalIETF(mac: string): string {
+ return convertMac(mac.toLocaleLowerCase());
+};
+export function convertMacCanonical(mac: string): string {
+ return convertMac(mac, 2, '.');
+};
+export function convertMacCanonicalIEEE(mac: string): string {
+ return convertMac(mac.toLocaleUpperCase(), 2, '-');
+};
+export function convertMacCISCO(mac: string): string {
+ return convertMac(mac.toLocaleLowerCase(), 4, '.');
+};
diff --git a/src/tools/mac-address-converter/mac-address-converter.vue b/src/tools/mac-address-converter/mac-address-converter.vue
new file mode 100644
index 00000000..4e49c9d5
--- /dev/null
+++ b/src/tools/mac-address-converter/mac-address-converter.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+