When looking a packet byte code, how would you identify a dns packet. The IP header's protocol field would tell that a UDP frame follows, but inside the UDP frame no protocol field exists to specify what comes next and, from what I can see, there is nothing inside the frame that would uniquely identify it as a dns packet.
Other than it being on port 53, there's a few things you can look out for which might give a hint that you're looking at DNS traffic.
I will refer to the field names used in §4.1 of RFC 1035 a lot here:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
As you can see above the header is 12 bytes long - a 2 byte ID, 2 bytes of flags, and 4 x 2 bytes of counts.
In any DNS packet the QDCOUNT
field will be exactly one (0x0001
). Technically other values are allowed by the protocol, but in practise they are never used.
In a query (QR == 0
) the ANCOUNT
and NSCOUNT
values will be exactly zero (0x0000
), and the ARCOUNT
will typically be 0, 1, or 2, depending on whether EDNS0
(RFC 2671)and TSIG
(RFC 2845) are being used. RCODE
will also be zero in a query.
Responses are somewhat harder to identify, unless you're observing both sides of the conversation and can correlate each response to the query that triggered it.
Obviously the QR
bit will be set, and as above the QDCOUNT
should still be one. The remaining counters however will have many and varied permutations. However it's exceedingly unlikely that any of the counters will be greater than 255, so you should be able to rely on bytes 4, 6, 8 and 10 all being zero.
Following the headers you'll start to find resource records, the first one being the actual question that was asked (§4.1.2). The unfortunate part here is that the designers of the protocol saw fit to include a variable length label field (QNAME
) in front of two fixed fields (QTYPE
and QCLASS
).
[To further complicate matters labels can be compressed, using a backwards pointer to somewhere else in the packet. Fortunately you will almost never see a compressed label in the Question Section, since by definition you can't go backwards from there. Technically a perverse implementor could send a compression pointer back into the header, but that shouldn't happen].
So, start reading each length byte and then skip that many bytes until you reach a null byte, and then the next two 16 bit words will be QTYPE
and QCLASS
. There are very few legal values for QCLASS
, and almost all packets will contain the value 1
for IN
("Internet"). You may occasionally see 3
for CH
(Chaos).
That's it for now - if I think of anything else I'll add it later.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With