Skip to content

Commit 0d9b8c4

Browse files
much tidier dns frontend
1 parent 3fa174c commit 0d9b8c4

3 files changed

Lines changed: 91 additions & 50 deletions

File tree

include/dns.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
#define FLAGS_MASK_Z 0x70
2323
#define FLAGS_MASK_RA 0x80
2424

25+
/**
26+
* Returned by dns_lookup_host_async() if the result is immediately
27+
* available in the ip parameter, and the ip parameter was non-NULL.
28+
*/
29+
#define DNS_RESULT_CACHED 0xFFFFFFFF
30+
2531
enum query_type_t {
2632
/** Uninitialized Query */
2733
DNS_QUERY_NONE = 0,
@@ -40,16 +46,6 @@ enum query_type_t {
4046
DNS_QUERY_PTR6 = 0xFFFE
4147
};
4248

43-
/** Represents a dns resource record (rr)
44-
*/
45-
struct ResourceRecord
46-
{
47-
uint8_t type; /* Record type */
48-
uint32_t rr_class; /* Record class */
49-
uint32_t ttl; /* Time to live */
50-
uint32_t rdlength; /* Record length */
51-
};
52-
5349
/** Represents a dns request/reply header, and its payload as opaque data.
5450
*/
5551
typedef struct dns_header {
@@ -80,6 +76,11 @@ typedef struct dns_request {
8076
dns_reply_callback_ptr callback_ptr; /* For later */
8177
} dns_request_t;
8278

79+
typedef struct dns_cache_entry_t {
80+
const char* host;
81+
const char* result;
82+
} dns_cache_entry_t;
83+
8384
typedef struct resource_record {
8485
uint16_t type; /* Record type */
8586
uint16_t rr_class; /* Record class */
@@ -100,11 +101,11 @@ struct dns_result_t {
100101
*
101102
* @param resolver_ip The IP of the resolver to use, in network byte order
102103
* @param hostname Host address to resolve
103-
* @param timeout Timeout in seconds
104+
* @param timeout_ms Timeout in millisseconds
104105
* @return uint32_t Resolved IP address. On error or timeout, the return value is 0,
105106
* which translates to 0.0.0.0.
106107
*/
107-
uint32_t dns_lookup_host(uint32_t resolver_ip, const char* hostname, uint32_t timeout);
108+
uint32_t dns_lookup_host(uint32_t resolver_ip, const char* hostname, uint32_t timeout_ms);
108109

109110
/**
110111
* @brief Look up an IPV4 hostname to IP address, with timeout
@@ -113,13 +114,15 @@ uint32_t dns_lookup_host(uint32_t resolver_ip, const char* hostname, uint32_t ti
113114
*
114115
* @param resolver_ip The IP of the resolver to use, in network byte order
115116
* @param hostname Host address to resolve
116-
* @param timeout Timeout in seconds
117+
* @param ip Pointer to uint32_t IP address to immediately return if the result is cached
117118
* @param dns_reply_callback_a Callback to receive the resolved IP address.
118119
* If an error occured during resolution, the received IP address will be 0,
119120
* which is a representation of 0.0.0.0.
120-
* @return uint16_t Request ID that was submitted, or 0 on error
121+
* @return uint16_t Request ID that was submitted, or 0 on error.
122+
* a special value DNS_RESULT_CACHED (0xffffffff) is returned if the result was immediately
123+
* filled from the DNS cache.
121124
*/
122-
uint16_t dns_lookup_host_async(uint32_t resolver_ip, const char* hostname, uint32_t timeout, dns_reply_callback_a callback);
125+
uint32_t dns_lookup_host_async(uint32_t resolver_ip, const char* hostname, uint32_t* ip, dns_reply_callback_a callback);
123126

124127
/**
125128
* @brief Initialise DNS protocol.

src/basic/sockets.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ char* basic_dns(struct basic_ctx* ctx)
188188
PARAMS_GET_ITEM(BIP_STRING);
189189
PARAMS_END("DNS$","");
190190
char ip[16] = { 0 };
191-
uint32_t addr = dns_lookup_host(getdnsaddr(), strval, 2);
191+
uint32_t addr = dns_lookup_host(getdnsaddr(), strval, 2000);
192192
get_ip_str(ip, (uint8_t*)&addr);
193193
return gc_strdup(ip);
194194
}

src/net/dns.c

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
static uint16_t id = 1;
44
uint16_t dns_query_port = 0;
55
static struct hashmap* dns_replies = NULL;
6+
static struct hashmap* dns_cache = NULL;
67

78
void dns_result_ready(dns_header_t* header, dns_request_t* request, unsigned length, char** error, char* res, uint8_t* outlength);
89
uint8_t dns_collect_request(uint16_t id, char* result, size_t max);
@@ -21,6 +22,12 @@ static int dns_request_compare(const void *a, const void *b, [[maybe_unused]] vo
2122
return fa->id == fb->id ? 0 : (fa->id < fb->id ? -1 : 1);
2223
}
2324

25+
static int dns_cache_compare(const void *a, const void *b, [[maybe_unused]] void *udata) {
26+
const dns_cache_entry_t* fa = a;
27+
const dns_cache_entry_t* fb = b;
28+
return strcmp(fa->host, fb->host);
29+
}
30+
2431
/**
2532
* @brief Hash two DNS requests by ID
2633
*
@@ -34,6 +41,15 @@ static uint64_t dns_request_hash(const void *item, uint64_t seed0, uint64_t seed
3441
return (uint64_t)header->id * seed0 * seed1;
3542
}
3643

44+
static uint64_t dns_cache_hash(const void *item, uint64_t seed0, uint64_t seed1) {
45+
const dns_cache_entry_t* header = item;
46+
uint64_t seed = 0, pos = 0;
47+
for (const char* x = header->host; *x; ++x) {
48+
seed += *x * pos++;
49+
}
50+
return (uint64_t)seed * seed0 * seed1;
51+
}
52+
3753
/**
3854
* @brief Convert a packet to a buffer
3955
*
@@ -102,7 +118,7 @@ static int dns_send_request(const char * const name, uint32_t resolver_ip, dns_r
102118

103119
/**
104120
* @brief Build a binary payload for a request for a specific type of DNS entry
105-
*
121+
*
106122
* @param name name to resolve. Even reverse DNS uses these label-separated names
107123
* @param rr Resource record - identifies the type of record, e.g. A, AAAA, PTR, CNAME
108124
* @param rr_class Resource record class
@@ -174,14 +190,14 @@ void dns_handle_packet(uint32_t src_ip, uint16_t src_port, uint16_t dst_port, vo
174190
}
175191
} else if (request->callback_aaaa && request->type == DNS_QUERY_AAAA) {
176192
dprintf("Query result AAAA\n");
177-
uint8_t result[16];
193+
uint8_t result[16] = { 0 };
178194
if (dns_collect_request(inbound_id, (char*)&result, 16)) {
179195
dprintf("dns AAAA result collected\n");
180196
request->callback_aaaa(result, (const char*)request->orig, inbound_id);
181197
}
182198
} else if (request->callback_ptr && request->type == DNS_QUERY_PTR4) {
183199
dprintf("Query result PTR4\n");
184-
char result[256];
200+
char result[256] = { 0 };
185201
if (dns_collect_request(inbound_id, (char*)&result, sizeof(result))) {
186202
dprintf("dns PTR4 result collected: %s\n", result);
187203
request->callback_ptr(result, 0, inbound_id);
@@ -399,6 +415,17 @@ uint8_t dns_collect_request(uint16_t id, char* result, size_t max)
399415
if (request && request->result_length != 0) {
400416
uint8_t len = request->result_length;
401417
memcpy(result, request->result, max > request->result_length ? max : request->result_length);
418+
419+
if (request->type == DNS_QUERY_A) {
420+
char ip[16] = { 0 };
421+
get_ip_str(ip, (const uint8_t*)result);
422+
dprintf("Cached result '%s' -> '%s'\n", request->orig, ip);
423+
dns_cache_entry_t cache_entry = {
424+
.host = strdup((const char *) request->orig),
425+
.result = strdup(ip),
426+
};
427+
hashmap_set(dns_cache, &cache_entry);
428+
}
402429
kfree_null(&request->orig);
403430
hashmap_delete(dns_replies, request);
404431
return len;
@@ -423,15 +450,33 @@ void dns_delete_request(uint16_t id)
423450
}
424451
}
425452

426-
uint16_t dns_lookup_host_async(uint32_t resolver_ip, const char* hostname, uint32_t timeout, dns_reply_callback_a callback)
453+
bool is_cached(uint32_t* ip, const char* hostname)
454+
{
455+
if (!ip) {
456+
return false;
457+
}
458+
dns_cache_entry_t find_cache = {
459+
.host = hostname,
460+
};
461+
dns_cache_entry_t* cached = (dns_cache_entry_t*)hashmap_get(dns_cache, &find_cache);
462+
if (cached) {
463+
dprintf("Returned cached DNS %s -> %s\n", hostname, cached->result);
464+
*ip = str_to_ip(cached->result);
465+
return true;
466+
}
467+
*ip = 0;
468+
return false;
469+
}
470+
471+
uint32_t dns_lookup_host_async(uint32_t resolver_ip, const char* hostname, uint32_t* ip, dns_reply_callback_a callback)
427472
{
428473
dns_request_t request;
429474
dns_header_t h;
430475
int length;
431476

432-
if (timeout == 0) {
433-
timeout = 5;
434-
}
477+
if (ip && is_cached(ip, hostname)) {
478+
return DNS_RESULT_CACHED;
479+
};
435480

436481
if ((length = dns_make_payload(hostname, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1) {
437482
return 0;
@@ -447,54 +492,47 @@ uint16_t dns_lookup_host_async(uint32_t resolver_ip, const char* hostname, uint3
447492

448493
dns_send_request(hostname, resolver_ip, &request, &h, length, DNS_QUERY_A);
449494

450-
return ntohs(h.id);
495+
return h.id;
451496

452497
}
453498

454-
uint32_t dns_lookup_host(uint32_t resolver_ip, const char* hostname, uint32_t timeout)
499+
uint32_t dns_blocking_wait_for_result(uint32_t request_id, uint32_t timeout_ms)
455500
{
456-
dns_request_t request;
457-
dns_header_t h;
458-
int length;
459501
uint32_t result = 0;
460-
461-
if (timeout == 0) {
462-
timeout = 5;
502+
if (timeout_ms == 0) {
503+
timeout_ms = 5000;
463504
}
505+
timeout_ms /= 10; // Timer is only 1 centi-second resolution, not 1ms
506+
time_t now = get_ticks();
464507

465-
if ((length = dns_make_payload(hostname, DNS_QUERY_A, 1, (unsigned char*)&h.payload)) == -1) {
466-
return 0;
467-
}
468-
469-
h.flags1 = FLAGS_MASK_RD;
470-
h.flags2 = 0;
471-
h.qdcount = 1;
472-
h.ancount = h.nscount = h.arcount = 0;
473-
request.callback_a = NULL;
474-
request.callback_aaaa = NULL;
475-
request.callback_ptr = NULL;
476-
477-
dns_send_request(hostname, resolver_ip, &request, &h, length, DNS_QUERY_A);
478-
time_t now = time(NULL);
479-
480-
while (!dns_request_is_completed(h.id)) {
508+
while (!dns_request_is_completed(request_id)) {
481509
__asm__ volatile("hlt");
482-
if (time(NULL) - now > timeout) {
510+
if (get_ticks() - now > timeout_ms) {
483511
/* Request timed out */
484-
dns_delete_request(h.id);
512+
dns_delete_request(request_id);
485513
return 0;
486514
}
487515
}
488-
if (dns_collect_request(h.id, (char*)&result, sizeof(uint32_t))) {
516+
if (dns_collect_request(request_id, (char*)&result, sizeof(uint32_t))) {
489517
return result;
490518
}
491519

492520
return 0;
493521
}
494522

523+
uint32_t dns_lookup_host(uint32_t resolver_ip, const char* hostname, uint32_t timeout_ms)
524+
{
525+
uint32_t ip = 0, request_id = dns_lookup_host_async(resolver_ip, hostname, &ip, NULL);
526+
if (request_id == DNS_RESULT_CACHED) {
527+
return ip;
528+
}
529+
return dns_blocking_wait_for_result(request_id, timeout_ms);
530+
}
531+
495532
void init_dns()
496533
{
497534
dns_replies = hashmap_new(sizeof(dns_request_t), 0, 6453563734, 7645356235, dns_request_hash, dns_request_compare, NULL, NULL);
535+
dns_cache = hashmap_new(sizeof(dns_cache_entry_t), 0, 6453563734, 7645356235, dns_cache_hash, dns_cache_compare, NULL, NULL);
498536
/* Let the IP stack decide on the port number to use */
499537
dns_query_port = udp_register_daemon(0, &dns_handle_packet);
500538
if (dns_query_port == 0) {

0 commit comments

Comments
 (0)