Networking in C · intermediate · ~12 min

DNS on the wire — names as labels

Decode a DNS question name from its label encoding, safely.

Overview

Walk length-prefixed labels to the 0x00 terminator; insert dots; refuse 0xC0 pointer bytes to stay loop-proof.

Why it matters

Label decoding is step one of every DNS tool, and the pointer-refusal is the difference between a safe parser and a DoS.

Lesson

Why this matters

Every DNS tool — dig, a resolver, a passive-DNS monitor — starts by decoding the QNAME. DNS doesn't store names as dotted strings; it stores them as a chain of length-prefixed labels ending in a zero byte.

What the bytes look like

03 'w' 'w' 'w'  07 'e' 'x' 'a' 'm' 'p' 'l' 'e'  03 'c' 'o' 'm'  00
└len┘ └label┘   └len┘ └────label────┘           └len┘└label┘    └end

Read a length, copy that many bytes, insert a dot, repeat until the 0x00.

The safety catch: compression pointers

A length byte with its top two bits set (& 0xC0) is a compression pointer into an earlier part of the packet. Following pointers naively can loop forever — a classic parser DoS. A defensive decoder that only reads one name refuses pointer bytes outright.

Your job

Implement int parse_dns_qname(const uint8_t *pkt, size_t n, char *out, size_t cap) that decodes the dotted name, bounds-checking every label against n and every write against cap, and returns -1 on a pointer byte or any overrun.

What this is NOT

  • A full message parser (header, answers, RRs) — just the QNAME.
  • A pointer follower — we deliberately refuse compression here.

Summary

Length, bytes, dot, repeat — until 0x00. Bounds-check everything; refuse 0xC0.

Practice with these exercises