DNS packet structure







Foreword



I decided to write a DNS sniffer, so to speak, just for fun. Just see which addresses are resolving on my system. The protocol is old, there should be a lot of documentation. Lot. But all the articles are very incomplete and end, at the most interesting moment. Yes, there is rfc1035, but I would like in Russian and with explanations. Actually on accumulation of experience and analysis of a package this article has ripened. It is designed for those who understand what DNS is and understands that there are requests and answers. For those who want to understand a little in the structure of this protocol.



The article involves theory, and then a little practice.



DNS packet structure



+---------------------+ | Header |  +---------------------+ | Question |   +---------------------+ | Answer |   +---------------------+ | Authority |      +---------------------+ | Additional |     +---------------------+
      
      





Header - The header of the DNS packet, consisting of 12 octets.



Question section - in this section, the DNS client transmits queries to the DNS server informing about the name for which it is necessary to resolve (resolve) the DNS record, as well as what type (NS, A, TXT, etc.). When responding, the server copies this information and gives it back to the client in the same section.



Answer section - the server tells the client the answer or several responses to the request, in which it reports the above data.



Authoritative Section - contains information on which authoritative servers obtained the information included in the DNS response section.



Additional Record Section - additional records that relate to the request, but are not strictly answers to the question.



There may be several or few entries in sections. Everything is determined by the heading.



DNS header structure



  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 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      
      





ID (16 bits) - this field is used as a unique transaction identifier. Indicates that the packet belongs to the same “request-response” session and occupies 16 bits.



QR (1 bit) - this bit is used to identify whether the packet is a request (QR = 0) or a response (QR = 1).



Opcode (4 bits) - using this code, the client can specify the type of request, where the usual value is:





AA (1 bit) - this field only makes sense in DNS responses from the server and reports whether the answer is authoritative or not.



TC (1 bit) - this flag is set in the response packet if the server could not put all the necessary information into the packet due to existing restrictions.



RD (1 bit) - this one-bit flag is set in the request and copied to the response. If the flag is set in the request, this means that the client asks the server not to tell him intermediate answers, but to return only the IP address.



RA (1 bit) - sent only in responses, and reports that the server supports recursion



Z (3 bits) - are reserved and always equal to zero.



RCODE (4 bits) - this field is used to notify clients whether the request was completed successfully or with an error.





QDCOUNT (16 bits) - the number of records in the query section

ANCOUNT (16 bits) - the number of entries in the answers section

NSCOUNT (16 bits) - the number of entries in the Authority Section

ARCOUNT (16 bits) - the number of records in the Additional Record Section



Request Section Structure



  1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      
      





QNAME - Each request and response record begins with NAME. This is the domain name to which this record is linked or to which “belongs”. It is encoded as a series of tags. At this point, we should dwell in more detail.



In the articles that I saw, they forget to say that the original DNS protocol provides two types of labels, which are determined by the first two bits:



00 (standard label) - means the remaining 6 bits determine the length of the label, followed by a given number of octets. Accordingly, the label length cannot be more than 63 bytes (For example, nslookup will display the message “is not a legal name (label too long)” when trying to sober up a host with a long label). The recording ends with the code 0x00.

11 (compressed label) - then the next 14 bits define a link to the starting address of the series of labels. As experience has shown, it may also contain a compressed label to another address. In the request, as a rule, there are no such labels.



Also, the label can contain the value 0x00 (zero length), which means that it is the root domain name (root).



The maximum length of NAME is <= 255. This is for the sake of ease of implementation.



QTYPE - The type of DNS record we are looking for (NS, A, TXT, etc.).

QCLASS - The defining request class (IN for the Internet).



Response Section Structure



  1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / / / NAME / | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | CLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TTL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RDLENGTH | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| / RDATA / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      
      





NAME - Same format as QNAME in the request section.

TYPE - type of resource record. Defines the format and purpose of this resource record.

CLASS - resource record class; it is theoretically believed that DNS can be used not only with TCP / IP, but also with other types of networks, the code in the class field determines the type of network. Basically IN for Internet (Code 0x0001)

TTL - (Time To Live) - the valid storage time for this resource record in the cache of an unresponsive DNS server.

RDLENGTH - data field length (RDATA).

RDATA - data field, the format and content of which depends on the type of record.



Practice



Consider a package from a real request and response. Launch your favorite sniffer and resolve habrahabr.ru.



Request







Let's analyze the dns header structure.



Transaction ID = 0x9bce



Next are the flags. 01 00 is represented as a binary value 0'0000'0'0'1'0'000'0000 (hereinafter I separate the bits with an apostrophe for a better visual representation of flag division)

QR = 0 - means this packet is a request;

Opcode = 0000 - Standard request;

AA = 0 - this field makes sense only in DNS answers, therefore always 0;

TC = 0 - this field makes sense only in DNS answers, therefore always 0;

RD = 1 - Please return only the IP address;

RA = 0 - sent only by the server;

Z = 000 - always zeros, reserved field;

RCODE = 0000 - Everything went without errors



QDCOUNT = 00 01 - 1 entry in the query section

ANCOUNT = 00 00 - The request is always 0, section for answers

NSCOUNT = 00 00 - The request is always 0, section for answers

ARCOUNT = 00 00 - The request is always 0, section for answers

Next we have the request and response sections. With one entry.

The first octet we have is 0x09, imagine it as a binary value 00'001001. The first two bits go 00, which means that this is a regular label. Tag length 9 bytes (b001001). “68 61 62 72 61 68 61 62 72”. These are 9 bytes. It says “habrahabr” (in hexadecimal). Go ahead. Octet 0x02. The first two bits are 00, then again a regular label with a length of 2 bytes. Here they are: “72 75.” It is written “ru”. Go ahead. Octet 0x00. This means the end of the host entry. We got two words “habrahabr” and “ru”. We unite them with a point, we get “habrahabr.ru”, this is the host that we requested.

QTYPE = 0x0001 - Corresponds to type A (host address request)

QCLASS = 0x0001 - Corresponds to the class IN.



Answer







Let's analyze the dns header structure.



Transaction ID = 0x9bce. It must be exactly the ID from the request.

Flags again. 81 80 represent binary value 1'0000'0'0'1'1'000'0000

QR = 1 - means this package is the answer;

Opcode = 0000 - Standard request;

AA = 0 - The server is not authoritative for the domain;

TC = 0 - All information fit in one package;

RD = 1 - Please return only the IP address;

RA = 1 - Server supports recursion;

Z = 000 - always zeros, reserved field;

RCODE = 0000 - Everything went without errors



QDCOUNT = 00 01 - 1 entry in the query section

ANCOUNT = 00 01 - Now we have one entry in the answer

NSCOUNT = 00 00 - The request is always 0, section for answers

ARCOUNT = 00 00 - The request is always 0, section for answers



Next we have the request and response sections. With two entries. One record of the request, another record with the answer. I will not paint the request section, it will always be 1v1 the same as in the request package. Proceed with the answer section.



The first octet we have is 0x09, the first two bits are 00, which means a regular label with a length of 9 bytes. Read 9 bytes, get “HABRAHABR". Next comes 0XC0 (b11000000). As you can see, the first two bits have a value of 11, which means that we have a compressed link. We look at the next 8 bits (we have 0x16 (b00010110)) and combine with the current last 6 bits. We get b00000000010110. Link to the 22nd byte of the DNS packet (02 72 75 00). Starting at octet 22, we get the labels again. By the same rules. We get it “.ru”. We unite everything that we received, it turns out “HABRAHABR.ru” This is the host, which will be discussed further.



QTYPE = 0x0001 - Corresponds to type A (host address request)

QCLASS = 0x0001 - Corresponds to the class IN.

TTL = 0x00000c90 - data up-time 3216 seconds.

RDLENGTH = 0x0004 - The data length is 4 octets.

RDATA = "b2 f8 ed 44".



As already mentioned, the format and content depends on the type of recording. The record type is “A”. So, to get the IP we must read 4 bytes. Each byte is the corresponding octet of the IP address, written in hexadecimal.



We get the IP: b2.f8.ed.44 or "178.248.237.68". What was required to receive.



For example, for type NS, the format would be:



  +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ / NSDNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
      
      





And we would read the name according to the rules of QNAME.



All Articles