Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate an IPv6 address using a combination of RegEx and code?

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.

like image 846
Gili Avatar asked Jan 03 '17 03:01

Gili


People also ask

How do I check if my IPv6 address is valid?

A valid IPv6 address is an IP in the form “x1 : x2 : x3 : x4 : x5 : x6 : x7 : x8” where: 1 ≤ xi. length ≤ 4. xi is a hexadecimal string which may contain digits, lower-case English letter ('a' to 'f') and upper-case English letters ('A' to 'F').

How do I match IPv6 address?

Match an IPv6 address in standard notation, which consists of eight 16-bit words using hexadecimal notation, delimited by colons (e.g.: 1762:0:0:0:0:B03:1:AF18 ). Leading zeros are optional.

What is an example of a valid IPv6 address?

The following list shows examples of valid IPv6 (Normal) addresses: 2001 : db8: 3333 : 4444 : 5555 : 6666 : 7777 : 8888. 2001 : db8 : 3333 : 4444 : CCCC : DDDD : EEEE : FFFF. : : (implies all 8 segments are zero)


2 Answers

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'));
like image 81
Gili Avatar answered Sep 29 '22 14:09

Gili


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'));
like image 35
Brandon Avatar answered Sep 29 '22 13:09

Brandon