[mdns] add support for legacy unicast response feature (#10053)

Signed-off-by: Cristib05 <[email protected]>
This commit is contained in:
Cristian Bulacu
2024-06-07 14:01:50 -07:00
committed by GitHub
parent 3873c6fcd5
commit 9cc1cd9e58
3 changed files with 391 additions and 82 deletions
+105 -38
View File
@@ -391,12 +391,13 @@ bool Core::NameMatch(const Heap::String &aFirst, const Heap::String &aSecond)
return !aSecond.IsNull() && NameMatch(aFirst, aSecond.AsCString());
}
void Core::UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection)
void Core::UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection, bool aIsLegacyUnicast)
{
// Do not set the cache-flush flag is the record is
// appended in Authority Section in a probe message.
// Do not set the cache-flush flag if the record is
// appended in Authority Section in a probe message,
// or is intended for a Legacy Unicast response.
if (aSection != kAuthoritySection)
if (aSection != kAuthoritySection && !aIsLegacyUnicast)
{
aResourceRecord.SetClass(aResourceRecord.GetClass() | kClassCacheFlushFlag);
}
@@ -579,6 +580,11 @@ void Core::RecordInfo::UpdateProperty(AddressArray &aAddrProperty, const Ip6::Ad
}
}
uint32_t Core::RecordInfo::GetTtl(bool aIsLegacyUnicast) const
{
return aIsLegacyUnicast ? Min(kMaxLegacyUnicastTtl, mTtl) : mTtl;
}
void Core::RecordInfo::UpdateTtl(uint32_t aTtl) { return UpdateProperty(mTtl, aTtl); }
void Core::RecordInfo::StartAnnouncing(void)
@@ -596,7 +602,7 @@ void Core::RecordInfo::ScheduleAnswer(const AnswerInfo &aInfo)
{
VerifyOrExit(CanAnswer());
if (aInfo.mUnicastResponse)
if (aInfo.mUnicastResponse || aInfo.mLegacyUnicastResponse)
{
mUnicastAnswerPending = true;
ExitNow();
@@ -647,6 +653,7 @@ bool Core::RecordInfo::ShouldAppendTo(TxMessage &aResponse, TimeMilli aNow) cons
break;
case TxMessage::kUnicastResponse:
case TxMessage::kLegacyUnicastResponse:
shouldAppend = mUnicastAnswerPending;
break;
@@ -693,6 +700,7 @@ void Core::RecordInfo::UpdateStateAfterAnswer(const TxMessage &aResponse)
break;
case TxMessage::kUnicastResponse:
case TxMessage::kLegacyUnicastResponse:
VerifyOrExit(IsAppended());
VerifyOrExit(mAppendSection == kAnswerSection);
mUnicastAnswerPending = false;
@@ -765,6 +773,7 @@ void Core::RecordInfo::MarkAsAppended(TxMessage &aTxMessage, Section aSection)
break;
case TxMessage::kUnicastResponse:
case TxMessage::kLegacyUnicastResponse:
mAppendState = kAppendedInUnicastMsg;
break;
@@ -1229,7 +1238,6 @@ template <typename EntryType> void Core::Entry::HandleTimer(EntryTimerContext &a
case kRemoving:
ExitNow();
}
thisAsEntryType->DetermineNextFireTime();
exit:
@@ -1258,6 +1266,7 @@ void Core::Entry::AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, Nam
{
Message *message;
ResourceRecord record;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
VerifyOrExit(mKeyRecord.CanAppend());
mKeyRecord.MarkAsAppended(aTxMessage, aSection);
@@ -1270,9 +1279,9 @@ void Core::Entry::AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection, Nam
aNameAppender(*this, aTxMessage, aSection);
record.Init(ResourceRecord::kTypeKey);
record.SetTtl(mKeyRecord.GetTtl());
record.SetLength(mKeyData.GetLength());
UpdateCacheFlushFlagIn(record, aSection);
record.SetTtl(mKeyRecord.GetTtl(isLegacyUnicast));
UpdateCacheFlushFlagIn(record, aSection, isLegacyUnicast);
SuccessOrAssert(message->Append(record));
SuccessOrAssert(message->AppendBytes(mKeyData.GetBytes(), mKeyData.GetLength()));
@@ -1292,10 +1301,11 @@ void Core::Entry::AppendNsecRecordTo(TxMessage &aTxMessage,
NsecRecord nsec;
NsecRecord::TypeBitMap bitmap;
uint16_t offset;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
nsec.Init();
nsec.SetTtl(kNsecTtl);
UpdateCacheFlushFlagIn(nsec, aSection);
nsec.SetTtl(isLegacyUnicast ? kLegacyUnicastNsecTtl : kNsecTtl);
UpdateCacheFlushFlagIn(nsec, aSection, isLegacyUnicast);
bitmap.Clear();
@@ -1606,6 +1616,7 @@ exit:
void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSection)
{
Message *message;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
VerifyOrExit(mAddrRecord.CanAppend());
mAddrRecord.MarkAsAppended(aTxMessage, aSection);
@@ -1617,9 +1628,9 @@ void Core::HostEntry::AppendAddressRecordsTo(TxMessage &aTxMessage, Section aSec
AaaaRecord aaaaRecord;
aaaaRecord.Init();
aaaaRecord.SetTtl(mAddrRecord.GetTtl());
aaaaRecord.SetAddress(address);
UpdateCacheFlushFlagIn(aaaaRecord, aSection);
aaaaRecord.SetTtl(mAddrRecord.GetTtl(isLegacyUnicast));
UpdateCacheFlushFlagIn(aaaaRecord, aSection, isLegacyUnicast);
AppendNameTo(aTxMessage, aSection);
SuccessOrAssert(message->Append(aaaaRecord));
@@ -2383,6 +2394,7 @@ void Core::ServiceEntry::AppendSrvRecordTo(TxMessage &aTxMessage, Section aSecti
Message *message;
SrvRecord srv;
uint16_t offset;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
VerifyOrExit(mSrvRecord.CanAppend());
mSrvRecord.MarkAsAppended(aTxMessage, aSection);
@@ -2390,13 +2402,17 @@ void Core::ServiceEntry::AppendSrvRecordTo(TxMessage &aTxMessage, Section aSecti
message = &aTxMessage.SelectMessageFor(aSection);
srv.Init();
srv.SetTtl(mSrvRecord.GetTtl());
srv.SetPriority(mPriority);
srv.SetWeight(mWeight);
srv.SetPort(mPort);
UpdateCacheFlushFlagIn(srv, aSection);
srv.SetTtl(mSrvRecord.GetTtl(isLegacyUnicast));
UpdateCacheFlushFlagIn(srv, aSection, isLegacyUnicast);
// RFC6762, Section 18.14 Name Compression:
// In legacy unicast responses generated to answer legacy queries, name
// compression MUST NOT be performed on SRV records.
AppendServiceNameTo(aTxMessage, aSection, /* aPerformNameCompression */ !isLegacyUnicast);
AppendServiceNameTo(aTxMessage, aSection);
offset = message->GetLength();
SuccessOrAssert(message->Append(srv));
AppendHostNameTo(aTxMessage, aSection);
@@ -2412,6 +2428,7 @@ void Core::ServiceEntry::AppendTxtRecordTo(TxMessage &aTxMessage, Section aSecti
{
Message *message;
TxtRecord txt;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
VerifyOrExit(mTxtRecord.CanAppend());
mTxtRecord.MarkAsAppended(aTxMessage, aSection);
@@ -2419,9 +2436,9 @@ void Core::ServiceEntry::AppendTxtRecordTo(TxMessage &aTxMessage, Section aSecti
message = &aTxMessage.SelectMessageFor(aSection);
txt.Init();
txt.SetTtl(mTxtRecord.GetTtl());
txt.SetLength(mTxtData.GetLength());
UpdateCacheFlushFlagIn(txt, aSection);
txt.SetTtl(mTxtRecord.GetTtl(isLegacyUnicast));
UpdateCacheFlushFlagIn(txt, aSection, isLegacyUnicast);
AppendServiceNameTo(aTxMessage, aSection);
SuccessOrAssert(message->Append(txt));
@@ -2442,6 +2459,7 @@ void Core::ServiceEntry::AppendPtrRecordTo(TxMessage &aTxMessage, Section aSecti
RecordInfo &ptrRecord = (aSubType == nullptr) ? mPtrRecord : aSubType->mPtrRecord;
PtrRecord ptr;
uint16_t offset;
bool isLegacyUnicast = (aTxMessage.GetType() == TxMessage::kLegacyUnicastResponse);
VerifyOrExit(ptrRecord.CanAppend());
ptrRecord.MarkAsAppended(aTxMessage, aSection);
@@ -2449,7 +2467,7 @@ void Core::ServiceEntry::AppendPtrRecordTo(TxMessage &aTxMessage, Section aSecti
message = &aTxMessage.SelectMessageFor(aSection);
ptr.Init();
ptr.SetTtl(ptrRecord.GetTtl());
ptr.SetTtl(ptrRecord.GetTtl(isLegacyUnicast));
if (aSubType == nullptr)
{
@@ -2506,12 +2524,22 @@ void Core::ServiceEntry::AppendEntryName(Entry &aEntry, TxMessage &aTxMessage, S
static_cast<ServiceEntry &>(aEntry).AppendServiceNameTo(aTxMessage, aSection);
}
void Core::ServiceEntry::AppendServiceNameTo(TxMessage &aTxMessage, Section aSection)
void Core::ServiceEntry::AppendServiceNameTo(TxMessage &aTxMessage, Section aSection, bool aPerformNameCompression)
{
AppendOutcome outcome;
outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), mServiceNameOffset);
VerifyOrExit(outcome != kAppendedFullNameAsCompressed);
if (!aPerformNameCompression)
{
uint16_t compressOffset = kUnspecifiedOffset;
outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), compressOffset);
VerifyOrExit(outcome == kAppendedLabels);
}
else
{
outcome = aTxMessage.AppendLabel(aSection, mServiceInstance.AsCString(), mServiceNameOffset);
VerifyOrExit(outcome != kAppendedFullNameAsCompressed);
}
AppendServiceTypeTo(aTxMessage, aSection);
@@ -2775,7 +2803,14 @@ void Core::ServiceType::AppendPtrRecordTo(TxMessage &aResponse, uint16_t aServic
message = &aResponse.SelectMessageFor(kAnswerSection);
ptr.Init();
ptr.SetTtl(mServicesPtr.GetTtl());
if (aResponse.GetType() == TxMessage::kLegacyUnicastResponse)
{
ptr.SetTtl(Min(Core::RecordInfo::kMaxLegacyUnicastTtl, mServicesPtr.GetTtl()));
}
else
{
ptr.SetTtl(mServicesPtr.GetTtl());
}
aResponse.AppendServicesDnssdName(kAnswerSection);
offset = message->GetLength();
@@ -2792,19 +2827,19 @@ exit:
//----------------------------------------------------------------------------------------------------------------------
// Core::TxMessage
Core::TxMessage::TxMessage(Instance &aInstance, Type aType)
Core::TxMessage::TxMessage(Instance &aInstance, Type aType, uint16_t aQueryId)
: InstanceLocator(aInstance)
{
Init(aType);
Init(aType, aQueryId);
}
Core::TxMessage::TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest)
: TxMessage(aInstance, aType)
Core::TxMessage::TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest, uint16_t aQueryId)
: TxMessage(aInstance, aType, aQueryId)
{
mUnicastDest = aUnicastDest;
}
void Core::TxMessage::Init(Type aType)
void Core::TxMessage::Init(Type aType, uint16_t aMessageId)
{
Header header;
@@ -2837,7 +2872,9 @@ void Core::TxMessage::Init(Type aType)
break;
case kMulticastResponse:
case kUnicastResponse:
case kLegacyUnicastResponse:
header.SetType(Header::kTypeResponse);
header.SetMessageId(aMessageId);
break;
}
@@ -2864,9 +2901,9 @@ Message &Core::TxMessage::SelectMessageFor(Section aSection)
mainSection = kQuestionSection;
extraSection = kAnswerSection;
break;
case kMulticastResponse:
case kLegacyUnicastResponse:
case kUnicastResponse:
case kMulticastResponse:
break;
}
@@ -3022,6 +3059,16 @@ exit:
return;
}
void Core::TxMessage::AddQuestionFrom(const Message &aMessage)
{
uint16_t offset = sizeof(Header);
IgnoreError(Name::ParseName(aMessage, offset));
offset += sizeof(ot::Dns::Question);
SuccessOrAssert(mMsgPtr->AppendBytesFromMessage(aMessage, sizeof(Header), offset - sizeof(Header)));
IncrementRecordCount(kQuestionSection);
}
void Core::TxMessage::SaveOffset(uint16_t &aCompressOffset, const Message &aMessage, Section aSection)
{
// Saves the current message offset in `aCompressOffset` for name
@@ -3147,6 +3194,7 @@ void Core::TxMessage::Send(void)
break;
case kUnicastResponse:
case kLegacyUnicastResponse:
otPlatMdnsSendUnicast(&GetInstance(), mMsgPtr.Release(), &mUnicastDest);
break;
}
@@ -3215,6 +3263,8 @@ void Core::TxMessage::Reinit(void)
// compress offset since the host name should not be used
// in any other query question.
break;
case kLegacyUnicastResponse:
break;
}
}
@@ -3297,11 +3347,12 @@ Error Core::RxMessage::Init(Instance &aInstance,
if (aSenderAddress.mPort != kUdpPort)
{
if (mIsQuery)
// Simple DNS resolver does not allow more than one question in a query message
if (mIsQuery && header.GetQuestionCount() == 1)
{
// Section 6.7 Legacy Unicast
LogInfo("We do not yet support legacy unicast message (source port not matching mDNS port)");
ExitNow(error = kErrorNotCapable);
mIsLegacyUnicast = true;
mQueryId = header.GetMessageId();
}
else
{
@@ -3427,13 +3478,18 @@ Core::RxMessage::ProcessOutcome Core::RxMessage::ProcessQuery(bool aShouldProces
{
canAnswer = true;
if (question.mUnicastResponse)
if (question.mUnicastResponse || mIsLegacyUnicast)
{
needUnicastResponse = true;
}
}
}
if (mIsLegacyUnicast)
{
shouldDelay = false;
}
VerifyOrExit(canAnswer);
if (mTruncated && !aShouldProcessTruncated)
@@ -3569,10 +3625,11 @@ void Core::RxMessage::AnswerQuestion(const Question &aQuestion, TimeMilli aAnswe
VerifyOrExit(aQuestion.mCanAnswer);
answerInfo.mQuestionRrType = aQuestion.mRrType;
answerInfo.mAnswerTime = aAnswerTime;
answerInfo.mIsProbe = aQuestion.mIsProbe;
answerInfo.mUnicastResponse = aQuestion.mUnicastResponse;
answerInfo.mQuestionRrType = aQuestion.mRrType;
answerInfo.mAnswerTime = aAnswerTime;
answerInfo.mIsProbe = aQuestion.mIsProbe;
answerInfo.mUnicastResponse = aQuestion.mUnicastResponse;
answerInfo.mLegacyUnicastResponse = mIsLegacyUnicast;
if (aQuestion.mIsForAllServicesDnssd)
{
@@ -3790,7 +3847,17 @@ exit:
void Core::RxMessage::SendUnicastResponse(const AddressInfo &aUnicastDest)
{
TxMessage response(GetInstance(), TxMessage::kUnicastResponse, aUnicastDest);
TxMessage response(GetInstance(),
mIsLegacyUnicast ? TxMessage::kLegacyUnicastResponse : TxMessage::kUnicastResponse, aUnicastDest,
mIsLegacyUnicast ? mQueryId : 0);
if (mIsLegacyUnicast)
{
// RFC6762, section 6.7:
// Legacy Unicast Response must repeat the question
response.AddQuestionFrom(*mMessagePtr);
}
TimeMilli now = TimerMilli::GetNow();
for (HostEntry &entry : Get<Core>().mHostEntries)
+24 -13
View File
@@ -759,11 +759,12 @@ private:
static constexpr uint32_t kMaxInitialQueryDelay = 120; // msec
static constexpr uint32_t kRandomDelayReuseInterval = 2; // msec
static constexpr uint32_t kUnspecifiedTtl = 0;
static constexpr uint32_t kDefaultTtl = 120;
static constexpr uint32_t kDefaultKeyTtl = kDefaultTtl;
static constexpr uint32_t kNsecTtl = 4500;
static constexpr uint32_t kServicesPtrTtl = 4500;
static constexpr uint32_t kUnspecifiedTtl = 0;
static constexpr uint32_t kDefaultTtl = 120;
static constexpr uint32_t kDefaultKeyTtl = kDefaultTtl;
static constexpr uint32_t kLegacyUnicastNsecTtl = 10;
static constexpr uint32_t kNsecTtl = 4500;
static constexpr uint32_t kServicesPtrTtl = 4500;
static constexpr uint16_t kClassQuestionUnicastFlag = (1U << 15);
static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
@@ -858,6 +859,7 @@ private:
TimeMilli mAnswerTime;
bool mIsProbe;
bool mUnicastResponse;
bool mLegacyUnicastResponse;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -896,16 +898,19 @@ private:
public:
// Keeps track of record state and timings.
static constexpr uint32_t kMaxLegacyUnicastTtl = 10; // seconds
RecordInfo(void) { Clear(); }
bool IsPresent(void) const { return mIsPresent; }
uint32_t GetTtl(void) const { return mTtl; }
bool IsPresent(void) const { return mIsPresent; }
template <typename UintType> void UpdateProperty(UintType &aProperty, UintType aValue);
void UpdateProperty(AddressArray &aAddrProperty, const Ip6::Address *aAddrs, uint16_t aNumAddrs);
void UpdateProperty(Heap::String &aStringProperty, const char *aString);
void UpdateProperty(Heap::Data &aDataProperty, const uint8_t *aData, uint16_t aLength);
void UpdateTtl(uint32_t aTtl);
uint32_t GetTtl(bool aIsLegacyUnicast = false) const;
void UpdateTtl(uint32_t aTtl);
void StartAnnouncing(void);
bool ShouldAppendTo(TxMessage &aResponse, TimeMilli aNow) const;
@@ -1162,7 +1167,7 @@ private:
void AppendPtrRecordTo(TxMessage &aTxMessage, Section aSection, SubType *aSubType = nullptr);
void AppendKeyRecordTo(TxMessage &aTxMessage, Section aSection);
void AppendNsecRecordTo(TxMessage &aTxMessage, Section aSection);
void AppendServiceNameTo(TxMessage &TxMessage, Section aSection);
void AppendServiceNameTo(TxMessage &TxMessage, Section aSection, bool aPerformNameCompression = true);
void AppendServiceTypeTo(TxMessage &aTxMessage, Section aSection);
void AppendSubServiceTypeTo(TxMessage &aTxMessage, Section aSection);
void AppendSubServiceNameTo(TxMessage &aTxMessage, Section aSection, SubType &aSubType);
@@ -1239,10 +1244,11 @@ private:
kMulticastQuery,
kMulticastResponse,
kUnicastResponse,
kLegacyUnicastResponse,
};
TxMessage(Instance &aInstance, Type aType);
TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest);
TxMessage(Instance &aInstance, Type aType, uint16_t aQueryId = 0);
TxMessage(Instance &aInstance, Type aType, const AddressInfo &aUnicastDest, uint16_t aQueryId = 0);
Type GetType(void) const { return mType; }
Message &SelectMessageFor(Section aSection);
AppendOutcome AppendLabel(Section aSection, const char *aLabel, uint16_t &aCompressOffset);
@@ -1250,6 +1256,7 @@ private:
void AppendServiceType(Section aSection, const char *aServiceType, uint16_t &aCompressOffset);
void AppendDomainName(Section aSection);
void AppendServicesDnssdName(Section aSection);
void AddQuestionFrom(const Message &aMessage);
void IncrementRecordCount(Section aSection) { mRecordCounts.Increment(aSection); }
void CheckSizeLimitToPrepareAgain(bool &aPrepareAgain);
void SaveCurrentState(void);
@@ -1259,7 +1266,7 @@ private:
private:
static constexpr bool kIsSingleLabel = true;
void Init(Type aType);
void Init(Type aType, uint16_t aMessageId = 0);
void Reinit(void);
bool IsOverSizeLimit(void) const;
AppendOutcome AppendLabels(Section aSection,
@@ -1382,8 +1389,10 @@ private:
AddressInfo mSenderAddress;
RecordCounts mRecordCounts;
uint16_t mStartOffset[kNumSections];
uint16_t mQueryId;
bool mIsQuery : 1;
bool mIsUnicast : 1;
bool mIsLegacyUnicast : 1;
bool mTruncated : 1;
bool mIsSelfOriginating : 1;
};
@@ -1984,7 +1993,9 @@ private:
static uint32_t DetermineTtl(uint32_t aTtl, uint32_t aDefaultTtl);
static bool NameMatch(const Heap::String &aHeapString, const char *aName);
static bool NameMatch(const Heap::String &aFirst, const Heap::String &aSecond);
static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord, Section aSection);
static void UpdateCacheFlushFlagIn(ResourceRecord &aResourceRecord,
Section aSection,
bool aIsLegacyUnicast = false);
static void UpdateRecordLengthInMessage(ResourceRecord &aRecord, Message &aMessage, uint16_t aOffset);
static void UpdateCompressOffset(uint16_t &aOffset, uint16_t aNewOffse);
static bool QuestionMatches(uint16_t aQuestionRrType, uint16_t aRrType);
+262 -31
View File
@@ -62,17 +62,20 @@ namespace Multicast {
//---------------------------------------------------------------------------------------------------------------------
// Constants
static constexpr uint16_t kClassQueryUnicastFlag = (1U << 15);
static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
static constexpr uint16_t kClassMask = 0x7fff;
static constexpr uint16_t kStringSize = 300;
static constexpr uint16_t kMaxDataSize = 400;
static constexpr uint16_t kNumAnnounces = 3;
static constexpr uint16_t kNumInitalQueries = 3;
static constexpr uint16_t kNumRefreshQueries = 4;
static constexpr bool kCacheFlush = true;
static constexpr uint16_t kMdnsPort = 5353;
static constexpr uint32_t kInfraIfIndex = 1;
static constexpr uint16_t kClassQueryUnicastFlag = (1U << 15);
static constexpr uint16_t kClassCacheFlushFlag = (1U << 15);
static constexpr uint16_t kClassMask = 0x7fff;
static constexpr uint16_t kStringSize = 300;
static constexpr uint16_t kMaxDataSize = 400;
static constexpr uint16_t kNumAnnounces = 3;
static constexpr uint16_t kNumInitalQueries = 3;
static constexpr uint16_t kNumRefreshQueries = 4;
static constexpr bool kCacheFlush = true;
static constexpr uint16_t kMdnsPort = 5353;
static constexpr uint16_t kEphemeralPort = 49152;
static constexpr uint16_t kLegacyUnicastMessageId = 1;
static constexpr uint16_t kMaxLegacyUnicastTtl = 10;
static constexpr uint32_t kInfraIfIndex = 1;
static const char kDeviceIp6Address[] = "fd01::1";
@@ -209,6 +212,7 @@ enum TtlCheckMode : uint8_t
{
kZeroTtl,
kNonZeroTtl,
kLegacyUnicastTtl,
};
enum Section : uint8_t
@@ -372,6 +376,9 @@ struct DnsRecord : public Allocatable<DnsRecord>, public LinkedListEntry<DnsReco
VerifyOrExit(mTtl > 0);
break;
case kLegacyUnicastTtl:
VerifyOrQuit(mTtl <= kMaxLegacyUnicastTtl);
break;
}
matches = true;
@@ -571,6 +578,7 @@ enum DnsMessageType : uint8_t
kMulticastQuery,
kMulticastResponse,
kUnicastResponse,
kLegacyUnicastResponse,
};
struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMessage>
@@ -682,9 +690,15 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
VerifyOrQuit(mUnicastDest.mPort == kMdnsPort);
VerifyOrQuit(mUnicastDest.GetAddress() == ip6Address);
}
if (aType == kLegacyUnicastResponse)
{
VerifyOrQuit(mHeader.GetMessageId() == kLegacyUnicastMessageId);
VerifyOrQuit(mUnicastDest.mPort == kEphemeralPort);
}
}
static void DetemineFullNameForKey(const Core::Key &aKey, DnsNameString &aFullName)
static void DetermineFullNameForKey(const Core::Key &aKey, DnsNameString &aFullName)
{
if (aKey.mServiceType != nullptr)
{
@@ -696,6 +710,22 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
}
}
static TtlCheckMode DetermineTtlCheckMode(DnsMessageType aMessageType, bool aIsGoodBye)
{
TtlCheckMode ttlCheck;
if (aMessageType == kLegacyUnicastResponse)
{
ttlCheck = kLegacyUnicastTtl;
}
else
{
ttlCheck = aIsGoodBye ? kZeroTtl : kNonZeroTtl;
}
return ttlCheck;
}
void ValidateAsProbeFor(const Core::Host &aHost, bool aUnicastResponse) const
{
DnsNameString fullName;
@@ -735,7 +765,7 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
VerifyOrQuit(mHeader.GetType() == Header::kTypeQuery);
VerifyOrQuit(!mHeader.IsTruncationFlagSet());
DetemineFullNameForKey(aKey, fullName);
DetermineFullNameForKey(aKey, fullName);
VerifyOrQuit(mQuestions.Contains(fullName, aUnicastResponse));
VerifyOrQuit(mAuthRecords.ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), !kCacheFlush,
@@ -745,6 +775,11 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
void Validate(const Core::Host &aHost, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
{
DnsNameString fullName;
TtlCheckMode ttlCheck;
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
@@ -752,8 +787,8 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
for (uint16_t index = 0; index < aHost.mAddressesLength; index++)
{
VerifyOrQuit(RecordsFor(aSection).ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]), kCacheFlush,
aIsGoodBye ? kZeroTtl : kNonZeroTtl, aHost.mTtl));
VerifyOrQuit(RecordsFor(aSection).ContainsAaaa(fullName, AsCoreType(&aHost.mAddresses[index]),
cacheFlushSet, ttlCheck, aHost.mTtl));
}
if (!aIsGoodBye && (aSection == kInAnswerSection))
@@ -769,7 +804,11 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
{
DnsNameString serviceName;
DnsNameString serviceType;
bool checkNsec = false;
TtlCheckMode ttlCheck;
bool checkNsec = false;
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
@@ -778,22 +817,23 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
if (aCheckFlags & kCheckSrv)
{
VerifyOrQuit(RecordsFor(aSection).ContainsSrv(serviceName, aService, kCacheFlush,
aIsGoodBye ? kZeroTtl : kNonZeroTtl, aService.mTtl));
VerifyOrQuit(
RecordsFor(aSection).ContainsSrv(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
checkNsec = true;
}
if (aCheckFlags & kCheckTxt)
{
VerifyOrQuit(RecordsFor(aSection).ContainsTxt(serviceName, aService, kCacheFlush,
aIsGoodBye ? kZeroTtl : kNonZeroTtl, aService.mTtl));
VerifyOrQuit(
RecordsFor(aSection).ContainsTxt(serviceName, aService, cacheFlushSet, ttlCheck, aService.mTtl));
checkNsec = true;
}
if (aCheckFlags & kCheckPtr)
{
VerifyOrQuit(RecordsFor(aSection).ContainsPtr(serviceType, serviceName, aIsGoodBye ? kZeroTtl : kNonZeroTtl,
aService.mTtl));
VerifyOrQuit(RecordsFor(aSection).ContainsPtr(serviceType, serviceName, ttlCheck, aService.mTtl));
}
if (aCheckFlags & kCheckServicesPtr)
@@ -811,12 +851,17 @@ struct DnsMessage : public Allocatable<DnsMessage>, public LinkedListEntry<DnsMe
void Validate(const Core::Key &aKey, Section aSection, GoodBye aIsGoodBye = kNotGoodBye) const
{
DnsNameString fullName;
TtlCheckMode ttlCheck;
bool cacheFlushSet = (mType == kLegacyUnicastResponse) ? !kCacheFlush : kCacheFlush;
VerifyOrQuit(mHeader.GetType() == Header::kTypeResponse);
DetemineFullNameForKey(aKey, fullName);
VerifyOrQuit(RecordsFor(aSection).ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), kCacheFlush,
aIsGoodBye ? kZeroTtl : kNonZeroTtl, aKey.mTtl));
DetermineFullNameForKey(aKey, fullName);
ttlCheck = DetermineTtlCheckMode(mType, aIsGoodBye);
VerifyOrQuit(RecordsFor(aSection).ContainsKey(fullName, Data(aKey.mKeyData, aKey.mKeyDataLength), cacheFlushSet,
ttlCheck, aKey.mTtl));
if (!aIsGoodBye && (aSection == kInAnswerSection))
{
@@ -1035,7 +1080,7 @@ static void ParseMessage(const Message &aMessage, const Core::AddressInfo *aUnic
}
else
{
msg->mType = kUnicastResponse;
msg->mType = (aUnicastDest->mPort == kEphemeralPort) ? kLegacyUnicastResponse : kUnicastResponse;
msg->mUnicastDest = *aUnicastDest;
}
}
@@ -1045,8 +1090,9 @@ static void ParseMessage(const Message &aMessage, const Core::AddressInfo *aUnic
static void SendQuery(const char *aName,
uint16_t aRecordType,
uint16_t aRecordClass = ResourceRecord::kClassInternet,
bool aTruncated = false)
uint16_t aRecordClass = ResourceRecord::kClassInternet,
bool aTruncated = false,
bool aLegacyUnicastQuery = false)
{
Message *message;
Header header;
@@ -1059,6 +1105,11 @@ static void SendQuery(const char *aName,
header.SetType(Header::kTypeQuery);
header.SetQuestionCount(1);
if (aLegacyUnicastQuery)
{
header.SetMessageId(kLegacyUnicastMessageId);
}
if (aTruncated)
{
header.SetTruncationFlag();
@@ -1069,7 +1120,7 @@ static void SendQuery(const char *aName,
SuccessOrQuit(message->Append(Question(aRecordType, aRecordClass)));
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
senderAddrInfo.mPort = kMdnsPort;
senderAddrInfo.mPort = aLegacyUnicastQuery ? kEphemeralPort : kMdnsPort;
senderAddrInfo.mInfraIfIndex = 0;
Log("Sending query for %s %s", aName, RecordTypeToString(aRecordType));
@@ -1077,7 +1128,11 @@ static void SendQuery(const char *aName,
otPlatMdnsHandleReceive(sInstance, message, /* aIsUnicast */ false, &senderAddrInfo);
}
static void SendQueryForTwo(const char *aName1, uint16_t aRecordType1, const char *aName2, uint16_t aRecordType2)
static void SendQueryForTwo(const char *aName1,
uint16_t aRecordType1,
const char *aName2,
uint16_t aRecordType2,
bool aIsLegacyUnicast = false)
{
// Send query with two questions.
@@ -1099,7 +1154,7 @@ static void SendQueryForTwo(const char *aName1, uint16_t aRecordType1, const cha
SuccessOrQuit(message->Append(Question(aRecordType2, ResourceRecord::kClassInternet)));
SuccessOrQuit(AsCoreType(&senderAddrInfo.mAddress).FromString(kDeviceIp6Address));
senderAddrInfo.mPort = kMdnsPort;
senderAddrInfo.mPort = aIsLegacyUnicast ? kEphemeralPort : kMdnsPort;
senderAddrInfo.mInfraIfIndex = 0;
Log("Sending query for %s %s and %s %s", aName1, RecordTypeToString(aRecordType1), aName2,
@@ -6877,6 +6932,181 @@ void TestPassiveCache(void)
testFreeInstance(sInstance);
}
void TestLegacyUnicastResponse(void)
{
Core *mdns = InitTest();
Core::Host host;
Core::Service service;
const DnsMessage *dnsMsg;
uint16_t heapAllocations;
DnsNameString fullServiceName;
DnsNameString fullServiceType;
DnsNameString hostFullName;
Ip6::Address hostAddresses[2];
Log("-------------------------------------------------------------------------------------------");
Log("TestLegacyUnicastResponse");
AdvanceTime(1);
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(mdns->SetEnabled(true, kInfraIfIndex));
SuccessOrQuit(hostAddresses[0].FromString("fd00::1:aaaa"));
SuccessOrQuit(hostAddresses[1].FromString("fd00::1:bbbb"));
host.mHostName = "host";
host.mAddresses = hostAddresses;
host.mAddressesLength = 2;
host.mTtl = 1500;
hostFullName.Append("%s.local.", host.mHostName);
service.mHostName = host.mHostName;
service.mServiceInstance = "myservice";
service.mServiceType = "_srv._udp";
service.mSubTypeLabels = nullptr;
service.mSubTypeLabelsLength = 0;
service.mTxtData = kTxtData1;
service.mTxtDataLength = sizeof(kTxtData1);
service.mPort = 1234;
service.mPriority = 1;
service.mWeight = 2;
service.mTtl = 1000;
fullServiceName.Append("%s.%s.local.", service.mServiceInstance, service.mServiceType);
fullServiceType.Append("%s.local.", service.mServiceType);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
sDnsMessages.Clear();
for (RegCallback &regCallbck : sRegCallbacks)
{
regCallbck.Reset();
}
SuccessOrQuit(mdns->RegisterHost(host, 0, HandleSuccessCallback));
SuccessOrQuit(mdns->RegisterService(service, 1, HandleSuccessCallback));
AdvanceTime(10 * 1000);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query with two questions (SRV for service1 and AAAA for host). Validate that no response is sent");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQueryForTwo(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, hostFullName.AsCString(),
ResourceRecord::kTypeAaaa, /* aIsLegacyUnicast */ true);
AdvanceTime(200);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg == nullptr);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query for SRV record and validate the response");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeSrv, ResourceRecord::kClassInternet,
/* aTruncated */ false,
/* aLegacyUnicastQuery */ true);
AdvanceTime(1000);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg != nullptr);
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 3);
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv);
dnsMsg->Validate(host, kInAdditionalSection);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query for TXT record and validate the response");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeTxt, ResourceRecord::kClassInternet,
/* aTruncated */ false,
/* aLegacyUnicastQuery */ true);
AdvanceTime(1000);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg != nullptr);
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 1);
dnsMsg->Validate(service, kInAnswerSection, kCheckTxt);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query for ANY record and validate the response");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQuery(fullServiceName.AsCString(), ResourceRecord::kTypeAny, ResourceRecord::kClassInternet,
/* aTruncated */ false,
/* aLegacyUnicastQuery */ true);
AdvanceTime(1000);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg != nullptr);
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 2, /* Auth */ 0, /* Addnl */ 3);
dnsMsg->Validate(service, kInAnswerSection, kCheckSrv | kCheckTxt);
dnsMsg->Validate(host, kInAdditionalSection);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query for PTR record for service type and validate the response");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQuery(fullServiceType.AsCString(), ResourceRecord::kTypePtr, ResourceRecord::kClassInternet,
/* aTruncated */ false,
/* aLegacyUnicastQuery */ true);
AdvanceTime(1000);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg != nullptr);
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 1, /* Auth */ 0, /* Addnl */ 4);
dnsMsg->Validate(service, kInAnswerSection, kCheckPtr);
dnsMsg->Validate(service, kInAdditionalSection, kCheckSrv | kCheckTxt);
dnsMsg->Validate(host, kInAdditionalSection);
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
Log("Send a query for non-existing record and validate the response with NSEC");
AdvanceTime(2000);
sDnsMessages.Clear();
SendQuery(hostFullName.AsCString(), ResourceRecord::kTypeA, ResourceRecord::kClassInternet, /* aTruncated */ false,
/* aLegacyUnicastQuery */ true);
AdvanceTime(1000);
dnsMsg = sDnsMessages.GetHead();
VerifyOrQuit(dnsMsg != nullptr);
dnsMsg->ValidateHeader(kLegacyUnicastResponse, /* Q */ 1, /* Ans */ 0, /* Auth */ 0, /* Addnl */ 1);
VerifyOrQuit(dnsMsg->mAdditionalRecords.ContainsNsec(hostFullName, ResourceRecord::kTypeAaaa));
Log("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
sDnsMessages.Clear();
SuccessOrQuit(mdns->UnregisterHost(host));
AdvanceTime(15000);
SuccessOrQuit(mdns->SetEnabled(false, kInfraIfIndex));
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
Log("End of test");
testFreeInstance(sInstance);
}
} // namespace Multicast
} // namespace Dns
} // namespace ot
@@ -6904,6 +7134,7 @@ int main(void)
ot::Dns::Multicast::TestTxtResolver();
ot::Dns::Multicast::TestIp6AddrResolver();
ot::Dns::Multicast::TestPassiveCache();
ot::Dns::Multicast::TestLegacyUnicastResponse();
printf("All tests passed\n");
#else