Reputation: 90150
I'd like to validate an IPv6 address using an algorithm that emphasizes readability. The ideal solution combines a dead-simple regular expression with source-code.
Using https://blogs.msdn.microsoft.com/oldnewthing/20060522-08/?p=31113 as an example:
function isDottedIPv4(s)
{
var match = s.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
return match != null &&
match[1] <= 255 && match[2] <= 255 &&
match[3] <= 255 && match[4] <= 255;
}
Notice how Raymond moves the complexity from the regular expression into code. I'd like a solution that does the same for IPv6.
Upvotes: 5
Views: 3196
Reputation: 200
This still may be too complex, but I think it covers most scenarios with IPv6 addresses. I went through something similar recently, it is really hard to replace a huge RegEx for something as complex as IPv6.
function isIPv6(s)
{
// Check if there are more then 2 : together (ex. :::)
if(/:{3,}/.test(s)) return false;
// Check if there are more then 2 :: (ex. ::2001::)
if(/::.+::/.test(s)) return false;
// Check if there is a single : at the end (requires :: if any)
if(/[^:]:$/.test(s)) return false;
// Check for leading colon
if(/^:(?!:)/.test(s)) return false;
// Split all the part to check each
var ipv6_parts = s.split(':');
// Make sure there are at lease 2 parts and no more then 8
if(ipv6_parts.length < 2 || ipv6_parts.length > 8) return false;
var is_valid = true;
// Loop through the parts
ipv6_parts.forEach(function(part) {
// If the part is not blank (ex. ::) it must have no more than 4 digits
if(/^[0-9a-fA-F]{0,4}$/.test(part)) return;
// Fail if none of the above match
is_valid = false;
});
return is_valid;
}
console.log(isIPv6('2001:cdba:0000:0000:0000:0000:3257:9652'));
console.log(isIPv6('2001:cdba:0:0:0:0:3257:9652'));
console.log(isIPv6('2001:cdba::3257:9652'));
console.log(isIPv6('::2001:cdba:3257:9652'));
Upvotes: 1
Reputation: 90150
Here is a variant of Brandon's answer:
/**
* @param {String} a String
* @return {Boolean} true if the String is a valid IPv6 address; false otherwise
*/
function isIPv6(value)
{
// See https://blogs.msdn.microsoft.com/oldnewthing/20060522-08/?p=31113 and
// https://4sysops.com/archives/ipv6-tutorial-part-4-ipv6-address-syntax/
const components = value.split(":");
if (components.length < 2 || components.length > 8)
return false;
if (components[0] !== "" || components[1] !== "")
{
// Address does not begin with a zero compression ("::")
if (!components[0].match(/^[\da-f]{1,4}/i))
{
// Component must contain 1-4 hex characters
return false;
}
}
let numberOfZeroCompressions = 0;
for (let i = 1; i < components.length; ++i)
{
if (components[i] === "")
{
// We're inside a zero compression ("::")
++numberOfZeroCompressions;
if (numberOfZeroCompressions > 1)
{
// Zero compression can only occur once in an address
return false;
}
continue;
}
if (!components[i].match(/^[\da-f]{1,4}/i))
{
// Component must contain 1-4 hex characters
return false;
}
}
return true;
}
console.log('Expecting true...');
console.log(isIPv6('2001:cdba:0000:0000:0000:0000:3257:9652'));
console.log(isIPv6('2001:cdba:0:0:0:0:3257:9652'));
console.log(isIPv6('2001:cdba::3257:9652'));
console.log(isIPv6('2001:cdba::257:9652'));
console.log(isIPv6('2001:DB8:0:2F3B:2AA:FF:FE28:9C5A'));
console.log(isIPv6('::0:2F3B:2AA:FF:FE28:9C5A'));
console.log('\n');
console.log('Expecting false...');
console.log(isIPv6(':0:2F3B:2AA:FF:FE28:9C5A'));
Upvotes: 5