mirror of
https://github.com/espressif/openthread.git
synced 2026-08-03 09:27:47 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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())
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user