I recently needed to perform an ICMP echo (aka a ping) in Clojure. After some research I found the java method InetAddress.isReachable. I wrapped this as a clojure function like so:
(ns pinger
(import (java.net InetAddress)))
(defn ping
[host]
(.isReachable (InetAddress/getByName host) 5000))
Running this worked great on bigjason.com:
(println (ping "bigjason.com"))
;; => true
However when I tried pinging one of my routers, it failed:
(println (ping "192.168.1.1"))
;; => false
While a manual ping worked just fine:
$ ping -c 4 192.168.1.1
PING 192.168.1.1 (192.168.1.1): 56 data bytes
64 bytes from 192.168.1.1: icmp_seq=0 ttl=64 time=0.776 ms
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=3.134 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=3.198 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.995 ms
--- 192.168.1.1 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.776/2.026/3.198/1.143 ms
Confused I did some more research and found this in the documentation of isReachable:
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.
A little checking revealed the router was indeed blocking port 7. So figuring it
must be a privilege problem, I ran it again with sudo. It worked exactly as
expected sending out an actual ping.
Moral
If you want to send out an ICMP message on a *nix based system with the jvm, you must be root.