As issue #38 mentioned, the top level format of message is divided into 5 sections (some of which are empty in certain cases) shown below:
+---------------------+
| Header |
+---------------------+
| Question | the question for the name server
+---------------------+
| Answer | RRs answering the question
+---------------------+
| Authority | RRs pointing toward an authority
+---------------------+
| Additional | RRs holding additional information
+---------------------+
So, we need to fill these five section to make a DNS request message.
Header
The format string pack the DNS request header section as followers:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 Pack Value
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID | H: request_id
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE | BB: 1 0 (RD is set 1, others are 0)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT | H: 1
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT | H: 0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT | H: 0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT | H: 0
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Details:
- RD is set 1 in query, it directs the name server to pursue the query recursively.
- QDCOUNT is set 1, it specifies there is only one number entry in the question section.
In asyncdns.build_request, there are following snippet:
header = struct.pack('!HBBHHHH', request_id, 1, 0, 1, 0, 0, 0)
Format string !HBBHHHH specify that the byte order is network(= big-endian), and:
- H: unsigned shorted - integer(2 Bytes)
- B: unsigned char - integer(1 Bytes)
Question
The question section is used to carry the "question" in most queries, i.e., the parameters that define what is being asked. The section contains QDCOUNT (usually 1) entries, each of the following format:
1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 Pack Value
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ QNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE | H: qtype
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS | H: QCLASS_IN
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
The following snippet packs the QTYPE and QCLASS para in question section.
qtype_qclass = struct.pack('!HH', qtype, QCLASS_IN)
QNAME is created by the following snippet:
def build_address(address):
""" Convert domain name to QNAME used in the DNS Question section.
Return a sequence of labels, where each label consists of a
length octet followed by that number of octets.
The domain name terminates with the zero length octet
for the null label of the root.
"""
address = address.strip(b'.')
labels = address.split(b'.')
results = []
# Labels must be 63 characters or less. Ref: RFC 1035
for label in labels:
l = len(label)
if l > 63:
return None
results.append(common.chr(l))
results.append(label)
results.append(b'\0')
return b''.join(results)
Ref
#37 Struct: working with binary data
#38 Data format of message used in DNS
#39 View DNS data datagram via wireshark
As issue #38 mentioned, the top level format of message is divided into 5 sections (some of which are empty in certain cases) shown below:
So, we need to fill these five section to make a DNS request message.
Header
The format string pack the DNS request header section as followers:
Details:
In
asyncdns.build_request, there are following snippet:Format string
!HBBHHHHspecify that the byte order is network(= big-endian), and:Question
The question section is used to carry the "question" in most queries, i.e., the parameters that define what is being asked. The section contains QDCOUNT (usually 1) entries, each of the following format:
The following snippet packs the QTYPE and QCLASS para in question section.
QNAME is created by the following snippet:
Ref
#37 Struct: working with binary data
#38 Data format of message used in DNS
#39 View DNS data datagram via wireshark