diff --git a/include/openthread-types.h b/include/openthread-types.h index c0fdb9619..a04903101 100644 --- a/include/openthread-types.h +++ b/include/openthread-types.h @@ -111,6 +111,11 @@ typedef enum ThreadError */ kThreadError_DestinationAddressFiltered = 24, + /** + * The requested item could not be found. + */ + kThreadError_NotFound = 25, + kThreadError_Error = 255, } ThreadError; diff --git a/include/openthread.h b/include/openthread.h index 33af5aa8c..b0f0413d5 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -586,6 +586,40 @@ ThreadError otRemoveExternalRoute(const otIp6Prefix *aPrefix); */ ThreadError otSendServerData(void); +/** + * This function adds a port to the allowed unsecured port list. + * + * @param[in] aPort The port value. + * + * @retval kThreadError_None The port was successfully added to the allowed unsecure port list. + * @retval kThreadError_NoBufs The unsecure port list is full. + * + */ +ThreadError otAddUnsecurePort(uint16_t aPort); + +/** + * This function removes a port from the allowed unsecure port list. + * + * @param[in] aPort The port value. + * + * @retval kThreadError_None The port was successfully removed from the allowed unsecure port list. + * @retval kThreadError_NotFound The port was not found in the unsecure port list. + * + */ +ThreadError otRemoveUnsecurePort(uint16_t aPort); + +/** + * This function returns a pointer to the unsecure port list. + * + * @note Port value 0 is used to indicate an invalid entry. + * + * @param[out] aNumEntries The number of entries in the list. + * + * @returns A pointer to the unsecure port list. + * + */ +const uint16_t *otGetUnsecurePorts(uint8_t *aNumEntries); + /** * @} * diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 374218db7..27432b426 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -50,6 +50,7 @@ libopenthread_a_SOURCES = \ net/icmp6.cpp \ net/ip6.cpp \ net/ip6_address.cpp \ + net/ip6_filter.cpp \ net/ip6_mpl.cpp \ net/ip6_routes.cpp \ net/netif.cpp \ @@ -87,6 +88,7 @@ noinst_HEADERS = \ net/icmp6.hpp \ net/ip6.hpp \ net/ip6_address.hpp \ + net/ip6_filter.hpp \ net/ip6_mpl.hpp \ net/ip6_routes.hpp \ net/netif.hpp \ diff --git a/src/core/net/ip6_filter.cpp b/src/core/net/ip6_filter.cpp new file mode 100644 index 000000000..f8217f6b4 --- /dev/null +++ b/src/core/net/ip6_filter.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file implements IPv6 datagram filtering. + */ + +#include + +#include +#include +#include +#include +#include + +namespace Thread { +namespace Ip6 { + +Filter::Filter(void) +{ + memset(mUnsecurePorts, 0, sizeof(mUnsecurePorts)); +} + +bool Filter::Accept(Message &aMessage) const +{ + bool rval = false; + Header ip6; + UdpHeader udp; + uint16_t dstport; + + // Allow all received IPv6 datagrams with link security enabled + if (aMessage.IsLinkSecurityEnabled()) + { + ExitNow(rval = true); + } + + // Read IPv6 header + VerifyOrExit(sizeof(ip6) == aMessage.Read(0, sizeof(ip6), &ip6), ;); + + // Allow only link-local unicast or multicast + VerifyOrExit(ip6.GetDestination().IsLinkLocal() || ip6.GetDestination().IsLinkLocalMulticast(), ;); + + // Allow only UDP traffic + VerifyOrExit(ip6.GetNextHeader() == kProtoUdp, ;); + + // Read UDP header + VerifyOrExit(sizeof(udp) == aMessage.Read(sizeof(ip6), sizeof(udp), &udp), ;); + dstport = udp.GetDestinationPort(); + + // Check for MLE traffic + if (dstport == Mle::kUdpPort) + { + ExitNow(rval = true); + } + + // Check against allowed unsecure port list + for (int i = 0; i < kMaxUnsecurePorts; i++) + { + if (mUnsecurePorts[i] != 0 && mUnsecurePorts[i] == dstport) + { + ExitNow(rval = true); + } + } + +exit: + return rval; +} + +ThreadError Filter::AddUnsecurePort(uint16_t aPort) +{ + ThreadError error = kThreadError_None; + + for (int i = 0; i < kMaxUnsecurePorts; i++) + { + if (mUnsecurePorts[i] == aPort) + { + ExitNow(); + } + } + + for (int i = 0; i < kMaxUnsecurePorts; i++) + { + if (mUnsecurePorts[i] == 0) + { + mUnsecurePorts[i] = aPort; + ExitNow(); + } + } + + ExitNow(error = kThreadError_NoBufs); + +exit: + return error; +} + +ThreadError Filter::RemoveUnsecurePort(uint16_t aPort) +{ + ThreadError error = kThreadError_None; + + for (int i = 0; i < kMaxUnsecurePorts; i++) + { + if (mUnsecurePorts[i] == aPort) + { + mUnsecurePorts[i] = 0; + ExitNow(); + } + } + + ExitNow(error = kThreadError_NotFound); + +exit: + return error; +} + +const uint16_t *Filter::GetUnsecurePorts(uint8_t &aNumEntries) const +{ + aNumEntries = kMaxUnsecurePorts; + return mUnsecurePorts; +} + +} // namespace Ip6 +} // namespace Thread diff --git a/src/core/net/ip6_filter.hpp b/src/core/net/ip6_filter.hpp new file mode 100644 index 000000000..38908730d --- /dev/null +++ b/src/core/net/ip6_filter.hpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Nest Labs, Inc. + * 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. + */ + +/** + * @file + * This file includes definitions for IPv6 datagram filtering. + */ + +#ifndef IP6_FILTER_HPP_ +#define IP6_FILTER_HPP_ + +#include + +namespace Thread { +namespace Ip6 { + +/** + * @addtogroup core-ipv6 + * + * @brief + * This module includes definitions for IPv6 datagram filtering. + * + * @{ + * + */ + +/** + * This class implements an IPv6 datagram filter. + * + */ +class Filter +{ +public: + /** + * This constructor initializes the Filter object. + * + */ + Filter(void); + + /** + * This method indicates whether or not the IPv6 datagram passes the filter. + * + * @param[in] aMessage The IPv6 datagram to process. + * + * @retval TRUE Accept the IPv6 datagram. + * @retval FALSE Reject the IPv6 datagram. + * + */ + bool Accept(Message &aMessage) const; + + /** + * This method adds a port to the allowed unsecured port list. + * + * @param[in] aPort The port value. + * + * @retval kThreadError_None The port was successfully added to the allowed unsecure port list. + * @retval kThreadError_NoBufs The unsecure port list is full. + * + */ + ThreadError AddUnsecurePort(uint16_t aPort); + + /** + * This method removes a port from the allowed unsecure port list. + * + * @param[in] aPort The port value. + * + * @retval kThreadError_None The port was successfully removed from the allowed unsecure port list. + * @retval kThreadError_NotFound The port was not found in the unsecure port list. + * + */ + ThreadError RemoveUnsecurePort(uint16_t aPort); + + /** + * This method returns a pointer to the unsecure port list. + * + * @note Port value 0 is used to indicate an invalid entry. + * + * @param[out] aNumEntries The number of entries in the list. + * + * @returns A pointer to the unsecure port list. + * + */ + const uint16_t *GetUnsecurePorts(uint8_t &aNumEntries) const; + +private: + enum + { + kMaxUnsecurePorts = 2, + }; + uint16_t mUnsecurePorts[kMaxUnsecurePorts]; +}; + +} // namespace Ip6 +} // namespace Thread + +#endif // IP6_FILTER_HPP_ diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index c68147fa9..8205d044e 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -328,6 +328,21 @@ ThreadError otSendServerData(void) return sThreadNetif->GetNetworkDataLocal().Register(destination); } +ThreadError otAddUnsecurePort(uint16_t aPort) +{ + return sThreadNetif->GetIp6Filter().AddUnsecurePort(aPort); +} + +ThreadError otRemoveUnsecurePort(uint16_t aPort) +{ + return sThreadNetif->GetIp6Filter().RemoveUnsecurePort(aPort); +} + +const uint16_t *otGetUnsecurePorts(uint8_t *aNumEntries) +{ + return sThreadNetif->GetIp6Filter().GetUnsecurePorts(*aNumEntries); +} + uint32_t otGetContextIdReuseDelay(void) { return sThreadNetif->GetNetworkDataLeader().GetContextIdReuseDelay(); diff --git a/src/core/thread/mesh_forwarder.cpp b/src/core/thread/mesh_forwarder.cpp index 8d259df39..32c52460f 100644 --- a/src/core/thread/mesh_forwarder.cpp +++ b/src/core/thread/mesh_forwarder.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1162,6 +1163,10 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength, message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity); headerLength = mLowpan.Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, datagramLength); VerifyOrExit(headerLength > 0, error = kThreadError_NoBufs); + + // Security Check + VerifyOrExit(mNetif.GetIp6Filter().Accept(*message), error = kThreadError_Drop); + aFrame += headerLength; aFrameLength -= headerLength; @@ -1263,6 +1268,10 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength, headerLength = mLowpan.Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, 0); VerifyOrExit(headerLength > 0, ;); + + // Security Check + VerifyOrExit(mNetif.GetIp6Filter().Accept(*message), error = kThreadError_Drop); + aFrame += headerLength; aFrameLength -= headerLength; @@ -1285,29 +1294,8 @@ exit: ThreadError MeshForwarder::HandleDatagram(Message &aMessage, const ThreadMessageInfo &aMessageInfo) { - ThreadError error = kThreadError_Drop; - Ip6::Header ip6; - Ip6::UdpHeader udp; - - // Security Check: only pass up IPv6 datagrams that were received with Security Enabled or all of the following: - // 1) Message contains IPv6 header - // 2) IPv6 Destination has link-local scope - // 3) IPv6 Next Header is UDP - // 4) Message contains UDP header - // 5) UDP Destination Port is the MLE port - VerifyOrExit(aMessage.IsLinkSecurityEnabled() || - (sizeof(ip6) == aMessage.Read(0, sizeof(ip6), &ip6) && - (ip6.GetDestination().IsLinkLocal() || ip6.GetDestination().IsLinkLocalMulticast()) && - ip6.GetNextHeader() == Ip6::kProtoUdp && - sizeof(udp) == aMessage.Read(sizeof(ip6), sizeof(udp), &udp) && - udp.GetDestinationPort() == Mle::kUdpPort), - ;); - Ip6::Ip6::HandleDatagram(aMessage, &mNetif, mNetif.GetInterfaceId(), &aMessageInfo, false); - error = kThreadError_None; - -exit: - return error; + return kThreadError_None; } void MeshForwarder::UpdateFramePending() diff --git a/src/core/thread/mesh_forwarder.hpp b/src/core/thread/mesh_forwarder.hpp index e59d05164..19a9516aa 100644 --- a/src/core/thread/mesh_forwarder.hpp +++ b/src/core/thread/mesh_forwarder.hpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -211,7 +210,7 @@ private: Tasklet mScheduleTransmissionTask; bool mEnabled; - Ip6::Netif &mNetif; + ThreadNetif &mNetif; AddressResolver &mAddressResolver; Lowpan::Lowpan &mLowpan; Mac::Mac &mMac; diff --git a/src/core/thread/thread_netif.hpp b/src/core/thread/thread_netif.hpp index e362d32ff..ed86c3888 100644 --- a/src/core/thread/thread_netif.hpp +++ b/src/core/thread/thread_netif.hpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -140,6 +141,14 @@ public: */ Coap::Server &GetCoapServer(void) { return mCoapServer; } + /** + * This method returns a reference to the IPv6 filter object. + * + * @returns A reference to the IPv6 filter object. + * + */ + Ip6::Filter &GetIp6Filter(void) { return mIp6Filter; } + /** * This method returns a pointer to the key manager object. * @@ -199,6 +208,7 @@ public: private: Coap::Server mCoapServer; AddressResolver mAddressResolver; + Ip6::Filter mIp6Filter; KeyManager mKeyManager; Lowpan::Lowpan mLowpan; Mac::Mac mMac;