[ip6] enforce filter rules when Thread role is disabled (#13050)

This commit updates `Ip6::Filter::Apply()` to remove the exception
that allowed all unsecure link-local IPv6 datagrams to pass through
when the Thread role was disabled (e.g., when the interface is up
but Thread has not yet started).

By removing this check, the device now consistently enforces strict
port filtering at all times. Only explicitly allowed traffic, such
as MLE messages, commissioner traffic, or user-configured unsecure
ports, will be permitted, improving the overall security posture
regardless of the current Thread role state.

For testing and backward compatibility on reference devices, the
`mAllowUnsecureWhenDisabled` flag is introduced (available when
`OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled). This allows
the legacy behavior to be restored via the new public APIs
`otIp6SetAllowUnsecureWhenDisabled()`. The new APIs are also provided
in CLI under `unsecureport allwhendisabled` command.
This commit is contained in:
Abtin Keshavarzian
2026-05-06 22:29:13 -07:00
committed by GitHub
parent 3c77c52136
commit e6134cb828
6 changed files with 88 additions and 3 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (594)
#define OPENTHREAD_API_VERSION (595)
/**
* @addtogroup api-instance
+23
View File
@@ -605,6 +605,29 @@ void otIp6RemoveAllUnsecurePorts(otInstance *aInstance);
*/
const uint16_t *otIp6GetUnsecurePorts(otInstance *aInstance, uint8_t *aNumEntries);
/**
* Sets whether to allow link-local unsecure IPv6 datagrams when the Thread role is disabled.
*
* Available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled. This is intended for testing. By default,
* this is disabled (i.e., unsecure traffic is always dropped regardless of the device's role).
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aAllow TRUE to allow, FALSE otherwise.
*/
void otIp6SetAllowUnsecureWhenDisabled(otInstance *aInstance, bool aAllow);
/**
* Indicates whether allowing link-local unsecure IPv6 datagrams when the Thread role is disabled is enabled.
*
* Available only when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval TRUE Does allow unsecure IPv6 datagrams when the Thread role is disabled.
* @retval FALSE Does not allow unsecure IPv6 datagrams when the Thread role is disabled.
*/
bool otIp6IsUnsecureAllowedWhenDisabled(otInstance *aInstance);
/**
* Test if two IPv6 addresses are the same.
*
+26
View File
@@ -7085,6 +7085,32 @@ template <> otError Interpreter::Process<Cmd("unsecureport")>(Arg aArgs[])
OutputNewLine();
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* @cli unsecureport allwhendisabled
* @code
* unsecureport allwhendisabled
* Disabled
* Done
* @endcode
* @par api_copy
* #otIp6IsUnsecureAllowedWhenDisabled
*/
else if (aArgs[0] == "allwhendisabled")
{
/**
* @cli unsecureport allwhendisabled (enable, disable)
* @code
* unsecureport allwhendisabled enable
* Done
* @endcode
* @cparam unsecureport allwhendisabled @ca{enable|disable}
* @par api_copy
* #otIp6SetAllowUnsecureWhenDisabled
*/
error = ProcessEnableDisable(aArgs + 1, otIp6IsUnsecureAllowedWhenDisabled, otIp6SetAllowUnsecureWhenDisabled);
}
#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
else
{
error = OT_ERROR_INVALID_COMMAND;
+12
View File
@@ -312,3 +312,15 @@ void otIp6ResetBorderRoutingCounters(otInstance *aInstance)
AsCoreType(aInstance).Get<Ip6::Ip6>().ResetBorderRoutingCounters();
}
#endif
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
void otIp6SetAllowUnsecureWhenDisabled(otInstance *aInstance, bool aAllow)
{
AsCoreType(aInstance).Get<Ip6::Filter>().SetAllowUnsecureWhenDisabled(aAllow);
}
bool otIp6IsUnsecureAllowedWhenDisabled(otInstance *aInstance)
{
return AsCoreType(aInstance).Get<Ip6::Filter>().IsUnsecureAllowedWhenDisabled();
}
#endif
+3 -2
View File
@@ -56,11 +56,12 @@ Error Filter::Apply(const Message &aMessage) const
VerifyOrExit(headers.GetDestinationAddress().IsLinkLocalUnicastOrMulticast());
// Allow all link-local IPv6 datagrams when Thread is not enabled
if (Get<Mle::Mle>().GetRole() == Mle::kRoleDisabled)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
if (mAllowUnsecureWhenDisabled && Get<Mle::Mle>().IsDisabled())
{
ExitNow(error = kErrorNone);
}
#endif
dstPort = headers.GetDestinationPort();
+23
View File
@@ -66,6 +66,9 @@ public:
*/
explicit Filter(Instance &aInstance)
: InstanceLocator(aInstance)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mAllowUnsecureWhenDisabled(false)
#endif
{
}
@@ -131,6 +134,23 @@ public:
return &mUnsecurePorts[0];
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* Sets whether to allow link-local unsecure IPv6 datagrams when the Thread role is disabled.
*
* @param[in] aAllow TRUE to allow, FALSE otherwise.
*/
void SetAllowUnsecureWhenDisabled(bool aAllow) { mAllowUnsecureWhenDisabled = aAllow; }
/**
* Indicates whether allowing link-local unsecure IPv6 datagrams when the Thread role is disabled is enabled.
*
* @retval TRUE Does allow unsecure IPv6 datagrams when the Thread role is disabled.
* @retval FALSE Does not allow unsecure IPv6 datagrams when the Thread role is disabled.
*/
bool IsUnsecureAllowedWhenDisabled(void) const { return mAllowUnsecureWhenDisabled; }
#endif
private:
static constexpr uint16_t kMaxUnsecurePorts = 2;
@@ -143,6 +163,9 @@ private:
Error UpdateUnsecurePorts(Action aAction, uint16_t aPort);
Array<uint16_t, kMaxUnsecurePorts> mUnsecurePorts;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
bool mAllowUnsecureWhenDisabled;
#endif
};
} // namespace Ip6