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