Frames | No Frames |
1: /* InetAddress.java -- Class to model an Internet address 2: Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.net; 40: 41: import gnu.classpath.Configuration; 42: 43: import java.io.IOException; 44: import java.io.ObjectInputStream; 45: import java.io.ObjectOutputStream; 46: import java.io.ObjectStreamException; 47: import java.io.Serializable; 48: 49: /** 50: * This class models an Internet address. It does not have a public 51: * constructor. Instead, new instances of this objects are created 52: * using the static methods getLocalHost(), getByName(), and 53: * getAllByName(). 54: * 55: * <p>This class fulfills the function of the C style functions gethostname(), 56: * gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names 57: * into their corresponding numeric addresses and vice versa.</p> 58: * 59: * @author Aaron M. Renn (arenn@urbanophile.com) 60: * @author Per Bothner 61: * 62: * @specnote This class is not final since JK 1.4 63: */ 64: public class InetAddress implements Serializable 65: { 66: private static final long serialVersionUID = 3286316764910316507L; 67: 68: /** 69: * Dummy InetAddress, used to bind socket to any (all) network interfaces. 70: */ 71: static InetAddress ANY_IF; 72: 73: private static final byte[] loopbackAddress = { 127, 0, 0, 1 }; 74: 75: private static final InetAddress loopback 76: = new Inet4Address(loopbackAddress, "localhost"); 77: 78: private static InetAddress localhost = null; 79: 80: static 81: { 82: // load the shared library needed for name resolution 83: if (Configuration.INIT_LOAD_LIBRARY) 84: System.loadLibrary("javanet"); 85: 86: byte[] zeros = { 0, 0, 0, 0 }; 87: ANY_IF = new Inet4Address(zeros, "0.0.0.0"); 88: } 89: 90: /** 91: * The Serialized Form specifies that an int 'address' is saved/restored. 92: * This class uses a byte array internally so we'll just do the conversion 93: * at serialization time and leave the rest of the algorithm as is. 94: */ 95: private int address; 96: 97: /** 98: * An array of octets representing an IP address. 99: */ 100: transient byte[] addr; 101: 102: /** 103: * The name of the host for this address. 104: */ 105: String hostName; 106: 107: /** 108: * The field 'family' seems to be the AF_ value. 109: * FIXME: Much of the code in the other java.net classes does not make 110: * use of this family field. A better implementation would be to make 111: * use of getaddrinfo() and have other methods just check the family 112: * field rather than examining the length of the address each time. 113: */ 114: int family; 115: 116: /** 117: * Initializes this object's addr instance variable from the passed in 118: * byte array. Note that this constructor is protected and is called 119: * only by static methods in this class. 120: * 121: * @param ipaddr The IP number of this address as an array of bytes 122: * @param hostname The hostname of this IP address. 123: */ 124: InetAddress(byte[] ipaddr, String hostname) 125: { 126: addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone(); 127: hostName = hostname; 128: 129: if (ipaddr != null) 130: family = getFamily(ipaddr); 131: } 132: 133: /** 134: * Returns true if this address is a multicast address, false otherwise. 135: * An address is multicast if the high four bits are "1110". These are 136: * also known as "Class D" addresses. 137: * 138: * @return true if mulitcast, false if not 139: * 140: * @since 1.1 141: */ 142: public boolean isMulticastAddress() 143: { 144: // Mask against high order bits of 1110 145: if (addr.length == 4) 146: return (addr[0] & 0xf0) == 0xe0; 147: 148: // Mask against high order bits of 11111111 149: if (addr.length == 16) 150: return addr [0] == (byte) 0xFF; 151: 152: return false; 153: } 154: 155: /** 156: * Utility routine to check if the InetAddress in a wildcard address 157: * 158: * @since 1.4 159: */ 160: public boolean isAnyLocalAddress() 161: { 162: // This is the IPv4 implementation. 163: // Any class derived from InetAddress should override this. 164: return equals(ANY_IF); 165: } 166: 167: /** 168: * Utility routine to check if the InetAddress is a loopback address 169: * 170: * @since 1.4 171: */ 172: public boolean isLoopbackAddress() 173: { 174: // This is the IPv4 implementation. 175: // Any class derived from InetAddress should override this. 176: return (addr[0] & 0xff) == 0x7f; 177: } 178: 179: /** 180: * Utility routine to check if InetAddress is a link local address 181: * 182: * @since 1.4 183: */ 184: public boolean isLinkLocalAddress() 185: { 186: // This is the IPv4 implementation. 187: // Any class derived from InetAddress should override this. 188: // XXX: This seems to not exist with IPv4 addresses 189: return false; 190: } 191: 192: /** 193: * Utility routine to check if InetAddress is a site local address 194: * 195: * @since 1.4 196: */ 197: public boolean isSiteLocalAddress() 198: { 199: // This is the IPv4 implementation. 200: // Any class derived from InetAddress should override this. 201: 202: // 10.0.0.0/8 203: if ((addr[0] & 0xff) == 0x0a) 204: return true; 205: 206: // 172.16.0.0/12 207: if ((addr[0] & 0xff) == 0xac && (addr[1] & 0xf0) == 0x10) 208: return true; 209: 210: // 192.168.0.0/16 211: if ((addr[0] & 0xff) == 0xc0 && (addr[1] & 0xff) == 0xa8) 212: return true; 213: 214: // XXX: Do we need to check more addresses here ? 215: return false; 216: } 217: 218: /** 219: * Utility routine to check if InetAddress is a global multicast address 220: * 221: * @since 1.4 222: */ 223: public boolean isMCGlobal() 224: { 225: // This is the IPv4 implementation. 226: // Any class derived from InetAddress should override this. 227: // XXX: This seems to not exist with IPv4 addresses 228: return false; 229: } 230: 231: /** 232: * Utility routine to check if InetAddress is a node local multicast address. 233: * 234: * @since 1.4 235: */ 236: public boolean isMCNodeLocal() 237: { 238: // This is the IPv4 implementation. 239: // Any class derived from InetAddress should override this. 240: // XXX: This seems to not exist with IPv4 addresses 241: return false; 242: } 243: 244: /** 245: * Utility routine to check if InetAddress is a link local multicast address. 246: * 247: * @since 1.4 248: */ 249: public boolean isMCLinkLocal() 250: { 251: // This is the IPv4 implementation. 252: // Any class derived from InetAddress should override this. 253: if (! isMulticastAddress()) 254: return false; 255: 256: return ((addr[0] & 0xff) == 0xe0 257: && (addr[1] & 0xff) == 0x00 258: && (addr[2] & 0xff) == 0x00); 259: } 260: 261: /** 262: * Utility routine to check if InetAddress is a site local multicast address. 263: * 264: * @since 1.4 265: */ 266: public boolean isMCSiteLocal() 267: { 268: // This is the IPv4 implementation. 269: // Any class derived from InetAddress should override this. 270: // XXX: This seems to not exist with IPv4 addresses 271: return false; 272: } 273: 274: /** 275: * Utility routine to check if InetAddress is a organization local 276: * multicast address. 277: * 278: * @since 1.4 279: */ 280: public boolean isMCOrgLocal() 281: { 282: // This is the IPv4 implementation. 283: // Any class derived from InetAddress should override this. 284: // XXX: This seems to not exist with IPv4 addresses 285: return false; 286: } 287: 288: /** 289: * Returns the hostname for this address. This will return the IP address 290: * as a String if there is no hostname available for this address 291: * 292: * @return The hostname for this address 293: */ 294: public String getHostName() 295: { 296: if (hostName != null) 297: return hostName; 298: 299: // Lookup hostname and set field. 300: lookup (null, this, false); 301: 302: return hostName; 303: } 304: 305: /** 306: * Returns the canonical hostname represented by this InetAddress 307: * 308: * @since 1.4 309: */ 310: public String getCanonicalHostName() 311: { 312: SecurityManager sm = System.getSecurityManager(); 313: if (sm != null) 314: { 315: try 316: { 317: sm.checkConnect(hostName, -1); 318: } 319: catch (SecurityException e) 320: { 321: return getHostAddress(); 322: } 323: } 324: 325: // Try to find the FDQN now 326: InetAddress address; 327: byte[] ipaddr = getAddress(); 328: 329: if (ipaddr.length == 16) 330: address = new Inet6Address(getAddress(), null); 331: else 332: address = new Inet4Address(getAddress(), null); 333: 334: return address.getHostName(); 335: } 336: 337: /** 338: * Returns the IP address of this object as a byte array. 339: * 340: * @return IP address 341: */ 342: public byte[] getAddress() 343: { 344: // An experiment shows that JDK1.2 returns a different byte array each 345: // time. This makes sense, in terms of security. 346: return (byte[]) addr.clone(); 347: } 348: 349: /* Helper function due to a CNI limitation. */ 350: private static InetAddress[] allocArray (int count) 351: { 352: return new InetAddress [count]; 353: } 354: 355: /* Helper function due to a CNI limitation. */ 356: private static SecurityException checkConnect (String hostname) 357: { 358: SecurityManager s = System.getSecurityManager(); 359: 360: if (s == null) 361: return null; 362: 363: try 364: { 365: s.checkConnect (hostname, -1); 366: return null; 367: } 368: catch (SecurityException ex) 369: { 370: return ex; 371: } 372: } 373: 374: /** 375: * Returns the IP address of this object as a String. The address is in 376: * the dotted octet notation, for example, "127.0.0.1". 377: * 378: * @return The IP address of this object in String form 379: * 380: * @since 1.0.2 381: */ 382: public String getHostAddress() 383: { 384: StringBuffer sb = new StringBuffer(40); 385: 386: int len = addr.length; 387: int i = 0; 388: 389: if (len == 16) 390: { // An IPv6 address. 391: for ( ; ; i += 2) 392: { 393: if (i >= 16) 394: return sb.toString(); 395: 396: int x = ((addr [i] & 0xFF) << 8) | (addr [i + 1] & 0xFF); 397: boolean empty = sb.length() == 0; 398: 399: if (empty) 400: { 401: if (i == 10 && x == 0xFFFF) 402: { // IPv4-mapped IPv6 address. 403: sb.append (":FFFF:"); 404: break; // Continue as IPv4 address; 405: } 406: else if (i == 12) 407: { // IPv4-compatible IPv6 address. 408: sb.append (':'); 409: break; // Continue as IPv4 address. 410: } 411: else if (i > 0) 412: sb.append ("::"); 413: } 414: else 415: sb.append (':'); 416: 417: if (x != 0 || i >= 14) 418: sb.append (Integer.toHexString (x).toUpperCase()); 419: } 420: } 421: 422: for ( ; ; ) 423: { 424: sb.append(addr[i] & 0xff); 425: i++; 426: 427: if (i == len) 428: break; 429: 430: sb.append('.'); 431: } 432: 433: return sb.toString(); 434: } 435: 436: /** 437: * Returns a hash value for this address. Useful for creating hash 438: * tables. Overrides Object.hashCode() 439: * 440: * @return A hash value for this address. 441: */ 442: public int hashCode() 443: { 444: // There hashing algorithm is not specified, but a simple experiment 445: // shows that it is equal to the address, as a 32-bit big-endian integer. 446: int hash = 0; 447: int len = addr.length; 448: int i = len > 4 ? len - 4 : 0; 449: 450: for (; i < len; i++) 451: hash = (hash << 8) | (addr[i] & 0xff); 452: 453: return hash; 454: } 455: 456: /** 457: * Tests this address for equality against another InetAddress. The two 458: * addresses are considered equal if they contain the exact same octets. 459: * This implementation overrides Object.equals() 460: * 461: * @param obj The address to test for equality 462: * 463: * @return true if the passed in object's address is equal to this one's, 464: * false otherwise 465: */ 466: public boolean equals(Object obj) 467: { 468: if (! (obj instanceof InetAddress)) 469: return false; 470: 471: // "The Java Class Libraries" 2nd edition says "If a machine has 472: // multiple names instances of InetAddress for different name of 473: // that same machine are not equal. This is because they have 474: // different host names." This violates the description in the 475: // JDK 1.2 API documentation. A little experimentation 476: // shows that the latter is correct. 477: byte[] addr2 = ((InetAddress) obj).addr; 478: 479: if (addr.length != addr2.length) 480: return false; 481: 482: for (int i = 0; i < addr.length; i++) 483: if (addr[i] != addr2[i]) 484: return false; 485: 486: return true; 487: } 488: 489: /** 490: * Converts this address to a String. This string contains the IP in 491: * dotted decimal form. For example: "127.0.0.1" This method is equivalent 492: * to getHostAddress() and overrides Object.toString() 493: * 494: * @return This address in String form 495: */ 496: public String toString() 497: { 498: String addr = getHostAddress(); 499: String host = (hostName != null) ? hostName : ""; 500: return host + "/" + addr; 501: } 502: 503: /** 504: * Returns an InetAddress object given the raw IP address. 505: * 506: * The argument is in network byte order: the highest order byte of the 507: * address is in getAddress()[0]. 508: * 509: * @param addr The IP address to create the InetAddress object from 510: * 511: * @exception UnknownHostException If IP address has illegal length 512: * 513: * @since 1.4 514: */ 515: public static InetAddress getByAddress(byte[] addr) 516: throws UnknownHostException 517: { 518: return getByAddress(null, addr); 519: } 520: 521: /** 522: * Creates an InetAddress based on the provided host name and IP address. 523: * No name service is checked for the validity of the address. 524: * 525: * @param host The hostname of the InetAddress object to create 526: * @param addr The IP address to create the InetAddress object from 527: * 528: * @exception UnknownHostException If IP address is of illegal length 529: * 530: * @since 1.4 531: */ 532: public static InetAddress getByAddress(String host, byte[] addr) 533: throws UnknownHostException 534: { 535: if (addr.length == 4) 536: return new Inet4Address(addr, host); 537: 538: if (addr.length == 16) 539: return new Inet6Address(addr, host); 540: 541: throw new UnknownHostException("IP address has illegal length"); 542: } 543: 544: /** 545: * If hostname is a valid numeric IP address, return the numeric address. 546: * Otherwise, return null. 547: * 548: * @param hostname the name of the host 549: */ 550: private static native byte[] aton(String hostname); 551: 552: /** 553: * Looks up all addresses of a given host. 554: * 555: * @param hostname the host to lookup 556: * @param ipaddr the IP address to lookup 557: * @param all return all known addresses for one host 558: * 559: * @return an array with all found addresses 560: */ 561: private static native InetAddress[] lookup (String hostname, 562: InetAddress ipaddr, boolean all); 563: 564: /** 565: * Returns tha family type of an IP address. 566: * 567: * @param addr the IP address 568: * 569: * @return the family 570: */ 571: private static native int getFamily (byte[] ipaddr); 572: 573: /** 574: * Returns an InetAddress object representing the IP address of the given 575: * hostname. This name can be either a hostname such as "www.urbanophile.com" 576: * or an IP address in dotted decimal format such as "127.0.0.1". If the 577: * hostname is null or "", the hostname of the local machine is supplied by 578: * default. This method is equivalent to returning the first element in 579: * the InetAddress array returned from GetAllByName. 580: * 581: * @param hostname The name of the desired host, or null for the local 582: * loopback address. 583: * 584: * @return The address of the host as an InetAddress object. 585: * 586: * @exception UnknownHostException If no IP address for the host could 587: * be found 588: * @exception SecurityException If a security manager exists and its 589: * checkConnect method doesn't allow the operation 590: */ 591: public static InetAddress getByName(String hostname) 592: throws UnknownHostException 593: { 594: // If null or the empty string is supplied, the loopback address 595: // is returned. Note that this is permitted without a security check. 596: if (hostname == null || hostname.length() == 0) 597: return loopback; 598: 599: SecurityManager s = System.getSecurityManager(); 600: if (s != null) 601: s.checkConnect(hostname, -1); 602: 603: // Assume that the host string is an IP address 604: byte[] address = aton(hostname); 605: if (address != null) 606: { 607: if (address.length == 4) 608: return new Inet4Address (address, null); 609: else if (address.length == 16) 610: { 611: if ((address [10] == 0xFF) && (address [11] == 0xFF)) 612: { 613: byte[] ip4addr = new byte [4]; 614: ip4addr [0] = address [12]; 615: ip4addr [1] = address [13]; 616: ip4addr [2] = address [14]; 617: ip4addr [3] = address [15]; 618: return new Inet4Address (ip4addr, null); 619: } 620: return new Inet6Address (address, null); 621: } 622: else 623: throw new UnknownHostException ("Address has invalid length"); 624: } 625: 626: // Try to resolve the host by DNS 627: InetAddress result = new InetAddress(null, null); 628: lookup (hostname, result, false); 629: return result; 630: } 631: 632: /** 633: * Returns an array of InetAddress objects representing all the host/ip 634: * addresses of a given host, given the host's name. This name can be 635: * either a hostname such as "www.urbanophile.com" or an IP address in 636: * dotted decimal format such as "127.0.0.1". If the value is null, the 637: * hostname of the local machine is supplied by default. 638: * 639: * @param hostname The name of the desired host, or null for the 640: * local loopback address. 641: * 642: * @return All addresses of the host as an array of InetAddress objects. 643: * 644: * @exception UnknownHostException If no IP address for the host could 645: * be found 646: * @exception SecurityException If a security manager exists and its 647: * checkConnect method doesn't allow the operation 648: */ 649: public static InetAddress[] getAllByName(String hostname) 650: throws UnknownHostException 651: { 652: // If null or the empty string is supplied, the loopback address 653: // is returned. Note that this is permitted without a security check. 654: if (hostname == null || hostname.length() == 0) 655: return new InetAddress[] {loopback}; 656: 657: SecurityManager s = System.getSecurityManager(); 658: if (s != null) 659: s.checkConnect(hostname, -1); 660: 661: // Check if hostname is an IP address 662: byte[] address = aton (hostname); 663: if (address != null) 664: { 665: InetAddress[] result = new InetAddress [1]; 666: result [0] = new InetAddress (address, null); 667: return result; 668: } 669: 670: // Try to resolve the hostname by DNS 671: return lookup (hostname, null, true); 672: } 673: 674: /** 675: * This native method looks up the hostname of the local machine 676: * we are on. If the actual hostname cannot be determined, then the 677: * value "localhost" will be used. This native method wrappers the 678: * "gethostname" function. 679: * 680: * @return The local hostname. 681: */ 682: private static native String getLocalHostname(); 683: 684: /** 685: * Returns an InetAddress object representing the address of the current 686: * host. 687: * 688: * @return The local host's address 689: * 690: * @exception UnknownHostException If no IP address for the host could 691: * be found 692: */ 693: public static InetAddress getLocalHost() throws UnknownHostException 694: { 695: SecurityManager s = System.getSecurityManager(); 696: 697: // Experimentation shows that JDK1.2 does cache the result. 698: // However, if there is a security manager, and the cached result 699: // is other than "localhost", we need to check again. 700: if (localhost == null 701: || (s != null && ! localhost.isLoopbackAddress())) 702: getLocalHost (s); 703: 704: return localhost; 705: } 706: 707: private static synchronized void getLocalHost (SecurityManager s) 708: throws UnknownHostException 709: { 710: // Check the localhost cache again, now that we've synchronized. 711: if (s == null && localhost != null) 712: return; 713: 714: String hostname = getLocalHostname(); 715: 716: if (s != null) 717: { 718: // "The Java Class Libraries" suggests that if the security 719: // manager disallows getting the local host name, then 720: // we use the loopback host. 721: // However, the JDK 1.2 API claims to throw SecurityException, 722: // which seems to suggest SecurityException is *not* caught. 723: // In this case, experimentation shows that former is correct. 724: try 725: { 726: // This is wrong, if the name returned from getLocalHostname() 727: // is not a fully qualified name. FIXME. 728: s.checkConnect (hostname, -1); 729: } 730: catch (SecurityException ex) 731: { 732: hostname = null; 733: } 734: } 735: 736: if (hostname != null && hostname.length() != 0) 737: { 738: try 739: { 740: localhost = new InetAddress (null, null); 741: lookup (hostname, localhost, false); 742: } 743: catch (Exception ex) 744: { 745: } 746: } 747: else 748: throw new UnknownHostException(); 749: 750: if (localhost == null) 751: localhost = new InetAddress (loopbackAddress, "localhost"); 752: } 753: 754: /** 755: * Needed for serialization 756: */ 757: private void readResolve() throws ObjectStreamException 758: { 759: // FIXME: implement this 760: } 761: 762: private void readObject(ObjectInputStream ois) 763: throws IOException, ClassNotFoundException 764: { 765: ois.defaultReadObject(); 766: addr = new byte[4]; 767: addr[3] = (byte) address; 768: 769: for (int i = 2; i >= 0; --i) 770: addr[i] = (byte) (address >>= 8); 771: 772: // Ignore family from serialized data. Since the saved address is 32 bits 773: // the deserialized object will have an IPv4 address i.e. AF_INET family. 774: // FIXME: An alternative is to call the aton method on the deserialized 775: // hostname to get a new address. The Serialized Form doc is silent 776: // on how these fields are used. 777: family = getFamily (addr); 778: } 779: 780: private void writeObject(ObjectOutputStream oos) throws IOException 781: { 782: // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address 783: // or a 16 byte IPv6 address. 784: int len = addr.length; 785: int i = len - 4; 786: 787: for (; i < len; i++) 788: address = address << 8 | (((int) addr[i]) & 0xFF); 789: 790: oos.defaultWriteObject(); 791: } 792: }