[dns] match DNS name with specific domain (#6114)

This commit adds:
- a new method Dns::Name::IsSubDomainOf that matches a DNS name with
given domain. This is useful for SRP and DNS-SD server to verify if a
RR is in our authorized domain.
- domain checks for names in a SRP update to the SRP server.
This commit is contained in:
kangping
2021-01-29 07:22:09 -08:00
committed by GitHub
parent 46f796d4f0
commit 4bb22d78de
5 changed files with 135 additions and 39 deletions
+31
View File
@@ -539,6 +539,37 @@ bool Name::LabelIterator::CompareLabel(const LabelIterator &aOtherIterator) cons
mLabelLength);
}
bool Name::IsSubDomainOf(const char *aName, const char *aDomain)
{
bool match = false;
uint16_t nameLength = StringLength(aName, kMaxLength);
uint16_t domainLength = StringLength(aDomain, kMaxLength);
if (nameLength > 0 && aName[nameLength - 1] == kLabelSeperatorChar)
{
--nameLength;
}
if (domainLength > 0 && aDomain[domainLength - 1] == kLabelSeperatorChar)
{
--domainLength;
}
VerifyOrExit(nameLength >= domainLength);
aName += nameLength - domainLength;
if (nameLength > domainLength)
{
VerifyOrExit(aName[-1] == kLabelSeperatorChar);
}
VerifyOrExit(memcmp(aName, aDomain, domainLength) == 0);
match = true;
exit:
return match;
}
otError ResourceRecord::ParseRecords(const Message &aMessage, uint16_t &aOffset, uint16_t aNumRecords)
{
otError error = OT_ERROR_NONE;
+13
View File
@@ -890,6 +890,19 @@ public:
*/
static otError CompareName(const Message &aMessage, uint16_t &aOffset, const Name &aName);
/**
* This static method tests if a DNS name is a sub-domain of a given domain.
*
* Both @p aName and @p aDomain can end without dot ('.').
*
* @param[in] aName The dot-separated name.
* @param[in] aDomain The dot-separated domain.
*
* @returns TRUE if the name is a sub-domain of @p aDomain, FALSE if is not.
*
*/
static bool IsSubDomainOf(const char *aName, const char *aDomain);
private:
enum : char
{
+28 -14
View File
@@ -223,11 +223,11 @@ void Server::RemoveAndFreeHost(Host *aHost)
aHost->Free();
}
Server::Service *Server::FindService(const char *aFullName)
const Server::Service *Server::FindService(const char *aFullName) const
{
Service *service = nullptr;
const Service *service = nullptr;
for (Host *host = mHosts.GetHead(); host != nullptr; host = host->GetNext())
for (const Host *host = mHosts.GetHead(); host != nullptr; host = host->GetNext())
{
service = host->FindService(aFullName);
if (service != nullptr)
@@ -239,11 +239,11 @@ Server::Service *Server::FindService(const char *aFullName)
return service;
}
bool Server::HasNameConflictsWith(Host &aHost)
bool Server::HasNameConflictsWith(Host &aHost) const
{
bool hasConflicts = false;
const Service *service = nullptr;
Host * existingHost = mHosts.FindMatching(aHost.GetFullName());
const Host * existingHost = mHosts.FindMatching(aHost.GetFullName());
if (existingHost != nullptr && *aHost.GetKey() != *existingHost->GetKey())
{
@@ -253,7 +253,7 @@ bool Server::HasNameConflictsWith(Host &aHost)
// Check not only services of this host but all hosts.
while ((service = aHost.GetNextService(service)) != nullptr)
{
Service *existingService = FindService(service->mFullName);
const Service *existingService = FindService(service->mFullName);
if (existingService != nullptr && *service->GetHost().GetKey() != *existingService->GetHost().GetKey())
{
ExitNow(hasConflicts = true);
@@ -569,14 +569,17 @@ exit:
otError Server::ProcessZoneSection(const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
uint16_t & aOffset,
Dns::Zone & aZone)
Dns::Zone & aZone) const
{
otError error = OT_ERROR_NONE;
char name[Dns::Name::kMaxLength + 1];
Dns::Zone zone;
VerifyOrExit(aDnsHeader.GetZoneRecordCount() == 1, error = OT_ERROR_PARSE);
SuccessOrExit(error = Dns::Name::ParseName(aMessage, aOffset));
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
// TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
VerifyOrExit(strcmp(name, GetDomain()) == 0, error = OT_ERROR_SECURITY);
SuccessOrExit(error = aMessage.Read(aOffset, zone));
aOffset += sizeof(zone);
@@ -591,7 +594,7 @@ otError Server::ProcessUpdateSection(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t & aOffset)
uint16_t & aOffset) const
{
otError error = OT_ERROR_NONE;
@@ -623,7 +626,7 @@ otError Server::ProcessHostDescriptionInstruction(Host & aHost
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset)
uint16_t aOffset) const
{
otError error;
@@ -635,6 +638,8 @@ otError Server::ProcessHostDescriptionInstruction(Host & aHost
Dns::ResourceRecord record;
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
// TODO: return `Dns::kResponseNotZone` for names not in the zone.
VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = OT_ERROR_SECURITY);
SuccessOrExit(error = aMessage.Read(aOffset, record));
if (record.GetClass() == Dns::ResourceRecord::kClassAny)
@@ -728,7 +733,7 @@ otError Server::ProcessServiceDiscoveryInstructions(Host & aHo
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset)
uint16_t aOffset) const
{
otError error = OT_ERROR_NONE;
@@ -740,6 +745,7 @@ otError Server::ProcessServiceDiscoveryInstructions(Host & aHo
Service * service;
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = OT_ERROR_SECURITY);
SuccessOrExit(error = aMessage.Read(aOffset, record));
aOffset += sizeof(record);
@@ -747,6 +753,7 @@ otError Server::ProcessServiceDiscoveryInstructions(Host & aHo
if (record.GetType() == Dns::ResourceRecord::kTypePtr)
{
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, serviceName, sizeof(serviceName)));
VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = OT_ERROR_SECURITY);
}
else
{
@@ -776,7 +783,7 @@ otError Server::ProcessServiceDescriptionInstructions(Host & a
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t & aOffset)
uint16_t & aOffset) const
{
Service *service;
otError error = OT_ERROR_NONE;
@@ -787,6 +794,7 @@ otError Server::ProcessServiceDescriptionInstructions(Host & a
Dns::ResourceRecord record;
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = OT_ERROR_SECURITY);
SuccessOrExit(error = aMessage.Read(aOffset, record));
if (record.GetClass() == Dns::ResourceRecord::kClassAny)
@@ -814,6 +822,7 @@ otError Server::ProcessServiceDescriptionInstructions(Host & a
aOffset += sizeof(srvRecord);
SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, hostName, hostNameLength));
VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = OT_ERROR_SECURITY);
VerifyOrExit(aHost.Matches(hostName), error = OT_ERROR_FAILED);
service = aHost.FindService(name);
@@ -862,7 +871,7 @@ bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
otError Server::ProcessAdditionalSection(Host * aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
uint16_t & aOffset)
uint16_t & aOffset) const
{
otError error = OT_ERROR_NONE;
Dns::OptRecord optRecord;
@@ -927,7 +936,7 @@ otError Server::VerifySignature(const Dns::Ecdsa256KeyRecord &aKey,
uint16_t aSigOffset,
uint16_t aSigRdataOffset,
uint16_t aSigRdataLength,
const char * aSignerName)
const char * aSignerName) const
{
otError error;
uint16_t offset = aMessage.GetOffset();
@@ -1571,6 +1580,11 @@ Server::Service *Server::Host::FindService(const char *aFullName)
return mServices.FindMatching(aFullName);
}
const Server::Service *Server::Host::FindService(const char *aFullName) const
{
return const_cast<Host *>(this)->FindService(aFullName);
}
otError Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
{
otError error = OT_ERROR_NONE;
+26 -25
View File
@@ -361,7 +361,8 @@ public:
void DeleteResourcesButRetainName(void);
void CopyResourcesFrom(const Host &aHost);
Service *FindService(const char *aFullName);
otError AddIp6Address(const Ip6::Address &aIp6Address);
const Service *FindService(const char *aFullName) const;
otError AddIp6Address(const Ip6::Address &aIp6Address);
char * mFullName;
Ip6::Address mAddresses[kMaxAddressesNum];
@@ -552,45 +553,45 @@ private:
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t & aOffset);
uint16_t & aOffset) const;
otError ProcessAdditionalSection(Host * aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
uint16_t & aOffset);
uint16_t & aOffset) const;
otError VerifySignature(const Dns::Ecdsa256KeyRecord &aKey,
const Message & aMessage,
Dns::UpdateHeader aDnsHeader,
uint16_t aSigOffset,
uint16_t aSigRdataOffset,
uint16_t aSigRdataLength,
const char * aSignerName);
const char * aSignerName) const;
otError ProcessZoneSection(const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
uint16_t & aOffset,
Dns::Zone & aZone) const;
otError ProcessHostDescriptionInstruction(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset) const;
otError ProcessServiceDiscoveryInstructions(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset) const;
otError ProcessServiceDescriptionInstructions(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t & aOffset) const;
static otError ProcessZoneSection(const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
uint16_t & aOffset,
Dns::Zone & aZone);
static otError ProcessHostDescriptionInstruction(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset);
static otError ProcessServiceDiscoveryInstructions(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t aOffset);
static otError ProcessServiceDescriptionInstructions(Host & aHost,
const Message & aMessage,
const Dns::UpdateHeader &aDnsHeader,
const Dns::Zone & aZone,
uint16_t & aOffset);
static bool IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord);
const Service *FindService(const char *aFullName) const;
void HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host *aHost, const Ip6::MessageInfo &aMessageInfo);
void AddHost(Host *aHost);
void RemoveAndFreeHost(Host *aHost);
Service * FindService(const char *aFullName);
bool HasNameConflictsWith(Host &aHost);
bool HasNameConflictsWith(Host &aHost) const;
void SendResponse(const Dns::UpdateHeader & aHeader,
Dns::UpdateHeader::Response aResponseCode,
const Ip6::MessageInfo & aMessageInfo);
+37
View File
@@ -145,6 +145,43 @@ void TestDnsName(void)
message->SetOffset(0);
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), "Name::IsSubDomainOf() failed");
subDomain = "my-service._ipps._tcp.local";
domain = "local.";
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain), "Name::IsSubDomainOf() failed");
subDomain = "my-service._ipps._tcp.local.";
domain = "local";
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain), "Name::IsSubDomainOf() failed");
subDomain = "my-service._ipps._tcp.local";
domain = "local";
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain), "Name::IsSubDomainOf() failed");
subDomain = "my-service._ipps._tcp.default.service.arpa.";
domain = "default.service.arpa.";
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain), "Name::IsSubDomainOf() failed");
subDomain = "my-service._ipps._tcp.default.service.arpa.";
domain = "service.arpa.";
VerifyOrQuit(Dns::Name::IsSubDomainOf(subDomain, domain), "Name::IsSubDomainOf() failed");
// 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), "Name::IsSubDomainOf() succeed");
}
printf("----------------------------------------------------------------\n");
printf("Append names, check encoded bytes, parse name and read labels:\n");