-
Notifications
You must be signed in to change notification settings - Fork 1
DNS Parsing the Body
The DNS body follows the 12-byte header and contains up to four sections:
- Questions
- Answers
- Authority Records
- Additional Records
Unlike the header, the body is variable-length and fully driven by the four count fields:
QDCOUNTANCOUNTNSCOUNTARCOUNT
These values were stored in DNSContext during header parsing. The body parser uses them to control exact repetition with h_repeat_n.
Source file:
dns.c,bodyParser()
Hammer concepts:h_length_value·h_choice·h_repeat_n·h_attr_bool·h_tell·h_sequence
Conceptually:
Body := Questions Answers Authorities Additionals
Each section appears exactly the number of times declared in the header.
If a section count is zero, that section parses as empty.
DNS names are composed of one or more labels. Each label has:
- A length byte (1–63)
- That many data bytes
| Parameter | Type | Description |
|---|---|---|
length_parser |
HParser * |
Produces the length |
value_parser |
HParser * |
Repeated length times |
In the DNS parser:
HParser *label = h_length_value(
h_ch_range(0x01, 0x3f), h_ch_range(0x00, 0xff)
);This enforces:
- Labels must be at least 1 byte
- Labels cannot exceed 63 bytes (spec limit)
DNS supports name compression using 2-byte pointers.
11xxxxxx xxxxxxxx
- Top two bits must be
11 - Remaining 14 bits form an offset from the start of the DNS message
HParser *pflag = h_bits(2, false);
HParser *vpflag = h_attr_bool(pflag, validate_pflag, ctx);validate_pflag ensures the value equals 3 (binary 11).
If the top two bits are not 11, the parser fails immediately.
HParser *temppointer = h_bits(14, false);
HParser *vpointer = h_attr_bool(temppointer, validate_pointer, ctx);The offset is validated to ensure:
- It points to a valid position in the message
- It satisfies any additional safety constraints
Pointer validation requires knowing the current parsing position.
h_tell() returns the current bit position in the input stream.
HParser *curr = h_tell();
HParser *newCurr = h_action(curr, updateCurr, ctx);This stores the current byte offset in DNSContext, allowing the pointer offset to be validated safely.
A DNS name can legally be encoded as:
- Labels + terminating
0x00 - Labels + compression pointer
- Pointer only
We model this using h_choice.
Attempts each parser in order until one succeeds.
When labels are present, a DNS packet may have one or more labels. h_many1 handles this:
Matches parser one or more times, collecting results into a sequence. It's greedy: it keeps matching until parser fails, then succeeds with however many matches it found.
HParser *name_end = h_choice(name_termination, pointer, NULL);
HParser *QName = h_choice(
h_sequence(h_many1(label), name_end, NULL),
pointer,
name_termination,
NULL
);This ensures:
- Proper label termination
- Proper pointer encoding
- Invalid pointer flag bits are rejected
- Zero-length labels (except termination) are rejected
Each Question contains:
- QNAME
- QTYPE (16 bits)
- QCLASS (16 bits)
HParser *QType = h_uint16();
HParser *vQType = h_attr_bool(QType, validate_type, NULL);
HParser *QClass = h_uint16();
HParser *vQClass = h_attr_bool(QClass, validate_qclass, NULL);
HParser *question =
h_sequence(QName, vQType, vQClass, NULL);The section is repeated exactly QDCOUNT times:
HParser *questions =
h_repeat_n(question, ctx->qdcount);Answers, Authorities, and Additionals share the same structure:
| Field | Size |
|---|---|
| NAME | variable |
| TYPE | 16 bits |
| CLASS | 16 bits |
| TTL | 32 bits |
| RDLENGTH | 16 bits |
| RDATA | variable |
Both TYPE and CLASS are validated with h_attr_bool against allowed ranges.
Invalid values cause immediate failure.
HParser *RDLength = h_uint16();
HParser *RData =
h_length_value(
RDLength,
h_bits(8, false)
);This ensures:
- Exactly
RDLENGTHbytes are consumed - Truncated RDATA causes parse failure
- Extra bytes are not silently ignored
Each section is repeated according to the header:
HParser *answers = h_repeat_n(response, ctx->ancount);
HParser *authorities = h_repeat_n(response, ctx->nscount);
HParser *additionals = h_repeat_n(response, ctx->arcount);The body parser combines everything:
return h_sequence(
questions,
answers,
authorities,
additionals,
NULL
);If any of the following occurs:
- Invalid pointer flag bits
- Invalid pointer offset
- Invalid TYPE or CLASS
- Label too long
- Missing termination byte
- Truncated RDATA
- Section count mismatch
The parse fails immediately.
Hammer automatically propagates failure upward through h_sequence, h_choice, and h_repeat_n.
| Concept | Hammer Function | Why It Matters in DNS |
|---|---|---|
| Length-prefixed parsing | h_length_value |
Labels and RDATA depend on dynamic lengths |
| Grammar alternatives | h_choice |
Names may be labels or pointers |
| Exact repetition | h_repeat_n |
Section counts must match header |
| Context validation |
h_tell + h_action
|
Required for safe pointer handling |
| Immediate invariant checks | h_attr_bool |
Reject malformed packets early |
Next: Assembling the Full Parser
Previous: Parsing the Header
Learn Hammer
Protocol Examples
NTP
- NTP Overview
- Parsing the Header
- Parsing Data Fields
- Extension Fields and MAC
- Assembling the Parser
- Hex Input Preprocessing
- Running and Testing
DNS
TFTP
- TFTP Overview
- RRQ/WRQ Packets
- DATA Packets
- ACK Packets
- ERROR Packets
- Assembling the Parser
- Running and Testing
References
- Hammer Quick Reference
- Parsing Backends
- Unit Testing
- Using RTEMS
- Extending Hammer
- Adding a New Example
- Adding a New Binding
Further Reading