From c14cc62ae681f5d15307572e1197481d1a4852cb Mon Sep 17 00:00:00 2001 From: "Adam St. Amand" Date: Mon, 6 Mar 2023 21:34:22 +0000 Subject: [PATCH] Allow use of loopback addresses in IP stack (127.0.0.0/8) --- source/FreeRTOS_ARP.c | 6 ++- source/FreeRTOS_IP.c | 2 + source/include/FreeRTOS_IP_Private.h | 4 ++ .../FreeRTOS_ARP/FreeRTOS_ARP_utest.c | 40 +++++++++++++++++++ .../unit-test/FreeRTOS_IP/FreeRTOS_IP_utest.c | 35 ++++++++++++++++ 5 files changed, 85 insertions(+), 2 deletions(-) diff --git a/source/FreeRTOS_ARP.c b/source/FreeRTOS_ARP.c index 453127dd1c..03156c97a7 100644 --- a/source/FreeRTOS_ARP.c +++ b/source/FreeRTOS_ARP.c @@ -413,7 +413,8 @@ BaseType_t xCheckRequiresARPResolution( const NetworkBufferDescriptor_t * pxNetw const IPPacket_t * pxIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); - if( ( pxIPHeader->ulSourceIPAddress & xNetworkAddressing.ulNetMask ) == ( *ipLOCAL_IP_ADDRESS_POINTER & xNetworkAddressing.ulNetMask ) ) + if( ( ( pxIPHeader->ulSourceIPAddress & xNetworkAddressing.ulNetMask ) == ( *ipLOCAL_IP_ADDRESS_POINTER & xNetworkAddressing.ulNetMask ) ) && + ( ( pxIPHeader->ulDestinationIPAddress & ipLOOPBACK_NETMASK ) != ( ipLOOPBACK_ADDRESS & ipLOOPBACK_NETMASK ) ) ) { /* If the IP is on the same subnet and we do not have an ARP entry already, * then we should send out ARP for finding the MAC address. */ @@ -726,7 +727,8 @@ eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress, * can be done. */ eReturn = eCantSendPacket; } - else if( *ipLOCAL_IP_ADDRESS_POINTER == *pulIPAddress ) + else if( ( *ipLOCAL_IP_ADDRESS_POINTER == *pulIPAddress ) || + ( ( *pulIPAddress & ipLOOPBACK_NETMASK ) == ( ipLOOPBACK_ADDRESS & ipLOOPBACK_NETMASK ) ) ) { /* The address of this device. May be useful for the loopback device. */ eReturn = eARPCacheHit; diff --git a/source/FreeRTOS_IP.c b/source/FreeRTOS_IP.c index 9e7fdf0901..df777be9ab 100644 --- a/source/FreeRTOS_IP.c +++ b/source/FreeRTOS_IP.c @@ -1446,6 +1446,8 @@ static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPP else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) && /* Is it the global broadcast address 255.255.255.255 ? */ ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) && + /* Is it a loopback address ? */ + ( ( ulDestinationIPAddress & ipLOOPBACK_NETMASK ) != ( ipLOOPBACK_ADDRESS & ipLOOPBACK_NETMASK ) ) && /* Is it a specific broadcast address 192.168.1.255 ? */ ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) && #if ( ipconfigUSE_LLMNR == 1 ) diff --git a/source/include/FreeRTOS_IP_Private.h b/source/include/FreeRTOS_IP_Private.h index 542c28b247..e14c19098f 100644 --- a/source/include/FreeRTOS_IP_Private.h +++ b/source/include/FreeRTOS_IP_Private.h @@ -387,6 +387,10 @@ extern const BaseType_t xBufferAllocFixedSize; * rather than duplicated in its own variable. */ #define ipLOCAL_MAC_ADDRESS ( xDefaultPartUDPPacketHeader.ucBytes ) +/* The loopback address block is defined as part of rfc5735 */ +#define ipLOOPBACK_ADDRESS ( FreeRTOS_inet_addr_quick( 127, 0, 0, 0 ) ) +#define ipLOOPBACK_NETMASK ( FreeRTOS_inet_addr_quick( 255, 0, 0, 0 ) ) + /* ICMP packets are sent using the same function as UDP packets. The port * number is used to distinguish between the two, as 0 is an invalid UDP port. */ #define ipPACKET_CONTAINS_ICMP_DATA ( 0 ) diff --git a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c index bcd3675681..ae48779853 100644 --- a/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c +++ b/test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c @@ -945,6 +945,29 @@ void test_xCheckRequiresARPResolution_OnLocalNetwork_InCache( void ) TEST_ASSERT_EQUAL( pdFALSE, xResult ); } +void test_xCheckRequiresARPResolution_OnLocalNetwork_Loopback( void ) +{ + NetworkBufferDescriptor_t xNetworkBuffer, * pxNetworkBuffer; + uint8_t ucEthernetBuffer[ ipconfigNETWORK_MTU ]; + BaseType_t xResult; + + pxNetworkBuffer = &xNetworkBuffer; + pxNetworkBuffer->pucEthernetBuffer = ucEthernetBuffer; + + IPPacket_t * pxIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ); + IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); + + *ipLOCAL_IP_ADDRESS_POINTER = ipLOOPBACK_ADDRESS; + + /* Make sure there is a match on source IP and loopback address */ + pxIPHeader->ulDestinationIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER & xNetworkAddressing.ulNetMask; + + xResult = xCheckRequiresARPResolution( pxNetworkBuffer ); + + TEST_ASSERT_EQUAL( pdFALSE, xResult ); +} + void test_ulARPRemoveCacheEntryByMac_NoMatch( void ) { @@ -1322,6 +1345,23 @@ void test_eARPGetCacheEntry_IPMatchesOtherBroadcastAddr( void ) /* =================================================== */ } +void test_eARPGetCacheEntry_IPMatchesLoopbackAddr( void ) +{ + uint32_t ulIPAddress; + MACAddress_t xMACAddress; + eARPLookupResult_t eResult; + uint32_t ulSavedGatewayAddress; + + /* =================================================== */ + ulIPAddress = ipLOOPBACK_ADDRESS; + /* Not worried about what these functions do. */ + xIsIPv4Multicast_ExpectAndReturn( ulIPAddress, 0UL ); + eResult = eARPGetCacheEntry( &ulIPAddress, &xMACAddress ); + TEST_ASSERT_EQUAL_MESSAGE( eARPCacheHit, eResult, "Test 3" ); + TEST_ASSERT_EQUAL_MEMORY_MESSAGE( &ipLOCAL_MAC_ADDRESS, &xMACAddress, sizeof( xMACAddress ), "Test 3" ); + /* =================================================== */ +} + void test_eARPGetCacheEntry_LocalIPIsZero( void ) { uint32_t ulIPAddress; diff --git a/test/unit-test/FreeRTOS_IP/FreeRTOS_IP_utest.c b/test/unit-test/FreeRTOS_IP/FreeRTOS_IP_utest.c index b955f6581b..d04c488a90 100644 --- a/test/unit-test/FreeRTOS_IP/FreeRTOS_IP_utest.c +++ b/test/unit-test/FreeRTOS_IP/FreeRTOS_IP_utest.c @@ -2249,6 +2249,41 @@ void test_prvAllowIPPacket_IncorrectProtocolChecksum( void ) TEST_ASSERT_EQUAL( eReleaseBuffer, eResult ); } +void test_prvAllowIPPacket_LoopbackDest( void ) +{ + eFrameProcessingResult_t eResult; + IPPacket_t * pxIPPacket; + NetworkBufferDescriptor_t * pxNetworkBuffer, xNetworkBuffer; + UBaseType_t uxHeaderLength = 0; + uint8_t ucEthBuffer[ ipconfigTCP_MSS ]; + IPHeader_t * pxIPHeader; + + memset( ucEthBuffer, 0, ipconfigTCP_MSS ); + + pxNetworkBuffer = &xNetworkBuffer; + pxNetworkBuffer->pucEthernetBuffer = ucEthBuffer; + pxIPPacket = ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer; + pxIPHeader = &( pxIPPacket->xIPHeader ); + + *ipLOCAL_IP_ADDRESS_POINTER = 0xFFFFFFFF; + + pxIPHeader->ucVersionHeaderLength = 0x45; + + pxIPHeader->ulDestinationIPAddress = ipLOOPBACK_ADDRESS; + + memcpy( pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes, &ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ); + + pxIPHeader->ulSourceIPAddress = 0xC0C00101; + + usGenerateChecksum_ExpectAndReturn( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength, ipCORRECT_CRC ); + + usGenerateProtocolChecksum_ExpectAndReturn( ( uint8_t * ) ( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE, ipCORRECT_CRC ); + + eResult = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength ); + + TEST_ASSERT_EQUAL( eProcessBuffer, eResult ); +} + void test_prvAllowIPPacket_HappyPath( void ) { eFrameProcessingResult_t eResult;