apernet-traced: How One C Program Can Lie Convincingly to traceroute

A compact Linux packet engine that forges ICMP Time Exceeded replies, injects MPLS labels, and makes a single host look like a whole provider backbone.

8 min read • View on GitHub • More from apernet

A lone Linux box sends traceroute probes toward a theatrical chain of MPLS routers that only exists in the replies. The scene explains that the project does not just answer packets, it stages an entire path that traceroute believes is real.
One host, many hops. The illusion lives in the reply packets, not in the physical topology.
Key Takeaways

Traceroute is supposed to reveal truth. `apernet-traced` uses that trust as the attack surface. A single Linux box can answer low-TTL probes with synthetic ICMP Time Exceeded packets, then dress those replies in MPLS label stacks so the path on screen looks like a provider backbone instead of a lone host.

That is the real story here. The repo is not a traceroute tool in the usual sense. It is a packet illusion engine that turns network visibility into a controlled performance.

The internet, as traceroute thinks it looks

The first surprise is conceptual, not technical. Traceroute only sees what routers choose to tell it, and `apernet-traced` exploits that rule directly. It intercepts packets with low TTL values, then emits handcrafted replies that make the outside world believe a path exists where there is only one machine.

A packet splits into two branches. One branch falls into a TUN interface, the other is sniffed at Layer 2 by a raw socket path, and both converge on the same synthetic ICMP reply engine. The image explains that the two modes differ in ingress, not in the forged response they produce.
Two ingress paths, one output. The illusion is assembled after capture, so the final reply looks the same from either mode.

That matters because traceroute is more than a troubleshooting command. It is a cultural habit in networking. Engineers use it to infer topology, blame latency, and sketch the shape of a path from the shape of replies. If the replies are fabricated well enough, the sketch still looks plausible.

Why fake MPLS labels at all?

The sharpest technical move in the repo is RFC 4950 support. `apernet-traced` does not stop at returning a generic ICMP response. It can append MPLS Label Stack Entries, which lets traceroute variants display the kind of metadata usually associated with carrier cores and backbone transit.

That is useful in two ways. As a teaching aid, it lets you see how MPLS-related traceroute output is formed without needing real ISP gear. As a diagnostic tool, it can simulate a transit path that is intentionally opaque or deliberately crafted for testing.

The core pipeline is simple to describe and easier to trust once you can see each field changing hands.

Two ways to stand in the path

The repo supports two operating modes, and that distinction is the key to its Linux plumbing. In TUN mode, the program behaves like a Layer 3 endpoint. Traffic is routed into a virtual interface, processed, and answered.

Inline mode is more invasive and more elegant. It uses `AF_PACKET` with promiscuous capture to sit transparently on a physical interface, inspect frames before the host stack claims them, and inject synthetic responses back into the flow.

PurposeWhat it observesWhat it emitsNetwork layerMain valueTypical user
apernet-tracedLow-TTL probes aimed at a configured pathSynthetic ICMP Time Exceeded replies, optionally with MPLS labelsL2 or L3 depending on modeMakes one host impersonate a longer pathNetwork engineer, researcher, tinkerer
Standard tracerouteLive routers along the routeProbe packets and observed ICMP repliesPrimarily L3Finds the path that already existsAnyone debugging reachability
Jaeger or OpenTelemetryApplication spans and service callsTracing telemetryApplication layerExplains request latency across servicesBackend teams and platform engineers
WiresharkCaptured packets on an interfaceDecoded packet viewsL2 through L7Shows what actually crossed the wireProtocol analyst, incident responder

The table hides a useful distinction. `apernet-traced` is not an observability stack and not a packet sniffer. It is a reply synthesizer. It sits between observation and belief.

The packet engine under the hood

The core logic lives in a small set of C files. `build_reply()` decides whether an incoming packet matches a configured hop and then constructs the response. `build_rfc4950()` attaches MPLS metadata when requested. `cksum()` finishes the job by calculating the Internet checksum for the resulting headers.

// Simplified shape of the reply path
if (match(packet, rule)) {
    icmp = build_reply(packet, rule);
    if (rule->mpls_enabled) {
        build_rfc4950(icmp, rule->label_stack);
    }
    icmp->checksum = cksum(icmp, icmp_len);
    send_packet(icmp);
}

What makes that interesting is the level of control. The repo can randomize IP addresses and MPLS fields, which gives the fake path some variance. It does not have to look like a static demo. It can look like a living network.

The config file is a tiny language

The strongest design choice may be the least visible one. Instead of a plain text file or a JSON blob, the project uses Flex and Bison to define a small DSL for rules and hops. That lets the author describe a path with code-like precision.

rule {
  hop 10.0.0.1
  hop $src
  hop random_ip(192.0.2.10, 192.0.2.99)
  mpls label 16000 exp 0 s 1 ttl 64
}

The DSL matters because it shifts the repo from a one-off demo to a programmable topology generator. A hop can echo the sender, pick from a range, or alter label fields per response. That is a lot of expressive power for a compact codebase.

What it is built to outsmart

This project does not compete with Jaeger, Zipkin, or OpenTelemetry. It does not replace Wireshark either. Those tools are built to reveal reality. `apernet-traced` is built to shape it.

That puts it in a category of its own. It is closest to a packet-stage illusion generator, something you would use to simulate transit, teach MPLS behavior, or mask the shape of a small network behind a much larger story.

The comparison is useful because it prevents category confusion. If you expect monitoring, you will miss the point. If you expect deception with protocol literacy, the repo makes immediate sense.

Why this tiny repo is worth noticing

`apernet-traced` is niche, but the idea behind it is broad. Network topology is partly a story told by packets, and stories can be edited. Once you accept that, the project reads less like a curiosity and more like a clean demonstration of how much authority a convincing reply can have.

That is why this repository is memorable. It makes a single host look like a backbone, then shows every layer of the trick in plain C.