[nat64] implement functions for NAT64 on the client side (#8126)

This commit adds the ability for accepting an IPv4 address for {ping,
tcp, udp} CLI commands.
This commit is contained in:
Song GUO
2022-09-15 08:43:36 -07:00
committed by GitHub
parent a7e0516fb2
commit 6973a1b067
13 changed files with 208 additions and 8 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (243)
#define OPENTHREAD_API_VERSION (244)
/**
* @addtogroup api-instance
+26
View File
@@ -384,6 +384,32 @@ void otIp4AddressToString(const otIp4Address *aAddress, char *aBuffer, uint16_t
*/
void otIp4CidrToString(const otIp4Cidr *aCidr, char *aBuffer, uint16_t aSize);
/**
* Converts a human-readable IPv4 address string into a binary representation.
*
* @param[in] aString A pointer to a NULL-terminated string.
* @param[out] aAddress A pointer to an IPv4 address.
*
* @retval OT_ERROR_NONE Successfully parsed the string.
* @retval OT_ERROR_INVALID_ARGS Failed to parse the string.
*
*/
otError otIp4AddressFromString(const char *aString, otIp4Address *aAddress);
/**
* Sets the IPv6 address by performing NAT64 address translation from the preferred NAT64 prefix and the given IPv4
* address as specified in RFC 6052.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aIp4Address A pointer to the IPv4 address to translate to IPv6.
* @param[out] aIp6Address A pointer to the synthesized IPv6 address.
*
* @returns OT_ERROR_NONE Successfully synthesized the IPv6 address from NAT64 prefix and IPv4 address.
* @returns OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data.
*
*/
otError otNat64SynthersizeIp6Address(otInstance *aInstance, const otIp4Address *aIp4Address, otIp6Address *aIp6Address);
/**
* @}
*
+12
View File
@@ -2147,6 +2147,18 @@ Done
Done
```
The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix from the network data.
> Note: The command will return `InvalidState` when the preferred NAT64 prefix is unavailable.
```bash
> ping 172.17.0.1
Pinging synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1
> 16 bytes from fdde:ad00:beef:2:0:0:ac11:1: icmp_seq=5 hlim=64 time=0ms
1 packets transmitted, 1 packets received. Packet loss = 0.0%. Round-trip min/avg/max = 0/0.0/0 ms.
Done
```
### ping stop
Stop sending ICMPv6 Echo Requests.
+11 -1
View File
@@ -109,7 +109,7 @@ Establishes a connection with the specified peer.
If the connection establishment is successful, the resulting TCP connection is associated with the example TCP endpoint.
- ip: the peer's IPv6 address.
- ip: the peer's IP address.
- port: the peer's TCP port.
```bash
@@ -118,6 +118,16 @@ Done
TCP: Connection established
```
The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix from the network data.
> Note: The command will return `InvalidState` when the preferred NAT64 prefix is unavailable.
```bash
> tcp connect 172.17.0.1 1234
Connecting to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1
Done
```
### deinit
Deinitializes the example TCP listener and the example TCP endpoint.
+22 -2
View File
@@ -96,7 +96,7 @@ Done
Specifies the peer with which the socket is to be associated.
- ip: the peer's IPv6 address.
- ip: the peer's IP address.
- port: the peer's UDP port.
```bash
@@ -104,6 +104,16 @@ Specifies the peer with which the socket is to be associated.
Done
```
The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix from the network data.
> Note: The command will return `InvalidState` when the preferred NAT64 prefix is unavailable.
```bash
> udp connect 172.17.0.1 1234
Connecting to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1
Done
```
### linksecurity
Indicates whether the link security is enabled or disabled.
@@ -145,7 +155,7 @@ Done
Send a UDP message.
- ip: the IPv6 destination address.
- ip: the destination address.
- port: the UDP destination port.
- message: the message to send.
@@ -154,6 +164,16 @@ Send a UDP message.
Done
```
The address can be an IPv4 address, which will be synthesized to an IPv6 address using the preferred NAT64 prefix from the network data.
> Note: The command will return `InvalidState` when the preferred NAT64 prefix is unavailable.
```bash
> udp send 172.17.0.1 1234
Sending to synthesized IPv6 address: fdde:ad00:beef:2:0:0:ac11:1
Done
```
### send \<ip\> \<port\> \<type\> \<value\>
Send a few bytes over UDP.
+32 -1
View File
@@ -455,6 +455,31 @@ const char *Interpreter::PreferenceToString(signed int aPreference)
return str;
}
otError Interpreter::ParseToIp6Address(otInstance * aInstance,
const Arg & aArg,
otIp6Address &aAddress,
bool & aSynthesized)
{
Error error = kErrorNone;
VerifyOrExit(!aArg.IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = aArg.ParseAsIp6Address(aAddress);
aSynthesized = false;
if (error != kErrorNone)
{
// It might be an IPv4 address, let's have a try.
otIp4Address ip4Address;
// Do not touch the error value if we failed to parse it as an IPv4 address.
SuccessOrExit(aArg.ParseAsIp4Address(ip4Address));
SuccessOrExit(error = otNat64SynthersizeIp6Address(aInstance, &ip4Address, &aAddress));
aSynthesized = true;
}
exit:
return error;
}
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
template <> otError Interpreter::Process<Cmd("history")>(Arg aArgs[])
{
@@ -4760,6 +4785,7 @@ template <> otError Interpreter::Process<Cmd("ping")>(Arg aArgs[])
otError error = OT_ERROR_NONE;
otPingSenderConfig config;
bool async = false;
bool nat64SynthesizedAddress;
if (aArgs[0] == "stop")
{
@@ -4799,7 +4825,12 @@ template <> otError Interpreter::Process<Cmd("ping")>(Arg aArgs[])
aArgs += 2;
}
SuccessOrExit(error = aArgs[0].ParseAsIp6Address(config.mDestination));
SuccessOrExit(error = ParseToIp6Address(GetInstancePtr(), aArgs[0], config.mDestination, nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Pinging synthesized IPv6 address: ");
OutputIp6AddressLine(config.mDestination);
}
if (!aArgs[1].IsEmpty())
{
+21
View File
@@ -235,6 +235,27 @@ public:
*/
static const char *PreferenceToString(signed int aPreference);
/**
* This method parses the argument as an IP address.
*
* If the argument string is an IPv4 address, this method will try to synthersize an IPv6 address using preferred
* NAT64 prefix in the network data.
*
* @param[in] aInstance A pointer to openthread instance.
* @param[in] aArg The argument string to parse.
* @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address.
* @param[out] aSynthesized Whether @p aAddress is synthesized from an IPv4 address.
*
* @retval OT_ERROR_NONE The argument was parsed successfully.
* @retval OT_ERROR_INVALID_ARGS The argument is empty or does not contain valid IP address.
* @retval OT_ERROR_INVALID_STATE No valid NAT64 prefix in the network data.
*
*/
static otError ParseToIp6Address(otInstance * aInstance,
const Arg & aArg,
otIp6Address &aAddress,
bool & aSynthesized);
protected:
static Interpreter *sInterpreter;
+10 -1
View File
@@ -39,6 +39,7 @@
#include "cli_tcp.hpp"
#include <openthread/nat64.h>
#include <openthread/tcp.h>
#include "cli/cli.hpp"
@@ -175,10 +176,18 @@ otError TcpExample::ProcessConnect(Arg aArgs[])
{
otError error;
otSockAddr sockaddr;
bool nat64SynthesizedAddress;
VerifyOrExit(mInitialized, error = OT_ERROR_INVALID_STATE);
SuccessOrExit(error = aArgs[0].ParseAsIp6Address(sockaddr.mAddress));
SuccessOrExit(
error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Connecting to synthesized IPv6 address: ");
OutputIp6AddressLine(sockaddr.mAddress);
}
SuccessOrExit(error = aArgs[1].ParseAsUint16(sockaddr.mPort));
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
+20 -2
View File
@@ -34,6 +34,7 @@
#include "cli_udp.hpp"
#include <openthread/message.h>
#include <openthread/nat64.h>
#include <openthread/udp.h>
#include "cli/cli.hpp"
@@ -94,8 +95,16 @@ otError UdpExample::ProcessConnect(Arg aArgs[])
{
otError error;
otSockAddr sockaddr;
bool nat64SynthesizedAddress;
SuccessOrExit(
error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], sockaddr.mAddress, nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Connecting to synthesized IPv6 address: ");
OutputIp6AddressLine(sockaddr.mAddress);
}
SuccessOrExit(error = aArgs[0].ParseAsIp6Address(sockaddr.mAddress));
SuccessOrExit(error = aArgs[1].ParseAsUint16(sockaddr.mPort));
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
@@ -143,7 +152,16 @@ otError UdpExample::ProcessSend(Arg aArgs[])
if (!aArgs[2].IsEmpty())
{
SuccessOrExit(error = aArgs[0].ParseAsIp6Address(messageInfo.mPeerAddr));
bool nat64SynthesizedAddress;
SuccessOrExit(error = Interpreter::ParseToIp6Address(GetInstancePtr(), aArgs[0], messageInfo.mPeerAddr,
nat64SynthesizedAddress));
if (nat64SynthesizedAddress)
{
OutputFormat("Sending to synthesized IPv6 address: ");
OutputIp6AddressLine(messageInfo.mPeerAddr);
}
SuccessOrExit(error = aArgs[1].ParseAsUint16(messageInfo.mPeerPort));
aArgs += 2;
}
+1
View File
@@ -39,6 +39,7 @@
#include "common/locator_getters.hpp"
#include "net/ip4_types.hpp"
#include "net/ip6_headers.hpp"
#include "thread/network_data_leader.hpp"
#include "utils/slaac_address.hpp"
using namespace ot;
+19
View File
@@ -110,6 +110,25 @@ void otIp4ExtractFromIp6Address(uint8_t aPrefixLength, const otIp6Address *aIp6A
AsCoreType(aIp4Address).ExtractFromIp6Address(aPrefixLength, AsCoreType(aIp6Address));
}
otError otIp4AddressFromString(const char *aString, otIp4Address *aAddress)
{
AssertPointerIsNotNull(aString);
return AsCoreType(aAddress).FromString(aString);
}
otError otNat64SynthersizeIp6Address(otInstance *aInstance, const otIp4Address *aIp4Address, otIp6Address *aIp6Address)
{
otError err = OT_ERROR_NONE;
NetworkData::ExternalRouteConfig nat64Prefix;
VerifyOrExit(AsCoreType(aInstance).Get<NetworkData::Leader>().GetPreferredNat64Prefix(nat64Prefix) == OT_ERROR_NONE,
err = OT_ERROR_INVALID_STATE);
AsCoreType(aIp6Address).SynthesizeFromIp4Address(nat64Prefix.GetPrefix(), AsCoreType(aIp4Address));
exit:
return err;
}
void otIp4AddressToString(const otIp4Address *aAddress, char *aBuffer, uint16_t aSize)
{
AssertPointerIsNotNull(aBuffer);
+5
View File
@@ -264,6 +264,11 @@ Error ParseAsIp6Address(const char *aString, otIp6Address &aAddress)
return (aString != nullptr) ? otIp6AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
}
Error ParseAsIp4Address(const char *aString, otIp4Address &aAddress)
{
return (aString != nullptr) ? otIp4AddressFromString(aString, &aAddress) : kErrorInvalidArgs;
}
Error ParseAsIp6Prefix(const char *aString, otIp6Prefix &aPrefix)
{
enum : uint8_t
+28
View File
@@ -38,7 +38,9 @@
#include <string.h>
#include <openthread/error.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
#include <openthread/nat64.h>
namespace ot {
namespace Utils {
@@ -182,6 +184,18 @@ otError ParseAsBool(const char *aString, bool &aBool);
*/
otError ParseAsIp6Address(const char *aString, otIp6Address &aAddress);
/**
* This function parses a string as an IPv4 address.
*
* @param[in] aString The string to parse.
* @param[out] aAddress A reference to an `otIp6Address` to output the parsed IPv6 address.
*
* @retval kErrorNone The string was parsed successfully.
* @retval kErrorInvalidArgs The string does not contain valid IPv4 address.
*
*/
otError ParseAsIp4Address(const char *aString, otIp4Address &aAddress);
/**
* This function parses a string as an IPv6 prefix.
*
@@ -485,6 +499,20 @@ public:
return CmdLineParser::ParseAsIp6Address(mString, aAddress);
}
/**
* This method parses the argument as an IPv4 address.
*
* @param[out] aAddress A reference to an `otIp4Address` to output the parsed IPv4 address.
*
* @retval kErrorNone The argument was parsed successfully.
* @retval kErrorInvalidArgs The argument is empty or does not contain valid IPv4 address.
*
*/
otError ParseAsIp4Address(otIp4Address &aAddress) const
{
return CmdLineParser::ParseAsIp4Address(mString, aAddress);
}
/**
* This method parses the argument as an IPv6 prefix.
*