IPv6 validation
I used IPAdd开发者_JAVA技巧ressUtil.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
- ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
- 2001:DB8:0:0:8:800:200C:417A
- FF01:0:0:0:0:0:0:101
- 0:0:0:0:0:0:0:1
- 0:0:0:0:0:0:0:0
- 2001:DB8::8:800:200C:417A
- FF01::101
- ::1
- ::
- 0:0:0:0:0:0:13.1.68.3
- 0:0:0:0:0:FFFF:129.144.52.38
- ::13.1.68.3
- FFFF:129.144.52.38
- 2001:0DB8:0000:CD30:0000:0000:0000:0000/60
- 2001:0DB8::CD30:0:0:0:0/60
- 2001:0DB8:0:CD30::/60
NOT legal representations of IPV6
- 2001:0DB8:0:CD3/60
- 2001:0DB8::CD30/60
- 2001:0DB8::CD3/60
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
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
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.
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.
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;
}
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();
}
}
精彩评论