[udp6] improve frame filtering (#6711)

If OpenThread is part of an OS with it's own IP stack filtering only
control messages is insufficient. Example could be that if application
is using OpenThread API to listen for CoAP messages received messages
are passed also to the IP callback. The message then is delivered to
the OS IP stack and generates error response: "ICMPv6 Destination
Unreachable (Port unreachable)" as the port is not open on the OS
side. OS IP stack is unaware of the OpenThread existence so it can not
be filtered on that level and the shim layer does not receive port, or
protocol information from OT so it can not filter out a frame without
parsing it first. Extended filtering also to ports originating from
OpenThread.
This commit is contained in:
Simon Lin
2021-06-10 13:29:31 -07:00
committed by GitHub
parent deba1024c9
commit 7344d9c8e1
6 changed files with 53 additions and 4 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (123)
#define OPENTHREAD_API_VERSION (124)
/**
* @addtogroup api-instance
+12
View File
@@ -289,6 +289,18 @@ void otUdpForwardReceive(otInstance * aInstance,
const otIp6Address *aPeerAddr,
uint16_t aSockPort);
/**
* Determines if the given UDP port is exclusively opened by OpenThread API.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] port UDP port number to verify.
*
* @retval true The port is being used exclusively by OpenThread.
* @retval false The port is not used by any of the OpenThread API or is shared (e.g. is Backbone socket).
*
*/
bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port);
/**
* @}
*
+7
View File
@@ -147,3 +147,10 @@ otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageI
return instance.Get<Ip6::Udp>().SendDatagram(*static_cast<ot::Message *>(aMessage),
*static_cast<Ip6::MessageInfo *>(aMessageInfo), Ip6::kProtoUdp);
}
bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.Get<Ip6::Udp>().IsPortInUse(port);
}
+4 -2
View File
@@ -49,6 +49,7 @@
#include "net/ip6_filter.hpp"
#include "net/netif.hpp"
#include "net/udp6.hpp"
#include "openthread/ip6.h"
#include "thread/mle.hpp"
using IcmpType = ot::Ip6::Icmp::Header::Type;
@@ -1029,8 +1030,9 @@ Error Ip6::ProcessReceiveCallback(Message & aMessage,
Udp::Header udp;
IgnoreError(aMessage.Read(aMessage.GetOffset(), udp));
VerifyOrExit(Get<Udp>().ShouldUsePlatformUdp(udp.GetDestinationPort()), error = kErrorNoRoute);
VerifyOrExit(Get<Udp>().ShouldUsePlatformUdp(udp.GetDestinationPort()) &&
!Get<Udp>().IsPortInUse(udp.GetDestinationPort()),
error = kErrorNoRoute);
break;
}
+17 -1
View File
@@ -480,7 +480,7 @@ Error Udp::HandleMessage(Message &aMessage, MessageInfo &aMessageInfo)
aMessageInfo.mSockPort = udpHeader.GetDestinationPort();
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
VerifyOrExit(!ShouldUsePlatformUdp(aMessageInfo.mSockPort));
VerifyOrExit(!ShouldUsePlatformUdp(aMessageInfo.mSockPort) || IsPortInUse(aMessageInfo.mSockPort));
#endif
for (Receiver *receiver = mReceivers.GetHead(); receiver; receiver = receiver->GetNext())
@@ -530,6 +530,22 @@ exit:
return;
}
bool Udp::IsPortInUse(uint16_t aPort) const
{
bool found = false;
for (const SocketHandle *socket = mSockets.GetHead(); socket != nullptr; socket = socket->GetNext())
{
if (socket->GetSockName().GetPort() == aPort)
{
found = true;
break;
}
}
return found;
}
bool Udp::ShouldUsePlatformUdp(uint16_t aPort) const
{
return (aPort != Mle::kUdpPort && aPort != Tmf::kUdpPort
+12
View File
@@ -573,6 +573,18 @@ public:
}
#endif
/**
* This method returns whether a udp port is being used by OpenThread or any of it's optional
* features, e.g. CoAP API.
*
* @param[in] aPort The udp port
*
* @retval True when port is used by the OpenThread.
* @retval False when the port is not used by OpenThread.
*
*/
bool IsPortInUse(uint16_t aPort) const;
/**
* This method returns whether a udp port belongs to the platform or the stack.
*