mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[nat64] add functions for processing IPv4 packets (#7824)
With NAT64, we need to handle the IPv4 packets inside the border router functions in OpenThread core. This commit introduces a few new classes for NAT64: - Add `Ip4::Cidr` (for specifying CIDR block of translated packets) - Updated Ip4 address format -- use a union of (m8[4], m16[2], m32) instead of 4 bytes. - Extend `Checksum` for supporting ICMP in Ip4 (and TCP4 / UDP4) and IPv4 header.
This commit is contained in:
+1
-1
@@ -298,7 +298,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/net/dns_types.cpp \
|
||||
src/core/net/dnssd_server.cpp \
|
||||
src/core/net/icmp6.cpp \
|
||||
src/core/net/ip4_address.cpp \
|
||||
src/core/net/ip4_types.cpp \
|
||||
src/core/net/ip6.cpp \
|
||||
src/core/net/ip6_address.cpp \
|
||||
src/core/net/ip6_filter.cpp \
|
||||
|
||||
@@ -70,6 +70,7 @@ openthread_headers = \
|
||||
openthread/logging.h \
|
||||
openthread/message.h \
|
||||
openthread/multi_radio.h \
|
||||
openthread/nat64.h \
|
||||
openthread/ncp.h \
|
||||
openthread/netdata.h \
|
||||
openthread/netdata_publisher.h \
|
||||
|
||||
@@ -74,6 +74,7 @@ source_set("openthread") {
|
||||
"logging.h",
|
||||
"message.h",
|
||||
"multi_radio.h",
|
||||
"nat64.h",
|
||||
"ncp.h",
|
||||
"netdata.h",
|
||||
"netdata_publisher.h",
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (226)
|
||||
#define OPENTHREAD_API_VERSION (227)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, The OpenThread Authors.
|
||||
* Copyright (c) 2022, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,69 +28,72 @@
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements IPv4 address related functionality.
|
||||
* @brief
|
||||
* This file defines the OpenThread API for NAT64 on a border router.
|
||||
*/
|
||||
|
||||
#include "ip4_address.hpp"
|
||||
#ifndef OPENTHREAD_NAT64_H_
|
||||
#define OPENTHREAD_NAT64_H_
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/numeric_limits.hpp"
|
||||
#include <openthread/message.h>
|
||||
|
||||
namespace ot {
|
||||
namespace Ip4 {
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
Error Address::FromString(const char *aString)
|
||||
/**
|
||||
* @addtogroup api-nat64
|
||||
*
|
||||
* @brief This module includes functions and structs for the NAT64 function on the border router. These functions are
|
||||
* only available when `OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE` is enabled.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
#define OT_IP4_ADDRESS_SIZE 4 ///< Size of an IPv4 address (bytes)
|
||||
|
||||
/**
|
||||
* @struct otIp4Address
|
||||
*
|
||||
* This structure represents an IPv4 address.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct otIp4Address
|
||||
{
|
||||
constexpr char kSeperatorChar = '.';
|
||||
constexpr char kNullChar = '\0';
|
||||
|
||||
Error error = kErrorParse;
|
||||
|
||||
for (uint8_t index = 0;; index++)
|
||||
union OT_TOOL_PACKED_FIELD
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint8_t hasFirstDigit = false;
|
||||
uint8_t m8[OT_IP4_ADDRESS_SIZE]; ///< 8-bit fields
|
||||
uint32_t m32; ///< 32-bit representation
|
||||
} mFields;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
for (char digitChar = *aString;; ++aString, digitChar = *aString)
|
||||
{
|
||||
if ((digitChar < '0') || (digitChar > '9'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* This structure represents an IPv4 address.
|
||||
*
|
||||
*/
|
||||
typedef struct otIp4Address otIp4Address;
|
||||
|
||||
value = static_cast<uint16_t>((value * 10) + static_cast<uint8_t>(digitChar - '0'));
|
||||
VerifyOrExit(value <= NumericLimits<uint8_t>::kMax);
|
||||
hasFirstDigit = true;
|
||||
}
|
||||
|
||||
VerifyOrExit(hasFirstDigit);
|
||||
|
||||
mBytes[index] = static_cast<uint8_t>(value);
|
||||
|
||||
if (index == sizeof(Address) - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kSeperatorChar);
|
||||
aString++;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kNullChar);
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Address::InfoString Address::ToString(void) const
|
||||
/**
|
||||
* @struct otIp4Cidr
|
||||
*
|
||||
* This structure represents an IPv4 CIDR block.
|
||||
*
|
||||
*/
|
||||
typedef struct otIp4Cidr
|
||||
{
|
||||
InfoString string;
|
||||
otIp4Address mAddress;
|
||||
uint8_t mLength;
|
||||
} otIp4Cidr;
|
||||
|
||||
string.Append("%d.%d.%d.%d", mBytes[0], mBytes[1], mBytes[2], mBytes[3]);
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
return string;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Ip4
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_NAT64_H_
|
||||
+2
-2
@@ -548,8 +548,8 @@ openthread_core_files = [
|
||||
"net/dnssd_server.hpp",
|
||||
"net/icmp6.cpp",
|
||||
"net/icmp6.hpp",
|
||||
"net/ip4_address.cpp",
|
||||
"net/ip4_address.hpp",
|
||||
"net/ip4_types.cpp",
|
||||
"net/ip4_types.hpp",
|
||||
"net/ip6.cpp",
|
||||
"net/ip6.hpp",
|
||||
"net/ip6_address.cpp",
|
||||
|
||||
@@ -164,7 +164,7 @@ set(COMMON_SOURCES
|
||||
net/dns_types.cpp
|
||||
net/dnssd_server.cpp
|
||||
net/icmp6.cpp
|
||||
net/ip4_address.cpp
|
||||
net/ip4_types.cpp
|
||||
net/ip6.cpp
|
||||
net/ip6_address.cpp
|
||||
net/ip6_filter.cpp
|
||||
|
||||
@@ -254,7 +254,7 @@ SOURCES_COMMON = \
|
||||
net/dns_types.cpp \
|
||||
net/dnssd_server.cpp \
|
||||
net/icmp6.cpp \
|
||||
net/ip4_address.cpp \
|
||||
net/ip4_types.cpp \
|
||||
net/ip6.cpp \
|
||||
net/ip6_address.cpp \
|
||||
net/ip6_filter.cpp \
|
||||
@@ -559,7 +559,7 @@ HEADERS_COMMON = \
|
||||
net/dns_types.hpp \
|
||||
net/dnssd_server.hpp \
|
||||
net/icmp6.hpp \
|
||||
net/ip4_address.hpp \
|
||||
net/ip4_types.hpp \
|
||||
net/ip6.hpp \
|
||||
net/ip6_address.hpp \
|
||||
net/ip6_filter.hpp \
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/tcp6.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
|
||||
@@ -115,6 +116,35 @@ void Checksum::Calculate(const Ip6::Address &aSource,
|
||||
}
|
||||
}
|
||||
|
||||
void Checksum::Calculate(const Ip4::Address &aSource,
|
||||
const Ip4::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage)
|
||||
{
|
||||
Message::Chunk chunk;
|
||||
uint16_t length = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
// Pseudo-header for checksum calculation (RFC-768/792/793).
|
||||
// Note: ICMP checksum won't count the presudo header like TCP and UDP.
|
||||
if (aIpProto != Ip4::kProtoIcmp)
|
||||
{
|
||||
AddData(aSource.GetBytes(), sizeof(Ip4::Address));
|
||||
AddData(aDestination.GetBytes(), sizeof(Ip4::Address));
|
||||
AddUint16(static_cast<uint16_t>(aIpProto));
|
||||
AddUint16(length);
|
||||
}
|
||||
|
||||
// Add message content (from offset to the end) to checksum.
|
||||
|
||||
aMessage.GetFirstChunk(aMessage.GetOffset(), length, chunk);
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
AddData(chunk.GetBytes(), chunk.GetLength());
|
||||
aMessage.GetNextChunk(length, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
Error Checksum::VerifyMessageChecksum(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint8_t aIpProto)
|
||||
{
|
||||
Checksum checksum;
|
||||
@@ -150,6 +180,8 @@ void Checksum::UpdateMessageChecksum(Message & aMessage,
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Clear the checksum before calculating it.
|
||||
aMessage.Write<uint16_t>(aMessage.GetOffset() + headerOffset, 0);
|
||||
checksum.Calculate(aSource, aDestination, aIpProto, aMessage);
|
||||
checksum.WriteToMessage(aMessage.GetOffset() + headerOffset, aMessage);
|
||||
|
||||
@@ -157,4 +189,48 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Checksum::UpdateMessageChecksum(Message & aMessage,
|
||||
const Ip4::Address &aSource,
|
||||
const Ip4::Address &aDestination,
|
||||
uint8_t aIpProto)
|
||||
{
|
||||
uint16_t headerOffset;
|
||||
Checksum checksum;
|
||||
|
||||
switch (aIpProto)
|
||||
{
|
||||
case Ip4::kProtoTcp:
|
||||
headerOffset = Ip4::Tcp::Header::kChecksumFieldOffset;
|
||||
break;
|
||||
|
||||
case Ip4::kProtoUdp:
|
||||
headerOffset = Ip4::Udp::Header::kChecksumFieldOffset;
|
||||
break;
|
||||
|
||||
case Ip4::kProtoIcmp:
|
||||
headerOffset = Ip4::Icmp::Header::kChecksumFieldOffset;
|
||||
break;
|
||||
|
||||
default:
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Clear the checksum before calculating it.
|
||||
aMessage.Write<uint16_t>(aMessage.GetOffset() + headerOffset, 0);
|
||||
checksum.Calculate(aSource, aDestination, aIpProto, aMessage);
|
||||
checksum.WriteToMessage(aMessage.GetOffset() + headerOffset, aMessage);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Checksum::UpdateIp4HeaderChecksum(Ip4::Header &aHeader)
|
||||
{
|
||||
Checksum checksum;
|
||||
|
||||
aHeader.SetChecksum(0);
|
||||
checksum.AddData(reinterpret_cast<const uint8_t *>(&aHeader), sizeof(aHeader));
|
||||
aHeader.SetChecksum(~checksum.GetValue());
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/message.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "net/ip6_headers.hpp"
|
||||
#include "net/socket.hpp"
|
||||
@@ -69,11 +70,11 @@ public:
|
||||
static Error VerifyMessageChecksum(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo, uint8_t aIpProto);
|
||||
|
||||
/**
|
||||
* This static method calculates and then updates the checksum in a given message (if UDP/ICMP6).
|
||||
* This static method calculates and then updates the checksum in a given message (if TCP/UDP/ICMPv6).
|
||||
*
|
||||
* @param[in,out] aMessage The message to update the checksum in. The `aMessage.GetOffset()` should point to start
|
||||
* of the UDP/ICMP6 header. On exit the checksum field in UDP/ICMP6 header in the message
|
||||
* is updated.
|
||||
* of the TCP/UDP/ICMPv6 header. On exit the checksum field in TCP/UDP/ICMPv6 header in the
|
||||
* message is updated.
|
||||
* @param[in] aSource The source address.
|
||||
* @param[in] aDestination The destination address.
|
||||
* @param[in] aIpProto The Internet Protocol value.
|
||||
@@ -84,6 +85,30 @@ public:
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto);
|
||||
|
||||
/**
|
||||
* This static method calculates and then updates the checksum in a given IPv4 message (if TCP/UDP/ICMP(v4)).
|
||||
*
|
||||
* @param[in,out] aMessage The message to update the checksum in. The `aMessage.GetOffset()` should point to start
|
||||
* of the TCP/UDP/ICMP(v4) header. On exit the checksum field in TCP/UDP/ICMP(v4) header in
|
||||
* the message is updated.
|
||||
* @param[in] aSource The source address.
|
||||
* @param[in] aDestination The destination address.
|
||||
* @param[in] aIpProto The Internet Protocol value.
|
||||
*
|
||||
*/
|
||||
static void UpdateMessageChecksum(Message & aMessage,
|
||||
const Ip4::Address &aSource,
|
||||
const Ip4::Address &aDestination,
|
||||
uint8_t aIpProto);
|
||||
|
||||
/**
|
||||
* This static method calculates and then updates the checksum field in the IPv4 header.
|
||||
*
|
||||
* @param[in,out] aHeader The IPv4 header to update the checksum in.
|
||||
*
|
||||
*/
|
||||
static void UpdateIp4HeaderChecksum(Ip4::Header &aHeader);
|
||||
|
||||
private:
|
||||
Checksum(void)
|
||||
: mValue(0)
|
||||
@@ -100,6 +125,10 @@ private:
|
||||
const Ip6::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage);
|
||||
void Calculate(const Ip4::Address &aSource,
|
||||
const Ip4::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage);
|
||||
|
||||
static constexpr uint16_t kValidRxChecksum = 0xffff;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "crypto/ecdsa.hpp"
|
||||
#include "net/ip4_address.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for IPv4 addresses.
|
||||
*/
|
||||
|
||||
#ifndef IP4_ADDRESS_HPP_
|
||||
#define IP4_ADDRESS_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/clearable.hpp"
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/error.hpp"
|
||||
#include "common/string.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Ip4 {
|
||||
|
||||
/**
|
||||
* This class represents an IPv4 address.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Address : public Equatable<Address>, public Clearable<Address>
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kSize = 4; ///< Size of an IPv4 Address (in bytes).
|
||||
static constexpr uint16_t kAddressStringSize = 17; ///< String size used by `ToString()`.
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<kAddressStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method gets the IPv4 address as a pointer to a byte array.
|
||||
*
|
||||
* @returns A pointer to a byte array containing the IPv4 address.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mBytes; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 address from a given byte array.
|
||||
*
|
||||
* @param[in] aBuffer Pointer to an array containing the IPv4 address. `kSize` bytes from the buffer
|
||||
* are copied to form the IPv4 address.
|
||||
*
|
||||
*/
|
||||
void SetBytes(const uint8_t *aBuffer) { memcpy(mBytes, aBuffer, kSize); }
|
||||
|
||||
/**
|
||||
* This method parses an IPv4 address string.
|
||||
*
|
||||
* The string MUST follow the quad-dotted notation of four decimal values (ranging from 0 to 255 each). For
|
||||
* example, "127.0.0.1"
|
||||
*
|
||||
* @param[in] aString A pointer to the null-terminated string.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the IPv4 address string.
|
||||
* @retval kErrorParse Failed to parse the IPv4 address string.
|
||||
*
|
||||
*/
|
||||
Error FromString(const char *aString);
|
||||
|
||||
/**
|
||||
* This method converts the IPv4 address to a string.
|
||||
*
|
||||
* The string format uses quad-dotted notation of four bytes in the address (e.g., "127.0.0.1").
|
||||
*
|
||||
* @returns An `InfoString` representing the IPv4 address.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
uint8_t mBytes[kSize];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
} // namespace Ip4
|
||||
} // namespace ot
|
||||
|
||||
#endif // IP4_ADDRESS_HPP_
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements IP4 headers processing.
|
||||
*/
|
||||
|
||||
#include "ip4_types.hpp"
|
||||
#include "ip6_address.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Ip4 {
|
||||
|
||||
Error Address::FromString(const char *aString)
|
||||
{
|
||||
constexpr char kSeperatorChar = '.';
|
||||
constexpr char kNullChar = '\0';
|
||||
|
||||
Error error = kErrorParse;
|
||||
|
||||
for (uint8_t index = 0;; index++)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
uint8_t hasFirstDigit = false;
|
||||
|
||||
for (char digitChar = *aString;; ++aString, digitChar = *aString)
|
||||
{
|
||||
if ((digitChar < '0') || (digitChar > '9'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
value = static_cast<uint16_t>((value * 10) + static_cast<uint8_t>(digitChar - '0'));
|
||||
VerifyOrExit(value <= NumericLimits<uint8_t>::kMax);
|
||||
hasFirstDigit = true;
|
||||
}
|
||||
|
||||
VerifyOrExit(hasFirstDigit);
|
||||
|
||||
mFields.m8[index] = static_cast<uint8_t>(value);
|
||||
|
||||
if (index == sizeof(Address) - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kSeperatorChar);
|
||||
aString++;
|
||||
}
|
||||
|
||||
VerifyOrExit(*aString == kNullChar);
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Address::ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address)
|
||||
{
|
||||
// The prefix length must be 32, 40, 48, 56, 64, 96. IPv4 bytes are added
|
||||
// after the prefix, skipping over the bits 64 to 71 (byte at `kSkipIndex`)
|
||||
// which must be set to zero. The suffix is set to zero (per RFC 6502).
|
||||
//
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |32| prefix |v4(32) | u | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |40| prefix |v4(24) | u |(8)| suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |48| prefix |v4(16) | u | (16) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |56| prefix |(8)| u | v4(24) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |64| prefix | u | v4(32) | suffix |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
// |96| prefix | v4(32) |
|
||||
// +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
|
||||
constexpr uint8_t kSkipIndex = 8;
|
||||
|
||||
uint8_t ip6Index;
|
||||
|
||||
OT_ASSERT(Ip6::Prefix::IsValidNat64PrefixLength(aPrefixLength));
|
||||
|
||||
ip6Index = aPrefixLength / CHAR_BIT;
|
||||
|
||||
for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
|
||||
{
|
||||
if (ip6Index == kSkipIndex)
|
||||
{
|
||||
ip6Index++;
|
||||
}
|
||||
|
||||
mFields.m8[i] = aIp6Address.GetBytes()[ip6Index++];
|
||||
}
|
||||
}
|
||||
|
||||
void Address::SynthesizeFromCidrAndHost(const Cidr &aCidr, const uint32_t aHost)
|
||||
{
|
||||
mFields.m32 = (aCidr.mAddress.mFields.m32 & aCidr.SubnetMask()) | (HostSwap32(aHost) & aCidr.HostMask());
|
||||
}
|
||||
|
||||
Address::InfoString Address::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.Append("%d.%d.%d.%d", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3]);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
Cidr::InfoString Cidr::ToString(void) const
|
||||
{
|
||||
InfoString string;
|
||||
|
||||
string.Append("%s/%d", AsCoreType(&mAddress).ToString().AsCString(), mLength);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
bool Cidr::operator==(const Cidr &aOther) const
|
||||
{
|
||||
return (mLength == aOther.mLength) &&
|
||||
(Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
|
||||
}
|
||||
|
||||
void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
|
||||
{
|
||||
memcpy(mAddress.mFields.m8, aAddress, Ip4::Address::kSize);
|
||||
mLength = aLength;
|
||||
}
|
||||
|
||||
Error Header::ParseFrom(const Message &aMessage)
|
||||
{
|
||||
Error error = kErrorParse;
|
||||
|
||||
SuccessOrExit(aMessage.Read(0, *this));
|
||||
VerifyOrExit(IsValid());
|
||||
VerifyOrExit(GetTotalLength() == aMessage.GetLength());
|
||||
|
||||
error = kErrorNone;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace Ip4
|
||||
} // namespace ot
|
||||
@@ -0,0 +1,672 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for IPv4 packet processing.
|
||||
*/
|
||||
|
||||
#ifndef IP4_TYPES_HPP_
|
||||
#define IP4_TYPES_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <openthread/nat64.h>
|
||||
|
||||
#include "common/clearable.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "net/ip6_types.hpp"
|
||||
#include "net/netif.hpp"
|
||||
#include "net/socket.hpp"
|
||||
#include "net/tcp6.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
namespace Ip6 {
|
||||
// Forward declaration for ExtractFromIp4Address
|
||||
class Address;
|
||||
} // namespace Ip6
|
||||
|
||||
/**
|
||||
* @namespace ot::Ip4
|
||||
*
|
||||
* @brief
|
||||
* This namespace includes definitions for IPv4 networking used by NAT64.
|
||||
*
|
||||
*/
|
||||
namespace Ip4 {
|
||||
|
||||
using Encoding::BigEndian::HostSwap16;
|
||||
using Encoding::BigEndian::HostSwap32;
|
||||
|
||||
using Ecn = Ip6::Ecn;
|
||||
|
||||
/**
|
||||
* @addtogroup core-ipv4
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for the IPv4 network layer.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup core-ip4-ip4
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for IPv4 networking used by NAT64.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
// Forward declaration for Address::SynthesizeFromCidrAndHost
|
||||
class Cidr;
|
||||
|
||||
/**
|
||||
* This class represents an IPv4 address.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Address : public otIp4Address, public Equatable<Address>, public Clearable<Address>
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kSize = 4; ///< Size of an IPv4 Address (in bytes).
|
||||
static constexpr uint16_t kAddressStringSize = 17; ///< String size used by `ToString()`.
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<kAddressStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method gets the IPv4 address as a pointer to a byte array.
|
||||
*
|
||||
* @returns A pointer to a byte array containing the IPv4 address.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mFields.m8; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 address from a given byte array.
|
||||
*
|
||||
* @param[in] aBuffer Pointer to an array containing the IPv4 address. `kSize` bytes from the buffer
|
||||
* are copied to form the IPv4 address.
|
||||
*
|
||||
*/
|
||||
void SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 address by performing NAT64 address translation from a given IPv6 address as specified
|
||||
* in RFC 6052.
|
||||
*
|
||||
* The NAT64 @p aPrefixLength MUST be one of the following values: 32, 40, 48, 56, 64, or 96, otherwise the behavior
|
||||
* of this method is undefined.
|
||||
*
|
||||
* @param[in] aPrefixLength The prefix length to use for IPv4/IPv6 translation.
|
||||
* @param[in] aIp6Address The IPv6 address to translate to IPv4.
|
||||
*
|
||||
*/
|
||||
void ExtractFromIp6Address(uint8_t aPrefixLength, const Ip6::Address &aIp6Address);
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 address from the given CIDR and the host field.
|
||||
*
|
||||
* @param[in] aCidr The CIDR for the IPv4 address.
|
||||
* @param[in] aHost The host bits of the IPv4 address in host byte order. The aHost will be masked by host mask.
|
||||
*
|
||||
*/
|
||||
void SynthesizeFromCidrAndHost(const Cidr &aCidr, uint32_t aHost);
|
||||
|
||||
/**
|
||||
* This method parses an IPv4 address string.
|
||||
*
|
||||
* The string MUST follow the quad-dotted notation of four decimal values (ranging from 0 to 255 each). For
|
||||
* example, "127.0.0.1"
|
||||
*
|
||||
* @param[in] aString A pointer to the null-terminated string.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the IPv4 address string.
|
||||
* @retval kErrorParse Failed to parse the IPv4 address string.
|
||||
*
|
||||
*/
|
||||
Error FromString(const char *aString);
|
||||
|
||||
/**
|
||||
* This method converts the IPv4 address to a string.
|
||||
*
|
||||
* The string format uses quad-dotted notation of four bytes in the address (e.g., "127.0.0.1").
|
||||
*
|
||||
* @returns An `InfoString` representing the IPv4 address.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class represents an IPv4 CIDR block.
|
||||
*
|
||||
*/
|
||||
class Cidr : public otIp4Cidr, public Unequatable<Cidr>, public Clearable<Address>
|
||||
{
|
||||
friend class Address;
|
||||
|
||||
public:
|
||||
static constexpr uint16_t kCidrSuffixSize = 3; ///< Suffix to represent CIDR (/dd).
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()`.
|
||||
*
|
||||
*/
|
||||
typedef String<Address::kAddressStringSize + kCidrSuffixSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method converts the IPv4 CIDR to a string.
|
||||
*
|
||||
* The string format uses quad-dotted notation of four bytes in the address with the length of prefix (e.g.,
|
||||
* "127.0.0.1/32").
|
||||
*
|
||||
* @returns An `InfoString` representing the IPv4 cidr.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
/**
|
||||
* This method gets the prefix as a pointer to a byte array.
|
||||
*
|
||||
* @returns A pointer to a byte array containing the Prefix.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mAddress.mFields.m8; }
|
||||
|
||||
/**
|
||||
* This method overloads operator `==` to evaluate whether or not two prefixes are equal.
|
||||
*
|
||||
* @param[in] aOther The other prefix to compare with.
|
||||
*
|
||||
* @retval TRUE If the two prefixes are equal.
|
||||
* @retval FALSE If the two prefixes are not equal.
|
||||
*
|
||||
*/
|
||||
bool operator==(const Cidr &aOther) const;
|
||||
|
||||
/**
|
||||
* This method sets the CIDR.
|
||||
*
|
||||
* @param[in] aAddress A pointer to buffer containing the CIDR bytes. The length of aAddress should be 4 bytes.
|
||||
* @param[in] aLength The length of CIDR in bits.
|
||||
*
|
||||
*/
|
||||
void Set(const uint8_t *aAddress, uint8_t aLength);
|
||||
|
||||
private:
|
||||
uint32_t HostMask(void) const
|
||||
{
|
||||
// Note: Using LL suffix to make it a uint64 since /32 is a valid CIDR, and right shifting 32 bits is undefined
|
||||
// for uint32.
|
||||
return HostSwap32(0xffffffffLL >> mLength);
|
||||
}
|
||||
|
||||
uint32_t SubnetMask(void) const { return ~HostMask(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements IPv4 header generation and parsing.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Header : public Clearable<Header>
|
||||
{
|
||||
public:
|
||||
static constexpr uint8_t kVersionIhlOffset = 0;
|
||||
static constexpr uint8_t kTrafficClassOffset = 1;
|
||||
static constexpr uint8_t kTotalLengthOffset = 2;
|
||||
static constexpr uint8_t kIdenficationOffset = 4;
|
||||
static constexpr uint8_t kFlagsFragmentOffset = 6;
|
||||
static constexpr uint8_t kTtlOffset = 8;
|
||||
static constexpr uint8_t kProtocolOffset = 9;
|
||||
static constexpr uint8_t kHeaderChecksumOffset = 10;
|
||||
static constexpr uint8_t kSourceAddressOffset = 12;
|
||||
static constexpr uint8_t kDestinationAddressOffset = 16;
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the header appears to be well-formed.
|
||||
*
|
||||
* @retval TRUE If the header appears to be well-formed.
|
||||
* @retval FALSE If the header does not appear to be well-formed.
|
||||
*
|
||||
*/
|
||||
bool IsValid(void) const { return IsVersion4(); }
|
||||
|
||||
/**
|
||||
* This method initializes the Version to 4 and sets Traffic Class and Flow fields to zero.
|
||||
*
|
||||
* The other fields in the IPv4 header remain unchanged.
|
||||
*
|
||||
*/
|
||||
void InitVersionIhl(void) { SetVersionIhl(kVersIhlInit); }
|
||||
|
||||
/**
|
||||
* This method sets the version and Ihl of the IPv4 header.
|
||||
*
|
||||
* @param[in] aVersionIhl The octet for the version and Ihl field.
|
||||
*
|
||||
*/
|
||||
void SetVersionIhl(uint8_t aVersionIhl) { mVersIhl = aVersionIhl; }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the IPv4 Version is set to 6.
|
||||
*
|
||||
* @retval TRUE If the IPv4 Version is set to 4.
|
||||
* @retval FALSE If the IPv4 Version is not set to 4.
|
||||
*
|
||||
*/
|
||||
bool IsVersion4(void) const { return (mVersIhl & kVersionMask) == kVersion4; }
|
||||
|
||||
/**
|
||||
* This method returns the octet for DSCP + ECN.
|
||||
*
|
||||
* @retval The octet for DSCP and ECN.
|
||||
*
|
||||
*/
|
||||
uint8_t GetDscpEcn(void) const { return mDscpEcn; }
|
||||
|
||||
/**
|
||||
* This method gets the 6-bit Differentiated Services Code Point (DSCP) from Traffic Class field.
|
||||
*
|
||||
* @returns The DSCP value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetDscp(void) const { return (mDscpEcn & kDscpMask) >> kDscpOffset; }
|
||||
|
||||
/**
|
||||
* This method sets 6-bit Differentiated Services Code Point (DSCP) in IPv4 header.
|
||||
*
|
||||
* @param[in] aDscp The DSCP value.
|
||||
*
|
||||
*/
|
||||
void SetDscp(uint8_t aDscp) { mDscpEcn = static_cast<uint8_t>((mDscpEcn & ~kDscpMask) | (aDscp << kDscpOffset)); }
|
||||
|
||||
/**
|
||||
* This method gets the 2-bit Explicit Congestion Notification (ECN) from Traffic Class field.
|
||||
*
|
||||
* @returns The ECN value.
|
||||
*
|
||||
*/
|
||||
Ecn GetEcn(void) const { return static_cast<Ecn>(mDscpEcn & kEcnMask); }
|
||||
|
||||
/**
|
||||
* This method sets the 2-bit Explicit Congestion Notification (ECN) in IPv4 header..
|
||||
*
|
||||
* @param[in] aEcn The ECN value.
|
||||
*
|
||||
*/
|
||||
void SetEcn(Ecn aEcn) { mDscpEcn = ((mDscpEcn & ~kEcnMask) | aEcn); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Payload Length value.
|
||||
*
|
||||
* @returns The IPv4 Payload Length value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetTotalLength(void) const { return HostSwap16(mTotalLength); }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 Payload Length value.
|
||||
*
|
||||
* @param[in] aLength The IPv4 Payload Length value.
|
||||
*
|
||||
*/
|
||||
void SetTotalLength(uint16_t aLength) { mTotalLength = HostSwap16(aLength); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 payload protocol.
|
||||
*
|
||||
* @returns The IPv4 payload protocol value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetProtocol(void) const { return mProtocol; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 payload protocol.
|
||||
*
|
||||
* @param[in] aProtocol The IPv4 payload protocol.
|
||||
*
|
||||
*/
|
||||
void SetProtocol(uint8_t aProtocol) { mProtocol = aProtocol; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 header checksum, the checksum is in host endian.
|
||||
*
|
||||
* @returns The checksum field in the IPv4 header.
|
||||
*
|
||||
*/
|
||||
uint16_t GetChecksum(void) const { return HostSwap16(mHeaderChecksum); }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 header checksum, the checksum is in host endian.
|
||||
*
|
||||
* @param[in] aChecksum The checksum for the IPv4 header.
|
||||
*
|
||||
*/
|
||||
void SetChecksum(uint16_t aChecksum) { mHeaderChecksum = HostSwap16(aChecksum); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Identification value.
|
||||
*
|
||||
* @returns The IPv4 Identification value.
|
||||
*
|
||||
*/
|
||||
uint16_t GetIdentification(void) const { return HostSwap16(mIdentification); }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 Identification value.
|
||||
*
|
||||
* @param[in] aIdentification The IPv4 Identification value.
|
||||
*
|
||||
*/
|
||||
void SetIdentification(uint16_t aIdentification) { mIdentification = HostSwap16(aIdentification); }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Time-to-Live value.
|
||||
*
|
||||
* @returns The IPv4 Time-to-Live value.
|
||||
*
|
||||
*/
|
||||
uint8_t GetTtl(void) const { return mTtl; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 Time-to-Live value.
|
||||
*
|
||||
* @param[in] aTtl The IPv4 Time-to-Live value.
|
||||
*
|
||||
*/
|
||||
void SetTtl(uint8_t aTtl) { mTtl = aTtl; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Source address.
|
||||
*
|
||||
* @returns A reference to the IPv4 Source address.
|
||||
*
|
||||
*/
|
||||
Address &GetSource(void) { return mSource; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Source address.
|
||||
*
|
||||
* @returns A reference to the IPv4 Source address.
|
||||
*
|
||||
*/
|
||||
const Address &GetSource(void) const { return mSource; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 Source address.
|
||||
*
|
||||
* @param[in] aSource A reference to the IPv4 Source address.
|
||||
*
|
||||
*/
|
||||
void SetSource(const Address &aSource) { mSource = aSource; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Destination address.
|
||||
*
|
||||
* @returns A reference to the IPv4 Destination address.
|
||||
*
|
||||
*/
|
||||
Address &GetDestination(void) { return mDestination; }
|
||||
|
||||
/**
|
||||
* This method returns the IPv4 Destination address.
|
||||
*
|
||||
* @returns A reference to the IPv4 Destination address.
|
||||
*
|
||||
*/
|
||||
const Address &GetDestination(void) const { return mDestination; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv4 Destination address.
|
||||
*
|
||||
* @param[in] aDestination A reference to the IPv4 Destination address.
|
||||
*
|
||||
*/
|
||||
void SetDestination(const Address &aDestination) { mDestination = aDestination; }
|
||||
|
||||
/**
|
||||
* This method parses and validates the IPv4 header from a given message.
|
||||
*
|
||||
* The header is read from @p aMessage at offset zero.
|
||||
*
|
||||
* @param[in] aMessage The IPv4 message.
|
||||
*
|
||||
* @retval kErrorNone Successfully parsed the IPv4 header from @p aMessage.
|
||||
* @retval kErrorParse Malformed IPv4 header or message (e.g., message does not contained expected payload length).
|
||||
*
|
||||
*/
|
||||
Error ParseFrom(const Message &aMessage);
|
||||
|
||||
/**
|
||||
* This method returns the Df flag in the IPv4 header.
|
||||
*
|
||||
* @returns Whether don't fragment flag is set.
|
||||
*
|
||||
*/
|
||||
bool GetDf(void) const { return HostSwap16(mFlagsFargmentOffset) & kFlagsDf; }
|
||||
|
||||
/**
|
||||
* This method returns the Mf flag in the IPv4 header.
|
||||
*
|
||||
* @returns Whether more fragments flag is set.
|
||||
*
|
||||
*/
|
||||
bool GetMf(void) const { return HostSwap16(mFlagsFargmentOffset) & kFlagsMf; }
|
||||
|
||||
/**
|
||||
* This method returns the fragment offset in the IPv4 header.
|
||||
*
|
||||
* @returns The fragment offset of the IPv4 packet.
|
||||
*
|
||||
*/
|
||||
uint16_t GetFragmentOffset(void) const { return HostSwap16(mFlagsFargmentOffset) & kFragmentOffsetMask; }
|
||||
|
||||
private:
|
||||
// IPv4 header
|
||||
//
|
||||
// +---------------+---------------+---------------+---------------+
|
||||
// |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |Version| IHL | DSCP |ECN| Total Length |
|
||||
// | Identification |Flags| Fragment Offset |
|
||||
// | TTL | Protocol | Header Checksum |
|
||||
// | Source IP Address |
|
||||
// | Dest IP Address |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
static constexpr uint8_t kVersion4 = 0x40; // Use with `mVersIhl`
|
||||
static constexpr uint8_t kVersionMask = 0xf0; // Use with `mVersIhl`
|
||||
static constexpr uint8_t kIhlMask = 0x0f; // Use with `mVersIhl`
|
||||
static constexpr uint8_t kDscpOffset = 2; // Use with `mDscpEcn`
|
||||
static constexpr uint16_t kDscpMask = 0xfc; // Use with `mDscpEcn`
|
||||
static constexpr uint8_t kEcnOffset = 0; // Use with `mDscpEcn`
|
||||
static constexpr uint8_t kEcnMask = 0x03; // Use with `mDscpEcn`
|
||||
static constexpr uint16_t kFlagsMask = 0xe000; // Use with `mFlagsFragmentOffset`
|
||||
static constexpr uint16_t kFlagsDf = 0x4000; // Use with `mFlagsFragmentOffset`
|
||||
static constexpr uint16_t kFlagsMf = 0x2000; // Use with `mFlagsFragmentOffset`
|
||||
static constexpr uint16_t kFragmentOffsetMask = 0x1fff; // Use with `mFlagsFragmentOffset`
|
||||
static constexpr uint32_t kVersIhlInit = 0x45; // Version 4, Header length = 5x8 bytes.
|
||||
|
||||
uint8_t mVersIhl;
|
||||
uint8_t mDscpEcn;
|
||||
uint16_t mTotalLength;
|
||||
uint16_t mIdentification;
|
||||
uint16_t mFlagsFargmentOffset;
|
||||
uint8_t mTtl;
|
||||
uint8_t mProtocol;
|
||||
uint16_t mHeaderChecksum;
|
||||
Address mSource;
|
||||
Address mDestination;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class implements ICMP(v4).
|
||||
* Note: ICMP(v4) messages will only be generated / handled by NAT64. So only header defination is required.
|
||||
*
|
||||
*/
|
||||
class Icmp
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This class represents an IPv4 ICMP header.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Header : public Clearable<Header>
|
||||
{
|
||||
public:
|
||||
static constexpr uint16_t kChecksumFieldOffset = 2;
|
||||
// A few ICMP types, only the ICMP types work with NAT64 are listed here.
|
||||
enum Type : uint8_t
|
||||
{
|
||||
kTypeEchoReply = 0,
|
||||
kTypeDestinationUnreachable = 3,
|
||||
kTypeEchoRequest = 8,
|
||||
kTypeTimeExceeded = 11,
|
||||
};
|
||||
|
||||
enum Code : uint8_t
|
||||
{
|
||||
kCodeNone = 0,
|
||||
// Destination Unreachable codes
|
||||
kCodeNetworkUnreachable = 0,
|
||||
kCodeHostUnreachable = 1,
|
||||
kCodeProtocolUnreachable = 2,
|
||||
kCodePortUnreachable = 3,
|
||||
kCodeSourceRouteFailed = 5,
|
||||
kCodeNetworkUnknown = 6,
|
||||
kCodeHostUnknown = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* This method returns the type of the ICMP message.
|
||||
*
|
||||
* @returns The type field of the ICMP message.
|
||||
*
|
||||
*/
|
||||
uint8_t GetType(void) const { return mType; }
|
||||
|
||||
/**
|
||||
* This method sets the type of the ICMP message.
|
||||
*
|
||||
* @param[in] aType The type of the ICMP message.
|
||||
*
|
||||
*/
|
||||
void SetType(uint8_t aType) { mType = aType; }
|
||||
|
||||
/**
|
||||
* This method returns the code of the ICMP message.
|
||||
*
|
||||
* @returns The code field of the ICMP message.
|
||||
*
|
||||
*/
|
||||
uint8_t GetCode(void) const { return mCode; }
|
||||
|
||||
/**
|
||||
* This method sets the code of the ICMP message.
|
||||
*
|
||||
* @param[in] aCode The code of the ICMP message.
|
||||
*
|
||||
*/
|
||||
void SetCode(uint8_t aCode) { mCode = aCode; }
|
||||
|
||||
/**
|
||||
* This method sets the checksum field in the ICMP message.
|
||||
*
|
||||
* @returns The checksum of the ICMP message.
|
||||
*
|
||||
*/
|
||||
uint16_t GetChecksum(void) const { return HostSwap16(mChecksum); }
|
||||
|
||||
/**
|
||||
* This method sets the checksum field in the ICMP message.
|
||||
*
|
||||
* @param[in] aChecksum The checksum of the ICMP message.
|
||||
*
|
||||
*/
|
||||
void SetChecksum(uint16_t aChecksum) { mChecksum = HostSwap16(aChecksum); }
|
||||
|
||||
/**
|
||||
* This method returns the rest of header field in the ICMP message.
|
||||
*
|
||||
* @returns The rest of header field in the ICMP message. The returned buffer has 4 octets.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetRestOfHeader(void) const { return mRestOfHeader; }
|
||||
|
||||
/**
|
||||
* This method sets the rest of header field in the ICMP message.
|
||||
*
|
||||
* @param[in] aRestOfHeader The rest of header field in the ICMP message. The buffer should have 4 octets.
|
||||
*
|
||||
*/
|
||||
void SetRestOfHeader(const uint8_t *aRestOfheader)
|
||||
{
|
||||
memcpy(mRestOfHeader, aRestOfheader, sizeof(mRestOfHeader));
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t mType;
|
||||
uint8_t mCode;
|
||||
uint16_t mChecksum;
|
||||
uint8_t mRestOfHeader[4];
|
||||
} OT_TOOL_PACKED_END;
|
||||
};
|
||||
|
||||
// Internet Protocol Numbers
|
||||
static constexpr uint8_t kProtoTcp = Ip6::kProtoTcp; ///< Transmission Control Protocol
|
||||
static constexpr uint8_t kProtoUdp = Ip6::kProtoUdp; ///< User Datagram
|
||||
static constexpr uint8_t kProtoIcmp = 1; ///< ICMP for IPv4
|
||||
|
||||
using Tcp = Ip6::Tcp; // TCP in IPv4 is the same as TCP in IPv6
|
||||
using Udp = Ip6::Udp; // UDP in IPv4 is the same as UDP in IPv6
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Ip4
|
||||
|
||||
DefineCoreType(otIp4Address, Ip4::Address);
|
||||
DefineCoreType(otIp4Cidr, Ip4::Cidr);
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // IP4_TYPES_HPP_
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "common/instance.hpp"
|
||||
#include "common/numeric_limits.hpp"
|
||||
#include "common/random.hpp"
|
||||
#include "net/ip4_address.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/netif.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap32;
|
||||
@@ -124,10 +124,10 @@ uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, ui
|
||||
return matchedLength;
|
||||
}
|
||||
|
||||
bool Prefix::IsValidNat64(void) const
|
||||
bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
|
||||
{
|
||||
return (mLength == 32) || (mLength == 40) || (mLength == 48) || (mLength == 56) || (mLength == 64) ||
|
||||
(mLength == 96);
|
||||
return (aLength == 32) || (aLength == 40) || (aLength == 48) || (aLength == 56) || (aLength == 64) ||
|
||||
(aLength == 96);
|
||||
}
|
||||
|
||||
Prefix::InfoString Prefix::ToString(void) const
|
||||
|
||||
@@ -46,11 +46,16 @@
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "net/ip4_address.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::HostSwap16;
|
||||
|
||||
namespace ot {
|
||||
|
||||
namespace Ip4 {
|
||||
// Forward declaration for SynthesizeFromIp4Address
|
||||
class Address;
|
||||
} // namespace Ip4
|
||||
|
||||
namespace Ip6 {
|
||||
|
||||
/**
|
||||
@@ -301,6 +306,19 @@ public:
|
||||
*/
|
||||
static uint8_t MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not a given prefix length is valid for use as a NAT64 prefix.
|
||||
*
|
||||
* A NAT64 prefix must have one of the following lengths: 32, 40, 48, 56, 64, or 96 (per RFC 6502).
|
||||
*
|
||||
* @param[in] aLength The length of the prefix.
|
||||
*
|
||||
* @retval TRUE If the prefix has a valid length for use as a NAT64 prefix.
|
||||
* @retval FALSE If the prefix does not have a valid length for use as a NAT64 prefix.
|
||||
*
|
||||
*/
|
||||
static bool IsValidNat64PrefixLength(uint8_t aLength);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the prefix has a valid length for use as a NAT64 prefix.
|
||||
*
|
||||
@@ -310,7 +328,7 @@ public:
|
||||
* @retval FALSE If the prefix does not have a valid length for use as a NAT64 prefix.
|
||||
*
|
||||
*/
|
||||
bool IsValidNat64(void) const;
|
||||
bool IsValidNat64(void) const { return IsValidNat64PrefixLength(mLength); }
|
||||
|
||||
/**
|
||||
* This method converts the prefix to a string.
|
||||
|
||||
@@ -431,6 +431,27 @@ target_link_libraries(ot-test-hmac-sha256
|
||||
|
||||
add_test(NAME ot-test-hmac-sha256 COMMAND ot-test-hmac-sha256)
|
||||
|
||||
add_executable(ot-test-ip4-header
|
||||
test_ip4_header.cpp
|
||||
)
|
||||
|
||||
target_include_directories(ot-test-ip4-header
|
||||
PRIVATE
|
||||
${COMMON_INCLUDES}
|
||||
)
|
||||
|
||||
target_compile_options(ot-test-ip4-header
|
||||
PRIVATE
|
||||
${COMMON_COMPILE_OPTIONS}
|
||||
)
|
||||
|
||||
target_link_libraries(ot-test-ip4-header
|
||||
PRIVATE
|
||||
${COMMON_LIBS}
|
||||
)
|
||||
|
||||
add_test(NAME ot-test-ip4-header COMMAND ot-test-ip4-header)
|
||||
|
||||
add_executable(ot-test-ip6-header
|
||||
test_ip6_header.cpp
|
||||
)
|
||||
|
||||
@@ -128,6 +128,7 @@ check_PROGRAMS += \
|
||||
ot-test-heap-string \
|
||||
ot-test-hkdf-sha256 \
|
||||
ot-test-hmac-sha256 \
|
||||
ot-test-ip4-header \
|
||||
ot-test-ip6-header \
|
||||
ot-test-ip-address \
|
||||
ot-test-link-quality \
|
||||
@@ -262,6 +263,10 @@ ot_test_hmac_sha256_LDADD = $(COMMON_LDADD)
|
||||
ot_test_hmac_sha256_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
|
||||
ot_test_hmac_sha256_SOURCES = $(COMMON_SOURCES) test_hmac_sha256.cpp
|
||||
|
||||
ot_test_ip4_header_LDADD = $(COMMON_LDADD)
|
||||
ot_test_ip4_header_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
|
||||
ot_test_ip4_header_SOURCES = $(COMMON_SOURCES) test_ip4_header.cpp
|
||||
|
||||
ot_test_ip6_header_LDADD = $(COMMON_LDADD)
|
||||
ot_test_ip6_header_LIBTOOLFLAGS = $(COMMON_LIBTOOLFLAGS)
|
||||
ot_test_ip6_header_SOURCES = $(COMMON_SOURCES) test_ip6_header.cpp
|
||||
|
||||
+191
-15
@@ -32,6 +32,7 @@
|
||||
#include "common/random.hpp"
|
||||
#include "net/checksum.hpp"
|
||||
#include "net/icmp6.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/udp6.hpp"
|
||||
|
||||
#include "test_platform.h"
|
||||
@@ -75,11 +76,7 @@ uint16_t CalculateChecksum(const Ip6::Address &aSource,
|
||||
const Message & aMessage)
|
||||
{
|
||||
// This method calculates the checksum over an IPv6 message.
|
||||
|
||||
enum : uint16_t
|
||||
{
|
||||
kMaxPayload = 1024,
|
||||
};
|
||||
constexpr uint16_t kMaxPayload = 1024;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct PseudoHeader
|
||||
@@ -112,6 +109,45 @@ uint16_t CalculateChecksum(const Ip6::Address &aSource,
|
||||
return CalculateChecksum(&data, sizeof(PseudoHeader) + payloadLength);
|
||||
}
|
||||
|
||||
uint16_t CalculateChecksum(const Ip4::Address &aSource,
|
||||
const Ip4::Address &aDestination,
|
||||
uint8_t aIpProto,
|
||||
const Message & aMessage)
|
||||
{
|
||||
// This method calculates the checksum over an IPv4 message.
|
||||
constexpr uint16_t kMaxPayload = 1024;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct PseudoHeader
|
||||
{
|
||||
Ip4::Address mSource;
|
||||
Ip4::Address mDestination;
|
||||
uint16_t mPayloadLength;
|
||||
uint16_t mProtocol;
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct ChecksumData
|
||||
{
|
||||
PseudoHeader mPseudoHeader;
|
||||
uint8_t mPayload[kMaxPayload];
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
ChecksumData data;
|
||||
uint16_t payloadLength;
|
||||
|
||||
payloadLength = aMessage.GetLength() - aMessage.GetOffset();
|
||||
|
||||
data.mPseudoHeader.mSource = aSource;
|
||||
data.mPseudoHeader.mDestination = aDestination;
|
||||
data.mPseudoHeader.mProtocol = Encoding::BigEndian::HostSwap16(aIpProto);
|
||||
data.mPseudoHeader.mPayloadLength = Encoding::BigEndian::HostSwap16(payloadLength);
|
||||
|
||||
SuccessOrQuit(aMessage.Read(aMessage.GetOffset(), data.mPayload, payloadLength));
|
||||
|
||||
return CalculateChecksum(&data, sizeof(PseudoHeader) + payloadLength);
|
||||
}
|
||||
|
||||
void CorruptMessage(Message &aMessage)
|
||||
{
|
||||
// Change a random bit in the message.
|
||||
@@ -133,11 +169,8 @@ void CorruptMessage(Message &aMessage)
|
||||
|
||||
void TestUdpMessageChecksum(void)
|
||||
{
|
||||
enum : uint16_t
|
||||
{
|
||||
kMinSize = sizeof(Ip6::Udp::Header),
|
||||
kMaxSize = kBufferSize * 3 + 24,
|
||||
};
|
||||
constexpr uint16_t kMinSize = sizeof(Ip6::Udp::Header);
|
||||
constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
|
||||
|
||||
const char *kSourceAddress = "fd00:1122:3344:5566:7788:99aa:bbcc:ddee";
|
||||
const char *kDestAddress = "fd01:2345:6789:abcd:ef01:2345:6789:abcd";
|
||||
@@ -204,11 +237,8 @@ void TestUdpMessageChecksum(void)
|
||||
|
||||
void TestIcmp6MessageChecksum(void)
|
||||
{
|
||||
enum : uint16_t
|
||||
{
|
||||
kMinSize = sizeof(Ip6::Icmp::Header),
|
||||
kMaxSize = kBufferSize * 3 + 24,
|
||||
};
|
||||
constexpr uint16_t kMinSize = sizeof(Ip6::Icmp::Header);
|
||||
constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
|
||||
|
||||
const char *kSourceAddress = "fd00:feef:dccd:baab:9889:7667:5444:3223";
|
||||
const char *kDestAddress = "fd01:abab:beef:cafe:1234:5678:9abc:0";
|
||||
@@ -274,6 +304,149 @@ void TestIcmp6MessageChecksum(void)
|
||||
}
|
||||
}
|
||||
|
||||
void TestTcp4MessageChecksum(void)
|
||||
{
|
||||
constexpr size_t kMinSize = sizeof(Ip4::Tcp::Header);
|
||||
constexpr size_t kMaxSize = kBufferSize * 3 + 24;
|
||||
|
||||
const char *kSourceAddress = "12.34.56.78";
|
||||
const char *kDestAddress = "87.65.43.21";
|
||||
|
||||
Ip4::Address sourceAddress;
|
||||
Ip4::Address destAddress;
|
||||
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
|
||||
VerifyOrQuit(instance != nullptr);
|
||||
|
||||
SuccessOrQuit(sourceAddress.FromString(kSourceAddress));
|
||||
SuccessOrQuit(destAddress.FromString(kDestAddress));
|
||||
|
||||
for (uint16_t size = kMinSize; size <= kMaxSize; size++)
|
||||
{
|
||||
Message * message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip4::Tcp::Header));
|
||||
Ip4::Tcp::Header tcpHeader;
|
||||
|
||||
VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
|
||||
SuccessOrQuit(message->SetLength(size));
|
||||
|
||||
// Write TCP header with a random payload.
|
||||
|
||||
Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&tcpHeader), sizeof(tcpHeader));
|
||||
message->Write(0, tcpHeader);
|
||||
|
||||
if (size > sizeof(tcpHeader))
|
||||
{
|
||||
uint8_t buffer[kMaxSize];
|
||||
uint16_t payloadSize = size - sizeof(tcpHeader);
|
||||
|
||||
Random::NonCrypto::FillBuffer(buffer, payloadSize);
|
||||
message->WriteBytes(sizeof(tcpHeader), &buffer[0], payloadSize);
|
||||
}
|
||||
|
||||
// Verify that the `Checksum::UpdateMessageChecksum` correctly
|
||||
// updates the checksum field in the UDP header on the message.
|
||||
|
||||
Checksum::UpdateMessageChecksum(*message, sourceAddress, destAddress, Ip4::kProtoTcp);
|
||||
|
||||
SuccessOrQuit(message->Read(message->GetOffset(), tcpHeader));
|
||||
VerifyOrQuit(tcpHeader.GetChecksum() != 0);
|
||||
|
||||
// Verify that the calculated UDP checksum is valid.
|
||||
|
||||
VerifyOrQuit(CalculateChecksum(sourceAddress, destAddress, Ip4::kProtoTcp, *message) == 0xffff);
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void TestUdp4MessageChecksum(void)
|
||||
{
|
||||
constexpr uint16_t kMinSize = sizeof(Ip4::Udp::Header);
|
||||
constexpr uint16_t kMaxSize = kBufferSize * 3 + 24;
|
||||
|
||||
const char *kSourceAddress = "12.34.56.78";
|
||||
const char *kDestAddress = "87.65.43.21";
|
||||
|
||||
Ip4::Address sourceAddress;
|
||||
Ip4::Address destAddress;
|
||||
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
|
||||
SuccessOrQuit(sourceAddress.FromString(kSourceAddress));
|
||||
SuccessOrQuit(destAddress.FromString(kDestAddress));
|
||||
|
||||
VerifyOrQuit(instance != nullptr);
|
||||
|
||||
for (uint16_t size = kMinSize; size <= kMaxSize; size++)
|
||||
{
|
||||
Message * message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(Ip4::Udp::Header));
|
||||
Ip4::Udp::Header udpHeader;
|
||||
|
||||
VerifyOrQuit(message != nullptr, "Ip6::NewMesssage() failed");
|
||||
SuccessOrQuit(message->SetLength(size));
|
||||
|
||||
// Write UDP header with a random payload.
|
||||
|
||||
Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&udpHeader), sizeof(udpHeader));
|
||||
udpHeader.SetChecksum(0);
|
||||
message->Write(0, udpHeader);
|
||||
|
||||
if (size > sizeof(udpHeader))
|
||||
{
|
||||
uint8_t buffer[kMaxSize];
|
||||
uint16_t payloadSize = size - sizeof(udpHeader);
|
||||
|
||||
Random::NonCrypto::FillBuffer(buffer, payloadSize);
|
||||
message->WriteBytes(sizeof(udpHeader), &buffer[0], payloadSize);
|
||||
}
|
||||
|
||||
// Verify that the `Checksum::UpdateMessageChecksum` correctly
|
||||
// updates the checksum field in the UDP header on the message.
|
||||
|
||||
Checksum::UpdateMessageChecksum(*message, sourceAddress, destAddress, Ip4::kProtoUdp);
|
||||
|
||||
SuccessOrQuit(message->Read(message->GetOffset(), udpHeader));
|
||||
VerifyOrQuit(udpHeader.GetChecksum() != 0);
|
||||
|
||||
// Verify that the calculated UDP checksum is valid.
|
||||
|
||||
VerifyOrQuit(CalculateChecksum(sourceAddress, destAddress, Ip4::kProtoUdp, *message) == 0xffff);
|
||||
message->Free();
|
||||
}
|
||||
}
|
||||
|
||||
void TestIcmp4MessageChecksum(void)
|
||||
{
|
||||
// A captured ICMP echo request (ping) message. Checksum field is set to zero.
|
||||
const uint8_t kExampleIcmpMessage[] = "\x08\x00\x00\x00\x67\x2e\x00\x00\x62\xaf\xf1\x61\x00\x04\xfc\x24"
|
||||
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17"
|
||||
"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27"
|
||||
"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37";
|
||||
uint16_t kChecksumForExampleMessage = 0x5594;
|
||||
Instance *instance = static_cast<Instance *>(testInitInstance());
|
||||
Message * message = instance->Get<Ip6::Ip6>().NewMessage(sizeof(kExampleIcmpMessage));
|
||||
|
||||
Ip4::Address source;
|
||||
Ip4::Address dest;
|
||||
|
||||
uint8_t mPayload[sizeof(kExampleIcmpMessage)];
|
||||
Ip4::Icmp::Header icmpHeader;
|
||||
|
||||
message->AppendBytes(kExampleIcmpMessage, sizeof(kExampleIcmpMessage));
|
||||
|
||||
// Random IPv4 address, ICMP message checksum does not include a presudo header like TCP and UDP.
|
||||
source.mFields.m32 = 0x12345678;
|
||||
dest.mFields.m32 = 0x87654321;
|
||||
|
||||
Checksum::UpdateMessageChecksum(*message, source, dest, Ip4::kProtoIcmp);
|
||||
|
||||
message->Read(0, icmpHeader);
|
||||
VerifyOrQuit(icmpHeader.GetChecksum() == kChecksumForExampleMessage);
|
||||
|
||||
SuccessOrQuit(message->Read(message->GetOffset(), mPayload, sizeof(mPayload)));
|
||||
VerifyOrQuit(CalculateChecksum(mPayload, sizeof(mPayload)) == 0xffff);
|
||||
}
|
||||
|
||||
class ChecksumTester
|
||||
{
|
||||
public:
|
||||
@@ -300,6 +473,9 @@ int main(void)
|
||||
ot::ChecksumTester::TestExampleVector();
|
||||
ot::TestUdpMessageChecksum();
|
||||
ot::TestIcmp6MessageChecksum();
|
||||
ot::TestTcp4MessageChecksum();
|
||||
ot::TestUdp4MessageChecksum();
|
||||
ot::TestIcmp4MessageChecksum();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
#include "common/encoding.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
using ot::Encoding::BigEndian::ReadUint16;
|
||||
|
||||
namespace ot {
|
||||
namespace Ip4 {
|
||||
|
||||
void VerifyEcnDscp(const Header &aHeader, uint8_t aDscp, Ecn aEcn)
|
||||
{
|
||||
uint8_t expectedDscpEcn = static_cast<uint8_t>((aDscp << 2) + aEcn);
|
||||
|
||||
printf("%02x {dscp:%d, ecn:%d}\n", aHeader.GetDscpEcn(), aHeader.GetDscp(), aHeader.GetEcn());
|
||||
|
||||
VerifyOrQuit(aHeader.GetDscp() == aDscp);
|
||||
VerifyOrQuit(aHeader.GetEcn() == aEcn);
|
||||
VerifyOrQuit(aHeader.GetDscpEcn() == expectedDscpEcn);
|
||||
}
|
||||
|
||||
void TestIp4Header(void)
|
||||
{
|
||||
static constexpr uint16_t kTotalLength = 84;
|
||||
static constexpr uint8_t kTtl = 64;
|
||||
|
||||
const uint8_t kDscps[] = {0x0, 0x1, 0x3, 0xf, 0x30, 0x2f, 0x3f};
|
||||
const Ecn kEcns[] = {Ecn::kEcnNotCapable, Ecn::kEcnCapable0, Ecn::kEcnCapable1, Ecn::kEcnMarked};
|
||||
const uint8_t kExampleIp4Header[] = "\x45\x00\x00\x54\x23\xed\x00\x00\x40\x01\x41\xd1\x0a\x00\x00\xeb"
|
||||
"\x0a\x00\x00\x01";
|
||||
|
||||
Header header;
|
||||
Address source;
|
||||
Address destination;
|
||||
const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header);
|
||||
|
||||
SuccessOrQuit(source.FromString("10.0.0.235"), "Address::FromString() failed");
|
||||
SuccessOrQuit(destination.FromString("10.0.0.1"), "Address::FromString() failed");
|
||||
|
||||
header.InitVersionIhl();
|
||||
|
||||
header.Clear();
|
||||
header.InitVersionIhl();
|
||||
VerifyOrQuit(header.IsValid());
|
||||
VerifyOrQuit(header.GetTotalLength() == 0);
|
||||
VerifyOrQuit(header.GetProtocol() == 0);
|
||||
VerifyOrQuit(header.GetTtl() == 0);
|
||||
VerifyOrQuit(header.GetSource().mFields.m32 == 0);
|
||||
VerifyOrQuit(header.GetDestination().mFields.m32 == 0);
|
||||
VerifyOrQuit(header.GetFragmentOffset() == 0);
|
||||
|
||||
header.SetTotalLength(kTotalLength);
|
||||
header.SetProtocol(Ip4::kProtoIcmp);
|
||||
header.SetTtl(kTtl);
|
||||
header.SetSource(source);
|
||||
header.SetDestination(destination);
|
||||
|
||||
VerifyOrQuit(header.IsValid());
|
||||
VerifyOrQuit(header.GetProtocol() == kProtoIcmp);
|
||||
VerifyOrQuit(header.GetTtl() == kTtl);
|
||||
VerifyOrQuit(header.GetSource() == source);
|
||||
VerifyOrQuit(header.GetDestination() == destination);
|
||||
|
||||
// Verify the offsets to different fields.
|
||||
|
||||
VerifyOrQuit(ReadUint16(headerBytes + Header::kTotalLengthOffset) == kTotalLength, "kTotalLength is incorrect");
|
||||
VerifyOrQuit(headerBytes[Header::kProtocolOffset] == kProtoIcmp, "kProtocol is incorrect");
|
||||
VerifyOrQuit(headerBytes[Header::kTtlOffset] == kTtl, "kTtl is incorrect");
|
||||
VerifyOrQuit(memcmp(&headerBytes[Header::kSourceAddressOffset], &source, sizeof(source)) == 0,
|
||||
"Source address is incorrect");
|
||||
VerifyOrQuit(memcmp(&headerBytes[Header::kDestinationAddressOffset], &destination, sizeof(destination)) == 0,
|
||||
"Destination address is incorrect");
|
||||
|
||||
for (uint8_t dscp : kDscps)
|
||||
{
|
||||
for (Ecn ecn : kEcns)
|
||||
{
|
||||
printf("Expecting {dscp:%-2d, ecn:%d} => ", dscp, ecn);
|
||||
header.SetEcn(ecn);
|
||||
header.SetDscp(dscp);
|
||||
VerifyEcnDscp(header, dscp, ecn);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&header, kExampleIp4Header, sizeof(header));
|
||||
VerifyOrQuit(header.IsValid());
|
||||
VerifyOrQuit(memcmp(&headerBytes[Header::kSourceAddressOffset], &source, sizeof(source)) == 0,
|
||||
"Source address is incorrect");
|
||||
VerifyOrQuit(memcmp(&headerBytes[Header::kDestinationAddressOffset], &destination, sizeof(destination)) == 0,
|
||||
"Destination address is incorrect");
|
||||
VerifyOrQuit(ReadUint16(headerBytes + Header::kTotalLengthOffset) == kTotalLength, "kTotalLength is incorrect");
|
||||
VerifyOrQuit(headerBytes[Header::kProtocolOffset] == kProtoIcmp, "kProtocol is incorrect");
|
||||
VerifyOrQuit(headerBytes[Header::kTtlOffset] == kTtl, "kTtl is incorrect");
|
||||
}
|
||||
|
||||
} // namespace Ip4
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Ip4::TestIp4Header();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* Copyright (c) 2019-2022, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "net/ip4_address.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "net/ip4_types.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
|
||||
#include "test_util.h"
|
||||
@@ -444,6 +445,73 @@ void TestIp4Ip6Translation(void)
|
||||
|
||||
VerifyOrQuit(address == expectedAddress, "Ip6::SynthesizeFromIp4Address() failed");
|
||||
}
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
const ot::Ip4::Address expectedAddress = ip4Address;
|
||||
ot::Ip4::Address address;
|
||||
ot::Ip6::Address ip6Address;
|
||||
|
||||
SuccessOrQuit(ip6Address.FromString(testCase.mIp6Address));
|
||||
|
||||
address.ExtractFromIp6Address(testCase.mLength, ip6Address);
|
||||
|
||||
printf("Ipv6Address: %-36s IPv4Addr: %-12s Expected: %s\n", testCase.mIp6Address,
|
||||
address.ToString().AsCString(), expectedAddress.ToString().AsCString());
|
||||
|
||||
VerifyOrQuit(address == expectedAddress, "Ip4::ExtractFromIp6Address() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void TestIp4Cidr(void)
|
||||
{
|
||||
using ot::Encoding::BigEndian::HostSwap32;
|
||||
struct TestCase
|
||||
{
|
||||
const char * mNetwork;
|
||||
const uint8_t mLength;
|
||||
const uint32_t mHost;
|
||||
const char * mOutcome;
|
||||
};
|
||||
|
||||
const TestCase kTestCases[] = {
|
||||
{"172.16.12.34", 32, 0x12345678, "172.16.12.34"}, {"172.16.12.34", 31, 0x12345678, "172.16.12.34"},
|
||||
{"172.16.12.34", 30, 0x12345678, "172.16.12.32"}, {"172.16.12.34", 29, 0x12345678, "172.16.12.32"},
|
||||
{"172.16.12.34", 28, 0x12345678, "172.16.12.40"}, {"172.16.12.34", 27, 0x12345678, "172.16.12.56"},
|
||||
{"172.16.12.34", 26, 0x12345678, "172.16.12.56"}, {"172.16.12.34", 25, 0x12345678, "172.16.12.120"},
|
||||
{"172.16.12.34", 24, 0x12345678, "172.16.12.120"}, {"172.16.12.34", 23, 0x12345678, "172.16.12.120"},
|
||||
{"172.16.12.34", 22, 0x12345678, "172.16.14.120"}, {"172.16.12.34", 21, 0x12345678, "172.16.14.120"},
|
||||
{"172.16.12.34", 20, 0x12345678, "172.16.6.120"}, {"172.16.12.34", 19, 0x12345678, "172.16.22.120"},
|
||||
{"172.16.12.34", 18, 0x12345678, "172.16.22.120"}, {"172.16.12.34", 17, 0x12345678, "172.16.86.120"},
|
||||
{"172.16.12.34", 16, 0x12345678, "172.16.86.120"}, {"172.16.12.34", 15, 0x12345678, "172.16.86.120"},
|
||||
{"172.16.12.34", 14, 0x12345678, "172.16.86.120"}, {"172.16.12.34", 13, 0x12345678, "172.20.86.120"},
|
||||
{"172.16.12.34", 12, 0x12345678, "172.20.86.120"}, {"172.16.12.34", 11, 0x12345678, "172.20.86.120"},
|
||||
{"172.16.12.34", 10, 0x12345678, "172.52.86.120"}, {"172.16.12.34", 9, 0x12345678, "172.52.86.120"},
|
||||
{"172.16.12.34", 8, 0x12345678, "172.52.86.120"}, {"172.16.12.34", 7, 0x12345678, "172.52.86.120"},
|
||||
{"172.16.12.34", 6, 0x12345678, "174.52.86.120"}, {"172.16.12.34", 5, 0x12345678, "170.52.86.120"},
|
||||
{"172.16.12.34", 4, 0x12345678, "162.52.86.120"}, {"172.16.12.34", 3, 0x12345678, "178.52.86.120"},
|
||||
{"172.16.12.34", 2, 0x12345678, "146.52.86.120"}, {"172.16.12.34", 1, 0x12345678, "146.52.86.120"},
|
||||
{"172.16.12.34", 0, 0x12345678, "18.52.86.120"},
|
||||
};
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
ot::Ip4::Address network;
|
||||
ot::Ip4::Cidr cidr;
|
||||
ot::Ip4::Address generated;
|
||||
|
||||
network.FromString(testCase.mNetwork);
|
||||
cidr.mAddress = network;
|
||||
cidr.mLength = testCase.mLength;
|
||||
|
||||
generated.SynthesizeFromCidrAndHost(cidr, testCase.mHost);
|
||||
|
||||
printf("CIDR: %-18s HostID: %-8x Host: %-14s Expected: %s\n", cidr.ToString().AsCString(), testCase.mHost,
|
||||
generated.ToString().AsCString(), testCase.mOutcome);
|
||||
|
||||
VerifyOrQuit(strcmp(generated.ToString().AsCString(), testCase.mOutcome) == 0,
|
||||
"Ip4::Address::SynthesizeFromCidrAndHost() failed");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -453,6 +521,7 @@ int main(void)
|
||||
TestIp6AddressFromString();
|
||||
TestIp6Prefix();
|
||||
TestIp4Ip6Translation();
|
||||
TestIp4Cidr();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user