The InetAddress Class

The java.net.InetAddress class is Java’s encapsulation of an IP address. It is used by most of the other networking classes, including Socket, ServerSocket, URL, DatagramSocket, DatagramPacket, and more.

public final class InetAddress extends Object implements Serializable

This class represents an Internet address as two fields: hostName (a String) and address (an int). hostName contains the name of the host; for example, www.oreilly.com. address contains the 32-bit IP address. These fields are not public, so you can’t access them directly. It will probably be necessary to change this representation to a byte array when 16-byte IPv6 addresses come into use. However, if you always use the InetAddress class to represent addresses, the changeover should not affect you; the class shields you from the details of how addresses are implemented.

Creating New InetAddress Objects

There are no public constructors in the InetAddress class. However, InetAddress has three static methods that return suitably initialized InetAddress objects, given a little information. They are:

public static InetAddress InetAddress.getByName(String hostName) 
 throws UnknownHostException
public static InetAddress[] InetAddress.getAllByName(String hostName) 
 throws UnknownHostException
public static InetAddress InetAddress.getLocalHost(  ) 
 throws UnknownHostException

All three of these may make a connection to the local DNS server to fill out the information in the InetAddress object. This has a number of possibly unexpected implications, among them that these methods may throw security exceptions if the connection to the DNS server is prohibited. Furthermore, invoking one of these methods may cause a host that uses a dialup PPP or SLIP connection to dial into its provider if it isn’t already connected. The key thing to remember is that these are not constructors; they do not simply use their arguments to set the internal fields. They actually make network connections to retrieve all the information they need. The other methods in this class such as getAddress( ) and getHostName( ) mostly work with the information provided by one of these three methods. They do not make network connections; and on the rare occasions they do, they do not throw any exceptions. Only these three methods have to go outside Java and the local system to get their work done.

public static InetAddress InetAddress.getByName(String hostName) throws UnknownHostException

The method you’ll use most frequently is InetAddress.getByName( ) . This is a static method that takes the hostname you’re looking for as its argument. It looks up the host’s IP address using DNS. Call getByName( ) like this:

java.net.InetAddress address =  
 java.net.InetAddress.getByName("www.oreilly.com");

If you have already imported the java.net.InetAddress class, which will almost always be the case, you can call getByName( ) like this:

InetAddress address = InetAddress.getByName("www.oreilly.com");

In the rest of this book, I will assume that there is an import java.net.*; statement at the top of the program containing each code fragment, as well as any other necessary import statements.

The InetAddress.getByName( ) method throws an UnknownHostException if the host can’t be found, so you need to declare that the method making the call throws UnknownHostException (or its superclass, IOException) or wrap it in a try block like this:

try {
  InetAddress address = InetAddress.getByName("www.oreilly.com");
  System.out.println(address);
}
catch (UnknownHostException e) {
  System.out.println("Could not find www.oreilly.com");
}

Example 6.1 is a complete program that creates an InetAddress object for www.oreilly.com and prints it out.

Example 6-1. A Program That Prints the Address of www.oreilly.com

import java.net.*;

public class OReillyByName {

  public static void main (String[] args) {

    try {
      InetAddress address = InetAddress.getByName("www.oreilly.com");
      System.out.println(address);
    }
    catch (UnknownHostException e) {
      System.out.println("Could not find www.oreilly.com");
    }

  }

}

Here’s the result:

% java OReillyByName 
www.oreilly.com/204.148.40.9

On rare occasions, you will need to connect to a machine that does not have a hostname. In this case, you can pass a String containing the dotted quad form of the IP address to InetAddress.getByName( ):

InetAddress address = InetAddress.getByName("204.148.40.9");

Example 6.2 uses the IP address for www.oreilly.com instead of the name.

Example 6-2. A Program That Prints the Address of 204.148.40.9

import java.net.*;

public class OReillyByAddress {

  public static void main (String[] args) {

    try {
      InetAddress address = InetAddress.getByName("204.148.40.9");
      System.out.println(address);
    }
    catch (UnknownHostException e) {
      System.out.println("Could not find 204.148.40.9");
    }

  }

}

Here’s the result:

% java OReillyByAddress 
helio.ora.com/204.148.40.9

In Java 1.1 and later, when you call getByName( ) with an IP address as an argument, it creates an InetAddress object for the requested IP address without checking with DNS. This means it’s possible to create InetAddress objects for hosts that don’t really exist and that you can’t connect to. The hostname of an InetAddress object created from a dotted quad string is initially set to that dotted quad string. A DNS lookup for the actual hostname is performed only when the hostname is requested, either explicitly via getAddress( ) or implicitly through toString( ). That’s how helio.ora.com is determined from the dotted quad address 204.148.40.9. If at the time the hostname is requested and a DNS lookup is finally performed, the host with the specified IP address can’t be found, then the hostname remains the original dotted quad string. However, no UnknownHostException is thrown.

Hostnames are much more stable than IP addresses. Some services such as the MIT FAQ archives have lived at the same hostname (rtfm.mit.edu) for years but switched IP addresses several times. If you have a choice between using a hostname like www.oreilly.com or an IP address like 204.148.40.9, always choose the hostname. Use an IP address only when a hostname is not available.

public static InetAddress[ ] InetAddress.getAllByName (String hostName) throws UnknownHostException

Some computers have more than one Internet address. Given a hostname, InetAddress.getAllByName( ) returns an array that contains all the addresses corresponding to that name. Its use is straightforward:

InetAddress[] addresses = InetAddress.getAllByName("www.apple.com");

Like InetAddress.getByName( ), InetAddress.getAllByName( ) can throw an UnknownHostException, so you need to enclose it in a try block or declare that your method throws UnknownHostException. Example 6.3 demonstrates by returning a complete list of the IP addresses for www.microsoft.com.

Example 6-3. A Program That Prints All the Addresses of www.microsoft.com

import java.net.*;

public class AllAddressesOfMicrosoft {

  public static void main (String[] args) {

    try {
      InetAddress[] addresses = 
       InetAddress.getAllByName("www.microsoft.com");
      for (int i = 0; i < addresses.length; i++) {
        System.out.println(addresses[i]);
      }
    }
    catch (UnknownHostException e) {
      System.out.println("Could not find www.microsoft.com");
    }

  }

}

Here’s the result:

% java AllAddressesOfMicrosoft
www.microsoft.com/207.46.131.15
www.microsoft.com/207.46.131.137
www.microsoft.com/207.46.130.14
www.microsoft.com/207.46.130.149
www.microsoft.com/207.46.130.150
www.microsoft.com/207.46.131.13

It appears that www.microsoft.com has six IP addresses. Hosts with more than one address are the exception rather than the rule. Most hosts with multiple IP addresses are, like www.microsoft.com, very high volume web servers. Even in those cases, you rarely need to know more than one address.

public static InetAddress InetAddress.getLocalHost( ) throws UnknownHostException

The InetAddress class contains one final means of getting an InetAddress object. The static method InetAddress.getLocalHost( ) returns the InetAddress of the machine on which it’s running. Like InetAddress.getByName( ) and InetAddress.getAllByName( ), it throws an UnknownHostException when it can’t find the address of the local machine. Its use is straightforward:

InetAddress thisComputer = InetAddress.getLocalHost(  );

Example 6.4 prints the address of the machine it’s run on.

Example 6-4. Find the Address of the Local Machine

import java.net.*;

public class MyAddress {

  public static void main (String[] args) {

    try {
      InetAddress address = InetAddress.getLocalHost(  );
      System.out.println(address);
    }
    catch (UnknownHostException e) {
      System.out.println("Could not find this computer's address.");
    }

  }

}

Here’s the output; I ran the program on titan.oit.unc.edu:

% java MyAddress
titan.oit.unc.edu/152.2.22.14

Whether you see a fully qualified name like titan.oit.unc.edu or a partial name like titan depends on what the local DNS server returns for hosts in the local domain.

Security issues

Creating a new InetAddress object from a hostname is considered a potentially insecure operation because it requires a DNS lookup. An untrusted applet under the control of the default security manager will be allowed to get only the IP address of the host it came from (its codebase) and possibly the local host. (Netscape 4.6 allows untrusted applets to get the name and IP address of the local host, while IE5 allows applets to get only the loopback address and name localhost/127.0.0.1 for the local host.) An untrusted applet is not allowed to create an InetAddress object from any other hostname. This is true whether it uses the InetAddress.getByName( ) method, the InetAddress.getAllByName( ) method, the InetAddress.getLocalHost( ) method, or something else. Netscape 4.6 does allow untrusted applets to construct InetAddress objects from arbitrary dotted quad strings, though it will not perform a DNS lookup for such an address. IE5 does not allow even this.

An untrusted applet is not allowed to perform arbitrary DNS lookups for third-party hosts because of the prohibition against making network connections to hosts other than the codebase. Arbitrary DNS lookups would open a covert channel by which an applet could talk to third-party hosts. For instance, suppose an applet downloaded from www.bigisp.com wants to send the message “macfaq.dialup.cloud9.net is vulnerable” to crackersinc.com. All it has to do is request DNS information for macfaq.dialup.cloud9.net.is.vulnerable.crackersinc.com. To resolve that hostname, the applet would contact the local DNS server. The local DNS server would contact the DNS server at crackersinc.com. Even though these hosts don’t exist, the cracker can inspect the DNS error log for crackersinc.com to retrieve the message. This scheme could be considerably more sophisticated with compression, error correction, encryption, custom DNS servers that email the messages to a fourth site, and more, but this is good enough for a proof of concept. Arbitrary DNS lookups are prohibited because arbitrary DNS lookups leak information.

An untrusted applet is allowed to call InetAddress.getLocalHost( ). However, this should always return a hostname of localhost and an IP address of 127.0.0.1. This is a special hostname and IP address called the loopback address. No matter which machine you use this hostname or IP address on, it always refers to the current machine. No specific DNS resolution is necessary. The reason for prohibiting the applet from finding out the true hostname and address is that the computer on which the applet is running may be deliberately hidden behind a firewall and a proxy server. In this case, an applet should not be a channel for information the web server doesn’t already have. (Netscape 4.6 does allow a little more information about the local host to leak out, including its IP address, but only if no DNS lookup is required to get this information.)

Like all security checks, prohibitions against DNS resolutions can be relaxed for trusted applets. The specific SecurityManager method used to test whether a host can be resolved is checkConnect( ):

public void checkConnect(String host, int port)

When the port argument is -1, this method checks whether DNS may be invoked to resolve the specified host. (If the port argument is greater than -1, this method checks whether a connection to the named host on the specified port is allowed.) The host argument may be either a hostname like www.oreilly.com or a dotted quad IP address like 204.148.40.9.

In Java 1.2 and later, you can grant an applet permission to resolve a host by using the Policy Tool to add a java.net.SocketPermission with the action connect and the target being the name of the host you want to allow the applet to resolve. You can use the asterisk wildcard (*) to allow all hosts in particular domains to be resolved. For example, setting the target to *.oreilly.com allows the applet to resolve the hosts www.oreilly.com, java.oreilly.com, perl.oreilly.com, and all others in the oreilly.com domain. Although you’ll generally use a hostname to set permissions, Java checks against the actual IP addresses. In this example, that also allows hosts in the ora.com domain to be resolved because this is simply an alias for oreilly.com with the same range of IP addresses. To allow all hosts in all domains to be resolved, just set the target to *. Figure 6.1 demonstrates.

Using the Policy Tool to grant DNS resolution permission to all applets

Figure 6-1. Using the Policy Tool to grant DNS resolution permission to all applets

Other sources of InetAddress objects

Several other methods in the java.net package also return InetAddress objects. These include the getAddress( ) method of DatagramPacket, the getLocalAddress( ) method of DatagramPacket, the getInetAddress( ) method of Socket, the getLocalAddress( ) method of Socket, the getInetAddress( ) method of SocketImpl, the getInetAddress( ) method of ServerSocket, and the getInterface( ) method of MulticastSocket. Each of these will be discussed, along with its respective class, in later chapters.

Getter Methods

The InetAddress class contains three getter methods that return the hostname as a string and the IP address as both a string and a byte array. These are:

public String getHostName(  )
public byte[] getAddress(  )
public String getHostAddress(  )

There are no corresponding setHostName( ) and setAddress( ) methods, which means that packages outside of java.net can’t change an InetAddress object’s fields behind its back. Therefore, Java can guarantee that the hostname and the IP address match each other.

public String getHostName( )

The getHostName( ) method returns a String that contains the name of the host with the IP address represented by this InetAddress object. If the machine in question doesn’t have a hostname or if applet security prevents the name from being determined, then a dotted quad format of the numeric IP address is returned. For example:

InetAddress machine = InetAddress.getLocalHost(  );
String localhost = machine.getHostName(  );

In some cases, you may only see a partially qualified name like titan instead of the full name like titan.oit.unc.edu. The details depend on how the local DNS behaves when resolving local hostnames.

The getHostName( ) method is particularly useful when you’re starting with a dotted quad IP address rather than the hostname. Example 6.5 converts the dotted quad address 152.2.22.3 into a hostname by using InetAddress.getByName( ) and then applying getHostName( ) on the resulting object.

Example 6-5. Given the Address, Find the Hostname

import java.net.*;


public class ReverseTest {

  public static void main (String[] args) {
  
    try {
      InetAddress ia = InetAddress.getByName("152.2.22.3");
      System.out.println(ia.getHostName(  ));
    }
    catch (Exception e) {
      System.err.println(e);
    }
   
  }

}

Here’s the result:

% java ReverseTest
helios.oit.unc.edu

public String getHostAddress( )

The getHostAddress( ) method returns a string containing the dotted quad format of the IP address. Example 6.6 uses this method to print the IP address of the local machine in the customary format.

Example 6-6. Find the IP Address of the Local Machine

import java.net.*;


public class MyDottedQuadAddress {

  public static void main (String[] args) {

    try {
      InetAddress me = InetAddress.getLocalHost(  );
      String dottedQuad = me.getHostAddress(  );
      System.out.println("My address is " + dottedQuad);
    }
    catch (UnknownHostException e) {
      System.out.println("I'm sorry. I don't know my own address.");
    }

  }

}

Here’s the result:

% java MyDottedQuadAddress
My address is 152.2.22.14.

Of course, the exact output depends on where the program is run.

public byte[ ] getAddress( )

If you want to know the IP address of a machine (and you rarely do), getAddress( ) lsreturns an IP address as an array of bytes in network byte order. The most significant byte (i.e., the first byte in the address’s dotted quad form) is the first byte in the array, or element zero—remember, Java array indices start with zero. To be ready for 128-bit IP addresses, try not to assume anything about the length of this array. While currently this array has a length of 4 bytes, future implementations are likely to return arrays with 16 bytes. If you need to know the length of the array, use the array’s length field:

InetAddress me = InetAddress.getLocalHost(  );
byte[] address = me.getAddress(  ));

The bytes returned are unsigned, which poses a problem. Unlike C, Java doesn’t have an unsigned byte primitive data type. Bytes with values higher than 127 are treated as negative numbers. Therefore, if you want to do anything with the bytes returned by getAddress( ), you need to promote the bytes to ints and make appropriate adjustments. Here’s one way to do it:

int unsignedByte = signedByte < 0 ? signedByte + 256 : signedByte;

Here signedByte may be either positive or negative. The conditional operator ? tests whether unsignedByte is negative. If it is, 256 is added to signedByte to make it positive. Otherwise, it’s left alone. signedByte is automatically promoted to an int before the addition is performed so wraparound is not a problem.

One reason to look at the raw bytes of an IP address is to determine the type of the address. As mentioned in Chapter 2, Class A addresses always begin with a bit. Class B addresses begin with the two bits 10. Class C addresses begin with the three bits 110. Class D addresses begin with the four bits 1110, and Class E addresses begin with the five bits 11110. Figure 6.2 summarizes.

The five address classes as divided into class ID, network ID, and host ID

Figure 6-2. The five address classes as divided into class ID, network ID, and host ID

Class D addresses are multicast addresses, used to refer not to a particular host but rather to a group of hosts that have chosen to join a particular multicast group. This will be discussed further in Chapter 14. The InetAddress class contains a method that tells you whether a particular address is a multicast address:

public boolean isMulticastAddress(  )

It operates merely by using the bitwise operators to compare the first 4 bits of the address to 1110 and returning true if they match, false otherwise. To retrieve the other information that’s implicit in the address, you’ll have to do your own comparisons. For example, you can test the first byte of the address to determine the address class. You can test the number of bytes in the array returned by getAddress( ) to determine whether you’re dealing with an IPv4 or IPv6 address. Example 6.7 demonstrates.

Example 6-7. Print the IP Address of the Local Machine

import java.net.*;


public class AddressTests {

  public static int getVersion(InetAddress ia) {
    
    byte[] address = ia.getAddress(  );
    if (address.length == 4) return 4;
    else if (address.length == 16) return 6;
    else return -1;
    
  }

  public static char getClass(InetAddress ia) {
  
    byte[] address = ia.getAddress(  );
    if (address.length != 4) {
      throw new IllegalArgumentException("No IPv6 addresses!");
    }
  
    int firstByte = address[0];
    if ((firstByte & 0x80) == 0) return 'A';
    else if ((firstByte & 0xC0) == 0x80) return 'B';
    else if ((firstByte & 0xE0) == 0xC0) return 'C';    
    else if ((firstByte & 0xF0) == 0xE0) return 'D';
    else if ((firstByte & 0xF8) == 0xF0) return 'E';
    else return 'F';
    
  }

}

Object Methods

Like every other class, java.net.InetAddress inherits from java.lang.Object. Thus it has access to all the methods of that class. It overrides three methods to provide more specialized behavior:

public boolean equals(Object o)
public int hashCode(  )
public String toString(  )

public boolean equals(Object o)

An object is equal to an InetAddress object only if it is itself an instance of the InetAddress class and it has the same IP address. It does not need to have the same hostname. Thus an InetAddress object for www.oreilly.com is equal to an InetAddress object for helio.ora.com since both names refer to the same IP address. Example 6.8 creates InetAddress objects for www.oreilly.com and helio.ora.com and then tells you whether they’re the same machine.

Example 6-8. Are www.oreilly.com and helio.ora.com the Same?

import java.net.*;

public class OReillyAliases {

  public static void main (String args[]) {

    try {
      InetAddress oreilly = InetAddress.getByName("www.oreilly.com");
      InetAddress helio = InetAddress.getByName("helio.ora.com");
      if (oreilly.equals(helio)) {
        System.out.println
         ("www.oreilly.com is the same as helio.ora.com");
      }
      else {
        System.out.println
         ("www.oreilly.com is not the same as helio.ora.com");
      }
    }
    catch (UnknownHostException e) {
      System.out.println("Host lookup failed.");
    }

  }

}

When you run this program, you discover:

% java OReillyAliases 
www.oreilly.com is the same as helio.ora.com

public int hashCode( )

The hashCode( ) method returns an int that is needed when InetAddress objects are used as keys in hash tables. This is called by the various methods of java.util.Hashtable. You will almost certainly not need to call this method directly.

Currently, the int that hashCode( ) returns is simply the four bytes of the IP address converted to an int. This is different for every two unequal InetAddress objects (where unequal has the meaning provided by the equals( ) method). If two InetAddress objects have the same address, then they have the same hash code, even if their hostnames are different. Therefore, if you try to store two objects in a Hashtable using equivalent InetAddress objects as a key (for example, the InetAddress objects for www.oreilly.com and helio.ora.com), the second will overwrite the first. If this is a problem, use the String returned by getHostName( ) as the key instead of the InetAddress itself.

The hashCode( ) method is the single method in the InetAddress class that can’t be easily modified to work with 16-byte addresses. The algorithm to calculate hash codes may become considerably more complex when 16-byte addresses are supported. Do not write code that depends on the hashCode( ) method returning the IP address.

public String toString( )

Like all good classes, java.net.InetAddress has a toString( ) method that returns a short text representation of the object. Example 6.1 through Example 6.4 all implicitly called this method when passing InetAddress objects to System.out.println( ). As you saw, the string produced by toString( ) has the form:

                  host name/dotted quad address

Not all InetAddress objects have hostnames. If one doesn’t, then the dotted quad format of the IP address will be substituted. This format isn’t particularly useful, so you’ll probably never call toString( ) explicitly. If you do, the syntax is simple:

InetAddress thisComputer = InetAddress.getLocalHost(  );
String address = thisComputer.toString(  );
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.158.47