Skip to content

Commit

Permalink
[ip6] drop UDP datagrams from an untrusted origin to TMF port (openth…
Browse files Browse the repository at this point in the history
…read#9437)

This commit drops UDP datagrams from an untrusted origin to TMF port.

Examples of untrusted origin:
- A process other than OT on the host sends the packet to Thread
  network via platform API.
- A packet forwarded from infrastructure network to Thread network by
  Thread Border Router.

OT shouldn't allow UDP datagrams from untrusted origins going to TMF
port of any Thread device.

To implement this, there's an API `otIp6SendFromOrigin`
introduced. This can be used for specifying the origin of a packet you
want to send. This commit also encapsulates the 'origin' information
in `Message::Metadata`.
  • Loading branch information
superwhd authored Oct 5, 2023
1 parent a363396 commit e64f38a
Show file tree
Hide file tree
Showing 22 changed files with 317 additions and 98 deletions.
17 changes: 10 additions & 7 deletions include/openthread/coap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions include/openthread/ip6.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
50 changes: 50 additions & 0 deletions include/openthread/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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`.
Expand Down
5 changes: 3 additions & 2 deletions include/openthread/udp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 21 additions & 4 deletions src/core/api/coap_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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

Expand All @@ -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
10 changes: 8 additions & 2 deletions src/core/api/ip6_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,14 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled)

otError otIp6Send(otInstance *aInstance, otMessage *aMessage)
{
return AsCoreType(aInstance).Get<Ip6::Ip6>().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<Ip6::Ip6>().SendRaw(AsCoreType(aMessage));

exit:
return error;
}

otMessage *otIp6NewMessage(otInstance *aInstance, const otMessageSettings *aSettings)
Expand Down
17 changes: 17 additions & 0 deletions src/core/api/message_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 14 additions & 2 deletions src/core/api/udp_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ip6::Udp>().SendTo(AsCoreType(aSocket), AsCoreType(aMessage),
AsCoreType(aMessageInfo));
otError error;

VerifyOrExit(AsCoreType(aMessage).GetOrigin() != Message::kOriginThreadNetif, error = kErrorInvalidArgs);

error = AsCoreType(aInstance).Get<Ip6::Udp>().SendTo(AsCoreType(aSocket), AsCoreType(aMessage),
AsCoreType(aMessageInfo));
exit:
return error;
}

otUdpSocket *otUdpGetSockets(otInstance *aInstance) { return AsCoreType(aInstance).Get<Ip6::Udp>().GetUdpSockets(); }
Expand Down Expand Up @@ -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<Ip6::Udp>().SendDatagram(AsCoreType(aMessage), AsCoreType(aMessageInfo),
Ip6::kProtoUdp);
exit:
return error;
}

bool otUdpIsPortInUse(otInstance *aInstance, uint16_t port)
Expand Down
4 changes: 4 additions & 0 deletions src/core/common/message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand Down
71 changes: 61 additions & 10 deletions src/core/common/message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,16 +207,18 @@ class Buffer : public otMessageBuffer, public LinkedListEntry<Buffer>
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.
Expand Down Expand Up @@ -349,6 +351,17 @@ class Message : public otMessage, public Buffer, public GetProvider<Message>
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.
*
Expand Down Expand Up @@ -1135,6 +1148,42 @@ class Message : public otMessage, public Buffer, public GetProvider<Message>
*/
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<Origin>(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.
*
Expand Down Expand Up @@ -1798,6 +1847,8 @@ DefineCoreType(otMessageSettings, Message::Settings);
DefineCoreType(otMessage, Message);
DefineCoreType(otMessageQueue, MessageQueue);

DefineMapEnum(otMessageOrigin, Message::Origin);

} // namespace ot

#endif // MESSAGE_HPP_
Loading

0 comments on commit e64f38a

Please sign in to comment.