mirror of
https://github.com/espressif/openthread.git
synced 2026-08-29 13:29:54 +00:00
[dns] change Dns::Name::CompareName/Label() to be case-insensitive (#7189)
This commit changes the `Dns::Name::CompareName/Label()` methods to perform case-insensitive string comparison. This is realized by adding a new flavor of `Data::MatchesBytesIn()` which accepts a `ByteMatcher` function pointer. This allows the caller to relax the definition of a match and how the bytes are compared. `Message` class methods that compare bytes are also updated to allow `ByteMatcher` as an input parameter. This commit also updates the unit test `test_dns` to cover the new method and behaviors.
This commit is contained in:
committed by
Jonathan Hui
parent
07031e1651
commit
e16261aa6c
@@ -221,6 +221,7 @@ LOCAL_SRC_FILES := \
|
||||
src/core/coap/coap_secure.cpp \
|
||||
src/core/common/appender.cpp \
|
||||
src/core/common/crc16.cpp \
|
||||
src/core/common/data.cpp \
|
||||
src/core/common/error.cpp \
|
||||
src/core/common/heap.cpp \
|
||||
src/core/common/heap_data.cpp \
|
||||
|
||||
@@ -382,6 +382,7 @@ openthread_core_files = [
|
||||
"common/const_cast.hpp",
|
||||
"common/crc16.cpp",
|
||||
"common/crc16.hpp",
|
||||
"common/data.cpp",
|
||||
"common/data.hpp",
|
||||
"common/debug.hpp",
|
||||
"common/encoding.hpp",
|
||||
|
||||
@@ -94,6 +94,7 @@ set(COMMON_SOURCES
|
||||
coap/coap_secure.cpp
|
||||
common/appender.cpp
|
||||
common/crc16.cpp
|
||||
common/data.cpp
|
||||
common/error.cpp
|
||||
common/heap.cpp
|
||||
common/heap_data.cpp
|
||||
|
||||
@@ -184,6 +184,7 @@ SOURCES_COMMON = \
|
||||
coap/coap_secure.cpp \
|
||||
common/appender.cpp \
|
||||
common/crc16.cpp \
|
||||
common/data.cpp \
|
||||
common/error.cpp \
|
||||
common/heap.cpp \
|
||||
common/heap_data.cpp \
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 implements `Data` related function
|
||||
*/
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
bool DataUtils::MatchBytes(const uint8_t *aFirstBuffer,
|
||||
const uint8_t *aSecondBuffer,
|
||||
uint16_t aLength,
|
||||
ByteMatcher aMatcher)
|
||||
{
|
||||
bool matches = true;
|
||||
|
||||
if (aMatcher == nullptr)
|
||||
{
|
||||
matches = (memcmp(aFirstBuffer, aSecondBuffer, aLength) == 0);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
while (aLength-- != 0)
|
||||
{
|
||||
VerifyOrExit(aMatcher(*aFirstBuffer++, *aSecondBuffer++), matches = false);
|
||||
}
|
||||
|
||||
exit:
|
||||
return matches;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
@@ -59,6 +59,35 @@ enum DataLengthType : uint8_t
|
||||
kWithUint16Length, ///< Use `uint16_t` for data length
|
||||
};
|
||||
|
||||
/**
|
||||
* This type specifies a function pointer which matches two given bytes.
|
||||
*
|
||||
* Such a function is used as a parameter in `Data::MatchesByteIn()` method. This can be used to relax the definition
|
||||
* of a match when comparing data bytes, e.g., can be used for case-insensitive string comparison.
|
||||
*
|
||||
* @param[in] aFirst A first byte.
|
||||
* @param[in] aSecond A second byte.
|
||||
*
|
||||
* @retval TRUE if @p aFirst matches @p aSecond.
|
||||
* @retval FLASE if @p aFirst does not match @p aSecond.
|
||||
*
|
||||
*/
|
||||
typedef bool (*ByteMatcher)(uint8_t aFirst, uint8_t aSecond);
|
||||
|
||||
/**
|
||||
* This class implements common utility methods used by `Data` and `MutableData`.
|
||||
*
|
||||
*/
|
||||
class DataUtils
|
||||
{
|
||||
protected:
|
||||
DataUtils(void) = default;
|
||||
static bool MatchBytes(const uint8_t *aFirstBuffer,
|
||||
const uint8_t *aSecondBuffer,
|
||||
uint16_t aLength,
|
||||
ByteMatcher aMatcher);
|
||||
};
|
||||
|
||||
template <DataLengthType kDataLengthType> class MutableData;
|
||||
|
||||
/**
|
||||
@@ -76,7 +105,7 @@ template <DataLengthType kDataLengthType> class MutableData;
|
||||
*
|
||||
*/
|
||||
template <DataLengthType kDataLengthType>
|
||||
class Data : public Clearable<Data<kDataLengthType>>, public Unequatable<Data<kDataLengthType>>
|
||||
class Data : public Clearable<Data<kDataLengthType>>, public Unequatable<Data<kDataLengthType>>, private DataUtils
|
||||
{
|
||||
friend class MutableData<kDataLengthType>;
|
||||
|
||||
@@ -176,6 +205,23 @@ public:
|
||||
*/
|
||||
bool MatchesBytesIn(const void *aBuffer) const { return memcmp(mBuffer, aBuffer, mLength) == 0; }
|
||||
|
||||
/**
|
||||
* This method compares the `Data` content with the bytes from a given buffer using a given `Matcher` function.
|
||||
*
|
||||
* It is up to the caller to ensure that @p aBuffer has enough bytes to compare with the current data length.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to a buffer to compare with the data.
|
||||
* @param[in] aMatcher A `ByteMatcher` function to match the bytes. If `nullptr`, bytes are compared directly.
|
||||
*
|
||||
* @retval TRUE The `Data` content matches the bytes in @p aBuffer.
|
||||
* @retval FALSE The `Data` content does not match the byes in @p aBuffer.
|
||||
*
|
||||
*/
|
||||
bool MatchesBytesIn(const void *aBuffer, ByteMatcher aMatcher)
|
||||
{
|
||||
return MatchBytes(mBuffer, static_cast<const uint8_t *>(aBuffer), mLength, aMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method overloads operator `==` to compare the `Data` content with the content from another one.
|
||||
*
|
||||
|
||||
@@ -578,7 +578,7 @@ Error Message::Read(uint16_t aOffset, void *aBuf, uint16_t aLength) const
|
||||
return (ReadBytes(aOffset, aBuf, aLength) == aLength) ? kErrorNone : kErrorParse;
|
||||
}
|
||||
|
||||
bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength) const
|
||||
bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher) const
|
||||
{
|
||||
uint16_t bytesToCompare = aLength;
|
||||
const uint8_t *bufPtr = reinterpret_cast<const uint8_t *>(aBuf);
|
||||
@@ -588,7 +588,7 @@ bool Message::CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength)
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
VerifyOrExit(chunk.MatchesBytesIn(bufPtr));
|
||||
VerifyOrExit(chunk.MatchesBytesIn(bufPtr, aMatcher));
|
||||
bufPtr += chunk.GetLength();
|
||||
bytesToCompare -= chunk.GetLength();
|
||||
GetNextChunk(aLength, chunk);
|
||||
@@ -601,7 +601,8 @@ exit:
|
||||
bool Message::CompareBytes(uint16_t aOffset,
|
||||
const Message &aOtherMessage,
|
||||
uint16_t aOtherOffset,
|
||||
uint16_t aLength) const
|
||||
uint16_t aLength,
|
||||
ByteMatcher aMatcher) const
|
||||
{
|
||||
uint16_t bytesToCompare = aLength;
|
||||
Chunk chunk;
|
||||
@@ -610,7 +611,7 @@ bool Message::CompareBytes(uint16_t aOffset,
|
||||
|
||||
while (chunk.GetLength() > 0)
|
||||
{
|
||||
VerifyOrExit(aOtherMessage.CompareBytes(aOtherOffset, chunk.GetBytes(), chunk.GetLength()));
|
||||
VerifyOrExit(aOtherMessage.CompareBytes(aOtherOffset, chunk.GetBytes(), chunk.GetLength(), aMatcher));
|
||||
aOtherOffset += chunk.GetLength();
|
||||
bytesToCompare -= chunk.GetLength();
|
||||
GetNextChunk(aLength, chunk);
|
||||
|
||||
@@ -697,12 +697,14 @@ public:
|
||||
* @param[in] aOffset Byte offset within the message to read from for the comparison.
|
||||
* @param[in] aBuf A pointer to a data buffer to compare with the bytes from message.
|
||||
* @param[in] aLength Number of bytes in @p aBuf.
|
||||
* @param[in] aMatcher A `ByteMatcher` function pointer to match the bytes. If `nullptr` then bytes are directly
|
||||
* compared.
|
||||
*
|
||||
* @returns TRUE if there are enough bytes available in @p aMessage and they match the bytes from @p aBuf,
|
||||
* FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength) const;
|
||||
bool CompareBytes(uint16_t aOffset, const void *aBuf, uint16_t aLength, ByteMatcher aMatcher = nullptr) const;
|
||||
|
||||
/**
|
||||
* This method compares the bytes in the message at a given offset with bytes read from another message.
|
||||
@@ -714,11 +716,17 @@ public:
|
||||
* @param[in] aOtherMessage The other message to compare with.
|
||||
* @param[in] aOtherOffset Byte offset within @p aOtherMessage to read from for the comparison.
|
||||
* @param[in] aLength Number of bytes to compare.
|
||||
* @param[in] aMatcher A `ByteMatcher` function pointer to match the bytes. If `nullptr` then bytes are
|
||||
* directly compared.
|
||||
*
|
||||
* @returns TRUE if there are enough bytes available in both messages and they all match. FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool CompareBytes(uint16_t aOffset, const Message &aOtherMessage, uint16_t aOtherOffset, uint16_t aLength) const;
|
||||
bool CompareBytes(uint16_t aOffset,
|
||||
const Message &aOtherMessage,
|
||||
uint16_t aOtherOffset,
|
||||
uint16_t aLength,
|
||||
ByteMatcher aMatcher = nullptr) const;
|
||||
|
||||
/**
|
||||
* This method compares the bytes in the message at a given offset with an object.
|
||||
|
||||
@@ -368,7 +368,7 @@ Error Name::CompareLabel(const Message &aMessage, uint16_t &aOffset, const char
|
||||
LabelIterator iterator(aMessage, aOffset);
|
||||
|
||||
SuccessOrExit(error = iterator.GetNextLabel());
|
||||
VerifyOrExit(iterator.CompareLabel(aLabel, /* aIsSingleLabel */ true), error = kErrorNotFound);
|
||||
VerifyOrExit(iterator.CompareLabel(aLabel, kIsSingleLabel), error = kErrorNotFound);
|
||||
aOffset = iterator.mNextLabelOffset;
|
||||
|
||||
exit:
|
||||
@@ -394,7 +394,7 @@ Error Name::CompareName(const Message &aMessage, uint16_t &aOffset, const char *
|
||||
switch (error)
|
||||
{
|
||||
case kErrorNone:
|
||||
if (matches && !iterator.CompareLabel(aName, /* aIsSingleLabel */ false))
|
||||
if (matches && !iterator.CompareLabel(aName, !kIsSingleLabel))
|
||||
{
|
||||
matches = false;
|
||||
}
|
||||
@@ -564,6 +564,11 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Name::LabelIterator::CaseInsensitiveMatch(uint8_t aFirst, uint8_t aSecond)
|
||||
{
|
||||
return ToLowercase(static_cast<char>(aFirst)) == ToLowercase(static_cast<char>(aSecond));
|
||||
}
|
||||
|
||||
bool Name::LabelIterator::CompareLabel(const char *&aName, bool aIsSingleLabel) const
|
||||
{
|
||||
// This method compares the current label in the iterator with the
|
||||
@@ -577,7 +582,7 @@ bool Name::LabelIterator::CompareLabel(const char *&aName, bool aIsSingleLabel)
|
||||
bool matches = false;
|
||||
|
||||
VerifyOrExit(StringLength(aName, mLabelLength) == mLabelLength);
|
||||
matches = mMessage.CompareBytes(mLabelStartOffset, aName, mLabelLength);
|
||||
matches = mMessage.CompareBytes(mLabelStartOffset, aName, mLabelLength, CaseInsensitiveMatch);
|
||||
|
||||
VerifyOrExit(matches);
|
||||
|
||||
@@ -606,7 +611,7 @@ bool Name::LabelIterator::CompareLabel(const LabelIterator &aOtherIterator) cons
|
||||
|
||||
return (mLabelLength == aOtherIterator.mLabelLength) &&
|
||||
mMessage.CompareBytes(mLabelStartOffset, aOtherIterator.mMessage, aOtherIterator.mLabelStartOffset,
|
||||
mLabelLength);
|
||||
mLabelLength, CaseInsensitiveMatch);
|
||||
}
|
||||
|
||||
Error Name::LabelIterator::AppendLabel(Message &aMessage) const
|
||||
@@ -626,30 +631,53 @@ exit:
|
||||
|
||||
bool Name::IsSubDomainOf(const char *aName, const char *aDomain)
|
||||
{
|
||||
bool match = false;
|
||||
uint16_t nameLength = StringLength(aName, kMaxNameLength);
|
||||
uint16_t domainLength = StringLength(aDomain, kMaxNameLength);
|
||||
bool match = false;
|
||||
bool nameEndsWithDot = false;
|
||||
bool domainEndsWithDot = false;
|
||||
uint16_t nameLength = StringLength(aName, kMaxNameLength);
|
||||
uint16_t domainLength = StringLength(aDomain, kMaxNameLength);
|
||||
|
||||
if (nameLength > 0 && aName[nameLength - 1] == kLabelSeperatorChar)
|
||||
{
|
||||
nameEndsWithDot = true;
|
||||
--nameLength;
|
||||
}
|
||||
|
||||
if (domainLength > 0 && aDomain[domainLength - 1] == kLabelSeperatorChar)
|
||||
{
|
||||
domainEndsWithDot = true;
|
||||
--domainLength;
|
||||
}
|
||||
|
||||
VerifyOrExit(nameLength >= domainLength);
|
||||
|
||||
aName += nameLength - domainLength;
|
||||
|
||||
if (nameLength > domainLength)
|
||||
{
|
||||
VerifyOrExit(aName[-1] == kLabelSeperatorChar);
|
||||
}
|
||||
VerifyOrExit(memcmp(aName, aDomain, domainLength) == 0);
|
||||
|
||||
match = true;
|
||||
// This method allows either `aName` or `aDomain` to include or
|
||||
// exclude the last `.` character. If both include it or if both
|
||||
// do not, we do a full comparison using `StringMatch()`.
|
||||
// Otherwise (i.e., when one includes and the other one does not)
|
||||
// we use `StringStartWith()` to allow the extra `.` character.
|
||||
|
||||
if (nameEndsWithDot == domainEndsWithDot)
|
||||
{
|
||||
match = StringMatch(aName, aDomain, kStringCaseInsensitiveMatch);
|
||||
}
|
||||
else if (nameEndsWithDot)
|
||||
{
|
||||
// `aName` ends with dot, but `aDomain` does not.
|
||||
match = StringStartsWith(aName, aDomain, kStringCaseInsensitiveMatch);
|
||||
}
|
||||
else
|
||||
{
|
||||
// `aDomain` ends with dot, but `aName` does not.
|
||||
match = StringStartsWith(aDomain, aName, kStringCaseInsensitiveMatch);
|
||||
}
|
||||
|
||||
exit:
|
||||
return match;
|
||||
|
||||
+16
-12
@@ -872,7 +872,7 @@ public:
|
||||
* This static method compares a single name label from a message with a given label string.
|
||||
*
|
||||
* This method can be used to compare labels one by one. It checks whether the label read from @p aMessage matches
|
||||
* @p aLabel string.
|
||||
* @p aLabel string (case-insensitive comparison).
|
||||
*
|
||||
* Unlike `CompareName()` which requires the labels in the the name string to contain no dot '.' character, this
|
||||
* method allows @p aLabel to include any character.
|
||||
@@ -883,7 +883,7 @@ public:
|
||||
* On exit and only when label is successfully read and does match @p aLabel,
|
||||
* @p aOffset is updated to point to the start of the next label.
|
||||
* @param[in] aLabel A pointer to a null terminated string containing the label to compare with.
|
||||
|
||||
*
|
||||
* @retval kErrorNone The label from @p aMessage matches @p aLabel. @p aOffset is updated.
|
||||
* @retval kErrorNotFound The label from @p aMessage does not match @p aLabel (note that @p aOffset is not
|
||||
* updated in this case).
|
||||
@@ -895,9 +895,10 @@ public:
|
||||
/**
|
||||
* This static method parses and compares a full name from a message with a given name.
|
||||
*
|
||||
* This method checks whether the encoded name in a message matches a given name string. It checks the name in
|
||||
* the message in place and handles compressed names. If the name read from the message does not match @p aName, it
|
||||
* returns `kErrorNotFound`. `kErrorNone` indicates that the name matches @p aName.
|
||||
* This method checks whether the encoded name in a message matches a given name string (using case-insensitive
|
||||
* comparison). It checks the name in the message in place and handles compressed names. If the name read from the
|
||||
* message does not match @p aName, it returns `kErrorNotFound`. `kErrorNone` indicates that the name matches
|
||||
* @p aName.
|
||||
*
|
||||
* The @p aName must follow "<label1>.<label2>.<label3>", i.e., a sequence of labels separated by dot '.' char.
|
||||
* E.g., "example.com", "example.com." (same as previous one), "local.", "default.service.arpa", "." or "" (root).
|
||||
@@ -922,9 +923,10 @@ public:
|
||||
/**
|
||||
* This static method parses and compares a full name from a message with a name from another message.
|
||||
*
|
||||
* This method checks whether the encoded name in @p aMessage matches the name from @p aMessage2. It compares the
|
||||
* names in both messages in place and handles compressed names. Note that this method works correctly even when
|
||||
* the same message instance is used for both @p aMessage and @p aMessage2 (e.g., at different offsets).
|
||||
* This method checks whether the encoded name in @p aMessage matches the name from @p aMessage2 (using
|
||||
* case-insensitive comparison). It compares the names in both messages in place and handles compressed names. Note
|
||||
* that this method works correctly even when the same message instance is used for both @p aMessage and
|
||||
* @p aMessage2 (e.g., at different offsets).
|
||||
*
|
||||
* Only the name in @p aMessage is fully parsed and checked for parse errors. This method assumes that the name in
|
||||
* @p aMessage2 was previously parsed and validated before calling this method (if there is a parse error in
|
||||
@@ -952,7 +954,8 @@ public:
|
||||
static Error CompareName(const Message &aMessage, uint16_t &aOffset, const Message &aMessage2, uint16_t aOffset2);
|
||||
|
||||
/**
|
||||
* This static method parses and compares a full name from a message with a given name.
|
||||
* This static method parses and compares a full name from a message with a given name (using case-insensitive
|
||||
* comparison).
|
||||
*
|
||||
* If @p aName is empty (not specified), then any name in @p aMessage is considered a match to it.
|
||||
*
|
||||
@@ -985,8 +988,6 @@ public:
|
||||
static bool IsSubDomainOf(const char *aName, const char *aDomain);
|
||||
|
||||
private:
|
||||
static constexpr char kNullChar = '\0';
|
||||
|
||||
// The first 2 bits of the encoded label specifies label type.
|
||||
//
|
||||
// - Value 00 indicates normal text label (lower 6-bits indicates the label length).
|
||||
@@ -1002,6 +1003,8 @@ private:
|
||||
static constexpr uint16_t kPointerLabelTypeUint16 = 0xc000; // Pointer label type mask (first 2 bits).
|
||||
static constexpr uint16_t kPointerLabelOffsetMask = 0x3fff; // Mask for offset in a pointer label (lower 14 bits).
|
||||
|
||||
static constexpr bool kIsSingleLabel = true; // Used in `LabelIterator::CompareLable()`.
|
||||
|
||||
struct LabelIterator
|
||||
{
|
||||
static constexpr uint16_t kUnsetNameEndOffset = 0; // Special value indicating `mNameEndOffset` is not yet set.
|
||||
@@ -1020,6 +1023,8 @@ private:
|
||||
bool CompareLabel(const LabelIterator &aOtherIterator) const;
|
||||
Error AppendLabel(Message &aMessage) const;
|
||||
|
||||
static bool CaseInsensitiveMatch(uint8_t aFirst, uint8_t aSecond);
|
||||
|
||||
const Message &mMessage; // Message to read labels from.
|
||||
uint16_t mLabelStartOffset; // Offset in `mMessage` to the first char of current label text.
|
||||
uint8_t mLabelLength; // Length of current label (number of chars).
|
||||
@@ -1182,7 +1187,6 @@ private:
|
||||
|
||||
static constexpr uint8_t kMaxKeyValueEncodedSize = 255;
|
||||
static constexpr char kKeyValueSeparator = '=';
|
||||
static constexpr char kNullChar = '\0';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+72
-29
@@ -64,6 +64,8 @@ void TestDnsName(void)
|
||||
char label[Dns::Name::kMaxLabelSize];
|
||||
uint8_t labelLength;
|
||||
char name[Dns::Name::kMaxNameSize];
|
||||
const char * subDomain;
|
||||
const char * domain;
|
||||
|
||||
static const uint8_t kEncodedName1[] = {7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0};
|
||||
static const uint8_t kEncodedName2[] = {3, 'f', 'o', 'o', 1, 'a', 2, 'b', 'b', 3, 'e', 'd', 'u', 0};
|
||||
@@ -147,39 +149,65 @@ void TestDnsName(void)
|
||||
printf("----------------------------------------------------------------\n");
|
||||
printf("Verify domain name match:\n");
|
||||
|
||||
{
|
||||
const char *subDomain;
|
||||
const char *domain;
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "local.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "local.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "local.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "local.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "local";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "local";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "local";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "local";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "default.service.arpa.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "default.service.arpa.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "service.arpa.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "service.arpa.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
// Verify it doesn't match a portion of a label.
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "vice.arpa.";
|
||||
VerifyOrQuit(!Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
// Verify it doesn't match a portion of a label.
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "vice.arpa.";
|
||||
VerifyOrQuit(!Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
}
|
||||
// Validate case does not matter
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "LOCAL.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "LOCAL.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local.";
|
||||
domain = "LOCAL";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.local";
|
||||
domain = "LOCAL";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.Default.Service.ARPA.";
|
||||
domain = "dEFAULT.Service.arpa.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
subDomain = "my-service._ipps._tcp.default.service.ARpa.";
|
||||
domain = "SeRvIcE.arPA.";
|
||||
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
// Verify it doesn't match a portion of a label.
|
||||
subDomain = "my-service._ipps._tcp.default.service.arpa.";
|
||||
domain = "Vice.arpa.";
|
||||
VerifyOrQuit(!Dns::Name::IsSubDomainOf(subDomain, domain));
|
||||
|
||||
printf("----------------------------------------------------------------\n");
|
||||
printf("Append names, check encoded bytes, parse name and read labels:\n");
|
||||
@@ -247,18 +275,33 @@ void TestDnsName(void)
|
||||
{
|
||||
uint16_t startOffset = offset;
|
||||
|
||||
SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, test.mLabels[index]));
|
||||
strcpy(label, test.mLabels[index]);
|
||||
|
||||
SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, label));
|
||||
VerifyOrQuit(offset != startOffset, "Name::CompareLabel() did not change offset");
|
||||
|
||||
VerifyOrQuit(Dns::Name::CompareLabel(*message, startOffset, kBadLabel) == kErrorNotFound,
|
||||
offset = startOffset;
|
||||
VerifyOrQuit(Dns::Name::CompareLabel(*message, offset, kBadLabel) == kErrorNotFound,
|
||||
"Name::CompareLabel() did not fail with incorrect label");
|
||||
|
||||
StringConvertToUppercase(label);
|
||||
|
||||
offset = startOffset;
|
||||
SuccessOrQuit(Dns::Name::CompareLabel(*message, offset, label));
|
||||
}
|
||||
|
||||
// Compare the whole name.
|
||||
strcpy(name, test.mExpectedReadName);
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(Dns::Name::CompareName(*message, offset, test.mExpectedReadName));
|
||||
SuccessOrQuit(Dns::Name::CompareName(*message, offset, name));
|
||||
VerifyOrQuit(offset == len, "Name::CompareName() returned incorrect offset");
|
||||
|
||||
StringConvertToUppercase(name);
|
||||
|
||||
offset = 0;
|
||||
SuccessOrQuit(Dns::Name::CompareName(*message, offset, name));
|
||||
|
||||
offset = 0;
|
||||
VerifyOrQuit(Dns::Name::CompareName(*message, offset, kBadName) == kErrorNotFound,
|
||||
"Name::CompareName() did not fail with incorrect name");
|
||||
|
||||
Reference in New Issue
Block a user