[ip6] drop UDP datagrams from an untrusted origin to TMF port (#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`.
This commit is contained in:
whd
2023-10-05 09:50:57 -07:00
committed by GitHub
parent a363396eb5
commit e64f38a816
22 changed files with 317 additions and 98 deletions
+10 -7
View File
@@ -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,
+1 -1
View File
@@ -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
+2
View File
@@ -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);
+50
View File
@@ -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`.
+3 -2
View File
@@ -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);
+21 -4
View File
@@ -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
+8 -2
View File
@@ -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)
+17
View File
@@ -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)
+14 -2
View File
@@ -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(); }
@@ -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)
+4
View File
@@ -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
+61 -10
View File
@@ -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<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.
*
@@ -1798,6 +1847,8 @@ DefineCoreType(otMessageSettings, Message::Settings);
DefineCoreType(otMessage, Message);
DefineCoreType(otMessageQueue, MessageQueue);
DefineMapEnum(otMessageOrigin, Message::Origin);
} // namespace ot
#endif // MESSAGE_HPP_
+49 -37
View File
@@ -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<ChildTable>().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<ThreadNetif>().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<BackboneRouter::Manager>().ShouldForwardDuaToBackbone(header.GetDestination()));
#else
forwardThread = true;
@@ -1228,7 +1226,7 @@ start:
// Process IPv6 Extension Headers
nextHeader = static_cast<uint8_t>(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<Mle::Mle>().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;
+8 -29
View File
@@ -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);
+4
View File
@@ -406,6 +406,8 @@ void Mpl::HandleRetransmissionTimer(void)
messageCopy->SetSubType(Message::kSubTypeMplRetransmission);
}
messageCopy->SetLoopbackToHostAllowed(true);
messageCopy->SetOrigin(Message::kOriginHostTrusted);
Get<Ip6>().EnqueueDatagram(*messageCopy);
}
@@ -426,6 +428,8 @@ void Mpl::HandleRetransmissionTimer(void)
}
metadata.RemoveFrom(message);
message.SetLoopbackToHostAllowed(true);
message.SetOrigin(Message::kOriginHostTrusted);
Get<Ip6>().EnqueueDatagram(message);
}
else
+1 -1
View File
@@ -99,7 +99,7 @@ Error Translator::SendMessage(Message &aMessage)
VerifyOrExit(result == kForward);
error = Get<Ip6::Ip6>().SendRaw(aMessage, !OPENTHREAD_CONFIG_IP6_ALLOW_LOOP_BACK_HOST_DATAGRAMS);
error = Get<Ip6::Ip6>().SendRaw(aMessage);
freed = true;
exit:
+4 -1
View File
@@ -1660,7 +1660,10 @@ Error MeshForwarder::HandleDatagram(Message &aMessage, const ThreadLinkInfo &aLi
mIpCounters.mRxSuccess++;
}
return Get<Ip6::Ip6>().HandleDatagram(aMessage, Ip6::Ip6::kFromThreadNetif, &aLinkInfo);
aMessage.SetLoopbackToHostAllowed(true);
aMessage.SetOrigin(Message::kOriginThreadNetif);
return Get<Ip6::Ip6>().HandleDatagram(aMessage, &aLinkInfo);
}
Error MeshForwarder::GetFramePriority(const FrameData &aFrameData,
+3 -1
View File
@@ -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<Ip6::Ip6>().HandleDatagram(message, Ip6::Ip6::kFromHostAllowLoopBack));
IgnoreError(Get<Ip6::Ip6>().HandleDatagram(message));
continue;
}
#endif
+2
View File
@@ -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
@@ -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()
+1
View File
@@ -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:'
View File
+27
View File
@@ -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++)