001: /*
002: * @(#)Inet6Address.java 1.28 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package java.net;
028:
029: import java.security.AccessController;
030: import java.io.ObjectInputStream;
031: import java.io.IOException;
032: import java.io.ObjectStreamException;
033: import java.io.InvalidObjectException;
034: import sun.security.action.*;
035:
036: /**
037: * This class represents an Internet Protocol version 6 (IPv6) address.
038: * Defined by <a href="http://www.ietf.org/rfc/rfc2373.txt">
039: * <i>RFC 2373: IP Version 6 Addressing Architecture</i></a>.
040: *
041: * <h4> <A NAME="format">Textual representation of IP addresses<a> </h4>
042: *
043: * Textual representation of IPv6 address used as input to methods
044: * takes one of the following forms:
045: *
046: * <ol>
047: * <li><p> <A NAME="lform">The preferred form<a> is x:x:x:x:x:x:x:x, where the 'x's are
048: * the hexadecimal values of the eight 16-bit pieces of the
049: * address. This is the full form. For example,
050: *
051: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
052: * <tr><td><tt>1080:0:0:0:8:800:200C:417A</tt><td></tr>
053: * </table></blockquote>
054: *
055: * <p> Note that it is not necessary to write the leading zeros in
056: * an individual field. However, there must be at least one numeral
057: * in every field, except as described below.</li>
058: *
059: * <li><p> Due to some methods of allocating certain styles of IPv6
060: * addresses, it will be common for addresses to contain long
061: * strings of zero bits. In order to make writing addresses
062: * containing zero bits easier, a special syntax is available to
063: * compress the zeros. The use of "::" indicates multiple groups
064: * of 16-bits of zeros. The "::" can only appear once in an address.
065: * The "::" can also be used to compress the leading and/or trailing
066: * zeros in an address. For example,
067: *
068: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
069: * <tr><td><tt>1080::8:800:200C:417A</tt><td></tr>
070: * </table></blockquote>
071: *
072: * <li><p> An alternative form that is sometimes more convenient
073: * when dealing with a mixed environment of IPv4 and IPv6 nodes is
074: * x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values
075: * of the six high-order 16-bit pieces of the address, and the 'd's
076: * are the decimal values of the four low-order 8-bit pieces of the
077: * standard IPv4 representation address, for example,
078: *
079: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
080: * <tr><td><tt>::FFFF:129.144.52.38</tt><td></tr>
081: * <tr><td><tt>::129.144.52.38</tt><td></tr>
082: * </table></blockquote>
083: *
084: * <p> where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the
085: * general forms of an IPv4-mapped IPv6 address and an
086: * IPv4-compatible IPv6 address. Note that the IPv4 portion must be
087: * in the "d.d.d.d" form. The following forms are invalid:
088: *
089: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
090: * <tr><td><tt>::FFFF:d.d.d</tt><td></tr>
091: * <tr><td><tt>::FFFF:d.d</tt><td></tr>
092: * <tr><td><tt>::d.d.d</tt><td></tr>
093: * <tr><td><tt>::d.d</tt><td></tr>
094: * </table></blockquote>
095: *
096: * <p> The following form:
097: *
098: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
099: * <tr><td><tt>::FFFF:d</tt><td></tr>
100: * </table></blockquote>
101: *
102: * <p> is valid, however it is an unconventional representation of
103: * the IPv4-compatible IPv6 address,
104: *
105: * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
106: * <tr><td><tt>::255.255.0.d</tt><td></tr>
107: * </table></blockquote>
108: *
109: * <p> while "::d" corresponds to the general IPv6 address
110: * "0:0:0:0:0:0:0:d".</li>
111: * </ol>
112: *
113: * <p> For methods that return a textual representation as output
114: * value, the full form is used. Inet6Address will return the full
115: * form because it is unambiguous when used in combination with other
116: * textual data.
117: *
118: * <h4> Special IPv6 address </h4>
119: *
120: * <blockquote>
121: * <table cellspacing=2 summary="Description of IPv4-mapped address"> <tr><th valign=top><i>IPv4-mapped address</i></th>
122: * <td>Of the form::ffff:w.x.y.z, this IPv6 address is used to
123: * represent an IPv4 address. It allows the native program to
124: * use the same address data structure and also the same
125: * socket when communicating with both IPv4 and IPv6 nodes.
126: *
127: * <p>In InetAddress and Inet6Address, it is used for internal
128: * representation; it has no functional role. Java will never
129: * return an IPv4-mapped address. These classes can take an
130: * IPv4-mapped address as input, both in byte array and text
131: * representation. However, it will be converted into an IPv4
132: * address.</td></tr>
133: * </table></blockquote>
134: */
135: public final class Inet6Address extends InetAddress {
136: final static int INADDRSZ = 16;
137:
138: /*
139: * cached scope_id - for link-local address use only.
140: */
141: private transient int cached_scope_id = 0;
142:
143: /**
144: * Holds a 128-bit (16 bytes) IPv6 address.
145: *
146: * @serial
147: */
148: byte[] ipaddress;
149:
150: private static final long serialVersionUID = 6880410070516793377L;
151:
152: /*
153: * Perform initializations.
154: */
155: static {
156: init();
157: }
158:
159: Inet6Address() {
160: super ();
161: hostName = null;
162: ipaddress = new byte[INADDRSZ];
163: family = IPv6;
164: }
165:
166: Inet6Address(String hostName, byte addr[]) {
167: this .hostName = hostName;
168: if (addr.length == INADDRSZ) { // normal IPv6 address
169: family = IPv6;
170: ipaddress = (byte[]) addr.clone();
171: }
172: }
173:
174: private void readObject(ObjectInputStream s) throws IOException,
175: ClassNotFoundException {
176: s.defaultReadObject();
177:
178: ipaddress = (byte[]) ipaddress.clone();
179:
180: // Check that our invariants are satisfied
181: if (ipaddress.length != INADDRSZ) {
182: throw new InvalidObjectException("invalid address length: "
183: + ipaddress.length);
184: }
185:
186: if (family != IPv6) {
187: throw new InvalidObjectException(
188: "invalid address family type");
189: }
190: }
191:
192: /**
193: * Utility routine to check if the InetAddress is an IP multicast
194: * address. 11111111 at the start of the address identifies the
195: * address as being a multicast address.
196: *
197: * @return a <code>boolean</code> indicating if the InetAddress is
198: * an IP multicast address
199: * @since JDK1.1
200: */
201: public boolean isMulticastAddress() {
202: return ((ipaddress[0] & 0xff) == 0xff);
203: }
204:
205: /**
206: * Utility routine to check if the InetAddress in a wildcard address.
207: * @return a <code>boolean</code> indicating if the Inetaddress is
208: * a wildcard address.
209: * @since 1.4
210: */
211: public boolean isAnyLocalAddress() {
212: byte test = 0x00;
213: for (int i = 0; i < INADDRSZ; i++) {
214: test |= ipaddress[i];
215: }
216: return (test == 0x00);
217: }
218:
219: /**
220: * Utility routine to check if the InetAddress is a loopback address.
221: *
222: * @return a <code>boolean</code> indicating if the InetAddress is
223: * a loopback address; or false otherwise.
224: * @since 1.4
225: */
226: public boolean isLoopbackAddress() {
227: byte test = 0x00;
228: for (int i = 0; i < 15; i++) {
229: test |= ipaddress[i];
230: }
231: return (test == 0x00) && (ipaddress[15] == 0x01);
232: }
233:
234: /**
235: * Utility routine to check if the InetAddress is an link local address.
236: *
237: * @return a <code>boolean</code> indicating if the InetAddress is
238: * a link local address; or false if address is not a link local unicast address.
239: * @since 1.4
240: */
241: public boolean isLinkLocalAddress() {
242: return ((ipaddress[0] & 0xff) == 0xfe && (ipaddress[1] & 0xc0) == 0x80);
243: }
244:
245: /**
246: * Utility routine to check if the InetAddress is a site local address.
247: *
248: * @return a <code>boolean</code> indicating if the InetAddress is
249: * a site local address; or false if address is not a site local unicast address.
250: * @since 1.4
251: */
252: public boolean isSiteLocalAddress() {
253: return ((ipaddress[0] & 0xff) == 0xfe && (ipaddress[1] & 0xc0) == 0xc0);
254: }
255:
256: /**
257: * Utility routine to check if the multicast address has global scope.
258: *
259: * @return a <code>boolean</code> indicating if the address has
260: * is a multicast address of global scope, false if it is not
261: * of global scope or it is not a multicast address
262: * @since 1.4
263: */
264: public boolean isMCGlobal() {
265: return ((ipaddress[0] & 0xff) == 0xff && (ipaddress[1] & 0x0f) == 0x0e);
266: }
267:
268: /**
269: * Utility routine to check if the multicast address has node scope.
270: *
271: * @return a <code>boolean</code> indicating if the address has
272: * is a multicast address of node-local scope, false if it is not
273: * of node-local scope or it is not a multicast address
274: * @since 1.4
275: */
276: public boolean isMCNodeLocal() {
277: return ((ipaddress[0] & 0xff) == 0xff && (ipaddress[1] & 0x0f) == 0x01);
278: }
279:
280: /**
281: * Utility routine to check if the multicast address has link scope.
282: *
283: * @return a <code>boolean</code> indicating if the address has
284: * is a multicast address of link-local scope, false if it is not
285: * of link-local scope or it is not a multicast address
286: * @since 1.4
287: */
288: public boolean isMCLinkLocal() {
289: return ((ipaddress[0] & 0xff) == 0xff && (ipaddress[1] & 0x0f) == 0x02);
290: }
291:
292: /**
293: * Utility routine to check if the multicast address has site scope.
294: *
295: * @return a <code>boolean</code> indicating if the address has
296: * is a multicast address of site-local scope, false if it is not
297: * of site-local scope or it is not a multicast address
298: * @since 1.4
299: */
300: public boolean isMCSiteLocal() {
301: return ((ipaddress[0] & 0xff) == 0xff && (ipaddress[1] & 0x0f) == 0x05);
302: }
303:
304: /**
305: * Utility routine to check if the multicast address has organization scope.
306: *
307: * @return a <code>boolean</code> indicating if the address has
308: * is a multicast address of organization-local scope,
309: * false if it is not of organization-local scope
310: * or it is not a multicast address
311: * @since 1.4
312: */
313: public boolean isMCOrgLocal() {
314: return ((ipaddress[0] & 0xff) == 0xff && (ipaddress[1] & 0x0f) == 0x08);
315: }
316:
317: /**
318: * Returns the raw IP address of this <code>InetAddress</code>
319: * object. The result is in network byte order: the highest order
320: * byte of the address is in <code>getAddress()[0]</code>.
321: *
322: * @return the raw IP address of this object.
323: */
324: public byte[] getAddress() {
325: return (byte[]) ipaddress.clone();
326: }
327:
328: /**
329: * Returns the IP address string in textual presentation.
330: *
331: * @return the raw IP address in a string format.
332: */
333: public String getHostAddress() {
334: return numericToTextFormat(ipaddress);
335: }
336:
337: /**
338: * Returns a hashcode for this IP address.
339: *
340: * @return a hash code value for this IP address.
341: */
342: public int hashCode() {
343: if (ipaddress != null) {
344:
345: int hash = 0;
346: int i = 0;
347: while (i < INADDRSZ) {
348: int j = 0;
349: int component = 0;
350: while (j < 4 && i < INADDRSZ) {
351: component = (component << 8) + ipaddress[i];
352: j++;
353: i++;
354: }
355: hash += component;
356: }
357: return hash;
358:
359: } else {
360: return 0;
361: }
362: }
363:
364: /**
365: * Compares this object against the specified object.
366: * The result is <code>true</code> if and only if the argument is
367: * not <code>null</code> and it represents the same IP address as
368: * this object.
369: * <p>
370: * Two instances of <code>InetAddress</code> represent the same IP
371: * address if the length of the byte arrays returned by
372: * <code>getAddress</code> is the same for both, and each of the
373: * array components is the same for the byte arrays.
374: *
375: * @param obj the object to compare against.
376: * @return <code>true</code> if the objects are the same;
377: * <code>false</code> otherwise.
378: * @see java.net.InetAddress#getAddress()
379: */
380: public boolean equals(Object obj) {
381: if (obj == null || !(obj instanceof Inet6Address))
382: return false;
383:
384: Inet6Address inetAddr = (Inet6Address) obj;
385:
386: for (int i = 0; i < INADDRSZ; i++) {
387: if (ipaddress[i] != inetAddr.ipaddress[i])
388: return false;
389: }
390:
391: return true;
392: }
393:
394: /**
395: * Utility routine to check if the InetAddress is an
396: * IPv4 mapped IPv6 address.
397: *
398: * @return a <code>boolean</code> indicating if the InetAddress is
399: * an IPv4 mapped IPv6 address; or false if address is IPv4 address.
400: */
401: static boolean isIPv4MappedAddress(byte[] addr) {
402: if (addr.length < INADDRSZ) {
403: return false;
404: }
405: if ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00)
406: && (addr[3] == 0x00) && (addr[4] == 0x00)
407: && (addr[5] == 0x00) && (addr[6] == 0x00)
408: && (addr[7] == 0x00) && (addr[8] == 0x00)
409: && (addr[9] == 0x00) && (addr[10] == (byte) 0xff)
410: && (addr[11] == (byte) 0xff)) {
411: return true;
412: }
413: return false;
414: }
415:
416: static byte[] convertFromIPv4MappedAddress(byte[] addr) {
417: if (isIPv4MappedAddress(addr)) {
418: byte[] newAddr = new byte[Inet4Address.INADDRSZ];
419: System.arraycopy(addr, 12, newAddr, 0,
420: Inet4Address.INADDRSZ);
421: return newAddr;
422: }
423: return null;
424: }
425:
426: /**
427: * Utility routine to check if the InetAddress is an
428: * IPv4 compatible IPv6 address.
429: *
430: * @return a <code>boolean</code> indicating if the InetAddress is
431: * an IPv4 compatible IPv6 address; or false if address is IPv4 address.
432: * @since 1.4
433: */
434: public boolean isIPv4CompatibleAddress() {
435: if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00)
436: && (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00)
437: && (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00)
438: && (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00)
439: && (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00)
440: && (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00)) {
441: return true;
442: }
443: return false;
444: }
445:
446: // Utilities
447: private final static int INT16SZ = 2;
448:
449: /*
450: * Convert IPv6 binary address into presentation (printable) format.
451: *
452: * @param src a byte array representing the IPv6 numeric address
453: * @return a String representing an IPv6 address in
454: * textual representation format
455: * @since 1.4
456: */
457: static String numericToTextFormat(byte[] src) {
458: StringBuffer sb = new StringBuffer(39);
459: for (int i = 0; i < (INADDRSZ / INT16SZ); i++) {
460: sb.append(Integer.toHexString(((src[i << 1] << 8) & 0xff00)
461: | (src[(i << 1) + 1] & 0xff)));
462: if (i < (INADDRSZ / INT16SZ) - 1) {
463: sb.append(":");
464: }
465: }
466: return sb.toString();
467: }
468:
469: /*
470: * Convert IPv6 presentation level address to network order binary form.
471: * credit:
472: * Converted from C code from Solaris 8 (inet_pton)
473: *
474: * @param src a String representing an IPv6 address in textual format
475: * @return a byte array representing the IPv6 numeric address
476: * @since 1.4
477: */
478: static byte[] textToNumericFormat(String src) {
479: if (src.length() == 0) {
480: return null;
481: }
482:
483: int colonp;
484: char ch;
485: boolean saw_xdigit;
486: int val;
487: char[] srcb = src.toCharArray();
488: byte[] dst = new byte[INADDRSZ];
489:
490: colonp = -1;
491: int i = 0, j = 0;
492: /* Leading :: requires some special handling. */
493: if (srcb[i] == ':')
494: if (srcb[++i] != ':')
495: return null;
496: int curtok = i;
497: saw_xdigit = false;
498: val = 0;
499: while (i < srcb.length) {
500: ch = srcb[i++];
501: int chval = Character.digit(ch, 16);
502: if (chval != -1) {
503: val <<= 4;
504: val |= chval;
505: if (val > 0xffff)
506: return null;
507: saw_xdigit = true;
508: continue;
509: }
510: if (ch == ':') {
511: curtok = i;
512: if (!saw_xdigit) {
513: if (colonp != -1)
514: return null;
515: colonp = j;
516: continue;
517: } else if (i == srcb.length) {
518: return null;
519: }
520: if (j + INT16SZ > INADDRSZ)
521: return null;
522: dst[j++] = (byte) ((val >> 8) & 0xff);
523: dst[j++] = (byte) (val & 0xff);
524: saw_xdigit = false;
525: val = 0;
526: continue;
527: }
528: if (ch == '.' && ((j + Inet4Address.INADDRSZ) <= INADDRSZ)) {
529: byte[] v4addr = Inet4Address.textToNumericFormat(src
530: .substring(curtok));
531: if (v4addr == null) {
532: return null;
533: }
534: for (int k = 0; k < Inet4Address.INADDRSZ; k++) {
535: dst[j++] = v4addr[k];
536: }
537: saw_xdigit = false;
538: break; /* '\0' was seen by inet_pton4(). */
539: }
540: return null;
541: }
542: if (saw_xdigit) {
543: if (j + INT16SZ > INADDRSZ)
544: return null;
545: dst[j++] = (byte) ((val >> 8) & 0xff);
546: dst[j++] = (byte) (val & 0xff);
547: }
548:
549: if (colonp != -1) {
550: int n = j - colonp;
551:
552: if (j == INADDRSZ)
553: return null;
554: for (i = 1; i <= n; i++) {
555: dst[INADDRSZ - i] = dst[colonp + n - i];
556: dst[colonp + n - i] = 0;
557: }
558: j = INADDRSZ;
559: }
560: if (j != INADDRSZ)
561: return null;
562: byte[] newdst = convertFromIPv4MappedAddress(dst);
563: if (newdst != null) {
564: return newdst;
565: } else {
566: return dst;
567: }
568: }
569:
570: /**
571: * Perform class load-time initializations.
572: */
573: private static native void init();
574:
575: }
|