Last active
July 2, 2021 09:43
-
-
Save ncruces/ad0a7f303f8714b152d7f3d184f0956a to your computer and use it in GitHub Desktop.
Parse IPv6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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