From 3bc871c02b386392c56e7e81e9f1a2b6bc23a0c4 Mon Sep 17 00:00:00 2001 From: Arcath Date: Tue, 26 Jul 2022 21:37:20 +0100 Subject: [PATCH] feat: add parseCDIR function --- src/functions/network.spec.ts | 27 +++++++++ src/functions/network.ts | 106 ++++++++++++++++++++++++++++++++++ src/index.ts | 1 + 3 files changed, 134 insertions(+) create mode 100644 src/functions/network.spec.ts create mode 100644 src/functions/network.ts diff --git a/src/functions/network.spec.ts b/src/functions/network.spec.ts new file mode 100644 index 0000000..3cce6d0 --- /dev/null +++ b/src/functions/network.spec.ts @@ -0,0 +1,27 @@ +import {parseCDIR} from '../index' + +describe('Network', () => { + it('should parse', () => { + const ip = parseCDIR('10.20.30.40/24') + + expect(ip.ip).toBe('10.20.30.40') + expect(ip.bitmask).toBe('24') + expect(ip.binary).toBe('00001010000101000001111000101000') + expect(ip.binaryMask).toBe('11111111111111111111111100000000') + expect(ip.binaryNetwork).toBe('00001010000101000001111000000000') + expect(ip.network).toBe('10.20.30.0') + expect(ip.mask).toBe('255.255.255.0') + expect(ip.binaryBroadcast).toBe('00001010000101000001111011111111') + expect(ip.broadcast).toBe('10.20.30.255') + expect(ip.first).toBe('10.20.30.1') + expect(ip.last).toBe('10.20.30.254') + expect(ip.size).toBe(254) + + const smallNetwork = parseCDIR('192.168.1.30/29') + + expect(smallNetwork.mask).toBe('255.255.255.248') + expect(smallNetwork.network).toBe('192.168.1.24') + expect(smallNetwork.broadcast).toBe('192.168.1.31') + expect(smallNetwork.size).toBe(6) + }) +}) diff --git a/src/functions/network.ts b/src/functions/network.ts new file mode 100644 index 0000000..49fc0b5 --- /dev/null +++ b/src/functions/network.ts @@ -0,0 +1,106 @@ +const binaryToIp = (binaryIp: string) => { + const blocks = [ + binaryIp.substring(0, 8), + binaryIp.substring(8, 16), + binaryIp.substring(16, 24), + binaryIp.substring(24, 32) + ] + + return blocks + .map(block => { + return parseInt(block, 2) + }) + .join('.') +} + +interface CIDRObject { + /** The IP as a binary string */ + binary: string + /** The broadcast address of the network as a binary string */ + binaryBroadcast: string + /** The network mask as a binary string */ + binaryMask: string + /** The network assdress as a binary string */ + binaryNetwork: string + /** The CDIR bitmask */ + bitmask: string + /** The boardcast address as an IP */ + broadcast: string + /** The first IP in the network */ + first: string + /** The ip */ + ip: string + /** The last IP in the network */ + last: string + /** The netmask as an IP */ + mask: string + /** The network IP */ + network: string + /** The number of usable hosts in the network */ + size: number +} + +/** + * Parse an IP in CDIR notation + * + * @param cdir An IP in CDIR notation e.g. 10.20.30.40/24 + * @returns An instance of `CDIRObject` + */ +export const parseCDIR = (cdir: string): CIDRObject => { + const [ip, bitmask] = cdir.split('/') + + const binary = ip + .split('.') + .map(block => { + return parseInt(block, 10).toString(2).padStart(8, '0') + }) + .join('') + + const binaryMask = ''.padStart(parseInt(bitmask, 10), '1').padEnd(32, '0') + + const binaryNetwork = binary + .split('') + .map((bit, i) => { + if (binaryMask[i] === '1') { + return bit + } + + return '0' + }) + .join('') + + const binaryBroadcast = binary + .split('') + .map((bit, i) => { + if (binaryMask[i] === '1') { + return bit + } + + return '1' + }) + .join('') + + const broadcast = binaryToIp(binaryBroadcast) + const network = binaryToIp(binaryNetwork) + const mask = binaryToIp(binaryMask) + + const first = binaryToIp(binaryNetwork.replace(/0$/, '1')) + const last = binaryToIp(binaryBroadcast.replace(/1$/, '0')) + + const size = parseInt(binaryBroadcast, 2) - parseInt(binaryNetwork, 2) - 1 + + return { + binary, + binaryBroadcast, + binaryMask, + binaryNetwork, + bitmask, + broadcast, + first, + ip, + last, + mask, + network, + size + } +} diff --git a/src/index.ts b/src/index.ts index 95b5875..1f5d230 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,6 +42,7 @@ export { } from './functions/increment' export {indexedBy, IndexedArray, IndexedByOptions} from './functions/indexed-by' export {keys} from './functions/keys' +export {parseCDIR} from './functions/network' export {mapProperty} from './functions/map-property' export {rangeAsString, rangeAsArray} from './functions/range-as-string' export {