1 /* 2 * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net.util; 27 28 public class IPAddressUtil { 29 private final static int INADDR4SZ = 4; 30 private final static int INADDR16SZ = 16; 31 private final static int INT16SZ = 2; 32 33 /* 34 * Converts IPv4 address in its textual presentation form 35 * into its numeric binary form. 36 * 37 * @param src a String representing an IPv4 address in standard format 38 * @return a byte array representing the IPv4 numeric address 39 */ 40 @SuppressWarnings("fallthrough") textToNumericFormatV4(String src)41 public static byte[] textToNumericFormatV4(String src) 42 { 43 byte[] res = new byte[INADDR4SZ]; 44 45 long tmpValue = 0; 46 int currByte = 0; 47 boolean newOctet = true; 48 49 int len = src.length(); 50 if (len == 0 || len > 15) { 51 return null; 52 } 53 /* 54 * When only one part is given, the value is stored directly in 55 * the network address without any byte rearrangement. 56 * 57 * When a two part address is supplied, the last part is 58 * interpreted as a 24-bit quantity and placed in the right 59 * most three bytes of the network address. This makes the 60 * two part address format convenient for specifying Class A 61 * network addresses as net.host. 62 * 63 * When a three part address is specified, the last part is 64 * interpreted as a 16-bit quantity and placed in the right 65 * most two bytes of the network address. This makes the 66 * three part address format convenient for specifying 67 * Class B net- work addresses as 128.net.host. 68 * 69 * When four parts are specified, each is interpreted as a 70 * byte of data and assigned, from left to right, to the 71 * four bytes of an IPv4 address. 72 * 73 * We determine and parse the leading parts, if any, as single 74 * byte values in one pass directly into the resulting byte[], 75 * then the remainder is treated as a 8-to-32-bit entity and 76 * translated into the remaining bytes in the array. 77 */ 78 for (int i = 0; i < len; i++) { 79 char c = src.charAt(i); 80 if (c == '.') { 81 if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) { 82 return null; 83 } 84 res[currByte++] = (byte) (tmpValue & 0xff); 85 tmpValue = 0; 86 newOctet = true; 87 } else { 88 int digit = Character.digit(c, 10); 89 if (digit < 0) { 90 return null; 91 } 92 tmpValue *= 10; 93 tmpValue += digit; 94 newOctet = false; 95 } 96 } 97 if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) { 98 return null; 99 } 100 switch (currByte) { 101 // BEGIN Android-changed: Require all four parts to be given for an IPv4 address. 102 /* 103 case 0: 104 res[0] = (byte) ((tmpValue >> 24) & 0xff); 105 case 1: 106 res[1] = (byte) ((tmpValue >> 16) & 0xff); 107 case 2: 108 res[2] = (byte) ((tmpValue >> 8) & 0xff); 109 */ 110 case 0: 111 case 1: 112 case 2: 113 return null; 114 // END Android-changed: Require all four parts to be given for an IPv4 address. 115 case 3: 116 res[3] = (byte) ((tmpValue >> 0) & 0xff); 117 } 118 return res; 119 } 120 121 /* 122 * Convert IPv6 presentation level address to network order binary form. 123 * credit: 124 * Converted from C code from Solaris 8 (inet_pton) 125 * 126 * Any component of the string following a per-cent % is ignored. 127 * 128 * @param src a String representing an IPv6 address in textual format 129 * @return a byte array representing the IPv6 numeric address 130 */ textToNumericFormatV6(String src)131 public static byte[] textToNumericFormatV6(String src) 132 { 133 // Shortest valid string is "::", hence at least 2 chars 134 if (src.length() < 2) { 135 return null; 136 } 137 138 int colonp; 139 char ch; 140 boolean saw_xdigit; 141 int val; 142 char[] srcb = src.toCharArray(); 143 byte[] dst = new byte[INADDR16SZ]; 144 145 int srcb_length = srcb.length; 146 int pc = src.indexOf ("%"); 147 if (pc == srcb_length -1) { 148 return null; 149 } 150 151 if (pc != -1) { 152 srcb_length = pc; 153 } 154 155 colonp = -1; 156 int i = 0, j = 0; 157 /* Leading :: requires some special handling. */ 158 if (srcb[i] == ':') 159 if (srcb[++i] != ':') 160 return null; 161 int curtok = i; 162 saw_xdigit = false; 163 val = 0; 164 while (i < srcb_length) { 165 ch = srcb[i++]; 166 int chval = Character.digit(ch, 16); 167 if (chval != -1) { 168 val <<= 4; 169 val |= chval; 170 if (val > 0xffff) 171 return null; 172 saw_xdigit = true; 173 continue; 174 } 175 if (ch == ':') { 176 curtok = i; 177 if (!saw_xdigit) { 178 if (colonp != -1) 179 return null; 180 colonp = j; 181 continue; 182 } else if (i == srcb_length) { 183 return null; 184 } 185 if (j + INT16SZ > INADDR16SZ) 186 return null; 187 dst[j++] = (byte) ((val >> 8) & 0xff); 188 dst[j++] = (byte) (val & 0xff); 189 saw_xdigit = false; 190 val = 0; 191 continue; 192 } 193 if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) { 194 String ia4 = src.substring(curtok, srcb_length); 195 /* check this IPv4 address has 3 dots, ie. A.B.C.D */ 196 int dot_count = 0, index=0; 197 while ((index = ia4.indexOf ('.', index)) != -1) { 198 dot_count ++; 199 index ++; 200 } 201 if (dot_count != 3) { 202 return null; 203 } 204 byte[] v4addr = textToNumericFormatV4(ia4); 205 if (v4addr == null) { 206 return null; 207 } 208 for (int k = 0; k < INADDR4SZ; k++) { 209 dst[j++] = v4addr[k]; 210 } 211 saw_xdigit = false; 212 break; /* '\0' was seen by inet_pton4(). */ 213 } 214 return null; 215 } 216 if (saw_xdigit) { 217 if (j + INT16SZ > INADDR16SZ) 218 return null; 219 dst[j++] = (byte) ((val >> 8) & 0xff); 220 dst[j++] = (byte) (val & 0xff); 221 } 222 223 if (colonp != -1) { 224 int n = j - colonp; 225 226 if (j == INADDR16SZ) 227 return null; 228 for (i = 1; i <= n; i++) { 229 dst[INADDR16SZ - i] = dst[colonp + n - i]; 230 dst[colonp + n - i] = 0; 231 } 232 j = INADDR16SZ; 233 } 234 if (j != INADDR16SZ) 235 return null; 236 byte[] newdst = convertFromIPv4MappedAddress(dst); 237 if (newdst != null) { 238 return newdst; 239 } else { 240 return dst; 241 } 242 } 243 244 /** 245 * @param src a String representing an IPv4 address in textual format 246 * @return a boolean indicating whether src is an IPv4 literal address 247 */ isIPv4LiteralAddress(String src)248 public static boolean isIPv4LiteralAddress(String src) { 249 return textToNumericFormatV4(src) != null; 250 } 251 252 /** 253 * @param src a String representing an IPv6 address in textual format 254 * @return a boolean indicating whether src is an IPv6 literal address 255 */ isIPv6LiteralAddress(String src)256 public static boolean isIPv6LiteralAddress(String src) { 257 return textToNumericFormatV6(src) != null; 258 } 259 260 /* 261 * Convert IPv4-Mapped address to IPv4 address. Both input and 262 * returned value are in network order binary form. 263 * 264 * @param src a String representing an IPv4-Mapped address in textual format 265 * @return a byte array representing the IPv4 numeric address 266 */ convertFromIPv4MappedAddress(byte[] addr)267 public static byte[] convertFromIPv4MappedAddress(byte[] addr) { 268 if (isIPv4MappedAddress(addr)) { 269 byte[] newAddr = new byte[INADDR4SZ]; 270 System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ); 271 return newAddr; 272 } 273 return null; 274 } 275 276 /** 277 * Utility routine to check if the InetAddress is an 278 * IPv4 mapped IPv6 address. 279 * 280 * @return a <code>boolean</code> indicating if the InetAddress is 281 * an IPv4 mapped IPv6 address; or false if address is IPv4 address. 282 */ isIPv4MappedAddress(byte[] addr)283 private static boolean isIPv4MappedAddress(byte[] addr) { 284 if (addr.length < INADDR16SZ) { 285 return false; 286 } 287 if ((addr[0] == 0x00) && (addr[1] == 0x00) && 288 (addr[2] == 0x00) && (addr[3] == 0x00) && 289 (addr[4] == 0x00) && (addr[5] == 0x00) && 290 (addr[6] == 0x00) && (addr[7] == 0x00) && 291 (addr[8] == 0x00) && (addr[9] == 0x00) && 292 (addr[10] == (byte)0xff) && 293 (addr[11] == (byte)0xff)) { 294 return true; 295 } 296 return false; 297 } 298 } 299