A familiar toolbox for private network debugging

Ping, traceroute, and MTR have been a staple of network troubleshooting since ping's debut in 1983. They provide a fast, straightforward way to answer the most basic networking question: can one machine reach another? Today, these utilities are so widely understood that they function as a common language among network operators, system administrators, and hobbyists alike.

As private networks built on Cloudflare grow — more than 10,000 teams now run one — that question of reachability becomes central. To support these users, Cloudflare is adding ICMP-based diagnostic tools to its Zero Trust platform. The new capability is available as a closed beta; interested users can sign up for early access.

Give us a ping. (Cloudflare) One ping only

Why this matters for Zero Trust

Cloudflare's Zero Trust offering is designed to be a single control plane for an organization's security and connectivity needs. Onboarding a private network takes three steps: install the WARP client on user devices, define identity- and device-aware access policies, and connect the network to Cloudflare via Tunnel from the Zero Trust dashboard.

BLOG-1418 Embedded Image - mhNWSa

This design philosophy extends to the broader Zero Trust product suite. Once any component — ZTNA, secure web gateway, or otherwise — is deployed, additional services such as Browser Isolation, Data Loss Prevention, CASB, and Email Security can be enabled without ripping out existing infrastructure. That stands in contrast to offerings where distinct services require separate, non-interoperable implementations.

How ping and friends actually work

Ping, traceroute, and MTR all rely on ICMP. Each ICMP message carries 8-bit type and code fields that define its purpose; for network diagnostics, the relevant types are echo request and echo reply. A conformant destination responds to an echo request with an echo reply that mirrors the request's identifier and sequence numbers — a detail that matters for how Cloudflare handles ICMP traffic at scale.

BLOG-1418 Embedded Image - y5KWK3

A quick refresher on the tools

Ping

Ping sends a sequence of ICMP echo requests to a destination. Every router hop along the way decrements the TTL field in the IP header. If a hop decrements TTL to zero before the packet reaches its destination, it returns an ICMP error — typically "TTL exceeded." If there's no route onward, the error is "Destination host unreachable." A host that speaks ICMP answers each request with an echo reply, and ping reports the round-trip latency. The final TTL in the reply also gives a rough sense of distance in terms of hop count.

Traceroute and MTR

Traceroute builds on the same mechanism but exploits TTL behavior to reveal the path. By sending packets with incrementing TTL values, it forces each successive router on the path to return an error message, allowing the utility to map the IP address of every hop. MTR operates in much the same way but adds aggregate statistics per hop and runs continuously until stopped, giving a more complete picture of path quality over time.

Debugging a private network connection

Consider a scenario where a user can't reach a private application server. With ICMP support enabled on a Zero Trust account, a traceroute can help isolate the fault. In a healthy case, the output might look like this:

BLOG-1418 Embedded Image - lV2xiY

If the server is online and reachable through the Tunnel, Cloudflare's traceroute should show something like:

traceroute -I 172.16.10.120
traceroute to 172.16.10.120 (172.16.10.120), 64 hops max, 72 byte packets
 1  172.68.101.57 (172.68.101.57)  20.782 ms  12.070 ms  15.888 ms
 2  172.16.10.100 (172.16.10.100)  31.508 ms  30.657 ms  29.478 ms
 3  172.16.10.120 (172.16.10.120)  40.158 ms  55.719 ms  27.603 ms

The first hop is the Cloudflare data center where the WARP client is connected via Anycast — that IP varies by location. The second hop is the server running cloudflared. The final hop is the application server.

If the application server is unreachable, the traceroute output will differ:

traceroute -I 172.16.10.120
traceroute to 172.16.10.120 (172.16.10.120), 64 hops max, 72 byte packets
 1  172.68.101.57 (172.68.101.57)  20.782 ms  12.070 ms  15.888 ms
 2  * * *
 3  * * *

In this case, ICMP echo requests are not reaching cloudflared. The next steps are to verify that the Tunnel is running in the Zero Trust dashboard and that the Tunnel has a route to the destination IP, as shown in the Routes column of the Tunnels table. If no route exists, adding one may change the traceroute result.

Once cloudflared is confirmed to be running and the route exists, traceroute should reach the cloudflared host but still fail to get replies from the application server:

raceroute -I 172.16.10.120
traceroute to 172.16.10.120 (172.16.10.120), 64 hops max, 72 byte packets
 1  172.68.101.57 (172.68.101.57)  20.782 ms  12.070 ms  15.888 ms
 2  172.16.10.100 (172.16.10.100)  31.508 ms  30.657 ms  29.478 ms
 3  * * *

At this point, the problem is isolated to the application server itself or to communication between cloudflared and the app server. Possible culprits include a downed machine or a firewall rule. Either way, the traceroute output tells you exactly which segment of the path needs attention.

Note that the route from cloudflared to the origin always appears as a single hop, even if there are intermediate routers. That's because cloudflared generates its own echo request to the origin rather than forwarding the original packet onward.

Why ICMP requires special handling

ICMP support builds on the same infrastructure Cloudflare previously used to add UDP proxying end-to-end. Both are datagram-based, so individual packets can be carried over QUIC datagrams between Cloudflare and cloudflared instances.

For UDP, Cloudflare maintains a session per client/destination pair, so only the payload and a session identifier need to be sent — the IP and port are not repeated in each datagram. For ICMP, however, establishing sessions would be overkill: typical ICMP exchanges involve only a handful of packets. Instead, Cloudflare sends the entire IP packet, with the ICMP message inside, as a single datagram.

That approach lets cloudflared read the destination address from the IP header. But sending the packet onward is not a simple forward, because the source IP is the original client address — not something routable to the cloudflared host. To get replies back, cloudflared must apply source NAT:

  • Read the destination IP from the packet header
  • Strip off the IP header to isolate the ICMP payload
  • Send the ICMP payload to the destination with a source IP bound to a local interface
  • When a reply arrives at that address, rewrite the destination back to the original client's source address

This kind of NAT is trivial for TCP and UDP because ports disambiguate flows. ICMP has no ports, so Cloudflare needed a different way to map each reply back to the requesting client.

Consider two clients, 192.0.2.1 and 192.0.2.2, both sending echo requests to 10.0.0.8. After cloudflared rewrites their source IPs, the replies from 10.0.0.8 will carry identical headers. How does cloudflared know which destination to write into each reply?

The solution takes advantage of the fact that ICMP echo replies mirror the identifier from the request. If client 192.0.2.1 sends its request with ID 23 and client 192.0.2.2 uses ID 45, the replies can be matched accordingly, just as ports are used to match TCP and UDP sessions.

This strategy only works for echo request/reply messages. Those are the only ICMP message types Cloudflare currently supports, both because they're sufficient for ping and traceroute and because limiting the surface area has security benefits. Other ICMP types may be added later, but for now the focus is on making the tools users already know work reliably across private networks.

Making ICMP safe without root

Sending ICMP packets normally requires raw sockets, which give the application full control over the IP header. That means elevated privileges. Since cloudflared shouldn't run with extra permissions, we looked at how the standard ping utility works: any user can run it without root. The answer, unfortunately, is platform-specific.

Linux: a socket that behaves like a port

On Linux, ping uses a datagram socket for the ICMP protocol via socket(PF_INET, SOCK_DGRAM, PROT_ICMP). This socket can be opened without root, as long as the user's group ID falls within /proc/sys/net/ipv4/ping_group_range. It is restricted to sending echo requests and receiving echo replies, and it carries a conceptual "port" even though ICMP has no ports. The kernel rewrites the identifier field of outgoing echo requests to match that port, and delivers incoming replies with the same identifier back to the originating socket.

For cloudflared, this means source NAT for ICMP is straightforward: open one unique socket per source IP address. The identifier and source address are rewritten on the way out, and replies arrive on that same socket, making it easy to map back to the original values before forwarding to the client.

Darwin: manual identifier handling

macOS also allows an unprivileged ICMP socket via the same socket(PF_INET, SOCK_DGRAM, PROT_ICMP) call, but there is a key difference: the Darwin kernel does not assign a conceptual port, nor does it rewrite the echo ID on outgoing requests. It also does not demultiplex replies by identifier. So cloudflared must handle echo ID rewriting itself.

When an echo request arrives on macOS, cloudflared selects an echo ID that is unique for the destination. It maintains a mapping keyed by that chosen ID and the destination IP, with the original echo ID and source IP as the value. After rewriting the identifier, it sends the request on. On reply, the source IP and echo ID are used to look up the original client details, and the reply is rewritten and returned to the client.

Windows: a system API

Windows provides a ready-made solution: the Win32 API IcmpSendEcho, which sends an echo request and returns the reply, timeout, or error. For ICMPv6, the equivalent is Icmp6SendEcho. These are C APIs, but cloudflared invokes them through CGO. Our wrapper is available as a reference for Go programs needing the same functionality.

Where we go from here

ICMP-based tools are just one piece of improving the Zero Trust administrator experience. The goal is to keep delivering ways to spot connectivity and performance problems in the network quickly and easily.

Upcoming work includes more observability controls, such as Digital Experience Monitoring, to help users proactively monitor changing network conditions. In the meantime, you can apply Zero Trust controls to a private network for free by signing up.