package org.openstack.atlas.api.validation.util.IPString; import java.util.regex.Pattern; import java.util.regex.Matcher; public class IPv6 { private String ip; private static final Pattern ipPattern; static { String ippatternstr = "\\A(.*::)([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})$|" + "^(.*):([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})\\z"; ipPattern = Pattern.compile(ippatternstr); } public static int[] splitvals(String ipStr) { int i; int length; int val; String[] words; int[] out; if (ipStr == null) { return null; } words = ipStr.split(":", -1); length = words.length; if (length <= 0) { return null; } out = new int[length]; for (i = 0; i < length; i++) { if (words[i].length() == 0) { out[i] = -1; continue; } val = IPUtils.hex16bit2int(words[i]); if (val == -1) { return null; } out[i] = val; } return out; } public static int countnegatives(int[] in) { int i; int out = 0; for (i = 0; i < in.length; i++) { if (in[i] < 0) { out += 1; } } return out; } public static String expand(String ipStr, int nwords) throws IPStringConversionException { StringBuilder sb; String hex; int[] vals; int[] expanded_vals; int i; sb = new StringBuilder(); vals = splitvals(ipStr); if (vals == null) { throw new IPStringConversionException("Error converting hex to binary in IPv6 ip"); } expanded_vals = expand(vals, nwords); for (i = 0; i < nwords - 1; i++) { hex = String.format("%s:", IPUtils.int16bit2hex(expanded_vals[i])); sb.append(hex); } hex = String.format("%s", IPUtils.int16bit2hex(expanded_vals[nwords - 1])); sb.append(hex); return sb.toString(); } public String expand() throws IPStringConversionException { return bytes2IpString(IpString2bytes(ip)); // Silly but just used the inversion to force expansion } public static int[] expand(int[] vals, int nwords) throws IPStringConversionException { int[] out; int i; int j; int nvals; int negatives; if (vals.length < 3 || vals.length > nwords) { throw new IPStringConversionException("Invalid Number of 16bit words in IPv6 address"); } nvals = vals.length; negatives = countnegatives(vals); out = new int[nwords]; for (i = 0; i < nwords; i++) { out[i] = 0; } if (negatives > 3) { throw new IPStringConversionException("Invalid IPv6 Zero compression"); } if (negatives == 3 && nvals == 3) { return out; // All Zero compression; } if (negatives == 1 && (vals[0] != -1 && vals[nvals - 1] != -1)) { // Middle Compression // Do left expand j = nvals - 1; i = nwords - 1; while (vals[j] != -1) { out[i] = vals[j]; i--; j--; } // Then do right Expand j = 0; i = 0; while (vals[i] != -1) { out[i] = vals[j]; i++; j++; } return out; } if (negatives == 2 && vals[0] == -1 && vals[1] == -1) { // Left Compression j = nvals - 1; i = nwords - 1; while (vals[j] != -1) { out[i] = vals[j]; i--; j--; } return out; } if (negatives == 2 && vals[nvals - 1] == -1 && vals[nvals - 2] == -1) { // Right Compression j = 0; i = 0; while (vals[i] != -1) { out[i] = vals[j]; i++; j++; } return out; } if (negatives == 0 && nvals == nwords) { // No Compression Straight copy; for (i = 0; i < nwords; i++) { out[i] = vals[i]; } return out; } throw new IPStringConversionException("Invapid IPv6 ip"); } public static byte[] IpString2bytes(String ipStr) throws IPStringConversionException { int i; int j; int val; byte[] out; String expanded_ipStr; Matcher ipMatch = ipPattern.matcher(ipStr); if (ipMatch.find()) { // Found a RFC4291 2.2.3 ipv4 mixed address String hex_part = ipMatch.group(1); String ip4_part = ipMatch.group(2); if (hex_part == null && ip4_part == null) { hex_part = ipMatch.group(3); ip4_part = ipMatch.group(4); } IPv4 ipv4 = new IPv4(ip4_part); byte[] ipv4_bytes = ipv4.getBytes(); byte[] hex_bytes = hex_part.getBytes(); int last = hex_bytes.length - 1; int hi_word = (IPUtils.ubyte2int(ipv4_bytes[0]) << 8) + (IPUtils.ubyte2int(ipv4_bytes[1])); int lo_word = (IPUtils.ubyte2int(ipv4_bytes[2]) << 8) + (IPUtils.ubyte2int(ipv4_bytes[3])); String hi_str = IPUtils.int16bit2hex(hi_word); String lo_str = IPUtils.int16bit2hex(lo_word); expanded_ipStr = expand(hex_part, 6) + String.format(":%s:%s", hi_str, lo_str); } else { String hex_part = ipStr; expanded_ipStr = expand(hex_part, 8); } i = 0; out = new byte[16]; for (String word : expanded_ipStr.split(":")) { val = IPUtils.hex16bit2int(word); out[i] = IPUtils.int2ubyte((val & 0xff00) >> 8); out[i + 1] = IPUtils.int2ubyte((val & 0x00ff)); i += 2; } return out; } public static String bytes2IpString(byte[] in) throws IPStringConversionException { int i; int hi; int lo; StringBuilder sb; String hex; if (in.length != 16) { String msg = "Error IPv6 requires byte array of length 16"; throw new IPStringConversionException(msg); } sb = new StringBuilder(); for (i = 0; i < 14; i += 2) { hi = IPUtils.ubyte2int(in[i]) << 8; lo = IPUtils.ubyte2int(in[i + 1]); hex = String.format("%s:", IPUtils.int16bit2hex(hi | lo)); sb.append(hex); } hi = IPUtils.ubyte2int(in[14]) << 8; lo = IPUtils.ubyte2int(in[15]); sb.append(String.format("%s", IPUtils.int16bit2hex(hi | lo))); return sb.toString(); } public IPv6() { } public IPv6(String ip) { this.ip = ip; } public IPv6(byte[] in) throws IPStringConversionException { ip = bytes2IpString(in); } public void setIp(byte[] in) throws IPStringConversionException { ip = bytes2IpString(in); } public String getString() { return ip; } public byte[] getBytes() throws IPStringConversionException { return IpString2bytes(this.ip); } public void setIp(String ip) { this.ip = ip; } }