001: /*
002: * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.net.util;
027:
028: public class IPAddressUtil {
029: private final static int INADDR4SZ = 4;
030: private final static int INADDR16SZ = 16;
031: private final static int INT16SZ = 2;
032:
033: /*
034: * Converts IPv4 address in its textual presentation form
035: * into its numeric binary form.
036: *
037: * @param src a String representing an IPv4 address in standard format
038: * @return a byte array representing the IPv4 numeric address
039: */
040: public static byte[] textToNumericFormatV4(String src) {
041: if (src.length() == 0) {
042: return null;
043: }
044:
045: byte[] res = new byte[INADDR4SZ];
046: String[] s = src.split("\\.", -1);
047: long val;
048: try {
049: switch (s.length) {
050: case 1:
051: /*
052: * When only one part is given, the value is stored directly in
053: * the network address without any byte rearrangement.
054: */
055:
056: val = Long.parseLong(s[0]);
057: if (val < 0 || val > 0xffffffffL)
058: return null;
059: res[0] = (byte) ((val >> 24) & 0xff);
060: res[1] = (byte) (((val & 0xffffff) >> 16) & 0xff);
061: res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
062: res[3] = (byte) (val & 0xff);
063: break;
064: case 2:
065: /*
066: * When a two part address is supplied, the last part is
067: * interpreted as a 24-bit quantity and placed in the right
068: * most three bytes of the network address. This makes the
069: * two part address format convenient for specifying Class A
070: * network addresses as net.host.
071: */
072:
073: val = Integer.parseInt(s[0]);
074: if (val < 0 || val > 0xff)
075: return null;
076: res[0] = (byte) (val & 0xff);
077: val = Integer.parseInt(s[1]);
078: if (val < 0 || val > 0xffffff)
079: return null;
080: res[1] = (byte) ((val >> 16) & 0xff);
081: res[2] = (byte) (((val & 0xffff) >> 8) & 0xff);
082: res[3] = (byte) (val & 0xff);
083: break;
084: case 3:
085: /*
086: * When a three part address is specified, the last part is
087: * interpreted as a 16-bit quantity and placed in the right
088: * most two bytes of the network address. This makes the
089: * three part address format convenient for specifying
090: * Class B net- work addresses as 128.net.host.
091: */
092: for (int i = 0; i < 2; i++) {
093: val = Integer.parseInt(s[i]);
094: if (val < 0 || val > 0xff)
095: return null;
096: res[i] = (byte) (val & 0xff);
097: }
098: val = Integer.parseInt(s[2]);
099: if (val < 0 || val > 0xffff)
100: return null;
101: res[2] = (byte) ((val >> 8) & 0xff);
102: res[3] = (byte) (val & 0xff);
103: break;
104: case 4:
105: /*
106: * When four parts are specified, each is interpreted as a
107: * byte of data and assigned, from left to right, to the
108: * four bytes of an IPv4 address.
109: */
110: for (int i = 0; i < 4; i++) {
111: val = Integer.parseInt(s[i]);
112: if (val < 0 || val > 0xff)
113: return null;
114: res[i] = (byte) (val & 0xff);
115: }
116: break;
117: default:
118: return null;
119: }
120: } catch (NumberFormatException e) {
121: return null;
122: }
123: return res;
124: }
125:
126: /*
127: * Convert IPv6 presentation level address to network order binary form.
128: * credit:
129: * Converted from C code from Solaris 8 (inet_pton)
130: *
131: * Any component of the string following a per-cent % is ignored.
132: *
133: * @param src a String representing an IPv6 address in textual format
134: * @return a byte array representing the IPv6 numeric address
135: */
136: public static byte[] textToNumericFormatV6(String src) {
137: // Shortest valid string is "::", hence at least 2 chars
138: if (src.length() < 2) {
139: return null;
140: }
141:
142: int colonp;
143: char ch;
144: boolean saw_xdigit;
145: int val;
146: char[] srcb = src.toCharArray();
147: byte[] dst = new byte[INADDR16SZ];
148:
149: int srcb_length = srcb.length;
150: int pc = src.indexOf("%");
151: if (pc == srcb_length - 1) {
152: return null;
153: }
154:
155: if (pc != -1) {
156: srcb_length = pc;
157: }
158:
159: colonp = -1;
160: int i = 0, j = 0;
161: /* Leading :: requires some special handling. */
162: if (srcb[i] == ':')
163: if (srcb[++i] != ':')
164: return null;
165: int curtok = i;
166: saw_xdigit = false;
167: val = 0;
168: while (i < srcb_length) {
169: ch = srcb[i++];
170: int chval = Character.digit(ch, 16);
171: if (chval != -1) {
172: val <<= 4;
173: val |= chval;
174: if (val > 0xffff)
175: return null;
176: saw_xdigit = true;
177: continue;
178: }
179: if (ch == ':') {
180: curtok = i;
181: if (!saw_xdigit) {
182: if (colonp != -1)
183: return null;
184: colonp = j;
185: continue;
186: } else if (i == srcb_length) {
187: return null;
188: }
189: if (j + INT16SZ > INADDR16SZ)
190: return null;
191: dst[j++] = (byte) ((val >> 8) & 0xff);
192: dst[j++] = (byte) (val & 0xff);
193: saw_xdigit = false;
194: val = 0;
195: continue;
196: }
197: if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
198: String ia4 = src.substring(curtok, srcb_length);
199: /* check this IPv4 address has 3 dots, ie. A.B.C.D */
200: int dot_count = 0, index = 0;
201: while ((index = ia4.indexOf('.', index)) != -1) {
202: dot_count++;
203: index++;
204: }
205: if (dot_count != 3) {
206: return null;
207: }
208: byte[] v4addr = textToNumericFormatV4(ia4);
209: if (v4addr == null) {
210: return null;
211: }
212: for (int k = 0; k < INADDR4SZ; k++) {
213: dst[j++] = v4addr[k];
214: }
215: saw_xdigit = false;
216: break; /* '\0' was seen by inet_pton4(). */
217: }
218: return null;
219: }
220: if (saw_xdigit) {
221: if (j + INT16SZ > INADDR16SZ)
222: return null;
223: dst[j++] = (byte) ((val >> 8) & 0xff);
224: dst[j++] = (byte) (val & 0xff);
225: }
226:
227: if (colonp != -1) {
228: int n = j - colonp;
229:
230: if (j == INADDR16SZ)
231: return null;
232: for (i = 1; i <= n; i++) {
233: dst[INADDR16SZ - i] = dst[colonp + n - i];
234: dst[colonp + n - i] = 0;
235: }
236: j = INADDR16SZ;
237: }
238: if (j != INADDR16SZ)
239: return null;
240: byte[] newdst = convertFromIPv4MappedAddress(dst);
241: if (newdst != null) {
242: return newdst;
243: } else {
244: return dst;
245: }
246: }
247:
248: /**
249: * @param src a String representing an IPv4 address in textual format
250: * @return a boolean indicating whether src is an IPv4 literal address
251: */
252: public static boolean isIPv4LiteralAddress(String src) {
253: return textToNumericFormatV4(src) != null;
254: }
255:
256: /**
257: * @param src a String representing an IPv6 address in textual format
258: * @return a boolean indicating whether src is an IPv6 literal address
259: */
260: public static boolean isIPv6LiteralAddress(String src) {
261: return textToNumericFormatV6(src) != null;
262: }
263:
264: /*
265: * Convert IPv4-Mapped address to IPv4 address. Both input and
266: * returned value are in network order binary form.
267: *
268: * @param src a String representing an IPv4-Mapped address in textual format
269: * @return a byte array representing the IPv4 numeric address
270: */
271: public static byte[] convertFromIPv4MappedAddress(byte[] addr) {
272: if (isIPv4MappedAddress(addr)) {
273: byte[] newAddr = new byte[INADDR4SZ];
274: System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
275: return newAddr;
276: }
277: return null;
278: }
279:
280: /**
281: * Utility routine to check if the InetAddress is an
282: * IPv4 mapped IPv6 address.
283: *
284: * @return a <code>boolean</code> indicating if the InetAddress is
285: * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
286: */
287: private static boolean isIPv4MappedAddress(byte[] addr) {
288: if (addr.length < INADDR16SZ) {
289: return false;
290: }
291: if ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00)
292: && (addr[3] == 0x00) && (addr[4] == 0x00)
293: && (addr[5] == 0x00) && (addr[6] == 0x00)
294: && (addr[7] == 0x00) && (addr[8] == 0x00)
295: && (addr[9] == 0x00) && (addr[10] == (byte) 0xff)
296: && (addr[11] == (byte) 0xff)) {
297: return true;
298: }
299: return false;
300: }
301: }
|