[dns] add MatchesKey() to Dns::TxtEntry (#12579)

This commit adds `MatchesKey()` method to `Dns::TxtEntry` class to
check if the entry's key matches a given key string using a
case-insensitive string comparison.

The new method properly handles the case where the entry's key is
`nullptr` (which can happen when the key is longer than the
recommended max length). It simplifies the TXT entry parsing logic in
`BorderAgent` and `Trel::PeerDiscoverer`.

The unit tests for `Dns::TxtEntry` are also updated to verify the new
method.
This commit is contained in:
Abtin Keshavarzian
2026-02-27 16:55:35 -08:00
committed by GitHub
parent be4ce643ec
commit d0237f5e91
5 changed files with 44 additions and 37 deletions
+15 -22
View File
@@ -303,28 +303,21 @@ Error TxtData::Info::ParseFrom(const uint8_t *aTxtData, uint16_t aTxtDataLength)
void TxtData::Info::ProcessTxtEntry(const Dns::TxtEntry &aEntry)
{
if (aEntry.mKey == nullptr)
{
// If the TXT data happens to have entries with key longer
// than `kMaxIterKeyLength`, `mKey` would be `nullptr` and full
// entry would be placed in `mValue`. We skip over such
// entries.
}
else if (StringMatch(aEntry.mKey, Key::kRecordVersion))
if (aEntry.MatchesKey(Key::kRecordVersion))
{
ReadStringValue(aEntry, mRecordVersion);
mHasRecordVersion = true;
}
else if (StringMatch(aEntry.mKey, Key::kAgentId))
else if (aEntry.MatchesKey(Key::kAgentId))
{
mHasAgentId = ReadValue(aEntry, mAgentId);
}
else if (StringMatch(aEntry.mKey, Key::kThreadVersion))
else if (aEntry.MatchesKey(Key::kThreadVersion))
{
ReadStringValue(aEntry, mThreadVersion);
mHasThreadVersion = true;
}
else if (StringMatch(aEntry.mKey, Key::kStateBitmap))
else if (aEntry.MatchesKey(Key::kStateBitmap))
{
uint32_t bitmap;
@@ -334,16 +327,16 @@ void TxtData::Info::ProcessTxtEntry(const Dns::TxtEntry &aEntry)
mHasStateBitmap = true;
}
}
else if (StringMatch(aEntry.mKey, Key::kNetworkName))
else if (aEntry.MatchesKey(Key::kNetworkName))
{
ReadStringValue(aEntry, mNetworkName.m8);
mHasNetworkName = true;
}
else if (StringMatch(aEntry.mKey, Key::kExtendedPanId))
else if (aEntry.MatchesKey(Key::kExtendedPanId))
{
mHasExtendedPanId = ReadValue(aEntry, mExtendedPanId);
}
else if (StringMatch(aEntry.mKey, Key::kActiveTimestamp))
else if (aEntry.MatchesKey(Key::kActiveTimestamp))
{
Timestamp timestamp;
@@ -353,37 +346,37 @@ void TxtData::Info::ProcessTxtEntry(const Dns::TxtEntry &aEntry)
mHasActiveTimestamp = true;
}
}
else if (StringMatch(aEntry.mKey, Key::kPartitionId))
else if (aEntry.MatchesKey(Key::kPartitionId))
{
mHasPartitionId = ReadBigEndianUintValue(aEntry, mPartitionId);
}
else if (StringMatch(aEntry.mKey, Key::kDomainName))
else if (aEntry.MatchesKey(Key::kDomainName))
{
ReadStringValue(aEntry, mDomainName.m8);
mHasDomainName = true;
}
else if (StringMatch(aEntry.mKey, Key::kBbrSeqNum))
else if (aEntry.MatchesKey(Key::kBbrSeqNum))
{
mHasBbrSeqNum = ReadBigEndianUintValue(aEntry, mBbrSeqNum);
}
else if (StringMatch(aEntry.mKey, Key::kBbrPort))
else if (aEntry.MatchesKey(Key::kBbrPort))
{
mHasBbrPort = ReadBigEndianUintValue(aEntry, mBbrPort);
}
else if (StringMatch(aEntry.mKey, Key::kOmrPrefix))
else if (aEntry.MatchesKey(Key::kOmrPrefix))
{
mHasOmrPrefix = ReadOmrPrefix(aEntry, AsCoreType(&mOmrPrefix));
}
else if (StringMatch(aEntry.mKey, Key::kExtAddress))
else if (aEntry.MatchesKey(Key::kExtAddress))
{
mHasExtAddress = ReadValue(aEntry, mExtAddress);
}
else if (StringMatch(aEntry.mKey, Key::kVendorName))
else if (aEntry.MatchesKey(Key::kVendorName))
{
ReadStringValue(aEntry, mVendorName);
mHasVendorName = true;
}
else if (StringMatch(aEntry.mKey, Key::kModelName))
else if (aEntry.MatchesKey(Key::kModelName))
{
ReadStringValue(aEntry, mModelName);
mHasModelName = true;
+5
View File
@@ -1380,6 +1380,11 @@ exit:
return error;
}
bool TxtEntry::MatchesKey(const char *aKey) const
{
return (mKey != nullptr) && StringMatch(mKey, aKey, kStringCaseInsensitiveMatch);
}
Error TxtEntry::AppendTo(Message &aMessage) const
{
Appender appender(aMessage);
+10
View File
@@ -1223,6 +1223,16 @@ public:
mValueLength = aValueLength;
}
/**
* Indicates whether the entry's key (`mKey`) matches a given key string using a case-insensitive comparison.
*
* @param[in] aKey A pointer to a key string to compare with.
*
* @retval TRUE The entry's key matches the given @p aKey.
* @retval FALSE The entry's key does not match or `mKey` is `nullptr`.
*/
bool MatchesKey(const char *aKey) const;
/**
* Encodes and appends the `TxtEntry` to a message.
*
+2 -11
View File
@@ -750,23 +750,14 @@ Error PeerDiscoverer::TxtData::Decode(Info &aInfo)
while ((error = iterator.GetNextEntry(entry)) == kErrorNone)
{
// If the TXT data happens to have entries with key longer
// than `kMaxIterKeyLength`, `mKey` would be `nullptr` and full
// entry would be placed in `mValue`. We skip over such
// entries.
if (entry.mKey == nullptr)
{
continue;
}
if (StringMatch(entry.mKey, kExtAddressKey))
if (entry.MatchesKey(kExtAddressKey))
{
VerifyOrExit(!parsedExtAddress, error = kErrorParse);
VerifyOrExit(entry.mValueLength >= sizeof(Mac::ExtAddress), error = kErrorParse);
aInfo.mExtAddress.Set(entry.mValue);
parsedExtAddress = true;
}
else if (StringMatch(entry.mKey, kExtPanIdKey))
else if (entry.MatchesKey(kExtPanIdKey))
{
VerifyOrExit(!parsedExtPanId, error = kErrorParse);
VerifyOrExit(entry.mValueLength >= sizeof(MeshCoP::ExtendedPanId), error = kErrorParse);
+12 -4
View File
@@ -34,6 +34,7 @@
#include "test_util.hpp"
#include "common/array.hpp"
#include "common/string.hpp"
#include "instance/instance.hpp"
#include "net/dns_types.hpp"
@@ -1632,10 +1633,8 @@ void TestHeaderAndResourceRecords(void)
void TestDnsTxtEntry(void)
{
enum
{
kMaxTxtDataSize = 255,
};
static constexpr uint16_t kMaxTxtDataSize = 255;
static constexpr uint16_t kMaxKeyStringSize = Dns::TxtEntry::kMaxIterKeyLength;
struct EncodedTxtData
{
@@ -1718,6 +1717,7 @@ void TestDnsTxtEntry(void)
Dns::TxtEntry txtEntry;
Dns::TxtEntry::Iterator iterator;
MutableData<kWithUint16Length> data;
char keyString[kMaxKeyStringSize];
printf("================================================================\n");
printf("TestDnsTxtEntry()\n");
@@ -1772,6 +1772,14 @@ void TestDnsTxtEntry(void)
}
VerifyOrQuit(strcmp(txtEntry.mKey, expectedTxtEntry.mKey) == 0);
SuccessOrQuit(StringCopy(keyString, expectedTxtEntry.mKey));
VerifyOrQuit(txtEntry.MatchesKey(keyString));
StringConvertToLowercase(keyString);
VerifyOrQuit(txtEntry.MatchesKey(keyString));
StringConvertToUppercase(keyString);
VerifyOrQuit(txtEntry.MatchesKey(keyString));
VerifyOrQuit(txtEntry.mValueLength == expectedTxtEntry.mValueLength);
if (txtEntry.mValueLength != 0)