mirror of
https://github.com/espressif/openthread.git
synced 2026-08-11 13:17:48 +00:00
[dns-client] add support for NAT64 during address resolution (#6414)
This commit adds support for NAT64 address translation (from IPv4 to IPv6) during address resolution in `Dns::Client`. This feature is enabled using `OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE` config option. When enabled, the caller can specify in the address query configuration whether to allow or disallow NAT64 address translation for a specific query. The default behavior can also be set using the default DNS client config. When the NAT64 is allowed, if the response from server does not provide an IPv6 address for the host name, we first check if the server has provided IPv4 address information in the response, and if not, start a new query for the IPv4 address. Once the IPv4 address(es) of the host name are resolved, they are translated to IPv6 address(es) and reported to the user in the query callback function.
This commit is contained in:
@@ -66,6 +66,20 @@ typedef enum
|
||||
OT_DNS_FLAG_NO_RECURSION = 2, ///< Indicates DNS name server can not resolve the query recursively.
|
||||
} otDnsRecursionFlag;
|
||||
|
||||
/**
|
||||
* This enumeration type represents the NAT64 mode in an `otDnsQueryConfig`.
|
||||
*
|
||||
* The NAT64 mode indicates whether to allow or disallow NAT64 address translation during DNS client address resolution.
|
||||
* This mode is only used when `OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE` is enabled.
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
OT_DNS_NAT64_UNSPECIFIED = 0, ///< NAT64 mode is not specified. Use default NAT64 mode.
|
||||
OT_DNS_NAT64_ALLOW = 1, ///< Allow NAT64 address translation during DNS client address resolution.
|
||||
OT_DNS_NAT64_DISALLOW = 2, ///< Do not allow NAT64 address translation during DNS client address resolution.
|
||||
} otDnsNat64Mode;
|
||||
|
||||
/**
|
||||
* This structure represents a DNS query configuration.
|
||||
*
|
||||
@@ -79,6 +93,7 @@ typedef struct otDnsQueryConfig
|
||||
uint32_t mResponseTimeout; ///< Wait time (in msec) to rx response. Zero indicates unspecified value.
|
||||
uint8_t mMaxTxAttempts; ///< Maximum tx attempts before reporting failure. Zero for unspecified value.
|
||||
otDnsRecursionFlag mRecursionFlag; ///< Indicates whether the server can resolve the query recursively or not.
|
||||
otDnsNat64Mode mNat64Mode; ///< Allow/Disallow NAT64 address translation during address resolution.
|
||||
} otDnsQueryConfig;
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (98)
|
||||
#define OPENTHREAD_API_VERSION (99)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -45,6 +45,28 @@
|
||||
#define OPENTHREAD_CONFIG_DNS_CLIENT_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
*
|
||||
* Define to 1 to enable support for NAT64 address translation (from IPv4 to IPv6) during address resolution by DNS
|
||||
* client.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
#define OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED
|
||||
*
|
||||
* Specifies the default NAT64 mode, i.e., whether to allow or disallow NAT64 address translation during DNS client
|
||||
* address resolution. This mode is only available when `OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE` is enabled.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED
|
||||
#define OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
*
|
||||
|
||||
+210
-39
@@ -60,6 +60,9 @@ Client::QueryConfig::QueryConfig(InitMode aMode)
|
||||
SetResponseTimeout(kDefaultResponseTimeout);
|
||||
SetMaxTxAttempts(kDefaultMaxTxAttempts);
|
||||
SetRecursionFlag(kDefaultRecursionDesired ? kFlagRecursionDesired : kFlagNoRecursion);
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
SetNat64Mode(kDefaultNat64Allowed ? kNat64Allow : kNat64Disallow);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Client::QueryConfig::SetFrom(const QueryConfig &aConfig, const QueryConfig &aDefaultConfig)
|
||||
@@ -94,6 +97,13 @@ void Client::QueryConfig::SetFrom(const QueryConfig &aConfig, const QueryConfig
|
||||
{
|
||||
SetRecursionFlag(aDefaultConfig.GetRecursionFlag());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
if (GetNat64Mode() == kNat64Unspecified)
|
||||
{
|
||||
SetNat64Mode(aDefaultConfig.GetNat64Mode());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -122,37 +132,57 @@ Error Client::Response::GetName(char *aNameBuffer, uint16_t aNameBufferSize) con
|
||||
return Name::ReadName(*mQuery, offset, aNameBuffer, aNameBufferSize);
|
||||
}
|
||||
|
||||
Error Client::Response::CheckForHostNameAlias(Section aSection, Name &aHostName) const
|
||||
{
|
||||
// If the response includes a CNAME record mapping the query host
|
||||
// name to a canonical name, we update `aHostName` to the new alias
|
||||
// name. Otherwise `aHostName` remains as before.
|
||||
|
||||
Error error;
|
||||
uint16_t offset;
|
||||
uint16_t numRecords;
|
||||
CnameRecord cnameRecord;
|
||||
|
||||
VerifyOrExit(mMessage != nullptr, error = kErrorNotFound);
|
||||
|
||||
SelectSection(aSection, offset, numRecords);
|
||||
error = ResourceRecord::FindRecord(*mMessage, offset, numRecords, /* aIndex */ 0, aHostName, cnameRecord);
|
||||
|
||||
switch (error)
|
||||
{
|
||||
case kErrorNone:
|
||||
// A CNAME record was found. `offset` now points to after the
|
||||
// last read byte within the `mMessage` into the `cnameRecord`
|
||||
// (which is the start of the new canonical name).
|
||||
aHostName.SetFromMessage(*mMessage, offset);
|
||||
error = Name::ParseName(*mMessage, offset);
|
||||
break;
|
||||
|
||||
case kErrorNotFound:
|
||||
error = kErrorNone;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Client::Response::FindHostAddress(Section aSection,
|
||||
const Name & aHostName,
|
||||
uint16_t aIndex,
|
||||
Ip6::Address &aAddress,
|
||||
uint32_t & aTtl) const
|
||||
{
|
||||
Error error;
|
||||
uint16_t offset;
|
||||
uint16_t numRecords;
|
||||
Name name = aHostName;
|
||||
CnameRecord cnameRecord;
|
||||
AaaaRecord aaaaRecord;
|
||||
Error error;
|
||||
uint16_t offset;
|
||||
uint16_t numRecords;
|
||||
Name name = aHostName;
|
||||
AaaaRecord aaaaRecord;
|
||||
|
||||
VerifyOrExit(mMessage != nullptr, error = kErrorNotFound);
|
||||
|
||||
// If the response includes a CNAME record mapping the query host
|
||||
// name to a canonical name, we then search for AAAA records
|
||||
// matching the canonical name.
|
||||
|
||||
SelectSection(aSection, offset, numRecords);
|
||||
error = ResourceRecord::FindRecord(*mMessage, offset, numRecords, /* aIndex */ 0, aHostName, cnameRecord);
|
||||
|
||||
if (error == kErrorNone)
|
||||
{
|
||||
name.SetFromMessage(*mMessage, offset);
|
||||
SuccessOrExit(error = Name::ParseName(*mMessage, offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(error == kErrorNotFound);
|
||||
}
|
||||
SuccessOrExit(error = CheckForHostNameAlias(aSection, name));
|
||||
|
||||
SelectSection(aSection, offset, numRecords);
|
||||
SuccessOrExit(error = ResourceRecord::FindRecord(*mMessage, offset, numRecords, aIndex, name, aaaaRecord));
|
||||
@@ -163,6 +193,26 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
Error Client::Response::FindARecord(Section aSection, const Name &aHostName, uint16_t aIndex, ARecord &aARecord) const
|
||||
{
|
||||
Error error;
|
||||
uint16_t offset;
|
||||
uint16_t numRecords;
|
||||
Name name = aHostName;
|
||||
|
||||
SuccessOrExit(error = CheckForHostNameAlias(aSection, name));
|
||||
|
||||
SelectSection(aSection, offset, numRecords);
|
||||
error = ResourceRecord::FindRecord(*mMessage, offset, numRecords, aIndex, name, aARecord);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
|
||||
Error Client::Response::FindServiceInfo(Section aSection, const Name &aName, ServiceInfo &aServiceInfo) const
|
||||
@@ -257,9 +307,60 @@ exit:
|
||||
|
||||
Error Client::AddressResponse::GetAddress(uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const
|
||||
{
|
||||
return FindHostAddress(kAnswerSection, Name(*mQuery, kNameOffsetInQuery), aIndex, aAddress, aTtl);
|
||||
Error error = kErrorNone;
|
||||
Name name(*mQuery, kNameOffsetInQuery);
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
// If the response is for an IPv4 address query or if it is an
|
||||
// IPv6 address query response with no IPv6 address but with
|
||||
// an IPv4 in its additional section, we read the IPv4 address
|
||||
// and translate it to an IPv6 address.
|
||||
|
||||
QueryInfo info;
|
||||
|
||||
info.ReadFrom(*mQuery);
|
||||
|
||||
if ((info.mQueryType == kIp4AddressQuery) || mIp6QueryResponseRequiresNat64)
|
||||
{
|
||||
Section section;
|
||||
ARecord aRecord;
|
||||
Ip6::Prefix nat64Prefix;
|
||||
|
||||
SuccessOrExit(error = GetNat64Prefix(nat64Prefix));
|
||||
|
||||
section = (info.mQueryType == kIp4AddressQuery) ? kAnswerSection : kAdditionalDataSection;
|
||||
SuccessOrExit(error = FindARecord(section, name, aIndex, aRecord));
|
||||
|
||||
aAddress.SynthesizeFromIp4Address(nat64Prefix, aRecord.GetAddress());
|
||||
aTtl = aRecord.GetTtl();
|
||||
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
ExitNow(error = FindHostAddress(kAnswerSection, name, aIndex, aAddress, aTtl));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
Error Client::AddressResponse::GetNat64Prefix(Ip6::Prefix &aPrefix) const
|
||||
{
|
||||
// Use well-known prefix "64:ff9b::/96" (temporary solution).
|
||||
static const uint8_t kWellknownPrefix[] = {0x00, 0x64, 0xff, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
aPrefix.Clear();
|
||||
aPrefix.Set(kWellknownPrefix, 96);
|
||||
|
||||
return kErrorNone;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -410,25 +511,34 @@ Error Client::ServiceResponse::GetHostAddress(const char * aHostName,
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Client
|
||||
|
||||
const uint16_t Client::kAddressQueryRecordTypes[] = {ResourceRecord::kTypeAaaa};
|
||||
const uint16_t Client::kIp6AddressQueryRecordTypes[] = {ResourceRecord::kTypeAaaa};
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
const uint16_t Client::kIp4AddressQueryRecordTypes[] = {ResourceRecord::kTypeA};
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
const uint16_t Client::kBrowseQueryRecordTypes[] = {ResourceRecord::kTypePtr};
|
||||
const uint16_t Client::kServiceQueryRecordTypes[] = {ResourceRecord::kTypeSrv, ResourceRecord::kTypeTxt};
|
||||
#endif
|
||||
|
||||
const uint8_t Client::kQuestionCount[] = {
|
||||
/* (0) kAddressQuery -> */ OT_ARRAY_LENGTH(kAddressQueryRecordTypes), // AAAA records
|
||||
/* kIp6AddressQuery -> */ OT_ARRAY_LENGTH(kIp6AddressQueryRecordTypes), // AAAA records
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
/* kIp4AddressQuery -> */ OT_ARRAY_LENGTH(kIp4AddressQueryRecordTypes), // A records
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
/* (1) kBrowseQuery -> */ OT_ARRAY_LENGTH(kBrowseQueryRecordTypes), // PTR records
|
||||
/* (2) kServiceQuery -> */ OT_ARRAY_LENGTH(kServiceQueryRecordTypes), // SRV and TXT records
|
||||
/* kBrowseQuery -> */ OT_ARRAY_LENGTH(kBrowseQueryRecordTypes), // PTR records
|
||||
/* kServiceQuery -> */ OT_ARRAY_LENGTH(kServiceQueryRecordTypes), // SRV and TXT records
|
||||
#endif
|
||||
};
|
||||
|
||||
const uint16_t *Client::kQuestionRecordTypes[] = {
|
||||
/* (0) kAddressQuery -> */ kAddressQueryRecordTypes,
|
||||
/* kIp6AddressQuery -> */ kIp6AddressQueryRecordTypes,
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
/* kIp4AddressQuery -> */ kIp4AddressQueryRecordTypes,
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
/* (1) kBrowseQuery -> */ kBrowseQueryRecordTypes,
|
||||
/* (2) kServiceQuery -> */ kServiceQueryRecordTypes,
|
||||
/* kBrowseQuery -> */ kBrowseQueryRecordTypes,
|
||||
/* kServiceQuery -> */ kServiceQueryRecordTypes,
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -438,8 +548,14 @@ Client::Client(Instance &aInstance)
|
||||
, mTimer(aInstance, Client::HandleTimer)
|
||||
, mDefaultConfig(QueryConfig::kInitFromDefaults)
|
||||
{
|
||||
static_assert(kAddressQuery == 0, "kAddressQuery value is not correct");
|
||||
static_assert(kIp6AddressQuery == 0, "kIp6AddressQuery value is not correct");
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
static_assert(kIp4AddressQuery == 1, "kIp4AddressQuery value is not correct");
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
static_assert(kBrowseQuery == 2, "kBrowseQuery value is not correct");
|
||||
static_assert(kServiceQuery == 3, "kServiceQuery value is not correct");
|
||||
#endif
|
||||
#elif OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
static_assert(kBrowseQuery == 1, "kBrowseQuery value is not correct");
|
||||
static_assert(kServiceQuery == 2, "kServiceQuery value is not correct");
|
||||
#endif
|
||||
@@ -488,7 +604,7 @@ Error Client::ResolveAddress(const char * aHostName,
|
||||
QueryInfo info;
|
||||
|
||||
info.Clear();
|
||||
info.mQueryType = kAddressQuery;
|
||||
info.mQueryType = kIp6AddressQuery;
|
||||
info.mCallback.mAddressCallback = aCallback;
|
||||
|
||||
return StartQuery(info, aConfig, nullptr, aHostName, aContext);
|
||||
@@ -694,7 +810,8 @@ void Client::FinalizeQuery(Query &aQuery, Error aError)
|
||||
Response response;
|
||||
QueryInfo info;
|
||||
|
||||
response.mQuery = &aQuery;
|
||||
response.mInstance = &Get<Instance>();
|
||||
response.mQuery = &aQuery;
|
||||
info.ReadFrom(aQuery);
|
||||
|
||||
FinalizeQuery(response, info.mQueryType, aError);
|
||||
@@ -709,7 +826,10 @@ void Client::FinalizeQuery(Response &aResponse, QueryType aType, Error aError)
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kAddressQuery:
|
||||
case kIp6AddressQuery:
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
case kIp4AddressQuery:
|
||||
#endif
|
||||
if (callback.mAddressCallback != nullptr)
|
||||
{
|
||||
callback.mAddressCallback(aError, &aResponse, context);
|
||||
@@ -777,7 +897,8 @@ void Client::ProcessResponse(const Message &aMessage)
|
||||
QueryType type;
|
||||
Error responseError;
|
||||
|
||||
response.mMessage = &aMessage;
|
||||
response.mInstance = &Get<Instance>();
|
||||
response.mMessage = &aMessage;
|
||||
|
||||
// We intentionally parse the response in a separate method
|
||||
// `ParseResponse()` to free all the stack allocated variables
|
||||
@@ -798,6 +919,7 @@ Error Client::ParseResponse(Response &aResponse, QueryType &aType, Error &aRespo
|
||||
uint16_t offset = message.GetOffset();
|
||||
Header header;
|
||||
QueryInfo info;
|
||||
Name queryName;
|
||||
|
||||
SuccessOrExit(error = message.Read(offset, header));
|
||||
offset += sizeof(Header);
|
||||
@@ -812,14 +934,15 @@ Error Client::ParseResponse(Response &aResponse, QueryType &aType, Error &aRespo
|
||||
info.ReadFrom(*aResponse.mQuery);
|
||||
aType = info.mQueryType;
|
||||
|
||||
queryName.SetFromMessage(*aResponse.mQuery, kNameOffsetInQuery);
|
||||
|
||||
// Check the Question Section
|
||||
|
||||
VerifyOrExit(header.GetQuestionCount() == kQuestionCount[aType], error = kErrorParse);
|
||||
|
||||
for (uint8_t num = 0; num < kQuestionCount[aType]; num++)
|
||||
{
|
||||
// The name is encoded after `Info` struct in `query`.
|
||||
SuccessOrExit(error = Name::CompareName(message, offset, *aResponse.mQuery, kNameOffsetInQuery));
|
||||
SuccessOrExit(error = Name::CompareName(message, offset, queryName));
|
||||
offset += sizeof(Question);
|
||||
}
|
||||
|
||||
@@ -838,6 +961,54 @@ Error Client::ParseResponse(Response &aResponse, QueryType &aType, Error &aRespo
|
||||
|
||||
aResponseError = Header::ResponseCodeToError(header.GetResponseCode());
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
if (aType == kIp6AddressQuery)
|
||||
{
|
||||
Ip6::Address ip6ddress;
|
||||
uint32_t ttl;
|
||||
ARecord aRecord;
|
||||
|
||||
// If the response does not contain an answer for the IPv6 address
|
||||
// resolution query and if NAT64 is allowed for this query, we can
|
||||
// perform IPv4 to IPv6 address translation.
|
||||
|
||||
VerifyOrExit(aResponse.FindHostAddress(Response::kAnswerSection, queryName, /* aIndex */ 0, ip6ddress, ttl) !=
|
||||
kErrorNone);
|
||||
VerifyOrExit(info.mConfig.GetNat64Mode() == QueryConfig::kNat64Allow);
|
||||
|
||||
// First, we check if the response already contains an A record
|
||||
// (IPv4 address) for the query name.
|
||||
|
||||
if (aResponse.FindARecord(Response::kAdditionalDataSection, queryName, /* aIndex */ 0, aRecord) == kErrorNone)
|
||||
{
|
||||
aResponse.mIp6QueryResponseRequiresNat64 = true;
|
||||
aResponseError = kErrorNone;
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
// Otherwise, we send a new query for IPv4 address resolution
|
||||
// for the same host name. We reuse the existing `query`
|
||||
// instance and keep all the info but clear `mTransmissionCount`
|
||||
// and `mMessageId` (so that a new random message ID is
|
||||
// selected). The new `info` will be saved in the query in
|
||||
// `SendQuery()`. Note that the current query is still in the
|
||||
// `mQueries` list when `SendQuery()` selects a new random
|
||||
// message ID, so the existing message ID for this query will
|
||||
// not be reused. Since the query is not yet resolved, we
|
||||
// return `kErrorPending`.
|
||||
|
||||
info.mQueryType = kIp4AddressQuery;
|
||||
info.mMessageId = 0;
|
||||
info.mTransmissionCount = 0;
|
||||
|
||||
SendQuery(*aResponse.mQuery, info, /* aUpdateTimer */ true);
|
||||
|
||||
error = kErrorPending;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
|
||||
exit:
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,19 @@ public:
|
||||
kFlagNoRecursion = OT_DNS_FLAG_NO_RECURSION, ///< Server can not resolve the query recursively.
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
/**
|
||||
* This enumeration type represents the NAT64 mode.
|
||||
*
|
||||
*/
|
||||
enum Nat64Mode
|
||||
{
|
||||
kNat64Unspecified = OT_DNS_NAT64_UNSPECIFIED, ///< NAT64 mode is not specified. Use default NAT64 mode.
|
||||
kNat64Allow = OT_DNS_NAT64_ALLOW, ///< Allow NAT64 address translation
|
||||
kNat64Disallow = OT_DNS_NAT64_DISALLOW, ///< Disallow NAT64 address translation.
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is the default constructor for `QueryConfig` object.
|
||||
*
|
||||
@@ -149,6 +162,16 @@ public:
|
||||
*/
|
||||
RecursionFlag GetRecursionFlag(void) const { return static_cast<RecursionFlag>(mRecursionFlag); }
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
/**
|
||||
* This method gets the NAT64 mode.
|
||||
*
|
||||
* @returns The NAT64 mode.
|
||||
*
|
||||
*/
|
||||
Nat64Mode GetNat64Mode(void) const { return static_cast<Nat64Mode>(mNat64Mode); }
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum : uint32_t
|
||||
{
|
||||
@@ -170,6 +193,13 @@ public:
|
||||
kDefaultRecursionDesired = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_RECURSION_DESIRED_FLAG,
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
enum : bool
|
||||
{
|
||||
kDefaultNat64Allowed = OPENTHREAD_CONFIG_DNS_CLIENT_DEFAULT_NAT64_ALLOWED,
|
||||
};
|
||||
#endif
|
||||
|
||||
enum InitMode : uint8_t
|
||||
{
|
||||
kInitFromDefaults,
|
||||
@@ -184,6 +214,9 @@ public:
|
||||
void SetResponseTimeout(uint32_t aResponseTimeout) { mResponseTimeout = aResponseTimeout; }
|
||||
void SetMaxTxAttempts(uint8_t aMaxTxAttempts) { mMaxTxAttempts = aMaxTxAttempts; }
|
||||
void SetRecursionFlag(RecursionFlag aFlag) { mRecursionFlag = static_cast<otDnsRecursionFlag>(aFlag); }
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
void SetNat64Mode(Nat64Mode aMode) { mNat64Mode = static_cast<otDnsNat64Mode>(aMode); }
|
||||
#endif
|
||||
|
||||
void SetFrom(const QueryConfig &aConfig, const QueryConfig &aDefaultConfig);
|
||||
};
|
||||
@@ -200,14 +233,12 @@ public:
|
||||
* This class represents a DNS query response.
|
||||
*
|
||||
*/
|
||||
class Response : public Clearable<Response>,
|
||||
public otDnsAddressResponse
|
||||
class Response : public otDnsAddressResponse,
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
,
|
||||
public otDnsBrowseResponse,
|
||||
public otDnsServiceResponse
|
||||
public otDnsServiceResponse,
|
||||
#endif
|
||||
|
||||
public Clearable<Response>
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
@@ -222,22 +253,34 @@ public:
|
||||
|
||||
Error GetName(char *aNameBuffer, uint16_t aNameBufferSize) const;
|
||||
void SelectSection(Section aSection, uint16_t &aOffset, uint16_t &aNumRecord) const;
|
||||
Error CheckForHostNameAlias(Section aSection, Name &aHostName) const;
|
||||
Error FindHostAddress(Section aSection,
|
||||
const Name & aHostName,
|
||||
uint16_t aIndex,
|
||||
Ip6::Address &aAddress,
|
||||
uint32_t & aTtl) const;
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
Error FindARecord(Section aSection, const Name &aHostName, uint16_t aIndex, ARecord &aARecord) const;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
Error FindServiceInfo(Section aSection, const Name &aName, ServiceInfo &aServiceInfo) const;
|
||||
#endif
|
||||
|
||||
Instance * mInstance; // The OpenThread instance.
|
||||
Query * mQuery; // The associated query.
|
||||
const Message *mMessage; // The response message.
|
||||
uint16_t mAnswerOffset; // Answer section offset in `mMessage`.
|
||||
uint16_t mAnswerRecordCount; // Number of records in answer section.
|
||||
uint16_t mAdditionalOffset; // Additional data section offset in `mMessage`.
|
||||
uint16_t mAdditionalRecordCount; // Number of records in additional data section.
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
// This flag is only used in an IPv6 address query response.
|
||||
// It indicates that the response does not contain any IPv6
|
||||
// addresses but server provided at least one IPv4 address
|
||||
// in the additional data section for NAT64 address synthesis.
|
||||
bool mIp6QueryResponseRequiresNat64;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -292,6 +335,11 @@ public:
|
||||
*
|
||||
*/
|
||||
Error GetAddress(uint16_t aIndex, Ip6::Address &aAddress, uint32_t &aTtl) const;
|
||||
|
||||
private:
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
Error GetNat64Prefix(Ip6::Prefix &aPrefix) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
@@ -612,7 +660,10 @@ public:
|
||||
private:
|
||||
enum QueryType : uint8_t
|
||||
{
|
||||
kAddressQuery, // Address resolution.
|
||||
kIp6AddressQuery, // IPv6 Address resolution.
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
kIp4AddressQuery, // IPv4 Address resolution
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
kBrowseQuery, // Browse (service instance enumeration).
|
||||
kServiceQuery, // Service instance resolution.
|
||||
@@ -668,11 +719,17 @@ private:
|
||||
Error ParseResponse(Response &aResponse, QueryType &aType, Error &aResponseError);
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
Error CheckAddressResponse(Response &aResponse, Error aResponseError) const;
|
||||
#endif
|
||||
|
||||
static const uint8_t kQuestionCount[];
|
||||
static const uint16_t *kQuestionRecordTypes[];
|
||||
|
||||
static const uint16_t kAddressQueryRecordTypes[];
|
||||
static const uint16_t kIp6AddressQueryRecordTypes[];
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_NAT64_ENABLE
|
||||
static const uint16_t kIp4AddressQueryRecordTypes[];
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_CLIENT_SERVICE_DISCOVERY_ENABLE
|
||||
static const uint16_t kBrowseQueryRecordTypes[];
|
||||
static const uint16_t kServiceQueryRecordTypes[];
|
||||
|
||||
@@ -453,7 +453,7 @@ bool Address::MatchesFilter(TypeFilter aFilter) const
|
||||
return matches;
|
||||
}
|
||||
|
||||
void Address::SetFromTranslatedIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
|
||||
void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address)
|
||||
{
|
||||
// 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`)
|
||||
|
||||
@@ -892,7 +892,7 @@ public:
|
||||
* @param[in] aIp4Address The IPv4 address to translate to IPv6.
|
||||
*
|
||||
*/
|
||||
void SetFromTranslatedIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address);
|
||||
void SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address &aIp4Address);
|
||||
|
||||
/**
|
||||
* This method converts an IPv6 address string to binary.
|
||||
|
||||
@@ -399,13 +399,13 @@ void TestIp4Ip6Translation(void)
|
||||
|
||||
SuccessOrQuit(expectedAddress.FromString(testCase.mIp6Address), "Ip6::FromString() failed");
|
||||
|
||||
address.SetFromTranslatedIp4Address(prefix, ip4Address);
|
||||
address.SynthesizeFromIp4Address(prefix, ip4Address);
|
||||
|
||||
printf("Prefix: %-26s IPv4Addr: %-12s Ipv6Address: %-36s Expected: %s (%s)\n", prefix.ToString().AsCString(),
|
||||
ip4Address.ToString().AsCString(), address.ToString().AsCString(), testCase.mIp6Address,
|
||||
expectedAddress.ToString().AsCString());
|
||||
|
||||
VerifyOrQuit(address == expectedAddress, "Ip6::SetFromTranslatedIp4Address() failed");
|
||||
VerifyOrQuit(address == expectedAddress, "Ip6::SynthesizeFromIp4Address() failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user