Hand writing DNS queries | Web from scratch pt. 1

Click here to skip to the tutorial.

About this series

In this tutorial series, I will show how to build a simple web browser from start to finish, assuming only the existence of an operating system, sockets, and an ability to draw to the screen. The rest we will fill in ourselves. This web browser will be very basic and unable to interpret CSS, JavaScript, or really any kind of styling, but it will illustrate how the internals of a web browser function -- and be able to fetch and render the page you are currently reading.

This will be done in C++, but the reader may follow along in any language. This tutorial is meant for people who have at least some experience in HTML and web development.

An understanding of the following things is assumed before this tutorial proceeds. Links are included to read about the topics if you want to learn them.

Required knowledge for this article: Required knowledge for future articles:


It may be beneficial to periodically refer to the official document, RFC 1035, to clear up any questions you may have and to learn more about DNS.

Outline of this post:

  1. Structure of DNS requests
  2. Crafting a request by hand
  3. Making a real request
  4. Structure of response
  5. Interpreting the response
  6. Next steps

Structure of DNS requests


Term: The RFC defines on page 25 a message, the structure which all DNS messages, whether requests or responses, must follow.

Each message is divided into 5 sections, all of which (except for the header) can be empty.

  1. Header
  2. Question: the question for the name server
  3. Answer: records answering the question
  4. Authority: records pointing towards an authoritative name server
  5. Additional: records that may relate to a query but are not strictly answers to a question

In this tutorial, we will only concern ourselves with sections 1 (header), 2 (question), and 3 (answer). When crafting requests, we will be using the first two sections, and when parsing respones, we will use all three sections.

Crafting a request by hand

I like to learn by example, so let's start by crafting a request to find the IP of google.com.

Typical requests to get an IP from a domain name include only a header and a question (from the message format shown above.

The header

DNS is not an ASCII-based format like HTTP, but binary. While this makes it easy for computers to understand, it unfortunately requires some extra effort for us humans. Regardless, we've just gotta suck it up and read the spec.

To construct the header, we will refer to the following table given on page 26 of the RFC 1035:

                                    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                    |

Each "row" on this table, (e.g. ID, QDCOUNT, NSCOUNT) contains 16 bits, shown as columns on the top row from 0 to 15. There are 6 rows, so our header will be 96 bits, or 12 bytes. Row 2 contains many smaller flags that are varying widths.

The header can be a little confusing because the exact same format is used for requests and responses, so some fields may not have meaning in a request and should simply be set to 0.

Try and skim the sections below, but don't stress too hard. We'll come back to all this later when we actually construct the request.

Also, you are not expected to know what everything means in the below list. Don't worry about it, we'll do an example.

Let's go through the rows one by one: