IPv6 validation

2020-03-01 15:41发布

问题:

I used IPAddressUtil.isIPv6LiteralAddress (ipAddress) method to validate IPv6, but this method fails for ipv6-address/prefix-length format (format is mentioned in RFC 4291 section 2.3) of IPV6.

Could anyone know any validators which validate " ipv6-address/prefix-length " format?

Legal representations of IPV6

  1. ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
  2. 2001:DB8:0:0:8:800:200C:417A
  3. FF01:0:0:0:0:0:0:101
  4. 0:0:0:0:0:0:0:1
  5. 0:0:0:0:0:0:0:0
  6. 2001:DB8::8:800:200C:417A
  7. FF01::101
  8. ::1
  9. ::
  10. 0:0:0:0:0:0:13.1.68.3
  11. 0:0:0:0:0:FFFF:129.144.52.38
  12. ::13.1.68.3
  13. FFFF:129.144.52.38
  14. 2001:0DB8:0000:CD30:0000:0000:0000:0000/60
  15. 2001:0DB8::CD30:0:0:0:0/60
  16. 2001:0DB8:0:CD30::/60

NOT legal representations of IPV6

  1. 2001:0DB8:0:CD3/60
  2. 2001:0DB8::CD30/60
  3. 2001:0DB8::CD3/60

回答1:

See if this works:

try {
    if (subjectString.matches(
        "(?ix)\\A(?:                                                  # Anchor address\n" +
        " (?:  # Mixed\n" +
        "  (?:[A-F0-9]{1,4}:){6}                                # Non-compressed\n" +
        " |(?=(?:[A-F0-9]{0,4}:){2,6}                           # Compressed with 2 to 6 colons\n" +
        "     (?:[0-9]{1,3}\\.){3}[0-9]{1,3}                     #    and 4 bytes\n" +
        "     \\z)                                               #    and anchored\n" +
        "  (([0-9A-F]{1,4}:){1,5}|:)((:[0-9A-F]{1,4}){1,5}:|:)  #    and at most 1 double colon\n" +
        " |::(?:[A-F0-9]{1,4}:){5}                              # Compressed with 7 colons and 5 numbers\n" +
        " )\n" +
        " (?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}  # 255.255.255.\n" +
        " (?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])           # 255\n" +
        "|     # Standard\n" +
        " (?:[A-F0-9]{1,4}:){7}[A-F0-9]{1,4}                    # Standard\n" +
        "|     # Compressed\n" +
        " (?=(?:[A-F0-9]{0,4}:){0,7}[A-F0-9]{0,4}               # Compressed with at most 7 colons\n" +
        "    \\z)                                                #    and anchored\n" +
        " (([0-9A-F]{1,4}:){1,7}|:)((:[0-9A-F]{1,4}){1,7}|:)    #    and at most 1 double colon\n" +
        "|(?:[A-F0-9]{1,4}:){7}:|:(:[A-F0-9]{1,4}){7}           # Compressed with 8 colons\n" +
        ")/[A-F0-9]{0,4}\\z                                                    # Anchor address")) 
        {
        // String matched entirely
    } else {
        // Match attempt failed
    } 
} catch (PatternSyntaxException ex) {
    // Syntax error in the regular expression
}

I purchased a very helpful program called RegexMagic nearly a year ago for some complicated regular expressions I planned on using.

This was suppose to be Java, so it should compile, I assume the /60 can be between the ranges of 0000 and FFFF you can modify that last part.

/[A-F0-9]{0,4} is what I added to the regular expression to match your example.



回答2:

You can use the Guava library, specifically using the com.google.common.net.InetAddresses class, calling isInetAddress().


isInetAddress

public static boolean isInetAddress(String ipString)

Returns true if the supplied string is a valid IP string literal, false otherwise.

Parameters: ipString - String to evaluated as an IP string literal

Returns: true if the argument is a valid IP string literal



回答3:

The IPAddress Java library supports parsing both IPv4 and IPv6 CIDR subnets (ie address/prefix format) in a polymorphic manner. Disclaimer: I am the project manager.

The following method is example code for validating:

static void parse(String str) {
    IPAddressString addrString = new IPAddressString(str);
    try {
         IPAddress addr = addrString.toAddress();
         IPAddress hostAddr = addrString.toHostAddress();
         Integer prefix = addr.getNetworkPrefixLength();
         if(prefix == null) {
             System.out.println(addr + " has no prefix length"); 
         } else {
             System.out.println(addr + " has host address " + hostAddr + " and prefix length " + prefix);
         }
    } catch(AddressStringException e) {
        System.out.println(addrString + " is invalid: " + e.getMessage());
    }
}

Using the examples provided in the question, the output of the above method is:

abcd:ef01:2345:6789:abcd:ef01:2345:6789 has no prefix length
2001:db8::8:800:200c:417a has no prefix length
ff01::101 has no prefix length
::1 has no prefix length
:: has no prefix length
2001:db8::8:800:200c:417a has no prefix length
ff01::101 has no prefix length
::1 has no prefix length
:: has no prefix length
::d01:4403 has no prefix length
::ffff:8190:3426 has no prefix length
::d01:4403 has no prefix length
FFFF:129.144.52.38 is invalid: FFFF:129.144.52.38 IP Address error: address has too few segments
2001:db8:0:cd30::/60 has host address 2001:db8:0:cd30:: and prefix length 60
2001:db8:0:cd30::/60 has host address 2001:db8:0:cd30:: and prefix length 60
2001:db8:0:cd30::/60 has host address 2001:db8:0:cd30:: and prefix length 60
2001:0DB8:0:CD3/60 is invalid: 2001:0DB8:0:CD3/60 IP Address error: address has too few segments
2001:db8::cd30/60 has host address 2001:db8::cd30 and prefix length 60
2001:db8::cd3/60 has host address 2001:db8::cd3 and prefix length 60

As you can see, the question was incorrect about FFFF:129.144.52.38 being valid and about 2001:db8::cd30/60 and 2001:db8::cd3/60 being invalid. The first one would be valid if it were ::FFFF:129.144.52.38



回答4:

Strictly speaking, a section 2.3 does not describe an address representation, but a representation of address prefix (even the "full-length" prefix is not the same as an address).

An IPv6 address prefix is represented by the notation: ipv6-address/prefix-length where ipv6-address is an IPv6 address in any of the notations listed in Section 2.2.

That means you may safely disregard this format if you need to validate addresses.



回答5:

My idea is to split it into two part, prefix address and prefix len.

1. validate prefix address use the some regex to validate IPv6 address
2. validate the prefix len that must be an integer
3. prefix address can only have ':' s less than the result ofprefix len divided by 16
4. other logic must be considered as well, leave TODOs here, sorry:(

  private int validateIPv6AddrWithPrefix(String address) {
        int occurCount = 0;
        for(char c : address) {
            if(c=='/'){
                occurCount++;
            }
        }
        if(occurCount != 1){
         //not good, to much / character
            return -1;
        }
        /* 2nd element should be an integer */
        String[] ss = pool.getAddress().split("/");
        Integer prefixLen = null;
        try{
            prefixLen = Integer.valueOf(ss[1]);
                    // TODO validate the prefix range(1, 128)

        }catch(NumberFormatException e) {
            /* not a Integer */
            return -1;
        }
        /* 1st element should be ipv6 address */
        if(!IPaddrUtilities.isIPv6Address(ss[0])) {
            return -1;
        }
        /* validate ':' character logic */
        occurCount = 0;
        for(char c : ss[0].toCharArray()){
            if(c==':') {
                occurCount++;
            }
        }
        if(occurCount >= prefixLen/16) {
            // to much ':' character
            return -1;
        }
        return 0;
    }


回答6:

I had tried below regex in java and it worked for IPV4 and IPV6

public class Utilities {
private static Pattern VALID_IPV4_PATTERN = null;
private static Pattern VALID_IPV6_PATTERN = null;
private static final String ipv4Pattern = "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])";
private static final String ipv6Pattern = "([0-9a-f]{1,4}:){7}([0-9a-f]){1,4}";

static {
try {
  VALID_IPV4_PATTERN = Pattern.compile(ipv4Pattern, Pattern.CASE_INSENSITIVE);
  VALID_IPV6_PATTERN = Pattern.compile(ipv6Pattern, Pattern.CASE_INSENSITIVE);
   } catch (PatternSyntaxException e) {
  //logger.severe("Unable to compile pattern", e);
 }
}

 /**
 * Determine if the given string is a valid IPv4 or IPv6 address.  This method
 * uses pattern matching to see if the given string could be a valid IP address.
 *
 * @param ipAddress A string that is to be examined to verify whether or not
 * it could be a valid IP address.
 * @return <code>true</code> if the string is a value that is a valid IP address,
 *  <code>false</code> otherwise.
 */
 public static boolean isIpAddress(String ipAddress) {

Matcher m1 = Utilities.VALID_IPV4_PATTERN.matcher(ipAddress);
if (m1.matches()) {
  return true;
}
Matcher m2 = Utilities.VALID_IPV6_PATTERN.matcher(ipAddress);
return m2.matches();
  }


}