Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4665037
Votes 31
Synopsis InetAddress.getLocalHost() ambiguous on Linux systems
Category java:classes_net
Reported Against 1.4
Release Fixed
State 11-Closed, Will Not Fix, request for enhancement
Priority: 4-Low
Related Bugs 4895667 , 4767169
Submit Date 09-APR-2002
Description


FULL PRODUCT VERSION :
java version "1.3.1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1-b24)
Java HotSpot(TM) Client VM (build 1.3.1-b24, mixed mode)

FULL OPERATING SYSTEM VERSION : Slackware 8.0

ADDITIONAL OPERATING SYSTEMS :  customer , likely all other
linux systems

A DESCRIPTION OF THE PROBLEM :
Linux machines differentiate between the localhost
(127.0.0.1) address, which is used to simulate a network
connection, and the actual IP address of the machine.  In
almost all cases, the latter is more valuable for developing
a program - if a developer wants to simulate a connection,
he can hard code in an address of 127.0.0.1.  However, he
obviously cannot hard code the IP address for every computer
that is to run the program.  Also, one can't ask every user
of one's program to edit their /etc/hosts file to run the
program.  That kind of requirement is enough to make
developers look for another platform on which to run their
programs.  It would be much nicer behavior for Java to
return the actual IP address of the machine on which it is
run.

   1. Bug ID : 4424859 Reg-test CheckInetAddress.java Failing
      java :classes_net, Reg-test CheckInetAddress.java
Failing, State: Closed, fixed, Reported: Mar 12, 2001,
  Release reported against: ladybird
     
 http://developer.java.sun.com/developer/bugParade/bugs/4424859.html
- Feb 12, 2002

   2. Bug ID : 4460816 rmi connection error using linux server
      java :rmi, rmi connection error using linux server,
 State : Closed, not reproducible, Reported: May 18, 2001,
  Release reported against: 1.3
     
 ^C
- Feb 12, 2002

   3. Bug ID : 4435662 InetAddress.getLocalHost() gives
127.0.0.1 under  customer  with DHCP



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.  See bug reports 4435662 4424859 4460816
2.  Note that this is rather important networking behavior
that affects all linux systems, and it would be really cool
to have Java be truly platform-independent.
3.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected results of getLocalHost: return IP address of machine
Actual results : return 127.0.0.1

This bug can be reproduced always.

----------------- BEGIN SOURCE --------------------
import java.net.*;

public class LocalHostTest {
	public static void main(String[] args) {
		try {
			System.out.println(InetAddress.getLocalHost());
		} catch (Exception e) { e.printStackTrace(); }
	}
}
(Review ID: 144338) 
======================================================================
Posted Date : 2006-12-08 03:09:05.0
Work Around
If the host has a static IP address then the simple workaround is to 
correct /etc/hosts so that the hostname resolves to the correct 
address.

Alternative, if the address is static and is registered in the
name service (DNS for example) then change /etc/nsswitch.conf so
that the name service is consulted prior to /etc/hosts.

If the address is dynamic (DHCP or dial-up for example) and isn't
registered (dynamically) in the name service then an alternative
approach is to use java.net.NetworkInterface to enumerate all the
local addresses. With the list of addresses the application can
choose an appropriate local address -- ie: ignore any addreses
that are loopback addresses (use InetAddress's isLoopbackAddress
method), and additional use the java.net.preferIPv6Addresses
system property so that an IPv4 or IPv6 local address is chosen
as appropriate.
Evaluation
On Linux the /etc/hosts file is normally configured depending
on if there is a static or DHCP allocated address.

If statically allocated then /etc/hosts file will typically
look like :-

# example 1
127.0.0.1	localhost.localdomain localhost
1.2.3.4		foo.domain.com foo

If DHCP is used then it will typically look like :-

# example 2
127.0.0.1	localhost.localdomain localhost foo

Some distributions (including RedHat) appear to always 
configure /etc/hosts to map the hostname to the loopback
address (even when the address is static), ie:-

# example 3
127.0.0.1	localhost.localdomain localhost foo


Assuming the above configurations the question is what does and
what should InetAddress.getLocalHost() return. 

Assuming that /etc/nsswitch.conf has the default search 
ordering (files dns) then getLocalHost will return :-

example 1:	foo/1.2.3.4
example 2:	foo/127.0.0.1
example 3:	foo/127.0.0.1	

If the DNS name service provider is used (sun.net.spi.nameservice.provider.1 system property set to "dns,sun") then the results are:-

example 1:	foo/1.2.3.4 or UHE
example 2:	foo/x.x.x.x or UHE
example 3:	foo/1.2.3.4 or UHE

In example 2 "x.x.x.x" is the address assigned by DHCP and is returned
if dynamic DNS has been used so that there is a mapping between foo
and x.x.x.x in DNS. 

If foo is not registered in DNS then an UnknownHostException is
throws in all cases.

This RFE is about changing getLocalHost so that it tries to
return a sensible host address rather than the loopback address.
This should be examined for tiger to see which address is 
appropriate to return in each case.

In the case of DHCP environments where dynamic DNS is used the
requirement is clear - the appropriate address to return is the
address known to DNS. However implementing this is awkward because
the host resolver will typicall search /etc/hosts before it
checks DNS and thus 127.0.0.1 will always be returned. 

In the case of a static IP address then /etc/hosts should be
configured correctly and getLocalHost() should not attempt to
work-around incorrectly configured hosts files. 

  xxxxx@xxxxx   2002-05-14


Further to the above note - on SLES 8, and perhaps other distributions,
if /etc/sysconfig/network/dhcp is configured with
DHCLIENT_SET_HOSTNAME="yes" then the DHCP client will set the hostname.
With this configuration it means that InetAddress.getLocalHost() will
return the expected result -- ie: ip address = address on eth0 or whatever
the primary interface is, and the hostname = whatever the ip address
resolves to via the name service. 

  xxxxx@xxxxx   2003-09-30
Posted Date : 2006-12-08 03:09:05.0

It'd be more desirable to iterate all NICs and InetAddress bound to them by NetworkInterface class. Users will have more control by using NetworkInterface, too. So close this as will not fix.
Posted Date : 2006-12-08 03:09:06.0
Comments
  
  Include a link with my name & email   

Submitted On 27-SEP-2002
m94mni
Just discovered this bug when doing development in JXTA
(edutella.jxta.org, to be more precise). It turns out you
will need to manually do

/sbin/ifconfig

copy the IP address, and insert it into the JXTA
configuration dialog *each time* you start JXTA with a new
IP address.

Hope there will be a solution. Nameless DHCP computers are
very common.

/Mikael Nilsson


Submitted On 10-JAN-2003
liquidcs
We developed the following code as a workaround for the 
problem described by this bug.  It is a utility class that makes 
use of the NetworkInterface class added in v1.4 of the SDK.  
We have had success with it on multiple distros and versions 
of Linux.  The method comments should make it clear enough 
as to how it works but basically the idea is to see if there are 
any addresses to return other than the loopback (127.0.0.1) 
before finally giving up and returning the loopback.

public class LinuxInetAddress {
	
	/**
	 * Returns an InetAddress representing the address 
of the localhost.  
	 * Every attempt is made to find an address for this 
host that is not 
	 * the loopback address.  If no other address can 
be found, the 
	 * loopback will be returned.
	 * 
	 * @return InetAddress - the address of localhost
	 * @throws UnknownHostException - if there is a 
problem determing the address
	 */
	public static InetAddress getLocalHost() throws 
UnknownHostException {
		InetAddress localHost = 
InetAddress.getLocalHost();
		if(!localHost.isLoopbackAddress()) return 
localHost;
		InetAddress[] addrs = 
getAllLocalUsingNetworkInterface();
		for(int i=0; i<addrs.length; i++) {
			if(!addrs[i].isLoopbackAddress()) 
return addrs[i];
		}
		return localHost;	
	}
	
	/**
	 * This method attempts to find all InetAddresses 
for this machine in a 
	 * conventional way (via InetAddress).  If only one 
address is found 
	 * and it is the loopback, an attempt is made to 
determine the addresses 
	 * for this machine using NetworkInterface.
	 * 
	 * @return InetAddress[] - all addresses assigned to 
the local machine
	 * @throws UnknownHostException - if there is a 
problem determining addresses
	 */
	public static InetAddress[] getAllLocal() throws 
UnknownHostException {
		InetAddress[] iAddresses = 
InetAddress.getAllByName("127.0.0.1");
		if(iAddresses.length != 1) return 
iAddresses;
		if(!iAddresses[0].isLoopbackAddress()) 
return iAddresses;
		return getAllLocalUsingNetworkInterface();
	
	}
	
	/**
	 * Utility method that delegates to the methods of 
NetworkInterface to 
	 * determine addresses for this machine.
	 * 
	 * @return InetAddress[] - all addresses found from 
the NetworkInterfaces
	 * @throws UnknownHostException - if there is a 
problem determining addresses
	 */
	private static InetAddress[] 
getAllLocalUsingNetworkInterface() throws 
UnknownHostException {
		ArrayList addresses = new ArrayList();
		Enumeration e = null;
		try {
			e = 
NetworkInterface.getNetworkInterfaces();
		} catch (SocketException ex) {
			throw new UnknownHostException
("127.0.0.1");
		}
		while(e.hasMoreElements()) {
			NetworkInterface ni = 
(NetworkInterface)e.nextElement();
			for(Enumeration e2 = 
ni.getInetAddresses(); e2.hasMoreElements();) {
				addresses.add
(e2.nextElement());
			}	
		}
		InetAddress[] iAddresses = new 
InetAddress[addresses.size()];
		for(int i=0; i<iAddresses.length; i++) {
			iAddresses[i] = (InetAddress)
addresses.get(i);
		}
		return iAddresses;
	}
}

Hope this helps.

-Hayes Davis


Submitted On 24-JUN-2003
Greg_Fraser
This issue manifests itself when trying to run the 1.3.1 J2EE 
Server on Redhat 9 using DHCP. Does anybody have any 
system level workarounds that could help fix this problem ?


Submitted On 18-JUL-2003
rrrw
One solution we just tested with 1.4.1_01-b01 is described here:

http://java.sun.com/j2se/1.4.2/docs/guide/net/relnotes.html

Simply set the following JVM property:

-Dsun.net.spi.nameservice.provider.1=dns,sun


Submitted On 15-MAR-2006
getLocalHost() is ambiguous since we do not know if it tries to:
(1) help the OTHERS connect to myself (here by querying some name system for my own name, which is NOT the "localhost" string!)
(2) help me connect to myself

Those are two very different goals. Considering this confusion, no surprise things go wrong when connectivity is dynamic.

I would deprecate this confusing method. There could be a "getLoopBack()" method to perform (2).
On the other hand (1) is intrinsically complex, so a "convenience" method that fails to hide this complexity is a bad idea. Do we want to query our own hostname? Browse the list of our network interfaces? Applications should do this by hand using several method calls.


Submitted On 13-MAY-2006
gagern
I agree with the previous comment.

There definitely should be a way to get a loopback address short of hardcoding the value. For example in an IPv6-only world (as in bug 5096347) you probably would want to return an IPv6 address instead of 127.0.0.1.

I don't think there is such a thing as a primary network device. I often have a connection to the internet on one NIC and a connection to some DNS-less LAN on the other, and maybe even a tunneling device.

The best approach to this kind of setup would be to specify a destination address as well. What would my IP address be if I were to be connected from a given IP? Looking at the routing tables, the interface that would be used to send a packet to that host could be identified, and the first IP assigned to that interface could be used in return. Specifying null as the target IP could be used to look up the default route.

Maybe this process should somehow be linked with the java.net.NetworkInterface class. It is already possible to get an enumeration of interfaces and network addresses from there, for example to present it to the user to choose. Maybe a static method "getByTarget" in that class would be a good approach to the problem of selecting the right interface.


Submitted On 14-AUG-2006
emil_ivov
I very much agree with the previous comment. Keeping a single default local address could be a very inappropriate strategy in numerous occasions:

1) On a dual stack IPv6/IPv4 box.
2) A double NIC box with a leg on the Internet and another one in a private LAN
3) In the presence of a virtual interface over a VPN or a MobileIP(v6) tunnel.

In all these cases the source local address needs to be chosen according to the intended destination and after consulting the local routing table.

I've recently come up with a decent workaround that looks like this:

public InetAddress getLocalHost(InetAddress intendedDestination)
	throws SocketException
{
	DatagramSocket sock = new DatagramSocket(RANDOM_PORT);
    sock.connect(intendedDestination, RANDOM_PORT);
    return sock.getLocalAddress();
}

I've tested this with various addresses in all the cases enumerated above with both j2sdk1.4 and jdk1.5.

Emil (dot) Ivov (at) sip-communicator (dot) org



PLEASE NOTE: JDK6 is formerly known as Project Mustang