Create DNS Query In Dart Language
Tags: dart, dartlang, dns
Published: 2021-12-26 14:36:31

In this Section, I will explain how to create DNS Query for getting a A Record.

And, in this section, We will try to use Google's Public DNS.
By sending a Get request to 

`https://dns.google/dns-query?dns=${base64ized DNS Message}`

You can retrieve a record from DNS by sending a Get request to


## DNS Message Format

The DNS format consists of five sections: `Header`, `Question`, `Answer`, `Authority`, `Additional`.


```
4. MESSAGES

4.1. Format

    +---------------------+
    |        Header       |
    +---------------------+
    |       Question      | the question for the name server
    +---------------------+
    |        Answer       | RRs answering the question
    +---------------------+
    |      Authority      | RRs pointing toward an authority
    +---------------------+
    |      Additional     | RRs holding additional information
    +---------------------+

from https://datatracker.ietf.org/doc/html/rfc1035
```

## Header for Request

Header Section is following format.

```
4.1.1. Header section format
                                    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                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

```

But if you just want to get A RECORD, you can do the following
- ID can be anything.
- RD will be 1.
- QDCOUNT will be 1.
- Otherwise, it can be 0.


Let's write this at dart.

```dart

var buffer = DNSBuffer(12);

void setInt16AtBE(Uint8List _buffer, int index, int value) {
  _buffer[index + 0] = (value >> 8) & 0xFF;
  _buffer[index + 1] = (value >> 0) & 0xFF;
}

void main() {
  var buffer = Uint8List(12);
  for (var i = 0; i < 12; i++) {
    buffer[i] = 0;
  }
  setInt16AtBE(buffer, 0, 0x1234);
  buffer[2] = 0x01;
  setInt16AtBE(buffer, 5, 0x01);
  print(toHex(buffer)); // 123401000001000000000000
}

```


## Question for Request

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

```

The format of the Question's Section is as above, and for QNAME If you want to get A RECORD,

QTYPE should be set to 1
QCLASS should be set to 1

QNAME should be set to the domain name, not a string like github.com.

## QNAME

```
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    12 |           6           |           g           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    14 |           i           |           t           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    16 |           h           |           u           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    26 |           b           |           3           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    28 |           c           |           o           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    30 |           m           |           0           |
       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

```

The above is a single-byte number, an ASCII string, a single-byte number, and an ASCII string.

The Null character is added at the end.


Let's write this at dart.

```dart

void main() {
  var host = 'github.com';
  var splitHost = host.split('.');
  // Calc Buffer Size
  var length = splitHost.length;
  splitHost.forEach((e) {
    length += e.length;
  });
  length += 1; // NULL CHAR
  length += 4; // CLASS  AND TYPE

  // Set Value
  var buffer = Uint8List(length);
  for (var i = 0; i < 12; i++) {
    buffer[i] = 0;
  }

  var index = 0;
  splitHost.forEach((e) {
    buffer[index++] = e.length;
    for (var i = 0; i < e.length; i++) {
      buffer[index++] = ascii.encode(e.substring(i, i + 1))[0];
    }
  });

  setInt16AtBE(buffer, length - 4, 0x01);
  setInt16AtBE(buffer, length - 2, 0x01);
  print(toHex(buffer)); // 0667697468756203636f6d0000010001
}

```


## Request at Browser

If you combine the Header and Question, you get `1234010000010000000000000667697468756203636f6d0000010001` byte data. When converted to Base64, 

```dart
import 'dart:typed_data' show Uint8List;
import 'dart:convert' show base64;

Uint8List fromHexString(String hexSrc) {
  var _buffer = Uint8List(hexSrc.length ~/ 2);
  for (var i = 0, j = 0; i < hexSrc.length; i += 2, j++) {
    var v = int.parse(hexSrc.substring(i, i + 2), radix: 16);
    _buffer[j] = v & 0xFF;
  }
  return _buffer;
}

void main() {
  var buffer = fromHexString('1234010000010000000000000667697468756203636f6d0000010001');
  print(base64.encode(buffer)); // EjQBAAABAAAAAAAABmdpdGh1YgNjb20AAAEAAQ==
}

```

it becomes `EjQBAAABAAAAAAAABmdpdGh1YgNjb20AAAEAAQ==`

From this, if we remove == and apply it to the Google Public DNS address, we get the following

`https://dns.google/dns-query?dns=EjQBAAABAAAAAAAABmdpdGh1YgNjb20AAAEAAQ`


You can get following DNS Response

```
1234818000010001000000000667697468756203636f6d0000010001c00c000100010000003c000434c04859
```

# REF

https://github.com/kyorohiro/dart2.dns

https://datatracker.ietf.org/doc/html/rfc1035