From d0d2b71af38733fd539ce939f1c10f05316a678f Mon Sep 17 00:00:00 2001 From: Yakun Xu Date: Tue, 13 Oct 2020 23:10:29 +0800 Subject: [PATCH] [ip6] no anycast as source address (#5632) - Check source address of packets from users - Determine anycast address by MLE API for accuracy - Replace anycast address with a valid unicast address when sending with platform UDP in UDP layer - Replace anycast address with a valid unicast address in IP layer --- include/openthread/instance.h | 2 +- include/openthread/ip6.h | 12 +++--- src/core/net/ip6.cpp | 18 +++++---- src/core/net/udp6.cpp | 9 +++++ tests/scripts/expect/cli-anycast.exp | 56 ++++++++++++++++++++++++++++ tests/scripts/expect/v1_2-rcp.exp | 2 +- 6 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 tests/scripts/expect/cli-anycast.exp diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 3e39262e0..74eb2eeb2 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 (32) +#define OPENTHREAD_API_VERSION (33) /** * @addtogroup api-instance diff --git a/include/openthread/ip6.h b/include/openthread/ip6.h index 2ea857060..e71369497 100644 --- a/include/openthread/ip6.h +++ b/include/openthread/ip6.h @@ -486,11 +486,13 @@ void otIp6SetReceiveFilterEnabled(otInstance *aInstance, bool aEnabled); * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aMessage A pointer to the message buffer containing the IPv6 datagram. * - * @retval OT_ERROR_NONE Successfully processed the message. - * @retval OT_ERROR_DROP Message was well-formed but not fully processed due to packet processing rules. - * @retval OT_ERROR_NO_BUFS Could not allocate necessary message buffers when processing the datagram. - * @retval OT_ERROR_NO_ROUTE No route to host. - * @retval OT_ERROR_PARSE Encountered a malformed header when processing the message. + * @retval OT_ERROR_NONE Successfully processed the message. + * @retval OT_ERROR_DROP Message was well-formed but not fully processed due to packet processing + * rules. + * @retval OT_ERROR_NO_BUFS Could not allocate necessary message buffers when processing the datagram. + * @retval OT_ERROR_NO_ROUTE No route to host. + * @retval OT_ERROR_INVALID_SOURCE_ADDRESS Source addresss is invalid, e.g. an anycast address or a multicast address. + * @retval OT_ERROR_PARSE Encountered a malformed header when processing the message. * */ otError otIp6Send(otInstance *aInstance, otMessage *aMessage); diff --git a/src/core/net/ip6.cpp b/src/core/net/ip6.cpp index 72437dfa6..2d2b7848c 100644 --- a/src/core/net/ip6.cpp +++ b/src/core/net/ip6.cpp @@ -457,7 +457,8 @@ otError Ip6::SendDatagram(Message &aMessage, MessageInfo &aMessageInfo, uint8_t header.SetHopLimit(static_cast(kDefaultHopLimit)); } - if (aMessageInfo.GetSockAddr().IsUnspecified() || aMessageInfo.GetSockAddr().IsMulticast()) + if (aMessageInfo.GetSockAddr().IsUnspecified() || aMessageInfo.GetSockAddr().IsMulticast() || + Get().IsAnycastLocator(aMessageInfo.GetSockAddr())) { const NetifUnicastAddress *source = SelectSourceAddress(aMessageInfo); @@ -1071,6 +1072,8 @@ otError Ip6::SendRaw(Message &aMessage) bool freed = false; SuccessOrExit(error = header.Init(aMessage)); + VerifyOrExit(!header.GetSource().IsMulticast() && !Get().IsAnycastLocator(header.GetSource()), + error = OT_ERROR_INVALID_SOURCE_ADDRESS); messageInfo.SetPeerAddr(header.GetSource()); messageInfo.SetSockAddr(header.GetDestination()); @@ -1301,10 +1304,11 @@ exit: const NetifUnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) { - Address * destination = &aMessageInfo.GetPeerAddr(); - uint8_t destinationScope = destination->GetScope(); - const NetifUnicastAddress *rvalAddr = nullptr; - uint8_t rvalPrefixMatched = 0; + Address * destination = &aMessageInfo.GetPeerAddr(); + uint8_t destinationScope = destination->GetScope(); + const bool destinationIsRoutingLocator = Get().IsRoutingLocator(*destination); + const NetifUnicastAddress *rvalAddr = nullptr; + uint8_t rvalPrefixMatched = 0; for (const NetifUnicastAddress *addr = Get().GetUnicastAddresses(); addr; addr = addr->GetNext()) { @@ -1312,7 +1316,7 @@ const NetifUnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) uint8_t candidatePrefixMatched; uint8_t overrideScope; - if (candidateAddr->GetIid().IsAnycastLocator()) + if (Get().IsAnycastLocator(*candidateAddr)) { // Don't use anycast address as source address. continue; @@ -1382,7 +1386,7 @@ const NetifUnicastAddress *Ip6::SelectSourceAddress(MessageInfo &aMessageInfo) rvalPrefixMatched = candidatePrefixMatched; } else if ((candidatePrefixMatched == rvalPrefixMatched) && - (destination->GetIid().IsRoutingLocator() == candidateAddr->GetIid().IsRoutingLocator())) + (destinationIsRoutingLocator == Get().IsRoutingLocator(*candidateAddr))) { // Additional rule: Prefer RLOC source for RLOC destination, EID source for anything else rvalAddr = addr; diff --git a/src/core/net/udp6.cpp b/src/core/net/udp6.cpp index c4b8e18f6..d4b493a48 100644 --- a/src/core/net/udp6.cpp +++ b/src/core/net/udp6.cpp @@ -327,6 +327,15 @@ otError Udp::SendTo(SocketHandle &aSocket, Message &aMessage, const MessageInfo if (!IsMlePort(aSocket.mSockName.mPort) && !(aSocket.mSockName.mPort == Tmf::kUdpPort && aMessage.GetSubType() == Message::kSubTypeJoinerEntrust)) { + // Replace anycast address with a valid unicast address since response messages typically copy the peer address + if (Get().IsAnycastLocator(messageInfoLocal.GetSockAddr())) + { + const NetifUnicastAddress *netifAddr = Get().SelectSourceAddress(messageInfoLocal); + + VerifyOrExit(netifAddr != nullptr, error = OT_ERROR_INVALID_ARGS); + messageInfoLocal.SetSockAddr(netifAddr->GetAddress()); + } + SuccessOrExit(error = otPlatUdpSend(&aSocket, &aMessage, &messageInfoLocal)); } else diff --git a/tests/scripts/expect/cli-anycast.exp b/tests/scripts/expect/cli-anycast.exp new file mode 100644 index 000000000..3081a6bea --- /dev/null +++ b/tests/scripts/expect/cli-anycast.exp @@ -0,0 +1,56 @@ +#!/usr/bin/expect -f +# +# Copyright (c) 2020, The OpenThread Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +source "tests/scripts/expect/_common.exp" + + +set spawn_id [spawn_node 1] + +send "panid 0xface\n" +expect "Done" +send "ifconfig up\n" +expect "Done" +send "thread start\n" +expect "Done" + +wait_for "state" "leader" +expect "Done" + +send "ping fdde:ad00:beef:0:0:ff:fe00:fc00\n" +expect "Done" +expect "16 bytes from " +expect { + "fdde:ad00:beef:0:0:ff:fe00:fc00" abort + + -re {(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4})} {} + + timeout abort +} + +dispose diff --git a/tests/scripts/expect/v1_2-rcp.exp b/tests/scripts/expect/v1_2-rcp.exp index abbf2c986..fce8e5fe0 100755 --- a/tests/scripts/expect/v1_2-rcp.exp +++ b/tests/scripts/expect/v1_2-rcp.exp @@ -40,7 +40,7 @@ expect "Done" wait_for "state" "leader" expect "Done" -send "ipaddr\n" +send "ipaddr mleid\n" expect -re {(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4})} set addr $expect_out(1,string) expect "Done"