---
title: DNS response parsing
summary: Decodes raw reply bytes into a structured Response, including typed resource records.
status: draft
owner: SAIF Documentation
last_reviewed: 2026-07-30
library: SAIF.Framework.DNS
reference_type: package
operation_id: OP-DNS-005
trigger: Resolver.Lookup constructs a Response from reply bytes
---

# DNS response parsing

This operation converts the raw reply datagram into the library's object model. It reads the DNS header flags and section counts, walks the question and resource-record sections in wire order, and dispatches each supported RDATA payload into a typed record class, skipping any record type it does not recognize.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-DNS-005 |
| **Trigger** | Generic DNS lookup receives reply bytes from the UDP transfer stage |
| **Inputs** | Reply `byte[]` |
| **Outputs** | Populated `Response`; throws `InvalidResponseException` when the question section cannot be parsed |
| **Primary components** | `Response.Response`, `Question`, `Answer`, `NameServer`, `AdditionalRecord`, `ResourceRecord`, `Pointer.ReadDomain` |
| **Entry point** | `SAIF.Framework.DNS\Response.cs` |

## Steps

1. Read bytes 2 and 3 of the reply as the DNS header flag bytes.
2. Convert the low four bits of byte 3 into a `ReturnCode`; if the resulting value is greater than 6, coerce it to `ReturnCode.Other`.
3. Derive `AuthoritativeAnswer`, `RecursionAvailable`, and `MessageTruncated` from their respective header flag bits.
4. Read the question, answer, name-server, and additional-record counts from bytes 4 through 11, and allocate arrays of the corresponding sizes.
5. Create a `Pointer` positioned at byte 12, immediately after the fixed 12-byte DNS header.
6. Parse each question in order by constructing `new Question(pointer)`.
   - If a question cannot be parsed, catch the exception and rethrow it as `InvalidResponseException`, so the caller never receives a partially built `Response` ([BR-007](../business-rules.md#br-007-malformed-embedded-questions-abort-response-construction)).
7. Parse each answer, name-server, and additional record in wire order by constructing the matching `ResourceRecord` subtype.
8. For each resource record, read the owner domain, record type, record class, TTL, and RDATA length.
9. Dispatch RDATA decoding according to the record's `DnsType`.
   - `DnsType.NS`: read one domain name and populate an `NSRecord`.
   - `DnsType.MX`: read the 16-bit preference value, then read the exchange domain name, and populate an `MXRecord`.
   - `DnsType.ANAME`: read four raw bytes and convert them into an IPv4 address for an `ANameRecord`.
   - `DnsType.SOA`: read two domain names, then five integer fields (serial, refresh, retry, expire, and default TTL), and populate a `SoaRecord`.
   - Any other `DnsType`: advance the pointer past the declared RDATA length without decoding it, leaving `Record` unset for that entry.
10. Whenever a domain name needs decoding, delegate to `Pointer.ReadDomain`.
    - Read the next length byte.
    - If its top two bits mark RFC1035 name compression, follow the referenced pointer recursively and append the resolved suffix.
    - Otherwise, read the label's character bytes, inserting a `.` separator between labels, and stop when a zero-length label terminates the name.
11. Leave the populated header flags and record arrays on the `Response` instance for the caller to read.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Response constructed from reply bytes]) --> H[Read header flags and section counts]
	H --> Q[Parse question section]
	Q --> D{Question parses successfully?}
	D -->|No| EndErr([Throw InvalidResponseException])
	D -->|Yes| R[Parse answer, name-server, additional records]
	R --> T[Decode supported RDATA types and domain names]
	T --> EndOk([Return populated Response])
```

## Failure and edge-case behavior

- Unsupported resource-record types are skipped by advancing past their RDATA rather than treated as a fatal parse error; the corresponding `Record` property is left unset.
- Only question-section parsing failures are explicitly wrapped as `InvalidResponseException`; exceptions raised while constructing answer, name-server, or additional-record entries propagate directly, unwrapped.
- Domain-name decoding follows RFC1035 compression pointers recursively, so compressed and uncompressed names both resolve to the same dotted-string representation.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- SAIF.Framework.DNS\Response.cs
- SAIF.Framework.DNS\Question.cs
- SAIF.Framework.DNS\ResourceRecord.cs
- SAIF.Framework.DNS\Pointer.cs
- SAIF.Framework.DNS\MXRecord.cs
- SAIF.Framework.DNS\ANameRecord.cs
- SAIF.Framework.DNS\NSRecord.cs
- SAIF.Framework.DNS\SoaRecord.cs
