Abstract

We describe the implementation of a custom Domain Name System (DNS) by using C socket programming for network communication, together with SQLite3 database for the storage of Internet Protocol (IP) for Uniform Resource Locator (URL). Then we provide a performance analysis of our implementation. Our code is available publicly [1].

Introduction

The DNS is used to retrieve IP addresses corresponding to a given URL. IP is essential for web browsing: the user specifies a human-friendly URL address to the browser and then, before loading the corresponding web page, the URL firstly translated into IP address. To perform this action, DNS servers are used.

DNS server is a database containing URL addresses and their corresponding IP addresses. Due to the large amount of the URL, the DNS server is organized as a distributed hierarchical database. In certain cases, DNS suffer from the problem of high load that results in long delays between user requests and server response and affects user experience. 

To overcome the problem of high load, custom DNS servers are introduced. The custom DNS server is used to store the most frequently visited user web pages. That mechanism provides high-speed performance. 

In Figure 1 we illustrate the interaction of a custom DNS server with an existent global DNS system. In the presence of a custom DNS server, the request of the user web browser first goes to a custom DNS server. If the custom DNS server already has the IP of the requested web page then it just returns it and the browser loads the web page. Observe, in that case, the custom DNS server does not contact other servers, thereby reducing the execution time of performing the user request. If custom DNS does not have the IP of the requested web page, it contacts the local DNS server. 

Figure 1. The high-level view of the DNS server working principal.
Figure 1. The high-level view of the DNS server working principal.

The paper is organized as follows: first, in section 2 we describe the key implementation aspects of a custom DNS server with section 2.1 covering the stack of technologies we use, section 2.2 covering the programming aspects of C sockets. Then in section 3, we provide the performance analysis of our implementation. Next in section 4, we make program testing. In section 5 we outline the limitations of the project. Finally, in section 6 we conclude the work that has been done.  

Implementation of a Custom DNS Server 

We below explain the key implementation aspects of the  DNS server. 

Used Technologies and Network Configuration

The list of technologies used in our implementation is listed in Table 1. 

Technology

Description

SQLite3 

Database, that stores corresponding IP and domain name addresses. 

C sockets

Standard C library, used for network communication.

UDP

Transport protocol, used for sending DNS queries. 

Dig (Domain Information Groper)

Command-line tool for querying DNS servers.

Table 1. List of technologists, used in our application

Custom DNS Implementation

The core of a DNS server is a database that stores pairs of IPs and URL addresses, described in Figure 2. 

Figure 2. SQLite 3 database system used in the project.
Figure 2. SQLite 3 database system used in the project.

We organized the internal structure in the database in 5 columns:  domain_name column stores the domain name of the server, which IP address should be resolved;

ip1, ip2, ip3, ip4 - first, second, third, fourth 4-bit fields of IPv4 address, associated with the domain name.

For the security issues, we limit the size of the database to 1 GB for avoiding extensive enlarging the database.

Our custom DNS server can be accessed via the following IP and port numbers.

Access information (IP and port)

Description

Port

9000

IP address

The IP address of the host that runs custom DNS (127.0.0.1 in case of running server locally).

Table 2. Access information for connecting to custom DNS.

When the client requests the IP, the custom server first checks if the requested mapping of hostname to IP is located in the SQLite 3 database. In case IP is stored in a database, the server retrieves it and responds to the user. In case if IP is not present in the database, the custom server makes a request to the local DNS server. We provide the illustration in Figure 3.

When the custom server fails to retrieve an IP from the custom DNS database, it makes a call to the local DNS server. After searching IP in its database, the local server returns it to the custom server, which saves information to the SQLite 3 database and only then returns it to the user. 

Figure 3. Principle of working of our Custom DNS server
Figure 3. Principle of working of our Custom DNS server

The list of functions used in our implementation is listed in Table 3.

Function name

Function argument

Description

1. dig

IP address (e.x. @127.0.0.1)  and port (e.x. -p 9000) to connect to a custom DNS server.

The command-line tool, used for DNS server communication.

2. int get_A_record_from_sqlite

u_int8_t addr[4] - pointer to a resolved IP address; 

const char domain_name[] - domain name (or URL), received from the user. 

The function that is used for searching IP addresses in database SQLite3.

Returns 0 in case of success, 1 in case of failure: loss of database connection, etc.

3. int local

char *argv[] - pointer to the domain name, that is sent to the local DNS server.

The function that is used for sending DNS queries to local DNS.

Returns 0 in the case of success, 1 in case of failure.

4. sqlite3::insert

The function that is used for putting IP addresses into a database. Implementation of the function consists of API SQLite3: sqlite3_prepare_v2 and sqlite3_step, used for parameter substitution.

Table 3. List of functions, used in our application

Performance analysis

We next provide a static analysis of the custom DNS application. We measure the processing time of the DNS requests using time command from the standard C-librarytime.h .

We evaluate performance in the following cases: 

  1. If IP presents in the storage of custom DNS - it immediately sends the requested IP address to the client; 

  2. If IP not present in the custom server database - it should be retrieved from the local server and then sent to the client; 

  3. Otherwise, in case of an invalid IP address, the user should receive an empty DNS packet. 

We measured the execution time on the 3 cases and reported the results in Figure 4.

Figure 4. Measuring response time of various use cases.
Figure 4. Measuring response time of various use cases.

We observe that a custom DNS server, having an IP address in the database, provides a huge performance gain, compared to the case when the IP is retrieved from a local DNS server (8 msec. compared to 200 msec.) and in the case of invalid IP address - 20 msec.

User Interface and Usage

We next describe detailed instructions on running a custom DNS server and provide an example of its usage.

The commands provided are suitable for Linux based operating systems only. Also, It is important to have a C compiler to run the application. Launching a DNS server should be done by command:

$ gcc -o main -lsqlite3 main.c  && ./main.

Accessing to the DNS server via terminal can be done by a command:  dig @<IPv4 address> -p <port number> <domain name> A.

After compiling a custom DNS server and asking it IP address of URL www.habr.com (by command dig @127.0.0.1 -p 9000 www.habr.com A), a user could see logs, created by the server, in Figure 5; and client logs - in Figure 6. 

Figure 5. Logs from the DNS server, obtained from resolving domain name (www.habr.com) to IP address (178.248.237.68).

Figure 6. DNS packet, received from the server by client, containing resolved IP address (178.248.237.68) of (www.habr.com) domain name. 

Limitations of the Project

We next describe the limitations of the project.

For the simplicity of the project, we limit the functionality of the server.  Firstly, the server is not constantly accessible to clients - it could process only one query at a time and then exits the program. Secondly, the server does not support concurrent fulfilling queries, so multiple users can not access it. Thirdly, the server only supports A type of queries. Moreover, the server can run only on Linux-based systems due to special libraries which are working only on that family of the operating system. 

Conclusion

We proposed the implementation of a DNS server that handles request IP and domain name conversion among clients. We discovered a decrease of latency of DNS resolving using a built-in SQLite 3 database that caches recently retrieved IP addresses. During the project, we deeply studied the main principles of the DNS resolution process, C socket programming API and best practices of working with database systems. However, more knowledge is needed to optimize our application.

Reference list:

  1.  https://github.com/homomorfism/dns_server

Authors: Dariya Vakhitova, Arslanov Shamil (@homomorfism)

Innopolis University, 2021