Skip to content
Snippets Groups Projects
Commit bc7d3ae4 authored by Roman Khlopkov's avatar Roman Khlopkov 🔜
Browse files

[+] Zone responsibility callbacks added

parent 8a030e58
Branches features-3330
No related tags found
1 merge request!7features-3330
......@@ -22,10 +22,6 @@
along with any DAP based project. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _WIN32
#include <pthread.h>
#endif
#include "dap_dns_server.h"
#include "dap_udp_server.h"
#include "dap_udp_client.h"
......@@ -40,6 +36,9 @@
#define UNUSED(x) (void)(x)
#define LOG_TAG "dap_dns_server"
static dap_dns_server_t *s_dns_server;
static char s_root_alias[] = "dnsroot";
/**
* @brief dap_dns_buf_init Initialize DNS parser buffer
* @param buf DNS buffer structure
......@@ -98,10 +97,68 @@ uint32_t dap_dns_resolve_hostname(char *str) {
dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t *) l_objs[l_node_num].value;
uint32_t addr = l_node_info->hdr.ext_addr_v4.s_addr;
dap_chain_global_db_objs_delete(l_objs, l_nodes_count);
log_it(L_DEBUG, "DNS resolver find ip %d.%d.%d.%d", addr & 0xFF, (addr >> 8) & 0xFF, (addr >> 16) & 0xFF, (addr >> 24) & 0xFF );
log_it(L_DEBUG, "DNS resolver find ip %d.%d.%d.%d", addr & 0xFF, (addr >> 8) & 0xFF, (addr >> 16) & 0xFF, (addr >> 24) & 0xFF);
return addr;
}
/**
* @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;
HASH_FIND_STR(s_dns_server->hash_table, zone, new_zone);
if (new_zone == NULL) { // zone is not present
new_zone = DAP_NEW(dap_dns_zone_hash_t);
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;
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;
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, '.') + 1;
if (zone_up == 1) {
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
......@@ -110,7 +167,6 @@ uint32_t dap_dns_resolve_hostname(char *str) {
*/
void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
UNUSED(arg);
if (client->buf_in_size < DNS_HEADER_SIZE) { // Bad request
return;
}
......@@ -131,17 +187,17 @@ void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
dns_reply->ptr += 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
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->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
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
......@@ -158,58 +214,84 @@ void dap_dns_client_read(dap_client_remote_t *client, void * arg) {
if (val) { // No other sections should present
goto cleanup;
}
dap_dns_buf_put_uint16(dns_reply, val);
dap_dns_buf_put_uint16(dns_reply, val);
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->ptr]) + 1 + 2 * sizeof(uint16_t);
dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->ptr + block_len);
memcpy(&dns_reply->data[dns_reply->ptr], &dns_message->data[dns_message->ptr], block_len);
dns_reply->ptr += block_len;
bool need_dot = false;
while (dns_message->ptr < dns_reply->ptr - 2 * sizeof(uint16_t))
{
if (need_dot) {
dap_string_append(dns_hostname, ".");
dns_reply->ptr += block_len;
if (flags->rcode)
break;
while (dns_message->ptr < dns_reply->ptr - 2 * sizeof(uint16_t)) {
uint8_t len = dns_message->data[dns_message->ptr++];
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, ".");
}
uint8_t len = dns_message->data[dns_message->ptr++];
dap_string_append_len(dns_hostname, &dns_message->data[dns_message->ptr], len);
dns_message->ptr += len;
need_dot = true;
dns_message->ptr += 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;
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;
flags->rcode = DNS_ERROR_NOT_SUPPORTED;
break;
}
if (dns_message->ptr != dns_reply->ptr) {
log_it(L_ERROR, "DNS parser pointer unequal, mptr = %u, rptr = %u", dns_message->ptr, dns_reply->ptr);
}
}
// Compose DNS answer
block_len = DNS_ANSWER_SIZE;
dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->ptr + block_len);
val = 0xc000 || DNS_HEADER_SIZE; // Link to host name
dap_dns_buf_put_uint16(dns_reply, val);
val = DNS_RECORD_TYPE_A;
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 = 4; // RD len for ipv4
dap_dns_buf_put_uint16(dns_reply, val);
}
// Find ip addr
uint32_t ip_addr = 0;
if (flags.rcode == DNS_ERROR_NONE) {
ip_addr = dap_dns_resolve_hostname(dns_hostname->str);
}
dap_dns_buf_put_uint32(dns_reply, ip_addr);
if (flags->rcode == DNS_ERROR_NONE) {
dap_dns_zone_callback_t callback = dap_dns_zone_find(dns_hostname->str);
if (callback) {
ip_addr = callback(dns_hostname->str);
}
}
if (ip_addr) {
// Compose DNS answer
block_len = DNS_ANSWER_SIZE;
dns_reply->data = DAP_REALLOC(dns_reply->data, dns_reply->ptr + block_len);
val = 0xc000 || DNS_HEADER_SIZE; // Link to host name
dap_dns_buf_put_uint16(dns_reply, val);
val = DNS_RECORD_TYPE_A;
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 = 4; // RD len for ipv4
dap_dns_buf_put_uint16(dns_reply, val);
dap_dns_buf_put_uint32(dns_reply, ip_addr);
} 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
msg_flags.flags = flags;
dns_reply->data[2] = msg_flags.val >> 8;
dns_reply->data[3] = msg_flags.val;
// Send DNS reply
......@@ -224,18 +306,25 @@ cleanup:
return;
}
dap_server_t *dap_dns_server_start() {
pthread_t tDNSThread;
dap_server_t *sh = dap_udp_server_listen(DNS_LISTEN_PORT);
sh->client_read_callback = *dap_dns_client_read;
sh->client_write_callback = NULL;
sh->client_new_callback = NULL;
sh->client_delete_callback = NULL;
pthread_create(&tDNSThread, NULL, (void *)dap_udp_server_loop, sh);
return sh;
void dap_dns_server_start() {
s_dns_server = DAP_NEW(dap_dns_server_t);
s_dns_server->hash_table = NULL;
s_dns_server->instance = dap_udp_server_listen(DNS_LISTEN_PORT);
s_dns_server->instance->client_read_callback = *dap_dns_client_read;
s_dns_server->instance->client_write_callback = NULL;
s_dns_server->instance->client_new_callback = NULL;
s_dns_server->instance->client_delete_callback = NULL;
dap_dns_zone_register(&s_root_alias[0], dap_dns_resolve_hostname); // root resolver
pthread_create(&s_dns_server->udp_thread, NULL, (void *)dap_udp_server_loop, s_dns_server->instance);
}
void dap_dns_server_stop(dap_server_t *sh) {
// TODO add deinit code to dac_udp_server
dap_udp_server_delete(sh);
void dap_dns_server_stop() {
dap_dns_zone_hash_t *current_zone, *tmp;
HASH_ITER(hh, s_dns_server->hash_table, current_zone, tmp) {
HASH_DEL(s_dns_server->hash_table, current_zone);
DAP_DELETE(current_zone->zone);
DAP_DELETE(current_zone);
}
// TODO add code to stop udp_thread
dap_udp_server_delete(s_dns_server->instance);
}
......@@ -24,12 +24,18 @@
#pragma once
#ifdef _WIN32
#include <pthread.h>
#endif
#include "dap_server.h"
#include "uthash.h"
#define DNS_LISTEN_PORT 53 // UDP
#define DNS_TIME_TO_LIVE 600 // Seconds
#define DNS_HEADER_SIZE 12
#define DNS_ANSWER_SIZE 16
#define DNS_ANSWER_SIZE 16
#define DNS_MAX_HOSTNAME_LEN 255
#define DNS_MAX_DOMAIN_NAME_LEN 63
typedef enum _dap_dns_query_type_t {
DNS_QUERY_TYPE_STANDARD,
......@@ -41,9 +47,9 @@ 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 nor exist
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 resfused
DNS_ERROR_REFUSED // Operation refused
} dap_dns_error_t;
typedef enum _dap_dns_record_type_t {
......@@ -79,26 +85,41 @@ typedef enum _dap_dns_class_type_t {
} dap_dns_class_type_t;
typedef struct _dap_dns_message_flags_bits_t {
uint16_t id; // message identifier
uint16_t qr : 1; // 0 - query, 1 - response
uint16_t opcode : 4; // type of query, copied to answer: 0 - standard, 1 - inverse, 2 - status, 3-15 - reserved
uint16_t aa : 1; // 1 - authoritative answer (answer only)
uint16_t tc : 1; // 1 - message truncated
uint16_t rd : 1; // 1 - recursion desired (query set, copied to answer)
uint16_t ra : 1; // 1 - recursion available (answer only)
uint16_t z : 3; // reserved, must be zero
uint16_t rcode : 4; // response code, answer only: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not supported, 5 - refused
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 uint32_t (*dap_dns_zone_callback_t) (char *hostname); // Callback for DNS zone operations
typedef union _dap_dns_message_flags_t {
dap_dns_message_flags_bits_t flags;
uint16_t val;
int val;
} dap_dns_message_flags_t;
typedef struct _dap_dns_but_t {
typedef struct _dap_dns_buf_t {
char *data;
uint32_t ptr;
} dap_dns_buf_t;
dap_server_t *dap_dns_server_start();
void dap_dns_server_stop(dap_server_t *sh);
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;
pthread_t udp_thread;
dap_dns_zone_hash_t *hash_table;
} dap_dns_server_t;
void dap_dns_server_start();
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);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment