Skip to content

DNS Running and Testing

Elbasiouny, Mahmoud edited this page May 29, 2026 · 5 revisions

Once you've built the DNS validator, the next step is to prove it behaves like a strict grammar checker:

  • Good packets should be accepted (Packet Passed)
  • Bad packets should be rejected (Packet Failed)

This project supports two workflows:

  1. Run one packet at a time (good for debugging)
  2. Run the full test suite using tests/runtests.py (good for regression testing)

Source files: main.c, tests/runtests.py
Hammer concepts: h_parse failure propagation · count-driven parsing · structural validation


Project Structure

.
├── Makefile
├── main.c
├── dns.c
├── dns.h
└── tests/
    ├── good_packets/
    ├── bad_packets/
    └── runtests.py

The test suite is intentionally split into:

  • tests/good_packets/ - packets expected to be accepted
  • tests/bad_packets/ - packets expected to be rejected

Step 1: Build the Parser

From the Hammer repository root, build the checkout-local library first:

scons examples

Then build the DNS example:

cd examples/dns
make

This should produce the dns_parser executable in examples/dns. If ../../build/opt/src is not present, the Makefile falls back to pkg-config libhammer.


Step 2: Run a Single Packet (Manual Testing)

Manual testing is the fastest way to debug one specific failure.

Run a known-good packet

From examples/dns:

./dns_parser tests/good_packets/1q_pass.bin

Expected output:

Packet Passed

Run a known-bad packet

./dns_parser tests/bad_packets/truncated_header.bin

Expected output:

Packet Failed

Step 3: Run the Entire Test Suite (Automated)

The repository includes a Python script that runs all packets in both directories and checks that they match expectations.

What the test runner does

  • Runs every file in tests/good_packets/
    • expects "Packet Passed"
  • Runs every file in tests/bad_packets/
    • expects rejection (anything that is not "Packet Passed")

The output is reported as:

  • [PASS] (packet accepted) for good packets that pass
  • [PASS] (packet rejected) for bad packets that fail
  • [FAIL] for mismatches

Run the test runner

From inside the tests/ directory:

cd tests
python3 runtests.py

You should see output like:

Testing good packets...
[PASS] (packet accepted) good_packets/1q_pass.bin
...

Testing bad packets...
[PASS] (packet rejected) bad_packets/truncated_header.bin
...

What Each Test Category Proves

Good packets (accept)

Good packets are designed to exercise valid grammar variations, such as:

  • Standard query format
  • Standard response format
  • Multiple questions / multiple answers
  • Pointer-only names (C0 0C form)
  • Label + pointer names (03 'www' C0 0C form)
  • Mixed sections (answers + authorities + additionals)
  • AAAA queries and uppercase labels

Bad packets (reject)

Bad packets are designed to trigger specific invariants, such as:

  • Pointer flag bits not 11
    • bad_pointer_pflag_not_11.bin
    • bad_label_plus_pointer_pflag_not_11.bin
  • Pointer offsets invalid
    • bad_pointer_offset_out_of_range.bin
    • invalid_aname_compression.bin
  • Count mismatches
    • wrong_qdcount.bin
    • bad_qdcount_fail.bin
  • Truncation / out-of-bounds
    • truncated_header.bin
    • truncated_packet_fail.bin
    • truncated_question.bin
    • truncated_rdata.bin
  • Invalid fields
    • invalid_qclass.bin
    • invalid_rtype.bin
    • invalid_rclass.bin
  • Label encoding violations
    • zero_length_label.bin
    • label_too_long.bin
  • Invalid flags
    • invalid_qr_flag.bin

Troubleshooting

"Everything fails"

Common causes:

  • You didn't run make first
  • You're running from the wrong working directory (the script assumes it's run inside tests/ and looks for ../dns_parser)

Summary

Task Command
Build make
Run one packet ./dns_parser tests/good_packets/<file>.bin
Run all tests cd tests && python3 runtests.py

When everything is correct, all good packets are accepted and all bad packets are rejected - giving you a repeatable regression suite for future parser changes.


Previous: Assembling the Full Parser
Back to: Examples Index

Clone this wiki locally