home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / net / InetAddress.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  17.8 KB  |  581 lines

  1. /*
  2.  * @(#)InetAddress.java    1.52 98/03/18
  3.  *
  4.  * Copyright 1995-1997 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.net;
  16.  
  17. import java.util.Hashtable;
  18.  
  19. /**
  20.  * This class represents an Internet Protocol (IP) address. 
  21.  * <p>
  22.  * Applications should use the methods <code>getLocalHost</code>, 
  23.  * <code>getByName</code>, or <code>getAllByName</code> to 
  24.  * create a new <code>InetAddress</code> instance. 
  25.  *
  26.  * @author  Chris Warth
  27.  * @version 1.52, 03/18/98
  28.  * @see     java.net.InetAddress#getAllByName(java.lang.String)
  29.  * @see     java.net.InetAddress#getByName(java.lang.String)
  30.  * @see     java.net.InetAddress#getLocalHost()
  31.  * @since   JDK1.0
  32.  */
  33. public final 
  34. class InetAddress implements java.io.Serializable {
  35.  
  36.     String hostName;
  37.     /* 
  38.      * Currently we only deal effectively with 32-bit addresses. 
  39.      * However this field can be expanded to be a byte array 
  40.      * or a 64-bit quantity without too much effort.
  41.      */
  42.     int address;
  43.     int family;
  44.  
  45.     /** use serialVersionUID from JDK 1.0.2 for interoperability */
  46.     private static final long serialVersionUID = 3286316764910316507L;
  47.  
  48.     /*
  49.      * Load net library into runtime, and perform initializations.  
  50.      */
  51.     static {
  52.     try {
  53.         java.security.AccessController.beginPrivileged();
  54.         System.loadLibrary("net");
  55.     } finally {
  56.         java.security.AccessController.endPrivileged();
  57.     }
  58.         init();
  59.     }
  60.  
  61.     /** 
  62.      * Constructor for the Socket.accept() method.
  63.      * This creates an empty InetAddress, which is filled in by
  64.      * the accept() method.  This InetAddress, however, is not
  65.      * put in the address cache, since it is not created by name.
  66.      */
  67.     InetAddress() {
  68.       family = impl.getInetFamily();
  69.     }
  70.  
  71.     /**
  72.      * Creates an InetAddress with the specified host name and IP address.
  73.      * @param hostName the specified host name
  74.      * @param addr the specified IP address.  The address is expected in 
  75.      *          network byte order.
  76.      * @exception UnknownHostException If the address is unknown.
  77.      */
  78.     InetAddress(String hostName, byte addr[]) {
  79.     this.hostName = hostName;
  80.     this.family = impl.getInetFamily();
  81.     /*
  82.      * We must be careful here to maintain the network byte
  83.      * order of the address.  As it comes in, the most
  84.      * significant byte of the address is in addr[0].  It
  85.      * actually doesn't matter what order they end up in the
  86.      * array, as long as it is documented and consistent.
  87.      */
  88.     address  = addr[3] & 0xFF;
  89.     address |= ((addr[2] << 8) & 0xFF00);
  90.     address |= ((addr[1] << 16) & 0xFF0000);
  91.     address |= ((addr[0] << 24) & 0xFF000000);
  92.     }
  93.  
  94.     /**
  95.      * Utility routine to check if the InetAddress is a 
  96.      * IP multicast address. IP multicast address is a Class D
  97.      * address i.e first four bits of the address are 1110.
  98.      * @since   JDK1.1
  99.      */
  100.     public boolean isMulticastAddress() {
  101.     return ((address & 0xf0000000) == 0xe0000000);
  102.     }
  103.  
  104.     /**
  105.      * Returns the hostname for this address.
  106.      * If the host is equal to null, then this address refers to any
  107.      * of the local machine's available network addresses.
  108.      *
  109.      * @return  the host name for this IP address.
  110.      */
  111.     public String getHostName() {
  112.     return getHostName(true);
  113.     }
  114.  
  115.     /**
  116.      * Returns the hostname for this address.
  117.      * If the host is equal to null, then this address refers to any
  118.      * of the local machine's available network addresses.
  119.      * this is package private so SocketPermission can make calls into
  120.      * here without a security check.
  121.      *
  122.      * @return  the host name for this IP address.
  123.      * @param check make security check if true
  124.      */
  125.     String getHostName(boolean check) {
  126.     if (hostName == null) {
  127.         try {
  128.         // first lookup the hostname
  129.         hostName = impl.getHostByAddr(address);
  130.  
  131.         /* check to see if calling code is allowed to know
  132.          * the hostname for this IP address, ie, connect to the host
  133.          */
  134.         if (check) {
  135.             SecurityManager sec = System.getSecurityManager();
  136.             if (sec != null) {
  137.             sec.checkConnect(hostName, -1);
  138.             }
  139.         }
  140.  
  141.         /* now get all the IP addresses for this hostname,
  142.          * and make sure one of them matches the original IP 
  143.          * address. We do this to try and prevent spoofing.
  144.          */
  145.  
  146.         InetAddress[] arr = getAllByName0(hostName, check);
  147.         boolean ok = false;
  148.  
  149.         if(arr != null) {
  150.             for(int i = 0; !ok && i < arr.length; i++) {
  151.             //System.out.println("check "+this+" "+arr[i]);
  152.             ok = (address == arr[i].address);
  153.             }
  154.         }
  155.  
  156.         //XXX: if it looks a spoof just return the address?
  157.         if (!ok) {
  158.             hostName = getHostAddress();
  159.             return getHostAddress();
  160.         }
  161.  
  162.         } catch (SecurityException e) {
  163.         hostName = getHostAddress();
  164.         } catch (UnknownHostException e) {
  165.         hostName = getHostAddress();
  166.         }
  167.     }
  168.     return hostName;
  169.     }
  170.  
  171.     /**
  172.      * Returns the raw IP address of this <code>InetAddress</code> 
  173.      * object. The result is in network byte order: the highest order 
  174.      * byte of the address is in <code>getAddress()[0]</code>. 
  175.      *
  176.      * @return  the raw IP address of this object.
  177.      */
  178.     public byte[] getAddress() {    
  179.     byte[] addr = new byte[4];
  180.  
  181.     addr[0] = (byte) ((address >>> 24) & 0xFF);
  182.     addr[1] = (byte) ((address >>> 16) & 0xFF);
  183.     addr[2] = (byte) ((address >>> 8) & 0xFF);
  184.     addr[3] = (byte) (address & 0xFF);
  185.     return addr;
  186.     }
  187.  
  188.     /**
  189.      * Returns the IP address string "%d.%d.%d.%d".
  190.      *
  191.      * @return  the raw IP address in a string format.
  192.      * @since   JDK1.0.2
  193.      */
  194.     public String getHostAddress() {    
  195.          return ((address >>> 24) & 0xFF) + "." +
  196.                 ((address >>> 16) & 0xFF) + "." +
  197.                 ((address >>>  8) & 0xFF) + "." +
  198.                 ((address >>>  0) & 0xFF);
  199.      }
  200.  
  201.  
  202.     /**
  203.      * Returns a hashcode for this IP address.
  204.      *
  205.      * @return  a hash code value for this IP address. 
  206.      */
  207.     public int hashCode() {
  208.     return address;
  209.     }
  210.  
  211.     /**
  212.      * Compares this object against the specified object.
  213.      * The result is <code>true</code> if and only if the argument is 
  214.      * not <code>null</code> and it represents the same IP address as 
  215.      * this object. 
  216.      * <p>
  217.      * Two instances of <code>InetAddress</code> represent the same IP 
  218.      * address if the length of the byte arrays returned by 
  219.      * <code>getAddress</code> is the same for both, and each of the 
  220.      * array components is the same for the byte arrays. 
  221.      *
  222.      * @param   obj   the object to compare against.
  223.      * @return  <code>true</code> if the objects are the same;
  224.      *          <code>false</code> otherwise.
  225.      * @see     java.net.InetAddress#getAddress()
  226.      */
  227.     public boolean equals(Object obj) {
  228.     return (obj != null) && (obj instanceof InetAddress) &&
  229.         (((InetAddress)obj).address == address);
  230.     }
  231.  
  232.     /**
  233.      * Converts this IP address to a <code>String</code>.
  234.      *
  235.      * @return  a string representation of this IP address.
  236.      */
  237.     public String toString() {
  238.     return getHostName() + "/" + getHostAddress();
  239.     }
  240.  
  241.     /* 
  242.      * Cached addresses - our own litle nis, not! 
  243.      *
  244.      * Do not purge cache of numerical IP addresses, since 
  245.      * duplicate dynamic DNS name lookups can leave the system
  246.      * vulnerable to hostname spoofing attacks.  Once a hostname
  247.      * has been looked up in DNS and entered into the Java cache, 
  248.      * from then on, the hostname is translated to IP address only
  249.      * via the cache.
  250.      */
  251.     static Hashtable        addressCache = new Hashtable();
  252.     static InetAddress        unknownAddress;
  253.     static InetAddress        anyLocalAddress;
  254.     static InetAddress      localHost;
  255.     static InetAddress[]    unknown_array; // put THIS in cache
  256.     static InetAddressImpl  impl;
  257.  
  258.     /* 
  259.      * generic localHost to give back to applets 
  260.      * - private so not API delta
  261.      */
  262.     private static InetAddress      loopbackHost;
  263.  
  264.     static {
  265.  
  266.     /*
  267.      * Property "impl.prefix" will be prepended to the classname
  268.      * of the implementation object we instantiate, to which we
  269.      * delegate the real work (like native methods).  This
  270.      * property can vary across implementations of the java.
  271.      * classes.  The default is an empty String "".  
  272.      */
  273.     String prefix = null;
  274.  
  275.     try {
  276.         java.security.AccessController.beginPrivileged();
  277.         prefix = System.getProperty("impl.prefix", "");
  278.     } finally {
  279.         java.security.AccessController.endPrivileged();
  280.     }
  281.     try {
  282.         impl = null;
  283.         impl = (InetAddressImpl)(Class.forName("java.net." + prefix + 
  284.                            "InetAddressImpl")
  285.                      .newInstance());
  286.     } catch (ClassNotFoundException e) {
  287.         System.err.println("Class not found: java.net." + prefix + 
  288.                    "InetAddressImpl:\ncheck impl.prefix property " +
  289.                    "in your properties file.");
  290.     } catch (InstantiationException e) {
  291.         System.err.println("Could not instantiate: java.net." + prefix + 
  292.                    "InetAddressImpl:\ncheck impl.prefix property " +
  293.                    "in your properties file.");
  294.     } catch (IllegalAccessException e) {
  295.         System.err.println("Cannot access class: java.net." + prefix + 
  296.                    "InetAddressImpl:\ncheck impl.prefix property " +
  297.                    "in your properties file.");
  298.     }
  299.  
  300.     if (impl == null) {
  301.         try {
  302.         impl = (InetAddressImpl)(Class.forName("java.net.InetAddressImpl")
  303.                      .newInstance());
  304.         } catch (Exception e) {
  305.         throw new Error("System property impl.prefix incorrect");
  306.         }
  307.     }
  308.  
  309.     unknownAddress = new InetAddress();
  310.     anyLocalAddress = new InetAddress();
  311.     impl.makeAnyLocalAddress(anyLocalAddress);
  312.     byte[] IP = new byte[4];
  313.     IP[0] = 0x7F;
  314.     IP[1] = 0x00;
  315.     IP[2] = 0x00;
  316.     IP[3] = 0x01;
  317.     loopbackHost = new InetAddress("localhost", IP);
  318.  
  319.     /* find the local host name */
  320.     try {
  321.         localHost = new InetAddress();
  322.         localHost.hostName = impl.getLocalHostName();
  323.         /* we explicitly leave the address of the local host
  324.          * uninitialized.  A DNS lookup in this, the static
  325.          * initializer, will cause a machine disconnected
  326.          * from the network to hang - it'll be trying to query
  327.          * a DNS server that isn't there.
  328.          *
  329.          * Instead, we just get the hostname of the local host.
  330.          * The native code for this just calls gethostname()
  331.          * which should be pretty innocuous - it shouldn't try
  332.          * to contact a DNS server.  If any application
  333.          * calls InetAddress.getLocalHost(), we initialize
  334.          * the local host's address there if not already initialized.
  335.          *
  336.          * Note that for this to work it is also essential that
  337.          * the localHost InetAddress is _NOT_ put into the address cache
  338.          * here in the static initializer (which happens if we call
  339.          * getByName() from the static initializer).  It _IS_ OK
  340.          * to put it in the addressCache after initialization.
  341.          *
  342.          * The unitialized state of the localHost's address is -1,
  343.          * or IP address 255.255.255.255 which we know cannot be
  344.          * a legal host address.
  345.          */
  346.         localHost.address = -1;
  347.     } catch (Exception ex) { /* this shouldn't happen */
  348.         localHost = unknownAddress;
  349.     }
  350.  
  351.     /* cache the name/address pair "0.0.0.0"/0.0.0.0 */
  352.     String unknownByAddr = "0.0.0.0";
  353.     unknown_array = new InetAddress[1];
  354.     unknown_array[0] = new InetAddress(unknownByAddr, 
  355.                        unknownAddress.getAddress());
  356.     addressCache.put(unknownByAddr, unknown_array);
  357.     }
  358.  
  359.     /**
  360.      * Determines the IP address of a host, given the host's name. The 
  361.      * host name can either be a machine name, such as 
  362.      * "<code>java.sun.com</code>", or a string representing its IP 
  363.      * address, such as "<code>206.26.48.100</code>". 
  364.      *
  365.      * @param      host   the specified host, or <code>null</code> for the
  366.      *                    local host.
  367.      * @return     an IP address for the given host name.
  368.      * @exception  UnknownHostException  if no IP address for the
  369.      *               <code>host</code> could be found.
  370.      */
  371.     public static InetAddress getByName(String host)
  372.     throws UnknownHostException {
  373.     Object obj = null;
  374.     if (host == null || host.length() == 0) {
  375.         return loopbackHost;
  376.     }
  377.  
  378.         if (!Character.isDigit(host.charAt(0))) {
  379.         return getAllByName0(host)[0];
  380.     } else {
  381.         /* The string (probably) represents a numerical IP address.
  382.          * Parse it into an int, don't do uneeded reverese lookup,
  383.          * leave hostName null, don't cache.  If it isn't an IP address,
  384.          * (i.e., not "%d.%d.%d.%d") or if any element > 0xFF, 
  385.          * we treat it as a hostname, and lookup that way.
  386.          * This seems to be 100% compliant to the RFC1123 spec: 
  387.          * a partial hostname like 3com.domain4 is technically valid.
  388.          */
  389.  
  390.         int IP = 0x00;
  391.         int hitDots = 0;
  392.         char[] data = host.toCharArray();
  393.  
  394.         for(int i = 0; i < data.length; i++) {
  395.         char c = data[i];
  396.         if (c < 48 || c > 57) { // !digit
  397.             return getAllByName0(host)[0];
  398.         }
  399.         int b = 0x00;
  400.         while(c != '.') {
  401.             if (c < 48 || c > 57) { // !digit
  402.             return getAllByName0(host)[0];
  403.             }
  404.             b = b*10 + c - '0';
  405.  
  406.             if (++i >= data.length)
  407.             break;
  408.             c = data[i];
  409.         }
  410.         if(b > 0xFF) { /* bogus - bigger than a byte */
  411.             return getAllByName0(host)[0];
  412.         }
  413.         IP = (IP << 8) + b;
  414.         hitDots++;
  415.         }
  416.  
  417.         if(hitDots != 4 || host.endsWith(".")) {
  418.         return getAllByName0(host)[0];
  419.         }
  420.  
  421.         InetAddress in = new InetAddress();
  422.         in.address = IP;
  423.         in.hostName = null;
  424.         return in;
  425.     }
  426.  
  427.     }
  428.  
  429.     /** 
  430.      * Determines all the IP addresses of a host, given the host's name. 
  431.      * The host name can either be a machine name, such as 
  432.      * "<code>java.sun.com</code>", or a string representing 
  433.      * its IP address, such as "<code>206.26.48.100</code>". 
  434.      *
  435.      * @param      host   the name of the host.
  436.      * @return     an array of all the IP addresses for a given host name.
  437.      * @exception  UnknownHostException  if no IP address for the
  438.      *               <code>host</code> could be found.
  439.      */
  440.     public static InetAddress getAllByName(String host)[]
  441.     throws UnknownHostException {
  442.  
  443.     if (host == null || host.length() == 0) {
  444.         throw new UnknownHostException("empty string");
  445.     }
  446.  
  447.     if(Character.isDigit(host.charAt(0))) {
  448.         InetAddress[] ret = new InetAddress[1];
  449.         ret[0] = getByName(host);
  450.         return ret;
  451.     } else {
  452.         return getAllByName0(host);
  453.     }
  454.     }
  455.  
  456.     private static InetAddress[] getAllByName0 (String host) 
  457.     throws UnknownHostException  
  458.     {
  459.     return getAllByName0(host, true);
  460.     }
  461.  
  462.     /** 
  463.      * package private so SocketPermission can call it
  464.      */
  465.     static InetAddress[] getAllByName0 (String host, boolean check) 
  466.     throws UnknownHostException  {
  467.     /* If it gets here it is presumed to be a hostname */
  468.     /* Cache.get can return: null, unknownAddress, or InetAddress[] */
  469.         Object obj = null;
  470.     Object objcopy = null;
  471.  
  472.     /* make sure the connection to the host is allowed, before we
  473.      * give out a hostname
  474.      */
  475.     if (check) {
  476.         SecurityManager security = System.getSecurityManager();
  477.         if (security != null) {
  478.         security.checkConnect(host, -1);
  479.         }
  480.     }
  481.  
  482.     synchronized (addressCache) {
  483.         obj = addressCache.get(host);
  484.  
  485.     /* If no entry in cache, then do the host lookup */
  486.     
  487.         if (obj == null) {
  488.         try {
  489.             /*
  490.              * Do not put the call to lookup() inside the
  491.              * constructor.  if you do you will still be
  492.              * allocating space when the lookup fails.
  493.              */
  494.             byte[][] byte_array = impl.lookupAllHostAddr(host);
  495.             InetAddress[] addr_array = 
  496.             new InetAddress[byte_array.length];
  497.  
  498.             for (int i = 0; i < byte_array.length; i++) {
  499.             byte addr[] = byte_array[i];
  500.             addr_array[i] = new InetAddress(host, addr);
  501.             }
  502.             obj = addr_array;
  503.         } catch (UnknownHostException e) {
  504.             obj  = unknown_array;
  505.         }
  506.         addressCache.put(host, obj);
  507.         }
  508.     } /* end synchronized block */
  509.  
  510.     if (obj == unknown_array) {
  511.         /*
  512.          * We currently cache the fact that a host is unknown.
  513.          */
  514.         throw new UnknownHostException(host);
  515.     }
  516.  
  517.     /* Make a copy of the InetAddress array */
  518.     try {
  519.           objcopy = ((InetAddress [])obj).clone();
  520.           // the following line is a hack, to ensure that the code
  521.           // can compile for both the broken compiler and the fixed one.
  522.           if (objcopy == null) 
  523.           throw new CloneNotSupportedException();
  524.     } catch (CloneNotSupportedException cnse) {
  525.           cnse.printStackTrace();
  526.     }
  527.  
  528.     return (InetAddress [])objcopy;
  529.     }
  530.  
  531.     /**
  532.      * Returns the local host.
  533.      *
  534.      * @return     the IP address of the local host.
  535.      * @exception  UnknownHostException  if no IP address for the
  536.      *               <code>host</code> could be found.
  537.      */
  538.     public static InetAddress getLocalHost() throws UnknownHostException {
  539.         if (localHost.equals(unknownAddress)) {
  540.         throw new UnknownHostException();
  541.     }
  542.  
  543.         /* make sure the connection to the host is allowed: if yes,
  544.      * return the "real" localHost; if not, return loopback "127.0.0.1"   
  545.      */
  546.     SecurityManager security = System.getSecurityManager();
  547.     try {
  548.  
  549.         /* If the localhost's address is not initialized yet, initialize
  550.          * it.  It is no longer initialized in the static initializer 
  551.          * (see comment there).
  552.          */
  553.  
  554.         if (localHost.address == -1) {
  555.         localHost = getAllByName(localHost.hostName)[0];
  556.         /* This puts it in the address cache as well */
  557.         }
  558.  
  559.         if (security != null) 
  560.         security.checkConnect(localHost.getHostName(), -1);
  561.     } catch (java.lang.SecurityException e) {
  562.         return loopbackHost;
  563.     }
  564.     return localHost;
  565.     }
  566.  
  567.     /**
  568.      * Perform class load-time initializations.
  569.      */
  570.     private static native void init();
  571. }
  572.  
  573. class InetAddressImpl {
  574.     native String getLocalHostName() throws UnknownHostException;
  575.     native void makeAnyLocalAddress(InetAddress addr);
  576.     native byte[][]
  577.         lookupAllHostAddr(String hostname) throws UnknownHostException;
  578.     native String getHostByAddr(int addr) throws UnknownHostException;
  579.     native int getInetFamily();
  580. }
  581.