Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 70 additions & 26 deletions source/FreeRTOS_DNS_Parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@
BaseType_t xReturn = pdTRUE;
uint32_t ulIPAddress = 0U;
BaseType_t xDNSHookReturn = 0U;
NetworkBufferDescriptor_t * pxNewBuffer = NULL;

( void ) memset( &( xSet ), 0, sizeof( xSet ) );
xSet.usPortNumber = usPort;
Expand Down Expand Up @@ -383,6 +384,13 @@
xSet.pucByte = &( xSet.pucByte[ uxResult ] );
xSet.uxSourceBytesRemaining -= uxResult;

if( ( x == 0U ) && ( xSet.usPortNumber == ipMDNS_PORT ) )
{
/* Note that the Questions section turns into the Answers section.
* uxSkipCount points to the first byte after e.g. 'name.local' */
xSet.uxSkipCount = ( size_t ) ( xSet.pucByte - pucUDPPayloadBuffer );
}

/* Check the remaining buffer size. */
if( xSet.uxSourceBytesRemaining >= sizeof( uint32_t ) )
{
Expand Down Expand Up @@ -430,6 +438,21 @@
NetworkEndPoint_t * pxEndPoint, xEndPoint;
size_t uxUDPOffset;

#if ( ipconfigUSE_IPv6 == 0 )
/* Don't treat AAAA request when IPv6 is not enabled. */
if( xSet.usType == dnsTYPE_AAAA_HOST )
{
break;
}
#endif
#if ( ipconfigUSE_IPv4 == 0 )
/* Don't treat A request when IPv4 is not enabled. */
if( xSet.usType == dnsTYPE_A_HOST )
{
break;
}
#endif

pxNetworkBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pucUDPPayloadBuffer );

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

xEndPoint.usDNSType = ( uint8_t ) xSet.usType;
}
Expand All @@ -482,24 +505,26 @@
if( xDNSHookReturn != pdFALSE )
{
int16_t usLength;
NetworkBufferDescriptor_t * pxNewBuffer = NULL;
LLMNRAnswer_t * pxAnswer;
uint8_t * pucNewBuffer = NULL;
size_t uxExtraLength;
size_t uxDataLength = uxBufferLength +
sizeof( UDPHeader_t ) +
sizeof( EthernetHeader_t ) +
uxIPHeaderSizePacket( pxNetworkBuffer );
/* Number of bytes to write the Answers section: 16 (A) or 28 (AAAA). */
size_t uxExtraLength = 0U;
size_t uxDataLength = uxBufferLength + /* Length of the UDP payload buffer */
sizeof( UDPHeader_t ) + /* Length of the UDP header */
sizeof( EthernetHeader_t ) + /* Length of the Ethernet header */
uxIPHeaderSizePacket( pxNetworkBuffer ); /* Lentgh of IP 20 or 40. */

#if ( ipconfigUSE_IPv6 != 0 )
if( xSet.usType == dnsTYPE_AAAA_HOST )
{
/* The number of bytes needed by Answers section (28 bytes). */
uxExtraLength = sizeof( LLMNRAnswer_t ) + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress );
}
else
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
#if ( ipconfigUSE_IPv4 != 0 )
{
/* The number of bytes needed by Answers section (16 bytes). */
uxExtraLength = sizeof( LLMNRAnswer_t );
}
#else /* ( ipconfigUSE_IPv4 != 0 ) */
Expand All @@ -510,7 +535,8 @@

if( xBufferAllocFixedSize == pdFALSE )
{
/* Set the size of the outgoing packet. */
/* Set the size of the outgoing packet.
* setting 'xDataLength' determines the minimum number of bytes copied. */
pxNetworkBuffer->xDataLength = uxDataLength;
pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer,
uxDataLength +
Expand Down Expand Up @@ -553,50 +579,63 @@

if( ( pxNetworkBuffer != NULL ) )
{
pxAnswer = ( ( LLMNRAnswer_t * ) xSet.pucByte );
size_t uxDistance;

/* We leave 'usIdentifier' and 'usQuestions' untouched */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_RESPONSE ); /* Set the response flag */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */
if( xSet.uxSkipCount >= 2 )
{
/* Four bytes back to write usType/usClass. */
pxAnswer = ( LLMNRAnswer_t * ) ( &( pucNewBuffer[ xSet.uxSkipCount - 2 ] ) );
/* Follow RFC6762 to set QR bit (section 18.2) and authoritative answer (AA) bit (section 18.4). */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsMDNS_FLAGS_IS_RESPONSE );
/* When replying to an mDNS request, do not include the Questions section. */
xSet.usQuestions = 0;
}
else
{
pxAnswer = ( ( LLMNRAnswer_t * ) xSet.pucByte );
/* Follow RFC4795 to set QR bit (section 2.1.1) */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usFlags, dnsLLMNR_FLAGS_IS_RESPONSE );
}

pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
pxAnswer->ucNameOffset = ( uint8_t ) ( xSet.pcRequestedName - ( char * ) pucNewBuffer );
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usQuestions, xSet.usQuestions ); /* Might be zero. */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAnswers, 1 ); /* Provide a single answer */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAuthorityRRs, 0 ); /* No authority */
vSetField16( xSet.pxDNSMessageHeader, DNSMessage_t, usAdditionalRRs, 0 ); /* No additional info */

if( xSet.usQuestions > 0 )
{
pxAnswer->ucNameCode = dnsNAME_IS_OFFSET;
pxAnswer->ucNameOffset = ( uint8_t ) ( xSet.pcRequestedName - ( char * ) pucNewBuffer );
}

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

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

#if ( ipconfigUSE_IPv6 != 0 )
if( xSet.usType == dnsTYPE_AAAA_HOST )
{
size_t uxDistance;
vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ipSIZE_OF_IPv6_ADDRESS );
( void ) memcpy( &( pxAnswer->ulIPAddress ), xEndPoint.ipv6_settings.xIPAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer );
/* An extra 12 bytes will be sent compared to an A-record. */
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance + ipSIZE_OF_IPv6_ADDRESS - sizeof( pxAnswer->ulIPAddress ) );
}
else
#endif /* ( ipconfigUSE_IPv6 != 0 ) */
{
size_t uxDistance;
vSetField16( pxAnswer, LLMNRAnswer_t, usDataLength, ( uint16_t ) sizeof( pxAnswer->ulIPAddress ) );
vSetField32( pxAnswer, LLMNRAnswer_t, ulIPAddress, FreeRTOS_ntohl( xEndPoint.ipv4_settings.ulIPAddress ) );
uxDistance = ( size_t ) ( xSet.pucByte - pucNewBuffer );
usLength = ( int16_t ) ( sizeof( *pxAnswer ) + uxDistance );
}

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

if( pxNewBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
}
/* This function will fill in the eth addresses and send the packet.
* xReleaseAfterSend = pdFALSE. */
vReturnEthernetFrame( pxNetworkBuffer, pdFALSE );
}
}
else
Expand All @@ -607,6 +646,11 @@
#endif /* ipconfigUSE_LLMNR == 1 */
( void ) uxBytesRead;
} while( ipFALSE_BOOL );

if( pxNewBuffer != NULL )
{
vReleaseNetworkBufferAndDescriptor( pxNewBuffer );
}
}

if( xReturn == pdFALSE )
Expand Down
13 changes: 8 additions & 5 deletions source/include/FreeRTOS_DNS_Globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,14 @@
#define ipLLMNR_IP_ADDR 0xFC0000E0UL
#endif /* ipconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN */

#define ipMDNS_TIME_TO_LIVE 255U
/* MDNS constants. */
#define ipMDNS_TIME_TO_LIVE 255U
#define dnsMDNS_FLAGS_IS_RESPONSE 0x8400U /**< MDNS flag value for response. */

#define ipLLMNR_PORT 5355U /* Standard LLMNR port. */
#define ipDNS_PORT 53U /* Standard DNS port. */
#define ipNBNS_PORT 137U /* NetBIOS Name Service. */
#define ipNBDGM_PORT 138U /* Datagram Service, not included. */
#define ipLLMNR_PORT 5355U /* Standard LLMNR port. */
#define ipDNS_PORT 53U /* Standard DNS port. */
#define ipNBNS_PORT 137U /* NetBIOS Name Service. */
#define ipNBDGM_PORT 138U /* Datagram Service, not included. */

/** @brief freertos_addrinfo is the equivalent of 'struct addrinfo'. */
struct freertos_addrinfo
Expand Down Expand Up @@ -175,6 +177,7 @@
uint16_t usAnswers; /**< The number of DNS answers that were given. */
uint8_t * pucUDPPayloadBuffer; /**< A pointer to the original UDP load buffer. */
uint8_t * pucByte; /**< A pointer that is used while parsing. */
size_t uxSkipCount; /**< Points to the byte after the complete name (mDNS only) */
size_t uxBufferLength; /**< The total number of bytes received in the UDP payload. */
size_t uxSourceBytesRemaining; /**< As pucByte is incremented, 'uxSourceBytesRemaining' will be decremented. */
uint16_t usType; /**< The type of address, recognised are dnsTYPE_A_HOST ( Ipv4 ) and
Expand Down
65 changes: 65 additions & 0 deletions test/unit-test/FreeRTOS_DNS_Parser/FreeRTOS_DNS_Parser_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -4025,3 +4025,68 @@ void test_prepareReplyDNSMessage_null_pointer( void )
uxIPHeaderSizePacket_IgnoreAndReturn( ipSIZE_OF_IPv4_HEADER );
catch_assert( prepareReplyDNSMessage( &pxNetworkBuffer, lNetLength ) );
}

void test_DNS_ParseDNSReply_mdns_request( void )
{
uint32_t ret;
uint8_t pucPacketBuffer[ 312 ];
size_t uxBufferLength = 250;
char dns[ 64 ];
struct freertos_addrinfo * pxAddressInfo;
uint16_t usPort = ipMDNS_PORT;
uint8_t * pucPayloadBuffer = pucPacketBuffer + sizeof( UDPPacket_t ); /* Skip 42 bytes. */

memset( dns, 'a', 64 );
memset( pucPacketBuffer, 0x00, sizeof pucPacketBuffer );
dns[ 63 ] = 0;
BaseType_t xExpected = pdFALSE;
size_t beg = sizeof( DNSMessage_t ); /* 8 x 2 = 16 bytes */
NetworkEndPoint_t xEndPoint = { 0 };

DNSMessage_t * dns_header;

NetworkBufferDescriptor_t xNetworkBuffer = { 0 };

xNetworkBuffer.pucEthernetBuffer = pucPacketBuffer;
xNetworkBuffer.pxEndPoint = &xEndPoint;
xEndPoint.ipv4_settings.ulIPAddress = 0xC0A8020B;

dns_header = ( DNSMessage_t * ) pucPayloadBuffer; /* pucPayloadBuffer without '&' */

dns_header->usQuestions = FreeRTOS_htons( 1 );
dns_header->usAnswers = FreeRTOS_htons( 2 );
dns_header->usFlags = 0; /* dnsEXPECTED_RX_FLAGS; */

/* Question-1: */
pucPayloadBuffer[ beg ] = 38; /* Length of name. */
beg++; /* Skip the length byte. */
strcpy( pucPayloadBuffer + beg, "FreeRTOSbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" );
beg += 38 + 1 + 4; /* Skip name, nul-byte, and Type/Class. */

/* xApplicationDNSQueryHook_Multi() must be called. */
hook_return = pdTRUE;
/* it hasn't been called yet. */
hook_called = pdFALSE;

usChar2u16_ExpectAnyArgsAndReturn( 0x0001 ); /* usType */
usChar2u16_ExpectAnyArgsAndReturn( 0x0001 ); /* usClass */
pxUDPPayloadBuffer_to_NetworkBuffer_ExpectAnyArgsAndReturn( &xNetworkBuffer );
uxIPHeaderSizePacket_IgnoreAndReturn( ipSIZE_OF_IPv4_HEADER );

pxDuplicateNetworkBufferWithDescriptor_ExpectAnyArgsAndReturn( &xNetworkBuffer );

usGenerateChecksum_ExpectAnyArgsAndReturn( 555 );
usGenerateProtocolChecksum_ExpectAnyArgsAndReturn( 444 );

vReturnEthernetFrame_Expect( &xNetworkBuffer, pdFALSE );
vReleaseNetworkBufferAndDescriptor_Expect( &xNetworkBuffer );

ret = DNS_ParseDNSReply( pucPayloadBuffer,
beg, /* uxBufferLength, */
&pxAddressInfo,
xExpected,
usPort );

TEST_ASSERT_EQUAL( pdFALSE, ret );
ASSERT_DNS_QUERY_HOOK_CALLED();
}
Loading