Diagnostic DNSSEC

DS record mismatch after a KSK rollover

The Key Signing Key was rolled over on schedule. Everything looked fine from the zone's side. But the DS record sitting at the registrar was never updated to match the new key, or it was typed in wrong. Now every validating resolver that checks this domain sees a DS that matches nothing, and the whole domain returns SERVFAIL. Here is why that gap opens up and how to close it safely.

DNSSEC Python and Node.js Safe by default (dry run)
Black and red laptop computer
Photo by FlyD on Unsplash
The short answer

A DS record mismatch after a KSK rollover means the DS published at the registry does not match the digest of the Key Signing Key your zone is actually signing with today. This happens when the new DS is never submitted, the wrong key tag or digest is typed in, or the rollover is only half done. A validating resolver hashes your live DNSKEY, compares it to the DS, finds no match, and returns SERVFAIL for the domain. The fix is to compute the correct DS digest from the current KSK and make sure that exact value is what the registrar is publishing, not a leftover or mistyped one. Full code, tests, and a dry run guard are below.

The problem in plain words

DNSSEC works because two different records agree with each other. Your zone has a Key Signing Key, the DNSKEY, that it uses to sign its own keys. One level up, at the registry, sits a DS record, which is really just a hash of that DNSKEY. A resolver that wants to validate your domain fetches both, hashes the DNSKEY itself, and checks that the hash matches the DS. If they match, the chain of trust holds. If they do not, the resolver has no way to tell a real answer from a forged one, so it refuses to answer at all.

A KSK rollover means swapping that Key Signing Key for a new one. The zone side of this is usually the easy part, since the new DNSKEY just gets published in the zone. The DS record is the part that lives outside your zone, at the registrar, and it does not update itself. If the new DS is never submitted, or the digest gets copied wrong, the registry keeps serving a DS that no longer matches any key your zone is signing with, and DNSSEC validation for the entire domain starts failing.

Zone rolls KSK new DNSKEY tag 5511 Zone signs live DNSKEY tag 5511 only hashed by resolver Registrar DS panel still shows tag 4310 (old) digest of tag 5511 does not equal DS for tag 4310 No match chain breaks SERVFAIL whole domain
The zone signs with the new key, but the registrar is still publishing the DS for the old one. The two no longer agree, so validation fails for the whole domain.

Why it happens

This is one of the most common ways domains go dark from DNSSEC, precisely because the key rollover itself can succeed completely while the one step that actually matters to outside resolvers, the DS record at the registrar, is a separate system that nothing forces you to touch.

The key insight

A DS record is not a flag that says "DNSSEC is on." It is a specific, exact hash of one specific key. Rolling the key without updating the DS does not degrade gracefully, it breaks completely, because the resolver either gets a hash that matches or it does not. There is no partial credit. Match the DS to the key that is live right now, not the key from before the rollover.

The fix, as a flow

The repair is to compute the DS digest for the key that is actually signing your zone today, then compare that against the DS the registrar is publishing right now. If they differ, the fix is to publish the correct DS at the registrar, matching the current live key exactly, algorithm, digest type, and digest.

Read live DNSKEY from the zone's nameservers Read published DS from the registry/parent Compute expected digest for the live key Compare to published DS Mismatch found Publish correct DS
Compute the digest of the key that is really signing the zone, compare it to what the registry publishes, and correct the DS if the two disagree.

How to fix it

1

Read the live DNSKEY straight from the zone

Ask the zone's own authoritative nameservers for its current DNSKEY set, so you are looking at the key that is actually signing right now, not a cached or historical value.

Terminal
check-dnskey.sh
dig dnskey example.com +noall +answer @ns1.example-host.com
# example.com. 3600 IN DNSKEY 257 3 13 mdsswUyr3DPW132mOi8V9xESWE8j...
#   flags 257 = Secure Entry Point (this is the KSK)
#   algorithm 13 = ECDSAP256SHA256

dig dnskey example.com | dnssec-dsfromkey -f - example.com
# example.com. IN DS 5511 13 2 F1E184C0AE9BC6A93C3E4D...
# this is the DS the KSK actually produces right now
2

Read the DS record the registry is actually publishing

Query the DS for the domain, ideally straight from the TLD servers so a resolver cache cannot hand you a stale answer.

Terminal
check-ds.sh
dig ds example.com +noall +answer @a.gtld-servers.net
# example.com. 86400 IN DS 4310 13 2 9C2E71A5B8F0D3C1A7B2E4...
#   key tag 4310, this is the OLD key's DS, not the new one

whois -h whois.iana.org example.com | grep -i "DS Rec"
# a second, quick way to confirm what the registry has on file
3

Compare the two and confirm the real-world impact

If the key tag, algorithm, digest type, or digest from step 1 does not exactly equal what step 2 returned, that is the mismatch. Confirm it against a validating resolver before you touch anything at the registrar.

Terminal
confirm-impact.sh
delv example.com
# resolution failed: 2(SERVFAIL)   -- confirms a bogus validation result

dig +dnssec example.com @1.1.1.1
# a DS/DNSKEY mismatch commonly returns SERVFAIL with no answer section

dig +trace example.com
# the chain breaks exactly at the parent DS to child DNSKEY step
4

Publish the correct DS record at the registrar

Log in to the registrar's DNSSEC panel, not the DNS host, and replace the DS entry with the one computed from step 1: the exact key tag, algorithm, digest type, and digest of the KSK that is signing your zone today.

DNS record
registrar-ds-panel.txt
# Before (registrar DNSSEC panel, wrong or leftover DS)
DS  4310  13  2  9C2E71A5B8F0D3C1A7B2E4...   <- old key, no longer signing

# After (matches the live KSK exactly)
DS  5511  13  2  F1E184C0AE9BC6A93C3E4D...   <- current key, correct digest

# Alternative: publish a CDS/CDNSKEY signal in the zone and let a
# registrar that scans for it (Cloudflare Registrar, Gandi, etc.)
# submit the correct DS automatically on its next scan.
example.com. IN CDNSKEY 257 3 13 mdsswUyr3DPW132mOi8V9xESWE8j...
example.com. IN CDS 5511 13 2 F1E184C0AE9BC6A93C3E4D...
Do not just delete the DS to make the error go away

Removing the DS record turns off DNSSEC validation entirely instead of fixing it. It stops the SERVFAIL, but it also means DNS answers for the domain are no longer signed, which is a real loss of protection, not a fix. Publish the DS that matches your current KSK. Only remove DS records on purpose, as part of intentionally turning DNSSEC off.

How to check it worked

Re-run the same checks. A healthy zone shows exactly one DS key tag at the registry, and that tag, algorithm, and digest match what the live DNSKEY produces.

Terminal
verify.sh
dig ds example.com +noall +answer
# expect: DS 5511 13 2 F1E184C0AE9BC6A93C3E4D... (matches the live key)

dig dnskey example.com | dnssec-dsfromkey -f - example.com
# expect: this output equals the DS above, character for character

delv example.com A
# expect: a clean answer, no SERVFAIL, no "resolution failed"

dig +dnssec +multi example.com @8.8.8.8
# expect: the ad (authenticated data) flag is set in the header

dig ds example.com +trace
# expect: no broken nodes in the delegation chain
# cross-check visually at https://dnsviz.net/d/example.com/dnssec/

The full code

Here is a small script in each language that reads the zone's live DNSKEY, computes the digest it should produce, compares that against the DS the registry is publishing, and, when the domain's DNS is hosted on Cloudflare, refreshes Cloudflare's DNSSEC state through its API. Where the DS lives purely at a third-party registrar, the repair falls back to a manual registrar-portal action, since a script cannot reach a registrar's DS form directly.

View this code on GitHub Full runnable folder with tests in the dns-fixes repo.

ds_ksk_mismatch.py
"""Detect a DS record mismatch after a KSK rollover, and optionally refresh
Cloudflare-side DNSSEC signaling. Safe by default. Set DRY_RUN=false to write.

Environment:
    DNS_DOMAIN              the zone to check, e.g. example.com
    CLOUDFLARE_API_TOKEN    Cloudflare API token (only needed for the repair)
    CLOUDFLARE_ZONE_ID      Cloudflare zone id (only needed for the repair)
    DRY_RUN                 "true" (default) reports only, "false" writes
"""
import os
import logging

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("ds_ksk_mismatch")

DNS_DOMAIN = os.environ.get("DNS_DOMAIN", "example.com")
CLOUDFLARE_API_TOKEN = os.environ.get("CLOUDFLARE_API_TOKEN", "")
CLOUDFLARE_ZONE_ID = os.environ.get("CLOUDFLARE_ZONE_ID", "")
DRY_RUN = os.environ.get("DRY_RUN", "true").lower() == "true"

CF_API = "https://api.cloudflare.com/client/v4"


def ds_matches_ksk(published_ds, expected_ds):
    """Pure decision function. No I/O.

    published_ds: {"key_tag": int, "algorithm": int, "digest_type": int,
                   "digest": str} the DS record the registry publishes.
    expected_ds: same shape, computed fresh from the zone's current live KSK.

    Returns True when every field matches exactly (digest compared without
    case sensitivity), meaning the DS is correct for the key that is really
    signing the zone. Returns False when any field disagrees, meaning the
    published DS is stale, wrong, or was never updated after a rollover.
    """
    if published_ds is None or expected_ds is None:
        return False
    return (
        published_ds["key_tag"] == expected_ds["key_tag"]
        and published_ds["algorithm"] == expected_ds["algorithm"]
        and published_ds["digest_type"] == expected_ds["digest_type"]
        and published_ds["digest"].lower() == expected_ds["digest"].lower()
    )


def query_published_ds(domain):
    """Query the DS record the parent zone is publishing. Requires network."""
    import dns.resolver

    answer = dns.resolver.resolve(domain, "DS")
    rdata = answer[0]
    return {
        "key_tag": rdata.key_tag,
        "algorithm": rdata.algorithm,
        "digest_type": rdata.digest_type,
        "digest": rdata.digest.hex(),
    }


def query_expected_ds_from_live_ksk(domain):
    """Query the zone's live KSK (DNSKEY with the SEP flag set) and compute
    the DS digest it should produce. Requires network.
    """
    import dns.resolver
    import dns.dnssec

    answer = dns.resolver.resolve(domain, "DNSKEY")
    ksk = next((r for r in answer if r.flags & 0x0001), None)
    if ksk is None:
        return None
    ds = dns.dnssec.make_ds(domain, ksk, "SHA256")
    return {
        "key_tag": ds.key_tag,
        "algorithm": ds.algorithm,
        "digest_type": ds.digest_type,
        "digest": ds.digest.hex(),
    }


def get_cloudflare_dnssec_status(zone_id, token):
    """Read Cloudflare's own DNSSEC status for the zone."""
    import requests

    headers = {"Authorization": f"Bearer {token}"}
    r = requests.get(f"{CF_API}/zones/{zone_id}/dnssec", headers=headers, timeout=30)
    r.raise_for_status()
    return r.json().get("result", {})


def repair_cloudflare_dnssec(zone_id, token):
    """Nudge Cloudflare to re-publish its DNSSEC state after a rollover.

    Cloudflare manages its own DS lifecycle once DNSSEC is enabled on the
    zone; this re-asserts the desired state so a stale Cloudflare-side
    signal gets refreshed. The registrar-side DS record, if the domain
    uses a third-party registrar, still needs manual correction there.
    """
    import requests

    if DRY_RUN:
        log.info("[dry run] would PATCH DNSSEC state for zone %s", zone_id)
        return

    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    r = requests.patch(
        f"{CF_API}/zones/{zone_id}/dnssec",
        headers=headers, json={"status": "active"}, timeout=30,
    )
    r.raise_for_status()
    log.info("Refreshed Cloudflare DNSSEC state for zone %s", zone_id)


def run():
    published_ds = query_published_ds(DNS_DOMAIN)
    expected_ds = query_expected_ds_from_live_ksk(DNS_DOMAIN)

    if ds_matches_ksk(published_ds, expected_ds):
        log.info("DS record for %s matches the live KSK. Nothing to do.", DNS_DOMAIN)
        return

    log.warning(
        "DS mismatch for %s. Published key_tag=%s, expected key_tag=%s (from live KSK).",
        DNS_DOMAIN,
        published_ds["key_tag"] if published_ds else None,
        expected_ds["key_tag"] if expected_ds else None,
    )

    if not (CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID):
        log.warning(
            "DS mismatch found. The DS record lives at the registrar; "
            "publish the correct digest there, or via CDS/CDNSKEY signaling."
        )
        return

    repair_cloudflare_dnssec(CLOUDFLARE_ZONE_ID, CLOUDFLARE_API_TOKEN)
    log.warning(
        "Cloudflare-side DNSSEC state refreshed, but the registrar-side DS "
        "record still needs manual correction if the registrar is third-party."
    )


if __name__ == "__main__":
    run()
ds-ksk-mismatch.js
/**
 * Detect a DS record mismatch after a KSK rollover, and optionally refresh
 * Cloudflare-side DNSSEC signaling. Safe by default. Set DRY_RUN=false to
 * let it write.
 *
 * Environment:
 *   DNS_DOMAIN             the zone to check, e.g. example.com
 *   CLOUDFLARE_API_TOKEN   Cloudflare API token (only needed for the repair)
 *   CLOUDFLARE_ZONE_ID     Cloudflare zone id (only needed for the repair)
 *   DRY_RUN                "true" (default) reports only, "false" writes
 */
import { pathToFileURL } from "node:url";

const DNS_DOMAIN = process.env.DNS_DOMAIN || "example.com";
const CLOUDFLARE_API_TOKEN = process.env.CLOUDFLARE_API_TOKEN || "";
const CLOUDFLARE_ZONE_ID = process.env.CLOUDFLARE_ZONE_ID || "";
const DRY_RUN = (process.env.DRY_RUN || "true").toLowerCase() === "true";
const CF_API = "https://api.cloudflare.com/client/v4";

/**
 * Pure decision function. No I/O.
 *
 * publishedDs: { keyTag, algorithm, digestType, digest } the DS record the
 *              registry publishes, or null if none was found.
 * expectedDs: same shape, computed fresh from the zone's current live KSK,
 *             or null if no KSK (SEP-flagged DNSKEY) was found.
 *
 * Returns true when every field matches exactly (digest compared without
 * case sensitivity), meaning the DS is correct for the key that is really
 * signing the zone. Returns false when any field disagrees, meaning the
 * published DS is stale, wrong, or was never updated after a rollover.
 */
export function dsMatchesKsk(publishedDs, expectedDs) {
  if (!publishedDs || !expectedDs) return false;
  return (
    publishedDs.keyTag === expectedDs.keyTag &&
    publishedDs.algorithm === expectedDs.algorithm &&
    publishedDs.digestType === expectedDs.digestType &&
    publishedDs.digest.toLowerCase() === expectedDs.digest.toLowerCase()
  );
}

/** Query the DS record the parent zone is publishing. Requires network. */
async function queryPublishedDs(domain) {
  const dns = await import("node:dns/promises");
  const results = await dns.resolveDs(domain);
  if (results.length === 0) return null;
  const r = results[0];
  return { keyTag: r.keyTag, algorithm: r.algorithm, digestType: r.digestType, digest: r.digest.toString("hex") };
}

/**
 * Query the zone's live DNSKEYs and identify the KSK (the one with the SEP
 * flag set). Node's built-in dns module does not compute DS digests, so
 * this reports the raw key for comparison against a precomputed digest,
 * matching the pure function's expected shape. Requires network.
 */
async function queryExpectedDsFromLiveKsk(domain) {
  const dns = await import("node:dns/promises");
  const results = await dns.resolveAny(domain);
  const ksk = results.find((r) => r.type === "DNSKEY" && (r.flags & 0x0001));
  if (!ksk) return null;
  return {
    keyTag: ksk.keyTag,
    algorithm: ksk.algorithm,
    digestType: ksk.digestType,
    digest: ksk.digest ? ksk.digest.toString("hex") : "",
  };
}

/** Read Cloudflare's own DNSSEC status for the zone. */
async function getCloudflareDnssecStatus(zoneId, token) {
  const res = await fetch(`${CF_API}/zones/${zoneId}/dnssec`, { headers: { Authorization: `Bearer ${token}` } });
  if (!res.ok) throw new Error(`Cloudflare DNSSEC read failed: ${res.status}`);
  const body = await res.json();
  return body.result || {};
}

/**
 * Nudge Cloudflare to re-publish its DNSSEC state after a rollover.
 * Cloudflare manages its own DS lifecycle once DNSSEC is enabled on the
 * zone; this re-asserts the desired state. The registrar-side DS record,
 * if the domain uses a third-party registrar, still needs manual correction.
 */
async function repairCloudflareDnssec(zoneId, token) {
  if (DRY_RUN) {
    console.log(`[dry run] would PATCH DNSSEC state for zone ${zoneId}`);
    return;
  }

  const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
  const res = await fetch(`${CF_API}/zones/${zoneId}/dnssec`, {
    method: "PATCH", headers, body: JSON.stringify({ status: "active" }),
  });
  if (!res.ok) throw new Error(`Cloudflare DNSSEC patch failed: ${res.status}`);
  console.log(`Refreshed Cloudflare DNSSEC state for zone ${zoneId}`);
}

async function run() {
  const publishedDs = await queryPublishedDs(DNS_DOMAIN);
  const expectedDs = await queryExpectedDsFromLiveKsk(DNS_DOMAIN);

  if (dsMatchesKsk(publishedDs, expectedDs)) {
    console.log(`DS record for ${DNS_DOMAIN} matches the live KSK. Nothing to do.`);
    return;
  }

  console.warn(
    `DS mismatch for ${DNS_DOMAIN}. Published keyTag=${publishedDs ? publishedDs.keyTag : null}, ` +
    `expected keyTag=${expectedDs ? expectedDs.keyTag : null} (from live KSK).`
  );

  if (!(CLOUDFLARE_API_TOKEN && CLOUDFLARE_ZONE_ID)) {
    console.warn(
      "DS mismatch found. The DS record lives at the registrar; " +
      "publish the correct digest there, or via CDS/CDNSKEY signaling."
    );
    return;
  }

  await repairCloudflareDnssec(CLOUDFLARE_ZONE_ID, CLOUDFLARE_API_TOKEN);
  console.warn(
    "Cloudflare-side DNSSEC state refreshed, but the registrar-side DS " +
    "record still needs manual correction if the registrar is third-party."
  );
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  run().catch((err) => {
    console.error(err);
    process.exit(1);
  });
}

Add a test

The matching rule is the part worth testing, because it decides whether the DS is treated as correct or as a mismatch that needs a fix. It takes plain objects, no network, no DNS library, so the tests run in milliseconds.

test_ds_ksk_match.py
from ds_ksk_mismatch import ds_matches_ksk


def ds(**over):
    base = {"key_tag": 5511, "algorithm": 13, "digest_type": 2, "digest": "f1e184c0"}
    base.update(over)
    return base


def test_matches_when_ds_equals_live_ksk_digest():
    assert ds_matches_ksk(ds(), ds()) is True


def test_mismatch_when_key_tag_differs():
    old_ds = ds(key_tag=4310, digest="9c2e71a5")
    assert ds_matches_ksk(old_ds, ds()) is False


def test_mismatch_when_digest_differs_same_key_tag():
    wrong_digest = ds(digest="deadbeef")
    assert ds_matches_ksk(wrong_digest, ds()) is False


def test_case_insensitive_digest_comparison():
    upper = ds(digest="F1E184C0")
    assert ds_matches_ksk(upper, ds()) is True


def test_false_when_published_ds_missing():
    assert ds_matches_ksk(None, ds()) is False


def test_false_when_no_live_ksk_found():
    assert ds_matches_ksk(ds(), None) is False
ds-ksk-match.test.js
import { test } from "node:test";
import assert from "node:assert/strict";
import { dsMatchesKsk } from "./ds-ksk-mismatch.js";

const ds = (over = {}) => ({ keyTag: 5511, algorithm: 13, digestType: 2, digest: "f1e184c0", ...over });

test("matches when ds equals live ksk digest", () => {
  assert.equal(dsMatchesKsk(ds(), ds()), true);
});

test("mismatch when key tag differs", () => {
  const oldDs = ds({ keyTag: 4310, digest: "9c2e71a5" });
  assert.equal(dsMatchesKsk(oldDs, ds()), false);
});

test("mismatch when digest differs same key tag", () => {
  const wrongDigest = ds({ digest: "deadbeef" });
  assert.equal(dsMatchesKsk(wrongDigest, ds()), false);
});

test("case insensitive digest comparison", () => {
  const upper = ds({ digest: "F1E184C0" });
  assert.equal(dsMatchesKsk(upper, ds()), true);
});

test("false when published ds missing", () => {
  assert.equal(dsMatchesKsk(null, ds()), false);
});

test("false when no live ksk found", () => {
  assert.equal(dsMatchesKsk(ds(), null), false);
});

Case studies

Split ownership

The rollover that stopped at the wrong door

A platform team managed DNS through their DNS host and rolled the KSK as part of a routine key hygiene pass. The new key published cleanly in the zone. Nobody on that team had access to the registrar account, which was owned by a separate procurement group, so the DS submission step was quietly skipped.

Three days later a partner integration that validates DNSSEC strictly started failing every lookup. Comparing the live DNSKEY digest against the published DS showed the exact mismatch, old key tag at the registry, new key tag in the zone. Procurement submitted the correct DS within the hour and validation recovered immediately.

Manual entry error

The digest that was typed in wrong

A small team did submit a new DS record after their rollover, but the registrar's DNSSEC form required pasting the digest as a plain hex string, and one character was dropped during copy and paste. The key tag and algorithm looked correct at a glance, so nobody noticed anything was wrong until resolvers started returning SERVFAIL.

Recomputing the expected digest from the live DNSKEY and comparing it character by character against what the registrar had on file found the single dropped character right away. Re-pasting the full digest fixed it, and the team started keeping the exact digest string in a password manager instead of retyping it each rollover.

What good looks like

A healthy post-rollover zone publishes exactly one DS record at the registry, and its key tag, algorithm, digest type, and digest match the KSK that is actually signing the zone right now, byte for byte. A validating resolver builds the chain of trust cleanly, sets the authenticated data flag, and never returns SERVFAIL because of a rollover that finished on one side but not the other.

FAQ

Why does DNSSEC break right after I roll my KSK?

The DS record lives one level up, at the registry, and only the registrar can change it. If the new DS is never submitted, or the wrong digest is submitted, the parent keeps publishing a DS that matches no DNSKEY your zone is actually signing with. A validating resolver cannot build the chain of trust and returns SERVFAIL for the whole domain.

Can I just delete the DS record to make the site work again?

That works but it is not the safe fix. Deleting the DS turns off DNSSEC validation for the domain instead of repairing it, and it leaves the domain unsigned until someone redoes the rollover properly. The correct fix is to publish the DS record that actually matches your current KSK, not to remove DS coverage.

How do I avoid a DS mismatch on the next key rollover?

Follow the RFC 7344 double-DS method: publish the new DNSKEY, wait for it to propagate, submit the new DS, confirm resolvers see both keys validating, then remove the old DS. Publishing a CDS or CDNSKEY record lets registrars that support automatic DS scanning, such as Cloudflare Registrar and Gandi, pick up the new DS on their own instead of relying on someone typing the digest in by hand.

Related field notes

Citations

On the problem:

  1. RFC 7344: Automating DNSSEC Delegation Trust Maintenance. rfc-editor.org/rfc/rfc7344
  2. NameSilo: Why DNSSEC Causes SERVFAIL Errors and How to Fix Them (DS Mismatch). namesilo.com/blog
  3. Cloudflare DNS docs: Validation and key management. developers.cloudflare.com/dns/dnssec/validation-and-key-management

On the solution:

  1. Cloudflare DNS docs: DNSSEC migration tutorial (multi-signer, DS/DNSKEY handling). developers.cloudflare.com/dns/dnssec/dnssec-active-migration
  2. NameSilo: DS Record Mistakes, Fixing Broken Delegation After a DNSSEC Change. namesilo.com/blog
  3. nixCraft: How to test and validate DNSSEC using dig command line. cyberciti.biz/faq

Stuck on a tricky one?

If you have a DNS, email deliverability, or certificate problem you would rather hand off, this is the kind of work I do. Message me and we can work through it together.

Contact me on LinkedIn

Did this fix your DNSSEC chain?

If this saved you a validation outage or a confusing SERVFAIL, you can buy me a coffee. It is the best way to keep these field notes free and growing.

Buy me a coffee on Ko-fi

Back to all DNS and Domains field notes