Understanding the DNS Protocol (Part 3)

by Don Parker [Published on 22 Nov. 2005 / Last Updated on 22 Nov. 2005]

Over the past two articles on DNS we have seen just how big the Domain Name Service protocol actually is. It performs more then simple domain name resolution as we have seen, and also is a key player in the delivery of email via the MX resource record. In this last part on DNS we will actually break out various fields in the DNS header.

If you missed the previous parts in this series please go read:

DNS and it’s bits and bytes

Over the course of the past two articles we have covered DNS at a fairly high level. We did not delve into any system administration content really, but concentrated more on getting a solid feel for what the protocol does, and how it does it. Lastly we also took a look at how a DNS packet looks like on the wire as it were. In this last part of the DNS article series we will take one DNS packet and go through the DNS header. This will allow you to hopefully better understand the protocol itself, and how it works. You may feel that going through the DNS packet, hex value by hex value, as unimportant.

My feelings on the matter are that being able to completely parse the packet will give you a sense of confidence when dealing with DNS. This in turn will allow you to approach any network related issue involving DNS with self-assurance. That kind of self-assurance will only come from having an understanding of not only how the protocol itself works, but also what it looks like in a packet format.

Lets pick this packet apart!

Well before we begin to pick the below noted packet apart you will need to make sure you have the SANS TCP/IP and tcpdump flyer located at the bottom of the page. This will allow you to navigate the DNS packet with a minimum of effort. I will now comment on the packet directly beneath it.

01:00:09.684739 > [udp sum ok]  59930 NXDomain 0/1/0 (102) (ttl 58, id 55787, len 130)
0x0000   4500 0082 d9eb 0000 3a11 f873 c0a8 01c8        E.......:..s..e.
0x0010   c0a8 0164 0035 0268 006e ba41 ea1a 8183        .....5.h.n.A....
0x0020   0001 0000 0001 0000 0133 0234 3503 3139        .........3.45.19
0x0030   3103 3230 3605 646e 7362 6c05 736f 7262        1.206.dnsbl.sorb
0x0040   7303 6e65 7400 0001 0001 c019 0006 0001        s.net...........
0x0050   0000 0e10 002c 0772 626c 646e 7330 c01f        .....,.rbldns0..
0x0060   0364 6e73 0469 7375 7803 636f 6d00 431c        .dns.isux.com.C.
0x0070   e07e 0000 1c20 0000 1c20 0009 3a80 0000        .~..........:...
0x0080   0e10                                                                        ..

As a refresher I will quickly go through all of the fields starting from the first line and work my way through going from right to left. The first line has the time stamp, which is the time that the destination computer received this DNS packet at.

Next we have the source IP address and source port ie: followed by the director sign, which signifies the flow of the conversation as it were. After that we then have the destination IP address and destination port. 

Now we have the [udp sum ok] signifying that the udp checksum is correct. After that we  have the DNS transaction number of 59930. This is, as mentioned before, used to keep track of the DNS queries and responses by the originator of the query.

Next we see the RCODE of NXDomain and that means that the domain that resolution was requested for does not exist. Following that are the numbers 0/1/0 and they mean that there is zero answer records, one authoritative record, and zero additional records in this packet.

Following that we have the value of 102 in brackets. That is the amount of DNS data contained in this packet. Next up is the ttl value of 58, an IP ID value of 55787, and lastly the overall packet length of 130. It is important to remember that the “len 130” field as seen in the above packet refers to overall packet size, and that includes both the protocol headers, and data if present. 

We won’t bother going through the hex values below that represent the IP and UDP header, but rather skip ahead to the DNS header and data. Once again a quick way to navigate to key points in the packet is to do the following.

We know that our IP header will end at bytes “0164” as underlined on line 0x0010. We also know there are no IP options due to the half-byte value of 5 as underlined on line 0x0000. Due to this we then know that the UDP header will start at bytes “0035” and end at bytes “ba41”. So from this we can ascertain that our DNS header will begin at byte “ea” as underlined on line 0x0010.

With that out of the way we will now break out the DNS header values. If you check your TCP/IP and tcpdump flyer that you downloaded you will note that the first field in the DNS header relates to the ID number. This field is assigned two bytes or 16 bits. You will need to write out a small chart like the one below.

| 32768 | 16384 | 8192 | 4096 | 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |

What we now need to do is take the two bytes represented by the characters “ea1a” and enter them in a calculator, which will perform hex to decimal conversions. You will note that once you convert “ea1a” to decimal that you indeed come up with the value of 59930 in the packet above. So far so good, the DNS record number matches.

Now we will see that the next values as noted on our SANS cheat sheet have a variety of different meanings. So far we have seen mostly values reflected in a header that break neatly either on a nibble (half of a byte or four bits) or a full byte or bytes. Well in DNS we have several values contained in a byte. That is why we need the chart shown above.

We will need to take the value of the two bytes “8183” and convert that to a decimal number. From that decimal number we will be able to determine what values are set, and which are not. Well 8183 in hex or as it should be written 0x8183 breaks out to 33155 in decimal.

Using the above chart as noted we begin to divide 33155 by the values assigned to the two byte field, which contain the values on your cheat sheet ie: QR, Opcode, and so on. So we know then that the first position of 32768 is set, thus we know this to be a Response, vice a Query. Having subtracted 33155 from 32768 we have a remainder of 387.

We now subtract 387 from the next closest fit. In this case that would be 256. So that value is also set, which tells us that the “Recursion Desired”, or RD field is set. Now we have a remainder of 131. This we subtract from 128 on our chart above, which tells us that the “Recursion Available” field is set. That now leaves us with a remainder of 3.

Here is the tricky part. You have to take this decimal value of 3 and look at your “Response code” field seen on your SANS cheat sheet, under the DNS header. You will see that a decimal value of 3 reflects that the “Non-existent domain” or NXDomain RCODE is set. We can see that it is in the header of this packet, as evidenced by the NXDomain underlined.

Following these values it is simply a matter of applying the same logic to the remainder of the values in the DNS header. As you can see it is not much more difficult then breaking out the normal TCP/IP packets that we have done before. It was only a bit more confusing as we were now looking at application layer data as well now. You have now successfully parsed a DNS packet. That is a skill not very many people have! On that note I will wrap up this three part article series on DNS, and sincerely hope that it was useful to you. I always welcome comments, so please feel free to write me. Till next time!

If you missed the previous parts in this series please go read:

See Also

Featured Links