home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 17.8 KB | 581 lines |
- /*
- * @(#)InetAddress.java 1.52 98/03/18
- *
- * Copyright 1995-1997 by Sun Microsystems, Inc.,
- * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
- * All rights reserved.
- *
- * This software is the confidential and proprietary information
- * of Sun Microsystems, Inc. ("Confidential Information"). You
- * shall not disclose such Confidential Information and shall use
- * it only in accordance with the terms of the license agreement
- * you entered into with Sun.
- */
-
- package java.net;
-
- import java.util.Hashtable;
-
- /**
- * This class represents an Internet Protocol (IP) address.
- * <p>
- * Applications should use the methods <code>getLocalHost</code>,
- * <code>getByName</code>, or <code>getAllByName</code> to
- * create a new <code>InetAddress</code> instance.
- *
- * @author Chris Warth
- * @version 1.52, 03/18/98
- * @see java.net.InetAddress#getAllByName(java.lang.String)
- * @see java.net.InetAddress#getByName(java.lang.String)
- * @see java.net.InetAddress#getLocalHost()
- * @since JDK1.0
- */
- public final
- class InetAddress implements java.io.Serializable {
-
- String hostName;
- /*
- * Currently we only deal effectively with 32-bit addresses.
- * However this field can be expanded to be a byte array
- * or a 64-bit quantity without too much effort.
- */
- int address;
- int family;
-
- /** use serialVersionUID from JDK 1.0.2 for interoperability */
- private static final long serialVersionUID = 3286316764910316507L;
-
- /*
- * Load net library into runtime, and perform initializations.
- */
- static {
- try {
- java.security.AccessController.beginPrivileged();
- System.loadLibrary("net");
- } finally {
- java.security.AccessController.endPrivileged();
- }
- init();
- }
-
- /**
- * Constructor for the Socket.accept() method.
- * This creates an empty InetAddress, which is filled in by
- * the accept() method. This InetAddress, however, is not
- * put in the address cache, since it is not created by name.
- */
- InetAddress() {
- family = impl.getInetFamily();
- }
-
- /**
- * Creates an InetAddress with the specified host name and IP address.
- * @param hostName the specified host name
- * @param addr the specified IP address. The address is expected in
- * network byte order.
- * @exception UnknownHostException If the address is unknown.
- */
- InetAddress(String hostName, byte addr[]) {
- this.hostName = hostName;
- this.family = impl.getInetFamily();
- /*
- * We must be careful here to maintain the network byte
- * order of the address. As it comes in, the most
- * significant byte of the address is in addr[0]. It
- * actually doesn't matter what order they end up in the
- * array, as long as it is documented and consistent.
- */
- address = addr[3] & 0xFF;
- address |= ((addr[2] << 8) & 0xFF00);
- address |= ((addr[1] << 16) & 0xFF0000);
- address |= ((addr[0] << 24) & 0xFF000000);
- }
-
- /**
- * Utility routine to check if the InetAddress is a
- * IP multicast address. IP multicast address is a Class D
- * address i.e first four bits of the address are 1110.
- * @since JDK1.1
- */
- public boolean isMulticastAddress() {
- return ((address & 0xf0000000) == 0xe0000000);
- }
-
- /**
- * Returns the hostname for this address.
- * If the host is equal to null, then this address refers to any
- * of the local machine's available network addresses.
- *
- * @return the host name for this IP address.
- */
- public String getHostName() {
- return getHostName(true);
- }
-
- /**
- * Returns the hostname for this address.
- * If the host is equal to null, then this address refers to any
- * of the local machine's available network addresses.
- * this is package private so SocketPermission can make calls into
- * here without a security check.
- *
- * @return the host name for this IP address.
- * @param check make security check if true
- */
- String getHostName(boolean check) {
- if (hostName == null) {
- try {
- // first lookup the hostname
- hostName = impl.getHostByAddr(address);
-
- /* check to see if calling code is allowed to know
- * the hostname for this IP address, ie, connect to the host
- */
- if (check) {
- SecurityManager sec = System.getSecurityManager();
- if (sec != null) {
- sec.checkConnect(hostName, -1);
- }
- }
-
- /* now get all the IP addresses for this hostname,
- * and make sure one of them matches the original IP
- * address. We do this to try and prevent spoofing.
- */
-
- InetAddress[] arr = getAllByName0(hostName, check);
- boolean ok = false;
-
- if(arr != null) {
- for(int i = 0; !ok && i < arr.length; i++) {
- //System.out.println("check "+this+" "+arr[i]);
- ok = (address == arr[i].address);
- }
- }
-
- //XXX: if it looks a spoof just return the address?
- if (!ok) {
- hostName = getHostAddress();
- return getHostAddress();
- }
-
- } catch (SecurityException e) {
- hostName = getHostAddress();
- } catch (UnknownHostException e) {
- hostName = getHostAddress();
- }
- }
- return hostName;
- }
-
- /**
- * Returns the raw IP address of this <code>InetAddress</code>
- * object. The result is in network byte order: the highest order
- * byte of the address is in <code>getAddress()[0]</code>.
- *
- * @return the raw IP address of this object.
- */
- public byte[] getAddress() {
- byte[] addr = new byte[4];
-
- addr[0] = (byte) ((address >>> 24) & 0xFF);
- addr[1] = (byte) ((address >>> 16) & 0xFF);
- addr[2] = (byte) ((address >>> 8) & 0xFF);
- addr[3] = (byte) (address & 0xFF);
- return addr;
- }
-
- /**
- * Returns the IP address string "%d.%d.%d.%d".
- *
- * @return the raw IP address in a string format.
- * @since JDK1.0.2
- */
- public String getHostAddress() {
- return ((address >>> 24) & 0xFF) + "." +
- ((address >>> 16) & 0xFF) + "." +
- ((address >>> 8) & 0xFF) + "." +
- ((address >>> 0) & 0xFF);
- }
-
-
- /**
- * Returns a hashcode for this IP address.
- *
- * @return a hash code value for this IP address.
- */
- public int hashCode() {
- return address;
- }
-
- /**
- * Compares this object against the specified object.
- * The result is <code>true</code> if and only if the argument is
- * not <code>null</code> and it represents the same IP address as
- * this object.
- * <p>
- * Two instances of <code>InetAddress</code> represent the same IP
- * address if the length of the byte arrays returned by
- * <code>getAddress</code> is the same for both, and each of the
- * array components is the same for the byte arrays.
- *
- * @param obj the object to compare against.
- * @return <code>true</code> if the objects are the same;
- * <code>false</code> otherwise.
- * @see java.net.InetAddress#getAddress()
- */
- public boolean equals(Object obj) {
- return (obj != null) && (obj instanceof InetAddress) &&
- (((InetAddress)obj).address == address);
- }
-
- /**
- * Converts this IP address to a <code>String</code>.
- *
- * @return a string representation of this IP address.
- */
- public String toString() {
- return getHostName() + "/" + getHostAddress();
- }
-
- /*
- * Cached addresses - our own litle nis, not!
- *
- * Do not purge cache of numerical IP addresses, since
- * duplicate dynamic DNS name lookups can leave the system
- * vulnerable to hostname spoofing attacks. Once a hostname
- * has been looked up in DNS and entered into the Java cache,
- * from then on, the hostname is translated to IP address only
- * via the cache.
- */
- static Hashtable addressCache = new Hashtable();
- static InetAddress unknownAddress;
- static InetAddress anyLocalAddress;
- static InetAddress localHost;
- static InetAddress[] unknown_array; // put THIS in cache
- static InetAddressImpl impl;
-
- /*
- * generic localHost to give back to applets
- * - private so not API delta
- */
- private static InetAddress loopbackHost;
-
- static {
-
- /*
- * Property "impl.prefix" will be prepended to the classname
- * of the implementation object we instantiate, to which we
- * delegate the real work (like native methods). This
- * property can vary across implementations of the java.
- * classes. The default is an empty String "".
- */
- String prefix = null;
-
- try {
- java.security.AccessController.beginPrivileged();
- prefix = System.getProperty("impl.prefix", "");
- } finally {
- java.security.AccessController.endPrivileged();
- }
- try {
- impl = null;
- impl = (InetAddressImpl)(Class.forName("java.net." + prefix +
- "InetAddressImpl")
- .newInstance());
- } catch (ClassNotFoundException e) {
- System.err.println("Class not found: java.net." + prefix +
- "InetAddressImpl:\ncheck impl.prefix property " +
- "in your properties file.");
- } catch (InstantiationException e) {
- System.err.println("Could not instantiate: java.net." + prefix +
- "InetAddressImpl:\ncheck impl.prefix property " +
- "in your properties file.");
- } catch (IllegalAccessException e) {
- System.err.println("Cannot access class: java.net." + prefix +
- "InetAddressImpl:\ncheck impl.prefix property " +
- "in your properties file.");
- }
-
- if (impl == null) {
- try {
- impl = (InetAddressImpl)(Class.forName("java.net.InetAddressImpl")
- .newInstance());
- } catch (Exception e) {
- throw new Error("System property impl.prefix incorrect");
- }
- }
-
- unknownAddress = new InetAddress();
- anyLocalAddress = new InetAddress();
- impl.makeAnyLocalAddress(anyLocalAddress);
- byte[] IP = new byte[4];
- IP[0] = 0x7F;
- IP[1] = 0x00;
- IP[2] = 0x00;
- IP[3] = 0x01;
- loopbackHost = new InetAddress("localhost", IP);
-
- /* find the local host name */
- try {
- localHost = new InetAddress();
- localHost.hostName = impl.getLocalHostName();
- /* we explicitly leave the address of the local host
- * uninitialized. A DNS lookup in this, the static
- * initializer, will cause a machine disconnected
- * from the network to hang - it'll be trying to query
- * a DNS server that isn't there.
- *
- * Instead, we just get the hostname of the local host.
- * The native code for this just calls gethostname()
- * which should be pretty innocuous - it shouldn't try
- * to contact a DNS server. If any application
- * calls InetAddress.getLocalHost(), we initialize
- * the local host's address there if not already initialized.
- *
- * Note that for this to work it is also essential that
- * the localHost InetAddress is _NOT_ put into the address cache
- * here in the static initializer (which happens if we call
- * getByName() from the static initializer). It _IS_ OK
- * to put it in the addressCache after initialization.
- *
- * The unitialized state of the localHost's address is -1,
- * or IP address 255.255.255.255 which we know cannot be
- * a legal host address.
- */
- localHost.address = -1;
- } catch (Exception ex) { /* this shouldn't happen */
- localHost = unknownAddress;
- }
-
- /* cache the name/address pair "0.0.0.0"/0.0.0.0 */
- String unknownByAddr = "0.0.0.0";
- unknown_array = new InetAddress[1];
- unknown_array[0] = new InetAddress(unknownByAddr,
- unknownAddress.getAddress());
- addressCache.put(unknownByAddr, unknown_array);
- }
-
- /**
- * Determines the IP address of a host, given the host's name. The
- * host name can either be a machine name, such as
- * "<code>java.sun.com</code>", or a string representing its IP
- * address, such as "<code>206.26.48.100</code>".
- *
- * @param host the specified host, or <code>null</code> for the
- * local host.
- * @return an IP address for the given host name.
- * @exception UnknownHostException if no IP address for the
- * <code>host</code> could be found.
- */
- public static InetAddress getByName(String host)
- throws UnknownHostException {
- Object obj = null;
- if (host == null || host.length() == 0) {
- return loopbackHost;
- }
-
- if (!Character.isDigit(host.charAt(0))) {
- return getAllByName0(host)[0];
- } else {
- /* The string (probably) represents a numerical IP address.
- * Parse it into an int, don't do uneeded reverese lookup,
- * leave hostName null, don't cache. If it isn't an IP address,
- * (i.e., not "%d.%d.%d.%d") or if any element > 0xFF,
- * we treat it as a hostname, and lookup that way.
- * This seems to be 100% compliant to the RFC1123 spec:
- * a partial hostname like 3com.domain4 is technically valid.
- */
-
- int IP = 0x00;
- int hitDots = 0;
- char[] data = host.toCharArray();
-
- for(int i = 0; i < data.length; i++) {
- char c = data[i];
- if (c < 48 || c > 57) { // !digit
- return getAllByName0(host)[0];
- }
- int b = 0x00;
- while(c != '.') {
- if (c < 48 || c > 57) { // !digit
- return getAllByName0(host)[0];
- }
- b = b*10 + c - '0';
-
- if (++i >= data.length)
- break;
- c = data[i];
- }
- if(b > 0xFF) { /* bogus - bigger than a byte */
- return getAllByName0(host)[0];
- }
- IP = (IP << 8) + b;
- hitDots++;
- }
-
- if(hitDots != 4 || host.endsWith(".")) {
- return getAllByName0(host)[0];
- }
-
- InetAddress in = new InetAddress();
- in.address = IP;
- in.hostName = null;
- return in;
- }
-
- }
-
- /**
- * Determines all the IP addresses of a host, given the host's name.
- * The host name can either be a machine name, such as
- * "<code>java.sun.com</code>", or a string representing
- * its IP address, such as "<code>206.26.48.100</code>".
- *
- * @param host the name of the host.
- * @return an array of all the IP addresses for a given host name.
- * @exception UnknownHostException if no IP address for the
- * <code>host</code> could be found.
- */
- public static InetAddress getAllByName(String host)[]
- throws UnknownHostException {
-
- if (host == null || host.length() == 0) {
- throw new UnknownHostException("empty string");
- }
-
- if(Character.isDigit(host.charAt(0))) {
- InetAddress[] ret = new InetAddress[1];
- ret[0] = getByName(host);
- return ret;
- } else {
- return getAllByName0(host);
- }
- }
-
- private static InetAddress[] getAllByName0 (String host)
- throws UnknownHostException
- {
- return getAllByName0(host, true);
- }
-
- /**
- * package private so SocketPermission can call it
- */
- static InetAddress[] getAllByName0 (String host, boolean check)
- throws UnknownHostException {
- /* If it gets here it is presumed to be a hostname */
- /* Cache.get can return: null, unknownAddress, or InetAddress[] */
- Object obj = null;
- Object objcopy = null;
-
- /* make sure the connection to the host is allowed, before we
- * give out a hostname
- */
- if (check) {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- security.checkConnect(host, -1);
- }
- }
-
- synchronized (addressCache) {
- obj = addressCache.get(host);
-
- /* If no entry in cache, then do the host lookup */
-
- if (obj == null) {
- try {
- /*
- * Do not put the call to lookup() inside the
- * constructor. if you do you will still be
- * allocating space when the lookup fails.
- */
- byte[][] byte_array = impl.lookupAllHostAddr(host);
- InetAddress[] addr_array =
- new InetAddress[byte_array.length];
-
- for (int i = 0; i < byte_array.length; i++) {
- byte addr[] = byte_array[i];
- addr_array[i] = new InetAddress(host, addr);
- }
- obj = addr_array;
- } catch (UnknownHostException e) {
- obj = unknown_array;
- }
- addressCache.put(host, obj);
- }
- } /* end synchronized block */
-
- if (obj == unknown_array) {
- /*
- * We currently cache the fact that a host is unknown.
- */
- throw new UnknownHostException(host);
- }
-
- /* Make a copy of the InetAddress array */
- try {
- objcopy = ((InetAddress [])obj).clone();
- // the following line is a hack, to ensure that the code
- // can compile for both the broken compiler and the fixed one.
- if (objcopy == null)
- throw new CloneNotSupportedException();
- } catch (CloneNotSupportedException cnse) {
- cnse.printStackTrace();
- }
-
- return (InetAddress [])objcopy;
- }
-
- /**
- * Returns the local host.
- *
- * @return the IP address of the local host.
- * @exception UnknownHostException if no IP address for the
- * <code>host</code> could be found.
- */
- public static InetAddress getLocalHost() throws UnknownHostException {
- if (localHost.equals(unknownAddress)) {
- throw new UnknownHostException();
- }
-
- /* make sure the connection to the host is allowed: if yes,
- * return the "real" localHost; if not, return loopback "127.0.0.1"
- */
- SecurityManager security = System.getSecurityManager();
- try {
-
- /* If the localhost's address is not initialized yet, initialize
- * it. It is no longer initialized in the static initializer
- * (see comment there).
- */
-
- if (localHost.address == -1) {
- localHost = getAllByName(localHost.hostName)[0];
- /* This puts it in the address cache as well */
- }
-
- if (security != null)
- security.checkConnect(localHost.getHostName(), -1);
- } catch (java.lang.SecurityException e) {
- return loopbackHost;
- }
- return localHost;
- }
-
- /**
- * Perform class load-time initializations.
- */
- private static native void init();
- }
-
- class InetAddressImpl {
- native String getLocalHostName() throws UnknownHostException;
- native void makeAnyLocalAddress(InetAddress addr);
- native byte[][]
- lookupAllHostAddr(String hostname) throws UnknownHostException;
- native String getHostByAddr(int addr) throws UnknownHostException;
- native int getInetFamily();
- }
-