blob: 29b30040992930d0dd11e9a040aab657d2d2ac01 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.net.util;
27
28public 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 public static byte[] textToNumericFormatV4(String src)
41 {
42 if (src.length() == 0) {
43 return null;
44 }
45
46 byte[] res = new byte[INADDR4SZ];
47 String[] s = src.split("\\.", -1);
48 long val;
49 try {
50 switch(s.length) {
51 case 1:
52 /*
53 * When only one part is given, the value is stored directly in
54 * the network address without any byte rearrangement.
55 */
56
57 val = Long.parseLong(s[0]);
58 if (val < 0 || val > 0xffffffffL)
59 return null;
60 res[0] = (byte) ((val >> 24) & 0xff);
61 res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);
62 res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
63 res[3] = (byte) (val & 0xff);
64 break;
65 case 2:
66 /*
67 * When a two part address is supplied, the last part is
68 * interpreted as a 24-bit quantity and placed in the right
69 * most three bytes of the network address. This makes the
70 * two part address format convenient for specifying Class A
71 * network addresses as net.host.
72 */
73
74 val = Integer.parseInt(s[0]);
75 if (val < 0 || val > 0xff)
76 return null;
77 res[0] = (byte) (val & 0xff);
78 val = Integer.parseInt(s[1]);
79 if (val < 0 || val > 0xffffff)
80 return null;
81 res[1] = (byte) ((val >> 16) & 0xff);
82 res[2] = (byte) (((val & 0xffff) >> 8) &0xff);
83 res[3] = (byte) (val & 0xff);
84 break;
85 case 3:
86 /*
87 * When a three part address is specified, the last part is
88 * interpreted as a 16-bit quantity and placed in the right
89 * most two bytes of the network address. This makes the
90 * three part address format convenient for specifying
91 * Class B net- work addresses as 128.net.host.
92 */
93 for (int i = 0; i < 2; i++) {
94 val = Integer.parseInt(s[i]);
95 if (val < 0 || val > 0xff)
96 return null;
97 res[i] = (byte) (val & 0xff);
98 }
99 val = Integer.parseInt(s[2]);
100 if (val < 0 || val > 0xffff)
101 return null;
102 res[2] = (byte) ((val >> 8) & 0xff);
103 res[3] = (byte) (val & 0xff);
104 break;
105 case 4:
106 /*
107 * When four parts are specified, each is interpreted as a
108 * byte of data and assigned, from left to right, to the
109 * four bytes of an IPv4 address.
110 */
111 for (int i = 0; i < 4; i++) {
112 val = Integer.parseInt(s[i]);
113 if (val < 0 || val > 0xff)
114 return null;
115 res[i] = (byte) (val & 0xff);
116 }
117 break;
118 default:
119 return null;
120 }
121 } catch(NumberFormatException e) {
122 return null;
123 }
124 return res;
125 }
126
127 /*
128 * Convert IPv6 presentation level address to network order binary form.
129 * credit:
130 * Converted from C code from Solaris 8 (inet_pton)
131 *
132 * Any component of the string following a per-cent % is ignored.
133 *
134 * @param src a String representing an IPv6 address in textual format
135 * @return a byte array representing the IPv6 numeric address
136 */
137 public static byte[] textToNumericFormatV6(String src)
138 {
139 // Shortest valid string is "::", hence at least 2 chars
140 if (src.length() < 2) {
141 return null;
142 }
143
144 int colonp;
145 char ch;
146 boolean saw_xdigit;
147 int val;
148 char[] srcb = src.toCharArray();
149 byte[] dst = new byte[INADDR16SZ];
150
151 int srcb_length = srcb.length;
152 int pc = src.indexOf ("%");
153 if (pc == srcb_length -1) {
154 return null;
155 }
156
157 if (pc != -1) {
158 srcb_length = pc;
159 }
160
161 colonp = -1;
162 int i = 0, j = 0;
163 /* Leading :: requires some special handling. */
164 if (srcb[i] == ':')
165 if (srcb[++i] != ':')
166 return null;
167 int curtok = i;
168 saw_xdigit = false;
169 val = 0;
170 while (i < srcb_length) {
171 ch = srcb[i++];
172 int chval = Character.digit(ch, 16);
173 if (chval != -1) {
174 val <<= 4;
175 val |= chval;
176 if (val > 0xffff)
177 return null;
178 saw_xdigit = true;
179 continue;
180 }
181 if (ch == ':') {
182 curtok = i;
183 if (!saw_xdigit) {
184 if (colonp != -1)
185 return null;
186 colonp = j;
187 continue;
188 } else if (i == srcb_length) {
189 return null;
190 }
191 if (j + INT16SZ > INADDR16SZ)
192 return null;
193 dst[j++] = (byte) ((val >> 8) & 0xff);
194 dst[j++] = (byte) (val & 0xff);
195 saw_xdigit = false;
196 val = 0;
197 continue;
198 }
199 if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
200 String ia4 = src.substring(curtok, srcb_length);
201 /* check this IPv4 address has 3 dots, ie. A.B.C.D */
202 int dot_count = 0, index=0;
203 while ((index = ia4.indexOf ('.', index)) != -1) {
204 dot_count ++;
205 index ++;
206 }
207 if (dot_count != 3) {
208 return null;
209 }
210 byte[] v4addr = textToNumericFormatV4(ia4);
211 if (v4addr == null) {
212 return null;
213 }
214 for (int k = 0; k < INADDR4SZ; k++) {
215 dst[j++] = v4addr[k];
216 }
217 saw_xdigit = false;
218 break; /* '\0' was seen by inet_pton4(). */
219 }
220 return null;
221 }
222 if (saw_xdigit) {
223 if (j + INT16SZ > INADDR16SZ)
224 return null;
225 dst[j++] = (byte) ((val >> 8) & 0xff);
226 dst[j++] = (byte) (val & 0xff);
227 }
228
229 if (colonp != -1) {
230 int n = j - colonp;
231
232 if (j == INADDR16SZ)
233 return null;
234 for (i = 1; i <= n; i++) {
235 dst[INADDR16SZ - i] = dst[colonp + n - i];
236 dst[colonp + n - i] = 0;
237 }
238 j = INADDR16SZ;
239 }
240 if (j != INADDR16SZ)
241 return null;
242 byte[] newdst = convertFromIPv4MappedAddress(dst);
243 if (newdst != null) {
244 return newdst;
245 } else {
246 return dst;
247 }
248 }
249
250 /**
251 * @param src a String representing an IPv4 address in textual format
252 * @return a boolean indicating whether src is an IPv4 literal address
253 */
254 public static boolean isIPv4LiteralAddress(String src) {
255 return textToNumericFormatV4(src) != null;
256 }
257
258 /**
259 * @param src a String representing an IPv6 address in textual format
260 * @return a boolean indicating whether src is an IPv6 literal address
261 */
262 public static boolean isIPv6LiteralAddress(String src) {
263 return textToNumericFormatV6(src) != null;
264 }
265
266 /*
267 * Convert IPv4-Mapped address to IPv4 address. Both input and
268 * returned value are in network order binary form.
269 *
270 * @param src a String representing an IPv4-Mapped address in textual format
271 * @return a byte array representing the IPv4 numeric address
272 */
273 public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
274 if (isIPv4MappedAddress(addr)) {
275 byte[] newAddr = new byte[INADDR4SZ];
276 System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
277 return newAddr;
278 }
279 return null;
280 }
281
282 /**
283 * Utility routine to check if the InetAddress is an
284 * IPv4 mapped IPv6 address.
285 *
286 * @return a <code>boolean</code> indicating if the InetAddress is
287 * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
288 */
289 private static boolean isIPv4MappedAddress(byte[] addr) {
290 if (addr.length < INADDR16SZ) {
291 return false;
292 }
293 if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
294 (addr[2] == 0x00) && (addr[3] == 0x00) &&
295 (addr[4] == 0x00) && (addr[5] == 0x00) &&
296 (addr[6] == 0x00) && (addr[7] == 0x00) &&
297 (addr[8] == 0x00) && (addr[9] == 0x00) &&
298 (addr[10] == (byte)0xff) &&
299 (addr[11] == (byte)0xff)) {
300 return true;
301 }
302 return false;
303 }
304}