Why ICMP is a privilege, and what SSHive does instead
Ping is not one thing. The classic tool sends an ICMP Echo Request (type 8) and waits for an Echo Reply (type 0), matching them by identifier and sequence number and subtracting timestamps. ICMP has no ports and no ordinary sockets; to emit one you need either a raw socket or, on Darwin, a datagram ICMP socket (SOCK_DGRAM with IPPROTO_ICMP). Historically that meant root. On modern macOS the setuid bit is gone from /sbin/ping — Darwin lets any process open an unprivileged datagram ICMP socket (SOCK_DGRAM with IPPROTO_ICMP), which is exactly what the system ping binary uses. /usr/sbin/traceroute, by contrast, is still installed setuid root.
That is exactly the privilege the App Sandbox does not hand out. A sandboxed Mac App Store application gets com.apple.security.network.client, which authorises outbound TCP and UDP connections. It does not authorise raw or datagram ICMP sockets, and it does not let you spawn a setuid helper. iOS is stricter still: Network.framework, the networking layer SSHive builds on, exposes TCP, UDP, QUIC and TLS. There is no ICMP transport in that API at all. An iOS app that advertises "ping" is therefore either vendoring Apple's ageing SimplePing sample against raw BSD sockets, or doing what SSHive does.
SSHive splits the implementation cleanly by build. The direct-download macOS DMG is not sandboxed, so it spawns the system ping binary with a fixed argument array — ping, -c, 10, hostname — through a process spawn with shell interpolation disabled, and pipes stdout and stderr straight to the interface over IPC. You get real ICMP because the system binary opens an unprivileged datagram ICMP socket that Darwin permits outside the sandbox, and passing arguments as an array rather than a command string means a hostname can never be turned into a shell injection. The one caveat worth knowing: the binary is invoked by name, so it has to be on PATH.
Everywhere else, SSHive measures TCP reachability instead. On Windows and in the Mac App Store build it opens a Node socket to port 80, ten probes, one per second, with a three-second socket timeout, and takes the round trip as the wall-clock delta between issuing the connect and the socket becoming usable. On iPhone and iPad the same idea runs on Network.framework: an NWConnection to port 80 over TCP, the timer stopped the moment the connection reaches its ready state, a cancellation task firing at three seconds, and results yielded one at a time through an AsyncStream so the chart and the stat cards fill in live. iOS runs twenty probes rather than ten, which gives the bar chart enough points to make a trend visible.
The trade-offs are real and worth stating plainly rather than burying. The port is hard-coded at 80 on every TCP path; you cannot choose it. Latency includes TCP handshake cost, so values run higher than a true ICMP round trip against the same host. A host that answers ICMP but drops port 80 reads as 100% loss. There are no TTL, packet-size, interval or count options on any platform, and no IPv6-specific mode is exposed. On iPhone and iPad the address shown next to each probe is the string you typed, not the resolved IP. What you get in exchange is a consistent, honest reachability and latency signal on every Apple device you own — including the two where the operating system will never permit anything better.