InetAddress.isReachable() returns false for hosts that respond to ping — inconsistent results across Linux and Windows
0 reputation · 15 Jun 2020, 09:49 UTC
0 reputation · 15 Jun 2020, 09:49 UTC
I am building a lightweight host-monitoring component in Java that uses InetAddress.getByName(host).isReachable(timeout) to decide whether to raise an alert. The goal is a single boolean signal that works the same way on Linux servers and Windows workstations, without spawning external ping processes.
The documented behavior is that the method may use ICMP echo where permitted and fall back to a TCP connection on the echo port (port 7) on some platforms, which means the result depends on OS, firewall rules, and runtime privileges rather than on a single guaranteed mechanism. The default timeout of 3000 ms is also a concern on higher-latency links, where a slow but healthy host could be flagged as down.
Assume a recent LTS JDK (17 or 21) and standard outbound firewall rules.
isReachable() return false even when the target host answers a system-level ping?35275 reputation · 15 Jun 2020, 17:23 UTC
InetAddress.isReachable() is not a wrapper around the system ping command. It is a best-effort probe whose mechanism is chosen by the JDK at runtime: it tries an ICMP echo request via a raw socket first, and if that is not permitted it falls back to a TCP connection to port 7 (the echo service). A false result therefore means "neither permitted probe succeeded," not "the host is down." A host that answers ping can still return false when the JVM lacks raw-socket privileges and nothing is listening on port 7 — which is the common case, since the echo service is disabled or firewalled on most modern systems.
The inconsistency you observe is almost always a privilege difference, not a JDK bug:
CAP_NET_RAW. If your monitoring process runs as an unprivileged service account, the ICMP attempt fails silently and the TCP port 7 fallback is used. Your shell ping works because the ping binary typically carries the setuid bit or cap_net_raw itself.So the same jar reports a host "up" from a root shell on Linux and "down" from a systemd unit or an unelevated Windows session — same code, different privileges.
No. There is no supported API, system property, or flag in JDK 17 or 21 to select the mechanism. The choice is implementation-defined per platform. The only lever you have is the process privilege level: grant raw-socket capability and the JDK will use ICMP; withhold it and you get the port 7 fallback. On Linux you can grant the capability to the java binary without running as root:
sudo setcap cap_net_raw+ep $(readlink -f $(which java))Be aware this grants raw-socket access to every Java process on the host; weigh that against simply not trusting isReachable() as your alerting signal.
The timeout is a hard ceiling on the probe, not a health budget. Size it from measured round-trip time, not a guess: take the p95 RTT to your farthest monitored host and use roughly 2× that plus a margin. Practical starting points: 1–3 s for LAN, 5–10 s for WAN links. The 3000 ms default is reasonable for LAN but marginal on congested WAN paths. Also note the timeout applies per probe attempt; if you retry, multiply your alert latency accordingly.
id -u) and test the fallback path directly with nc -vz <host> 7. If nc fails while ping succeeds, you have confirmed the diagnosis.new Socket() and a connect timeout). That tests what you care about and behaves identically on Linux and Windows without privileges.ping, spawning the system ping via ProcessBuilder is more predictable than isReachable(), at the cost of process overhead and OS-specific argument parsing.Exact fallback behavior can vary by JDK build and OS version; the description above reflects long-standing documented behavior through JDK 21. Confirm against your specific runtime with the nc/privilege checks above before redesigning.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.