From 7344d9c8e139b1830650ff2d9cea9202ea09df23 Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Fri, 11 Jun 2021 04:29:31 +0800 Subject: [PATCH] [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. --- include/openthread/instance.h | 2 +- include/openthread/udp.h | 12 ++++++++++++ src/core/api/udp_api.cpp | 7 +++++++ src/core/net/ip6.cpp | 6 ++++-- src/core/net/udp6.cpp | 18 +++++++++++++++++- src/core/net/udp6.hpp | 12 ++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index e3acb7c6b..94b175944 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -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 diff --git a/include/openthread/udp.h b/include/openthread/udp.h index f11d5d740..02773197d 100644 --- a/include/openthread/udp.h +++ b/include/openthread/udp.h @@ -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); + /** * @} * diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp index 43d45ddb5..567a027cc 100644 --- a/src/core/api/udp_api.cpp +++ b/src/core/api/udp_api.cpp @@ -147,3 +147,10 @@ otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageI return instance.Get().SendDatagram(*static_cast(aMessage), *static_cast(aMessageInfo), Ip6::kProtoUdp); } + +bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port) +{ + Instance &instance = *static_cast(aInstance); + + return instance.Get().IsPortInUse(port); +} diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 71c30f322..3203753f0 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -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().ShouldUsePlatformUdp(udp.GetDestinationPort()), error = kErrorNoRoute); - + VerifyOrExit(Get().ShouldUsePlatformUdp(udp.GetDestinationPort()) && + !Get().IsPortInUse(udp.GetDestinationPort()), + error = kErrorNoRoute); break; } diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index a99ace197..3df27e59c 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -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 diff --git a/src/core/net/udp6.hpp b/src/core/net/udp6.hpp index 178537b60..428500ae8 100644 --- a/src/core/net/udp6.hpp +++ b/src/core/net/udp6.hpp @@ -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. *