Skip to content

Commit 0db698c

Browse files
committed
mDNS: when a reply do not repeat the questions, set authoritative flag
1 parent a4b6330 commit 0db698c

File tree

2 files changed

+73
-26
lines changed

2 files changed

+73
-26
lines changed

source/FreeRTOS_DNS_Parser.c

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@
263263
BaseType_t xReturn = pdTRUE;
264264
uint32_t ulIPAddress = 0U;
265265
BaseType_t xDNSHookReturn = 0U;
266+
NetworkBufferDescriptor_t * pxNewBuffer = NULL;
266267

267268
( void ) memset( &( xSet ), 0, sizeof( xSet ) );
268269
xSet.usPortNumber = usPort;
@@ -383,6 +384,13 @@
383384
xSet.pucByte = &( xSet.pucByte[ uxResult ] );
384385
xSet.uxSourceBytesRemaining -= uxResult;
385386

387+
if( ( x == 0U ) && ( xSet.usPortNumber == ipMDNS_PORT ) )
388+
{
389+
/* Note that the Questions section turns into the Answers section.
390+
* uxSkipCount points to the first byte after e.g. 'name.local' */
391+
xSet.uxSkipCount = ( size_t ) ( xSet.pucByte - pucUDPPayloadBuffer );
392+
}
393+
386394
/* Check the remaining buffer size. */
387395
if( xSet.uxSourceBytesRemaining >= sizeof( uint32_t ) )
388396
{
@@ -430,6 +438,21 @@
430438
NetworkEndPoint_t * pxEndPoint, xEndPoint;
431439
size_t uxUDPOffset;
432440

441+
#if ( ipconfigUSE_IPv6 == 0 )
442+
/* Don't treat AAAA request when IPv6 is not enabled. */
443+
if( xSet.usType == dnsTYPE_AAAA_HOST )
444+
{
445+
break;
446+
}
447+
#endif
448+
#if ( ipconfigUSE_IPv4 == 0 )
449+
/* Don't treat A request when IPv4 is not enabled. */
450+
if( xSet.usType == dnsTYPE_A_HOST )
451+
{
452+
break;
453+
}
454+
#endif
455+
433456
pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );
434457

435458
/* This test could be replaced with a assert(). */
@@ -458,7 +481,7 @@
458481
#if ( ipconfigUSE_IPv6 != 0 )
459482
{
460483
/*logging*/
461-
FreeRTOS_printf( ( "prvParseDNS_HandleLLMNRRequest[%s]: type %04X\n", xSet.pcName, xSet.usType ) );
484+
FreeRTOS_printf( ( "DNS_ParseDNSReply[%s]: type %04X\n", xSet.pcName, xSet.usType ) );
462485

463486
xEndPoint.usDNSType = ( uint8_t ) xSet.usType;
464487
}
@@ -482,24 +505,26 @@
482505
if( xDNSHookReturn != pdFALSE )
483506
{
484507
int16_t usLength;
485-
NetworkBufferDescriptor_t * pxNewBuffer = NULL;
486508
LLMNRAnswer_t * pxAnswer;
487509
uint8_t * pucNewBuffer = NULL;
488-
size_t uxExtraLength;
489-
size_t uxDataLength = uxBufferLength +
490-
sizeof( UDPHeader_t ) +
491-
sizeof( EthernetHeader_t ) +
492-
uxIPHeaderSizePacket( pxNetworkBuffer );
510+
/* Number of bytes to write the Answers section: 16 (A) or 28 (AAAA). */
511+
size_t uxExtraLength = 0U;
512+
size_t uxDataLength = uxBufferLength + /* Length of the UDP payload buffer */
513+
sizeof( UDPHeader_t ) + /* Length of the UDP header */
514+
sizeof( EthernetHeader_t ) + /* Length of the Ethernet header */
515+
uxIPHeaderSizePacket( pxNetworkBuffer ); /* Lentgh of IP 20 or 40. */
493516

494517
#if ( ipconfigUSE_IPv6 != 0 )
495518
if( xSet.usType == dnsTYPE_AAAA_HOST )
496519
{
520+
/* The number of bytes needed by Answers section (28 bytes). */
497521
uxExtraLength = sizeof( LLMNRAnswer_t ) + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress );
498522
}
499523
else
500524
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
501525
#if ( ipconfigUSE_IPv4 != 0 )
502526
{
527+
/* The number of bytes needed by Answers section (16 bytes). */
503528
uxExtraLength = sizeof( LLMNRAnswer_t );
504529
}
505530
#else /* ( ipconfigUSE_IPv4 != 0 ) */
@@ -510,7 +535,8 @@
510535

511536
if( xBufferAllocFixedSize == pdFALSE )
512537
{
513-
/* Set the size of the outgoing packet. */
538+
/* Set the size of the outgoing packet.
539+
* setting 'xDataLength' determines the minimum number of bytes copied. */
514540
pxNetworkBuffer->xDataLength = uxDataLength;
515541
pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer,
516542
uxDataLength +
@@ -553,50 +579,63 @@
553579

554580
if( ( pxNetworkBuffer != NULL ) )
555581
{
556-
pxAnswer = ( ( LLMNRAnswer_t * ) xSet.pucByte );
582+
size_t uxDistance;
583+
557584
/* We leave 'usIdentifier' and 'usQuestions' untouched */
558-
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_RESPONSE ); /* Set the response flag */
559-
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
560-
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
561-
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
585+
if( xSet.uxSkipCount >= 2 )
586+
{
587+
/* Four bytes back to write usType/usClass. */
588+
pxAnswer = ( LLMNRAnswer_t * ) ( &( pucNewBuffer[ xSet.uxSkipCount - 2 ] ) );
589+
/* Follow RFC6762 to set QR bit (section 18.2) and authoritative answer (AA) bit (section 18.4). */
590+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsMDNS_FLAGS_IS_RESPONSE );
591+
/* When replying to an mDNS request, do not include the Questions section. */
592+
xSet.usQuestions = 0;
593+
}
594+
else
595+
{
596+
pxAnswer = ( ( LLMNRAnswer_t * ) xSet.pucByte );
597+
/* Follow RFC4795 to set QR bit (section 2.1.1) */
598+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_RESPONSE );
599+
}
562600

563-
pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
564-
pxAnswer->ucNameOffset = ( uint8_t ) ( xSet.pcRequestedName - ( char * ) pucNewBuffer );
601+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usQuestions, xSet.usQuestions ); /* Might be zero. */
602+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
603+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
604+
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
605+
606+
if( xSet.usQuestions > 0 )
607+
{
608+
pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
609+
pxAnswer->ucNameOffset = ( uint8_t ) ( xSet.pcRequestedName - ( char * ) pucNewBuffer );
610+
}
565611

566612
vSetField16( pxAnswer, LLMNRAnswer_t, usType, xSet.usType ); /* Type A or AAAA: host */
567613
vSetField16( pxAnswer, LLMNRAnswer_t, usClass, dnsCLASS_IN ); /* 1: Class IN */
568614
vSetField32( pxAnswer, LLMNRAnswer_t, ulTTL, dnsLLMNR_TTL_VALUE );
569615

570-
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + ( size_t ) ( xSet.pucByte - pucNewBuffer ) );
616+
uxDistance = ( size_t ) ( ( ( const uint8_t * ) pxAnswer ) - pucNewBuffer );
571617

572618
#if ( ipconfigUSE_IPv6 != 0 )
573619
if( xSet.usType == dnsTYPE_AAAA_HOST )
574620
{
575-
size_t uxDistance;
576621
vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ipSIZE_OF_IPv6_ADDRESS );
577622
( void ) memcpy( &( pxAnswer->ulIPAddress ), xEndPoint.ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
578-
uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer );
579623
/* An extra 12 bytes will be sent compared to an A-record. */
580624
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress ) );
581625
}
582626
else
583627
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
584628
{
585-
size_t uxDistance;
586629
vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ( uint16_t ) sizeof( pxAnswer->ulIPAddress ) );
587630
vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( xEndPoint.ipv4_settings.ulIPAddress ) );
588-
uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer );
589631
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance );
590632
}
591633

592634
prepareReplyDNSMessage( pxNetworkBuffer, usLength );
593-
/* This function will fill in the eth addresses and send the packet */
594-
vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
595635

596-
if( pxNewBuffer != NULL )
597-
{
598-
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
599-
}
636+
/* This function will fill in the eth addresses and send the packet.
637+
* xReleaseAfterSend = pdFALSE. */
638+
vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
600639
}
601640
}
602641
else
@@ -607,6 +646,11 @@
607646
#endif /* ipconfigUSE_LLMNR == 1 */
608647
( void ) uxBytesRead;
609648
} while( ipFALSE_BOOL );
649+
650+
if( pxNewBuffer != NULL )
651+
{
652+
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
653+
}
610654
}
611655

612656
if( xReturn == pdFALSE )

source/include/FreeRTOS_DNS_Globals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@
109109
#define ipLLMNR_IP_ADDR 0xFC0000E0UL
110110
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */
111111

112+
/* MDNS constants. */
112113
#define ipMDNS_TIME_TO_LIVE 255U
114+
#define dnsMDNS_FLAGS_IS_RESPONSE 0x8400U /**< MDNS flag value for response. */
113115

114116
#define ipLLMNR_PORT 5355U /* Standard LLMNR port. */
115117
#define ipDNS_PORT 53U /* Standard DNS port. */
@@ -175,6 +177,7 @@
175177
uint16_t usAnswers; /**< The number of DNS answers that were given. */
176178
uint8_t * pucUDPPayloadBuffer; /**< A pointer to the original UDP load buffer. */
177179
uint8_t * pucByte; /**< A pointer that is used while parsing. */
180+
size_t uxSkipCount; /**< Points to the byte after the complete name (mDNS only) */
178181
size_t uxBufferLength; /**< The total number of bytes received in the UDP payload. */
179182
size_t uxSourceBytesRemaining; /**< As pucByte is incremented, 'uxSourceBytesRemaining' will be decremented. */
180183
uint16_t usType; /**< The type of address, recognised are dnsTYPE_A_HOST ( Ipv4 ) and

0 commit comments

Comments
 (0)