]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c
Fix some build issues in older kernel demo projects.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_DNS.c
index e14e7d21247d78df396f90e9839b5876acd1e36f..894b7240da2ddef9c8c62b6d0c469669e7676d71 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * FreeRTOS+TCP V2.0.3\r
+ * FreeRTOS+TCP V2.0.7\r
  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
  *\r
  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
 #if( ipconfigUSE_DNS != 0 )\r
 \r
 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )\r
-       #define dnsDNS_PORT                                             0x3500u\r
-       #define dnsONE_QUESTION                                 0x0100u\r
-       #define dnsOUTGOING_FLAGS                               0x0001u /* Standard query. */\r
-       #define dnsRX_FLAGS_MASK                                0x0f80u /* The bits of interest in the flags field of incoming DNS messages. */\r
-       #define dnsEXPECTED_RX_FLAGS                    0x0080u /* Should be a response, without any errors. */\r
+       #define dnsDNS_PORT                                             0x3500\r
+       #define dnsONE_QUESTION                                 0x0100\r
+       #define dnsOUTGOING_FLAGS                               0x0001 /* Standard query. */\r
+       #define dnsRX_FLAGS_MASK                                0x0f80 /* The bits of interest in the flags field of incoming DNS messages. */\r
+       #define dnsEXPECTED_RX_FLAGS                    0x0080 /* Should be a response, without any errors. */\r
 #else\r
-       #define dnsDNS_PORT                                             0x0035u\r
-       #define dnsONE_QUESTION                                 0x0001u\r
-       #define dnsOUTGOING_FLAGS                               0x0100u /* Standard query. */\r
-       #define dnsRX_FLAGS_MASK                                0x800fu /* The bits of interest in the flags field of incoming DNS messages. */\r
-       #define dnsEXPECTED_RX_FLAGS                    0x8000u /* Should be a response, without any errors. */\r
+       #define dnsDNS_PORT                                             0x0035\r
+       #define dnsONE_QUESTION                                 0x0001\r
+       #define dnsOUTGOING_FLAGS                               0x0100 /* Standard query. */\r
+       #define dnsRX_FLAGS_MASK                                0x800f /* The bits of interest in the flags field of incoming DNS messages. */\r
+       #define dnsEXPECTED_RX_FLAGS                    0x8000 /* Should be a response, without any errors. */\r
 \r
 #endif /* ipconfigBYTE_ORDER */\r
 \r
@@ -72,29 +72,33 @@ name field is an offset to the string, rather than the string itself. */
 #define dnsNAME_IS_OFFSET                                      ( ( uint8_t ) 0xc0 )\r
 \r
 /* NBNS flags. */\r
-#define dnsNBNS_FLAGS_RESPONSE                         0x8000u\r
-#define dnsNBNS_FLAGS_OPCODE_MASK                      0x7800u\r
-#define dnsNBNS_FLAGS_OPCODE_QUERY                     0x0000u\r
-#define dnsNBNS_FLAGS_OPCODE_REGISTRATION      0x2800u\r
+#define dnsNBNS_FLAGS_RESPONSE                         0x8000\r
+#define dnsNBNS_FLAGS_OPCODE_MASK                      0x7800\r
+#define dnsNBNS_FLAGS_OPCODE_QUERY                     0x0000\r
+#define dnsNBNS_FLAGS_OPCODE_REGISTRATION      0x2800\r
 \r
 /* Host types. */\r
-#define dnsTYPE_A_HOST                                         0x0001u\r
-#define dnsCLASS_IN                                                    0x0001u\r
+#define dnsTYPE_A_HOST                                         0x01\r
+#define dnsCLASS_IN                                                    0x01\r
 \r
 /* LLMNR constants. */\r
-#define dnsLLMNR_TTL_VALUE                                     300000u\r
-#define dnsLLMNR_FLAGS_IS_REPONSE                      0x8000u\r
+#define dnsLLMNR_TTL_VALUE                                     300000\r
+#define dnsLLMNR_FLAGS_IS_REPONSE                      0x8000\r
 \r
 /* NBNS constants. */\r
-#define dnsNBNS_TTL_VALUE                                      3600u /* 1 hour valid */\r
-#define dnsNBNS_TYPE_NET_BIOS                          0x0020u\r
-#define dnsNBNS_CLASS_IN                                       0x0001u\r
-#define dnsNBNS_NAME_FLAGS                                     0x6000u\r
+#define dnsNBNS_TTL_VALUE                                      3600 /* 1 hour valid */\r
+#define dnsNBNS_TYPE_NET_BIOS                          0x0020\r
+#define dnsNBNS_CLASS_IN                                       0x01\r
+#define dnsNBNS_NAME_FLAGS                                     0x6000\r
 #define dnsNBNS_ENCODED_NAME_LENGTH                    32\r
 \r
 /* If the queried NBNS name matches with the device's name,\r
 the query will be responded to with these flags: */\r
-#define dnsNBNS_QUERY_RESPONSE_FLAGS           0x8500u\r
+#define dnsNBNS_QUERY_RESPONSE_FLAGS   ( 0x8500 )\r
+\r
+/* Flag DNS parsing errors in situations where an IPv4 address is the return \r
+type. */\r
+#define dnsPARSE_ERROR                      0UL\r
 \r
 /*\r
  * Create a socket and bind it to the standard DNS port number.  Return the\r
@@ -110,12 +114,12 @@ static size_t prvCreateDNSMessage( uint8_t *pucUDPPayloadBuffer, const char *pcH
 /*\r
  * Simple routine that jumps over the NAME field of a resource record.\r
  */\r
-static uint8_t *prvSkipNameField( uint8_t *pucByte );\r
+static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen );\r
 \r
 /*\r
  * Process a response packet from a DNS server.\r
  */\r
-static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier );\r
+static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier );\r
 \r
 /*\r
  * Prepare and send a message to a DNS server.  'xReadTimeOut_ms' will be passed as\r
@@ -131,18 +135,19 @@ static uint32_t prvGetHostByName( const char *pcHostName, TickType_t xIdentifier
 #endif\r
 \r
 #if( ipconfigUSE_NBNS == 1 )\r
-       static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress );\r
+       static portINLINE void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress );\r
 #endif /* ipconfigUSE_NBNS */\r
 \r
 #if( ipconfigUSE_DNS_CACHE == 1 )\r
-       static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen );\r
-       static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp );\r
+       static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xLen );\r
+       static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp );\r
 \r
        typedef struct xDNS_CACHE_TABLE_ROW\r
        {\r
                uint32_t ulIPAddress;           /* The IP address of an ARP cache entry. */\r
-               char pcName[ipconfigDNS_CACHE_NAME_LENGTH];  /* The name of the host */\r
-               uint8_t ucAge;                          /* A value that is periodically decremented but can also be refreshed by active communication.  The ARP cache entry is removed if the value reaches zero. */\r
+               char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ];  /* The name of the host */\r
+        uint32_t ulTTL; /* Time-to-Live (in seconds) from the DNS server. */\r
+               uint32_t ulTimeWhenAddedInSeconds;\r
        } DNSCacheRow_t;\r
 \r
        static DNSCacheRow_t xDNSCache[ ipconfigDNS_CACHE_ENTRIES ];\r
@@ -180,6 +185,18 @@ struct xDNSTail
 #include "pack_struct_end.h"\r
 typedef struct xDNSTail DNSTail_t;\r
 \r
+/* DNS answer record header. */\r
+#include "pack_struct_start.h"\r
+struct xDNSAnswerRecord\r
+{\r
+    uint16_t usType;\r
+    uint16_t usClass;\r
+    uint32_t ulTTL;\r
+    uint16_t usDataLength;\r
+}\r
+#include "pack_struct_end.h"\r
+typedef struct xDNSAnswerRecord DNSAnswerRecord_t;\r
+\r
 #if( ipconfigUSE_LLMNR == 1 )\r
 \r
        #include "pack_struct_start.h"\r
@@ -239,7 +256,7 @@ typedef struct xDNSTail DNSTail_t;
        uint32_t FreeRTOS_dnslookup( const char *pcHostName )\r
        {\r
        uint32_t ulIPAddress = 0UL;\r
-               prvProcessDNSCache( pcHostName, &ulIPAddress, pdTRUE );\r
+               prvProcessDNSCache( pcHostName, &ulIPAddress, 0, pdTRUE );\r
                return ulIPAddress;\r
        }\r
 #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
@@ -396,64 +413,70 @@ uint32_t FreeRTOS_gethostbyname_a( const char *pcHostName, FOnDNSEvent pCallback
 #endif\r
 {\r
 uint32_t ulIPAddress = 0UL;\r
-static uint16_t usIdentifier = 0u;\r
-TickType_t xReadTimeOut_ms = 1200U;\r
-/* Generate a unique identifier for this query. Keep it in a local variable\r
- as gethostbyname() may be called from different threads */\r
-TickType_t xIdentifier = ( TickType_t )usIdentifier++;\r
-\r
-       /* If the supplied hostname is IP address, convert it to uint32_t\r
-       and return. */\r
-       #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 )\r
-       {\r
-               ulIPAddress = FreeRTOS_inet_addr( pcHostName );\r
-       }\r
-       #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */\r
-\r
-       /* If a DNS cache is used then check the cache before issuing another DNS\r
-       request. */\r
-       #if( ipconfigUSE_DNS_CACHE == 1 )\r
-       {\r
-               if( ulIPAddress == 0UL )\r
-               {\r
-                       ulIPAddress = FreeRTOS_dnslookup( pcHostName );\r
-                       if( ulIPAddress != 0 )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* prvGetHostByName will be called to start a DNS lookup */\r
-                       }\r
-               }\r
-       }\r
-       #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
-\r
-       #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
-       {\r
-               if( pCallback != NULL )\r
-               {\r
-                       if( ulIPAddress == 0UL )\r
-                       {\r
-                               /* The user has provided a callback function, so do not block on recvfrom() */\r
-                               xReadTimeOut_ms  = 0;\r
-                               vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t ) xIdentifier );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The IP address is known, do the call-back now. */\r
-                               pCallback( pcHostName, pvSearchID, ulIPAddress );\r
-                       }\r
-               }\r
-       }\r
-       #endif\r
-\r
-       if( ulIPAddress == 0UL)\r
-       {\r
-               ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );\r
-       }\r
-\r
-       return ulIPAddress;\r
+TickType_t xReadTimeOut_ms = ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME;\r
+TickType_t xIdentifier = 0;\r
+\r
+    /* If the supplied hostname is IP address, convert it to uint32_t\r
+    and return. */\r
+    #if( ipconfigINCLUDE_FULL_INET_ADDR == 1 )\r
+    {\r
+        ulIPAddress = FreeRTOS_inet_addr( pcHostName );\r
+    }\r
+    #endif /* ipconfigINCLUDE_FULL_INET_ADDR == 1 */\r
+\r
+    /* If a DNS cache is used then check the cache before issuing another DNS\r
+    request. */\r
+    #if( ipconfigUSE_DNS_CACHE == 1 )\r
+    {\r
+        if( ulIPAddress == 0UL )\r
+        {\r
+            ulIPAddress = FreeRTOS_dnslookup( pcHostName );\r
+            if( ulIPAddress != 0 )\r
+            {\r
+                FreeRTOS_debug_printf( ( "FreeRTOS_gethostbyname: found '%s' in cache: %lxip\n", pcHostName, ulIPAddress ) );\r
+            }\r
+            else\r
+            {\r
+                /* prvGetHostByName will be called to start a DNS lookup */\r
+            }\r
+        }\r
+    }\r
+    #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
+\r
+    /* Generate a unique identifier. */\r
+    if( 0 == ulIPAddress )\r
+    {\r
+        xIdentifier = ( TickType_t )ipconfigRAND32( );\r
+    }\r
+\r
+    #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
+    {\r
+        if( pCallback != NULL )\r
+        {\r
+            if( ulIPAddress == 0UL )\r
+            {\r
+                /* The user has provided a callback function, so do not block on recvfrom() */\r
+                if( 0 != xIdentifier )\r
+                {\r
+                    xReadTimeOut_ms = 0;\r
+                    vDNSSetCallBack( pcHostName, pvSearchID, pCallback, xTimeout, ( TickType_t )xIdentifier );\r
+                }\r
+            }\r
+            else\r
+            {\r
+                /* The IP address is known, do the call-back now. */\r
+                pCallback( pcHostName, pvSearchID, ulIPAddress );\r
+            }\r
+        }\r
+    }\r
+    #endif\r
+\r
+    if( ulIPAddress == 0UL && 0 != xIdentifier )\r
+    {\r
+        ulIPAddress = prvGetHostByName( pcHostName, xIdentifier, xReadTimeOut_ms );\r
+    }\r
+\r
+    return ulIPAddress;\r
 }\r
 /*-----------------------------------------------------------*/\r
 \r
@@ -467,7 +490,7 @@ uint32_t ulAddressLength = sizeof( struct freertos_sockaddr );
 BaseType_t xAttempt;\r
 int32_t lBytes;\r
 size_t xPayloadLength, xExpectedPayloadLength;\r
-TickType_t xWriteTimeOut_ms = 100U;\r
+TickType_t xWriteTimeOut_ms = ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME;\r
 \r
 #if( ipconfigUSE_LLMNR == 1 )\r
        BaseType_t bHasDot = pdFALSE;\r
@@ -544,7 +567,7 @@ TickType_t xWriteTimeOut_ms = 100U;
                                        if( lBytes > 0 )\r
                                        {\r
                                                /* The reply was received.  Process it. */\r
-                                               ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, xIdentifier );\r
+                                               ulIPAddress = prvParseDNSReply( pucUDPPayloadBuffer, lBytes, xIdentifier );\r
 \r
                                                /* Finished with the buffer.  The zero copy interface\r
                                                is being used, so the buffer must be freed by the\r
@@ -649,33 +672,74 @@ static const DNSMessage_t xDefaultPartDNSHeader =
 \r
 #if( ipconfigUSE_DNS_CACHE == 1 )\r
 \r
-       static uint8_t *prvReadNameField( uint8_t *pucByte, char *pcName, BaseType_t xLen )\r
+       static uint8_t *prvReadNameField( uint8_t *pucByte, size_t xSourceLen, char *pcName, size_t xDestLen )\r
        {\r
-       BaseType_t xNameLen = 0;\r
+       size_t xNameLen = 0;\r
+    BaseType_t xCount;\r
+\r
+        if( 0 == xSourceLen )\r
+        {\r
+            return NULL;\r
+        }\r
+\r
                /* Determine if the name is the fully coded name, or an offset to the name\r
                elsewhere in the message. */\r
                if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )\r
                {\r
                        /* Jump over the two byte offset. */\r
-                       pucByte += sizeof( uint16_t );\r
-\r
+            if( xSourceLen > sizeof( uint16_t ) )\r
+            {\r
+                pucByte += sizeof( uint16_t );\r
+            }\r
+            else\r
+            {\r
+                pucByte = NULL;\r
+            }\r
                }\r
                else\r
                {\r
-                       /* pucByte points to the full name.  Walk over the string. */\r
-                       while( *pucByte != 0x00 )\r
+                       /* pucByte points to the full name. Walk over the string. */\r
+                       while( NULL != pucByte && *pucByte != 0x00 && xSourceLen > 1 )\r
                        {\r
-                               BaseType_t xCount;\r
-                               if( xNameLen && xNameLen < xLen - 1 )\r
-                                       pcName[xNameLen++] = '.';\r
-                               for( xCount = *(pucByte++); xCount--; pucByte++ )\r
+                /* If this is not the first time through the loop, then add a \r
+                separator in the output. */\r
+                if( xNameLen > 0 && xNameLen < xDestLen - 1 )\r
+                {\r
+                    pcName[ xNameLen++ ] = '.';\r
+                }\r
+\r
+                /* Process the first/next sub-string. */\r
+                               for( xCount = *(pucByte++), xSourceLen--;\r
+                     xCount-- && xSourceLen > 1; \r
+                     pucByte++, xSourceLen-- )\r
                                {\r
-                                       if( xNameLen < xLen - 1 )\r
-                                               pcName[xNameLen++] = *( ( char * ) pucByte );\r
+                    if( xNameLen < xDestLen - 1 )\r
+                    {\r
+                        pcName[ xNameLen++ ] = *( ( char * )pucByte );\r
+                    }\r
+                    else\r
+                    {\r
+                        /* DNS name is too big for the provided buffer. */\r
+                        pucByte = NULL;\r
+                        break;\r
+                    }\r
                                }\r
                        }\r
 \r
-                       pucByte++;\r
+            /* Confirm that a fully formed name was found. */\r
+            if( NULL != pucByte )\r
+            {\r
+                if( 0x00 == *pucByte )\r
+                {\r
+                    pucByte++;\r
+                    xSourceLen--;\r
+                    pcName[ xNameLen++ ] = '\0';\r
+                }\r
+                else\r
+                {\r
+                    pucByte = NULL;\r
+                }\r
+            }\r
                }\r
 \r
                return pucByte;\r
@@ -683,27 +747,60 @@ static const DNSMessage_t xDefaultPartDNSHeader =
 #endif /* ipconfigUSE_DNS_CACHE == 1 */\r
 /*-----------------------------------------------------------*/\r
 \r
-static uint8_t *prvSkipNameField( uint8_t *pucByte )\r
+static uint8_t *prvSkipNameField( uint8_t *pucByte, size_t xSourceLen )\r
 {\r
-       /* Determine if the name is the fully coded name, or an offset to the name\r
+    size_t xChunkLength;\r
+\r
+    if( 0 == xSourceLen )\r
+    {\r
+        return NULL;\r
+    }\r
+\r
+    /* Determine if the name is the fully coded name, or an offset to the name\r
        elsewhere in the message. */\r
        if( ( *pucByte & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET )\r
        {\r
                /* Jump over the two byte offset. */\r
-               pucByte += sizeof( uint16_t );\r
-\r
+        if( xSourceLen > sizeof( uint16_t ) )\r
+        {\r
+            pucByte += sizeof( uint16_t );\r
+        }\r
+        else\r
+        {\r
+            pucByte = NULL;\r
+        }\r
        }\r
        else\r
        {\r
-               /* pucByte points to the full name.  Walk over the string. */\r
-               while( *pucByte != 0x00 )\r
+               /* pucByte points to the full name. Walk over the string. */\r
+               while( *pucByte != 0x00 && xSourceLen > 1 )\r
                {\r
-                       /* The number of bytes to jump for each name section is stored in the byte\r
-                       before the name section. */\r
-                       pucByte += ( *pucByte + 1 );\r
+            xChunkLength = *pucByte + 1;\r
+\r
+            if( xSourceLen > xChunkLength )\r
+            {\r
+                xSourceLen -= xChunkLength;\r
+                pucByte += xChunkLength;\r
+            }\r
+            else\r
+            {\r
+                pucByte = NULL;\r
+                break;\r
+            }\r
                }\r
 \r
-               pucByte++;\r
+        /* Confirm that a fully formed name was found. */\r
+        if( NULL != pucByte )\r
+        {\r
+            if( 0x00 == *pucByte )\r
+            {\r
+                pucByte++;\r
+            }\r
+            else\r
+            {\r
+                pucByte = NULL;\r
+            }\r
+        }\r
        }\r
 \r
        return pucByte;\r
@@ -712,10 +809,25 @@ static uint8_t *prvSkipNameField( uint8_t *pucByte )
 \r
 uint32_t ulDNSHandlePacket( NetworkBufferDescriptor_t *pxNetworkBuffer )\r
 {\r
-uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );\r
-DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
+uint8_t *pucUDPPayloadBuffer;\r
+size_t xPlayloadBufferLength;\r
+DNSMessage_t *pxDNSMessageHeader;\r
 \r
-       prvParseDNSReply( pucUDPPayloadBuffer, ( uint32_t ) pxDNSMessageHeader->usIdentifier );\r
+       xPlayloadBufferLength = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );\r
+       if ( xPlayloadBufferLength < sizeof( DNSMessage_t ) )\r
+       {\r
+               return pdFAIL;\r
+       }\r
+\r
+       pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );\r
+       pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
+\r
+    if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t ) )\r
+    {\r
+        prvParseDNSReply( pucUDPPayloadBuffer, \r
+            xPlayloadBufferLength,\r
+            ( uint32_t )pxDNSMessageHeader->usIdentifier );\r
+    }\r
 \r
        /* The packet was not consumed. */\r
        return pdFAIL;\r
@@ -727,9 +839,14 @@ DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
        uint32_t ulNBNSHandlePacket (NetworkBufferDescriptor_t *pxNetworkBuffer )\r
        {\r
        UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
-       uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( *pxUDPPacket );\r
+       uint8_t *pucUDPPayloadBuffer = pxNetworkBuffer->pucEthernetBuffer + sizeof( UDPPacket_t );\r
 \r
-               prvTreatNBNS( pucUDPPayloadBuffer, pxUDPPacket->xIPHeader.ulSourceIPAddress );\r
+        if( pxNetworkBuffer->xDataLength > sizeof( UDPPacket_t) )\r
+        {\r
+                   prvTreatNBNS( pucUDPPayloadBuffer, \r
+                          pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ),\r
+                          pxUDPPacket->xIPHeader.ulSourceIPAddress );\r
+        }\r
 \r
                /* The packet was not consumed. */\r
                return pdFAIL;\r
@@ -738,28 +855,42 @@ DNSMessage_t *pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;
 #endif /* ipconfigUSE_NBNS */\r
 /*-----------------------------------------------------------*/\r
 \r
-static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, TickType_t xIdentifier )\r
+static uint32_t prvParseDNSReply( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, TickType_t xIdentifier )\r
 {\r
 DNSMessage_t *pxDNSMessageHeader;\r
+DNSAnswerRecord_t *pxDNSAnswerRecord;\r
 uint32_t ulIPAddress = 0UL;\r
 #if( ipconfigUSE_LLMNR == 1 )\r
        char *pcRequestedName = NULL;\r
 #endif\r
 uint8_t *pucByte;\r
+size_t xSourceBytesRemaining;\r
 uint16_t x, usDataLength, usQuestions;\r
 #if( ipconfigUSE_LLMNR == 1 )\r
        uint16_t usType = 0, usClass = 0;\r
 #endif\r
 #if( ipconfigUSE_DNS_CACHE == 1 )\r
-       char pcName[128] = ""; /*_RB_ What is the significance of 128?  Probably too big to go on the stack for a small MCU but don't know how else it could be made re-entrant.  Might be necessary. */\r
+       char pcName[ ipconfigDNS_CACHE_NAME_LENGTH ] = ""; \r
 #endif\r
 \r
+    /* Ensure that the buffer is of at least minimal DNS message length. */\r
+    if( xBufferLength < sizeof( DNSMessage_t ) )\r
+    {\r
+        return dnsPARSE_ERROR;\r
+    }\r
+    else\r
+    {\r
+        xSourceBytesRemaining = xBufferLength;\r
+    }\r
+\r
+    /* Parse the DNS message header. */\r
        pxDNSMessageHeader = ( DNSMessage_t * ) pucUDPPayloadBuffer;\r
 \r
        if( pxDNSMessageHeader->usIdentifier == ( uint16_t ) xIdentifier )\r
        {\r
                /* Start at the first byte after the header. */\r
                pucByte = pucUDPPayloadBuffer + sizeof( DNSMessage_t );\r
+        xSourceBytesRemaining -= sizeof( DNSMessage_t );\r
 \r
                /* Skip any question records. */\r
                usQuestions = FreeRTOS_ntohs( pxDNSMessageHeader->usQuestions );\r
@@ -777,56 +908,100 @@ uint16_t x, usDataLength, usQuestions;
 #if( ipconfigUSE_DNS_CACHE == 1 )\r
                        if( x == 0 )\r
                        {\r
-                               pucByte = prvReadNameField( pucByte, pcName, sizeof( pcName ) );\r
+                               pucByte = prvReadNameField( pucByte, \r
+                                            xSourceBytesRemaining,\r
+                                            pcName, \r
+                                            sizeof( pcName ) );\r
+                \r
+                /* Check for a malformed response. */\r
+                if( NULL == pucByte )\r
+                {\r
+                    return dnsPARSE_ERROR;\r
+                }\r
+                else\r
+                {\r
+                    xSourceBytesRemaining = ( pucUDPPayloadBuffer + xBufferLength ) - pucByte;\r
+                }\r
                        }\r
                        else\r
 #endif /* ipconfigUSE_DNS_CACHE */\r
                        {\r
                                /* Skip the variable length pcName field. */\r
-                               pucByte = prvSkipNameField( pucByte );\r
-                       }\r
-\r
-                       #if( ipconfigUSE_LLMNR == 1 )\r
-                       {\r
-                               /* usChar2u16 returns value in host endianness. */\r
-                               usType = usChar2u16( pucByte );\r
-                               usClass = usChar2u16( pucByte + 2 );\r
-                       }\r
-                       #endif /* ipconfigUSE_LLMNR */\r
-\r
-                       /* Skip the type and class fields. */\r
-                       pucByte += sizeof( uint32_t );\r
+                               pucByte = prvSkipNameField( pucByte, \r
+                                            xSourceBytesRemaining );\r
+            \r
+                /* Check for a malformed response. */\r
+                if( NULL == pucByte )\r
+                {\r
+                    return dnsPARSE_ERROR;\r
+                }\r
+                else\r
+                {\r
+                    xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte;\r
+                }\r
+            }\r
+\r
+            /* Check the remaining buffer size. */\r
+            if( xSourceBytesRemaining >= sizeof( uint32_t ) )\r
+            {\r
+                #if( ipconfigUSE_LLMNR == 1 )\r
+                {\r
+                    /* usChar2u16 returns value in host endianness */\r
+                    usType = usChar2u16( pucByte );\r
+                    usClass = usChar2u16( pucByte + 2 );\r
+                }\r
+                #endif /* ipconfigUSE_LLMNR */\r
+\r
+                /* Skip the type and class fields. */\r
+                pucByte += sizeof( uint32_t );\r
+                xSourceBytesRemaining -= sizeof( uint32_t );\r
+            }\r
+            else\r
+            {\r
+                /* Malformed response. */\r
+                return dnsPARSE_ERROR;\r
+            }\r
                }\r
 \r
-               /* Search through the answers records. */\r
+               /* Search through the answer records. */\r
                pxDNSMessageHeader->usAnswers = FreeRTOS_ntohs( pxDNSMessageHeader->usAnswers );\r
 \r
                if( ( pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) == dnsEXPECTED_RX_FLAGS )\r
                {\r
                        for( x = 0; x < pxDNSMessageHeader->usAnswers; x++ )\r
                        {\r
-                               pucByte = prvSkipNameField( pucByte );\r
-\r
-                               /* Is the type field that of an A record? */\r
-                               if( usChar2u16( pucByte ) == dnsTYPE_A_HOST )\r
+                               pucByte = prvSkipNameField( pucByte,\r
+                                            xSourceBytesRemaining );\r
+\r
+                /* Check for a malformed response. */\r
+                if( NULL == pucByte )\r
+                {\r
+                    return dnsPARSE_ERROR;\r
+                }\r
+                else\r
+                {\r
+                    xSourceBytesRemaining = pucUDPPayloadBuffer + xBufferLength - pucByte;\r
+                }\r
+\r
+                               /* Is there enough data for an IPv4 A record answer and, if so, \r
+                is this an A record? */\r
+                               if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) && \r
+                    usChar2u16( pucByte ) == dnsTYPE_A_HOST )\r
                                {\r
-                                       /* This is the required record.  Skip the type, class, and\r
-                                       time to live fields, plus the first byte of the data\r
-                                       length. */\r
-                                       pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) + sizeof( uint8_t ) );\r
+                                       /* This is the required record type and is of sufficient size. */\r
+                    pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte;\r
 \r
-                                       /* Sanity check the data length. */\r
-                                       if( ( size_t ) *pucByte == sizeof( uint32_t ) )\r
+                                       /* Sanity check the data length of an IPv4 answer. */\r
+                                       if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == sizeof( uint32_t ) )\r
                                        {\r
-                                               /* Skip the second byte of the length. */\r
-                                               pucByte++;\r
-\r
                                                /* Copy the IP address out of the record. */\r
-                                               memcpy( ( void * ) &ulIPAddress, ( void * ) pucByte, sizeof( uint32_t ) );\r
+                                               memcpy( &ulIPAddress, \r
+                                pucByte + sizeof( DNSAnswerRecord_t ),\r
+                                sizeof( uint32_t ) );\r
 \r
                                                #if( ipconfigUSE_DNS_CACHE == 1 )\r
                                                {\r
-                                                       prvProcessDNSCache( pcName, &ulIPAddress, pdFALSE );\r
+                                                       prvProcessDNSCache( pcName, &ulIPAddress, pxDNSAnswerRecord->ulTTL, pdFALSE );\r
                                                }\r
                                                #endif /* ipconfigUSE_DNS_CACHE */\r
                                                #if( ipconfigDNS_USE_CALLBACKS != 0 )\r
@@ -837,24 +1012,37 @@ uint16_t x, usDataLength, usQuestions;
                                                #endif  /* ipconfigDNS_USE_CALLBACKS != 0 */\r
                                        }\r
 \r
+                    pucByte += sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t );\r
+                    xSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + sizeof( uint32_t ) );\r
                                        break;\r
                                }\r
-                               else\r
+                               else if( xSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) )\r
                                {\r
-                                       /* Skip the type, class and time to live fields. */\r
-                                       pucByte += ( sizeof( uint32_t ) + sizeof( uint32_t ) );\r
-\r
-                                       /* Determine the length of the data in the field. */\r
-                                       memcpy( ( void * ) &usDataLength, ( void * ) pucByte, sizeof( uint16_t ) );\r
-                                       usDataLength = FreeRTOS_ntohs( usDataLength );\r
-\r
-                                       /* Jump over the data length bytes, and the data itself. */\r
-                                       pucByte += usDataLength + sizeof( uint16_t );\r
+                    /* It's not an A record, so skip it. Get the header location \r
+                    and then jump over the header. */\r
+                    pxDNSAnswerRecord = ( DNSAnswerRecord_t * )pucByte;\r
+                    pucByte += sizeof( DNSAnswerRecord_t );\r
+                    xSourceBytesRemaining -= sizeof( DNSAnswerRecord_t );\r
+                    \r
+                                       /* Determine the length of the answer data from the header. */\r
+                                       usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength );\r
+\r
+                                       /* Jump over the answer. */\r
+                    if( xSourceBytesRemaining >= usDataLength )\r
+                    {\r
+                        pucByte += usDataLength;\r
+                        xSourceBytesRemaining -= usDataLength;\r
+                    }\r
+                    else\r
+                    {\r
+                        /* Malformed response. */\r
+                        return dnsPARSE_ERROR;\r
+                    }\r
                                }\r
                        }\r
                }\r
 #if( ipconfigUSE_LLMNR == 1 )\r
-               else if( ( usQuestions != ( uint16_t )0u ) && ( usType == ( uint16_t )dnsTYPE_A_HOST ) && ( usClass == ( uint16_t )dnsCLASS_IN ) )\r
+               else if( usQuestions && ( usType == dnsTYPE_A_HOST ) && ( usClass == dnsCLASS_IN ) )\r
                {\r
                        /* If this is not a reply to our DNS request, it might an LLMNR\r
                        request. */\r
@@ -867,7 +1055,7 @@ uint16_t x, usDataLength, usQuestions;
 \r
                                if( ( xBufferAllocFixedSize == pdFALSE ) && ( pxNetworkBuffer != NULL ) )\r
                                {\r
-                               BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +\r
+                               BaseType_t xDataLength = xBufferLength + sizeof( UDPHeader_t ) +\r
                                        sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );\r
 \r
                                        /* The field xDataLength was set to the length of the UDP payload.\r
@@ -900,7 +1088,7 @@ uint16_t x, usDataLength, usQuestions;
                                {\r
                                        pxAnswer = (LLMNRAnswer_t *)pucByte;\r
 \r
-                                       /* Leave 'usIdentifier' and 'usQuestions' untouched. */\r
+                                       /* We leave 'usIdentifier' and 'usQuestions' untouched */\r
                                        vSetField16( pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE );    /* Set the response flag */\r
                                        vSetField16( pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 );  /* Provide a single answer */\r
                                        vSetField16( pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 );     /* No authority */\r
@@ -935,13 +1123,20 @@ uint16_t x, usDataLength, usQuestions;
 \r
 #if( ipconfigUSE_NBNS == 1 )\r
 \r
-       static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, uint32_t ulIPAddress )\r
+       static void prvTreatNBNS( uint8_t *pucUDPPayloadBuffer, size_t xBufferLength, uint32_t ulIPAddress )\r
        {\r
                uint16_t usFlags, usType, usClass;\r
                uint8_t *pucSource, *pucTarget;\r
                uint8_t ucByte;\r
                uint8_t ucNBNSName[ 17 ];\r
 \r
+        /* Check for minimum buffer size. */\r
+        if( xBufferLength < sizeof( NBNSRequest_t ) )\r
+        {\r
+            return;\r
+        }\r
+        \r
+        /* Read the request flags in host endianness. */\r
                usFlags = usChar2u16( pucUDPPayloadBuffer + offsetof( NBNSRequest_t, usFlags ) );\r
 \r
                if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) == dnsNBNS_FLAGS_OPCODE_QUERY )\r
@@ -986,7 +1181,7 @@ uint16_t x, usDataLength, usQuestions;
                                {\r
                                        /* If this is a response from another device,\r
                                        add the name to the DNS cache */\r
-                                       prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, pdFALSE );\r
+                                       prvProcessDNSCache( ( char * ) ucNBNSName, &ulIPAddress, 0, pdFALSE );\r
                                }\r
                        }\r
                        #else\r
@@ -1012,7 +1207,6 @@ uint16_t x, usDataLength, usQuestions;
                                {\r
                                NetworkBufferDescriptor_t *pxNewBuffer;\r
                                BaseType_t xDataLength = pxNetworkBuffer->xDataLength + sizeof( UDPHeader_t ) +\r
-\r
                                        sizeof( EthernetHeader_t ) + sizeof( IPHeader_t );\r
 \r
                                        /* The field xDataLength was set to the length of the UDP payload.\r
@@ -1127,7 +1321,7 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
                        pxIPHeader->usHeaderChecksum       = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );\r
 \r
                        /* calculate the UDP checksum for outgoing package */\r
-                       usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, pdTRUE );\r
+                       usGenerateProtocolChecksum( ( uint8_t* ) pxUDPPacket, lNetLength, pdTRUE );\r
                }\r
                #endif\r
 \r
@@ -1143,10 +1337,12 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
 \r
 #if( ipconfigUSE_DNS_CACHE == 1 )\r
 \r
-       static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, BaseType_t xLookUp )\r
+       static void prvProcessDNSCache( const char *pcName, uint32_t *pulIP, uint32_t ulTTL, BaseType_t xLookUp )\r
        {\r
        BaseType_t x;\r
        BaseType_t xFound = pdFALSE;\r
+    uint32_t ulCurrentTimeSeconds = \r
+        xTaskGetTickCount( ) / portTICK_PERIOD_MS / 1000;\r
        static BaseType_t xFreeEntry = 0;\r
 \r
                /* For each entry in the DNS cache table. */\r
@@ -1157,16 +1353,29 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
                                break;\r
                        }\r
 \r
-                       if( strncmp( xDNSCache[ x ].pcName, pcName, sizeof( xDNSCache[ x ].pcName ) ) == 0 )\r
+                       if( 0 == strcmp( xDNSCache[ x ].pcName, pcName ) )\r
                        {\r
                                /* Is this function called for a lookup or to add/update an IP address? */\r
                                if( xLookUp != pdFALSE )\r
                                {\r
-                                       *pulIP = xDNSCache[ x ].ulIPAddress;\r
+                    /* Confirm that the record is still fresh. */\r
+                    if( ulCurrentTimeSeconds < \r
+                            xDNSCache[ x ].ulTimeWhenAddedInSeconds + \r
+                            FreeRTOS_ntohl( xDNSCache[ x ].ulTTL ) )\r
+                    {\r
+                        *pulIP = xDNSCache[ x ].ulIPAddress;\r
+                    }\r
+                    else\r
+                    {\r
+                        /* Age out the old cached record. */\r
+                        xDNSCache[ x ].pcName[ 0 ] = 0;\r
+                    }\r
                                }\r
                                else\r
                                {\r
                                        xDNSCache[ x ].ulIPAddress = *pulIP;\r
+                    xDNSCache[ x ].ulTTL = ulTTL;\r
+                    xDNSCache[ x ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;\r
                                }\r
 \r
                                xFound = pdTRUE;\r
@@ -1182,15 +1391,21 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
                        }\r
                        else\r
                        {\r
-                               /* Called to add or update an item */\r
-                               strncpy( xDNSCache[ xFreeEntry ].pcName, pcName, sizeof( xDNSCache[ xFreeEntry ].pcName ) );\r
-                               xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;\r
-\r
-                               xFreeEntry++;\r
-                               if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )\r
-                               {\r
-                                       xFreeEntry = 0;\r
-                               }\r
+                               /* Add or update the item. */\r
+                if( strlen( pcName ) < ipconfigDNS_CACHE_NAME_LENGTH )\r
+                {\r
+                    strcpy( xDNSCache[ xFreeEntry ].pcName, pcName );\r
+\r
+                    xDNSCache[ xFreeEntry ].ulIPAddress = *pulIP;\r
+                    xDNSCache[ xFreeEntry ].ulTTL = ulTTL;\r
+                    xDNSCache[ xFreeEntry ].ulTimeWhenAddedInSeconds = ulCurrentTimeSeconds;\r
+\r
+                    xFreeEntry++;\r
+                    if( xFreeEntry == ipconfigDNS_CACHE_ENTRIES )\r
+                    {\r
+                        xFreeEntry = 0;\r
+                    }\r
+                }\r
                        }\r
                }\r
 \r
@@ -1204,4 +1419,9 @@ TickType_t xTimeoutTime = pdMS_TO_TICKS( 200 );
 \r
 #endif /* ipconfigUSE_DNS != 0 */\r
 \r
+/*-----------------------------------------------------------*/\r
 \r
+/* Provide access to private members for testing. */\r
+#ifdef AMAZON_FREERTOS_ENABLE_UNIT_TESTS\r
+    #include "aws_freertos_tcp_test_access_dns_define.h"\r
+#endif\r