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_Parser.c 30 * @brief Implements the DNS message parser 31 */ 32 33 /* FreeRTOS includes. */ 34 #include "FreeRTOS.h" 35 /* FreeRTOS+TCP includes. */ 36 #include "FreeRTOS_IP.h" 37 #include "FreeRTOS_IP_Private.h" 38 39 #include "FreeRTOS_DNS_Globals.h" 40 #include "FreeRTOS_DNS_Parser.h" 41 #include "FreeRTOS_DNS_Cache.h" 42 #include "FreeRTOS_DNS_Callback.h" 43 44 #include "NetworkBufferManagement.h" 45 46 #include <string.h> 47 48 #if ( ipconfigUSE_DNS != 0 ) 49 50 /** @brief The list of all callback structures. */ 51 52 53 #if ( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) ) 54 55 /** 56 * @brief Find the best matching end-point given a reply that was received. 57 * @param[in] pxNetworkBuffer The Ethernet packet that was received. 58 * @return An end-point. 59 */ prvFindEndPointOnNetMask(NetworkBufferDescriptor_t * pxNetworkBuffer)60 static NetworkEndPoint_t * prvFindEndPointOnNetMask( NetworkBufferDescriptor_t * pxNetworkBuffer ) 61 { 62 NetworkEndPoint_t * pxEndPoint = NULL; 63 64 #if ( ipconfigUSE_IPv6 != 0 ) 65 IPPacket_IPv6_t * xIPPacket_IPv6 = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 66 67 if( xIPPacket_IPv6->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE ) 68 { 69 pxEndPoint = FreeRTOS_FindEndPointOnNetMask_IPv6( &xIPPacket_IPv6->xIPHeader.xSourceAddress ); 70 } 71 else 72 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 73 74 #if ( ipconfigUSE_IPv4 != 0 ) 75 { 76 IPPacket_t * xIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); 77 78 pxEndPoint = FreeRTOS_FindEndPointOnNetMask( xIPPacket->xIPHeader.ulSourceIPAddress, 6 ); 79 } 80 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 81 82 if( pxEndPoint != NULL ) 83 { 84 pxNetworkBuffer->pxEndPoint = pxEndPoint; 85 } 86 87 return pxEndPoint; 88 } 89 #endif /* ( ( ipconfigUSE_NBNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) ) */ 90 /*-----------------------------------------------------------*/ 91 92 /** 93 * @brief Read the Name field out of a DNS response packet. 94 * 95 * @param[in,out] pxSet a set of variables that are shared among the helper functions. 96 * @param[in] uxDestLen Size of the pcName array. 97 * 98 * @return If a fully formed name was found, then return the number of bytes processed in pucByte. 99 */ DNS_ReadNameField(ParseSet_t * pxSet,size_t uxDestLen)100 size_t DNS_ReadNameField( ParseSet_t * pxSet, 101 size_t uxDestLen ) 102 { 103 size_t uxNameLen = 0U; 104 size_t uxIndex = 0U; 105 size_t uxSourceLen = pxSet->uxSourceBytesRemaining; 106 const uint8_t * pucByte = pxSet->pucByte; 107 108 /* uxCount gets the values from pucByte and counts down to 0. 109 * No need to have a different type than that of pucByte */ 110 size_t uxCount; 111 112 if( uxSourceLen == ( size_t ) 0U ) 113 { 114 /* Return 0 value in case of error. */ 115 uxIndex = 0U; 116 } 117 118 /* Determine if the name is the fully coded name, or an offset to the name 119 * elsewhere in the message. */ 120 else if( ( pucByte[ uxIndex ] & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) 121 { 122 /* Jump over the two byte offset. */ 123 if( uxSourceLen > sizeof( uint16_t ) ) 124 { 125 uxIndex += sizeof( uint16_t ); 126 } 127 else 128 { 129 uxIndex = 0U; 130 } 131 } 132 else 133 { 134 /* 'uxIndex' points to the full name. Walk over the string. */ 135 while( ( uxIndex < uxSourceLen ) && ( pucByte[ uxIndex ] != ( uint8_t ) 0x00U ) ) 136 { 137 /* If this is not the first time through the loop, then add a 138 * separator in the output. */ 139 if( ( uxNameLen > 0U ) ) 140 { 141 /* 142 * uxNameLen can never be greater than uxDestLen, since there are checks 143 * outside this condition, so the check is removed. 144 */ 145 pxSet->pcName[ uxNameLen ] = '.'; 146 uxNameLen++; 147 } 148 149 /* Process the first/next sub-string. */ 150 uxCount = ( size_t ) pucByte[ uxIndex ]; 151 152 /* uxIndex should point to the first character now, unless uxCount 153 * is an offset field. */ 154 uxIndex++; 155 156 if( ( uxIndex + uxCount ) > uxSourceLen ) 157 { 158 uxIndex = 0U; 159 break; 160 } 161 162 if( ( uxNameLen + uxCount ) >= uxDestLen ) 163 { 164 uxIndex = 0U; 165 break; 166 } 167 168 while( uxCount-- != 0U ) 169 { 170 /* 171 * uxNameLen can never be greater than uxDestLen, since there are checks 172 * outside this condition, so the check is removed. 173 */ 174 pxSet->pcName[ uxNameLen ] = ( char ) pucByte[ uxIndex ]; 175 uxNameLen++; 176 uxIndex++; 177 } 178 } 179 180 /* Confirm that a fully formed name was found. */ 181 if( uxIndex > 0U ) 182 { 183 /* Here, there is no need to check for pucByte[ uxindex ] == 0 because: 184 * When we break out of the above while loop, uxIndex is made 0 thereby 185 * failing above check. Whenever we exit the loop otherwise, either 186 * pucByte[ uxIndex ] == 0 (which makes the check here unnecessary) or 187 * uxIndex >= uxSourceLen (which makes sure that we do not go in the 'if' 188 * case). 189 */ 190 if( uxIndex < uxSourceLen ) 191 { 192 pxSet->pcName[ uxNameLen ] = '\0'; 193 uxIndex++; 194 } 195 else 196 { 197 uxIndex = 0U; 198 } 199 } 200 } 201 202 return uxIndex; 203 } 204 205 /** 206 * @brief Simple routine that jumps over the NAME field of a resource record. 207 * 208 * @param[in] pucByte The pointer to the resource record. 209 * @param[in] uxLength Length of the resource record. 210 * 211 * @return It returns the number of bytes read, or zero when an error has occurred. 212 */ DNS_SkipNameField(const uint8_t * pucByte,size_t uxLength)213 size_t DNS_SkipNameField( const uint8_t * pucByte, 214 size_t uxLength ) 215 { 216 size_t uxChunkLength; 217 size_t uxSourceLenCpy = uxLength; 218 size_t uxIndex = 0U; 219 220 if( uxSourceLenCpy == 0U ) 221 { 222 uxIndex = 0U; 223 } 224 225 /* Determine if the name is the fully coded name, or an offset to the name 226 * elsewhere in the message. */ 227 else if( ( pucByte[ uxIndex ] & dnsNAME_IS_OFFSET ) == dnsNAME_IS_OFFSET ) 228 { 229 /* Jump over the two byte offset. */ 230 if( uxSourceLenCpy > sizeof( uint16_t ) ) 231 { 232 uxIndex += sizeof( uint16_t ); 233 } 234 else 235 { 236 uxIndex = 0U; 237 } 238 } 239 else 240 { 241 /* pucByte points to the full name. Walk over the string. */ 242 while( ( pucByte[ uxIndex ] != 0U ) && ( uxSourceLenCpy > 1U ) ) 243 { 244 /* Conversion to size_t causes addition to be done 245 * in size_t */ 246 uxChunkLength = ( ( size_t ) pucByte[ uxIndex ] ) + 1U; 247 248 if( uxSourceLenCpy > uxChunkLength ) 249 { 250 uxSourceLenCpy -= uxChunkLength; 251 uxIndex += uxChunkLength; 252 } 253 else 254 { 255 uxIndex = 0U; 256 break; 257 } 258 } 259 260 /* Confirm that a fully formed name was found. */ 261 if( uxIndex > 0U ) 262 { 263 if( pucByte[ uxIndex ] == 0U ) 264 { 265 uxIndex++; 266 } 267 else 268 { 269 uxIndex = 0U; 270 } 271 } 272 } 273 274 return uxIndex; 275 } 276 277 /** 278 * @brief Process a response packet from a DNS server, or an LLMNR reply. 279 * 280 * @param[in] pucUDPPayloadBuffer The DNS response received as a UDP 281 * payload. 282 * @param[in] uxBufferLength Length of the UDP payload buffer. 283 * @param[in] ppxAddressInfo A pointer to a pointer where the results will be stored. 284 * @param[in] xExpected indicates whether the identifier in the reply 285 * was expected, and thus if the DNS cache may be 286 * updated with the reply. 287 * @param[in] usPort The server port number in order to identify the protocol. 288 * 289 * 290 * @return The IP address in the DNS response if present and if xExpected is set to pdTRUE. 291 * An error code (dnsPARSE_ERROR) if there was an error in the DNS response. 292 * 0 if xExpected set to pdFALSE. 293 */ 294 /* TODO cross check again */ DNS_ParseDNSReply(uint8_t * pucUDPPayloadBuffer,size_t uxBufferLength,struct freertos_addrinfo ** ppxAddressInfo,BaseType_t xExpected,uint16_t usPort)295 uint32_t DNS_ParseDNSReply( uint8_t * pucUDPPayloadBuffer, 296 size_t uxBufferLength, 297 struct freertos_addrinfo ** ppxAddressInfo, 298 BaseType_t xExpected, 299 uint16_t usPort ) 300 { 301 ParseSet_t xSet; 302 uint16_t x; 303 BaseType_t xReturn = pdTRUE; 304 uint32_t ulIPAddress = 0U; 305 BaseType_t xDNSHookReturn; 306 307 ( void ) memset( &( xSet ), 0, sizeof( xSet ) ); 308 xSet.usPortNumber = usPort; 309 xSet.ppxLastAddress = &( xSet.pxLastAddress ); 310 311 #if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) 312 xSet.xDoStore = xExpected; 313 #endif 314 315 /* Ensure that the buffer is of at least minimal DNS message length. */ 316 if( uxBufferLength < sizeof( DNSMessage_t ) ) 317 { 318 ( void ) xDNSHookReturn; 319 xReturn = pdFALSE; 320 } 321 else 322 { 323 xSet.uxBufferLength = uxBufferLength; 324 xSet.uxSourceBytesRemaining = uxBufferLength; 325 326 /* Parse the DNS message header. Map the byte stream onto a structure 327 * for easier access. */ 328 329 /* MISRA Ref 11.3.1 [Misaligned access] */ 330 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 331 /* coverity[misra_c_2012_rule_11_3_violation] */ 332 xSet.pxDNSMessageHeader = ( ( DNSMessage_t * ) 333 pucUDPPayloadBuffer ); 334 335 /* Introduce a do {} while (0) to allow the use of breaks. */ 336 do 337 { 338 size_t uxBytesRead = 0U; 339 size_t uxResult; 340 341 /* Start at the first byte after the header. */ 342 xSet.pucUDPPayloadBuffer = pucUDPPayloadBuffer; 343 xSet.pucByte = &( pucUDPPayloadBuffer[ sizeof( DNSMessage_t ) ] ); 344 xSet.uxSourceBytesRemaining -= sizeof( DNSMessage_t ); 345 346 /* Skip any question records. */ 347 xSet.usQuestions = FreeRTOS_ntohs( xSet.pxDNSMessageHeader->usQuestions ); 348 349 if( xSet.usQuestions == 0U ) 350 { 351 /* The IP-stack will only accept DNS replies that have a copy 352 * of the questions. */ 353 xReturn = pdFALSE; 354 break; 355 } 356 357 for( x = 0U; x < xSet.usQuestions; x++ ) 358 { 359 #if ( ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) ) 360 { 361 if( x == 0U ) 362 { 363 xSet.pcRequestedName = ( char * ) xSet.pucByte; 364 } 365 } 366 #endif 367 368 #if ( ipconfigUSE_DNS_CACHE == 1 ) || ( ipconfigDNS_USE_CALLBACKS == 1 ) 369 if( x == 0U ) 370 { 371 uxResult = DNS_ReadNameField( &xSet, 372 sizeof( xSet.pcName ) ); 373 } 374 else 375 #endif /* ipconfigUSE_DNS_CACHE || ipconfigDNS_USE_CALLBACKS */ 376 { 377 /* Skip the variable length pcName field. */ 378 uxResult = DNS_SkipNameField( xSet.pucByte, 379 xSet.uxSourceBytesRemaining ); 380 } 381 382 /* Check for a malformed response. */ 383 if( uxResult == 0U ) 384 { 385 xReturn = pdFALSE; 386 break; 387 } 388 389 uxBytesRead += uxResult; 390 xSet.pucByte = &( xSet.pucByte[ uxResult ] ); 391 xSet.uxSourceBytesRemaining -= uxResult; 392 393 /* Check the remaining buffer size. */ 394 if( xSet.uxSourceBytesRemaining >= sizeof( uint32_t ) ) 395 { 396 #if ( ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) ) 397 { 398 /* usChar2u16 returns value in host endianness. */ 399 xSet.usType = usChar2u16( xSet.pucByte ); 400 xSet.usClass = usChar2u16( &( xSet.pucByte[ 2 ] ) ); 401 } 402 #endif /* ipconfigUSE_LLMNR */ 403 404 /* Skip the type and class fields. */ 405 xSet.pucByte = &( xSet.pucByte[ sizeof( uint32_t ) ] ); 406 xSet.uxSourceBytesRemaining -= sizeof( uint32_t ); 407 } 408 else 409 { 410 xReturn = pdFALSE; 411 break; 412 } 413 } /* for( x = 0U; x < xSet.usQuestions; x++ ) */ 414 415 if( xReturn == pdFALSE ) 416 { 417 /* No need to proceed. Break out of the do-while loop. */ 418 break; 419 } 420 421 /* Search through the answer records. */ 422 xSet.pxDNSMessageHeader->usAnswers = 423 FreeRTOS_ntohs( xSet.pxDNSMessageHeader->usAnswers ); 424 425 if( ( xSet.pxDNSMessageHeader->usFlags & dnsRX_FLAGS_MASK ) 426 == dnsEXPECTED_RX_FLAGS ) 427 { 428 ulIPAddress = parseDNSAnswer( &( xSet ), ppxAddressInfo, &uxBytesRead ); 429 } 430 431 #if ( ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_MDNS == 1 ) ) 432 433 /* No need to check that pcRequestedName != NULL since sQuestions != 0, then 434 * pcRequestedName is assigned with this statement 435 * "pcRequestedName = ( char * ) pucByte;" */ 436 /* No need to check that usQuestions != 0, since the check is done before */ 437 else if( ( ( xSet.usType == dnsTYPE_A_HOST ) || ( xSet.usType == dnsTYPE_AAAA_HOST ) ) && 438 ( xSet.usClass == dnsCLASS_IN ) ) 439 { 440 NetworkBufferDescriptor_t * pxNetworkBuffer; 441 NetworkEndPoint_t * pxEndPoint, xEndPoint; 442 size_t uxUDPOffset; 443 444 pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer ); 445 446 /* This test could be replaced with a assert(). */ 447 if( pxNetworkBuffer == NULL ) 448 { 449 /* _HT_ just while testing. When the program gets here, 450 * pucUDPPayloadBuffer was invalid. */ 451 FreeRTOS_printf( ( "DNS_ParseDNSReply: pucUDPPayloadBuffer was invalid\n" ) ); 452 break; 453 } 454 455 uxUDPOffset = ( size_t ) ( pucUDPPayloadBuffer - pxNetworkBuffer->pucEthernetBuffer ); 456 configASSERT( ( uxUDPOffset == ipUDP_PAYLOAD_OFFSET_IPv4 ) || ( uxUDPOffset == ipUDP_PAYLOAD_OFFSET_IPv6 ) ); 457 458 if( pxNetworkBuffer->pxEndPoint == NULL ) 459 { 460 break; 461 } 462 463 pxEndPoint = pxNetworkBuffer->pxEndPoint; 464 465 /* Make a copy of the end-point because xApplicationDNSQueryHook() is allowed 466 * to write into it. */ 467 ( void ) memcpy( &( xEndPoint ), pxEndPoint, sizeof( xEndPoint ) ); 468 469 #if ( ipconfigUSE_IPv6 != 0 ) 470 { 471 /*logging*/ 472 FreeRTOS_printf( ( "prvParseDNS_HandleLLMNRRequest[%s]: type %04X\n", xSet.pcName, xSet.usType ) ); 473 474 xEndPoint.usDNSType = ( uint8_t ) xSet.usType; 475 } 476 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 477 478 /* If this is not a reply to our DNS request, it might be an mDNS or an LLMNR 479 * request. Ask the application if it uses the name. */ 480 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) 481 xDNSHookReturn = xApplicationDNSQueryHook( xSet.pcName ); 482 #else 483 xDNSHookReturn = xApplicationDNSQueryHook_Multi( &xEndPoint, xSet.pcName ); 484 #endif 485 486 if( xDNSHookReturn != pdFALSE ) 487 { 488 int16_t usLength; 489 NetworkBufferDescriptor_t * pxNewBuffer = NULL; 490 LLMNRAnswer_t * pxAnswer; 491 uint8_t * pucNewBuffer = NULL; 492 size_t uxExtraLength; 493 494 if( xBufferAllocFixedSize == pdFALSE ) 495 { 496 size_t uxDataLength = uxBufferLength + 497 sizeof( UDPHeader_t ) + 498 sizeof( EthernetHeader_t ) + 499 uxIPHeaderSizePacket( pxNetworkBuffer ); 500 501 #if ( ipconfigUSE_IPv6 != 0 ) 502 if( xSet.usType == dnsTYPE_AAAA_HOST ) 503 { 504 uxExtraLength = sizeof( LLMNRAnswer_t ) + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress ); 505 } 506 else 507 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 508 #if ( ipconfigUSE_IPv4 != 0 ) 509 { 510 uxExtraLength = sizeof( LLMNRAnswer_t ); 511 } 512 #else /* ( ipconfigUSE_IPv4 != 0 ) */ 513 { 514 /* do nothing, coverity happy */ 515 } 516 #endif /* ( ipconfigUSE_IPv4 != 0 ) */ 517 518 /* Set the size of the outgoing packet. */ 519 pxNetworkBuffer->xDataLength = uxDataLength; 520 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, 521 uxDataLength + 522 uxExtraLength ); 523 524 if( pxNewBuffer != NULL ) 525 { 526 BaseType_t xOffset1, xOffset2; 527 528 xOffset1 = ( BaseType_t ) ( xSet.pucByte - pucUDPPayloadBuffer ); 529 xOffset2 = ( BaseType_t ) ( ( ( uint8_t * ) xSet.pcRequestedName ) - pucUDPPayloadBuffer ); 530 531 pxNetworkBuffer = pxNewBuffer; 532 pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ uxUDPOffset ] ); 533 534 xSet.pucByte = &( pucNewBuffer[ xOffset1 ] ); 535 xSet.pcRequestedName = ( char * ) &( pucNewBuffer[ xOffset2 ] ); 536 xSet.pxDNSMessageHeader = ( ( DNSMessage_t * ) pucNewBuffer ); 537 } 538 else 539 { 540 /* Just to indicate that the message may not be answered. */ 541 pxNetworkBuffer = NULL; 542 } 543 } 544 else 545 { 546 pucNewBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ uxUDPOffset ] ); 547 } 548 549 if( ( pxNetworkBuffer != NULL ) ) 550 { 551 pxAnswer = ( ( LLMNRAnswer_t * ) xSet.pucByte ); 552 /* We leave 'usIdentifier' and 'usQuestions' untouched */ 553 vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_REPONSE ); /* Set the response flag */ 554 vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */ 555 vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */ 556 vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */ 557 558 pxAnswer->ucNameCode = dnsNAME_IS_OFFSET; 559 pxAnswer->ucNameOffset = ( uint8_t ) ( xSet.pcRequestedName - ( char * ) pucNewBuffer ); 560 561 vSetField16( pxAnswer, LLMNRAnswer_t, usType, xSet.usType ); /* Type A or AAAA: host */ 562 vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */ 563 vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE ); 564 565 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( xSet.pucByte - pucNewBuffer ) ); 566 567 #if ( ipconfigUSE_IPv6 != 0 ) 568 if( xSet.usType == dnsTYPE_AAAA_HOST ) 569 { 570 size_t uxDistance; 571 vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ipSIZE_OF_IPv6_ADDRESS ); 572 ( void ) memcpy( &( pxAnswer->ulIPAddress ), xEndPoint.ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 573 uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer ); 574 /* An extra 12 bytes will be sent compared to an A-record. */ 575 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress ) ); 576 } 577 else 578 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 579 { 580 size_t uxDistance; 581 vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ( uint16_t ) sizeof( pxAnswer->ulIPAddress ) ); 582 vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( xEndPoint.ipv4_settings.ulIPAddress ) ); 583 uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer ); 584 usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance ); 585 } 586 587 prepareReplyDNSMessage( pxNetworkBuffer, usLength ); 588 /* This function will fill in the eth addresses and send the packet */ 589 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE ); 590 591 if( pxNewBuffer != NULL ) 592 { 593 vReleaseNetworkBufferAndDescriptor( pxNewBuffer ); 594 } 595 } 596 } 597 else 598 { 599 /* Not an expected reply. */ 600 } 601 } 602 #endif /* ipconfigUSE_LLMNR == 1 */ 603 ( void ) uxBytesRead; 604 } while( ipFALSE_BOOL ); 605 } 606 607 if( xReturn == pdFALSE ) 608 { 609 /* There was an error while parsing the DNS response. Return error code. */ 610 ulIPAddress = ( uint32_t ) dnsPARSE_ERROR; 611 } 612 else if( xExpected == pdFALSE ) 613 { 614 /* Do not return a valid IP-address in case the reply was not expected. */ 615 ulIPAddress = 0U; 616 } 617 else 618 { 619 /* The IP-address found will be returned. */ 620 } 621 622 return ulIPAddress; 623 } 624 625 /** 626 * @brief perform a dns lookup in the local cache {TODO WRONG} 627 * @param[in] pxSet a set of variables that are shared among the helper functions. 628 * @param[out] ppxAddressInfo a linked list storing the DNS answers. 629 * @param[out] uxBytesRead total bytes consumed by the function 630 * @return pdTRUE when successful, otherwise pdFALSE. 631 */ parseDNSAnswer(ParseSet_t * pxSet,struct freertos_addrinfo ** ppxAddressInfo,size_t * uxBytesRead)632 uint32_t parseDNSAnswer( ParseSet_t * pxSet, 633 struct freertos_addrinfo ** ppxAddressInfo, 634 size_t * uxBytesRead ) 635 { 636 uint16_t x; 637 size_t uxResult; 638 uint32_t ulReturnIPAddress = 0U; 639 const uint16_t usCount = ( uint16_t ) ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY; 640 BaseType_t xReturn = pdTRUE; 641 const DNSAnswerRecord_t * pxDNSAnswerRecord; 642 IPv46_Address_t xIP_Address; 643 644 struct freertos_addrinfo * pxNewAddress = NULL; 645 646 for( x = 0U; x < pxSet->pxDNSMessageHeader->usAnswers; x++ ) 647 { 648 BaseType_t xDoAccept = pdFALSE; 649 650 if( pxSet->usNumARecordsStored >= usCount ) 651 { 652 /* Only count ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY number of records. */ 653 break; 654 } 655 656 uxResult = DNS_SkipNameField( pxSet->pucByte, 657 sizeof( pxSet->pcName ) ); 658 659 /* Check for a malformed response. */ 660 if( uxResult == 0U ) 661 { 662 xReturn = pdFALSE; 663 break; 664 } 665 666 if( uxBytesRead != NULL ) 667 { 668 *uxBytesRead += uxResult; 669 } 670 671 pxSet->pucByte = &( pxSet->pucByte[ uxResult ] ); 672 pxSet->uxSourceBytesRemaining -= uxResult; 673 674 /* Is there enough data for an IPv4 A record answer and, if so, 675 * is this an A record? */ 676 if( pxSet->uxSourceBytesRemaining < sizeof( uint16_t ) ) 677 { 678 xReturn = pdFALSE; 679 break; 680 } 681 682 pxSet->usType = usChar2u16( pxSet->pucByte ); 683 684 if( pxSet->usType == ( uint16_t ) dnsTYPE_AAAA_HOST ) 685 { 686 pxSet->uxAddressLength = ipSIZE_OF_IPv6_ADDRESS; 687 688 if( pxSet->uxSourceBytesRemaining >= ( sizeof( DNSAnswerRecord_t ) + pxSet->uxAddressLength ) ) 689 { 690 xDoAccept = pdTRUE; 691 } 692 } 693 else if( pxSet->usType == ( uint16_t ) dnsTYPE_A_HOST ) 694 { 695 pxSet->uxAddressLength = ipSIZE_OF_IPv4_ADDRESS; /*TODO check if fine */ 696 697 if( pxSet->uxSourceBytesRemaining >= ( sizeof( DNSAnswerRecord_t ) + pxSet->uxAddressLength ) ) 698 { 699 xDoAccept = pdTRUE; 700 } 701 } 702 else 703 { 704 /* Unknown host type, AAAA nor A. 705 * 'xDoAccept' was already initialised as pdFALSE. */ 706 } 707 708 if( xDoAccept != pdFALSE ) 709 { 710 /* This is the required record type and is of sufficient size. */ 711 712 /* Mapping pucBuffer to a DNSAnswerRecord allows easy access of the 713 * fields of the structure. */ 714 715 /* MISRA Ref 11.3.1 [Misaligned access] */ 716 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 717 /* coverity[misra_c_2012_rule_11_3_violation] */ 718 pxDNSAnswerRecord = ( ( DNSAnswerRecord_t * ) pxSet->pucByte ); 719 720 /* Sanity check the data length of an IPv4 answer. */ 721 if( FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ) == 722 ( uint16_t ) pxSet->uxAddressLength ) 723 { 724 if( pxSet->uxAddressLength == ipSIZE_OF_IPv6_ADDRESS ) /*No check needed for pxSet->usType as uxAddressLength is set based on usType*/ 725 { 726 ( void ) memcpy( xIP_Address.xIPAddress.xIP_IPv6.ucBytes, 727 &( pxSet->pucByte[ sizeof( DNSAnswerRecord_t ) ] ), 728 ipSIZE_OF_IPv6_ADDRESS ); 729 730 if( ppxAddressInfo != NULL ) 731 { 732 pxNewAddress = pxNew_AddrInfo( pxSet->pcName, FREERTOS_AF_INET6, xIP_Address.xIPAddress.xIP_IPv6.ucBytes ); 733 } 734 735 xIP_Address.xIs_IPv6 = pdTRUE; 736 737 /* Return non-zero to inform the caller that a valid 738 * IPv6 address was found. */ 739 pxSet->ulIPAddress = 1U; 740 } 741 else 742 { 743 void * pvCopyDest; 744 const void * pvCopySource; 745 746 /* Copy the IP address out of the record. Using different pointers 747 * to copy only the portion we want is intentional here. */ 748 749 /* 750 * Use helper variables for memcpy() to remain 751 * compliant with MISRA Rule 21.15. These should be 752 * optimized away. 753 */ 754 pvCopySource = &( pxSet->pucByte[ sizeof( DNSAnswerRecord_t ) ] ); 755 pvCopyDest = &( pxSet->ulIPAddress ); 756 ( void ) memcpy( pvCopyDest, pvCopySource, pxSet->uxAddressLength ); 757 758 if( ppxAddressInfo != NULL ) 759 { 760 const uint8_t * ucBytes = ( uint8_t * ) &( pxSet->ulIPAddress ); 761 762 pxNewAddress = pxNew_AddrInfo( pxSet->pcName, FREERTOS_AF_INET4, ucBytes ); 763 } 764 765 xIP_Address.xIPAddress.ulIP_IPv4 = pxSet->ulIPAddress; 766 xIP_Address.xIs_IPv6 = pdFALSE; 767 } 768 769 if( pxNewAddress != NULL ) 770 { 771 if( *( ppxAddressInfo ) == NULL ) 772 { 773 /* For the first address found. */ 774 *( ppxAddressInfo ) = pxNewAddress; 775 } 776 else 777 { 778 /* For the next address found. */ 779 *( pxSet->ppxLastAddress ) = pxNewAddress; 780 } 781 782 pxSet->ppxLastAddress = &( pxNewAddress->ai_next ); 783 } 784 785 #if ( ipconfigDNS_USE_CALLBACKS == 1 ) 786 { 787 BaseType_t xCallbackResult; 788 789 xCallbackResult = xDNSDoCallback( pxSet, ( ppxAddressInfo != NULL ) ? *( ppxAddressInfo ) : NULL ); 790 791 /* See if any asynchronous call was made to FreeRTOS_gethostbyname_a() */ 792 if( xCallbackResult != pdFALSE ) 793 { 794 /* This device has requested this DNS look-up. 795 * The result may be stored in the DNS cache. */ 796 pxSet->xDoStore = pdTRUE; 797 } 798 } 799 #endif /* ipconfigDNS_USE_CALLBACKS == 1 */ 800 #if ( ipconfigUSE_DNS_CACHE == 1 ) 801 { 802 char cBuffer[ 40 ]; 803 804 /* The reply will only be stored in the DNS cache when the 805 * request was issued by this device. */ 806 if( pxSet->xDoStore != pdFALSE ) 807 { 808 ( void ) FreeRTOS_dns_update( 809 pxSet->pcName, 810 &xIP_Address, 811 pxDNSAnswerRecord->ulTTL, 812 pdFALSE, 813 NULL ); 814 pxSet->usNumARecordsStored++; /* Track # of A records stored */ 815 } 816 817 if( pxSet->usType == ( uint16_t ) dnsTYPE_AAAA_HOST ) 818 { 819 ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET6, ( const void * ) xIP_Address.xIPAddress.xIP_IPv6.ucBytes, cBuffer, sizeof( cBuffer ) ); 820 FreeRTOS_printf( ( "DNS[0x%04X]: The answer to '%s' (%s) will%s be stored\n", 821 ( unsigned ) pxSet->pxDNSMessageHeader->usIdentifier, 822 pxSet->pcName, 823 cBuffer, 824 ( pxSet->xDoStore != 0 ) ? "" : " NOT" ) ); 825 } 826 else 827 { 828 ( void ) FreeRTOS_inet_ntop( FREERTOS_AF_INET, 829 ( const void * ) &( pxSet->ulIPAddress ), 830 cBuffer, 831 ( socklen_t ) sizeof( cBuffer ) ); 832 /* Show what has happened. */ 833 FreeRTOS_printf( ( "DNS[0x%04X]: The answer to '%s' (%s) will%s be stored\n", 834 pxSet->pxDNSMessageHeader->usIdentifier, 835 pxSet->pcName, 836 cBuffer, 837 ( pxSet->xDoStore != 0 ) ? "" : " NOT" ) ); 838 } 839 } 840 #endif /* ipconfigUSE_DNS_CACHE */ 841 842 if( ( ulReturnIPAddress == 0U ) && ( pxSet->ulIPAddress != 0U ) ) 843 { 844 /* Remember the first IP-address that is found. */ 845 ulReturnIPAddress = pxSet->ulIPAddress; 846 } 847 } 848 else 849 { 850 FreeRTOS_printf( ( "DNS sanity check failed: %u != %u\n", 851 FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ), 852 ( unsigned ) pxSet->uxAddressLength ) ); 853 } 854 855 pxSet->pucByte = &( pxSet->pucByte[ sizeof( DNSAnswerRecord_t ) + pxSet->uxAddressLength ] ); 856 pxSet->uxSourceBytesRemaining -= ( sizeof( DNSAnswerRecord_t ) + pxSet->uxAddressLength ); 857 } 858 else if( pxSet->uxSourceBytesRemaining >= sizeof( DNSAnswerRecord_t ) ) 859 { 860 uint16_t usDataLength; 861 862 /* It's not an A record, so skip it. Get the header location 863 * and then jump over the header. */ 864 /* Cast the response to DNSAnswerRecord for easy access to fields of the DNS response. */ 865 866 /* MISRA Ref 11.3.1 [Misaligned access] */ 867 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */ 868 /* coverity[misra_c_2012_rule_11_3_violation] */ 869 pxDNSAnswerRecord = ( ( DNSAnswerRecord_t * ) pxSet->pucByte ); 870 871 pxSet->pucByte = &( pxSet->pucByte[ sizeof( DNSAnswerRecord_t ) ] ); 872 pxSet->uxSourceBytesRemaining -= sizeof( DNSAnswerRecord_t ); 873 874 /* Determine the length of the answer data from the header. */ 875 usDataLength = FreeRTOS_ntohs( pxDNSAnswerRecord->usDataLength ); 876 877 /* Jump over the answer. */ 878 if( pxSet->uxSourceBytesRemaining >= usDataLength ) 879 { 880 pxSet->pucByte = &( pxSet->pucByte[ usDataLength ] ); 881 pxSet->uxSourceBytesRemaining -= usDataLength; 882 } 883 else 884 { 885 /* Malformed response. */ 886 xReturn = pdFALSE; 887 break; 888 } 889 } 890 else 891 { 892 /* Do nothing */ 893 } 894 } 895 896 return ( xReturn != 0 ) ? ulReturnIPAddress : 0U; 897 } 898 899 #if ( ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_NBNS == 1 ) ) 900 901 /** 902 * @brief Send a DNS message to be used in MDNS, LLMNR or NBNS. 903 * 904 * @param[in] pxNetworkBuffer The network buffer descriptor with the DNS message. 905 * @param[in] lNetLength The length of the DNS message. 906 */ prepareReplyDNSMessage(NetworkBufferDescriptor_t * pxNetworkBuffer,BaseType_t lNetLength)907 void prepareReplyDNSMessage( NetworkBufferDescriptor_t * pxNetworkBuffer, 908 BaseType_t lNetLength ) 909 { 910 UDPPacket_t * pxUDPPacket; 911 IPHeader_t * pxIPHeader; 912 UDPHeader_t * pxUDPHeader; 913 size_t uxDataLength; 914 NetworkEndPoint_t * pxEndPoint = prvFindEndPointOnNetMask( pxNetworkBuffer ); 915 const size_t uxIPHeaderLength = uxIPHeaderSizePacket( pxNetworkBuffer ); 916 917 pxUDPPacket = ( ( UDPPacket_t * ) 918 pxNetworkBuffer->pucEthernetBuffer ); 919 pxIPHeader = &pxUDPPacket->xIPHeader; 920 921 #if ( ipconfigUSE_IPv6 != 0 ) 922 if( ( ( uxIPHeaderLength == ipSIZE_OF_IPv6_HEADER ) && ( ( pxIPHeader->ucVersionHeaderLength & 0xf0U ) == 0x60U ) ) ) 923 { 924 UDPPacket_IPv6_t * xUDPPacket_IPv6; 925 IPHeader_IPv6_t * pxIPHeader_IPv6; 926 927 xUDPPacket_IPv6 = ( ( UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer ); 928 pxIPHeader_IPv6 = &( xUDPPacket_IPv6->xIPHeader ); 929 pxUDPHeader = &xUDPPacket_IPv6->xUDPHeader; 930 931 pxIPHeader_IPv6->usPayloadLength = FreeRTOS_htons( ( uint16_t ) lNetLength + ipSIZE_OF_UDP_HEADER ); 932 933 { 934 ( void ) memcpy( pxIPHeader_IPv6->xDestinationAddress.ucBytes, pxIPHeader_IPv6->xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 935 ( void ) memcpy( pxIPHeader_IPv6->xSourceAddress.ucBytes, pxEndPoint->ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS ); 936 } 937 938 xUDPPacket_IPv6->xUDPHeader.usLength = FreeRTOS_htons( ( uint16_t ) lNetLength + ipSIZE_OF_UDP_HEADER ); 939 vFlip_16( pxUDPHeader->usSourcePort, pxUDPHeader->usDestinationPort ); 940 uxDataLength = ( size_t ) lNetLength + ipSIZE_OF_IPv6_HEADER + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER; 941 } 942 else 943 #endif /* ( ipconfigUSE_IPv6 != 0 ) */ 944 { 945 pxUDPHeader = &pxUDPPacket->xUDPHeader; 946 /* HT: started using defines like 'ipSIZE_OF_xxx' */ 947 pxIPHeader->usLength = FreeRTOS_htons( ( uint16_t ) lNetLength + 948 uxIPHeaderLength + 949 ipSIZE_OF_UDP_HEADER ); 950 951 /* HT:endian: should not be translated, copying from packet to packet */ 952 if( pxIPHeader->ulDestinationIPAddress == ipMDNS_IP_ADDRESS ) 953 { 954 pxIPHeader->ucTimeToLive = ipMDNS_TIME_TO_LIVE; 955 } 956 else 957 { 958 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; 959 pxIPHeader->ucTimeToLive = ipconfigUDP_TIME_TO_LIVE; 960 } 961 962 pxIPHeader->ulSourceIPAddress = ( pxEndPoint != NULL ) ? pxEndPoint->ipv4_settings.ulIPAddress : 0U; 963 pxIPHeader->usIdentification = FreeRTOS_htons( usPacketIdentifier ); 964 965 /* The stack doesn't support fragments, so the fragment offset field must always be zero. 966 * The header was never memset to zero, so set both the fragment offset and fragmentation flags in one go. 967 */ 968 #if ( ipconfigFORCE_IP_DONT_FRAGMENT != 0 ) 969 pxIPHeader->usFragmentOffset = ipFRAGMENT_FLAGS_DONT_FRAGMENT; 970 #else 971 pxIPHeader->usFragmentOffset = 0U; 972 #endif 973 usPacketIdentifier++; 974 pxUDPHeader->usLength = FreeRTOS_htons( ( uint32_t ) lNetLength + 975 ipSIZE_OF_UDP_HEADER ); 976 vFlip_16( pxUDPHeader->usSourcePort, pxUDPHeader->usDestinationPort ); 977 978 /* Important: tell NIC driver how many bytes must be sent */ 979 uxDataLength = ( ( size_t ) lNetLength ) + uxIPHeaderLength + ipSIZE_OF_UDP_HEADER + ipSIZE_OF_ETH_HEADER; 980 } 981 982 #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) 983 { 984 #if ( ipconfigUSE_IPv6 != 0 ) 985 /* IPv6 IP-headers have no checksum field. */ 986 if( ( pxIPHeader->ucVersionHeaderLength & 0xf0U ) != 0x60U ) 987 #endif 988 { 989 /* Calculate the IP header checksum. */ 990 pxIPHeader->usHeaderChecksum = 0U; 991 pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), uxIPHeaderLength ); 992 pxIPHeader->usHeaderChecksum = ( uint16_t ) ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum ); 993 } 994 995 /* calculate the UDP checksum for outgoing package */ 996 ( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket, uxDataLength, pdTRUE ); 997 } 998 #endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */ 999 1000 /* Important: tell NIC driver how many bytes must be sent */ 1001 pxNetworkBuffer->xDataLength = uxDataLength; 1002 } 1003 1004 #endif /* ( ipconfigUSE_MDNS == 1 ) || ( ipconfigUSE_LLMNR == 1 ) || ( ipconfigUSE_NBNS == 1 ) */ 1005 1006 #if ( ipconfigUSE_NBNS == 1 ) 1007 1008 /** 1009 * @brief Respond to an NBNS query or an NBNS reply. 1010 * 1011 * @param[in] pucPayload the UDP payload of the NBNS message. 1012 * @param[in] uxBufferLength Length of the Buffer. 1013 * @param[in] ulIPAddress IP address of the sender. 1014 */ DNS_TreatNBNS(uint8_t * pucPayload,size_t uxBufferLength,uint32_t ulIPAddress)1015 void DNS_TreatNBNS( uint8_t * pucPayload, 1016 size_t uxBufferLength, 1017 uint32_t ulIPAddress ) 1018 { 1019 uint16_t usFlags, usType, usClass; 1020 uint8_t * pucSource, * pucTarget; 1021 uint8_t ucByte; 1022 uint8_t ucNBNSName[ 17 ]; 1023 uint8_t * pucUDPPayloadBuffer = pucPayload; 1024 size_t uxSizeNeeded; 1025 NetworkBufferDescriptor_t * pxNetworkBuffer; 1026 size_t uxBytesNeeded = sizeof( UDPPacket_t ) + sizeof( NBNSRequest_t ); 1027 BaseType_t xDNSHookReturn; 1028 uint16_t usLength; 1029 DNSMessage_t * pxMessage; 1030 NBNSAnswer_t * pxAnswer; 1031 1032 /* Introduce a do {} while (0) loop to allow the use of breaks. */ 1033 do 1034 { 1035 NetworkEndPoint_t xEndPoint; 1036 1037 /* Check for minimum buffer size: 92 bytes. */ 1038 if( uxBufferLength < uxBytesNeeded ) 1039 { 1040 break; 1041 } 1042 1043 /* Is a valid payload/network buffer provided? */ 1044 if( pucUDPPayloadBuffer == NULL ) 1045 { 1046 break; 1047 } 1048 1049 pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer ); 1050 1051 if( pxNetworkBuffer == NULL ) 1052 { 1053 break; 1054 } 1055 1056 /* Read the request flags in host endianness. */ 1057 usFlags = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usFlags ) ] ) ); 1058 1059 if( ( usFlags & dnsNBNS_FLAGS_OPCODE_MASK ) != dnsNBNS_FLAGS_OPCODE_QUERY ) 1060 { 1061 /* No need to answer, this is not a query. */ 1062 break; 1063 } 1064 1065 usType = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usType ) ] ) ); 1066 usClass = usChar2u16( &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usClass ) ] ) ); 1067 1068 /* Not used for now */ 1069 ( void ) usClass; 1070 1071 /* For NBNS a name is 16 bytes long, written with capitals only. 1072 * Make sure that the copy is terminated with a zero. */ 1073 pucTarget = &( ucNBNSName[ sizeof( ucNBNSName ) - 2U ] ); 1074 pucTarget[ 1 ] = ( uint8_t ) 0U; 1075 1076 /* Start with decoding the last 2 bytes. */ 1077 pucSource = &( pucUDPPayloadBuffer[ ( dnsNBNS_ENCODED_NAME_LENGTH - 2 ) + 1078 offsetof( NBNSRequest_t, ucName ) ] ); 1079 1080 for( ; ; ) 1081 { 1082 /* Define the ASCII value of the capital "A". */ 1083 const uint8_t ucCharA = ( uint8_t ) 0x41U; 1084 1085 ucByte = ( uint8_t ) ( ( ( pucSource[ 0 ] - ucCharA ) << 4 ) | 1086 ( pucSource[ 1 ] - ucCharA ) ); 1087 1088 /* Make sure there are no trailing spaces in the name. */ 1089 if( ( ucByte == ( uint8_t ) ' ' ) && ( pucTarget[ 1 ] == 0U ) ) 1090 { 1091 ucByte = 0U; 1092 } 1093 1094 *pucTarget = ucByte; 1095 1096 if( pucTarget == ucNBNSName ) 1097 { 1098 break; 1099 } 1100 1101 pucTarget -= 1; 1102 pucSource -= 2; 1103 } 1104 1105 #if ( ipconfigUSE_DNS_CACHE == 1 ) 1106 { 1107 if( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0U ) 1108 { 1109 /* If this is a response from another device, 1110 * add the name to the DNS cache */ 1111 IPv46_Address_t xIPAddress; 1112 1113 xIPAddress.xIPAddress.ulIP_IPv4 = ulIPAddress; 1114 #if ( ipconfigUSE_IPv6 != 0 ) 1115 { 1116 xIPAddress.xIs_IPv6 = pdFALSE; 1117 } 1118 #endif 1119 1120 ( void ) FreeRTOS_dns_update( ( char * ) ucNBNSName, &( xIPAddress ), 0, pdFALSE, NULL ); 1121 } 1122 } 1123 #else /* if ( ipconfigUSE_DNS_CACHE == 1 ) */ 1124 { 1125 /* Avoid compiler warnings. */ 1126 ( void ) ulIPAddress; 1127 } 1128 #endif /* ipconfigUSE_DNS_CACHE */ 1129 1130 if( ( usType != dnsNBNS_TYPE_NET_BIOS ) || 1131 ( ( usFlags & dnsNBNS_FLAGS_RESPONSE ) != 0U ) ) 1132 { 1133 /* The request is not for NBNS, or the response flag is set. */ 1134 break; 1135 } 1136 1137 /* When pxUDPPayloadBuffer_to_NetworkBuffer fails, there 1138 * is a real problem, like data corruption. */ 1139 if( pxNetworkBuffer->pxEndPoint == NULL ) 1140 { 1141 /* Should have been asserted earlier in the call tree. */ 1142 break; 1143 } 1144 1145 ( void ) memcpy( &xEndPoint, pxNetworkBuffer->pxEndPoint, sizeof( xEndPoint ) ); 1146 1147 /* NBNS only handles IPv4 or "A" records. */ 1148 xEndPoint.bits.bIPv6 = pdFALSE_UNSIGNED; 1149 xEndPoint.usDNSType = dnsTYPE_A_HOST; 1150 1151 #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) 1152 xDNSHookReturn = xApplicationDNSQueryHook( ( const char * ) ucNBNSName ); 1153 #else 1154 xDNSHookReturn = xApplicationDNSQueryHook_Multi( &( xEndPoint ), ( const char * ) ucNBNSName ); 1155 #endif 1156 1157 if( xDNSHookReturn == pdFALSE ) 1158 { 1159 /* The application informs that the name in 'ucNBNSName' 1160 * does not refer to this host. */ 1161 break; 1162 } 1163 1164 /* Someone is looking for a device with ucNBNSName, 1165 * prepare a positive reply. 1166 * The reply will be a bit longer than the request, so make some space. 1167 * NBNSAnswer_t will be added, minus the two shorts 'usType' and 'usClass' 1168 * that were already present. */ 1169 uxSizeNeeded = pxNetworkBuffer->xDataLength + sizeof( NBNSAnswer_t ) - 2 * sizeof( uint16_t ); 1170 1171 if( xBufferAllocFixedSize == pdFALSE ) 1172 { 1173 /* We're linked with BufferAlolocation_2.c 1174 * pxResizeNetworkBufferWithDescriptor() will malloc a new bigger buffer, 1175 * and memcpy the data. The old buffer will be free'd. 1176 */ 1177 NetworkBufferDescriptor_t * pxNewBuffer = pxResizeNetworkBufferWithDescriptor( pxNetworkBuffer, uxSizeNeeded ); 1178 1179 if( pxNewBuffer == NULL ) 1180 { 1181 break; 1182 } 1183 1184 /* pxNewBuffer and pxNetworkBuffer are now the same pointers. 1185 * Only pucEthernetBuffer has been renewed. */ 1186 pxNetworkBuffer->xDataLength = uxSizeNeeded; 1187 pucUDPPayloadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ); 1188 } 1189 else 1190 { 1191 /* BufferAllocation_1.c is used, the Network Buffers can contain at least 1192 * ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER. */ 1193 configASSERT( uxSizeNeeded < ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ); 1194 } 1195 1196 pxNetworkBuffer->xDataLength = uxSizeNeeded; 1197 1198 pxMessage = ( ( DNSMessage_t * ) pucUDPPayloadBuffer ); 1199 1200 /* As the fields in the structures are not word-aligned, we have to 1201 * copy the values byte-by-byte using macro's vSetField16() and vSetField32() */ 1202 vSetField16( pxMessage, DNSMessage_t, usFlags, dnsNBNS_QUERY_RESPONSE_FLAGS ); /* 0x8500 */ 1203 vSetField16( pxMessage, DNSMessage_t, usQuestions, 0 ); 1204 vSetField16( pxMessage, DNSMessage_t, usAnswers, 1 ); 1205 vSetField16( pxMessage, DNSMessage_t, usAuthorityRRs, 0 ); 1206 vSetField16( pxMessage, DNSMessage_t, usAdditionalRRs, 0 ); 1207 1208 pxAnswer = ( ( NBNSAnswer_t * ) &( pucUDPPayloadBuffer[ offsetof( NBNSRequest_t, usType ) ] ) ); 1209 1210 vSetField16( pxAnswer, NBNSAnswer_t, usType, usType ); /* Type */ 1211 vSetField16( pxAnswer, NBNSAnswer_t, usClass, dnsNBNS_CLASS_IN ); /* Class */ 1212 vSetField32( pxAnswer, NBNSAnswer_t, ulTTL, dnsNBNS_TTL_VALUE ); 1213 vSetField16( pxAnswer, NBNSAnswer_t, usDataLength, 6 ); /* 6 bytes including the length field */ 1214 vSetField16( pxAnswer, NBNSAnswer_t, usNbFlags, dnsNBNS_NAME_FLAGS ); 1215 /* The function vSetField32() expects host-endian values, that is why ntohl() is called. */ 1216 vSetField32( pxAnswer, NBNSAnswer_t, ulIPAddress, FreeRTOS_ntohl( xEndPoint.ipv4_settings.ulIPAddress ) ); 1217 1218 usLength = ( uint16_t ) ( sizeof( NBNSAnswer_t ) + ( size_t ) offsetof( NBNSRequest_t, usType ) ); 1219 1220 prepareReplyDNSMessage( pxNetworkBuffer, ( BaseType_t ) usLength ); 1221 1222 /* This function will fill in the eth addresses and send the packet */ 1223 vReturnEthernetFrame( pxNetworkBuffer, pdFALSE ); 1224 1225 /*pxNewBuffer and pxNetworkBuffer are now the same pointers.pxNetworkBuffer will be released elsewhere. 1226 * so pxNewBuffer does not need to released, since they share a single memory location*/ 1227 } while( ipFALSE_BOOL ); 1228 } 1229 #endif /* ( ipconfigUSE_NBNS == 1 ) */ 1230 1231 #endif /* ipconfigUSE_DNS != 0 */ 1232