Skip to content

Commit 2f1ab8d

Browse files
committed
Add readme
1 parent c7ff702 commit 2f1ab8d

File tree

4 files changed

+278
-11
lines changed

4 files changed

+278
-11
lines changed

README.md

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
# Managed DNS Server
2+
3+
A DNS server implementation written in Go from **scratch**,
4+
supporting a management service via a RESTful API.
5+
This project includes custom DNS record handling, database
6+
integration for record persistence, and configuration management.
7+
8+
## Features
9+
10+
- Custom _authorative_ DNS server and client implementation.
11+
- REST API for managing DNS records.
12+
- Supports `A`, `CNAME`, and other common DNS record types.
13+
- Uses PostgreSQL for persistent record storage.
14+
- Implements EDNS (Extension Mechanisms for DNS) with optional support.
15+
16+
# Background
17+
18+
## How DNS Resolution Works
19+
20+
When you type a domain name into your browser (e.g., `www.example.com`), your computer needs to convert that domain name into an
21+
IP address so it can communicate with the correct server. This process is known as **DNS resolution** and involves several steps:
22+
23+
1. **Root Name Servers**
24+
The process begins with a request to a **root name server**.
25+
The root name servers are responsible for directing the query to the appropriate **Top-Level Domain (TLD)** server based
26+
on the suffix of the domain name (e.g., `.com`, `.org`, `.net`).
27+
28+
2. **TLD Servers**
29+
The TLD servers are responsible for handling the domain extensions (such as `.com`, `.org`, etc.).
30+
When the root name server directs the query to the correct TLD server, the TLD server then provides information about the authoritative name servers for the requested domain.
31+
32+
3. **Authoritative Name Servers**
33+
The **authoritative name servers** hold the final DNS records for the domain.
34+
They are responsible for returning the IP address of the requested domain.
35+
These servers can be the domain's hosting provider or a DNS service you configure (such as Cloudflare or Google DNS).
36+
**This implementation works as an authoritative name server**
37+
38+
### Types of Resolvers
39+
40+
There are two main types of DNS resolvers that interact with these name servers:
41+
42+
- **Recursive Resolver**
43+
A **recursive resolver** is responsible for making the full query process.
44+
It starts at the root name servers and follows the chain through the TLD servers until it
45+
reaches the authoritative servers. It then returns the final result (IP address) to the client.
46+
This type of resolver performs all the necessary steps and provides a complete answer.
47+
48+
- **Iterative Resolver**
49+
An **iterative resolver**, on the other hand, only provides partial answers.
50+
It queries the root name servers for a direction to the TLD servers and then asks the TLD servers for the authoritative servers.
51+
The iterative resolver does not follow the full path and relies on the client (or a recursive resolver) to complete the final step.
52+
53+
## DNS Message Format
54+
55+
The DNS protocol uses a specific binary message format for communication between clients (resolvers) and servers.
56+
Each DNS message consists of a **header**, a **question section**, and optional **answer**, **authority**, and **additional sections**.
57+
Below is a detailed explanation of each part of the DNS message.
58+
59+
---
60+
61+
### DNS Message Structure
62+
63+
1. **Header (12 bytes)**
64+
The header contains metadata about the DNS query or response.
65+
66+
| Field | Size (bits) | Description |
67+
| ------------------- | ----------- | ------------------------------------------------------------ |
68+
| Transaction ID | 16 | Unique identifier for matching requests and responses. |
69+
| Flags | 16 | Control and status flags (e.g., QR, Opcode, AA, TC, RD, RA). |
70+
| Question Count | 16 | Number of questions in the Question section. |
71+
| Answer Record Count | 16 | Number of resource records in the Answer section. |
72+
| Authority Count | 16 | Number of resource records in the Authority section. |
73+
| Additional Count | 16 | Number of resource records in the Additional section. |
74+
75+
#### Header Flags Breakdown (16 bits)
76+
77+
The flags field is divided into individual control flags and operation codes:
78+
| Bit | Name | Description |
79+
|-----|---------------|-----------------------------------------------------------------------------|
80+
| 0 | QR | Query (0) or Response (1). |
81+
| 1-4 | Opcode | Type of query (e.g., 0 for standard query). |
82+
| 5 | AA | Authoritative Answer (set by authoritative servers in responses). |
83+
| 6 | TC | Truncated Message (set if the message is too large for the transport). |
84+
| 7 | RD | Recursion Desired (set by clients to request recursion). |
85+
| 8 | RA | Recursion Available (set by servers that support recursion). |
86+
| 9-11| Z | Reserved for future use; must be set to 0. |
87+
| 12-15 | RCODE | Response Code (e.g., 0 for NOERROR, 3 for NXDOMAIN). |
88+
89+
---
90+
91+
2. **Question Section**
92+
The question section specifies the query details sent by the client.
93+
94+
| Field | Size (variable) | Description |
95+
| ------ | --------------- | --------------------------------------------- |
96+
| QNAME | Variable | Domain name being queried, encoded in labels. |
97+
| QTYPE | 16 bits | Type of query (e.g., A, AAAA, CNAME, MX). |
98+
| QCLASS | 16 bits | Class of query (e.g., IN for Internet). |
99+
100+
#### Example:
101+
102+
For the domain `example.com`, the `QNAME` is encoded as: [7]example[3]com[0]
103+
104+
Where each label is preceded by its length, and the name is terminated by a zero byte.
105+
106+
---
107+
108+
3. **Answer Section**
109+
Contains resource records (RRs) that answer the query. Each RR has the following fields:
110+
111+
| Field | Size (variable) | Description |
112+
| -------- | --------------- | ---------------------------------------------------------- |
113+
| NAME | Variable | Domain name to which the RR applies (often a pointer). |
114+
| TYPE | 16 bits | Type of RR (e.g., A, AAAA, CNAME). |
115+
| CLASS | 16 bits | Class of RR (e.g., IN for Internet). |
116+
| TTL | 32 bits | Time-to-live, in seconds, for caching the RR. |
117+
| RDLENGTH | 16 bits | Length of the RDATA field. |
118+
| RDATA | Variable | Data associated with the RR (e.g., IP address for A type). |
119+
120+
---
121+
122+
4. **Authority Section**
123+
Contains RRs pointing to authoritative servers for the queried domain. The format is identical to the Answer section.
124+
125+
---
126+
127+
5. **Additional Section**
128+
Provides additional data, such as: EDNS cookies or resolved records that might be useful for the resolver
129+
130+
## Name Compression in DNS Messages
131+
132+
To reduce the size of DNS messages, domain names can be encoded using **name compression**. Name compression replaces repeated domain name labels with pointers to their previous occurrences in the message.
133+
134+
### Pointer Format
135+
136+
A pointer uses the most significant 2 bits of a label length byte to indicate a compressed label:
137+
138+
- **Pointer Indicator:** The first two bits of the byte are set to `11` (binary).
139+
- **Offset:** The remaining 14 bits represent the pointer's offset from the start of the DNS message.
140+
141+
### Example:
142+
143+
Consider the domain name `example.com` appearing multiple times in a DNS response:
144+
145+
- The first occurrence is encoded as: [7]example[3]com[0]
146+
147+
- Subsequent occurrences use a pointer: [C0 0C]
148+
149+
## Extended DNS (EDNS)
150+
151+
EDNS extends DNS by adding an **OPT pseudo-record** in the additional section, enabling features like larger message sizes and DNS Cookies.
152+
153+
### OPT Record Structure:
154+
155+
| Field | Size | Description |
156+
| -------------- | -------- | ---------------------------------------- |
157+
| NAME | 0 bytes | Must be 0 (root domain). |
158+
| TYPE | 16 bits | Always `OPT` (value 41). |
159+
| UDP Size | 16 bits | Maximum UDP payload size supported. |
160+
| Extended RCODE | 8 bits | Extended response codes. |
161+
| Version | 8 bits | EDNS version (currently 0). |
162+
| Flags | 16 bits | Various flags (e.g., DO bit for DNSSEC). |
163+
| Data | Variable | Optional data like DNS Cookies. |
164+
165+
---
166+
167+
## Requirements
168+
169+
- [Go 1.20+](https://go.dev/dl/)
170+
- [PostgreSQL 12+](https://www.postgresql.org/)
171+
- [GORM](https://gorm.io/) ORM for database operations
172+
- [GIN](https://gin-gonic.com/) Web framework for REST API interface
173+
- Docker (optional, for containerized deployment)
174+
175+
## Installation
176+
177+
1. Clone the repository:
178+
179+
```bash
180+
git clone https://github.com/XxRoloxX/dns.git
181+
cd dns
182+
```
183+
184+
2. Set up environment variable for database configuration
185+
186+
```bash
187+
export DB_HOST=localhost
188+
export DB_USER=youruser
189+
export DB_PASSWORD=yourpassword
190+
export DB_NAME=yourdb
191+
export DB_PORT=5432
192+
```
193+
194+
or just write them to the .env file
195+
196+
3. Build and run docker-compose
197+
198+
```bash
199+
docker compose up -d
200+
```
201+
202+
![Alt text](./assets/dns-check.gif)
203+
204+
## Deployment
205+
206+
To begin using this server in production, register a NS
207+
(Name Server) record with your domain registrar and point it
208+
to the instance hosting this server. Once this is done,
209+
the server will be able to manage the **delegated zone**, and
210+
all DNS queries for the associated subdomain will be directed to the newly deployed server.
211+
212+
For example, if your domain is `example.com` and the subdomain is `sub.example.com`,
213+
you would add a NS record pointing sub.example.com to the IP address or
214+
hostname of the new server, allowing it to handle all DNS traffic for that subdomain.
215+
216+
## API ENDPOINTS
217+
218+
### BASE URL
219+
220+
`http://localhost:8080/`
221+
222+
### For DNS server
223+
224+
`localhost:53` (udp)
225+
226+
### Endpoints
227+
228+
#### Get all Records
229+
230+
_GET_ `/records`
231+
232+
- Request response
233+
234+
```json
235+
[
236+
{
237+
"name": "example.com",
238+
"type": "A",
239+
"class": "IN",
240+
"data": "192.168.1.1"
241+
}
242+
]
243+
```
244+
245+
#### Create record
246+
247+
_POST_ `/records`
248+
249+
- Request body
250+
251+
```json
252+
[
253+
{
254+
"name": "example.com",
255+
"type": "A",
256+
"class": "IN",
257+
"data": "192.168.1.1"
258+
}
259+
]
260+
```
261+
262+
#### Delete record
263+
264+
_DELETE_ `/records/:id`
265+
266+
```json
267+
{
268+
"message": "Record deleted succefully"
269+
}
270+
```
271+
272+
![Alt text](./assets/management-check.gif)
273+
274+
## Resources
275+
276+
- [RFC 1035: Domain Names - Implementation and Specification](https://datatracker.ietf.org/doc/html/rfc1035)
277+
- [RFC 1034: Concepts and Facilities](https://www.ietf.org/rfc/rfc1034.txt)
278+
- [RFC 6891: Extension Mechanisms for DNS (EDNS)](https://datatracker.ietf.org/doc/html/rfc6891)

assets/dns-check.gif

61.5 KB
Loading

assets/management-check.gif

34.1 KB
Loading

cmd/dns/main.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,13 @@
11
package main
22

33
import (
4-
// "github.com/XxRoloxX/dns/internal/client"
54
"github.com/XxRoloxX/dns/pkg/dns_message"
65
"github.com/XxRoloxX/dns/pkg/dns_server"
7-
// "log/slog"
86
)
97

108
func main() {
119

1210
srv := server.NewServer()
1311

1412
srv.Listen(make(chan message.Message))
15-
16-
// client := client.NewClient()
17-
//
18-
// _, err := client.QueryATypeRecords("wmsdev.pl")
19-
// if err != nil {
20-
// slog.Error("Failed to query A type record", "err", err)
21-
// return
22-
// }
23-
2413
}

0 commit comments

Comments
 (0)