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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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
int
s 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.
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'; } }
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( )
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
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.
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( );
18.117.158.47