Skip to content

SAIF.Framework.DNS architecture

SAIF.Framework.DNS is a small, self-contained, low-level DNS client that performs lookups over raw UDP sockets in accordance with RFC1035 message framing. It has zero dependencies on other SAIF framework components and performs no I/O other than DNS UDP requests.

Responsibilities

  • Build DNS query messages from caller-supplied domain, type, and class values (Request, Question).
  • Transmit query messages over UDP to a caller-specified DNS server on port 53, with retry and timeout handling (Resolver).
  • Parse raw UDP reply bytes into a structured Response, including header flags/counts and Question/Answer/NameServer/AdditionalRecord sections (Response, Pointer).
  • Decode individual resource-record RDATA into typed records (ANameRecord, MXRecord, NSRecord, SoaRecord) based on the record's DnsType, skipping unrecognized types.
  • Provide a convenience MX-lookup operation that filters and sorts MX answers by preference (Resolver.MXLookup).
  • Signal failure conditions via typed exceptions (NoResponseException, InvalidResponseException).

Component boundaries

  • Resolver: static-only (sealed, private constructor) entry-point facade exposing Lookup and MXLookup; owns UDP socket transfer and retry logic.
  • Request: caller-facing message builder; holds one or more Question instances and serializes them to wire format via GetMessage().
  • Question: represents a single DNS query (domain/type/class); validates inputs and can also be constructed internally from a Pointer when decoding an embedded question in a response.
  • Response: parses a raw reply byte array into ReturnCode, questions, and resource-record arrays.
  • ResourceRecord (and semantic subtypes Answer, NameServer, AdditionalRecord): shared RR wire-format parser producing a RecordBase payload.
  • RecordBase subtypes (ANameRecord, MXRecord, NSRecord, SoaRecord): typed RDATA payloads for the record kinds this library understands.
  • Pointer: internal byte-array cursor used across parsing components to decode domain names (including RFC1035 message-compression pointers) and primitive wire values.
  • Enums (DnsType, DnsClass, ReturnCode, Opcode): shared value types used across the request/response boundary.
  • InvalidResponseException / NoResponseException: typed failure signals surfaced to callers.
  • MXHelper.cs (namespace SAIF.Framework.DNSLib): a parallel, independent MX-lookup implementation (its own UdpClient-based transport and a distinct MXRecord type) that is not part of the compiled component boundary — see Design constraints.

Interaction model

  • Caller constructs a Request and adds one or more Question objects.
  • Resolver.Lookup(request, dnsServer) serializes the request via Request.GetMessage(), sends it over UDP to port 53 with up to _udpRetryAttempts (2) retries and a 1-second receive timeout, then wraps the raw reply in a Response.
  • Response's constructor parses the DNS message header (flags, counts) and, via an internal Pointer cursor, decodes Question, Answer, NameServer, and AdditionalRecord arrays in wire order.
  • Each ResourceRecord decodes its RDATA into a RecordBase subtype based on DnsType; unrecognized types are skipped by advancing the pointer past the record length.
  • Resolver.MXLookup(domain, dnsServer) is a convenience wrapper that issues an MX question, filters Answers to MXRecord instances, and returns them sorted by preference using MXRecord's IComparable implementation.
  • The library does not call into any other SAIF assembly, database, configuration system, or security component; all interaction is confined to the caller and the target DNS server over UDP.

Architecture diagram

The following diagram shows the high-level component interactions for a lookup request.

flowchart TD
    Caller[Caller] --> Request[Request / Question]
    Request --> Resolver[Resolver]
    Resolver -->|UDP port 53, retry x2, 1s timeout| DnsServer[External DNS server]
    DnsServer -->|raw reply bytes| Resolver
    Resolver --> Response[Response]
    Response --> Pointer[Pointer<br>wire-format cursor]
    Pointer --> Records[RecordBase subtypes<br>ANameRecord / MXRecord / NSRecord / SoaRecord]
    Records --> Caller

Sequence diagram

The following diagram shows the primary request/response sequence for a lookup, including the retry path.

sequenceDiagram
    participant Caller
    participant Resolver
    participant DnsServer as External DNS server
    participant Response
    Caller->>Resolver: Lookup(request, dnsServer) / MXLookup(domain, dnsServer)
    Resolver->>DnsServer: UDP datagram (stamped transaction id)
    alt matching-id reply received within 1s
        DnsServer-->>Resolver: UDP reply bytes
    else timeout or SocketException
        Resolver->>DnsServer: retry (up to 2 additional attempts)
        DnsServer-->>Resolver: UDP reply bytes
    end
    Resolver->>Response: new Response(replyBytes)
    Response-->>Resolver: parsed Answer/NameServer/AdditionalRecord arrays
    Resolver-->>Caller: Response (or thrown NoResponseException)

Design constraints

  • Resolver is a static-only utility class (private constructor, sealed), consistent with a stateless helper; it holds no instance state across calls.
  • Unrecognized resource-record types are skipped rather than causing a parse failure, so the response model is intentionally tolerant of unknown DnsType values.
  • A returned UDP datagram is only accepted if its 2-byte transaction id matches the request's stamped id; mismatched packets are ignored, implicitly triggering the retry loop.
  • Malformed embedded questions during response parsing abort construction via InvalidResponseException rather than returning a partially-parsed Response.
  • Dead/parallel implementation: MXHelper.cs (namespace SAIF.Framework.DNSLib) implements an independent, self-contained MX-lookup mechanism with its own raw UdpClient transport, manual DNS wire encode/decode, and its own distinct MXRecord type. It is present in the project folder but is not included in the <Compile> item group of SAIF.BOF.Framework.DNS.csproj, so it has no effect on the assembly's public surface or runtime behavior. Its source is nonetheless captured by the repository-wide packaging nuspec glob (SAIF.Framework.Core\SAIF.BOF.Framework.Core.nuspec), which bundles it as loose source under the package's src folder even though it never executes*. Maintainers should treat this file as dead code and consider removing it or restoring it to the compile list to avoid confusion about which MX-lookup implementation is authoritative. It is not documented as part of the API reference for this library because it is not part of the compiled public surface.

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • SAIF.Framework.DNS\SAIF.BOF.Framework.DNS.csproj
  • SAIF.Framework.DNS\Resolver.cs
  • SAIF.Framework.DNS\Request.cs
  • SAIF.Framework.DNS\Question.cs
  • SAIF.Framework.DNS\Response.cs
  • SAIF.Framework.DNS\ResourceRecord.cs
  • SAIF.Framework.DNS\RecordBase.cs
  • SAIF.Framework.DNS\ANameRecord.cs
  • SAIF.Framework.DNS\MXRecord.cs
  • SAIF.Framework.DNS\NSRecord.cs
  • SAIF.Framework.DNS\SoaRecord.cs
  • SAIF.Framework.DNS\Pointer.cs
  • SAIF.Framework.DNS\Enums.cs
  • SAIF.Framework.DNS\InvalidResponseException.cs
  • SAIF.Framework.DNS\NoResponseException.cs
  • SAIF.Framework.DNS\MXHelper.cs
  • SAIF.Framework.Core\SAIF.BOF.Framework.Core.nuspec