Skip to content

Commit

Permalink
Gratuituous ARP fixes (#988)
Browse files Browse the repository at this point in the history
* adding more checks for GARP

* adding more checks for GARP

* adding more checks for GARP

* more debug logs

* more debug logs

* more testing

* verify subnet

* fix formatting, cleaning up

* fix formatting, cleaning up

* adding unit tests

* updating review comments
  • Loading branch information
tony-josi-aws authored Aug 4, 2023
1 parent ae3cd02 commit 941cad7
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 12 deletions.
35 changes: 23 additions & 12 deletions source/FreeRTOS_ARP.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,22 +302,33 @@ static TickType_t xLastGratuitousARPTime = 0U;
eReturn = eReturnEthernetFrame;
}
}
else if( ulSenderProtocolAddress == ulTargetProtocolAddress ) /* Gratuitous ARP request? */
/* Check if its a Gratuitous ARP request and verify if it belongs to same subnet mask. */
else if( ( ulSenderProtocolAddress == ulTargetProtocolAddress ) &&
( ( ulSenderProtocolAddress & pxTargetEndPoint->ipv4_settings.ulNetMask ) == ( pxTargetEndPoint->ipv4_settings.ulNetMask & pxTargetEndPoint->ipv4_settings.ulIPAddress ) ) )
{
MACAddress_t xHardwareAddress;
NetworkEndPoint_t * pxCachedEndPoint;
const MACAddress_t xGARPTargetAddress = { { 0, 0, 0, 0, 0, 0 } };

pxCachedEndPoint = NULL;

/* The request is a Gratuitous ARP message.
* Refresh the entry if it already exists. */
/* Determine the ARP cache status for the requested IP address. */
if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEndPoint ) ) == eARPCacheHit )
/* Make sure target MAC address is either ff:ff:ff:ff:ff:ff or 00:00:00:00:00:00 and senders MAC
* address is not matching with the endpoint MAC address. */
if( ( ( memcmp( &( pxARPHeader->xTargetHardwareAddress ), xBroadcastMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ||
( ( memcmp( &( pxARPHeader->xTargetHardwareAddress ), xGARPTargetAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ) ) &&
( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes, ( pxARPHeader->xSenderHardwareAddress.ucBytes ), ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) )
{
/* Check if the endpoint matches with the one present in the ARP cache */
if( pxCachedEndPoint == pxTargetEndPoint )
MACAddress_t xHardwareAddress;
NetworkEndPoint_t * pxCachedEndPoint;

pxCachedEndPoint = NULL;

/* The request is a Gratuitous ARP message.
* Refresh the entry if it already exists. */
/* Determine the ARP cache status for the requested IP address. */
if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEndPoint ) ) == eARPCacheHit )
{
vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
/* Check if the endpoint matches with the one present in the ARP cache */
if( pxCachedEndPoint == pxTargetEndPoint )
{
vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
}
}
}
}
Expand Down
179 changes: 179 additions & 0 deletions test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,8 @@ void test_eARPProcessPacket_Request_GratuitousARP( void )
memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x34, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
xARPCache[ 0 ].pxEndPoint = &xEndPoint;

memset( &( xARPFrame.xARPHeader.xTargetHardwareAddress.ucBytes ), 0xff, sizeof( MACAddress_t ) );

/* Reset the private variable uxARPClashCounter. */
vResetARPClashCounter();

Expand Down Expand Up @@ -820,6 +822,183 @@ void test_eARPProcessPacket_Request_GratuitousARP_MACUnchanged( void )
/* =================================================== */
}

/**
* @brief This function verify receiving Gratuitous ARP packet
* but the sender protocol address is outside the subnet.
*/
void test_eARPProcessPacket_Request_GratuitousARP_OutOfSubnetIP( void )
{
ARPPacket_t xARPFrame = { 0 };
eFrameProcessingResult_t eResult;
NetworkInterface_t xInterface;
struct xNetworkEndPoint xEndPoint = { 0 };
NetworkBufferDescriptor_t xNetworkBuffer = { 0 };
uint32_t ulTargetIP = 0xAACCDDBB;

memset( &xARPFrame, 0, sizeof( ARPPacket_t ) );
memset( xARPCache, 0, sizeof( xARPCache ) );

/* =================================================== */
/* Add settings required for ARP header to pass checks */
xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET;
xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE;
xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES;
xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES;

/* Process an ARP request - meant for this node with target and source same. */
xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD;
xEndPoint.ipv4_settings.ulNetMask = 0xFFFF0000;
/* Fill in the request option. */
xARPFrame.xARPHeader.usOperation = ipARP_REQUEST;
xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP;
memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) );

memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) );

xARPCache[ 0 ].ulIPAddress = ulTargetIP;
xARPCache[ 0 ].ucAge = 1;
xARPCache[ 0 ].ucValid = pdTRUE;
memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
xARPCache[ 0 ].pxEndPoint = &xEndPoint;

/* Reset the private variable uxARPClashCounter. */
vResetARPClashCounter();

xNetworkBuffer.pucEthernetBuffer = &xARPFrame;
xNetworkBuffer.xDataLength = sizeof( ARPPacket_t );
xNetworkBuffer.pxEndPoint = &xEndPoint;
xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED;

eResult = eARPProcessPacket( &xNetworkBuffer );
TEST_ASSERT_EQUAL( eReleaseBuffer, eResult );
TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress );
TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge );
TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid );
TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint );
TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
/* =================================================== */
}

/**
* @brief This function verify receiving Gratuitous ARP packet
* but the new MAC address matches with the MAC address of the
* endpoint.
*/
void test_eARPProcessPacket_Request_GratuitousARP_MACMatchesWithEndpoint( void )
{
ARPPacket_t xARPFrame = { 0 };
eFrameProcessingResult_t eResult;
NetworkInterface_t xInterface;
struct xNetworkEndPoint xEndPoint = { 0 };
NetworkBufferDescriptor_t xNetworkBuffer = { 0 };
uint32_t ulTargetIP = 0xAACCDDBB;

memset( &xARPFrame, 0, sizeof( ARPPacket_t ) );
memset( xARPCache, 0, sizeof( xARPCache ) );

/* =================================================== */
/* Add settings required for ARP header to pass checks */
xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET;
xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE;
xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES;
xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES;

/* Process an ARP request - meant for this node with target and source same. */
xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD;
xEndPoint.ipv4_settings.ulNetMask = 0;
memset( xEndPoint.xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
/* Fill in the request option. */
xARPFrame.xARPHeader.usOperation = ipARP_REQUEST;
xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP;
memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) );

memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) );

xARPCache[ 0 ].ulIPAddress = ulTargetIP;
xARPCache[ 0 ].ucAge = 1;
xARPCache[ 0 ].ucValid = pdTRUE;
memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
xARPCache[ 0 ].pxEndPoint = &xEndPoint;

/* Reset the private variable uxARPClashCounter. */
vResetARPClashCounter();

xNetworkBuffer.pucEthernetBuffer = &xARPFrame;
xNetworkBuffer.xDataLength = sizeof( ARPPacket_t );
xNetworkBuffer.pxEndPoint = &xEndPoint;
xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED;

eResult = eARPProcessPacket( &xNetworkBuffer );
TEST_ASSERT_EQUAL( eReleaseBuffer, eResult );
TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress );
TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge );
TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid );
TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint );
TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
/* =================================================== */
}

/**
* @brief This function verify receiving Gratuitous ARP packet
* but the target MAC address in the ARP request is not a
* broadcast address.
*/
void test_eARPProcessPacket_Request_GratuitousARP_TargetHWAddressNotBroadcast( void )
{
ARPPacket_t xARPFrame = { 0 };
eFrameProcessingResult_t eResult;
NetworkInterface_t xInterface;
struct xNetworkEndPoint xEndPoint = { 0 };
NetworkBufferDescriptor_t xNetworkBuffer = { 0 };
uint32_t ulTargetIP = 0xAACCDDBB;

memset( &xARPFrame, 0, sizeof( ARPPacket_t ) );
memset( xARPCache, 0, sizeof( xARPCache ) );

/* =================================================== */
/* Add settings required for ARP header to pass checks */
xARPFrame.xARPHeader.usHardwareType = ipARP_HARDWARE_TYPE_ETHERNET;
xARPFrame.xARPHeader.usProtocolType = ipARP_PROTOCOL_TYPE;
xARPFrame.xARPHeader.ucHardwareAddressLength = ipMAC_ADDRESS_LENGTH_BYTES;
xARPFrame.xARPHeader.ucProtocolAddressLength = ipIP_ADDRESS_LENGTH_BYTES;

/* Process an ARP request - meant for this node with target and source same. */
xEndPoint.ipv4_settings.ulIPAddress = 0xAABBCCDD;
xEndPoint.ipv4_settings.ulNetMask = 0;
memset( xEndPoint.xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
/* Fill in the request option. */
xARPFrame.xARPHeader.usOperation = ipARP_REQUEST;
xARPFrame.xARPHeader.ulTargetProtocolAddress = ulTargetIP;
memcpy( xARPFrame.xARPHeader.ucSenderProtocolAddress, &( xARPFrame.xARPHeader.ulTargetProtocolAddress ), sizeof( xARPFrame.xARPHeader.ulTargetProtocolAddress ) );

memset( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), 0x22, sizeof( MACAddress_t ) );
memset( &( xARPFrame.xARPHeader.xTargetHardwareAddress.ucBytes ), 0x11, sizeof( MACAddress_t ) );

xARPCache[ 0 ].ulIPAddress = ulTargetIP;
xARPCache[ 0 ].ucAge = 1;
xARPCache[ 0 ].ucValid = pdTRUE;
memset( xARPCache[ 0 ].xMACAddress.ucBytes, 0x22, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
xARPCache[ 0 ].pxEndPoint = &xEndPoint;

/* Reset the private variable uxARPClashCounter. */
vResetARPClashCounter();

xNetworkBuffer.pucEthernetBuffer = &xARPFrame;
xNetworkBuffer.xDataLength = sizeof( ARPPacket_t );
xNetworkBuffer.pxEndPoint = &xEndPoint;
xEndPoint.bits.bEndPointUp = pdTRUE_UNSIGNED;

eResult = eARPProcessPacket( &xNetworkBuffer );
TEST_ASSERT_EQUAL( eReleaseBuffer, eResult );
TEST_ASSERT_EQUAL( ulTargetIP, xARPCache[ 0 ].ulIPAddress );
TEST_ASSERT_EQUAL( 1, xARPCache[ 0 ].ucAge );
TEST_ASSERT_EQUAL( pdTRUE, xARPCache[ 0 ].ucValid );
TEST_ASSERT_EQUAL( &xEndPoint, xARPCache[ 0 ].pxEndPoint );
TEST_ASSERT_EQUAL_MEMORY( &( xARPFrame.xARPHeader.xSenderHardwareAddress.ucBytes ), xARPCache[ 0 ].xMACAddress.ucBytes, sizeof( xARPCache[ 0 ].xMACAddress.ucBytes ) );
/* =================================================== */
}


/**
* @brief This function verify receiving Gratuitous ARP packet
* but the packet is received in a different endpoint compared
Expand Down

0 comments on commit 941cad7

Please sign in to comment.