Reputation: 1258
Was trying to intercept incoming DNS requests by spinning up a small udp server and ended up trying https://stackoverflow.com/a/16981944/9488865.
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
To deduce QR, opcode, AA, TC etc, we are doing:
DNS_QUERY_MESSAGE_HEADER = struct.Struct("!6H")
id, misc, qdcount, ancount, nscount, arcount = DNS_QUERY_MESSAGE_HEADER.unpack_from(message)
qr = (misc & 0x8000) != 0
opcode = (misc & 0x7800) >> 11
aa = (misc & 0x0400) != 0
tc = (misc & 0x200) != 0
rd = (misc & 0x100) != 0
ra = (misc & 0x80) != 0
z = (misc & 0x70) >> 4
rcode = misc & 0xF
While Scapy makes it all super easy (https://stackoverflow.com/a/6732956/9488865), I would like to use this opportunity to learn a bit more here.
How can I find out to use 0x8000, 0x7800, 0x0400 .. 0x70, 0xF etc for doing those ANDs? How do we find and lock in on those values?
Upvotes: 0
Views: 252
Reputation: 12485
The DNS wire format is defined in https://www.rfc-editor.org/rfc/rfc1035.txt
For example you have this:
4.1.1. Header section format
The header contains the following fields:
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 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
What you see on top are bytes, and hence will show the necessary offsets to apply to get each specific part.
You can also study how current DNS parsers/generators library do it, for example in Python: https://github.com/rthalley/dnspython/blob/master/dns/message.py#L732
Upvotes: 1