HackBlue

Tools · Network tools · 04 / 24

tcpdump: DNS questions and answers on the wire

UDP port 53 lines show the name a lab host asked for and the address the resolver returned. That is how you check a wrong destination before you blame the service that never saw a connection.

14 min read · practice only with authorization

How a DNS line reads

A query line looks like a UDP frame from a high source port to port 53, then an id, a plus sign when recursion is desired, and the question: A? files.lab.internal. The answer line comes back from port 53 with the same id, a count such as 1/0/0, and the record, for example A 10.8.0.40. The counts are answers, authority records, and additional records.

The name is metadata. It is useful and it is sensitive. A capture of a resolver sees every name the lab asked about. Keep the file with the ticket, and filter to the host you are allowed to investigate. tcpdump -nn still prints the DNS name inside the payload summary, because that name is not an address tcpdump resolved. -nn stops tcpdump's own lookups. It does not hide names that were already on the wire.

What a defender compares

Compare the A record to the address the service actually uses. If files.lab.internal answers 10.8.0.77 and the runbook says 10.8.0.40, the TCP conversation you pull next is the one to 10.8.0.77. Pulling port 443 on 10.8.0.40 will look like silence and you will file the wrong fault.

NXDomain or ServFail in the answer is a resolver result, written in the rcode tcpdump prints for that reply. A name that should exist inside the lab and does not is a lab DNS change. A burst of names your applications never use, from one host, is a reason to ask who ran that host. You record the names and the timestamp. You do not need the contents of any later connection to file that observation.

  • A? is an address query. AAAA? is IPv6. PTR? is a reverse lookup.
  • The id on the query and the id on the reply should match.
  • A reply from an address that is not the lab resolver is its own finding.
  • Filter host 10.8.0.20 and udp port 53 when the ticket is about one machine.

A worked defensive case

The web tier reports that the files service refused connections. The runbook says files.lab.internal is 10.8.0.40. You read UDP/53 for 10.8.0.20 and find A? files.lab.internal answered with A 10.8.0.77. A TCP filter for 10.8.0.77 port 443 then shows a normal handshake. The VM at 10.8.0.40 is quiet because nothing called it.

The ticket becomes a lab DNS record pointing at the wrong address. The fix is the record, plus a short note of the query timestamp and the answer. You do not widen the capture to every resolver on the campus network.

Snippet
2026-11-02 10:13:58.221 IP 10.8.0.20.46112 > 10.8.0.53.53: 12345+ A? files.lab.internal. (35)
2026-11-02 10:13:58.224 IP 10.8.0.53.53 > 10.8.0.20.46112: 12345 1/0/0 A 10.8.0.77 (51)

Where this is documented

DNS message layout is RFC 1035. tcpdump's domain printer produces the query and answer summary. The resolver in this lesson is the lab resolver at 10.8.0.53.

Use a host-only lab network, or a capture the owner already handed you. These commands read that file or record a single lab host. They are not a scan of the public internet.

Commands

DNS to and from one lab host
tcpdump -nn -tttt -r /lab/evidence.pcap 'host 10.8.0.20 and udp port 53'
Only the queries that host sent to the lab resolver
tcpdump -nn -tttt -r /lab/evidence.pcap 'src host 10.8.0.20 and dst host 10.8.0.53 and udp dst port 53'

Diagram

From a failed connection back to the name that was asked

  1. Symptom

    The app says the files service refused the call.

  2. Name

    UDP/53 shows the question files.lab.internal and the A record that came back.

  3. Address

    The answer is 10.8.0.77. The runbook still says 10.8.0.40.

  4. Fix

    Correct the lab DNS record. The TCP capture of the old address was the wrong path.

Check yourself

1. The reply line says 12345 1/0/0 A 10.8.0.77. What do you use as the destination of the follow-up TCP read?

2. You read the capture with -nn and the query name files.lab.internal still appears. Why?

3. Which filter shows queries 10.8.0.20 sent to the lab resolver, and not the replies?