Case: a DNS lookup pattern
A host that suddenly asks for many unique names, most of them missing, is a pattern you can count. You do not need to decode the labels to report it.
Start from the names this host usually asks
A DNS pattern is a change from a baseline. The lab client 10.8.0.40 normally asks the resolver 10.8.0.53 for a short list: files.lab.example and print.lab.example, type A, and gets NOERROR with answers. You can show that with a query filter and a glance at dns.qry.name. Write the baseline down so the new pattern has something to differ from.
Count questions, not packets. A query and its response are two frames and one question. Filter dns.flags.response == 0 && ip.src == 10.8.0.40 so the rows are the client’s questions. Note the destination. Questions that skip the lab resolver are part of the pattern even before you read the names.
dns.flags.response == 0 && ip.src == 10.8.0.40 && ip.dst == 10.8.0.53
Worked case: many unique names, mostly NXDOMAIN
At 11:15 the same client starts asking for names under ns.example.test. The labels are long and do not repeat. Over ten minutes you count about two hundred questions, spaced a few seconds apart. Responses from 10.8.0.53 are mostly dns.flags.rcode == 3. A handful are NOERROR with a single address that the client never opens a TCP connection to. The qtype is A. The resolver is still the lab resolver.
You extract the names with tshark and count unique values. Almost every name appears once. The baseline names are still present, a few times, and they still resolve. The new names are the change: volume, uniqueness, NXDOMAIN share, and a steady cadence. You record samples of the qnames, not every label, plus the counts and the time window. You do not try to interpret the labels as a hidden message. The host owner gets the pattern and the samples.
tshark -n -r lab.pcapng -Y "dns.flags.response == 0 && ip.src == 10.8.0.40" -T fields -e frame.time_relative -e dns.qry.name -e dns.qry.type -E separator=,
Other shapes worth counting the same way
A burst of TXT queries with large responses is a different shape and the same method: qtype, size, cadence, unique names, resolver. A single long name is not a pattern. A name the lab software was just configured to use is a pattern only if nobody expected it. The count and the baseline do the work.
NXDOMAIN from a typo in a browser happens. It does not happen two hundred times, on a timer, under one parent domain, while the user says the machine was idle. Context from the person at the keyboard belongs in the note next to the counts.
Hand it over without a theory you cannot show
The report lists client, resolver, parent domain, question count, unique count, rcode mix, qtype, cadence, and whether any TCP connection followed the answers. Attach a CSV of names to the case file if the agreement allows, and keep it out of broad chat. Names can be sensitive even when they are not passwords.
The people who own the workstation decide whether a program on it is generating the lookups. Your capture showed the lookups. Decoding or “trying” the names against other resolvers is a new action and needs its own permission.
Diagram
From a baseline of a few names to a count of many missing ones
- Baseline
List the names this host usually resolves, and the resolver it uses.
- Questions
Filter the client’s queries. Count questions, unique names, and rcodes.
dns.flags.response == 0 && ip.src == 10.8.0.40 && ip.dst == 10.8.0.53
- Shape
Note cadence, qtype, and whether any answer was followed by a connection.
- Hand
Give the owner the counts, the window, and a sample of names.
Check yourself
1. Which filter counts DNS questions from the lab client, rather than questions plus answers?
2. What makes this lookup pattern worth handing to the host owner?
3. What should the note avoid?