unresolved socket address - java

This is more of a novice question, but I am unable to get the type of answer I am looking for on Google.
I was reading the InetSocketAddress class in java.net package and I came across this method named createUnresolved(String host, int port). This method creates an unresolved Socket.
Basically what do we mean by unresolved ? I have come across this term often in errors while compiling a program but never have understood it completely. Can anyone please explain the general meaning in java, and meaning with context to the said method.
Thanks.

I found this in a sun-blog:
But decided to keep it as is but use createUnresolved() to create an
InetSocketAddress, so that we know what was used to instantiate it. If
the user slapped in an IP address to begin with, we won't handle it.
(I think it was indistinguishable before) The token will have whatever
the user used (IP or name) in the beginning and in case of using name,
the key to the token cache won't change even with addr changes. So the
delegation token should continue to work.
Basically, it's a half-baked InetSocketAddress - so it's not the final iteration. It's an intermediary step..
And From API:
It can also be a pair (hostname + port number), in which case an
attempt will be made to resolve the hostname.
If resolution fails then the address is said to be unresolved but can
still be used on some circumstances like connecting through a proxy
So we didn't find the hostname, or the user-friendly "www.abc.com" method.
But if we are connecting via a proxy it's OK because that the proxy server handles the hostname .

I had the same exception: java.net.UnknownHostException: Host is unresolved: https://www.google.com
The problem was because I added the protocol https://, the problem is resolved after I removed https://
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress("www.google.com", 443), 100);
socket.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}

Related

What exactly does the 'protect' method in VpnService.java

I was going through VpnService.java from the ToyVpn project.
I see these following lines in the run method initially
// Create a DatagramChannel as the VPN tunnel.
tunnel = DatagramChannel.open();
// Protect the tunnel before connecting to avoid loopback.
if (!protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
I understand that the first line creates a Datagram/UDP channel to connect to a remote server. But I do not understand what exactly the "protect" method is doing.
Could someone explain to me in as much technical detail. Thank you.
It is a function from the android.net.VpnService library that is imported in the ToyVpnService.java class as you can see in the source code
You can find what it does here
public boolean protect (int socket)
Added in API level 14
Protect a socket from VPN connections. After
protecting, data sent through this socket will go directly to the
underlying network, so its traffic will not be forwarded through the
VPN. This method is useful if some connections need to be kept outside
of VPN. For example, a VPN tunnel should protect itself if its
destination is covered by VPN routes. Otherwise its outgoing packets
will be sent back to the VPN interface and cause an infinite loop.
This method will fail if the application is not prepared or is
revoked.
The socket is NOT closed by this method.
Returns true on success.

java.net.InetSocketAddress and java.net.SocketAddress Support IPv6?

Do java.net.InetSocketAddress and java.net.SocketAddress support IPv6?
Because the two classes that i have research and try it couldnt able me to view ipv6 connection it only able to view ipv4 connection anyone there have try and able to do the editing of the code?
A partial answer to your question, even though it may come too late to be of immediate use =).
I had the following lines of code attempt to connect to two different IP addresses:
// Defined port must be 13; that is NIST's default listening port.
SocketAddress socketAddress = new InetSocketAddress(currentIpAddress, 13);
socket = new Socket();
socket.connect(socketAddress, nistServerTimeoutInMilliseconds);
The first address works fine : '206.246.122.250'
The second address throws a 'java.net.SocketException: Protocol family unavailable' on the third line. That address is '2610:20:6F15:15::27'.
I thought at first that the problem was that IPv6 is not supported by InetSocketAddress in Java 1.7, but I found out that there are actually two classes that inherit from the InetAddress class in Java: Inet4Address and Inet6Address
http://docs.oracle.com/javase/6/docs/api/java/net/Inet4Address.html
http://docs.oracle.com/javase/7/docs/api/java/net/Inet6Address.html
This explains why my code, when trying to construct an Inet4Address using an IPv6 format was failing, and it may explain your issue as well.
Hope this helps =)
P.S. InetAddress and InetSocketAddress aren't the same class, but by testing for the kind of IP address you're dealing with, there may be a way to get around the problem.

How to detect internet connectivity using java program

How to write a java program which will tell me whether I have internet access or not. I donot want to ping or create connection with some external url because if that server will be down then my program will not work. I want reliable way to detect which will tell me 100% guarantee that whether I have internet connection or not irrespective of my Operating System. I want the program for the computers who are directly connected to internet.
I have tried with the below program
URL url = new URL("http://www.xyz.com/");
URLConnection conn = url.openConnection();
conn.connect();
I want something more appropriate than this program
Thanks
Sunil Kumar Sahoo
It depends on what you mean by "internet" connection. Many computers are not connected directly to the internet, so even if you could check whether they have a network connection, it doesn't always mean they can access the internet.
The only 100% reliable way to test whether the computer can access some other server is to actually try.
Effective connectivity to the internet (i.e. where you can actually do stuff) depends on lots of things being correct, on your machine, your local net, your router, your modem, your ISP and so on. There are lots of places where a failure or misconfiguration will partly or completely block network access.
It is impossible to test all of these potential failure points with any certainty ... or even to enumerate them. (For example, you typically have no way of knowing what is happening inside your ISP's networking infrastructure.)
As #codeka says: "the only 100% reliable way to test whether the computer can access some other server is to actually try".
I think if you were to open up a HTTP session with all of:
www.google.com
www.microsoft.com
www.ibm.com
www.ford.com
and at least one of them came back with a valid response, you would have internet connectivity. Don't keep testing once you get a valid response since that would be a waste.
Feel free to expand on that list with some more mega-corporations in case you fear that all four of them may be down at the same time :-)
Of course, even that method can be tricked if someone has taken control of your DNS servers but it's probably about as reliable as you're going to get.
Just put a try/catch block around the code you mentioned. If an exception is thrown/caught then you don't have connectivity.
boolean connectivity;
try {
URL url = new URL("http://www.xyz.com/");
URLConnection conn = url.openConnection();
conn.connect();
connectivity = true;
} catch (Exception e) {
connectivity = false;
}
For better results investigate what kind of exceptions can be thrown and handle each individually.
You can check the connectivity by ask the Internet Protocol from InetAddress class. If you get an exception, or for example you use getLocalHost() -- which is returns the address of the local host -- give you the following output:
localhost/127.0.0.1 instead of fully qualified name like for example jaf-stephen-lenovoG40-80/152.6.44.13 then you're not connected to the Internet.
public static void main(String[] args) {
try {
InetAddress address = InetAddress.getByName("www.facebook.com");
System.out.println(address);
} catch (UnknownHostException e) {
System.err.println("Couldn't find www.facebook.com");
}
}
if you're connected to the Internet, you'll get the following output:
www.facebook.com/31.13.78.35
Enumaration<NetworkInterface> networkInterface = null;
networkInterface = NetworkInterface.getNetworkInterfaces();
for(NetworkInterface interface : Collections.list(networkInterface)){
System.out.println("Internet Available status is :"+ interface.isUp());
}

Cannot get hostname from getHostName

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.

MulticastSocket: Socket operation on non socket

I have some code like this:
InetAddress bind = InetAddress.getByName("192.168.0.1")
MulticastSocket socket = new MulticastSocket(new InetSocketAddress(bind,0));
socket.setInterface(bind);
On windows 7 and windows XP with JDK6u17,I got a SocketException: Socket operation on non socket.
But if I change the line 2 to :
MulticastSocket socket = new MulticastSocket(0);
It's ok, and works find too with jdk6u14.
Why? thanks.
EDIT:
Why port 0 should be the matter?
MulticastSocket socket = new MulticastSocket(0);
Everything goes well with this code.But not
MulticastSocket socket = new MulticastSocket(new InetSocketAddress(bind,port));
Whatever the port is.
As you are binding to a specific interface, calling setInterface() to the same interface is redundant. Remove it. It's only needed when you bind to INADDR_ANY, or in Java an InetAddress of null (or unspecified as a parameter).
To address errors in some of the other answers, and their implications:
Port zero is legal. It means a system-assigned port.
You only need a MulticastSocket for receiving multicasts. For sending, you can just use a DatagramSocket.
If the multicast interface needs to be specified, which it doesn't in this case, it can be done either via MulticastSocket.setInterface() or when calling joinGroup() or leaveGroup(). The latter option gives you granularity at the group level, but both techniques work. That's why they're both provided.
If you don't bind to a specific interface you should definitely call setInterface(). If you are on a multi-homed host you must to call joinGroup()/leaveGroup() once per interface, if you want to receive via all of them.
And a question: is 192.168.0.1 an IP address of an NIC on the local machine? It needs to be.
According to the documentation, you are supposed to instantiate it with a port number (thus 0 would be valid).
I am not so sure.
What's the constructor MulticastSocket(SocketAddress bindaddr) for.
And why it works fine with jdk6u14,but not jdk6u17?
And why it ok on windows 2003 server with jdk6u17?
On RHEL5.2 jdk1.4+
http://www.sockets.com/err_lst1.htm
Berkeley description: An operation was attempted on something that is not a socket. The specified socket parameter refers to a file, not a socket.
WinSock description: Same as Berkeley. The socket input parameter is not a valid socket handle (either it never was valid, it's a file handle (not a socket handle), or if it was a socket handle, it has been closed).
Detailed description:
select(): fails with WSAENOTSOCK if any socket in an fd_set is an invalid socket handle.
Developer suggestions: Did you close a socket inadvertently in one part of an application without keeping another part notified? Use socket state in an application and/or handle this error gracefully as a non-fatal error.
when the MulticastSocket created,socket.isClosed()==true
I haven't used these classes before, but the Exception occurs on line 3 when you call the setInterface method.
I would guess it's something to the effect that you're using the same reference twice or something.
I found a snippet of code that looked like this, maybe this is how you should be doing it:
MulticastSocket ms = new MulticastSocket(new InetSocketAddress(0));
ms.setInterface(InetAddress.getByName("192.168.0.1"));
You should first create the Multicast socket with a well known port - something higher than 1024 and less than 65535 - as already stated 0 means the operating system will choose a port for you (but then its going to be kinda random - which I guess you don't want).
For multicast - you generally need to set the interface to use on joinGroup() not on creation - e.g:
MulticastSocket socket = new MulticastSocket(2121);
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 2121);
if (networkInterfaceName != null){
NetworkInterface ni = NetworkInterface.getByName(networkInterfaceName);
socket.joinGroup(this.socketAddress, ni);
}else {
socket.joinGroup(socketAddress.getAddress());
}
According to the MulticastSocket documentation you should use
Class D IP addresses in the range
224.0.0.0 to 239.255.255.255, inclusive
to bind a MulticastSocket. Apparently, the "192.168.0.1" is out of the multicast range.

Categories