xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_DNS_Cache.c (revision 2d3f4daa567ffe71aeda2e0f6d0bc02850db0627)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_DNS_Cache.c
30  * @brief File that handles the DNS caching option
31  */
32 
33 /* FreeRTOS+TCP includes. */
34 #include "FreeRTOS_IP.h"
35 #include "FreeRTOS_Sockets.h"
36 #include "FreeRTOS_UDP_IP.h"
37 #include "FreeRTOS_DHCP.h"
38 #include "NetworkBufferManagement.h"
39 #include "NetworkInterface.h"
40 
41 #include "FreeRTOS_DNS_Cache.h"
42 #include "FreeRTOS_DNS_Globals.h"
43 
44 /* Standard includes. */
45 #include <stdint.h>
46 #include <stdio.h>
47 #include <string.h>
48 
49 #if ( ( ipconfigUSE_DNS != 0 ) && ( ipconfigUSE_DNS_CACHE == 1 ) )
50 
51 /*!
52  * @brief DNS cache structure instantiation
53  */
54     static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];
55 
56 /*!
57  * @brief indicates the index of a free entry in the cache structure
58  *        \a  DNSCacheRow_t
59  */
60     static UBaseType_t uxFreeEntry = 0U;
61 
62 /** returns the index of the hostname entry in the dns cache. */
63     static BaseType_t prvFindEntryIndex( const char * pcName,
64                                          const IPv46_Address_t * pxIP,
65                                          UBaseType_t * uxResult );
66 
67 /** get entry at \p index from the cache. */
68     static BaseType_t prvGetCacheIPEntry( UBaseType_t uxIndex,
69                                           IPv46_Address_t * pxIP,
70                                           uint32_t ulCurrentTimeSeconds,
71                                           struct freertos_addrinfo ** ppxAddressInfo );
72 
73 /** update entry at \p index in the cache. */
74     static void prvUpdateCacheEntry( UBaseType_t uxIndex,
75                                      uint32_t ulTTL,
76                                      const IPv46_Address_t * pxIP,
77                                      uint32_t ulCurrentTimeSeconds );
78 
79 /** insert entry in the cache. */
80     static void prvInsertCacheEntry( const char * pcName,
81                                      uint32_t ulTTL,
82                                      const IPv46_Address_t * pxIP,
83                                      uint32_t ulCurrentTimeSeconds );
84 
85 /** Copy DNS cache entries at xIndex to a linked struct addrinfo. */
86     static void prvReadDNSCache( BaseType_t uxIndex,
87                                  struct freertos_addrinfo ** ppxAddressInfo );
88 
89 /*-----------------------------------------------------------*/
90 
91     #if ( ipconfigUSE_IPv4 != 0 )
92 
93 /**
94  * @brief perform a dns lookup in the local cache
95  * @param pcHostName the lookup name
96  * @return ulIPAddress with the value from the cache else returns a zero if the
97  *         cache is not enabled or the lookup is not successful
98  * @post the global structure \a xDNSCache might be modified
99  */
FreeRTOS_dnslookup(const char * pcHostName)100         uint32_t FreeRTOS_dnslookup( const char * pcHostName )
101         {
102             IPv46_Address_t xIPv46_Address;
103 
104 /* Looking up an IPv4 address in the DNS cache. */
105             ( void ) memset( &xIPv46_Address, 0, sizeof( xIPv46_Address ) );
106             ( void ) FreeRTOS_ProcessDNSCache( pcHostName,
107                                                &( xIPv46_Address ),
108                                                0,
109                                                pdTRUE,
110                                                NULL );
111 
112             return xIPv46_Address.xIPAddress.ulIP_IPv4;
113         }
114 /*-----------------------------------------------------------*/
115     #endif /* if ( ipconfigUSE_IPv4 != 0 ) */
116 
117     #if ( ipconfigUSE_IPv6 != 0 )
118 
119 /**
120  * @brief Perform a dns lookup in the local cache (IPv6)
121  * @param pcHostName The lookup name
122  * @param pxAddress_IPv6 The IPv6 address looked up from the cache if the return value is non zero.
123  * @return ulReturn Non zero if name is found in cache else returns a zero if the
124  *         cache is not enabled or the lookup is not successful
125  * @post the global structure \a xDNSCache might be modified
126  */
FreeRTOS_dnslookup6(const char * pcHostName,IPv6_Address_t * pxAddress_IPv6)127         uint32_t FreeRTOS_dnslookup6( const char * pcHostName,
128                                       IPv6_Address_t * pxAddress_IPv6 )
129         {
130             IPv46_Address_t xIPv46_Address;
131             BaseType_t xResult;
132             uint32_t ulReturn = 0U;
133 
134             /* Looking up an IPv6 address in the DNS cache. */
135             ( void ) memset( &xIPv46_Address, 0, sizeof( xIPv46_Address ) );
136             /* Let FreeRTOS_ProcessDNSCache only return IPv6 addresses. */
137             xIPv46_Address.xIs_IPv6 = pdTRUE;
138             xResult = FreeRTOS_ProcessDNSCache( pcHostName, &xIPv46_Address, 0, pdTRUE, NULL );
139 
140             if( xResult != pdFALSE )
141             {
142                 ( void ) memcpy( pxAddress_IPv6->ucBytes, xIPv46_Address.xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
143                 ulReturn = 1U;
144             }
145 
146             return ulReturn;
147         }
148 /*-----------------------------------------------------------*/
149     #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
150 
151 /**
152  * @brief perform a dns update in the local cache
153  * @param pcName the lookup name
154  * @param pxIP the ip value to insert/replace (IPv4/v6)
155  * @param ulTTL Time To live (in seconds)
156  * @param xLookUp Ignored
157  * @param ppxAddressInfo A pointer to a pointer where the find results
158  *                                will be stored.
159  * @return this is a dummy return, we are actually ignoring the return value
160  *         from this function
161  * @post the global structure \a xDNSCache might be modified
162  */
FreeRTOS_dns_update(const char * pcName,IPv46_Address_t * pxIP,uint32_t ulTTL,BaseType_t xLookUp,struct freertos_addrinfo ** ppxAddressInfo)163     BaseType_t FreeRTOS_dns_update( const char * pcName,
164                                     IPv46_Address_t * pxIP,
165                                     uint32_t ulTTL,
166                                     BaseType_t xLookUp,
167                                     struct freertos_addrinfo ** ppxAddressInfo )
168     {
169         /* _HT_ we can as well remove the parameter 'xLookUp'. */
170         ( void ) xLookUp;
171         ( void ) FreeRTOS_ProcessDNSCache( pcName,
172                                            pxIP,
173                                            ulTTL,
174                                            pdFALSE,
175                                            ppxAddressInfo );
176         return pdTRUE;
177     }
178 
179 /**
180  * @brief perform a dns clear in the local cache
181  * @post the global structure \a xDNSCache is modified
182  */
FreeRTOS_dnsclear(void)183     void FreeRTOS_dnsclear( void )
184     {
185         ( void ) memset( xDNSCache, 0x0, sizeof( xDNSCache ) );
186         uxFreeEntry = 0U;
187     }
188 
189 /**
190  * @brief process a DNS Cache request (get, update, or insert)
191  *
192  * @param[in] pcName the name of the host
193  * @param[in,out] pxIP when doing a lookup, will be set, when doing an update,
194  *                       will be read.
195  * @param[in] ulTTL Time To Live (in seconds)
196  * @param[in] xLookUp pdTRUE if a look-up is expected, pdFALSE, when the DNS cache must
197  *                     be updated.
198  * @param[in,out] ppxAddressInfo A pointer to a pointer where the find results
199  *                                will be stored.
200  * @return whether the operation was successful
201  * @post the global structure \a xDNSCache might be modified
202  */
FreeRTOS_ProcessDNSCache(const char * pcName,IPv46_Address_t * pxIP,uint32_t ulTTL,BaseType_t xLookUp,struct freertos_addrinfo ** ppxAddressInfo)203     BaseType_t FreeRTOS_ProcessDNSCache( const char * pcName,
204                                          IPv46_Address_t * pxIP,
205                                          uint32_t ulTTL,
206                                          BaseType_t xLookUp,
207                                          struct freertos_addrinfo ** ppxAddressInfo )
208     {
209         UBaseType_t uxIndex;
210         BaseType_t xResult;
211         /* Get the current time in clock-ticks. */
212         TickType_t xCurrentTickCount = xTaskGetTickCount();
213         /* In milliseconds. */
214         uint32_t ulCurrentTimeSeconds;
215 
216         configASSERT( ( pcName != NULL ) );
217 
218         if( xLookUp != pdFALSE )
219         {
220             pxIP->xIPAddress.ulIP_IPv4 = 0U;
221         }
222 
223         ulCurrentTimeSeconds = ( uint32_t ) ( ( xCurrentTickCount / portTICK_PERIOD_MS ) / 1000U );
224         xResult = prvFindEntryIndex( pcName, pxIP, &uxIndex );
225 
226         if( xResult == pdTRUE )
227         { /* Element found */
228             /* Is this function called for a lookup or to add/update an IP address? */
229             if( xLookUp == pdTRUE )
230             {
231                 /* This statement can only be reached when xResult is true; which
232                  * implies that the entry is present and a 'get' operation will result
233                  * in success. Therefore, it is safe to ignore the return value of the
234                  * below function. */
235                 ( void ) prvGetCacheIPEntry( uxIndex,
236                                              pxIP,
237                                              ulCurrentTimeSeconds,
238                                              ppxAddressInfo );
239             }
240             else
241             {
242                 prvUpdateCacheEntry( uxIndex,
243                                      ulTTL,
244                                      pxIP,
245                                      ulCurrentTimeSeconds );
246             }
247         }
248         else /* Element not Found xResult = pdFALSE */
249         {
250             if( xLookUp == pdTRUE )
251             {
252                 pxIP->xIPAddress.ulIP_IPv4 = 0U;
253             }
254             else
255             {
256                 prvInsertCacheEntry( pcName,
257                                      ulTTL,
258                                      pxIP,
259                                      ulCurrentTimeSeconds );
260             }
261         }
262 
263         #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
264             if( ( xLookUp == pdFALSE ) || ( pxIP->xIPAddress.ulIP_IPv4 != 0U ) )
265             {
266                 char pcAddress[ 40 ];
267                 IP_Address_t xAddress;
268                 BaseType_t xFamily = FREERTOS_AF_INET;
269 
270                 switch( pxIP->xIs_IPv6 )
271                 {
272                     #if ( ipconfigUSE_IPv6 != 0 )
273                         case pdTRUE:
274                             ( void ) memcpy( xAddress.xIP_IPv6.ucBytes, pxIP->xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
275                             xFamily = FREERTOS_AF_INET6;
276                             break;
277                     #endif /* if ( ipconfigUSE_IPv6 != 0 ) */
278 
279                     #if ( ipconfigUSE_IPv4 != 0 )
280                         case pdFALSE:
281                             xAddress.ulIP_IPv4 = pxIP->xIPAddress.ulIP_IPv4;
282                             break;
283                     #endif /* if ( ipconfigUSE_IPv4 != 0 ) */
284 
285                     default:
286                         /* MISRA 16.4 Compliance */
287                         FreeRTOS_debug_printf( ( "FreeRTOS_ProcessDNSCache: Undefined IP Type \n" ) );
288                         break;
289                 }
290 
291                 ( void ) FreeRTOS_inet_ntop( xFamily,
292                                              ( const void * ) xAddress.xIP_IPv6.ucBytes,
293                                              pcAddress,
294                                              ( socklen_t ) sizeof( pcAddress ) );
295                 FreeRTOS_debug_printf( ( "FreeRTOS_ProcessDNSCache: %s: '%s' @ %s (TTL %u)\n",
296                                          ( xLookUp != 0 ) ? "look-up" : "add",
297                                          pcName,
298                                          pcAddress,
299                                          ( unsigned ) FreeRTOS_ntohl( ulTTL ) ) );
300             }
301         #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
302 
303         return xResult;
304     }
305 
306 /**
307  * @brief returns the index of the hostname entry in the dns cache.
308  * @param[in] pcName find it in the cache
309  * @param[in] pxIP ip address
310  * @param [out] uxResult index number
311  * @returns res pdTRUE if index in found else pdFALSE
312  */
prvFindEntryIndex(const char * pcName,const IPv46_Address_t * pxIP,UBaseType_t * uxResult)313     static BaseType_t prvFindEntryIndex( const char * pcName,
314                                          const IPv46_Address_t * pxIP,
315                                          UBaseType_t * uxResult )
316     {
317         BaseType_t xReturn = pdFALSE;
318         UBaseType_t uxIndex;
319 
320         /* For each entry in the DNS cache table. */
321         for( uxIndex = 0; uxIndex < ipconfigDNS_CACHE_ENTRIES; uxIndex++ )
322         {
323             if( xDNSCache[ uxIndex ].pcName[ 0 ] == ( char ) 0 )
324             { /* empty slot */
325                 continue;
326             }
327 
328             if( strcmp( xDNSCache[ uxIndex ].pcName, pcName ) == 0 )
329             { /* hostname found */
330                 /* IPv6 is enabled, See if the cache entry has the correct type. */
331                 if( pxIP->xIs_IPv6 == xDNSCache[ uxIndex ].xAddresses[ 0 ].xIs_IPv6 )
332                 {
333                     xReturn = pdTRUE;
334                     *uxResult = uxIndex;
335                     break;
336                 }
337             }
338         }
339 
340         return xReturn;
341     }
342 /*-----------------------------------------------------------*/
343 
344 /**
345  * @brief get entry at \p index from the cache
346  * @param[in]  uxIndex index in the cache
347  * @param[out] pxIP fill it with the result
348  * @param[in]  ulCurrentTimeSeconds current time
349  * @param[out] ppxAddressInfo Target to store the DNS entries.
350  * @returns    \c pdTRUE if the value is valid \c pdFALSE otherwise
351  * @post the global structure \a xDNSCache might be modified
352  *
353  */
354 
prvGetCacheIPEntry(UBaseType_t uxIndex,IPv46_Address_t * pxIP,uint32_t ulCurrentTimeSeconds,struct freertos_addrinfo ** ppxAddressInfo)355     static BaseType_t prvGetCacheIPEntry( UBaseType_t uxIndex,
356                                           IPv46_Address_t * pxIP,
357                                           uint32_t ulCurrentTimeSeconds,
358                                           struct freertos_addrinfo ** ppxAddressInfo )
359     {
360         BaseType_t isRead;
361         uint32_t ulIPAddressIndex = 0;
362         uint32_t ulAge = ulCurrentTimeSeconds - xDNSCache[ uxIndex ].ulTimeWhenAddedInSeconds;
363 
364         /* Confirm that the record is still fresh.
365          * The field ulTTL was stored as network-endian. */
366         if( ulAge < FreeRTOS_ntohl( xDNSCache[ uxIndex ].ulTTL ) )
367         {
368             #if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
369                 uint8_t ucIndex;
370 
371                 /* The ucCurrentIPAddress value increments without bound and will rollover, */
372                 /*  modulo it by the number of IP addresses to keep it in range.     */
373                 /*  Also perform a final modulo by the max number of IP addresses    */
374                 /*  per DNS cache entry to prevent out-of-bounds access in the event */
375                 /*  that ucNumIPAddresses has been corrupted.                        */
376 
377                 ucIndex = xDNSCache[ uxIndex ].ucCurrentIPAddress % xDNSCache[ uxIndex ].ucNumIPAddresses;
378                 ucIndex = ucIndex % ( uint8_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY;
379                 ulIPAddressIndex = ucIndex;
380 
381                 xDNSCache[ uxIndex ].ucCurrentIPAddress++;
382             #endif /* if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 ) */
383 
384             ( void ) memcpy( pxIP, &( xDNSCache[ uxIndex ].xAddresses[ ulIPAddressIndex ] ), sizeof( *pxIP ) );
385             isRead = pdTRUE;
386 
387             if( ppxAddressInfo != NULL )
388             {
389                 /* Copy all entries from position 'uxIndex' to a linked struct addrinfo. */
390                 prvReadDNSCache( ( BaseType_t ) uxIndex, ppxAddressInfo );
391             }
392         }
393         else
394         {
395             /* Age out the old cached record. */
396             xDNSCache[ uxIndex ].pcName[ 0 ] = ( char ) 0;
397             isRead = pdFALSE;
398         }
399 
400         return isRead;
401     }
402 /*-----------------------------------------------------------*/
403 
404 /**
405  * @brief update entry at \p index in the cache
406  * @param[in] uxIndex index in the cache
407  * @param[in] ulTTL time to live (in seconds)
408  * @param[in] pxIP ip to update the cache with
409  * @param[in] ulCurrentTimeSeconds current time
410  * @post the global structure \a xDNSCache is modified
411  */
prvUpdateCacheEntry(UBaseType_t uxIndex,uint32_t ulTTL,const IPv46_Address_t * pxIP,uint32_t ulCurrentTimeSeconds)412     static void prvUpdateCacheEntry( UBaseType_t uxIndex,
413                                      uint32_t ulTTL,
414                                      const IPv46_Address_t * pxIP,
415                                      uint32_t ulCurrentTimeSeconds )
416     {
417         uint32_t ulIPAddressIndex = 0;
418 
419         #if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
420             if( xDNSCache[ uxIndex ].ucNumIPAddresses <
421                 ( uint8_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY )
422             {
423                 /* If more answers exist than there are IP address storage
424                  * slots they will overwrite entry 0 */
425                 ulIPAddressIndex = xDNSCache[ uxIndex ].ucNumIPAddresses;
426                 xDNSCache[ uxIndex ].ucNumIPAddresses++;
427             }
428         #endif
429         ( void ) memcpy( &( xDNSCache[ uxIndex ].xAddresses[ ulIPAddressIndex ] ), pxIP, sizeof( *pxIP ) );
430         xDNSCache[ uxIndex ].ulTTL = ulTTL;
431         xDNSCache[ uxIndex ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
432     }
433 /*-----------------------------------------------------------*/
434 
435 /**
436  * @brief insert entry in the cache
437  * @param[in] pcName cache entry key
438  * @param[in] ulTTL time to live (in seconds)
439  * @param[in] pxIP ip address
440  * @param[in] ulCurrentTimeSeconds current time
441  * @post the global structure \a xDNSCache is modified
442  */
prvInsertCacheEntry(const char * pcName,uint32_t ulTTL,const IPv46_Address_t * pxIP,uint32_t ulCurrentTimeSeconds)443     static void prvInsertCacheEntry( const char * pcName,
444                                      uint32_t ulTTL,
445                                      const IPv46_Address_t * pxIP,
446                                      uint32_t ulCurrentTimeSeconds )
447     {
448         /* Add or update the item. */
449         if( strlen( pcName ) < ( size_t ) ipconfigDNS_CACHE_NAME_LENGTH )
450         {
451             ( void ) strcpy( xDNSCache[ uxFreeEntry ].pcName, pcName );
452             ( void ) memcpy( &( xDNSCache[ uxFreeEntry ].xAddresses[ 0 ] ), pxIP, sizeof( *pxIP ) );
453 
454 
455             xDNSCache[ uxFreeEntry ].ulTTL = ulTTL;
456             xDNSCache[ uxFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;
457             #if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
458                 xDNSCache[ uxFreeEntry ].ucNumIPAddresses = 1;
459                 xDNSCache[ uxFreeEntry ].ucCurrentIPAddress = 0;
460 
461                 /* Initialize all remaining IP addresses in this entry to 0 */
462                 ( void ) memset( &xDNSCache[ uxFreeEntry ].xAddresses[ 1 ],
463                                  0,
464                                  sizeof( xDNSCache[ uxFreeEntry ].xAddresses[ 1 ] ) *
465                                  ( ( uint32_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY - 1U ) );
466             #endif
467             uxFreeEntry++;
468 
469             if( uxFreeEntry == ipconfigDNS_CACHE_ENTRIES )
470             {
471                 uxFreeEntry = 0;
472             }
473         }
474     }
475 /*-----------------------------------------------------------*/
476 
477 /**
478  * @brief Copy DNS cache entries at uxIndex to a linked struct addrinfo.
479  * @param[in] uxIndex The index from where entries must be copied.
480  * @param[out] ppxAddressInfo Target to store the DNS entries.
481  */
prvReadDNSCache(BaseType_t uxIndex,struct freertos_addrinfo ** ppxAddressInfo)482     static void prvReadDNSCache( BaseType_t uxIndex,
483                                  struct freertos_addrinfo ** ppxAddressInfo )
484     {
485         size_t uxIPAddressIndex;
486         size_t uxNumIPAddresses = 1U;
487         const IPv46_Address_t * pxAddresses;
488         struct freertos_addrinfo * pxNewAddress = NULL;
489         struct freertos_addrinfo ** ppxLastAddress = ppxAddressInfo;
490 
491         #if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
492             uxNumIPAddresses = ( size_t ) xDNSCache[ uxIndex ].ucNumIPAddresses;
493 
494             if( uxNumIPAddresses > ( size_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY )
495             {
496                 /* Make this a configASSERT()? */
497                 uxNumIPAddresses = ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY;
498             }
499         #endif /* ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 ) */
500 
501         for( uxIPAddressIndex = 0; uxIPAddressIndex < uxNumIPAddresses; uxIPAddressIndex++ )
502         {
503             pxAddresses = &( xDNSCache[ uxIndex ].xAddresses[ uxIPAddressIndex ] );
504 
505             switch( pxAddresses->xIs_IPv6 ) /* LCOV_EXCL_BR_LINE - xIs_IPv6 is always either pdFALSE or pdTRUE. */
506             {
507                 #if ( ipconfigUSE_IPv4 != 0 )
508                     case pdFALSE:
509                        {
510                            const uint8_t * ucBytes = ( const uint8_t * ) &( pxAddresses->xIPAddress.ulIP_IPv4 );
511                            pxNewAddress = pxNew_AddrInfo( xDNSCache[ uxIndex ].pcName, FREERTOS_AF_INET4, ucBytes );
512                        }
513                        break;
514                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
515 
516                 #if ( ipconfigUSE_IPv6 != 0 )
517                     case pdTRUE:
518                         pxNewAddress = pxNew_AddrInfo( xDNSCache[ uxIndex ].pcName, FREERTOS_AF_INET6, pxAddresses->xIPAddress.xIP_IPv6.ucBytes );
519                         break;
520                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
521 
522                 default: /* LCOV_EXCL_LINE - xIs_IPv6 is always either pdFALSE or FREERTOS_AF_INET6. */
523                     /* MISRA 16.4 Compliance */
524                     FreeRTOS_debug_printf( ( "prvReadDNSCache: Undefined IP Type \n" ) );
525                     break; /* LCOV_EXCL_LINE - xIs_IPv6 is always either pdFALSE or FREERTOS_AF_INET6. */
526             }
527 
528             if( pxNewAddress == NULL )
529             {
530                 /* Malloc must has failed. */
531                 break;
532             }
533 
534             /* Set either 'ppxAddressInfo' or 'pxNewAddress->ai_next'. */
535             *( ppxLastAddress ) = pxNewAddress;
536 
537             ppxLastAddress = &( pxNewAddress->ai_next );
538         }
539     }
540 /*-----------------------------------------------------------*/
541 
542 /**
543  * @brief Lookup the given hostname in the DNS cache
544  * @param[in] pcHostName THe host name to lookup
545  * @param[in] xFamily IP type FREERTOS_AF_INET6 / FREERTOS_AF_INET4
546  * @param[out] ppxAddressInfo Target to store the DNS entries.
547  * @returns This function returns either a valid IPv4 address, or
548  *                          in case of an IPv6 lookup, it will return a non-zero.
549  */
Prepare_CacheLookup(const char * pcHostName,BaseType_t xFamily,struct freertos_addrinfo ** ppxAddressInfo)550     uint32_t Prepare_CacheLookup( const char * pcHostName,
551                                   BaseType_t xFamily,
552                                   struct freertos_addrinfo ** ppxAddressInfo )
553     {
554         uint32_t ulIPAddress = 0U;
555         IPv46_Address_t xIPv46_Address;
556 
557         switch( xFamily )
558         {
559             #if ( ipconfigUSE_IPv4 != 0 )
560                 case FREERTOS_AF_INET:
561                    {
562                        BaseType_t xFound;
563 
564                        xIPv46_Address.xIs_IPv6 = pdFALSE;
565                        xFound = FreeRTOS_ProcessDNSCache( pcHostName, &( xIPv46_Address ), 0, pdTRUE, ppxAddressInfo );
566 
567                        if( xFound != 0 )
568                        {
569                            if( ( ppxAddressInfo != NULL ) && ( *( ppxAddressInfo ) != NULL ) )
570                            {
571                                const struct freertos_sockaddr * sockaddr = ( *( ppxAddressInfo ) )->ai_addr;
572 
573                                ulIPAddress = sockaddr->sin_address.ulIP_IPv4;
574                            }
575                        }
576                        else
577                        {
578                            /* prvGetHostByName will be called to start a DNS lookup. */
579                        }
580                    }
581                    break;
582             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
583 
584             #if ( ipconfigUSE_IPv6 != 0 )
585                 case FREERTOS_AF_INET6:
586                    {
587                        BaseType_t xFound;
588 
589                        xIPv46_Address.xIs_IPv6 = pdTRUE;
590                        xFound = FreeRTOS_ProcessDNSCache( pcHostName, &( xIPv46_Address ), 0, pdTRUE, ppxAddressInfo );
591 
592                        if( xFound != 0 )
593                        {
594                            if( ( ppxAddressInfo != NULL ) && ( *( ppxAddressInfo ) != NULL ) )
595                            {
596                                /* This function returns either a valid IPv4 address, or
597                                 * in case of an IPv6 lookup, it will return a non-zero */
598                                ulIPAddress = 1U;
599                            }
600                        }
601                        else
602                        {
603                            /* prvGetHostByName will be called to start a DNS lookup. */
604                        }
605                    }
606                    break;
607             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
608 
609             default:
610                 /* MISRA 16.4 Compliance */
611                 FreeRTOS_debug_printf( ( "Prepare_CacheLookup: Undefined xFamily \n" ) );
612                 break;
613         }
614 
615         return ulIPAddress;
616     }
617 /*-----------------------------------------------------------*/
618 
619     #if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 )
620 
621 /**
622  * @brief For debugging only: prints the contents of the DNS cache table.
623  */
vShowDNSCacheTable(void)624         void vShowDNSCacheTable( void )
625         {
626             UBaseType_t xEntry;
627             UBaseType_t xSubEntry;
628 
629             for( xEntry = 0; xEntry < ipconfigDNS_CACHE_ENTRIES; xEntry++ )
630             {
631                 const DNSCacheRow_t * pxRow = &( xDNSCache[ xEntry ] );
632 
633                 if( pxRow->pcName[ 0 ] != ( char ) 0 )
634                 {
635                     FreeRTOS_printf( ( "Entry %2u: %s use %u/%u\n",
636                                        ( unsigned ) xEntry,
637                                        pxRow->pcName,
638                                        ( unsigned ) pxRow->ucCurrentIPAddress,
639                                        ( unsigned ) pxRow->ucNumIPAddresses ) );
640 
641                     for( xSubEntry = 0; xSubEntry < pxRow->ucNumIPAddresses; xSubEntry++ )
642                     {
643                         char pcAddress[ 40 ] = "";
644 
645                         switch( pxRow->xAddresses[ 0 ].xIs_IPv6 )
646                         {
647                             /* The first entry determines the type of row:
648                              * either IPv4 or IPv6. */
649                             #if ( ipconfigUSE_IPv4 != 0 )
650                                 case pdFALSE:
651                                     ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET4,
652                                                                  ( const void * ) &( pxRow->xAddresses[ xSubEntry ].xIPAddress.ulIP_IPv4 ),
653                                                                  pcAddress,
654                                                                  sizeof( pcAddress ) );
655                                     break;
656                             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
657 
658                             #if ( ipconfigUSE_IPv6 != 0 )
659                                 case pdTRUE:
660                                     ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET6,
661                                                                  ( const void * ) pxRow->xAddresses[ xSubEntry ].xIPAddress.xIP_IPv6.ucBytes,
662                                                                  pcAddress,
663                                                                  sizeof( pcAddress ) );
664                                     break;
665                             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
666 
667                             default:
668                                 /* MISRA 16.4 Compliance */
669                                 FreeRTOS_debug_printf( ( "vShowDNSCacheTable: Undefined IP Type \n" ) );
670                                 break;
671                         }
672 
673                         FreeRTOS_printf( ( "      %2u: %s\n",
674                                            ( unsigned ) xSubEntry,
675                                            pcAddress ) );
676                     }
677                 }
678             }
679         }
680     #endif /* if ( ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY > 1 ) */
681     /*-----------------------------------------------------------*/
682 
683 #endif /* if ( ( ipconfigUSE_DNS != 0 ) && ( ipconfigUSE_DNS_CACHE == 1 ) ) */
684