Cannot get hostname from getHostName - java

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;
}
the result (not localhost)
getHostAddress : 192.168.2.139
getHostName : 192.168.2.139
getCanonicalHostName : 192.168.2.139
the result (localhost)
getHostAddress : 127.0.0.1
getHostName : localhost
getCanonicalHostName : localhost
Thank you

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.

Looking at the source for 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 return getHostAddress()
*If step 3 or 4 throws a SecurityException/UnknownHostException, return getHostAddress()
For me, step #2 successfully resolved the hostname, but failed at step #4 with an UnknownHostException.
TLDR; you must fulfill ALL of the following requirements:
the SecurityManager must provide permission to access the host
you must be able to forward AND reverse DNS lookup your InetAddress
the forward lookup details MUST match the reverse lookup details
Only then will Java give you the hostname.
OR, you could bypass these steps with the following method, and just get 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();
}

Your DNS is broken. Then IP-numbers are returned instead.

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?

Reply Feedback for Carl Smotricz
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

The problem can be caused by multiple reasons.
Reason 1: the IP address doesn't have a hostname
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.
Detailed explanation
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.
Reason 2: a security manager is applied
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.

Related

Java getLocalAddr() returning IPV6 address

I have some code to determine whether a web request has been made from the local machine. It uses HttpServletRequest.getLocalAddr() and compares the result to 127.0.0.1.
However, in the last day this has started failing for requests made from a Chrome browser. The address is now in IPV6 format rather than IPV4, i.e. 0:0:0:0:0:0:0:1. If IE is used rather than Chrome the address is still IPV4.
What would cause this? Is it something to do with Chrome, maybe an update to the browser? Or is it more likely to be my environment?
You cannot rely on HttpServletRequest.getLocalAddr() to always return IPv4 address. Instead, you should either be checking if that address is an IPv4 or IPv6 address and act accordingly
InetAddress inetAddress = InetAddress.getByName(request.getRemoteAddr());
if (inetAddress instanceof Inet6Address) {
// handle IPv6
} else {
// handle IPv4
}
or resolve "localhost" to all possible addresses and match the remote address against that
Set<String> localhostAddresses = new HashSet<String>();
localhostAddresses.add(InetAddress.getLocalHost().getHostAddress());
for (InetAddress address : InetAddress.getAllByName("localhost")) {
localhostAddresses.add(address.getHostAddress());
}
if (localhostAddresses.contains(request.getRemoteAddr())) {
// handle localhost
} else {
// handle non-localhost
}
See this useful post.

Java UnknownHostException - Same URL but sometimes only [duplicate]

I am trying to data from a server. Sometimes my code fails due to an UnknownHostException. Why is that? What is the cause of this problem?
This may occur if a hiccup in DNS server has occurred. Apart from making the DNS server more robust or looking for another one, you can also just use the full IP address instead of the hostname. This way it doesn't need to lookup the IP address based on the hostname. However, I would rather fix the DNS issue and prefer the DNS since IP addresses may change from time to time.
An UnknownHostException indicates the host specified couldn't be translated to an IP address. It could very well be a problem with your DNS server.
If the DNS resolution fails intermittently, catch the exception and try again until you get name resolution. You can only control, what you can control... And if you can't control/fix the DNS server, make your app robust enough to handle the quirky DNS server.
I too am seeing sporadic UnknownHostExceptions in Java for no apparent reason. The solution is just to retry a few times. Here is a wrapper for DocumentBuilder.parse that does this:
static Document DocumentBuilder_parse(DocumentBuilder b, String uri) throws SAXException, IOException {
UnknownHostException lastException = null;
for (int tries = 0; tries < 2; tries++) {
try {
return b.parse(uri);
} catch (UnknownHostException e) {
lastException = e;
System.out.println("Retrying because of: " + e);
continue;
}
}
throw lastException;
}

isLocalHost(String hostNameOrIpAddress) in Java

I want to write a ContainerRequestFilter for a Jersey webapp that will filter out all remote calls.
So only requests from same machine (where webapp is running) are allowed.
I get a context object of type ContainerRequestContext where I get the host name via ctx.getUriInfo().getRequestUri().getHost().
How can I check if this host name (in form of IPv4, IPv6 or domain name) is an address of the local machine?
I'd go with something like this, once you stripped the host name from the request. It should work with inputs like localhost and such as well.
public boolean isLocalAddress(String domain) {
try {
InetAddress address = InetAddress.getByName(domain);
return address.isAnyLocalAddress()
|| address.isLoopbackAddress()
|| NetworkInterface.getByInetAddress(address) != null;
} catch (UnknownHostException | SocketException e) {
// ignore
}
return false;
}
But please keep in mind, as it's not straightforward to determine if a request is originated from a local client, and there is also performance implications, I'd suggest to bind the container's listen address only to a locally accessible interface (127.0.0.1, ::1), or implement some sort of authentication. This approach - where you trying to determine this info from the request is also insecure.

Error 0:0:0:0:0:0:0:1%0 getting IP V6 client

I have this function to get the HostAddress from my request (HttpServletRequest) on Java. But using Jetty 7.x and my IP is ipV6 I have always this error with iPv6 address.
My function:
xxxx.getIP(request, false);
public static String getIP(HttpServletRequest request, boolean proxy) {
String ip = "";
log.debug("X-getHeaderNames ["+ request.getHeaderNames()+"]");
if (proxy) {
ip = XFordwardedInetAddressUtil.getAddressFromRequest(request);
} else {
String _ip = request.getRemoteAddr();
ip = InetAddresses.forString(_ip).getHostAddress();
}
return ip;
}
The error:
DEBUG: org.encuestame.core.exception.EnMeMappingExceptionResolver - Resolving exception from handler [org.encuestame.mvc.controller.TweetPollController#4fc23996]: java.lang.IllegalArgumentException: '0:0:0:0:0:0:0:1%0' is not an IP string literal.
java.lang.IllegalArgumentException: '0:0:0:0:0:0:0:1%0' is not an IP string literal.
at org.encuestame.utils.net.InetAddresses.forString(InetAddresses.java:59)
at org.encuestame.core.util.EnMeUtils.getIP(EnMeUtils.java:210)
at org.encuestame.mvc.controller.AbstractBaseOperations.getIpClient(AbstractBaseOperations.java:262)
at org.encuestame.mvc.controller.TweetPollController.detailTweetPollController(TweetPollController.java:332)
at org.encuestame.mvc.controller.TweetPollController$$FastClassByCGLIB$$6990b004.invoke()
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedIntercepto
I know the iPv6 localhost format should be '0:0:0:0:0:0:0:1' but my request always return this string '0:0:0:0:0:0:0:1%0'
Anyone can help me?
The problem is that the class you're using (org.encuestame.utils.net.InetAddresses) clearly doesn't support IPv6. Try using the java InetAddress class that Joachim mentioned in his answer.
When you're using a link local address, the % should be included in the address.
This is due to the fact that the computer needs to know which interface/zone the request came from to be able to reply out the correct interface.
If you're using correctly configured, Internet routable IPv6 addresses, the zone index will not be a part of the address.
In this case, I can't see a way to solve your problem for localhost/link local testing except to filter out anything after the % sign, or use another class that works with link local addresses to parse the address.
EDIT: Here's another - similar - question I didn't see earlier.

IP Address not obtained in java

This code used to return my local ip address as 192.xxx.x.xxx but now it is returning 127.0.0.1 . Please help me why the same code is returning different value. Is there something that I need to watch at linux OS.
import java.util.*;
import java.lang.*;
import java.net.*;
public class GetOwnIP
{
public static void main(String args[]) {
try{
InetAddress ownIP=InetAddress.getLocalHost();
System.out.println("IP of my system is := "+ownIP.getHostAddress());
}catch (Exception e){
System.out.println("Exception caught ="+e.getMessage());
}
}
}
127.0.0.1 is the loopback adapter - it's a perfectly correct response to the (somewhat malfomed) question "what is my IP address?"
The problem is that there are multiple correct answers to that question.
EDIT: The docs for getLocalHost say:
If there is a security manager, its
checkConnect method is called with the
local host name and -1 as its
arguments to see if the operation is
allowed. If the operation is not
allowed, an InetAddress representing
the loopback address is returned.
Is it possible that the change in behaviour is due to a change in permissions?
EDIT: I believe that NetworkInterface.getNetworkInterfaces is what you need to enumerate all the possibilities. Here's an example which doesn't show virtual addresses, but works for "main" interfaces:
import java.net.*;
import java.util.*;
public class Test
{
public static void main(String[] args)
throws Exception // Just for simplicity
{
for (Enumeration<NetworkInterface> ifaces =
NetworkInterface.getNetworkInterfaces();
ifaces.hasMoreElements(); )
{
NetworkInterface iface = ifaces.nextElement();
System.out.println(iface.getName() + ":");
for (Enumeration<InetAddress> addresses =
iface.getInetAddresses();
addresses.hasMoreElements(); )
{
InetAddress address = addresses.nextElement();
System.out.println(" " + address);
}
}
}
}
(I'd forgotten just how awful the Enumeration<T> type is to work with directly!)
Here are the results on my laptop right now:
lo:
/127.0.0.1
eth0:
/169.254.148.66
eth1:
eth2:
ppp0:
/10.54.251.111
(I don't think that's giving away any hugely sensitive information :)
If you know which network interface you want to use, call NetworkInterface.getByName(...) and then look at the addresses for that interface (as shown in the code above).
When you use InetAddress.getLocalHost() you are not guaranteed to get a particular interface, ie. you could receive the loopback (127) interface or a connected one.
In order to ensure you always get an external interface, you should use the java.net.NetworkInterface class. The static getByName(String) class will give you the interface with the defined name (such as "eth0"). Then you can use the getInetAddresses() function to obtain the IP addresses (could be just one) bound to that interface.
NetworkInterface ni = NetworkInterface.getByName("eth1");
ni.getInetAddresses();
Check your /etc/host file. If you put 127.0.0.1 first, it will return this as result.
The correct way to get the ip address is to use NetworkInterface.getNetworkInterfaces() and run getInetAddresses() on each of them.
You can use the NetworkInterface.getNetworkInterfaces() method to retrieve an Enumeration of all of the network interfaces for your system.
For each of the NetworkInterface instances, you can then use the getInetAddresses() method to retrieve an Enumeration of all of the InetAddress instances associated with the network interface.
Finally, you can use the getHostAddress() method on each InetAddress instance to retrieve the IP address in textual form.
This is because you have a line in /etc/hosts like
127.0.0.1 localhost
you need to have
192.xxx.xxx.xxx localhost
Though please note that this would be very bad as to solve a code issue you should not modify linux config files. Not only is it not right (and risks breaking some other network aware apps on your linux box) it will also not work anywhere else (unless the admins of those boxes are also like minded).
javadoc for InetAddress.getLocalHost(); read "....an InetAddress representing the loopback address is returned." so it appears that the implementation of getLocalHost() is incorrect
on your UNIX and WIN boxes. The loopback address is nearly allways 127.0.0.1
Found this comment
"A host may have several IP addresses and other hosts may have to use different addresses to reach it. E.g. hosts on the intranet may have to use 192.168.0.100, but external machines may have to use 65.123.66.124. If you have a socket connection to another host you can call
Socket.getLocalAddress() to find out which local address is used for the socket."

Categories