networking · intermediate · ~15 min · safe pentest lab

Decode a DNS question name

Bounds-safe label decoding with loop-proof refusal of pointers.

Challenge

A DNS question name (QNAME) is stored as a series of length-prefixed labels: [len][bytes...][len][bytes...]... ending with a zero-length byte (0x00). Decode one from a packet byte buffer into a dotted string. The grader supplies fixed byte arrays — no DNS queries are sent.

Task

Implement int parse_dns_qname(const uint8_t *pkt, size_t n, char *out, size_t cap) that decodes the QNAME at the start of pkt into a dotted name in out (e.g. www.example.com).

Input

  • pkt, n: the packet bytes and the number of bytes available.
  • out, cap: destination buffer and its capacity.

Output

Returns the number of bytes written to out (excluding the NUL terminator), or -1 on any error.

Example

{3,'w','w','w', 7,'e','x','a','m','p','l','e', 3,'c','o','m', 0}   ->   15, out="www.example.com"
{0}                                                               ->   0,  out=""   (root name)
{0xC0,0x0C}                                                       ->   -1  (compression pointer rejected)

Edge cases

  • The root name (a single 0x00) decodes to the empty string, returning 0.
  • Place a . between labels, but not before the first label.

Rules

  • Return -1 on: NULL input, a label length that runs past n, output that would overflow cap, a missing 0x00 terminator, or a compression/reserved length byte (top two bits set, i.e. len & 0xC0). Compression pointers are refused because they can form decoding loops.

Why this matters

Every DNS tool starts by decoding the label-encoded QNAME. Doing it safely means refusing compression pointers that could loop.

Input format

Packet bytes (pkt) and available length (n), plus an output buffer (out) with capacity (cap).

Output format

Returns the number of bytes written to out (excluding NUL), or -1 on any error.

Constraints

Return -1 on NULL input, a label running past n, output overflow, missing 0x00 terminator, or a length byte with len & 0xC0 set (compression pointer).

Starter code

#include <stdint.h>
#include <stddef.h>
int parse_dns_qname(const uint8_t *pkt, size_t n, char *out, size_t cap) {
    /* TODO */
    (void)pkt; (void)n; (void)out; (void)cap;
    return -1;
}

Common mistakes

Following compression pointers (can loop forever). Forgetting the inter-label dot. Reading past n.

Edge cases to handle

Root name (single 0x00) → 0. Truncated label. Output too small.

Complexity

O(n).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.