Skip to content
Lesson 2 of 13

Step 1 of 5 · Reading · ~4 min

Read

DNS Wire Format

Encoded Names & Compression

A DNS message carries no delimiters. There are no quotes around a name, no comma between fields, nothing to scan for — a resolver reads the packet by knowing exactly how many bytes each piece occupies. So example.com cannot travel as the eleven characters you typed. It travels as a structure that tells the reader where it stops.

One length byte per label

Split the name at its dots. Each piece — each label — goes on the wire as a single byte holding its length, immediately followed by that many bytes of text. A zero length byte marks the end of the whole name.

example.com  ->  07 65 78 61 6d 70 6c 65   03 63 6f 6d   00
                  e  x  a  m  p  l  e        c  o  m
                  ^                          ^             ^
                  length 7                   length 3      end of name

Two hard limits fall straight out of that one byte. A length only ever has to count to 63, because the top two bits of every length byte are reserved — which is exactly why no label may exceed 63 bytes. And a complete name is capped at 255 bytes including its length bytes, not just its text. (DNS compares names case-insensitively, but encoding is not a normalisation step: the bytes you write are the bytes that arrive.)

Reading it back: mind the length byte

Decoding is a walk. Read a length byte, take that many bytes as the label, and land on the next length byte. The step is 1 + n, not n — the length byte is itself a byte in the buffer, and skipping only the text is the single most common way to get this wrong:

python

Look at the loop condition, because it is doing real work. With while pos < len(wire), a wrong step reads garbage lengths and wanders — but it still stops, and a wrong answer is something you can debug. Write while True instead and the identical bug becomes a program that never finishes, which a grader can only report back to you as a run it was unable to complete. Bound the walk by the length of the buffer and the worst case stays debuggable.

Compression: the pointer every parser must understand

Real messages repeat names relentlessly — one question for example.com, then three answer records that all name example.com again. So a name is allowed to stop early and hand off to a pointer at a name already written earlier in the same message. Here the question's name sits at offset 12, immediately after the fixed 12-byte header:

offset 12, in the question:   07 'example' 03 'com' 00
later, inside an answer:      03 'w' 'w' 'w' c0 0c
                                             ^^^^^
                                             1100 0000 0000 1100
                                             ^^ marker: not a length, a pointer
                                                low 14 bits = 12 = the offset

That marker is why the top two bits of a length byte were reserved: 11 means "read me as an offset instead". The offset counts from the start of the whole message, never from the start of the current record. A name on the wire is therefore one of three shapes: labels closed by 00, a pointer standing alone, or labels that stop early and hand off to a pointer. You may choose to write messages that never use one; you do not get to read only messages that never use one.

Which is where the bugs live. Follow a pointer that aims at itself, and a trusting parser spins forever on a packet an attacker can craft in four bytes. The lesson Name Compression Decoder builds that resolver, with the loop protection it has to carry.

Your exercise: Encode/Decode Names

Read ENCODE <name> and DECODE <hex> lines and convert both ways. The input here never contains a pointer — every DECODE argument is plain labels ending in 00 — so do not build a pointer chaser yet.

Your starter already reads the lines, separates the command from its argument, and converts hex in both directions. It leaves two holes, one in encode_name and one in decode_name, and they are the two ideas above: a label on the wire is its length byte plus its text, and reading one label means stepping past both.

Up nextQuestion SectionDNS Wire Format

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…