diff --git a/include/openthread/coap.h b/include/openthread/coap.h index e494c3c6a..4b7149adb 100644 --- a/include/openthread/coap.h +++ b/include/openthread/coap.h @@ -878,9 +878,9 @@ otMessage *otCoapNewMessage(otInstance *aInstance, const otMessageSettings *aSet * 2. mAckRandomFactorNumerator / mAckRandomFactorDenominator must not be below 1.0. * 3. The calculated exchange life time must not overflow uint32_t. * - * @retval OT_ERROR_INVALID_ARGS @p aTxParameters is invalid. * @retval OT_ERROR_NONE Successfully sent CoAP message. * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendRequestWithParameters(otInstance *aInstance, @@ -909,8 +909,9 @@ otError otCoapSendRequestWithParameters(otInstance *aInstance, * @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer. * @param[in] aReceiveHook A pointer to a hook function for incoming block-wise transfer. * - * @retval OT_ERROR_NONE Successfully sent CoAP message. - * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_NONE Successfully sent CoAP message. + * @retval OT_ERROR_NO_BUFS Failed to allocate retransmission data. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendRequestBlockWiseWithParameters(otInstance *aInstance, @@ -1059,8 +1060,9 @@ void otCoapSetDefaultHandler(otInstance *aInstance, otCoapRequestHandler aHandle * @param[in] aMessageInfo A pointer to the message info associated with @p aMessage. * @param[in] aTxParameters A pointer to transmission parameters for this response. Use NULL for defaults. * - * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. - * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. + * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendResponseWithParameters(otInstance *aInstance, @@ -1081,8 +1083,9 @@ otError otCoapSendResponseWithParameters(otInstance *aInstance, * @param[in] aContext A pointer to arbitrary context information. May be NULL if not used. * @param[in] aTransmitHook A pointer to a hook function for outgoing block-wise transfer. * - * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. - * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_NONE Successfully enqueued the CoAP response message. + * @retval OT_ERROR_NO_BUFS Insufficient buffers available to send the CoAP response. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otCoapSendResponseBlockWiseWithParameters(otInstance *aInstance, diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 1dece9bd9..d450a0218 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 (362) +#define OPENTHREAD_API_VERSION (363) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index e34205f46..35c11057e 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -527,6 +527,8 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled); * @retval OT_ERROR_NO_ROUTE No route to host. * @retval OT_ERROR_INVALID_SOURCE_ADDRESS Source address is invalid, e.g. an anycast address or a multicast address. * @retval OT_ERROR_PARSE Encountered a malformed header when processing the message. + * @retval OT_ERROR_INVALID_ARGS The message's metadata is invalid, e.g. the message uses + * `OT_MESSAGE_ORIGIN_THREAD_NETIF` as the origin. * */ otError otIp6Send(otInstance *aInstance, otMessage *aMessage); diff --git a/include/openthread/message.h b/include/openthread/message.h index 6bdf5f1be..99dc49cf1 100644 --- a/include/openthread/message.h +++ b/include/openthread/message.h @@ -69,6 +69,17 @@ typedef enum otMessagePriority OT_MESSAGE_PRIORITY_HIGH = 2, ///< High priority level. } otMessagePriority; +/** + * Defines the OpenThread message origins. + * + */ +typedef enum otMessageOrigin +{ + OT_MESSAGE_ORIGIN_THREAD_NETIF = 0, ///< Message from Thread Netif. + OT_MESSAGE_ORIGIN_HOST_TRUSTED = 1, ///< Message from a trusted source on host. + OT_MESSAGE_ORIGIN_HOST_UNTRUSTED = 2, ///< Message from an untrusted source on host. +} otMessageOrigin; + /** * Represents a message settings. * @@ -180,6 +191,45 @@ void otMessageSetOffset(otMessage *aMessage, uint16_t aOffset); */ bool otMessageIsLinkSecurityEnabled(const otMessage *aMessage); +/** + * Indicates whether or not the message is allowed to be looped back to host. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @retval TRUE If the message is allowed to be looped back to host. + * @retval FALSE If the message is not allowed to be looped back to host. + * + */ +bool otMessageIsLoopbackToHostAllowed(const otMessage *aMessage); + +/** + * Sets whether or not the message is allowed to be looped back to host. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aAllowLoopbackToHost Whether to allow the message to be looped back to host. + * + */ +void otMessageSetLoopbackToHostAllowed(otMessage *aMessage, bool aAllowLoopbackToHost); + +/** + * Gets the message origin. + * + * @param[in] aMessage A pointer to a message buffer. + * + * @returns The message origin. + * + */ +otMessageOrigin otMessageGetOrigin(const otMessage *aMessage); + +/** + * Sets the message origin. + * + * @param[in] aMessage A pointer to a message buffer. + * @param[in] aOrigin The message origin. + * + */ +void otMessageSetOrigin(otMessage *aMessage, otMessageOrigin aOrigin); + /** * Sets/forces the message to be forwarded using direct transmission. * Default setting for a new message is `false`. diff --git a/include/openthread/udp.h b/include/openthread/udp.h index 6e577c4a1..3512b7bdc 100644 --- a/include/openthread/udp.h +++ b/include/openthread/udp.h @@ -104,8 +104,9 @@ otError otUdpRemoveReceiver(otInstance *aInstance, otUdpReceiver *aUdpReceiver); * @param[in] aMessage A pointer to a message without UDP header. * @param[in] aMessageInfo A pointer to a message info associated with @p aMessage. * - * @retval OT_ERROR_NONE Successfully enqueued the message into an output interface. - * @retval OT_ERROR_NO_BUFS Insufficient available buffer to add the IPv6 headers. + * @retval OT_ERROR_NONE Successfully enqueued the message into an output interface. + * @retval OT_ERROR_NO_BUFS Insufficient available buffer to add the IPv6 headers. + * @retval OT_ERROR_INVALID_ARGS Invalid arguments are given. * */ otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo); diff --git a/src/core/api/coap_api.cpp b/src/core/api/coap_api.cpp index 6c52cd2e0..b218d29e7 100644 --- a/src/core/api/coap_api.cpp +++ b/src/core/api/coap_api.cpp @@ -211,6 +211,8 @@ otError otCoapSendRequestBlockWiseWithParameters(otInstance *aIn Error error; const Coap::TxParameters &txParameters = Coap::TxParameters::From(aTxParameters); + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + if (aTxParameters != nullptr) { VerifyOrExit(txParameters.IsValid(), error = kErrorInvalidArgs); @@ -236,6 +238,8 @@ otError otCoapSendRequestWithParameters(otInstance *aInstance, const Coap::TxParameters &txParameters = Coap::TxParameters::From(aTxParameters); + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + if (aTxParameters != nullptr) { VerifyOrExit(txParameters.IsValid(), error = kErrorInvalidArgs); @@ -290,9 +294,15 @@ otError otCoapSendResponseBlockWiseWithParameters(otInstance *aI void *aContext, otCoapBlockwiseTransmitHook aTransmitHook) { - return AsCoreType(aInstance).GetApplicationCoap().SendMessage(AsCoapMessage(aMessage), AsCoreType(aMessageInfo), - Coap::TxParameters::From(aTxParameters), nullptr, - aContext, aTransmitHook, nullptr); + otError error; + + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).GetApplicationCoap().SendMessage(AsCoapMessage(aMessage), AsCoreType(aMessageInfo), + Coap::TxParameters::From(aTxParameters), nullptr, + aContext, aTransmitHook, nullptr); +exit: + return error; } #endif @@ -301,8 +311,15 @@ otError otCoapSendResponseWithParameters(otInstance *aInstance, const otMessageInfo *aMessageInfo, const otCoapTxParameters *aTxParameters) { - return AsCoreType(aInstance).GetApplicationCoap().SendMessage( + otError error; + + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).GetApplicationCoap().SendMessage( AsCoapMessage(aMessage), AsCoreType(aMessageInfo), Coap::TxParameters::From(aTxParameters), nullptr, nullptr); + +exit: + return error; } #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE diff --git a/src/core/api/ip6_api.cpp b/src/core/api/ip6_api.cpp index 4ff7d229c..710001919 100644 --- a/src/core/api/ip6_api.cpp +++ b/src/core/api/ip6_api.cpp @@ -132,8 +132,14 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled) otError otIp6Send(otInstance *aInstance, otMessage *aMessage) { - return AsCoreType(aInstance).Get().SendRaw(AsCoreType(aMessage), - OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); + otError error; + + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).Get().SendRaw(AsCoreType(aMessage)); + +exit: + return error; } otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings) diff --git a/src/core/api/message_api.cpp b/src/core/api/message_api.cpp index eafc1d2c7..f564e3abd 100644 --- a/src/core/api/message_api.cpp +++ b/src/core/api/message_api.cpp @@ -52,6 +52,23 @@ void otMessageSetOffset(otMessage *aMessage, uint16_t aOffset) { AsCoreType(aMes bool otMessageIsLinkSecurityEnabled(const otMessage *aMessage) { return AsCoreType(aMessage).IsLinkSecurityEnabled(); } +bool otMessageIsLoopbackToHostAllowed(const otMessage *aMessage) +{ + return AsCoreType(aMessage).IsLoopbackToHostAllowed(); +} + +void otMessageSetLoopbackToHostAllowed(otMessage *aMessage, bool aAllowLoopbackToHost) +{ + return AsCoreType(aMessage).SetLoopbackToHostAllowed(aAllowLoopbackToHost); +} + +otMessageOrigin otMessageGetOrigin(const otMessage *aMessage) { return MapEnum(AsCoreType(aMessage).GetOrigin()); } + +void otMessageSetOrigin(otMessage *aMessage, otMessageOrigin aOrigin) +{ + AsCoreType(aMessage).SetOrigin(MapEnum(aOrigin)); +} + void otMessageSetDirectTransmission(otMessage *aMessage, bool aEnabled) { if (aEnabled) diff --git a/src/core/api/udp_api.cpp b/src/core/api/udp_api.cpp index 16817b629..48dc5845f 100644 --- a/src/core/api/udp_api.cpp +++ b/src/core/api/udp_api.cpp @@ -72,8 +72,14 @@ otError otUdpConnect(otInstance *aInstance, otUdpSocket *aSocket, const otSockAd otError otUdpSend(otInstance *aInstance, otUdpSocket *aSocket, otMessage *aMessage, const otMessageInfo *aMessageInfo) { - return AsCoreType(aInstance).Get().SendTo(AsCoreType(aSocket), AsCoreType(aMessage), - AsCoreType(aMessageInfo)); + otError error; + + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + + error = AsCoreType(aInstance).Get().SendTo(AsCoreType(aSocket), AsCoreType(aMessage), + AsCoreType(aMessageInfo)); +exit: + return error; } otUdpSocket *otUdpGetSockets(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetUdpSockets(); } @@ -116,8 +122,14 @@ otError otUdpRemoveReceiver(otInstance *aInstance, otUdpReceiver *aUdpReceiver) otError otUdpSendDatagram(otInstance *aInstance, otMessage *aMessage, otMessageInfo *aMessageInfo) { + otError error; + + VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs); + return AsCoreType(aInstance).Get().SendDatagram(AsCoreType(aMessage), AsCoreType(aMessageInfo), Ip6::kProtoUdp); +exit: + return error; } bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port) diff --git a/src/core/common/message.cpp b/src/core/common/message.cpp index 9d3ebcaae..bdb513ab8 100644 --- a/src/core/common/message.cpp +++ b/src/core/common/message.cpp @@ -80,6 +80,8 @@ Message *MessagePool::Allocate(Message::Type aType, uint16_t aReserveHeader, con message->SetType(aType); message->SetReserved(aReserveHeader); message->SetLinkSecurityEnabled(aSettings.IsLinkSecurityEnabled()); + message->SetLoopbackToHostAllowed(OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); + message->SetOrigin(Message::kOriginHostTrusted); SuccessOrExit(error = message->SetPriority(aSettings.GetPriority())); SuccessOrExit(error = message->SetLength(0)); @@ -772,6 +774,8 @@ Message *Message::Clone(uint16_t aLength) const messageCopy->SetOffset(offset); messageCopy->SetSubType(GetSubType()); + messageCopy->SetLoopbackToHostAllowed(IsLoopbackToHostAllowed()); + messageCopy->SetOrigin(GetOrigin()); #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE messageCopy->SetTimeSync(IsTimeSync()); #endif diff --git a/src/core/common/message.hpp b/src/core/common/message.hpp index d40bf08a2..5edb3344e 100644 --- a/src/core/common/message.hpp +++ b/src/core/common/message.hpp @@ -207,16 +207,18 @@ protected: ChildMask mChildMask; // ChildMask to indicate which sleepy children need to receive this. #endif - uint8_t mType : 3; // The message type. - uint8_t mSubType : 4; // The message sub type. - bool mDirectTx : 1; // Whether a direct transmission is required. - bool mLinkSecurity : 1; // Whether link security is enabled. - uint8_t mPriority : 2; // The message priority level (higher value is higher priority). - bool mInPriorityQ : 1; // Whether the message is queued in normal or priority queue. - bool mTxSuccess : 1; // Whether the direct tx of the message was successful. - bool mDoNotEvict : 1; // Whether this message may be evicted. - bool mMulticastLoop : 1; // Whether this multicast message may be looped back. - bool mResolvingAddress : 1; // Whether the message is pending an address query resolution. + uint8_t mType : 3; // The message type. + uint8_t mSubType : 4; // The message sub type. + bool mDirectTx : 1; // Whether a direct transmission is required. + bool mLinkSecurity : 1; // Whether link security is enabled. + uint8_t mPriority : 2; // The message priority level (higher value is higher priority). + bool mInPriorityQ : 1; // Whether the message is queued in normal or priority queue. + bool mTxSuccess : 1; // Whether the direct tx of the message was successful. + bool mDoNotEvict : 1; // Whether this message may be evicted. + bool mMulticastLoop : 1; // Whether this multicast message may be looped back. + bool mResolvingAddress : 1; // Whether the message is pending an address query resolution. + bool mAllowLookbackToHost : 1; // Whether the message is allowed to be looped back to host. + uint8_t mOrigin : 2; // The origin of the message. #if OPENTHREAD_CONFIG_MULTI_RADIO uint8_t mRadioType : 2; // The radio link type the message was received on, or should be sent on. bool mIsRadioTypeSet : 1; // Whether the radio type is set. @@ -349,6 +351,17 @@ public: kCopyToUse, }; + /** + * Represents an IPv6 message origin. + * + */ + enum Origin : uint8_t + { + kOriginThreadNetif = OT_MESSAGE_ORIGIN_THREAD_NETIF, // Message from Thread Netif. + kOriginHostTrusted = OT_MESSAGE_ORIGIN_HOST_TRUSTED, // Message from a trusted source on host. + kOriginHostUntrusted = OT_MESSAGE_ORIGIN_HOST_UNTRUSTED, // Message from an untrusted source on host. + }; + /** * Represents settings used for creating a new message. * @@ -1135,6 +1148,42 @@ public: */ void SetResolvingAddress(bool aResolvingAddress) { GetMetadata().mResolvingAddress = aResolvingAddress; } + /** + * Indicates whether the message is allowed to be looped back to host. + * + * @retval TRUE If the message is allowed to be looped back to host. + * @retval FALSE If the message is not allowed to be looped back to host. + * + */ + bool IsLoopbackToHostAllowed(void) const { return GetMetadata().mAllowLookbackToHost; } + + /** + * Sets whether or not allow the message to be looped back to host. + * + * @param[in] aAllowLoopbackToHost Whether or not allow the message to be looped back to host. + * + */ + void SetLoopbackToHostAllowed(bool aAllowLoopbackToHost) + { + GetMetadata().mAllowLookbackToHost = aAllowLoopbackToHost; + } + + /** + * Gets the message origin. + * + * @returns An enum representing the origin of the message. + * + */ + Origin GetOrigin(void) const { return static_cast(GetMetadata().mOrigin); } + + /** + * Sets the message origin. + * + * @param[in] aOrigin An enum representing the origin of the message. + * + */ + void SetOrigin(Origin aOrigin) { GetMetadata().mOrigin = aOrigin; } + /** * Indicates whether or not link security is enabled for the message. * @@ -1798,6 +1847,8 @@ DefineCoreType(otMessageSettings, Message::Settings); DefineCoreType(otMessage, Message); DefineCoreType(otMessageQueue, MessageQueue); +DefineMapEnum(otMessageOrigin, Message::Origin); + } // namespace ot #endif // MESSAGE_HPP_ diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index b130377a8..d55713ec6 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -288,7 +288,7 @@ Error Ip6::InsertMplOption(Message &aMessage, Header &aHeader) if ((messageCopy = aMessage.Clone()) != nullptr) { - IgnoreError(HandleDatagram(*messageCopy, kFromHostDisallowLoopBack)); + IgnoreError(HandleDatagram(*messageCopy)); LogInfo("Message copy for indirect transmission to sleepy children"); } else @@ -512,7 +512,7 @@ void Ip6::HandleSendQueue(void) while ((message = mSendQueue.GetHead()) != nullptr) { mSendQueue.Dequeue(*message); - IgnoreError(HandleDatagram(*message, kFromHostAllowLoopBack)); + IgnoreError(HandleDatagram(*message)); } } @@ -634,7 +634,7 @@ exit: return error; } -Error Ip6::HandleFragment(Message &aMessage, MessageOrigin aOrigin, MessageInfo &aMessageInfo) +Error Ip6::HandleFragment(Message &aMessage, MessageInfo &aMessageInfo) { Error error = kErrorNone; Header header, headerBuffer; @@ -721,7 +721,7 @@ Error Ip6::HandleFragment(Message &aMessage, MessageOrigin aOrigin, MessageInfo mReassemblyList.Dequeue(*message); - IgnoreError(HandleDatagram(*message, aOrigin, aMessageInfo.mLinkInfo, /* aIsReassembled */ true)); + IgnoreError(HandleDatagram(*message, aMessageInfo.mLinkInfo, /* aIsReassembled */ true)); } exit: @@ -805,9 +805,8 @@ Error Ip6::FragmentDatagram(Message &aMessage, uint8_t aIpProto) return kErrorNone; } -Error Ip6::HandleFragment(Message &aMessage, MessageOrigin aOrigin, MessageInfo &aMessageInfo) +Error Ip6::HandleFragment(Message &aMessage, MessageInfo &aMessageInfo) { - OT_UNUSED_VARIABLE(aOrigin); OT_UNUSED_VARIABLE(aMessageInfo); Error error = kErrorNone; @@ -824,15 +823,14 @@ exit: } #endif // OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE -Error Ip6::HandleExtensionHeaders(Message &aMessage, - MessageOrigin aOrigin, - MessageInfo &aMessageInfo, - Header &aHeader, - uint8_t &aNextHeader, - bool &aReceive) +Error Ip6::HandleExtensionHeaders(Message &aMessage, + MessageInfo &aMessageInfo, + Header &aHeader, + uint8_t &aNextHeader, + bool &aReceive) { Error error = kErrorNone; - bool isOutbound = (aOrigin != kFromThreadNetif); + bool isOutbound = (aMessage.GetOrigin() != Message::kOriginThreadNetif); ExtensionHeader extHeader; while (aReceive || aNextHeader == kProtoHopOpts) @@ -846,9 +844,9 @@ Error Ip6::HandleExtensionHeaders(Message &aMessage, break; case kProtoFragment: - IgnoreError(PassToHost(aMessage, aOrigin, aMessageInfo, aNextHeader, + IgnoreError(PassToHost(aMessage, aMessageInfo, aNextHeader, /* aApplyFilter */ false, aReceive, Message::kCopyToUse)); - SuccessOrExit(error = HandleFragment(aMessage, aOrigin, aMessageInfo)); + SuccessOrExit(error = HandleFragment(aMessage, aMessageInfo)); break; case kProtoDstOpts: @@ -945,7 +943,6 @@ exit: } Error Ip6::PassToHost(Message &aMessage, - MessageOrigin aOrigin, const MessageInfo &aMessageInfo, uint8_t aIpProto, bool aApplyFilter, @@ -973,7 +970,7 @@ Error Ip6::PassToHost(Message &aMessage, message = &aMessage; } - VerifyOrExit(aOrigin != kFromHostDisallowLoopBack, error = kErrorNoRoute); + VerifyOrExit(aMessage.IsLoopbackToHostAllowed(), error = kErrorNoRoute); VerifyOrExit(mReceiveIp6DatagramCallback.IsSet(), error = kErrorNoRoute); @@ -1092,7 +1089,7 @@ exit: return error; } -Error Ip6::SendRaw(Message &aMessage, bool aAllowLoopBackToHost) +Error Ip6::SendRaw(Message &aMessage) { Error error = kErrorNone; Header header; @@ -1120,7 +1117,7 @@ Error Ip6::SendRaw(Message &aMessage, bool aAllowLoopBackToHost) SuccessOrExit(error = InsertMplOption(aMessage, header)); } - error = HandleDatagram(aMessage, aAllowLoopBackToHost ? kFromHostAllowLoopBack : kFromHostDisallowLoopBack); + error = HandleDatagram(aMessage); freed = true; #if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE @@ -1137,16 +1134,17 @@ exit: return error; } -Error Ip6::HandleDatagram(Message &aMessage, MessageOrigin aOrigin, const void *aLinkMessageInfo, bool aIsReassembled) +Error Ip6::HandleDatagram(Message &aMessage, const void *aLinkMessageInfo, bool aIsReassembled) { - Error error; - MessageInfo messageInfo; - Header header; - bool receive; - bool forwardThread; - bool forwardHost; - bool shouldFreeMessage; - uint8_t nextHeader; + Error error; + MessageInfo messageInfo; + Header header; + bool receive; + bool forwardThread; + bool forwardHost; + bool shouldFreeMessage; + uint8_t nextHeader; + Message::Origin origin = aMessage.GetOrigin(); start: receive = false; @@ -1170,10 +1168,10 @@ start: { // Destination is multicast - forwardThread = (aOrigin != kFromThreadNetif); + forwardThread = (origin != Message::kOriginThreadNetif); #if OPENTHREAD_FTD - if ((aOrigin == kFromThreadNetif) && header.GetDestination().IsMulticastLargerThanRealmLocal() && + if ((origin == Message::kOriginThreadNetif) && header.GetDestination().IsMulticastLargerThanRealmLocal() && Get().HasSleepyChildWithAddress(header.GetDestination())) { forwardThread = true; @@ -1182,7 +1180,7 @@ start: forwardHost = header.GetDestination().IsMulticastLargerThanRealmLocal(); - if (((aOrigin == kFromThreadNetif) || aMessage.GetMulticastLoop()) && + if (((origin == Message::kOriginThreadNetif) || aMessage.GetMulticastLoop()) && Get().IsMulticastSubscribed(header.GetDestination())) { receive = true; @@ -1200,7 +1198,7 @@ start: { receive = true; } - else if ((aOrigin != kFromThreadNetif) || !header.GetDestination().IsLinkLocal()) + else if ((origin != Message::kOriginThreadNetif) || !header.GetDestination().IsLinkLocal()) { if (header.GetDestination().IsLinkLocal()) { @@ -1209,7 +1207,7 @@ start: else if (IsOnLink(header.GetDestination())) { #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_DUA_NDPROXYING_ENABLE - forwardThread = ((aOrigin == kFromHostDisallowLoopBack) || + forwardThread = (!aMessage.IsLoopbackToHostAllowed() || !Get().ShouldForwardDuaToBackbone(header.GetDestination())); #else forwardThread = true; @@ -1228,7 +1226,7 @@ start: // Process IPv6 Extension Headers nextHeader = static_cast(header.GetNextHeader()); - SuccessOrExit(error = HandleExtensionHeaders(aMessage, aOrigin, messageInfo, header, nextHeader, receive)); + SuccessOrExit(error = HandleExtensionHeaders(aMessage, messageInfo, header, nextHeader, receive)); if (receive && (nextHeader == kProtoIp6)) { @@ -1240,7 +1238,7 @@ start: if ((forwardHost || receive) && !aIsReassembled) { - error = PassToHost(aMessage, aOrigin, messageInfo, nextHeader, + error = PassToHost(aMessage, messageInfo, nextHeader, /* aApplyFilter */ !forwardHost, receive, (receive || forwardThread) ? Message::kCopyToUse : Message::kTakeCustody); @@ -1263,7 +1261,7 @@ start: { uint8_t hopLimit; - if (aOrigin == kFromThreadNetif) + if (origin == Message::kOriginThreadNetif) { VerifyOrExit(Get().IsRouterOrLeader()); header.SetHopLimit(header.GetHopLimit() - 1); @@ -1291,8 +1289,22 @@ start: VerifyOrExit(isAllowedType, error = kErrorDrop); } + if (aMessage.GetOrigin() == Message::kOriginHostUntrusted && nextHeader == kProtoUdp) + { + uint16_t destPort; + + SuccessOrExit(error = aMessage.Read(aMessage.GetOffset() + Udp::Header::kDestPortFieldOffset, destPort)); + destPort = HostSwap16(destPort); + + if (destPort == Tmf::kUdpPort) + { + LogNote("Dropping TMF message from untrusted origin"); + ExitNow(error = kErrorDrop); + } + } + #if !OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE - if ((aOrigin == kFromHostDisallowLoopBack) && (nextHeader == kProtoUdp)) + if ((origin == Message::kOriginHostTrusted && !aMessage.IsLoopbackToHostAllowed()) && (nextHeader == kProtoUdp)) { uint16_t destPort; diff --git a/src/core/net/ip6.hpp b/src/core/net/ip6.hpp index 9fc5bd5f3..ff5c1fd0c 100644 --- a/src/core/net/ip6.hpp +++ b/src/core/net/ip6.hpp @@ -113,20 +113,6 @@ class Ip6 : public InstanceLocator, private NonCopyable friend class Mpl; public: - /** - * Represents an IPv6 message origin. - * - * In case the message is originating from host, it also indicates whether or not it is allowed to passed back the - * message to the host. - * - */ - enum MessageOrigin : uint8_t - { - kFromThreadNetif, ///< Message originates from Thread Netif. - kFromHostDisallowLoopBack, ///< Message originates from host and should not be passed back to host. - kFromHostAllowLoopBack, ///< Message originates from host and can be passed back to host. - }; - /** * Initializes the object. * @@ -212,7 +198,6 @@ public: * processing is complete, including when a value other than `kErrorNone` is returned. * * @param[in] aMessage A reference to the message. - * @param[in] aAllowLoopBackToHost Indicate whether or not the message is allowed to be passed back to host. * * @retval kErrorNone Successfully processed the message. * @retval kErrorDrop Message was well-formed but not fully processed due to packet processing rules. @@ -221,13 +206,12 @@ public: * @retval kErrorParse Encountered a malformed header when processing the message. * */ - Error SendRaw(Message &aMessage, bool aAllowLoopBackToHost); + Error SendRaw(Message &aMessage); /** * Processes a received IPv6 datagram. * * @param[in] aMessage A reference to the message. - * @param[in] aOrigin The message oirgin. * @param[in] aLinkMessageInfo A pointer to link-specific message information. * * @retval kErrorNone Successfully processed the message. @@ -237,10 +221,7 @@ public: * @retval kErrorParse Encountered a malformed header when processing the message. * */ - Error HandleDatagram(Message &aMessage, - MessageOrigin aOrigin, - const void *aLinkMessageInfo = nullptr, - bool aIsReassembled = false); + Error HandleDatagram(Message &aMessage, const void *aLinkMessageInfo = nullptr, bool aIsReassembled = false); /** * Registers a callback to provide received raw IPv6 datagrams. @@ -387,20 +368,18 @@ private: void EnqueueDatagram(Message &aMessage); Error PassToHost(Message &aMessage, - MessageOrigin aOrigin, const MessageInfo &aMessageInfo, uint8_t aIpProto, bool aApplyFilter, bool aReceive, Message::Ownership aMessageOwnership); - Error HandleExtensionHeaders(Message &aMessage, - MessageOrigin aOrigin, - MessageInfo &aMessageInfo, - Header &aHeader, - uint8_t &aNextHeader, - bool &aReceive); + Error HandleExtensionHeaders(Message &aMessage, + MessageInfo &aMessageInfo, + Header &aHeader, + uint8_t &aNextHeader, + bool &aReceive); Error FragmentDatagram(Message &aMessage, uint8_t aIpProto); - Error HandleFragment(Message &aMessage, MessageOrigin aOrigin, MessageInfo &aMessageInfo); + Error HandleFragment(Message &aMessage, MessageInfo &aMessageInfo); #if OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE void CleanupFragmentationBuffer(void); void HandleTimeTick(void); diff --git a/src/core/net/ip6_mpl.cpp b/src/core/net/ip6_mpl.cpp index 616b0314a..c5dd2d3e5 100644 --- a/src/core/net/ip6_mpl.cpp +++ b/src/core/net/ip6_mpl.cpp @@ -406,6 +406,8 @@ void Mpl::HandleRetransmissionTimer(void) messageCopy->SetSubType(Message::kSubTypeMplRetransmission); } + messageCopy->SetLoopbackToHostAllowed(true); + messageCopy->SetOrigin(Message::kOriginHostTrusted); Get().EnqueueDatagram(*messageCopy); } @@ -426,6 +428,8 @@ void Mpl::HandleRetransmissionTimer(void) } metadata.RemoveFrom(message); + message.SetLoopbackToHostAllowed(true); + message.SetOrigin(Message::kOriginHostTrusted); Get().EnqueueDatagram(message); } else diff --git a/src/core/net/nat64_translator.cpp b/src/core/net/nat64_translator.cpp index c7d93a65a..0415f909f 100644 --- a/src/core/net/nat64_translator.cpp +++ b/src/core/net/nat64_translator.cpp @@ -99,7 +99,7 @@ Error Translator::SendMessage(Message &aMessage) VerifyOrExit(result == kForward); - error = Get().SendRaw(aMessage, !OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS); + error = Get().SendRaw(aMessage); freed = true; exit: diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 048322448..d4e61cf08 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -1660,7 +1660,10 @@ Error MeshForwarder::HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLi mIpCounters.mRxSuccess++; } - return Get().HandleDatagram(aMessage, Ip6::Ip6::kFromThreadNetif, &aLinkInfo); + aMessage.SetLoopbackToHostAllowed(true); + aMessage.SetOrigin(Message::kOriginThreadNetif); + + return Get().HandleDatagram(aMessage, &aLinkInfo); } Error MeshForwarder::GetFramePriority(const FrameData &aFrameData, diff --git a/src/core/thread/mesh_forwarder_ftd.cpp b/src/core/thread/mesh_forwarder_ftd.cpp index e46ff7e0d..5e84f4c0e 100644 --- a/src/core/thread/mesh_forwarder_ftd.cpp +++ b/src/core/thread/mesh_forwarder_ftd.cpp @@ -184,8 +184,10 @@ void MeshForwarder::HandleResolved(const Ip6::Address &aEid, Error aError) IgnoreError(message.Read(Ip6::Header::kHopLimitFieldOffset, hopLimit)); hopLimit++; message.Write(Ip6::Header::kHopLimitFieldOffset, hopLimit); + message.SetLoopbackToHostAllowed(true); + message.SetOrigin(Message::kOriginHostTrusted); - IgnoreError(Get().HandleDatagram(message, Ip6::Ip6::kFromHostAllowLoopBack)); + IgnoreError(Get().HandleDatagram(message)); continue; } #endif diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index 83760250b..331c0d747 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -1132,6 +1132,8 @@ static void processTransmit(otInstance *aInstance) message = otIp6NewMessage(aInstance, &settings); #endif VerifyOrExit(message != nullptr, error = OT_ERROR_NO_BUFS); + otMessageSetLoopbackToHostAllowed(message, true); + otMessageSetOrigin(message, OT_MESSAGE_ORIGIN_HOST_UNTRUSTED); } #if OPENTHREAD_POSIX_LOG_TUN_PACKETS diff --git a/tests/scripts/thread-cert/border_router/test_firewall.py b/tests/scripts/thread-cert/border_router/test_firewall.py index 443da698d..54d0a1b2b 100755 --- a/tests/scripts/thread-cert/border_router/test_firewall.py +++ b/tests/scripts/thread-cert/border_router/test_firewall.py @@ -201,6 +201,15 @@ class Firewall(thread_cert.TestCase): br1.ping_ether(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], interface=br1.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) + # 16. Host sends a UDP packet to router1's OMR address's TMF port. + host.udp_send_host(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], config.TMF_PORT, "HELLO") + + # 17. BR1 sends a UDP packet to router1's ML-EID's TMF port. + br1.udp_send_host(router1.get_mleid(), config.TMF_PORT, "BYE") + + # 18. BR1 sends a UDP packet to its own ML-EID's TMF port. + br1.udp_send_host(br1.get_mleid(), config.TMF_PORT, "SELF") + self.collect_ipaddrs() self.collect_rlocs() self.collect_rloc16s() @@ -292,7 +301,7 @@ class Firewall(thread_cert.TestCase): pkts.filter_eth_src(vars['BR_1_ETH']).filter_ipv6_src_dst( vars['Router_1_MLEID'], vars['Host_BGUA']).filter_ping_request().must_not_next() - # 14. BR pings router1's ML-EID from BR's infra interface. + # 14. BR pings router1's ML-EID from BR's ML-EID. _pkt = pkts.filter_wpan_src64(vars['BR_1']).filter_ipv6_src_dst( vars['BR_1_MLEID'], vars['Router_1_MLEID']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['Router_1']).filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).must_next() @@ -301,6 +310,23 @@ class Firewall(thread_cert.TestCase): _pkt = pkts.filter_wpan_src64(vars['BR_1']).filter_ping_request().must_next() pkts.filter_wpan_src64(vars['Router_1']).filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).must_next() + # 16. Host sends a UDP packet to router1's OMR address's TMF port (61631). + # The packet should be able to reach BR1 but BR1 won't forward it to Thread. + pkts.filter_eth_src(vars['Host_ETH']).filter_ipv6_dst(vars['Router_1_OMR'][0]).filter( + lambda p: p.udp.dstport == config.TMF_PORT and p.udp.length == len("HELLO") + 8).must_next() + pkts.filter_wpan_src64(vars['BR_1']).filter_ipv6_dst(vars['Router_1_OMR'][0]).filter( + lambda p: p.udp.dstport == config.TMF_PORT and p.udp.length == len("HELLO") + 8).must_not_next() + + # 17. BR1 sends a UDP packet to router1's ML-EID's TMF port (61631). + # The packet should be dropped by BR1, so it should not be present in Thread. + pkts.filter_wpan_src64(vars['BR_1']).filter_ipv6_dst(vars['Router_1_MLEID']).filter( + lambda p: p.udp.dstport == config.TMF_PORT and p.udp.length == len("BYE") + 8).must_not_next() + + # 18. BR1 sends a UDP packet to its own ML-EID's TMF port (61631). + # The packet should be dropped by BR1, so it should not be present anywhere. + pkts.filter_wpan_src64(vars['BR_1']).filter_ipv6_dst(vars['BR_1_MLEID']).filter( + lambda p: p.udp.dstport == config.TMF_PORT and p.udp.length == len("SELF") + 8).must_not_next() + if __name__ == '__main__': unittest.main() diff --git a/tests/scripts/thread-cert/config.py b/tests/scripts/thread-cert/config.py index ffb4dc6b4..ebb90dd47 100644 --- a/tests/scripts/thread-cert/config.py +++ b/tests/scripts/thread-cert/config.py @@ -57,6 +57,7 @@ REALM_LOCAL_ALL_NODES_ADDRESS = 'ff03::1' REALM_LOCAL_ALL_ROUTERS_ADDRESS = 'ff03::2' LINK_LOCAL_ALL_NODES_ADDRESS = 'ff02::1' LINK_LOCAL_ALL_ROUTERS_ADDRESS = 'ff02::2' +TMF_PORT = 61631 DOMAIN_PREFIX = 'fd00:7d03:7d03:7d03::/64' DOMAIN_PREFIX_REGEX_PATTERN = '^fd00:7d03:7d03:7d03:' diff --git a/tests/scripts/thread-cert/pktverify/verify.py b/tests/scripts/thread-cert/pktverify/verify.py old mode 100644 new mode 100755 diff --git a/tests/unit/test_message.cpp b/tests/unit/test_message.cpp index d6aa9d330..8efa5b847 100644 --- a/tests/unit/test_message.cpp +++ b/tests/unit/test_message.cpp @@ -50,6 +50,7 @@ void TestMessage(void) MessagePool *messagePool; Message *message; Message *message2; + Message *messageCopy; uint8_t writeBuffer[kMaxSize]; uint8_t readBuffer[kMaxSize]; uint8_t zeroBuffer[kMaxSize]; @@ -66,6 +67,12 @@ void TestMessage(void) Random::NonCrypto::FillBuffer(writeBuffer, kMaxSize); VerifyOrQuit((message = messagePool->Allocate(Message::kTypeIp6)) != nullptr); + message->SetLinkSecurityEnabled(Message::kWithLinkSecurity); + message->SetPriority(Message::Priority::kPriorityNet); + message->SetType(Message::Type::kType6lowpan); + message->SetSubType(Message::SubType::kSubTypeMleChildIdRequest); + message->SetLoopbackToHostAllowed(true); + message->SetOrigin(Message::kOriginHostUntrusted); SuccessOrQuit(message->SetLength(kMaxSize)); message->WriteBytes(0, writeBuffer, kMaxSize); SuccessOrQuit(message->Read(0, readBuffer, kMaxSize)); @@ -74,6 +81,26 @@ void TestMessage(void) VerifyOrQuit(message->Compare(0, readBuffer)); VerifyOrQuit(message->GetLength() == kMaxSize); + // Verify `Clone()` behavior + message->SetOffset(15); + messageCopy = message->Clone(); + VerifyOrQuit(messageCopy->GetOffset() == message->GetOffset()); + SuccessOrQuit(messageCopy->Read(0, readBuffer, kMaxSize)); + VerifyOrQuit(memcmp(writeBuffer, readBuffer, kMaxSize) == 0); + VerifyOrQuit(messageCopy->CompareBytes(0, readBuffer, kMaxSize)); + VerifyOrQuit(messageCopy->Compare(0, readBuffer)); + VerifyOrQuit(messageCopy->GetLength() == kMaxSize); + VerifyOrQuit(messageCopy->GetType() == message->GetType()); + VerifyOrQuit(messageCopy->GetSubType() == message->GetSubType()); + VerifyOrQuit(messageCopy->IsLinkSecurityEnabled() == message->IsLinkSecurityEnabled()); + VerifyOrQuit(messageCopy->GetPriority() == message->GetPriority()); + VerifyOrQuit(messageCopy->IsLoopbackToHostAllowed() == message->IsLoopbackToHostAllowed()); + VerifyOrQuit(messageCopy->GetOrigin() == message->GetOrigin()); + VerifyOrQuit(messageCopy->Compare(0, readBuffer)); + message->SetOffset(0); + + messageCopy->Free(); + for (uint16_t offset = 0; offset < kMaxSize; offset++) { for (uint16_t length = 0; length <= kMaxSize - offset; length++)