33static uint16_t id = 1 ;
44uint16_t dns_query_port = 0 ;
55static struct hashmap * dns_replies = NULL ;
6+ static struct hashmap * dns_cache = NULL ;
67
78void dns_result_ready (dns_header_t * header , dns_request_t * request , unsigned length , char * * error , char * res , uint8_t * outlength );
89uint8_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+
495532void 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