Skip to content

Instantly share code, notes, and snippets.

@ncruces
Last active July 2, 2021 09:43
Show Gist options
  • Save ncruces/ad0a7f303f8714b152d7f3d184f0956a to your computer and use it in GitHub Desktop.
Save ncruces/ad0a7f303f8714b152d7f3d184f0956a to your computer and use it in GitHub Desktop.
Parse IPv6
// https://tools.ietf.org/html/rfc5952
function parseIPv6(addr) {
// does it have an IPv4 suffix
let ipv4 = /^([\s\S]*):(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(addr);
if (ipv4) {
// dot-decimal to ints
let dec = ipv4.slice(2).map(s => parseInt(s, 10));
if (dec.some(i => i > 255)) return null;
// ints to hexs
let hex = dec.map(i => ('0' + i.toString(16)).substr(-2));
// rebuild
addr = ipv4[1] + ':' + hex[0] + hex[1] + ':' + hex[2] + hex[3];
}
// where's the ::, is there a single one?
let ellipsis = addr.indexOf('::');
if (ellipsis !== addr.lastIndexOf('::')) return null;
let groups;
if (ellipsis < 0) {
// must have exactly 8 groups
groups = addr.split(':', 9);
if (groups.length != 8) return null;
} else {
// must have less than 8 groups
let head = [];
let tail = [];
if (ellipsis > 0)
head = addr.slice(0, ellipsis).split(':', 8);
if (ellipsis < addr.length - 2)
tail = addr.slice(ellipsis + 2).split(':', 8);
if (head.length + tail.length > 7) return null;
// fill in ellipsis, concat tail
head.length = 8 - tail.length;
groups = head.concat(tail);
}
// convert to an array of 8 16-bit ints
let ipv6 = [];
for (let i = 0; i < 8; ++i) {
let g = groups[i] || '0';
if (!/^[0-9a-fA-F]{1,4}$/.test(g)) return null;
ipv6.push(parseInt(g, 16));
}
Object.defineProperty(ipv6, 'getByte', {
value: function(i) {
let b = this[i / 2 >>> 0];
return (i & 1) === 0 ? b >>> 8 : b & 0xff;
}
});
Object.defineProperty(ipv6, 'toString', {
value: function() {
// find longest run of zeros
let e0 = -1;
let e1 = -1;
for (let i = 0; i < 8; ++i) {
let j = i;
while (this[j] === 0) ++j;
if (j - i > e1 - e0) {
e0 = i;
e1 = j;
}
if (j > i) i = j;
}
// don't replace single group
if (e1 - e0 <= 1) {
e0 = -1;
e1 = -1;
}
let str = '';
for (let i = 0; i < 8; ++i) {
if (i === e0) {
str += '::';
if (e1 >= 8) break;
i = e1;
} else if (i > 0) {
str += ':';
}
str += this[i].toString(16);
}
return str;
}
});
return ipv6;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment