in sshd-common/src/main/java/org/apache/sshd/common/util/net/SshdSocketAddress.java [598:693]
public static boolean isIPv6Address(String address) {
address = GenericUtils.trimToEmpty(address);
if (GenericUtils.isEmpty(address)) {
return false;
}
if (WELL_KNOWN_IPV6_ADDRESSES.contains(address)) {
return true;
}
boolean containsCompressedZeroes = address.contains("::");
if (containsCompressedZeroes && (address.indexOf("::") != address.lastIndexOf("::"))) {
return false;
}
if (((address.indexOf(':') == 0) && (!address.startsWith("::")))
|| (address.endsWith(":") && (!address.endsWith("::")))) {
return false;
}
String[] splitOctets = GenericUtils.split(address, ':');
List<String> octetList = new ArrayList<>(Arrays.asList(splitOctets));
if (containsCompressedZeroes) {
if (address.endsWith("::")) {
// String.split() drops ending empty segments
octetList.add("");
} else if (address.startsWith("::") && (!octetList.isEmpty())) {
octetList.remove(0);
}
}
int numOctests = octetList.size();
if (numOctests > IPV6_MAX_HEX_GROUPS) {
return false;
}
int validOctets = 0;
int emptyOctets = 0; // consecutive empty chunks
for (int index = 0; index < numOctests; index++) {
String octet = octetList.get(index);
int pos = octet.indexOf('%'); // is it a zone index
if (pos >= 0) {
// zone index must come last
if (index != (numOctests - 1)) {
return false;
}
octet = (pos > 0) ? octet.substring(0, pos) : "";
}
int octetLength = octet.length();
if (octetLength == 0) {
emptyOctets++;
if (emptyOctets > 1) {
return false;
}
validOctets++;
continue;
}
emptyOctets = 0;
// Is last chunk an IPv4 address?
if ((index == (numOctests - 1)) && (octet.indexOf('.') > 0)) {
if (!isIPv4Address(octet)) {
return false;
}
validOctets += 2;
continue;
}
if (octetLength > IPV6_MAX_HEX_DIGITS_PER_GROUP) {
return false;
}
int octetInt = 0;
try {
octetInt = Integer.parseInt(octet, 16);
} catch (NumberFormatException e) {
return false;
}
if ((octetInt < 0) || (octetInt > 0x000ffff)) {
return false;
}
validOctets++;
}
if ((validOctets > IPV6_MAX_HEX_GROUPS)
|| ((validOctets < IPV6_MAX_HEX_GROUPS) && (!containsCompressedZeroes))) {
return false;
}
return true;
}