Entwickler-Referenz

Vergleich rekursiver DNS-Resolver

DomScan-API: Vergleichen Sie DNS-Antworten von zwei unabhängig abgefragten öffentlichen rekursiven DoH-Anbietern: Cloudflare und Google.

Vergleich rekursiver DNS-Resolver

Vergleichen Sie DNS-Antworten von zwei unabhängig abgefragten öffentlichen rekursiven DoH-Anbietern: Cloudflare und Google. Beide sind globale Anycast-Dienste. Die Ergebnisse sind Beobachtungen aus dem Anfragepfad, keine geografischen Messpunkte, keine Abfragen autoritativer Nameserver und kein Nachweis einer weltweiten Propagation.

GET /v1/dns/propagation

Abfrageparameter

ParameterTypBeschreibung
domain erforderlich string Domain, die über jeden konfigurierten Resolver abgefragt wird (z. B. "example.com")
type optional string Datensatztyp: A, AAAA, CNAME, MX, TXT, NS, SOA (Standard: A)
expected optional string Optionaler erwarteter Eintragswert als Vergleichsgrundlage (z. B. eine neue IP-Adresse)

Antwortfelder

FeldTypBeschreibung
propagation_percentagenumberOhne expected: größte Gruppe identischer Antworten geteilt durch alle konfigurierten Resolver. Mit expected: exakte Übereinstimmungen mit dem erwarteten Wert geteilt durch alle konfigurierten Resolver. Fehler bleiben im Nenner (0-100)
fully_propagatedbooleanWahr, wenn innerhalb der konfigurierten Stichprobe alle Resolver übereinstimmen oder, falls expected angegeben ist, alle den erwarteten Wert zurückgeben
consistentbooleanWahr nur dann, wenn jeder konfigurierte Resolver erfolgreich antwortet und alle dieselbe kanonische Antwortmenge zurückgeben
unique_valuesarrayEindeutige Eintragswerte, die von erfolgreichen Resolvern zurückgegeben wurden
resultsarrayAnbieter, Einträge, beobachtete TTL, Antwortzeit aus dem Anfragepfad und Fehler pro Resolver

Beispielanfrage

# Compare A records across configured resolvers
curl -H "X-API-Key: your-api-key" "https://domscan.net/v1/dns/propagation?domain=example.com&type=A"

# Compare MX answers against an expected value
curl -H "X-API-Key: your-api-key" "https://domscan.net/v1/dns/propagation?domain=example.com&type=MX&expected=mail.example.com"
const domscanFetch = (url, options = {}) =>
  fetch(url, {
    ...options,
    headers: { ...options.headers, "X-API-Key": "your-api-key" },
  });

const url = new URL("https://domscan.net/v1/dns/propagation");
url.searchParams.set("domain", "example.com");
url.searchParams.set("type", "A");
url.searchParams.set("expected", "203.0.113.42");

const response = await domscanFetch(url);
const data = await response.json();

// Legacy response field names are retained for API compatibility.
console.log(`Resolver convergence: ${data.propagation_percentage}%`);
console.log(`All configured resolvers match: ${data.fully_propagated}`);

// Check which servers are still showing old values
data.results
  .filter(r => !r.success || !r.records.includes(data.expected_value))
  .forEach(r => console.log(`${r.server.name}: ${r.records}`));
import requests

domscan = requests.Session()
domscan.headers.update({"X-API-Key": "your-api-key"})

response = domscan.get(
    "https://domscan.net/v1/dns/propagation",
    params={"domain": "example.com", "type": "A"}
)
data = response.json()

# Legacy response field names are retained for API compatibility.
print(f"Resolver convergence: {data['propagation_percentage']}%")
print(f"All configured resolvers match: {data['fully_propagated']}")

# Show servers with different values
for result in data['results']:
    print(f"{result['server']['name']}: {result['records']}")
package main

import (
  "encoding/json"
  "fmt"
  "net/http"
  "os"
)

func domscanGet(url string) (*http.Response, error) {
  request, err := http.NewRequest(http.MethodGet, url, nil)
  if err != nil {
    return nil, err
  }
  request.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
  return http.DefaultClient.Do(request)
}

func main() {
  resp, _ := domscanGet("https://domscan.net/v1/dns/propagation?domain=example.com&type=A")
  defer resp.Body.Close()

  var data map[string]interface{}
  json.NewDecoder(resp.Body).Decode(&data)

  // Legacy response field names are retained for API compatibility.
  fmt.Printf("Resolver convergence: %.0f%%\n", data["propagation_percentage"])
  fmt.Printf("All configured resolvers match: %v\n", data["fully_propagated"])
}
require 'net/http'
require 'json'

uri = URI("https://domscan.net/v1/dns/propagation?domain=example.com&type=A")
request = Net::HTTP::Get.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
data = JSON.parse(response.body)

# Legacy response field names are retained for API compatibility.
puts "Resolver convergence: #{data['propagation_percentage']}%"
puts "All configured resolvers match: #{data['fully_propagated']}"

Beispielantwort

{
  "domain": "example.com",
  "record_type": "A",
  "measurement_scope": "configured_recursive_resolvers",
  "percentage_basis": "resolver_convergence",
  "propagation_percentage": 100,
  "fully_propagated": true,
  "consistent": true,
  "unique_values": ["93.184.216.34"],
  "results": [
    {
      "server": {
        "name": "Cloudflare 1.1.1.1",
        "ip": "1.1.1.1",
        "provider": "Cloudflare",
        "location": "Global anycast",
        "country": "GLOBAL",
        "scope": "global-anycast",
        "doh_endpoint": "https://cloudflare-dns.com/dns-query"
      },
      "success": true,
      "records": ["93.184.216.34"],
      "ttl": 86400,
      "response_time_ms": 12
    },
    {
      "server": {
        "name": "Google Public DNS",
        "ip": "8.8.8.8",
        "provider": "Google",
        "location": "Global anycast",
        "country": "GLOBAL",
        "scope": "global-anycast",
        "doh_endpoint": "https://dns.google/resolve"
      },
      "success": true,
      "records": ["93.184.216.34"],
      "ttl": 86400,
      "response_time_ms": 15
    }
  ],
  "summary": {
    "total_servers": 2,
    "successful": 2,
    "failed": 0
  }
}
GET /v1/dns/servers

Listet die zwei öffentlichen rekursiven DoH-Anbieter auf, die für den Vergleich verwendet werden: Cloudflare und Google. Beide sind globale Anycast-Resolver, keine geografischen Messpunkte und keine autoritativen Nameserver.

Beispielantwort

{
  "measurement_scope": "configured_recursive_resolvers",
  "geographic_vantage": false,
  "servers": [
    {
      "name": "Cloudflare 1.1.1.1",
      "ip": "1.1.1.1",
      "provider": "Cloudflare",
      "location": "Global anycast",
      "country": "GLOBAL",
      "scope": "global-anycast",
      "doh_endpoint": "https://cloudflare-dns.com/dns-query"
    },
    {
      "name": "Google Public DNS",
      "ip": "8.8.8.8",
      "provider": "Google",
      "location": "Global anycast",
      "country": "GLOBAL",
      "scope": "global-anycast",
      "doh_endpoint": "https://dns.google/resolve"
    }
  ],
  "total": 2
}

Antwortfelder

Feld Typ
measurement_scope string
geographic_vantage boolean
servers[] object[]
servers[] object
servers[].name string
servers[].location string
servers[].country string
servers[].ip string
servers[].provider string
servers[].scope string
servers[].doh_endpoint string
servers[].documentation_url string
servers[].format string
total integer
meta object
meta.served_by string
POST /v1/dns/propagation/bulk Credits: 2/item

Abfrageparameter

Parameter Typ erforderlich
dry_run string
Zulässige Werte true
optional

Body-Parameter

Parameter Typ erforderlich
domains string[] erforderlich
type string
Zulässige Werte AAAAACNAMEMXTXTNSSOA
Standard A
optional
expected string optional

Antwortfelder

Feld Typ
results[] unknown[]
meta object
meta.total integer
meta.succeeded integer
meta.failed integer
meta.max_items integer
meta.credits_per_item integer
meta.duration_ms integer

Beispielanfrage

curl -X POST "https://domscan.net/v1/dns/propagation/bulk" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $DOMSCAN_API_KEY" \
  -d '{
  "domains": [
    "example.com",
    "cloudflare.com"
  ],
  "type": "A"
}'
const response = await fetch("https://domscan.net/v1/dns/propagation/bulk", {
  method: "POST",
  headers: { "X-API-Key": process.env.DOMSCAN_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "domains": [
      "example.com",
      "cloudflare.com"
    ],
    "type": "A"
  }),
});
const data = await response.json();
console.log(data);
import os
import requests

response = requests.post(
    "https://domscan.net/v1/dns/propagation/bulk",
    headers={"X-API-Key": os.environ["DOMSCAN_API_KEY"]},
    json={
        "domains": [
            "example.com",
            "cloudflare.com",
        ],
        "type": "A",
    },
)
print(response.json())
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strings"
)

func main() {
	body := strings.NewReader(`{
	  "domains": [
	    "example.com",
	    "cloudflare.com"
	  ],
	  "type": "A"
	}`)
	req, err := http.NewRequest(http.MethodPost, "https://domscan.net/v1/dns/propagation/bulk", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("X-API-Key", os.Getenv("DOMSCAN_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(resp.Status, string(data))
}
require "json"
require "net/http"

uri = URI("https://domscan.net/v1/dns/propagation/bulk")
request = Net::HTTP::Post.new(uri)
request["X-API-Key"] = ENV.fetch("DOMSCAN_API_KEY")
request["Content-Type"] = "application/json"
request.body = JSON.generate({
  "domains" => [
    "example.com",
    "cloudflare.com"
  ],
  "type" => "A"
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end
puts JSON.pretty_generate(JSON.parse(response.body))

Beispielantwort

{
  "results": [
    {
      "input": "example",
      "data": {}
    }
  ],
  "meta": {
    "total": 1,
    "succeeded": 1,
    "failed": 1,
    "max_items": 10,
    "credits_per_item": 1,
    "duration_ms": 1
  }
}

HTTP-Statuscodes

  • 200 OK
  • 400 Ungültige Anfrage
  • 401 Nicht autorisiert
  • 402 Zahlung erforderlich
  • 409 HTTP 409
  • 422 HTTP 422
  • 429 Zu viele Anfragen