DEV Community

Cover image for Your DDoS protection is provisioned. I checked whether it was actually in the path.
BlackNeuron
BlackNeuron

Posted on

Your DDoS protection is provisioned. I checked whether it was actually in the path.

A managed edge defends the requests that pass through it. That is the entire contract, and it is easy to read past.

Anything reaching your origin by another route is outside that contract. Not degraded, not partially covered. Outside. And the provider dashboard will report a perfectly healthy service the whole time, because from its point of view nothing happened.

So before any of the interesting tuning questions, there is a boring one: is the protection actually in the path?

The shape of the failure

It is almost always the same story.

www points at the edge, because that is the hostname everyone remembers to migrate. The apex still resolves to the address it used before the edge existed, because moving it was awkward at the time and nothing broke.

Both names serve the same site. One of them is defended.

An attacker needs nothing clever here. They resolve the name, see an address that is not the edge, and aim at it. Your protection logs nothing, because it never saw the traffic.

Why the apex is the one that drifts

This is not carelessness, and it is worth understanding why it keeps happening.

Putting a hostname behind an edge normally means a CNAME to the provider's name. But DNS does not allow a CNAME at a zone apex. The apex has to coexist with the zone's SOA and NS records, and a CNAME cannot coexist with other records at the same name. So www.example.com gets a one-line CNAME, and example.com cannot.

Providers solved this with non-standard extensions: ALIAS records, ANAME, CNAME flattening, or an A record pointing at an anycast address the provider owns. All of them work. All of them are provider-specific, and all of them require deliberately doing a different thing at the apex than you did at www.

That asymmetry is the bug factory. Two hostnames, two mechanisms, one of which is easy to forget during a migration.

Checking it from outside

The gap is invisible from inside the platform, because the platform only sees traffic that arrives. It is perfectly visible in DNS.

So the tool is deliberately small. For the apex and www it:

  1. follows the CNAME chain, since delegation to a known edge is the strongest available proof;
  2. reads ordinary HTTPS response headers, where each edge leaves a fingerprint (cf-ray, x-amz-cf-id, x-azure-ref, eagleeye-traceid, and friends);
  3. maps the resolved addresses to their network operator via Team Cymru's public ASN interface;
  4. compares the hostnames, which is the actual point.

Everything it touches is public. DNS over HTTPS, public ASN data, and the same GET a browser makes. No scanning, no probing, no traffic aimed at anyone's infrastructure.

// One DNS-over-HTTPS query. The whole tool is built out of this plus header reads.
fn doh(name: &str, rtype: &str) -> Option<Value> {
    let url = format!("{DOH}?name={name}&type={rtype}");
    let body = ureq::get(&url)
        .set("accept", "application/dns-json")
        .set("User-Agent", UA)
        .timeout(TIMEOUT)
        .call()
        .ok()?
        .into_string()
        .ok()?;
    serde_json::from_str(&body).ok()
}
Enter fullscreen mode Exit fullscreen mode

It found a real one immediately

I pointed it at a well-known open-source project's site while testing. The apex sits behind a major CDN. The www hostname resolves straight to donated university hosting running a bare web server.

Two names, same site, one defended.

These are not careless people. It is what happens when infrastructure grows across years and volunteers, and one record stays where it has always been. Which is the whole argument for checking from outside rather than reasoning about what you believe you deployed.

Two bugs I had to fix, both about honesty

The interesting part of building this was not the DNS. It was getting the tool to stop claiming more than it knew.

Bug one: ASN evidence proved less than I assumed. My first version accepted "this address is on Amazon's network" as evidence of CloudFront. Then I ran it against my own site, which is on Vercel, and it confidently reported CloudFront. Of course it did: AMAZON-02 carries EC2 and a hundred other things. Being on a cloud's network says nothing about which of that cloud's products is in front of you.

Now ASN evidence only counts for networks that are exclusively edges: Cloudflare, Akamai, Fastly, Imperva, Sucuri. Amazon, Google, Microsoft and Alibaba run general compute on the same ASNs, so for those the tool demands a CNAME or a header and refuses to guess.

Bug two: "not detected" is not "not protected." The first version printed a hard failure saying traffic reached the origin without passing a scrubbing layer. Then I ran it against a large platform that operates its own first-party edge. It matched no third-party signature, so the tool declared it exposed. It is not exposed. It just does not look like anyone else.

That result is now INCONCLUSIVE. The tool prints the server banner, says plainly that it cannot distinguish "no edge" from "an edge I do not recognise," and hands the judgment back to you.

Absence of recognition is not evidence of absence. A security tool that forgets this produces confident numbers that are wrong, which is worse than producing no number.

Three outcomes, and what they are worth

Result Exit Meaning
IN PATH 0 Every hostname checked transits a recognised edge.
INCONCLUSIVE 1 Nothing recognised. Read the server banner before concluding anything.
MIXED PATH 2 Some hostnames are fronted, others reach the origin directly.

Only one of those is a finding. That is intentional.

What it deliberately does not tell you

Knowing protection is in the path tells you traffic arrives. It says nothing about what happens next.

It does not tell you whether the edge classifies a flood as an attack or as popularity. It does not tell you the rate-limit threshold, or whether that threshold sits above or below the point your origin starts shedding. It does not tell you how many seconds elapse before mitigation engages, and those seconds are usually where the outage actually lives.

Three different things get run together, and the distinction matters under load:

  • Provisioned: you are paying for it.
  • In the path: traffic actually transits it.
  • Effective: it holds when something real arrives.

This tool answers the middle one. The middle one is worth answering because it is cheap, checkable, and wrong more often than anyone expects. The last one needs a test, not a lookup.

Run it on your own domain

cargo run --release -- example.com
Enter fullscreen mode Exit fullscreen mode

Rust 2021, stable, two dependencies, one main.rs. MIT.

Point it at domains you own or are authorized to test, and check more than the apex and www. Origins hide behind api, dev, staging, and mail far more often, because those are the names nobody thinks of as public.

Repo: https://github.com/BlackNeuron-ai/ddos-protection-path-check

Same series: origin-exposure-check (is your origin reachable past the CDN?), dns-resilience-check (is your DNS a single point of failure?), edge-cache-check (does your edge actually absorb the flood?).

Top comments (0)