[routing-manager] employ RA hash tracking to detect self-originating RAs (#9939)

This commit updates how `RoutingManager` differentiates between
self-generated RA messages and those from other sources sending RA on
the same device. This enables learning of the RA header, specifically
the default route lifetime.

This commit introduces a new mechanism to calculate and store a SHA256
hash of recently emitted RAs. Received RAs are cross-referenced
against the stored hashes to determine their origin. This replaces
the prior method, which relied on parsing and analyzing the included
options in the received RA.

A new test case is added in `test_routing_manager` to validate the
learning of RA header from other sources on same device.
This commit is contained in:
Abtin Keshavarzian
2024-03-26 11:13:41 -07:00
committed by GitHub
parent 4db6520d17
commit 4545daf010
3 changed files with 188 additions and 78 deletions
+102 -3
View File
@@ -160,6 +160,12 @@ bool sRespondToNs; // Indicates whether or not to respond to NS.
ExpectedPio sExpectedPio; // Expected PIO in the emitted RA by BR (MUST be seen in RA to set `sRaValidated`).
uint32_t sOnLinkLifetime; // Valid lifetime for local on-link prefix from the last processed RA.
// Indicate whether or not to check the emitted RA header (default route) lifetime
bool sCheckRaHeaderLifetime;
// Expected default route lifetime in emitted RA header by BR.
uint32_t sExpectedRaHeaderLifetime;
enum ExpectedRaHeaderFlags
{
kRaHeaderFlagsSkipChecking, // Skip checking the RA header flags.
@@ -424,7 +430,10 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
VerifyOrQuit(raMsg.IsValid());
VerifyOrQuit(raMsg.GetHeader().GetRouterLifetime() == 0);
if (sCheckRaHeaderLifetime)
{
VerifyOrQuit(raMsg.GetHeader().GetRouterLifetime() == sExpectedRaHeaderLifetime);
}
switch (sExpectedRaHeaderFlags)
{
@@ -1188,8 +1197,10 @@ void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false)
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
sRespondToNs = true;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
sRespondToNs = true;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 0;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ensure device starts as leader.
@@ -2950,6 +2961,93 @@ void TestLearningAndCopyingOfFlags(void)
FinalizeTest();
}
void TestLearnRaHeader(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestLearnRaHeader");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
VerifyDiscoveredRoutersIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from the same address (another entity on the device)
// advertising a default route.
SendRouterAdvert(sInfraIfAddress, DefaultRoute(1000, NetworkData::kRoutePreferenceLow));
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(sInfraIfAddress, /* M */ false, /* O */ false, /* StubRouter */ false)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// RoutingManager should learn the header from the
// received RA (from same address) and start advertising
// the same default route lifetime in the emitted RAs.
sRaValidated = false;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 1000;
AdvanceTime(30 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for longer than entry lifetime (for it to expire) and
// make sure `RoutingManager` stops advertising default route.
sCheckRaHeaderLifetime = false;
AdvanceTime(1000 * 1000);
sRaValidated = false;
sCheckRaHeaderLifetime = true;
sExpectedRaHeaderLifetime = 0;
AdvanceTime(700 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyDiscoveredRoutersIsEmpty();
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestLearnRaHeader");
FinalizeTest();
}
void TestConflictingPrefix(void)
{
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
@@ -3921,6 +4019,7 @@ int main(void)
ot::TestConflictingPrefix();
ot::TestRouterNsProbe();
ot::TestLearningAndCopyingOfFlags();
ot::TestLearnRaHeader();
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
ot::TestSavedOnLinkPrefixes();
#endif