diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39ee26ae704de55b51459d73f9a44b4b2dec1650..e1baa758096e7bba746a041c6681bde58999c154 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -67,7 +67,7 @@ endif()
 if (CELLFRAME_MODULES MATCHES "dap-sdk-net-client")
 
     set(DAPSDK_MODULES "core crypto io network-core network-link_manager network-client network-server")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_core dap_crypto dap_io dap_server dap_client m)
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_core dap_crypto dap_io dap_server dap_client dap_dns_server m)
     if(NOT ANDROID)
         set(CELLFRAME_LIBS ${CELLFRAME_LIBS} pthread)
     endif()
diff --git a/core/include/dap_common.h b/core/include/dap_common.h
index d08bf97a6661e275864152f76d228743814d87de..88d1c07d392c94b7de39c62badff97c539de92a8 100755
--- a/core/include/dap_common.h
+++ b/core/include/dap_common.h
@@ -231,7 +231,7 @@ static inline void *s_vm_extend(const char *a_rtn_name, int a_rtn_line, void *a_
 #define VA_NARGS(...) VA_NARGS_IMPL(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
 #define DAP_DEL_MULTY(...) dap_delete_multy(VA_NARGS(__VA_ARGS__), __VA_ARGS__)
 
-#define DAP_DEL_Z(a)          do if (a) { DAP_DELETE(a); (a) = NULL; } while (0);
+#define DAP_DEL_Z(a)          do { if (a) { DAP_DELETE(a); (a) = NULL; } } while (0);
 // a - pointer to alloc
 // t - type return pointer
 // s - size to alloc
diff --git a/core/src/dap_config.c b/core/src/dap_config.c
index 1c2c9cf296bdfac0e7fc1793e3d37aea923bf26c..2c273373092fc20e5a021c4505f80b70b62faa62 100644
--- a/core/src/dap_config.c
+++ b/core/src/dap_config.c
@@ -300,9 +300,13 @@ dap_config_t *dap_config_open(const char* a_file_path) {
     }
     log_it(L_DEBUG, "Looking for config name %s...", a_file_path);
     char l_path[MAX_PATH] = { '\0' };
+    const char *l_suffix = "";
+    size_t l_path_len = strlen(a_file_path);
+    if (l_path_len < 4 || strcmp(a_file_path + l_path_len - 4, ".cfg"))
+        l_suffix = ".cfg";
     int l_pos = dap_strncmp(a_file_path, s_configs_path, strlen(s_configs_path) - 4)
-            ? snprintf(l_path, MAX_PATH, "%s/%s.cfg", s_configs_path, a_file_path)
-            : snprintf(l_path, MAX_PATH, "%s.cfg", a_file_path);
+            ? snprintf(l_path, MAX_PATH, "%s/%s%s", s_configs_path, a_file_path, l_suffix)
+            : snprintf(l_path, MAX_PATH, "%s%s", a_file_path, l_suffix);
 
     if (l_pos >= MAX_PATH) {
         log_it(L_ERROR, "Too long config name!");
diff --git a/io/include/dap_net.h b/io/include/dap_net.h
index 252aadd0c955b814a4756445e460a32e27cb43cb..81d337fb79d6523e709255d82afc9df19461cc36 100644
--- a/io/include/dap_net.h
+++ b/io/include/dap_net.h
@@ -48,16 +48,25 @@
 #define DAP_CFG_PARAM_SOCK_PERMISSIONS  "listen-unix-socket-permissions"
 #define DAP_CFG_PARAM_LEGACY_PORT       "listen-port-tcp"
 
+typedef struct dap_link_info {
+    dap_stream_node_addr_t node_addr;
+    char uplink_addr[DAP_HOSTADDR_STRLEN];
+    uint16_t uplink_port;
+} DAP_ALIGN_PACKED dap_link_info_t;
+
+typedef struct dap_net_links {
+    uint64_t count_node;
+    byte_t nodes_info[];
+} DAP_ALIGN_PACKED dap_net_links_t;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-
-
 int dap_net_resolve_host(const char *a_host, const char *a_port, bool a_numeric_only, struct sockaddr_storage *a_addr_out, int *a_family);
 int dap_net_parse_config_address(const char *a_src, char *a_addr, uint16_t *a_port, struct sockaddr_storage *a_saddr, int *a_family);
 long dap_net_recv(SOCKET sd, unsigned char *buf, size_t bufsize, int timeout);
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/net/client/include/dap_client.h b/net/client/include/dap_client.h
index 9d7ae83f74f1da0a9cc9a0daf441715ec33f9f1b..b8e3aa42f5718703b2b3ce750d4ffdbd23cd51e3 100644
--- a/net/client/include/dap_client.h
+++ b/net/client/include/dap_client.h
@@ -23,7 +23,7 @@
 */
 #pragma once
 
-#include "dap_events.h"
+#include "dap_net.h"
 #include <stdint.h>
 #include "dap_enc_key.h"
 #include "dap_stream.h"
@@ -77,12 +77,6 @@ typedef void (*dap_client_callback_t) (dap_client_t *, void *);
 typedef void (*dap_client_callback_int_t) (dap_client_t *, void *, int);
 typedef void (*dap_client_callback_data_size_t) (dap_client_t *, void *, size_t);
 
-typedef struct dap_link_info {
-    dap_stream_node_addr_t node_addr;
-    char uplink_addr[DAP_HOSTADDR_STRLEN];
-    uint16_t uplink_port;
-} DAP_ALIGN_PACKED dap_link_info_t;
-
 /**
  * @brief The dap_client struct
  */
diff --git a/net/server/CMakeLists.txt b/net/server/CMakeLists.txt
index 9d8ed804e823ef4ed5fcc56d12a69eed0aedeac5..deaf9312346492c81f5374e3a86f00f8a078d8bb 100644
--- a/net/server/CMakeLists.txt
+++ b/net/server/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(cli_server)
 add_subdirectory(notify_server)
 add_subdirectory(http_server)
 add_subdirectory(enc_server)
+add_subdirectory(dns_server)
 add_subdirectory(json_rpc)
 
 
diff --git a/net/server/dns_server/CMakeLists.txt b/net/server/dns_server/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..354d1232f19c803b7586cfd3239e0c9b5755ca2c
--- /dev/null
+++ b/net/server/dns_server/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.10)
+project (dap_dns_server C)
+
+file(GLOB DAP_DNS_SRV_SRCS *.c)
+
+file(GLOB DAP_DNS_SRV_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_DNS_SRV_SRCS} ${DAP_DNS_SRV_HEADERS} )
+
+target_link_libraries(${PROJECT_NAME} dap_core dap_io m dap_json_rpc)
+target_include_directories(${PROJECT_NAME} PUBLIC include/ )
+
+if(INSTALL_DAP_SDK)
+set_target_properties(${PROJECT_NAME}  PROPERTIES PUBLIC_HEADER "${DAP_DNS_SRV_HEADERS}")
+INSTALL(TARGETS ${PROJECT_NAME} 
+        LIBRARY DESTINATION lib/dap/net/server/dns_server/
+        ARCHIVE DESTINATION lib/dap/net/server/dns_server/
+        PUBLIC_HEADER DESTINATION include/dap/net/server/dns_server/
+)
+endif()
diff --git a/net/server/dns_server/dap_dns_client.c b/net/server/dns_server/dap_dns_client.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d10cd272285734f7bf77c0b0dd37c96801a685c
--- /dev/null
+++ b/net/server/dns_server/dap_dns_client.c
@@ -0,0 +1,306 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * Dmitriy Gerasimov <dmitriy.gerasmiov@demlabs.net>
+ * DeM Labs Ltd   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2021
+ * All rights reserved.
+
+ This file is part of DapChain SDK the open source project
+
+    DapChain SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DapChain SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DapChain SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dap_context.h"
+#include "dap_timerfd.h"
+#include "dap_net.h"
+#include "dap_dns_server.h"
+#include "dap_dns_client.h"
+
+#define LOG_TAG "dap_chain_node_dns_client"
+
+struct dns_client
+{
+    dap_events_socket_t * parent;
+    struct in_addr addr;
+    uint16_t port;
+    char *name;
+    dap_dns_buf_t dns_request;
+    byte_t buf[1024];
+
+    dap_dns_client_node_info_request_success_callback_t callback_success;
+    dap_dns_client_node_info_request_error_callback_t callback_error;
+    void * callbacks_arg;
+
+    bool is_callbacks_called;
+};
+
+static void s_dns_client_esocket_read_callback(dap_events_socket_t * a_esocket, void * a_arg);
+static void s_dns_client_esocket_error_callback(dap_events_socket_t * a_esocket, int a_error);
+static bool s_dns_client_esocket_timeout_callback( void * a_arg);
+static void s_dns_client_esocket_delete_callback(dap_events_socket_t * a_esocket, void * a_arg);
+static void s_dns_client_esocket_worker_assign_callback(dap_events_socket_t * a_esocket, dap_worker_t * a_worker);
+
+/**
+ * @brief s_dns_client_esocket_read_callback
+ * @param a_esocket
+ * @param a_arg
+ */
+static void s_dns_client_esocket_read_callback(dap_events_socket_t * a_esocket, void * a_arg)
+{
+    (void) a_arg;
+    struct dns_client * l_dns_client = (struct dns_client*) a_esocket->_inheritor;
+    byte_t * l_buf = a_esocket->buf_in;
+    size_t l_recieved = a_esocket->buf_in_size;
+    size_t l_addr_point = DNS_REQUEST_SIZE + strlen(l_dns_client->name) + DNS_ANSWER_SIZE;
+    if (l_recieved < l_addr_point + sizeof(dap_link_info_t)) {
+        log_it(L_WARNING, "DNS answer incomplete");
+        l_dns_client->callback_error(a_esocket->worker, l_dns_client->callbacks_arg, EIO);
+        l_dns_client->is_callbacks_called = true;
+        a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+        a_esocket->buf_in_size = a_esocket->buf_out_size = 0;
+        return;
+    }
+    byte_t * l_cur = l_buf + 3 * sizeof(uint16_t);
+    int l_answers_count = ntohs(*(uint16_t *)l_cur);
+    if (l_answers_count != 1) {
+        log_it(L_WARNING, "Incorrect DNS answer format");
+        l_dns_client->callback_error(a_esocket->worker, l_dns_client->callbacks_arg, EINVAL);
+        l_dns_client->is_callbacks_called = true;
+        a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+        a_esocket->buf_in_size = a_esocket->buf_out_size = 0;
+        return;
+    }
+
+    dap_net_links_t *l_link_full_node_list = DAP_NEW_Z_SIZE(dap_net_links_t,sizeof(dap_net_links_t) + sizeof(dap_link_info_t));
+    l_cur = l_buf + l_addr_point;
+    *(dap_link_info_t *)l_link_full_node_list->nodes_info = *(dap_link_info_t *)l_cur;
+    l_link_full_node_list->count_node = 1;
+
+    l_dns_client->callback_success(a_esocket->worker, l_link_full_node_list, l_dns_client->callbacks_arg);
+    l_dns_client->is_callbacks_called = true;
+    a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
+    a_esocket->buf_in_size = a_esocket->buf_out_size = 0;
+    DAP_DELETE(l_link_full_node_list);
+}
+
+/**
+ * @brief s_dns_client_esocket_error_callback
+ * @param a_esocket
+ * @param a_error
+ */
+static void s_dns_client_esocket_error_callback(dap_events_socket_t * a_esocket, int a_error)
+{
+    struct dns_client * l_dns_client = (struct dns_client*) a_esocket->_inheritor;
+    log_it(L_ERROR,"DNS client esocket error %d", a_error);
+    l_dns_client->callback_error(a_esocket->worker, l_dns_client->callbacks_arg, a_error);
+    l_dns_client->is_callbacks_called = true;
+}
+
+/**
+ * @brief s_dns_client_esocket_timeout_callback
+ * @param a_worker
+ * @param a_arg
+ * @return
+ */
+static bool s_dns_client_esocket_timeout_callback(void * a_arg)
+{
+    assert(a_arg);
+    dap_events_socket_uuid_t * l_es_uuid_ptr = (dap_events_socket_uuid_t *) a_arg;
+    assert(l_es_uuid_ptr);
+
+
+    dap_worker_t * l_worker = dap_worker_get_current(); // We're in own esocket context
+    assert(l_worker);
+
+    dap_events_socket_t * l_es;
+    if((l_es = dap_context_find(l_worker->context,*l_es_uuid_ptr) ) != NULL){ // If we've not closed this esocket
+        struct dns_client * l_dns_client = (struct dns_client*) l_es->_inheritor;
+        log_it(L_WARNING,"DNS request timeout, bad network?");
+        if(! l_dns_client->is_callbacks_called ){
+            l_dns_client->callback_error(l_es->worker, l_dns_client->callbacks_arg, ETIMEDOUT);
+            l_dns_client->is_callbacks_called = true;
+        }
+        dap_events_socket_remove_and_delete_unsafe( l_es, false);
+    }
+    DAP_DEL_Z(l_es_uuid_ptr);
+    return false;
+}
+
+/**
+ * @brief s_dns_client_esocket_delete_callback
+ * @param a_esocket
+ * @param a_arg
+ */
+static void s_dns_client_esocket_delete_callback(dap_events_socket_t * a_esocket, void * a_arg)
+{
+    (void) a_arg;
+    struct dns_client * l_dns_client = (struct dns_client*) a_esocket->_inheritor;
+    if(! l_dns_client->is_callbacks_called )
+        l_dns_client->callback_error(a_esocket->worker, l_dns_client->callbacks_arg, EBUSY);
+    if(l_dns_client->name)
+        DAP_DELETE(l_dns_client->name);
+}
+
+/**
+ * @brief s_dns_client_esocket_worker_assign_callback
+ * @param a_esocket
+ * @param a_worker
+ */
+static void s_dns_client_esocket_worker_assign_callback(dap_events_socket_t * a_esocket, dap_worker_t * a_worker)
+{
+    struct dns_client * l_dns_client = (struct dns_client*) a_esocket->_inheritor;
+    dap_events_socket_write_unsafe(a_esocket,l_dns_client->dns_request.data, l_dns_client->dns_request.size );
+
+    dap_events_socket_uuid_t * l_es_uuid_ptr = DAP_NEW_Z(dap_events_socket_uuid_t);
+    if (!l_es_uuid_ptr) {
+        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
+        return;
+    }
+    *l_es_uuid_ptr = a_esocket->uuid;
+    dap_timerfd_start_on_worker(a_worker, dap_config_get_item_uint64_default(g_config,"dns_client","request_timeout",10)*1000,
+                                 s_dns_client_esocket_timeout_callback,l_es_uuid_ptr);
+
+}
+
+/**
+ * @brief dap_chain_node_info_dns_request
+ * @param a_addr
+ * @param a_port
+ * @param a_name
+ * @param a_result
+ * @param a_callback_success
+ * @param a_callback_error
+ * @param a_callbacks_arg
+ */
+int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_addr, uint16_t a_port, char *a_name,
+                           dap_dns_client_node_info_request_success_callback_t a_callback_success,
+                           dap_dns_client_node_info_request_error_callback_t a_callback_error,void * a_callbacks_arg)
+{
+    char l_addr_str[INET_ADDRSTRLEN] = {};
+    inet_ntop(AF_INET, &a_addr, l_addr_str, INET_ADDRSTRLEN);
+
+    log_it(L_INFO, "DNS request for bootstrap nodelist  %s : %d, net %s", l_addr_str, a_port, a_name);
+
+    struct dns_client * l_dns_client = DAP_NEW_Z(struct dns_client);
+    if(!l_dns_client)
+        return -1;
+    l_dns_client->name = dap_strdup(a_name);
+    l_dns_client->callback_error = a_callback_error;
+    l_dns_client->callback_success = a_callback_success;
+    l_dns_client->callbacks_arg = a_callbacks_arg;
+    l_dns_client->addr = a_addr;
+    dap_dns_buf_init(&l_dns_client->dns_request, (char *)l_dns_client->buf);
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, rand() % 0xFFFF);    // ID
+
+
+    dap_dns_message_flags_t l_flags = {};
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, l_flags.val);
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, 1);                  // we have only 1 question
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, 0);
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, 0);
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, 0);
+
+    size_t l_ptr = 0;
+    uint8_t *l_cur = l_dns_client->buf + l_dns_client->dns_request.size;
+    size_t l_name_len = strlen(a_name);
+    for (size_t i = 0; i <= l_name_len; i++)
+        if (a_name[i] == '.' || a_name[i] == 0) {
+            *l_cur++ = i - l_ptr;
+            while (l_ptr < i)
+                *l_cur++ = a_name[l_ptr++];
+            l_ptr++;
+        }
+    *l_cur++='\0';
+    l_dns_client->dns_request.size = l_cur - l_dns_client->buf;
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, DNS_RECORD_TYPE_A);
+    dap_dns_buf_put_uint16(&l_dns_client->dns_request, DNS_CLASS_TYPE_IN);
+
+    dap_events_socket_callbacks_t l_esocket_callbacks={};
+
+    l_esocket_callbacks.worker_assign_callback = s_dns_client_esocket_worker_assign_callback;
+    l_esocket_callbacks.delete_callback = s_dns_client_esocket_delete_callback; // Delete client callback
+    l_esocket_callbacks.read_callback = s_dns_client_esocket_read_callback; // Read function
+    l_esocket_callbacks.error_callback = s_dns_client_esocket_error_callback; // Error processing function
+
+    dap_events_socket_t * l_esocket = dap_events_socket_create(DESCRIPTOR_TYPE_SOCKET_UDP,&l_esocket_callbacks);
+    strcpy(l_esocket->remote_addr_str, l_addr_str);
+    l_esocket->remote_port = a_port;
+    l_esocket->_inheritor = l_dns_client;
+
+    dap_events_socket_assign_on_worker_mt(l_esocket, a_worker);
+    return 0;
+}
+
+
+/**
+ * @brief dap_dns_buf_init Initialize DNS parser buffer
+ * @param buf DNS buffer structure
+ * @param msg DNS message
+ * @return none
+ */
+void dap_dns_buf_init(dap_dns_buf_t *buf, char *msg)
+{
+    buf->data = msg;
+    buf->size = 0;
+}
+
+/**
+ * @brief dap_dns_buf_get_uint16 Get uint16 from network order
+ * @param buf DNS buffer structure
+ * @return uint16 in host order
+ */
+uint16_t dap_dns_buf_get_uint16(dap_dns_buf_t *buf)
+{
+    char c;
+    c = buf->data[buf->size++];
+    return c << 8 | buf->data[buf->size++];
+}
+
+/**
+ * @brief dap_dns_buf_put_uint16 Put uint16 to network order
+ * @param buf DNS buffer structure
+ * @param val uint16 in host order
+ * @return none
+ */
+void dap_dns_buf_put_uint16(dap_dns_buf_t *buf, uint16_t val)
+{
+    buf->data[buf->size++] = val >> 8;
+    buf->data[buf->size++] = val;
+}
+
+/**
+ * @brief dap_dns_buf_put_uint32 Put uint32 to network order
+ * @param buf DNS buffer structure
+ * @param val uint32 in host order
+ * @return none
+ */
+void dap_dns_buf_put_uint32(dap_dns_buf_t *buf, uint32_t val)
+{
+    dap_dns_buf_put_uint16(buf, val >> 16);
+    dap_dns_buf_put_uint16(buf, val);
+}
+
+/**
+ * @brief dap_dns_buf_put_uint64 Put uint64 to network order
+ * @param buf DNS buffer structure
+ * @param val uint64 in host order
+ * @return none
+ */
+void dap_dns_buf_put_uint64(dap_dns_buf_t *buf, uint64_t val)
+{
+    dap_dns_buf_put_uint32(buf, val >> 32);
+    dap_dns_buf_put_uint32(buf, val);
+}
diff --git a/net/server/dns_server/dap_dns_server.c b/net/server/dns_server/dap_dns_server.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ca786ff6847b9f2b50e6d2c52920f1f0d6e32e8
--- /dev/null
+++ b/net/server/dns_server/dap_dns_server.c
@@ -0,0 +1,269 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2017-2020
+ * All rights reserved.
+
+ This file is part of DAP (Distributed Applications Platform) the open source project
+
+    DAP (Distributed Applications Platform) is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DAP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include "dap_dns_client.h"
+#include "dap_dns_server.h"
+#include "dap_events_socket.h"
+#include "dap_common.h"
+#include "dap_string.h"
+#include "dap_client.h"
+
+#define LOG_TAG "dap_chain_node_dns_server"
+#define BUF_SIZE 1024
+
+static dap_dns_server_t *s_dns_server;
+static char s_root_alias[] = "dnsroot";
+
+
+/**
+ * @brief dap_dns_zone_register Register DNS zone and set callback to handle it
+ * @param zone Name of zone to register
+ * @param callback Callback to handle DNS zone
+ * @return 0 if success, else return error code
+ */
+int dap_dns_zone_register(char *zone, dap_dns_zone_callback_t callback) {
+    dap_dns_zone_hash_t *new_zone = NULL;
+    HASH_FIND_STR(s_dns_server->hash_table, zone, new_zone);
+    if (new_zone == NULL) {      // zone is not present
+      DAP_NEW_Z_RET_VAL(new_zone, dap_dns_zone_hash_t, DNS_ERROR_FAILURE, NULL);
+      new_zone->zone = dap_strdup(zone);
+      HASH_ADD_KEYPTR(hh, s_dns_server->hash_table, new_zone->zone, strlen(new_zone->zone), new_zone);
+    }                           // if zone present, just reassign callback
+    new_zone->callback = callback;
+    return DNS_ERROR_NONE;
+}
+
+/**
+ * @brief dap_dns_zone_unregister Unregister DNS zone
+ * @param zone Name of zone to unregister
+ * @return 0 if success, else return error code
+ */
+int dap_dns_zone_unregister(char *zone) {
+    dap_dns_zone_hash_t *asked_zone = NULL;
+    HASH_FIND_STR(s_dns_server->hash_table, zone, asked_zone);
+    if (asked_zone == NULL) {
+        return DNS_ERROR_NAME;
+    }
+    HASH_DEL(s_dns_server->hash_table, asked_zone);
+    DAP_DELETE(asked_zone->zone);
+    DAP_DELETE(asked_zone);
+    return DNS_ERROR_NONE;
+}
+
+/**
+ * @brief dap_dns_zone_find Find callback to registered DNS zone
+ * @param hostname Name of host for which the zone callback being searched
+ * @return Callback for registered DNS zone, else return NULL
+ */
+dap_dns_zone_callback_t dap_dns_zone_find(char *hostname) {
+    dap_dns_zone_hash_t *asked_zone = NULL;
+    HASH_FIND_STR(s_dns_server->hash_table, hostname, asked_zone);
+    if (asked_zone == NULL) {
+        if (!strcmp(hostname, &s_root_alias[0])) {
+            return NULL;
+        }
+        char *zone_up = strchr(hostname, '.');
+        if (zone_up++ == NULL) {
+            zone_up = &s_root_alias[0];
+        }
+        return dap_dns_zone_find(zone_up);
+    } else {
+        return asked_zone->callback;
+    }
+    return NULL;
+}
+
+/**
+ * @brief dap_dns_client_read Read and parse incoming DNS message, send reply to it
+ * @param client DAP client remote structure
+ * @param arg Unused
+ * @return none
+ */
+void dap_dns_client_read(dap_events_socket_t *a_es, UNUSED_ARG void *a_arg) {
+// sanity check
+    dap_return_if_pass(!a_es || a_es->buf_in_size < DNS_HEADER_SIZE);  // Bad request
+// memory alloc
+    int block_len = DNS_HEADER_SIZE;
+    dap_dns_buf_t *dns_message = NULL;
+    dap_dns_buf_t *dns_reply = NULL;
+    DAP_NEW_Z_RET(dns_message, dap_dns_buf_t, NULL);
+    DAP_NEW_Z_RET(dns_reply, dap_dns_buf_t, dns_message);
+    DAP_NEW_Z_SIZE_RET(dns_message->data, char, a_es->buf_in_size + 1, dns_message, dns_reply);
+    DAP_NEW_Z_SIZE_RET(dns_reply->data, char, block_len, dns_message->data, dns_message, dns_reply);
+// func work
+    dns_message->data[a_es->buf_in_size] = 0;
+    dap_events_socket_pop_from_buf_in(a_es, dns_message->data, a_es->buf_in_size);
+    dns_message->size = 0;
+
+    // Parse incoming DNS message
+    dns_reply->size = 0;
+    uint16_t val = dap_dns_buf_get_uint16(dns_message); // ID
+    dap_dns_buf_put_uint16(dns_reply, val);
+    val = dap_dns_buf_get_uint16(dns_message);          // Flags
+    dns_reply->size += sizeof(uint16_t);                 // Put flags later
+    dap_dns_message_flags_t msg_flags;
+    msg_flags.val = val;
+    dap_dns_message_flags_bits_t *flags = &msg_flags.flags;
+    if (flags->qr) {                                     // It's not request
+        goto cleanup;
+    }
+    flags->rcode = DNS_ERROR_NONE;
+    flags->qr = 1;                                       // Response bit set
+    if (flags->tc) {                                     // Truncated messages not supported yet
+        flags->rcode = DNS_ERROR_NOT_SUPPORTED;
+    }
+    flags->ra = 0;                                       // Recursion not supported yet
+    flags->aa = 1;                                       // Authoritative answer
+    uint16_t qdcount = dap_dns_buf_get_uint16(dns_message);
+    dap_dns_buf_put_uint16(dns_reply, qdcount);
+    val = dap_dns_buf_get_uint16(dns_message);          // AN count
+    if (val) {                                          // No other sections should present
+        goto cleanup;
+    }
+    dap_dns_buf_put_uint16(dns_reply, 1);               // 1 answer section
+    val = dap_dns_buf_get_uint16(dns_message);          // NS count
+    if (val) {                                          // No other sections should present
+        goto cleanup;
+    }
+    dap_dns_buf_put_uint16(dns_reply, val);
+    val = dap_dns_buf_get_uint16(dns_message);          // AR count
+    if (val) {                                          // No other sections should present
+        goto cleanup;
+    }
+    dap_dns_buf_put_uint16(dns_reply, 1);               // 1 aditional section
+    int dot_count = 0;
+    dap_string_t *dns_hostname = dap_string_new("");
+    for (int i = 0; i < qdcount; i++) {
+        block_len = strlen(&dns_message->data[dns_message->size]) + 1 + 2 * sizeof(uint16_t);
+        dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->size + block_len);
+        memcpy(&dns_reply->data[dns_reply->size], &dns_message->data[dns_message->size], block_len);
+        dns_reply->size += block_len;
+        if (flags->rcode)
+            break;
+        while (dns_message->size < dns_reply->size - 2 * sizeof(uint16_t)) {
+            uint8_t len = dns_message->data[dns_message->size++];
+            if (len > DNS_MAX_DOMAIN_NAME_LEN) {
+                flags->rcode = DNS_ERROR_NAME;
+                break;
+            }
+            if (!len) {
+                break;
+            }
+            if (dot_count) {
+                if (dot_count > 3) {                    // Max three dots allowed
+                    flags->rcode = DNS_ERROR_NAME;
+                    break;
+                }
+                dap_string_append(dns_hostname, ".");
+            }
+            dap_string_append_len(dns_hostname, &dns_message->data[dns_message->size], len);
+            dns_message->size += len;
+            dot_count++;
+            if (dns_hostname->len >= DNS_MAX_HOSTNAME_LEN) {
+                flags->rcode = DNS_ERROR_NAME;
+                break;
+            }
+        }
+        val = dap_dns_buf_get_uint16(dns_message);      // DNS record type
+        if (val != DNS_RECORD_TYPE_A) {                 // Only host address ipv4
+            flags->rcode = DNS_ERROR_NOT_SUPPORTED;
+            break;
+        }
+        val = dap_dns_buf_get_uint16(dns_message);      // DNS class type
+        if (val != DNS_CLASS_TYPE_IN) {                 // Internet only
+            flags->rcode = DNS_ERROR_NOT_SUPPORTED;
+            break;
+        }
+        if (dns_message->size != dns_reply->size) {
+            log_it(L_ERROR, "DNS parser pointer unequal, mptr = %u, rptr = %u", dns_message->size, dns_reply->size);
+        }
+    }
+    // Find link info
+    dap_link_info_t *l_link_info = NULL;
+    if (flags->rcode == DNS_ERROR_NONE) {
+        dap_dns_zone_callback_t callback = dap_dns_zone_find(dns_hostname->str);
+        if (callback) {
+            l_link_info = callback(dns_hostname->str);
+        }
+    }
+    if (l_link_info) {
+        // Compose DNS answer
+        block_len = DNS_ANSWER_SIZE + sizeof(dap_link_info_t);
+        dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->size + block_len);
+        val = 0xc000 | DNS_HEADER_SIZE;                // Link to host name
+        dap_dns_buf_put_uint16(dns_reply, val);
+        val = DNS_RECORD_TYPE_TXT;
+        dap_dns_buf_put_uint16(dns_reply, val);
+        val = DNS_CLASS_TYPE_IN;
+        dap_dns_buf_put_uint16(dns_reply, val);
+        uint32_t ttl = DNS_TIME_TO_LIVE;
+        dap_dns_buf_put_uint32(dns_reply, ttl);
+        val = sizeof(dap_link_info_t);
+        memcpy(dns_reply->data + dns_reply->size, l_link_info, sizeof(dap_link_info_t));
+        DAP_DELETE(l_link_info);
+    } else if (flags->rcode == DNS_ERROR_NONE) {
+        flags->rcode = DNS_ERROR_NAME;
+    }
+    if (flags->rcode) {
+        dns_reply->data[7] = 0;                         // No answer section
+    }
+    // Set reply flags
+    dns_reply->data[2] = msg_flags.val >> 8;
+    dns_reply->data[3] = msg_flags.val;
+    // Send DNS reply
+    dap_events_socket_write_unsafe(a_es, dns_reply->data, dns_reply->size);
+    dap_string_free(dns_hostname, true);
+cleanup:
+    DAP_DEL_MULTY(dns_reply->data, dns_message->data, dns_reply, dns_message);
+    return;
+}
+
+void dap_dns_server_start(const char *a_cfg_section)
+{
+    DAP_NEW_Z_RET(s_dns_server, dap_dns_server_t, NULL);
+    dap_events_socket_callbacks_t l_cb = { .read_callback = dap_dns_client_read };
+    s_dns_server->instance = dap_server_new(a_cfg_section, NULL, &l_cb);
+    if (!s_dns_server->instance) {
+        log_it(L_ERROR, "Can't start DNS server");
+        DAP_DELETE(s_dns_server);
+        return;
+    }
+    log_it(L_NOTICE,"DNS server started");
+}
+
+void dap_dns_server_stop() {
+    if(!s_dns_server)
+        return;
+
+    dap_dns_zone_hash_t *current_zone, *tmp;
+    HASH_ITER(hh, s_dns_server->hash_table, current_zone, tmp) {
+        // Clang bug at this, current_zone should change at every loop cycle
+        HASH_DEL(s_dns_server->hash_table, current_zone);
+        DAP_DELETE(current_zone->zone);
+        DAP_DELETE(current_zone);
+    }
+    dap_server_delete(s_dns_server->instance);
+    DAP_DELETE(s_dns_server);
+}
diff --git a/net/server/dns_server/include/dap_dns_client.h b/net/server/dns_server/include/dap_dns_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..6381229fb9935a632e7da15327cee0b7aa53d36d
--- /dev/null
+++ b/net/server/dns_server/include/dap_dns_client.h
@@ -0,0 +1,53 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * Dmitriy Gerasimov <dmitriy.gerasmiov@demlabs.net>
+ * DeM Labs Ltd   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2021
+ * All rights reserved.
+
+ This file is part of DapChain SDK the open source project
+
+    DapChain SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DapChain SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DapChain SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include <stdint.h>
+#include "dap_worker.h"
+#include "dap_net.h"
+
+#define DNS_LISTEN_PORT 53      // UDP
+#define DNS_LISTEN_PORT_STR "53"      // UDP
+#define DNS_REQUEST_SIZE 16
+
+typedef struct _dap_dns_buf_t {
+    char *data;
+    uint32_t size;
+} dap_dns_buf_t;
+
+// node info request callbacks
+typedef void (*dap_dns_client_node_info_request_success_callback_t) (dap_worker_t *a_worker, dap_net_links_t *a_result, void *a_arg);
+typedef void (*dap_dns_client_node_info_request_error_callback_t) (dap_worker_t *a_worker, void *a_arg, int a_errno);
+
+int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_addr, uint16_t a_port, char *a_name,
+                           dap_dns_client_node_info_request_success_callback_t a_callback_success,
+                           dap_dns_client_node_info_request_error_callback_t a_callback_error, void * a_callback_arg);
+
+void dap_dns_buf_init(dap_dns_buf_t *buf, char *msg);
+void dap_dns_buf_put_uint64(dap_dns_buf_t *buf, uint64_t val);
+void dap_dns_buf_put_uint32(dap_dns_buf_t *buf, uint32_t val);
+void dap_dns_buf_put_uint16(dap_dns_buf_t *buf, uint16_t val);
+uint16_t dap_dns_buf_get_uint16(dap_dns_buf_t *buf);
diff --git a/net/server/dns_server/include/dap_dns_server.h b/net/server/dns_server/include/dap_dns_server.h
new file mode 100644
index 0000000000000000000000000000000000000000..2fb7ea1ebf4eb1e32db1f5629ac3ad5b50ce1883
--- /dev/null
+++ b/net/server/dns_server/include/dap_dns_server.h
@@ -0,0 +1,124 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * Dmitriy Gerasimov <dmitriy.gerasmiov@demlabs.net>
+ * DeM Labs Ltd   https://demlabs.net
+ * DeM Labs Open source community https://gitlab.demlabs.net
+ * Copyright  (c) 2021
+ * All rights reserved.
+
+ This file is part of DapChain SDK the open source project
+
+    DapChain SDK is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    DapChain SDK is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with any DapChain SDK based project.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#ifdef _WIN32
+#include <pthread.h>
+#endif
+#include "dap_server.h"
+#include "uthash.h"
+#include "dap_client.h"
+
+#define DNS_TIME_TO_LIVE 600    // Seconds
+#define DNS_HEADER_SIZE 12
+#define DNS_ANSWER_SIZE 10
+#define DNS_MAX_HOSTNAME_LEN 255
+#define DNS_MAX_DOMAIN_NAME_LEN 63
+
+typedef enum _dap_dns_query_type_t {
+    DNS_QUERY_TYPE_STANDARD,
+    DNS_QUERY_TYPE_INVERSE,
+    DNS_QUERY_TYPE_STATUS
+} dap_dns_query_type_t;
+
+typedef enum _dap_dns_error_t {
+    DNS_ERROR_NONE,         // No error
+    DNS_ERROR_FORMAT,       // DNS message parsing error
+    DNS_ERROR_FAILURE,      // Internal server error
+    DNS_ERROR_NAME,         // Only for authoritative servers. Name does not exist
+    DNS_ERROR_NOT_SUPPORTED,// This kind of query not implemented
+    DNS_ERROR_REFUSED       // Operation refused
+} dap_dns_error_t;
+
+typedef enum _dap_dns_record_type_t {
+    DNS_RECORD_TYPE_A = 1,  // Host address
+    DNS_RECORD_TYPE_NS,     // Authoritative name server
+    DNS_RECORD_TYPE_MD,     // Mail destination (obsolete, use MX)
+    DNS_RECORD_TYPE_MF,     // Mail forwarder (obsolete, use MX)
+    DNS_RECORD_TYPE_CNAME,  // Canonical name of alias
+    DNS_RECORD_TYPE_SOA,    // Marks a start of a zone of authority
+    DNS_RECORD_TYPE_MB,     // Mailbox domain name (experimental)
+    DNS_RECORD_TYPE_MG,     // Mail group member (experimental)
+    DNS_RECORD_TYPE_MR,     // Mail rename domain name (experimental)
+    DNS_RECORD_TYPE_NULL,   // NULL resource record (experimental)
+    DNS_RECORD_TYPE_WKS,    // Well known services description
+    DNS_RECORD_TYPE_PTR,    // Domain name pointer
+    DNS_RECORD_TYPE_HINFO,  // Host information
+    DNS_RECORD_TYPE_MINFO,  // Mail box or list information
+    DNS_RECORD_TYPE_MX,     // Mail exchange
+    DNS_RECORD_TYPE_TXT,    // Text strings
+    DNS_RECORD_TYPE_RP,     // Responsible person
+    DNS_RECORD_TYPE_AXFR = 252, // A request for a transfer of an entire zone - QTYPE only
+    DNS_RECORD_TYPE_MAILB,  // A request for mailbox-related records (MB, MG or MR) - QTYPE only
+    DNS_RECORD_TYPE_MAILA,  // A request for mail agent RRs (obsolete - see MX) - QTYPE only
+    DNS_RECORD_TYPE_ANY     // A request for all records - QTYPE only
+} dap_dns_record_type_t;
+
+typedef enum _dap_dns_class_type_t {
+    DNS_CLASS_TYPE_IN = 1,  // Internet
+    DNS_CLASS_TYPE_CS,      // CSNET (obsolete)
+    DNS_CLASS_TYPE_CH,      // CHAOS
+    DNS_CLASS_TYPE_HS,      // Hesiod [Dyer 87]
+    DNS_CLASS_TYPE_ANY = 255    // Any class
+} dap_dns_class_type_t;
+
+typedef struct _dap_dns_message_flags_bits_t {
+    int rcode : 4;          // response code, answer only: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not supported, 5 - refused
+    int z : 3;              // reserved, must be zero
+    int ra : 1;             // 1 - recursion available (answer only)
+    int rd : 1;             // 1 - recursion desired (query set, copied to answer)
+    int tc : 1;             // 1 - message truncated
+    int aa : 1;             // 1 - authoritative answer (answer only)
+    int opcode : 4;         // type of query, copied to answer: 0 - standard, 1 - inverse, 2 - status, 3-15 - reserved
+    int qr : 1;             // 0 - query, 1 - response
+} dap_dns_message_flags_bits_t;
+
+
+typedef union _dap_dns_message_flags_t {
+    dap_dns_message_flags_bits_t flags;
+    int val;
+} dap_dns_message_flags_t;
+
+typedef dap_link_info_t *(*dap_dns_zone_callback_t) (const char *zonename); // Callback for DNS zone operations
+
+typedef struct _dap_dns_zone_hash_t {
+    char *zone;
+    dap_dns_zone_callback_t callback;
+    UT_hash_handle hh;
+} dap_dns_zone_hash_t;
+
+typedef struct _dap_dns_server_t {
+    dap_server_t *instance;
+    dap_dns_zone_hash_t *hash_table;
+} dap_dns_server_t;
+
+
+
+void dap_dns_server_start(const char* a_cfg_section);
+void dap_dns_server_stop();
+int dap_dns_zone_register(char *zone, dap_dns_zone_callback_t callback);
+int dap_dns_zone_unregister(char *zone);
+