#   # IPv6 Mask / Prefix Conversion

## Functions to convert and validate IPv6 Mask

In our SDWAN solution, I have just started to implement IPv6 Support for the upcoming release. For all IP validations I'm using ip-address.js NPM library, however it doesn't have all the functionalities.

So I had to extend it and build our own NPM library so that it could be consumed by our products.

One of the main functionality which was missing was prefix - mask conversion and validation. As usual, I googled it, Unfortunately I didn't find any solution. So I had to implement it on my own and i thought it could be useful for the community.

Input will be a number between 0 and 128 and the function should return the corresponding IPv6 Mask.

#### Explanation:

1. Create a 128 bit binary string
2. Fill the first n (prefix) bits with 1s and the remaining with 0s.
3. Chunk them with a size of 16 bits each
4. Convert each chuck to a hex value and join them with (:)

For Example: `118 => 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00'`

``````
const HEX = 16;
const BINARY = 2;
const MAX_PREFIX = 128;
const MIN_PREFIX = 0;

static isValidPrefix(prefix: number): boolean {
return Number.isInteger(prefix) && prefix >= MIN_PREFIX && prefix <= MAX_PREFIX;
}
/**
*
* @param prefix
*
* Fill an array with 1s for given number of prefix bits
* Fill the remaining bits with 0s
* chunk it with 16 elements and covert each chunk to hex
*
*/
if (!IPV6.isValidPrefix(prefix)) {
throw new TypeError('Invalid IPv6 Prefix');
}

const prefixArr: number[] = new Array(prefix).fill(1);
const chunkArr = Array.from({
length: Math.ceil(prefixArr.length / HEX),
}, (_v, i) => prefixArr.slice(i * HEX, i * HEX + HEX));

// Converting from binary to hex
let subnet = chunkArr.map((item) => {
}).join(':');

if (subnet.length < 35) {
subnet = `\${subnet}::`;
}

}
``````

This is the opposite of the previous function. With a given mask it should return the corresponding prefix.

Ex: `expect(IPV6.getPrefixForNetmask('ffff:ffff:ffff:ffff:ffff:fffc:0000:0000')).toBe(94);`

#### Explanation:

1. Convert the mask to binary using `ip-address.js` function.
2. Count the number of 1's and return the count as result.
``````
/**
*
* @returns {number} prefix
*
* Returns exception if its an invalid mask
*/

}

}
``````

But before attempting to get the prefix out of the mask, we also need to check whether it is a valid mask, else it might return the wrong results.

Ideally, a valid mask can have a maximum of one flip bit in it and starts with 1 with trailing 0s or starts with 0 and no trailing 1s.

Example: 1100 => valid // starts with 1 with trailing 0s 0000 => valid // with 0 and no trailing 1s 1010 => Invalid 0001 => Invalid

#### Explanation:

1. Convert the mask to binary string
2. Iterate through each bit to count the flips.
3. If the count is more than 1, then it's not a valid mask.
``````
try {
let flips = 0;
let oldBit = '1';

for (let i = 0; i < bits.length; i++) {
if (oldBit !== bits.charAt(i)) {
flips += 1;
oldBit = bits.charAt(i);
}

if (flips > 1) {
return false;
}
}

return flips <= 1;
} catch (e) {
return false;
}
}
``````

### Bonus : Random IPv6 Address Generator ( used for testing)

Sometimes I needed a random IPv6 address for testing.

#### Explanation:

1. Create 7 * 4 chars chunks of individual sets with `Math.random()` and valid characters from IPv6 char set [0-9][a-f].
2. Append them with the given prefix and join it with the colon(:).
``````
/**
*
* @param ipPrefix defaults to 2000:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
* @returns a random IPv6 address with the given prefix
*/
static generateRandomIPv6Address(ipPrefix = '2000'): string {
const items = '0123456789abcdef'.split('');
const randomised = [];

for (let i = 0; i < 28; i++) {
randomised[i] = items[Math.floor(Math.random() * items.length)];
}

const ipBlock: string[][] = [];

for (let i = 0; i < randomised.length; i++) {
const blockIndex = Math.floor(i / 4);

if (!Array.isArray(ipBlock[blockIndex])) {
ipBlock.push([]);
}

if (!(ipBlock[blockIndex].length === 0) || randomised[i] !== '0') {
ipBlock[blockIndex].push(randomised[i]);
}
}

const ip: string[][] = [];

for (let i = 0; i < ipBlock.length; i++) {
const ipIndex = Math.floor(i / 8);

if (!Array.isArray(ip[ipIndex])) {
ip.push([]);
}

ip[ipIndex].push(ipBlock[i].join(''));
}

let suffixIp = '';

for (let i = 0; i < ip.length; i++) {
suffixIp += ip[i].join(':');
}

return `\${ipPrefix}:\${suffixIp}`;
}
``````