best Alternative for InetAddress.getByName(host).isReachable(timeout) - java

I am trying to reach a host and have the following code
if(!InetAddress.getByName(host).isReachable(TIMEOUT)){
throw new Exception("Host does not exist::"+ hostname);
}
The hostname I am able to ping from windows, and also did a tracert on it and it returns all the packets. But java throws out exception "Host does not exist::";
The Timeout value I experimented from giving 2000ms, to 5000ms. I tried 3000 as well. What is the cause of this problem I am not able to understand. I researched on the net and some say that InetAddress.getByName(host).isReachable(time) is not reliable and behaves according to the internal system.
What is the best alternative for this if this is true. Please suggest.

Either open a TCP Socket to a port you think is open (22 for Linux, 139 for Windows, etc.)
public static boolean isReachableByTcp(String host, int port, int timeout) {
try {
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, timeout);
socket.close();
return true;
} catch (IOException e) {
return false;
}
}
Or use some hack to send an actual ping. (inspired from here: http://www.inprose.com/en/content/icmp-ping-in-java)
public static boolean isReachableByPing(String host) {
try{
String cmd = "";
if(System.getProperty("os.name").startsWith("Windows"))
cmd = "cmd /C ping -n 1 " + host + " | find \"TTL\"";
else
cmd = "ping -c 1 " + host;
Process myProcess = Runtime.getRuntime().exec(cmd);
myProcess.waitFor();
return myProcess.exitValue() == 0;
} catch( Exception e ) {
e.printStackTrace();
return false;
}
}
Same hack for Android can be found here:

I've found that ping -n 1 hostname isn't reliable either. If you get Reply from X.X.X.X: Destination host unreachable. the command actually gives an exit code of 0, thus giving you a lot of false positives.
The solution is to search for the string "TTL" in the result, as it only exists when you get a successful ping. Because the command has a pipe, you also need to use cmd /C.
Here is an example (Windows):
public boolean isReachable(String hostname) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(
"cmd /C ping -n 1 "+hostname+" | find \"TTL\""
);
return (p.waitFor() == 0);
}
I'm not sure of the unix equivalent, and don't have a unix machine to test on.

For Android developers: the above method does not work if inet is unavailable (more precisely when DNS cache runs in a timeout); what I found: DSN lookup always takes about 1 minute.
My code is like the following:
TIMEOUT = 5000;
socket.connect(new InetSocketAddress(ServerDomainName, Port), TIMEOUT);
It is expected that connect throws a timeout exception within about 5 seconds, but the time was 65 seconds when inet was unreachable (somebody describes it as fake inet connection: Connectivity says connected, but inet is unreachable).

Related

Don't list all ip lan [duplicate]

InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));
Why does isReachable return false? I can ping the IP.
The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.
The issue
There is alot of chatter about this :
Here are other, similar questions :
Detect internet Connection using Java
How do I test the availability of the internet in Java?
And even a reported bug on this same matter :
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816
Part 1 : A reproducible example of the problem
Note that in this case, it fails.
//also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd"
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*
Part 2 : A Hackish Workaround
As an alternative, you can do this :
// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).
This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.
Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.
PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.
I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
Update: Based on a recent comment to this answer, here is a succinct version of the above code:
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
return true;
} catch (IOException ex) {
return false;
}
}
If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.
public static boolean isInternetReachable()
{
try {
//make a URL to a known source
URL url = new URL("http://www.google.com");
//open a connection to that source
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
//trying to retrieve data from the source. If there
//is no connection, this line will fail
Object objData = urlConnect.getContent();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:
And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.
Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.
I am not sure what was the state when the original question was asked back in 2012.
As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.
So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.
you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)
InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.
Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.
I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.
You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.
private boolean isReachable(int nping, int wping, String ipping) throws Exception {
int nReceived = 0;
int nLost = 0;
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
ArrayList<String> strings = new ArrayList<>();
String data = "";
//
while (scanner.hasNextLine()) {
String string = scanner.nextLine();
data = data + string + "\n";
strings.add(string);
}
if (data.contains("IP address must be specified.")
|| (data.contains("Ping request could not find host " + ipping + ".")
|| data.contains("Please check the name and try again."))) {
throw new Exception(data);
} else if (nping > strings.size()) {
throw new Exception(data);
}
int index = 2;
for (int i = index; i < nping + index; i++) {
String string = strings.get(i);
if (string.contains("Destination host unreachable.")) {
nLost++;
} else if (string.contains("Request timed out.")) {
nLost++;
} else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
nReceived++;
} else {
}
}
return nReceived > 0;
}
nping is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:
isReachable(5, 2000, "192.168.7.93");
Or using this way:
public static boolean exists(final String host)
{
try
{
InetAddress.getByName(host);
return true;
}
catch (final UnknownHostException exception)
{
exception.printStackTrace();
// Handler
}
return false;
}
InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.
I tried the following:
ping -c 1 <fqdn> and check the exit status.
Works for all the cases i had tried where InetAddress.isReachable doesn't work.
To Check Internet
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
//You can replace it with your name
return !ipAddr.equals("");
} catch (Exception e1) {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping -W 1 -c 1 www.google.com");
int returnVal = 0;
returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e2) {
e2.printStackTrace();
return false;
}
}
}
To check network connectivity
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port

Checking if Booting Server is Ready for SSH with Java

I'm wanting to use Java to check if a server that's in a state of booting up is reachable yet via SSH (port 22). Currently, I'm just looping using the isReachable method like so ...
reachable = InetAddress.getByName(host).isReachable(timeout);
But this of course doesn't specifically check SSH port 22, so my Java application may jump the gun and try to SSH into the host when it's "reachable" but not necessarily via SSH. Any recommendations for how best to check if a server is ready to be SSH'ed into?
In order to specifically check for port 22, you could use standard Java Sockets, e.g.:
Socket socket = null;
boolean reaching = false;
try {
socket = new Socket("yourserver.com", 22);
reaching = true;
}catch(Exception e){
reaching = false;
}finally{
if(socket != null){
try {
socket.close();
}catch(IOException e){}
}
}
System.out.println(reaching);
In order to avoid unpleasant blocking, you could also set a timeout:
try {
int timeout = 3000; // timeout in ms
socket = new Socket();
socket.connect(new InetSocketAddress("yourserver.com",22), timeout);
reaching = true;
} catch(Exception e) {
reaching = false;
}

To scan for ports and to list the services running on each port

I am trying to build a port scanner which not only scans for port numbers but, also list the services running on the respective port .I am new to java-programming and As you can see i have the code for scanning the status of ports on the local machine. I don't know where to start when it comes to list services running on each port. I would appreciate if anyone can suggest me any code/links to list those services. Thanks for the help.....
public class port {
public static void main(String[] args) throws Exception {
String host = "localhost";
InetAddress inetAddress = InetAddress.getByName(host);
String hostName = inetAddress.getHostName();
for (int port = 0; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
String text = hostName + " is listening on port " + port;
System.out.println(text);
socket.close();
}
catch (IOException e)
{
String s = hostName + " is not listening on port " + port;
System.out.println(s);
}
}
}
}
The code seems fine if you want to check for open ports, but identifying services... well, that's tricky.
It's a bit like identifying the type of file by reading the first few bytes. An easy solution is to compare the port number with the list of well known ports. So if port 80 is open, you just assume it's HTTP and move on.
This method assumes that services actually listen on their assigned ports. This is like assuming that a file that ends with "zip" is always a zip file. It's correct most of the time, but only because it's a convention. Not because it has to be this way. If you want to actually fingerprint services - determine the type of service by "talking to it", then it's a serious undertaking, not something that can be explained in a few lines. I suggest you take a look at Nmap, as it's an existing tool that does just that. You might be able to use it instead of writing your own.
So, you are looking for something like Nmap?
Your code seems good to me, although I would do something like
public class PortScanner {
public static void main(String[] args) throws Exception {
final String host = "localhost";
final InetAddress inetAddress = InetAddress.getByName(host);
final String hostName = inetAddress.getHostName();
final List<int> openPorts = new ArrayList();
// we begin at port 1 because port 0 is never used
for (int port = 1; port <= 200; port++) {
try {
Socket socket = new Socket(hostName, port);
openPorts.add(port);
} catch (IOException) {
} finally {
socket.close();
}
}
}
}
You cannot easily know what service is running on the port, you can only simply assume what service is running on that port using this list. But beware, a web server can use custom ports instead of default ones.
If you do have the requirement to know exactly what service is running on what port, I suggest you use Nmap and make a bash script out of it which in turn outputs it's findings in a .txt file. That .txt file can then be read by Java. This approach saves tons of work.

isReachable() method for ping measurements returns wrong value [duplicate]

InetAddress byName = InetAddress.getByName("173.39.161.140");
System.out.println(byName);
System.out.println(byName.isReachable(1000));
Why does isReachable return false? I can ping the IP.
The "isReachable" method has not been worthy of using for me in many cases. You can scroll to the bottom to see my alternative for simply testing if you're online and capable of resolving external hosts (i.e. google.com) ... Which generally seems to work on *NIX machines.
The issue
There is alot of chatter about this :
Here are other, similar questions :
Detect internet Connection using Java
How do I test the availability of the internet in Java?
And even a reported bug on this same matter :
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4921816
Part 1 : A reproducible example of the problem
Note that in this case, it fails.
//also, this fails for an invalid address, like "www.sjdosgoogle.com1234sd"
InetAddress[] addresses = InetAddress.getAllByName("www.google.com");
for (InetAddress address : addresses) {
if (address.isReachable(10000))
{
System.out.println("Connected "+ address);
}
else
{
System.out.println("Failed "+address);
}
}
//output:*Failed www.google.com/74.125.227.114*
Part 2 : A Hackish Workaround
As an alternative, you can do this :
// in case of Linux change the 'n' to 'c'
Process p1 = java.lang.Runtime.getRuntime().exec("ping -n 1 www.google.com");
int returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
The -c option of ping will allow ping to simply try to reach the server once(as opposed to the infinite ping which we're used to using at the terminal).
This will return 0 if the host is reachable. Otherwise, you will get "2" as a return value.
Much simpler - but of course it is platform specific.
And there may be certain privilege caveats to using this command - but I find it works on my machines.
PLEASE Note that :
1) This solution is not production quality. Its a bit of a hack. If google is down, or your internet is temporarily slow, or maybe even if there is some funniness in your privileges/system settings, if could return false negatives (i.e. it could fail even though the input address is reachable).
2) The isReachable failure is an outstanding issue. Again - there are several online resources indicating that there is no "perfect" way of doing this at the time of this writing, due to the way the JVM tries to reach hosts - I guess it is an intrinsically platform specific task which, although simple, hasn't yet been abstracted sufficiently by the JVM.
I came here to get an answer for this same question, but I was unsatisfied by any of the answers because I was looking for a platform independent solution. Here is the code which I wrote and is platform independent, but requires information about any open port on the other machine (which we have most of the time).
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try {
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
}
return true;
} catch (IOException ex) {
return false;
}
}
Update: Based on a recent comment to this answer, here is a succinct version of the above code:
private static boolean isReachable(String addr, int openPort, int timeOutMillis) {
// Any Open port on other machine
// openPort = 22 - ssh, 80 or 443 - webserver, 25 - mailserver etc.
try (Socket soc = new Socket()) {
soc.connect(new InetSocketAddress(addr, openPort), timeOutMillis);
return true;
} catch (IOException ex) {
return false;
}
}
If you only want to check if it is connected to internet use this method , It returns true if internet is connected, Its preferable if you use the address of the site you are trying to connect through the program.
public static boolean isInternetReachable()
{
try {
//make a URL to a known source
URL url = new URL("http://www.google.com");
//open a connection to that source
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
//trying to retrieve data from the source. If there
//is no connection, this line will fail
Object objData = urlConnect.getContent();
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
Just mentioning it explicitly since the other answers don't. The ping part of isReachable() requires root access on Unix. And as pointed out by bestsss in 4779367:
And if you ask why ping from bash doesn't, actually it does need as well. Do that ls -l /bin/ping.
Since using root was not an option in my case the solution was to allow access to port 7 in the firewall to the specific server I was interested in.
I am not sure what was the state when the original question was asked back in 2012.
As it stands now, ping will be executed as a root. Through the ping executable's authorization you will see the +s flag, and the process belonging to root, meaning it will run as root. run ls -liat on where the ping is located and you should see it.
So, if you run InetAddress.getByName("www.google.com").isReacheable(5000) as root, it should return true.
you need proper authorizations for the raw socket, which is used by ICMP (the protocol used by ping)
InetAddress.getByName is as reliable as ping, but you need proper permissions on the process to have it running properly.
Since you can ping the computer, your Java process should run with sufficient privileges to perform the check. Probably due to use of ports in the lower range. If you run your java program with sudo/superuser, I'll bet it works.
I would suggest that the ONLY reliable way to test an internet connection is to actually connect AND download a file, OR to parse the output of an OS ping call via exec(). You cannot rely on the exit code for ping and isReachable() is crap.
You cannot rely on a ping exit code as it returns 0 if the ping command executes correctly. Unfortunately, ping executes correctly if it can't reach the target host but gets a "Destination host unreachable" from your home ADSL router. This is kind of a reply that gets treated as a successfull hit, thus exit code = 0. Have to add though that this is on a Windows system. Not checked *nixes.
private boolean isReachable(int nping, int wping, String ipping) throws Exception {
int nReceived = 0;
int nLost = 0;
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec("ping -n " + nping + " -w " + wping + " " + ipping);
Scanner scanner = new Scanner(process.getInputStream());
process.waitFor();
ArrayList<String> strings = new ArrayList<>();
String data = "";
//
while (scanner.hasNextLine()) {
String string = scanner.nextLine();
data = data + string + "\n";
strings.add(string);
}
if (data.contains("IP address must be specified.")
|| (data.contains("Ping request could not find host " + ipping + ".")
|| data.contains("Please check the name and try again."))) {
throw new Exception(data);
} else if (nping > strings.size()) {
throw new Exception(data);
}
int index = 2;
for (int i = index; i < nping + index; i++) {
String string = strings.get(i);
if (string.contains("Destination host unreachable.")) {
nLost++;
} else if (string.contains("Request timed out.")) {
nLost++;
} else if (string.contains("bytes") && string.contains("time") && string.contains("TTL")) {
nReceived++;
} else {
}
}
return nReceived > 0;
}
nping is number of try to ping ip(packets), if you have busy network or systems choose biger nping numbers.
wping is time waiting for pong from ip, you can set it 2000ms
for using this method u can write this:
isReachable(5, 2000, "192.168.7.93");
Or using this way:
public static boolean exists(final String host)
{
try
{
InetAddress.getByName(host);
return true;
}
catch (final UnknownHostException exception)
{
exception.printStackTrace();
// Handler
}
return false;
}
InetAddress.isReachable is flappy, and sometimes returns unreachable for addresses which we can ping.
I tried the following:
ping -c 1 <fqdn> and check the exit status.
Works for all the cases i had tried where InetAddress.isReachable doesn't work.
To Check Internet
public boolean isInternetAvailable() {
try {
InetAddress ipAddr = InetAddress.getByName("google.com");
//You can replace it with your name
return !ipAddr.equals("");
} catch (Exception e1) {
try {
Process p1 = java.lang.Runtime.getRuntime().exec("/system/bin/ping -W 1 -c 1 www.google.com");
int returnVal = 0;
returnVal = p1.waitFor();
boolean reachable = (returnVal==0);
return reachable;
} catch (Exception e2) {
e2.printStackTrace();
return false;
}
}
}
To check network connectivity
private boolean isNetworkConnected() {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null && cm.getActiveNetworkInfo().isConnected();
}
Because isReachable is using the TCP protocol(by WireShark) The Ping command is using ICMP protocol,if you want to return true you need to open the 7 port

Detecting port availability in Java fails

I try to check if port 80 is available using the following method :
Sockets: Discover port availability using Java
I have a Java application that checks if port 80 is available, if so, it runs a small web server listening on port 80. It works great to detect if another Java application listens on port 80, e.g. if I run my application two times, the second instance will correctly tell me that the port 80 is being used.
The problem is that I have WAMP running and listening on port 80, and that if I run my Java application after I started WAMP, it won't tell me that the port 80 is busy. It seems that it only tells me if another Java application uses the port 80.
That goes beyond my understanding ... any help is greatly appreciated!
Code snippet:
int port = 80;
if(!Connection.isPortAvailable(port)) {
logger.info("Port " + port + " is already in use");
}
// in Connection class
public static boolean isPortAvailable(int port) {
ServerSocket ss = null;
DatagramSocket ds = null;
try {
ss = new ServerSocket(port);
ss.setReuseAddress(true);
ds = new DatagramSocket(port);
ds.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (ds != null) {
ds.close();
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
/* should not be thrown */
}
}
}
return false;
}
The correct answer to all questions of this nature is to try to use it and catch the exception. Not try to see if it's available and then try to use it and still have to handle the exception, which has several obvious problems:
There is a timing window between 'see' and 'try' during which the situation can change (both ways).
You still have to catch failures in the 'use' part anyway.
It is basically just trying to predict the future. This is supposed to be computer science, not fortune-telling.
This applies to most values of 'it', including network ports, files, any resource really.
I was able to reproduce your problem by running WampServer (verified that it was running by visiting localhost:80) and running a minimal java program given your example code.
The code in the try block did not throw an exception when WampServer was running. However, modify the first few lines of the try block like this
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));
and isPortAvailable will properly detect when WampServer is running and when it is not. Using "0.0.0.0" instead of "127.0.0.1" didn't work with WampServer, but did properly detect when IIS was running. You can check both by closing the first socket
ss = new ServerSocket();
ss.bind(new InetSocketAddress("0.0.0.0", port));
ss.close();
ss = new ServerSocket();
ss.bind(new InetSocketAddress("127.0.0.1", port));

Categories

Resources