dns_cache.c
Go to the documentation of this file.
1 /**
2  * @file dns_cache.c
3  * @brief DNS cache management
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DNS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "dns/dns_cache.h"
37 #include "dns/dns_client.h"
38 #include "mdns/mdns_client.h"
39 #include "netbios/nbns_client.h"
40 #include "llmnr/llmnr_client.h"
41 #include "core/udp.h"
42 #include "debug.h"
43 
44 //Check TCP/IP stack configuration
45 #if (DNS_CLIENT_SUPPORT == ENABLED || MDNS_CLIENT_SUPPORT == ENABLED || \
46  NBNS_CLIENT_SUPPORT == ENABLED || LLMNR_CLIENT_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief DNS cache initialization
51  * @param[in] context Pointer to the TCP/IP stack context
52  * @return Error code
53  **/
54 
56 {
57  //Initialize DNS cache
58  osMemset(context->dnsCache, 0, DNS_CACHE_SIZE * sizeof(DnsCacheEntry));
59 
60  //Successful initialization
61  return NO_ERROR;
62 }
63 
64 
65 /**
66  * @brief Flush DNS cache
67  * @param[in] interface Underlying network interface
68  **/
69 
70 void dnsFlushCache(NetInterface *interface)
71 {
72  uint_t i;
73  NetContext *context;
74  DnsCacheEntry *entry;
75 
76  //Point to the TCP/IP stack context
77  context = interface->netContext;
78 
79  //Go through DNS cache
80  for(i = 0; i < DNS_CACHE_SIZE; i++)
81  {
82  //Point to the current entry
83  entry = &context->dnsCache[i];
84 
85  //Check whether the entry is currently in use
86  if(entry->state != DNS_STATE_NONE)
87  {
88  //Delete DNS entries only for the given network interface
89  if(entry->interface == interface)
90  {
91  dnsDeleteEntry(entry);
92  }
93  }
94  }
95 }
96 
97 
98 /**
99  * @brief Create a new entry in the DNS cache
100  * @param[in] context Pointer to the TCP/IP stack context
101  * @return Pointer to the newly created entry
102  **/
103 
105 {
106  uint_t i;
107  systime_t time;
108  DnsCacheEntry *entry;
109  DnsCacheEntry *oldestEntry;
110 
111  //Get current time
112  time = osGetSystemTime();
113 
114  //Keep track of the oldest entry
115  oldestEntry = &context->dnsCache[0];
116 
117  //Loop through DNS cache entries
118  for(i = 0; i < DNS_CACHE_SIZE; i++)
119  {
120  //Point to the current entry
121  entry = &context->dnsCache[i];
122 
123  //Check whether the entry is currently in use or not
124  if(entry->state == DNS_STATE_NONE)
125  {
126  //Erase contents
127  osMemset(entry, 0, sizeof(DnsCacheEntry));
128  //Return a pointer to the DNS entry
129  return entry;
130  }
131 
132  //Keep track of the oldest entry in the table
133  if((time - entry->timestamp) > (time - oldestEntry->timestamp))
134  {
135  oldestEntry = entry;
136  }
137  }
138 
139  //The oldest entry is removed whenever the table runs out of space
140  dnsDeleteEntry(oldestEntry);
141  //Erase contents
142  osMemset(oldestEntry, 0, sizeof(DnsCacheEntry));
143 
144  //Return a pointer to the DNS entry
145  return oldestEntry;
146 }
147 
148 
149 /**
150  * @brief Delete the specified DNS cache entry
151  * @param[in] entry Pointer to the DNS cache entry to be deleted
152  **/
153 
155 {
156  //Make sure the specified entry is valid
157  if(entry != NULL)
158  {
159  //Name resolution in progress?
160  if(entry->state == DNS_STATE_IN_PROGRESS)
161  {
162  //Unregister UDP callback function
163  if(entry->port != 0)
164  {
165  udpUnregisterRxCallback(entry->interface, entry->port);
166  }
167  }
168 
169  //Delete DNS cache entry
170  entry->state = DNS_STATE_NONE;
171  entry->refCount = 0;
172  }
173 }
174 
175 
176 /**
177  * @brief Search the DNS cache for a given domain name
178  * @param[in] interface Underlying network interface
179  * @param[in] name Domain name
180  * @param[in] type Host type (IPv4 or IPv6)
181  * @param[in] protocol Host name resolution protocol
182  * @return A pointer to the matching DNS entry is returned. NULL is returned
183  * if the specified domain name could not be found in the DNS cache
184  **/
185 
188 {
189  uint_t i;
190  NetContext *context;
191  DnsCacheEntry *entry;
192 
193  //Point to the TCP/IP stack context
194  context = interface->netContext;
195 
196  //Loop through DNS cache entries
197  for(i = 0; i < DNS_CACHE_SIZE; i++)
198  {
199  //Point to the current entry
200  entry = &context->dnsCache[i];
201 
202  //Make sure that the entry is currently in use
203  if(entry->state == DNS_STATE_NONE)
204  continue;
205 
206  //Filter out entries that do not match the specified criteria
207  if(entry->interface != interface)
208  continue;
209  if(entry->type != type && type != HOST_TYPE_ANY)
210  continue;
212  continue;
213 
214  //Does the entry match the specified domain name?
215  if(name == NULL || osStrcasecmp(entry->name, name) == 0)
216  return entry;
217  }
218 
219  //No matching entry in the DNS cache
220  return NULL;
221 }
222 
223 
224 /**
225  * @brief DNS timer handler
226  * @param[in] context Pointer to the TCP/IP stack context
227  *
228  * This routine must be periodically called by the TCP/IP stack to
229  * manage DNS cache
230  *
231  **/
232 
233 void dnsTick(NetContext *context)
234 {
235  error_t error;
236  uint_t i;
237  systime_t time;
238  DnsCacheEntry *entry;
239 
240  //Get current time
241  time = osGetSystemTime();
242 
243  //Go through DNS cache
244  for(i = 0; i < DNS_CACHE_SIZE; i++)
245  {
246  //Point to the current entry
247  entry = &context->dnsCache[i];
248 
249  //Name resolution in progress?
250  if(entry->state == DNS_STATE_IN_PROGRESS)
251  {
252  //The request timed out?
253  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
254  {
255  //Check whether the maximum number of retransmissions has been exceeded
256  if(entry->retransmitCount > 0)
257  {
258 #if (DNS_CLIENT_SUPPORT == ENABLED)
259  //DNS resolver?
260  if(entry->protocol == HOST_NAME_RESOLVER_DNS)
261  {
262  //Retransmit DNS query
263  error = dnsSendQuery(entry);
264  }
265  else
266 #endif
267 #if (MDNS_CLIENT_SUPPORT == ENABLED)
268  //mDNS resolver?
269  if(entry->protocol == HOST_NAME_RESOLVER_MDNS)
270  {
271  //Retransmit mDNS query
272  error = mdnsClientSendQuery(entry);
273  }
274  else
275 #endif
276 #if (NBNS_CLIENT_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
277  //NetBIOS Name Service resolver?
278  if(entry->protocol == HOST_NAME_RESOLVER_NBNS)
279  {
280  //Retransmit NBNS query
281  error = nbnsSendQuery(entry);
282  }
283  else
284 #endif
285 #if (LLMNR_CLIENT_SUPPORT == ENABLED)
286  //LLMNR resolver?
287  if(entry->protocol == HOST_NAME_RESOLVER_LLMNR)
288  {
289  //Retransmit LLMNR query
290  error = llmnrSendQuery(entry);
291  }
292  else
293 #endif
294  //Unknown protocol?
295  {
296  error = ERROR_FAILURE;
297  }
298 
299  //Query message successfully sent?
300  if(!error)
301  {
302  //Save the time at which the query message was sent
303  entry->timestamp = time;
304  //The timeout value is doubled for each subsequent retransmission
305  entry->timeout = MIN(entry->timeout * 2, entry->maxTimeout);
306  //Decrement retransmission counter
307  entry->retransmitCount--;
308  }
309  else
310  {
311  //Unregister UDP callback function
312  if(entry->port != 0)
313  {
314  udpUnregisterRxCallback(entry->interface, entry->port);
315  }
316 
317  //Host name resolution failed
318  entry->state = DNS_STATE_FAILED;
319  }
320  }
321 #if (DNS_CLIENT_SUPPORT == ENABLED)
322  //DNS resolver?
323  else if(entry->protocol == HOST_NAME_RESOLVER_DNS)
324  {
325  //Select the next DNS server
326  dnsSelectNextServer(entry);
327  }
328 #endif
329  else
330  {
331  //Unregister UDP callback function
332  if(entry->port != 0)
333  {
334  udpUnregisterRxCallback(entry->interface, entry->port);
335  }
336 
337  //Host name resolution failed
338  entry->state = DNS_STATE_FAILED;
339  }
340  }
341  }
342  //Name successfully resolved?
343  else if(entry->state == DNS_STATE_RESOLVED)
344  {
345  //Check the lifetime of the current DNS cache entry
346  if(timeCompare(time, entry->timestamp + entry->timeout) >= 0)
347  {
348  //Periodically time out DNS cache entries
349  dnsDeleteEntry(entry);
350  }
351  }
352  }
353 }
354 
355 #endif
error_t dnsSendQuery(DnsCacheEntry *entry)
Send a DNS query message.
Definition: dns_client.c:260
HostType
Host types.
Definition: socket.h:215
HostType type
IPv4 or IPv6 host?
Definition: dns_cache.h:101
#define NetContext
Definition: net.h:36
HostnameResolver
Name resolution protocols.
Definition: socket.h:227
error_t udpUnregisterRxCallback(NetInterface *interface, uint16_t port)
Unregister user callback.
Definition: udp.c:1080
uint8_t protocol
Definition: ipv4.h:353
@ HOST_NAME_RESOLVER_DNS
Definition: socket.h:229
@ HOST_TYPE_ANY
Definition: socket.h:216
error_t llmnrSendQuery(DnsCacheEntry *entry)
Send a LLMNR query message.
Definition: llmnr_client.c:256
systime_t timeout
Retransmission timeout.
Definition: dns_cache.h:110
@ HOST_NAME_RESOLVER_LLMNR
Definition: socket.h:232
uint8_t type
Definition: coap_common.h:176
HostnameResolver protocol
Name resolution protocol.
Definition: dns_cache.h:102
char_t name[]
uint_t refCount
Reference count for the current entry.
Definition: dns_cache.h:100
void dnsFlushCache(NetInterface *interface)
Flush DNS cache.
Definition: dns_cache.c:70
#define timeCompare(t1, t2)
Definition: os_port.h:40
error_t nbnsSendQuery(DnsCacheEntry *entry)
Send a NBNS query message.
Definition: nbns_client.c:237
uint16_t port
Port number used by the resolver.
Definition: dns_cache.h:105
error_t
Error codes.
Definition: error.h:43
char_t name[DNS_MAX_NAME_LEN+1]
Domain name.
Definition: dns_cache.h:107
systime_t timestamp
Timestamp to manage entry lifetime.
Definition: dns_cache.h:109
@ HOST_NAME_RESOLVER_MDNS
Definition: socket.h:230
NBNS client (NetBIOS Name Service)
error_t dnsInit(NetContext *context)
DNS cache initialization.
Definition: dns_cache.c:55
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ DNS_STATE_FAILED
Definition: dns_cache.h:88
#define NetInterface
Definition: net.h:40
DNS cache entry.
Definition: dns_cache.h:98
#define osStrcasecmp(s1, s2)
Definition: os_port.h:189
mDNS client (Multicast DNS)
systime_t maxTimeout
Maximum retransmission timeout.
Definition: dns_cache.h:111
#define MIN(a, b)
Definition: os_port.h:63
void dnsTick(NetContext *context)
DNS timer handler.
Definition: dns_cache.c:233
DNS client (Domain Name System)
DnsCacheEntry * dnsCreateEntry(NetContext *context)
Create a new entry in the DNS cache.
Definition: dns_cache.c:104
uint32_t systime_t
System time.
char char_t
Definition: compiler_port.h:55
LLMNR client (Link-Local Multicast Name Resolution)
DnsCacheEntry * dnsFindEntry(NetInterface *interface, const char_t *name, HostType type, HostnameResolver protocol)
Search the DNS cache for a given domain name.
Definition: dns_cache.c:186
DNS cache management.
uint32_t time
@ HOST_NAME_RESOLVER_ANY
Definition: socket.h:228
@ DNS_STATE_IN_PROGRESS
Definition: dns_cache.h:86
NetInterface * interface
Underlying network interface.
Definition: dns_cache.h:103
#define DNS_CACHE_SIZE
Definition: dns_cache.h:47
@ DNS_STATE_RESOLVED
Definition: dns_cache.h:87
UDP (User Datagram Protocol)
@ HOST_NAME_RESOLVER_NBNS
Definition: socket.h:231
error_t mdnsClientSendQuery(DnsCacheEntry *entry)
Send a mDNS query message.
Definition: mdns_client.c:238
void dnsDeleteEntry(DnsCacheEntry *entry)
Delete the specified DNS cache entry.
Definition: dns_cache.c:154
DnsState state
Entry state.
Definition: dns_cache.h:99
void dnsSelectNextServer(DnsCacheEntry *entry)
Select the next DNS server.
Definition: dns_client.c:633
uint_t retransmitCount
Retransmission counter.
Definition: dns_cache.h:112
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:141
TCP/IP stack core.
@ DNS_STATE_NONE
Definition: dns_cache.h:85
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
systime_t osGetSystemTime(void)
Retrieve system time.