Nameserver09

Status: Final

Purpose

  • Compare nameserver results for two differently cased query names that are equivalent under DNS case-insensitive matching.

Preconditions And Inputs

  • Preconditions:
    • A zone.Zone object is available.
  • Required inputs:
    • Nameserver addresses from ZoneNameservers .
    • SOA query responses for two randomized-case www.<zone> names.
  • Profile/config knobs that affect behavior:
    • net.ipv4 and net.ipv6: disabled transports are skipped with transport debug tags.
    • resolver.defaults.parallel: parallel nameserver query fanout.

Algorithm And Decision Flow

  1. Emit TEST_CASE_START.
  2. Build original = "www." + <zone> (trailing dot removed), record type SOA.
  3. Generate two randomized case variants (random1, random2) such that both differ from original and from each other.
  4. Read nameserver list from ZoneNameservers , deduplicate by name/ip, preserving first-seen order.
  5. For each deduplicated nameserver (parallelized, input-order merged logs):
    • If transport is disabled, emit IPV4_DISABLED or IPV6_DISABLED for rrtype SOA, store no mismatch for this nameserver, and skip.
    • Query random1 and random2.
    • If first query has answer RRs:
      • Compare normalized (sorted, lowercased) answer sets.
      • Emit CASE_QUERY_SAME_ANSWER when equal, else emit CASE_QUERY_DIFFERENT_ANSWER and mark mismatch.
    • Else if both queries returned DNS messages:
      • Compare response RCODE strings.
      • Emit CASE_QUERY_SAME_RC when equal, else emit CASE_QUERY_DIFFERENT_RC and mark mismatch.
    • Else if exactly one query returned a DNS message:
      • Emit CASE_QUERY_NO_ANSWER and mark mismatch.
    • Else (both queries missing DNS messages):
      • Emit no per-server case-result tag and keep mismatch unset.
  6. If no nameserver outcome is marked mismatch, emit CASE_QUERIES_RESULTS_OK; else emit CASE_QUERIES_RESULTS_DIFFER.
  7. Emit TEST_CASE_END.

Per-NS Case-Variant Comparison (steps 2-7)

original = "www." + z.Name (trailing dot stripped); recordType = SOA
random1 = scrambleCase(original)  // != original
random2 = scrambleCase(original)  // != original, != random1

ns list = ZoneNameservers; dedupe by ns key, preserve first-seen order

For each unique nameserver (parallel; fan-out = resolver.defaults.parallel):

   transport disabled for SOA -> IPV4_DISABLED / IPV6_DISABLED
                                 (no mismatch recorded); skip
   query SOA at random1 -> p1
   query SOA at random2 -> p2

   p1.Answer() non-empty:
      compare normalizedAnswer(p1) vs normalizedAnswer(p2)
         equal      -> CASE_QUERY_SAME_ANSWER      (ns, type, query1, query2)
         differ     -> CASE_QUERY_DIFFERENT_ANSWER (ns, type, query1, query2);
                       mismatch = true
   else p1.Msg != nil AND p2.Msg != nil:
      compare p1.Rcode() vs p2.Rcode()
         equal      -> CASE_QUERY_SAME_RC      (ns, type, query1, query2, rcode)
         differ     -> CASE_QUERY_DIFFERENT_RC (ns, type, query1, query2,
                                                rcode1, rcode2);
                       mismatch = true
   else exactly one of p1.Msg, p2.Msg is non-nil:
      -> CASE_QUERY_NO_ANSWER (ns, type, domain); mismatch = true
   else (both responses missing):
      -> (no per-server tag; mismatch unset)

After all tasks:
   any outcome.mismatch == true
      -> CASE_QUERIES_RESULTS_DIFFER (type, domain = original)
   otherwise
      -> CASE_QUERIES_RESULTS_OK     (type, domain = original)

emit TEST_CASE_END

Emitted Tags (Possible Set)

TagEmitted when
CASE_QUERIES_RESULTS_DIFFERAt least one nameserver comparison outcome is marked mismatch.
CASE_QUERIES_RESULTS_OKNo nameserver comparison outcome is marked mismatch.
CASE_QUERY_DIFFERENT_ANSWERBoth queries compared by answer set and normalized answers differ.
CASE_QUERY_DIFFERENT_RCAnswer-set comparison not used and query RCODE values differ.
CASE_QUERY_NO_ANSWERExactly one of the two queries returned a DNS message.
CASE_QUERY_SAME_ANSWERBoth queries compared by answer set and normalized answers match.
CASE_QUERY_SAME_RCAnswer-set comparison not used and query RCODE values match.
IPV4_DISABLEDIPv4 nameserver evaluation is skipped because IPv4 is disabled.
IPV6_DISABLEDIPv6 nameserver evaluation is skipped because IPv6 is disabled.
TEST_CASE_ENDTestcase completion marker is emitted.
TEST_CASE_STARTTestcase start marker is emitted.

Tag Arguments

TagArgument keyTypeMeaning
CASE_QUERIES_RESULTS_DIFFERtypestringCompared rrtype (SOA).
CASE_QUERIES_RESULTS_DIFFERdomainstringBase name used for comparisons (www.<zone>).
CASE_QUERIES_RESULTS_OKtypestringCompared rrtype (SOA).
CASE_QUERIES_RESULTS_OKdomainstringBase name used for comparisons (www.<zone>).
CASE_QUERY_DIFFERENT_ANSWERnsstringNameserver identity (ns name only; use address for IP).
CASE_QUERY_DIFFERENT_ANSWERaddressstringNameserver IP address for the same endpoint.
CASE_QUERY_DIFFERENT_ANSWERtypestringCompared rrtype (SOA).
CASE_QUERY_DIFFERENT_ANSWERquery1stringFirst randomized query name.
CASE_QUERY_DIFFERENT_ANSWERquery2stringSecond randomized query name.
CASE_QUERY_DIFFERENT_RCnsstringNameserver identity (ns name only; use address for IP).
CASE_QUERY_DIFFERENT_RCaddressstringNameserver IP address for the same endpoint.
CASE_QUERY_DIFFERENT_RCtypestringCompared rrtype (SOA).
CASE_QUERY_DIFFERENT_RCquery1stringFirst randomized query name.
CASE_QUERY_DIFFERENT_RCquery2stringSecond randomized query name.
CASE_QUERY_DIFFERENT_RCrcode1stringFirst query response code.
CASE_QUERY_DIFFERENT_RCrcode2stringSecond query response code.
CASE_QUERY_NO_ANSWERnsstringNameserver identity (ns name only; use address for IP).
CASE_QUERY_NO_ANSWERaddressstringNameserver IP address for the same endpoint.
CASE_QUERY_NO_ANSWERtypestringCompared rrtype (SOA).
CASE_QUERY_NO_ANSWERdomainstringQuery name that had a DNS message.
CASE_QUERY_SAME_ANSWERnsstringNameserver identity (ns name only; use address for IP).
CASE_QUERY_SAME_ANSWERaddressstringNameserver IP address for the same endpoint.
CASE_QUERY_SAME_ANSWERtypestringCompared rrtype (SOA).
CASE_QUERY_SAME_ANSWERquery1stringFirst randomized query name.
CASE_QUERY_SAME_ANSWERquery2stringSecond randomized query name.
CASE_QUERY_SAME_RCnsstringNameserver identity (ns name only; use address for IP).
CASE_QUERY_SAME_RCaddressstringNameserver IP address for the same endpoint.
CASE_QUERY_SAME_RCtypestringCompared rrtype (SOA).
CASE_QUERY_SAME_RCquery1stringFirst randomized query name.
CASE_QUERY_SAME_RCquery2stringSecond randomized query name.
CASE_QUERY_SAME_RCrcodestringShared query response code.
IPV4_DISABLEDnsstringNameserver identity (ns name only; use address for IP) skipped on IPv4.
IPV4_DISABLEDaddressstringNameserver IP address for the same endpoint.
IPV4_DISABLEDrrtypestringrrtype skipped (SOA).
IPV6_DISABLEDnsstringNameserver identity (ns name only; use address for IP) skipped on IPv6.
IPV6_DISABLEDaddressstringNameserver IP address for the same endpoint.
IPV6_DISABLEDrrtypestringrrtype skipped (SOA).
TEST_CASE_ENDtestcasestringTestcase display name (Nameserver09).
TEST_CASE_STARTtestcasestringTestcase display name (Nameserver09).

Severity Levels Per Tag

TagLevelNotes
CASE_QUERIES_RESULTS_DIFFERERRORDefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERIES_RESULTS_OKINFODefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERY_DIFFERENT_ANSWERWARNINGDefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERY_DIFFERENT_RCWARNINGDefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERY_NO_ANSWERWARNINGDefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERY_SAME_ANSWERDEBUGDefault from share/profile.json (test_levels.NAMESERVER).
CASE_QUERY_SAME_RCDEBUGDefault from share/profile.json (test_levels.NAMESERVER).
IPV4_DISABLEDDEBUGDefault from share/profile.json (test_levels.NAMESERVER).
IPV6_DISABLEDDEBUGDefault from share/profile.json (test_levels.NAMESERVER).
TEST_CASE_ENDDEBUGDefault from share/profile.json (test_levels.NAMESERVER).
TEST_CASE_STARTDEBUGDefault from share/profile.json (test_levels.NAMESERVER).

Differences From Upstream

  • Differences (Upstream vs Gonemaster):
    • Upstream: specifies compare-and-fail semantics without explicit per-branch message taxonomy. Gonemaster: emits granular per-server branch tags (CASE_QUERY_*) plus testcase summary tags (CASE_QUERIES_RESULTS_OK / CASE_QUERIES_RESULTS_DIFFER).
    • Upstream: describes evaluation over nameserver IP set. Gonemaster: deduplicates nameservers by name/ip.
    • Upstream: does not explicitly describe testcase boundary and transport-disabled debug emissions. Gonemaster: emits TEST_CASE_START, TEST_CASE_END, IPV4_DISABLED, and IPV6_DISABLED.
  • Potential upstream report:
    • no

Edge Cases And Limitations

  • If both queries for a nameserver return no DNS message, that nameserver does not set mismatch and emits no CASE_QUERY_* tag.
  • In the answer-comparison branch (len(p1.Answer()) > 0), a missing/no-message second response is treated as CASE_QUERY_DIFFERENT_ANSWER (not CASE_QUERY_NO_ANSWER).
  • CASE_QUERIES_RESULTS_OK can still be emitted when all nameservers were skipped by transport-disable checks.