Reputation: 2179
I am trying to get hostname/computer name using this method. Unfortunately i only can get localhost but not other computer.
private String getHostName(String _strIP) {
try {
InetAddress inetAddress = InetAddress.getByName(_strIP);
System.out.println("getHostAddress : " + inetAddress.getHostAddress());
System.out.println("getHostName : " + inetAddress.getHostName());
System.out.println("getCanonicalHostName : " + inetAddress.getCanonicalHostName());
return inetAddress.getHostName();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return strDefaultHostName;
}
getHostAddress : 192.168.2.139
getHostName : 192.168.2.139
getCanonicalHostName : 192.168.2.139
getHostAddress : 127.0.0.1
getHostName : localhost
getCanonicalHostName : localhost
Thank you
Upvotes: 3
Views: 13543
Reputation: 5271
The problem can be caused by multiple reasons.
This is probably the most common reason, and has nothing to do with security managers.
If an IP address doesn't resolve to a hostname, because there is no hostname, then you would expect getHostName()
to return null
or throw a UnknownHostException
, but this doesn't happen. Instead getHostName()
simply returns the IP address as a string back again. For reasons unknown to me, this common situation is undocumented.
So if the IP address is the same as the result returned by getHostName()
, then the hostname doesn't exist.
The following JDK code is the cause of this undocumented problem: https://github.com/openjdk/jdk/blob/jdk-17+35/src/java.base/share/classes/java/net/InetAddress.java#L697
public class InetAddress implements java.io.Serializable {
private static String getHostFromNameService(InetAddress addr, boolean check) {
String host = null;
try {
// first lookup the hostname
host = nameService.getHostByAddr(addr.getAddress());
/* check to see if calling code is allowed to know
* the hostname for this IP address, ie, connect to the host
*/
if (check) {
@SuppressWarnings("removal")
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkConnect(host, -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 = InetAddress.getAllByName0(host, check);
boolean ok = false;
if(arr != null) {
for(int i = 0; !ok && i < arr.length; i++) {
ok = addr.equals(arr[i]);
}
}
//XXX: if it looks a spoof just return the address?
if (!ok) {
host = addr.getHostAddress();
return host;
}
} catch (SecurityException e) {
host = addr.getHostAddress();
} catch (UnknownHostException e) {
host = addr.getHostAddress();
// let next provider resolve the hostname
}
return host;
}
}
So what happens is that the IP-address is passed to NameService.getHostByAddr()
(NameService
is a private interface), which has this (private) documentation in the source code:
Lookup the host corresponding to the IP address provided
@param addr byte array representing an IP address
@return {@code String} representing the host name mapping
@throws UnknownHostException if no host found for the specified IP address
So NameService.getHostByAddr()
throws an UnknownHostException
if the IP doesn't have a hostname, but InetAddress.getHostFromNameService()
swallows this exception and instead, it returns the provided IP-address itself!!! IMO it should have let the exception be thrown instead of swallowing it, because swallowing it makes it more difficult for the client to determine whether a hostname exists.
You can check if the IP address has a hostname by using the nslookup
commandline tool: nslookup 192.168.2.139
. If it returns something like:
** server can't find 139.2.168.192.in-addr.arpa: NXDOMAIN
(Linux) or *** can't find 192.168.2.139: Non-existent domain
(Windows) then there is no hostname.
By default, Java doesn't have a security manager enabled. In that case, this reason doesn't apply.
A security manager is an object that defines a security policy for an application. If you have a security manager and want to find out if it is the cause of your problem, then you should check whether it is allowing you to open a socket to the resolved hostname (if any). To do so, first use nslookup 192.168.2.139
and verify if a hostname is resolved. If no hostname is resolved, then your problem is caused by "Reason 1". If it does resolve to a hostname, for example myhostname
, then try this:
SecurityManager sec = System.getSecurityManager();
if (sec != null) {
sec.checkConnect("myhostname", -1);
}
If checkConnect()
throws a SecurityException
, then a SecurityManager is active and is causing the problem. So then you could look into how you can configure your securityManager to solve the problem.
Upvotes: 1
Reputation: 25864
InetAddress.getHostName()
(Sun JDK8)...The method performs the following logic:
- Loops through the available
sun.net.spi.nameservice.NameService's
- Performs a reverse DNS lookup - e.g.
192.168.0.23 -> frodo.baggins.com.au
- *Checks with the
java.lang.SecurityManager
, to see if "we have permission to connect" to hostname- *Performs a forward DNS lookup on the hostname, to prevent spoofing - e.g.
frodo.baggins.com.au -> 192.168.0.99
- If forward lookup result matches the original address (e.g.
192.168.0.23 == 192.168.0.99?
), return hostname, otherwise returngetHostAddress()
*If step 3 or 4 throws a
SecurityException
/UnknownHostException
, returngetHostAddress()
For me, step #2 successfully resolved the hostname, but failed at step #4 with an UnknownHostException
.
SecurityManager
must provide permission to access the hostInetAddress
Only then will Java give you the hostname.
@SuppressWarnings("unchecked")
public static String getHostName(InetAddress addr) {
String host = null;
List<NameService> nameServicesImpl = new ArrayList<>();
try {
// do naughty things...
Field nameServices = InetAddress.class.getDeclaredField("nameServices");
nameServices.setAccessible(true);
nameServicesImpl = (List<NameService>) nameServices.get(null);
} catch (Throwable t) {
throw new RuntimeException("Got caught doing naughty things.", t);
}
for (NameService nameService : nameServicesImpl) {
try {
// lookup the hostname...
host = nameService.getHostByAddr(addr.getAddress());
} catch (Throwable t) {
// NOOP: problem getting hostname from this name service, continue looping...
}
}
return host != null ? host : addr.getHostAddress();
}
Upvotes: 3
Reputation: 75376
Your DNS is broken. Then IP-numbers are returned instead.
Upvotes: 2
Reputation: 67760
We've established roughly what the problem is in tangens' answer.
I think you can fix the problem pretty simply by putting host names into your hosts file.
%SystemRoot%\system32\drivers\etc\hosts
is the file you're looking for; localhost is defined here. You want to put a name and address line in it for every host you want to resolve.
I've never tried this. If it doesn't work, you get your money back.
Update
The above is the "quick hack" solution. This essentially entails that whenever someone manually changes the IP address of a host you're interested in, someone must at the same time change the hosts
files on any machines that want to access those hosts.
The other alternative is to operate your own DNS server. You still need to update IP addresses when a host's address changes, but you only need to do so in one place, and you get both forward and reverse name resolution throughout your network. This takes more setting up but is easier to maintain in the long run.
Here is a very useful reference: http://www.dns.net/dnsrd/servers/windows.html
They mention that the "built in" Microsoft DNS server is a terrible solution (up until the one in Windows 2003 Server) but mention at least two alternatives, one commercial and one free. BIND is what is currently holding much of the Internet together, DNS-wise, and it's great that they have a Windows port too.
Upvotes: 5
Reputation: 2179
Great answer, but we still don't know if the host name has been updated or not... This is something like we hardcode.
Anyway thank you so much
# Copyright (c) 1993-1999 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
127.0.0.1 localhost
192.168.2.139 dev-testing
Upvotes: 1
Reputation: 39733
The javadoc of InetAddress.getCanonicalHostName() says:
Gets the fully qualified domain name for this IP address. Best effort method, meaning we may not be able to return the FQDN depending on the underlying system configuration.
If there is a security manager, this method first calls its checkConnect method with the hostname and -1 as its arguments to see if the calling code is allowed to know the hostname for this IP address, i.e., to connect to the host. If the operation is not allowed, it will return the textual representation of the IP address.
I looks like your system configuration isn't correct. Are you running from within an applet?
Upvotes: 2