mirror of
https://github.com/espressif/openthread.git
synced 2026-10-06 07:47:41 +00:00
[ip6] update MPL option processing and validation (#11816)
This commit enhances MPL option processing and validation. Previously, the MPL option was processed immediately upon being found, and multiple MPL options in the same message were accepted. This could allow a malformed IPv6 message to be buffered for MPL re-transmission multiple times with different seed IDs. This change ensures the code first iterates through and validates all included options within a Hop-by-Hop extension header, enforcing that at most one MPL option is present before processing. This is implemented by splitting `Mpl::ProcessOption()` into `ReadAndValidateOption()` and a new version of `ProcessOption()` that acts on a pre-validated `MplOption`.
This commit is contained in:
+18
-2
@@ -508,15 +508,22 @@ exit:
|
||||
|
||||
Error Ip6::HandleOptions(Message &aMessage, const Header &aHeader, bool &aReceive)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
bool hasMplOption = false;
|
||||
HopByHopHeader hbhHeader;
|
||||
Option option;
|
||||
OffsetRange offsetRange;
|
||||
MplOption mplOption;
|
||||
|
||||
offsetRange.InitFromMessageOffsetToEnd(aMessage);
|
||||
|
||||
SuccessOrExit(error = ReadHopByHopHeader(aMessage, offsetRange, hbhHeader));
|
||||
|
||||
// `ReadHopByHopHeader()` updates `offsetRange` to refer to the
|
||||
// location of the options within the HBH header. We first
|
||||
// validate all options, ensuring there is at most one MPL
|
||||
// option, before processing it.
|
||||
|
||||
for (; !offsetRange.IsEmpty(); offsetRange.AdvanceOffset(option.GetSize()))
|
||||
{
|
||||
SuccessOrExit(error = option.ParseFrom(aMessage, offsetRange));
|
||||
@@ -528,13 +535,22 @@ Error Ip6::HandleOptions(Message &aMessage, const Header &aHeader, bool &aReceiv
|
||||
|
||||
if (option.GetType() == MplOption::kType)
|
||||
{
|
||||
SuccessOrExit(error = mMpl.ProcessOption(aMessage, offsetRange, aHeader.GetSource(), aReceive));
|
||||
VerifyOrExit(!hasMplOption, error = kErrorDrop);
|
||||
hasMplOption = true;
|
||||
|
||||
SuccessOrExit(error = mMpl.ReadAndValidateOption(aMessage, offsetRange, aHeader.GetSource(), mplOption));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
VerifyOrExit(option.GetAction() == Option::kActionSkip, error = kErrorDrop);
|
||||
}
|
||||
|
||||
if (hasMplOption)
|
||||
{
|
||||
SuccessOrExit(error = mMpl.ProcessOption(aMessage, mplOption, aReceive));
|
||||
}
|
||||
|
||||
aMessage.SetOffset(offsetRange.GetEndOffset());
|
||||
|
||||
exit:
|
||||
|
||||
+21
-12
@@ -83,25 +83,27 @@ void Mpl::InitOption(MplOption &aOption, const Address &aAddress)
|
||||
aOption.SetSequence(mSequence++);
|
||||
}
|
||||
|
||||
Error Mpl::ProcessOption(Message &aMessage, const OffsetRange &aOffsetRange, const Address &aAddress, bool &aReceive)
|
||||
Error Mpl::ReadAndValidateOption(Message &aMessage,
|
||||
const OffsetRange &aOffsetRange,
|
||||
const Address &aAddress,
|
||||
MplOption &aOption)
|
||||
{
|
||||
Error error;
|
||||
MplOption option;
|
||||
Error error;
|
||||
|
||||
// Read the min size bytes first, then check the expected
|
||||
// `SeedIdLength` and read the full `MplOption` if needed.
|
||||
SuccessOrExit(error = aMessage.Read(aOffsetRange, &option, MplOption::kMinSize));
|
||||
SuccessOrExit(error = aMessage.Read(aOffsetRange, &aOption, MplOption::kMinSize));
|
||||
|
||||
switch (option.GetSeedIdLength())
|
||||
switch (aOption.GetSeedIdLength())
|
||||
{
|
||||
case MplOption::kSeedIdLength0:
|
||||
// Retrieve Seed ID from the IPv6 Source Address RLOC.
|
||||
VerifyOrExit(aAddress.GetIid().IsLocator(), error = kErrorDrop);
|
||||
option.SetSeedId(aAddress.GetIid().GetLocator());
|
||||
VerifyOrExit(aAddress.GetIid().IsLocator(), error = kErrorParse);
|
||||
aOption.SetSeedId(aAddress.GetIid().GetLocator());
|
||||
break;
|
||||
|
||||
case MplOption::kSeedIdLength2:
|
||||
SuccessOrExit(error = aMessage.Read(aOffsetRange, option));
|
||||
SuccessOrExit(error = aMessage.Read(aOffsetRange, aOption));
|
||||
break;
|
||||
|
||||
case MplOption::kSeedIdLength8:
|
||||
@@ -109,13 +111,21 @@ Error Mpl::ProcessOption(Message &aMessage, const OffsetRange &aOffsetRange, con
|
||||
ExitNow(error = kErrorParse);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Mpl::ProcessOption(Message &aMessage, const MplOption &aOption, bool &aReceive)
|
||||
{
|
||||
Error error;
|
||||
|
||||
// Check if the MPL Data Message is new.
|
||||
error = UpdateSeedSet(option.GetSeedId(), option.GetSequence());
|
||||
error = UpdateSeedSet(aOption.GetSeedId(), aOption.GetSequence());
|
||||
|
||||
if (error == kErrorNone)
|
||||
{
|
||||
#if OPENTHREAD_FTD
|
||||
AddBufferedMessage(aMessage, option.GetSeedId(), option.GetSequence());
|
||||
AddBufferedMessage(aMessage, aOption.GetSeedId(), aOption.GetSequence());
|
||||
#endif
|
||||
}
|
||||
else if (!aMessage.IsOriginThreadNetif())
|
||||
@@ -123,10 +133,9 @@ Error Mpl::ProcessOption(Message &aMessage, const OffsetRange &aOffsetRange, con
|
||||
aReceive = false;
|
||||
// In case MPL Data Message is generated locally, ignore potential error of the MPL Seed Set
|
||||
// to allow subsequent retransmissions with the same sequence number.
|
||||
ExitNow(error = kErrorNone);
|
||||
error = kErrorNone;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
@@ -171,21 +171,33 @@ public:
|
||||
void InitOption(MplOption &aOption, const Address &aAddress);
|
||||
|
||||
/**
|
||||
* Processes an MPL option. When the MPL module acts as an MPL Forwarder
|
||||
* it disseminates MPL Data Message using Trickle timer expirations. When acts as an
|
||||
* MPL Seed it allows to send the first MPL Data Message directly, then sets up Trickle
|
||||
* timer expirations for subsequent retransmissions.
|
||||
* Reads and validates an MPL option from a given message.
|
||||
*
|
||||
* @param[in] aMessage A reference to the message.
|
||||
* @param[in] aOffsetRange The offset range in @p aMessage to read the MPL option.
|
||||
* @param[in] aAddress A reference to the IPv6 Source Address.
|
||||
* @param[in] aMessage The message from which to read the option.
|
||||
* @param[in] aOffsetRange The offset range within @p aMessage to read from.
|
||||
* @param[in] aAddress A reference to the IPv6 source address.
|
||||
* @param[out] aOption An `MplOption` object to populate with the read option.
|
||||
*
|
||||
* @retval kErrorNone Successfully read and validated the MPL option.
|
||||
* @retval kErrorParse Failed to parse the option. Invalid format.
|
||||
*/
|
||||
Error ReadAndValidateOption(Message &aMessage,
|
||||
const OffsetRange &aOffsetRange,
|
||||
const Address &aAddress,
|
||||
MplOption &aOption);
|
||||
|
||||
/**
|
||||
* Processes a previously read and validated MPL option.
|
||||
*
|
||||
* @param[in] aMessage The message.
|
||||
* @param[in] aOption The MPL option.
|
||||
* @param[out] aReceive Set to FALSE if the MPL message is a duplicate and must not
|
||||
* go through the receiving process again, untouched otherwise.
|
||||
*
|
||||
* @retval kErrorNone Successfully processed the MPL option.
|
||||
* @retval kErrorDrop The MPL message is a duplicate and should be dropped.
|
||||
*/
|
||||
Error ProcessOption(Message &aMessage, const OffsetRange &aOffsetRange, const Address &aAddress, bool &aReceive);
|
||||
Error ProcessOption(Message &aMessage, const MplOption &aOption, bool &aReceive);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user