diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index e11919cd1..dda9f844b 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -352,7 +352,7 @@ void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError) otThreadErrorToString(aError)); IgnoreError(mOutstandingUpdates.Remove(*aUpdate)); - CommitSrpUpdate(aError, aUpdate->GetDnsHeader(), aUpdate->GetHost(), aUpdate->GetMessageInfo()); + CommitSrpUpdate(aError, *aUpdate); aUpdate->Free(); if (mOutstandingUpdates.IsEmpty()) @@ -361,14 +361,28 @@ void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError) } else { - mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0); + mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime()); } } +void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata) +{ + CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo, + aMessageMetadata.mLeaseConfig); +} + +void Server::CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata) +{ + CommitSrpUpdate(aError, aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(), + aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr, + aUpdateMetadata.GetLeaseConfig()); +} + void Server::CommitSrpUpdate(Error aError, - const Dns::UpdateHeader &aDnsHeader, Host & aHost, - const Ip6::MessageInfo & aMessageInfo) + const Dns::UpdateHeader &aDnsHeader, + const Ip6::MessageInfo * aMessageInfo, + const LeaseConfig & aLeaseConfig) { Host * existingHost; uint32_t hostLease; @@ -381,8 +395,8 @@ void Server::CommitSrpUpdate(Error aError, hostLease = aHost.GetLease(); hostKeyLease = aHost.GetKeyLease(); - grantedLease = mLeaseConfig.GrantLease(hostLease); - grantedKeyLease = mLeaseConfig.GrantKeyLease(hostKeyLease); + grantedLease = aLeaseConfig.GrantLease(hostLease); + grantedKeyLease = aLeaseConfig.GrantKeyLease(hostKeyLease); aHost.SetLease(grantedLease); aHost.SetKeyLease(grantedKeyLease); @@ -446,13 +460,16 @@ void Server::CommitSrpUpdate(Error aError, HandleLeaseTimer(); exit: - if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease)) + if (aMessageInfo != nullptr) { - SendResponse(aDnsHeader, grantedLease, grantedKeyLease, aMessageInfo); - } - else - { - SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), aMessageInfo); + if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease)) + { + SendResponse(aDnsHeader, grantedLease, grantedKeyLease, *aMessageInfo); + } + else + { + SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), *aMessageInfo); + } } if (shouldFreeHost) @@ -618,16 +635,17 @@ void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent) } } -const Server::UpdateMetadata *Server::FindOutstandingUpdate(const Ip6::MessageInfo &aMessageInfo, - uint16_t aDnsMessageId) +const Server::UpdateMetadata *Server::FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const { const UpdateMetadata *ret = nullptr; + VerifyOrExit(aMessageMetadata.IsDirectRxFromClient()); + for (const UpdateMetadata &update : mOutstandingUpdates) { - if (aDnsMessageId == update.GetDnsHeader().GetMessageId() && - aMessageInfo.GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() && - aMessageInfo.GetPeerPort() == update.GetMessageInfo().GetPeerPort()) + if (aMessageMetadata.mDnsHeader.GetMessageId() == update.GetDnsHeader().GetMessageId() && + aMessageMetadata.mMessageInfo->GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() && + aMessageMetadata.mMessageInfo->GetPeerPort() == update.GetMessageInfo().GetPeerPort()) { ExitNow(ret = &update); } @@ -637,22 +655,20 @@ exit: return ret; } -void Server::ProcessDnsUpdate(Message & aMessage, - const Ip6::MessageInfo & aMessageInfo, - const Dns::UpdateHeader &aDnsHeader, - uint16_t aOffset) +void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata) { - Error error = kErrorNone; - Dns::Zone zone; - Host * host = nullptr; + Error error = kErrorNone; + Host *host = nullptr; - otLogInfoSrp("[server] receive DNS update from %s", aMessageInfo.GetPeerAddr().ToString().AsCString()); + otLogInfoSrp("[server] Received DNS update from %s", + aMetadata.IsDirectRxFromClient() ? aMetadata.mMessageInfo->GetPeerAddr().ToString().AsCString() + : "an SRPL Partner"); - SuccessOrExit(error = ProcessZoneSection(aMessage, aDnsHeader, aOffset, zone)); + SuccessOrExit(error = ProcessZoneSection(aMessage, aMetadata)); - if (FindOutstandingUpdate(aMessageInfo, aDnsHeader.GetMessageId()) != nullptr) + if (FindOutstandingUpdate(aMetadata) != nullptr) { - otLogInfoSrp("[server] drop duplicated SRP update request: messageId=%hu", aDnsHeader.GetMessageId()); + otLogInfoSrp("[server] Drop duplicated SRP update request: MessageId=%hu", aMetadata.mDnsHeader.GetMessageId()); // Silently drop duplicate requests. // This could rarely happen, because the outstanding SRP update timer should @@ -661,16 +677,16 @@ void Server::ProcessDnsUpdate(Message & aMessage, } // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update. - VerifyOrExit(aDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed); + VerifyOrExit(aMetadata.mDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed); - host = Host::New(GetInstance()); + host = Host::New(GetInstance(), aMetadata.mRxTime); VerifyOrExit(host != nullptr, error = kErrorNoBufs); - SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aDnsHeader, zone, aOffset)); + SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aMetadata)); // Parse lease time and validate signature. - SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aDnsHeader, aOffset)); + SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata)); - HandleUpdate(aDnsHeader, *host, aMessageInfo); + HandleUpdate(*host, aMetadata); exit: if (error != kErrorNone) @@ -680,39 +696,35 @@ exit: host->Free(); } - SendResponse(aDnsHeader, ErrorToDnsResponseCode(error), aMessageInfo); + if (aMetadata.IsDirectRxFromClient()) + { + SendResponse(aMetadata.mDnsHeader, ErrorToDnsResponseCode(error), *aMetadata.mMessageInfo); + } } } -Error Server::ProcessZoneSection(const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - uint16_t & aOffset, - Dns::Zone & aZone) const +Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const { - Error error = kErrorNone; - char name[Dns::Name::kMaxNameSize]; - Dns::Zone zone; + Error error = kErrorNone; + char name[Dns::Name::kMaxNameSize]; + uint16_t offset = aMetadata.mOffset; - VerifyOrExit(aDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse); + VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse); - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); // TODO: return `Dns::kResponseNotAuth` for not authorized zone names. VerifyOrExit(strcmp(name, GetDomain()) == 0, error = kErrorSecurity); - SuccessOrExit(error = aMessage.Read(aOffset, zone)); - aOffset += sizeof(zone); + SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone)); + offset += sizeof(Dns::Zone); - VerifyOrExit(zone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse); - aZone = zone; + VerifyOrExit(aMetadata.mDnsZone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse); + aMetadata.mOffset = offset; exit: return error; } -Error Server::ProcessUpdateSection(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t & aOffset) const +Error Server::ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const { Error error = kErrorNone; @@ -722,16 +734,13 @@ Error Server::ProcessUpdateSection(Host & aHost, // 0. Enumerate over all Service Discovery Instructions before processing any other records. // So that we will know whether a name is a hostname or service instance name when processing // a "Delete All RRsets from a name" record. - error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset); - SuccessOrExit(error); + SuccessOrExit(error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aMetadata)); // 1. Enumerate over all RRs to build the Host Description Instruction. - error = ProcessHostDescriptionInstruction(aHost, aMessage, aDnsHeader, aZone, aOffset); - SuccessOrExit(error); + SuccessOrExit(error = ProcessHostDescriptionInstruction(aHost, aMessage, aMetadata)); // 2. Enumerate over all RRs to build the Service Description Instructions. - error = ProcessServiceDescriptionInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset); - SuccessOrExit(error); + SuccessOrExit(error = ProcessServiceDescriptionInstructions(aHost, aMessage, aMetadata)); // 3. Verify that there are no name conflicts. VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated); @@ -740,24 +749,23 @@ exit: return error; } -Error Server::ProcessHostDescriptionInstruction(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t aOffset) const +Error Server::ProcessHostDescriptionInstruction(Host & aHost, + const Message & aMessage, + const MessageMetadata &aMetadata) const { - Error error; + Error error; + uint16_t offset = aMetadata.mOffset; OT_ASSERT(aHost.GetFullName() == nullptr); - for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) + for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { char name[Dns::Name::kMaxNameSize]; Dns::ResourceRecord record; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); - SuccessOrExit(error = aMessage.Read(aOffset, record)); + SuccessOrExit(error = aMessage.Read(offset, record)); if (record.GetClass() == Dns::ResourceRecord::kClassAny) { @@ -778,11 +786,11 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost, { Dns::AaaaRecord aaaaRecord; - VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed); + VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); SuccessOrExit(error = aHost.SetFullName(name)); - SuccessOrExit(error = aMessage.Read(aOffset, aaaaRecord)); + SuccessOrExit(error = aMessage.Read(offset, aaaaRecord)); VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse); // Tolerate kErrorDrop for AAAA Resources. @@ -793,15 +801,15 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost, // We currently support only ECDSA P-256. Dns::Ecdsa256KeyRecord key; - VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed); - SuccessOrExit(error = aMessage.Read(aOffset, key)); + VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); + SuccessOrExit(error = aMessage.Read(offset, key)); VerifyOrExit(key.IsValid(), error = kErrorParse); VerifyOrExit(aHost.GetKey() == nullptr || *aHost.GetKey() == key, error = kErrorSecurity); aHost.SetKey(key); } - aOffset += record.GetSize(); + offset += record.GetSize(); } // Verify that we have a complete Host Description Instruction. @@ -817,15 +825,14 @@ exit: return error; } -Error Server::ProcessServiceDiscoveryInstructions(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t aOffset) const +Error Server::ProcessServiceDiscoveryInstructions(Host & aHost, + const Message & aMessage, + const MessageMetadata &aMetadata) const { - Error error = kErrorNone; + Error error = kErrorNone; + uint16_t offset = aMetadata.mOffset; - for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) + for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { char serviceName[Dns::Name::kMaxNameSize]; char instanceName[Dns::Name::kMaxNameSize]; @@ -834,10 +841,10 @@ Error Server::ProcessServiceDiscoveryInstructions(Host & aHost Service * service; bool isSubType; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, serviceName, sizeof(serviceName))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName, sizeof(serviceName))); VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity); - error = Dns::ResourceRecord::ReadRecord(aMessage, aOffset, ptrRecord); + error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord); if (error == kErrorNotFound) { @@ -849,10 +856,10 @@ Error Server::ProcessServiceDiscoveryInstructions(Host & aHost SuccessOrExit(error); - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, instanceName, sizeof(instanceName))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, instanceName, sizeof(instanceName))); VerifyOrExit(ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone || - ptrRecord.GetClass() == aZone.GetClass(), + ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); // Check if the `serviceName` is a subtype with the name @@ -875,7 +882,7 @@ Error Server::ProcessServiceDiscoveryInstructions(Host & aHost // Ensure the same service does not exist already. VerifyOrExit(aHost.FindService(serviceName, instanceName) == nullptr, error = kErrorFailed); - service = aHost.AddNewService(serviceName, instanceName, isSubType); + service = aHost.AddNewService(serviceName, instanceName, isSubType, aMetadata.mRxTime); VerifyOrExit(service != nullptr, error = kErrorNoBufs); // This RR is a "Delete an RR from an RRset" update when the CLASS is NONE. @@ -886,23 +893,21 @@ exit: return error; } -Error Server::ProcessServiceDescriptionInstructions(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t & aOffset) const +Error Server::ProcessServiceDescriptionInstructions(Host & aHost, + const Message & aMessage, + MessageMetadata &aMetadata) const { - Error error = kErrorNone; - TimeMilli now = TimerMilli::GetNow(); + Error error = kErrorNone; + uint16_t offset = aMetadata.mOffset; - for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) + for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--) { Service::Description *desc; char name[Dns::Name::kMaxNameSize]; Dns::ResourceRecord record; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name))); - SuccessOrExit(error = aMessage.Read(aOffset, record)); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = aMessage.Read(offset, record)); if (record.GetClass() == Dns::ResourceRecord::kClassAny) { @@ -914,10 +919,10 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHo if (desc != nullptr) { desc->ClearResources(); - desc->mTimeLastUpdate = now; + desc->mUpdateTime = aMetadata.mRxTime; } - aOffset += record.GetSize(); + offset += record.GetSize(); continue; } @@ -927,11 +932,11 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHo char hostName[Dns::Name::kMaxNameSize]; uint16_t hostNameLength = sizeof(hostName); - VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed); - SuccessOrExit(error = aMessage.Read(aOffset, srvRecord)); - aOffset += sizeof(srvRecord); + VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); + SuccessOrExit(error = aMessage.Read(offset, srvRecord)); + offset += sizeof(srvRecord); - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, hostName, hostNameLength)); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName, hostNameLength)); VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity); VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed); @@ -940,35 +945,35 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHo // Make sure that this is the first SRV RR for this service description VerifyOrExit(desc->mPort == 0, error = kErrorFailed); - desc->mPriority = srvRecord.GetPriority(); - desc->mWeight = srvRecord.GetWeight(); - desc->mPort = srvRecord.GetPort(); - desc->mTimeLastUpdate = now; + desc->mPriority = srvRecord.GetPriority(); + desc->mWeight = srvRecord.GetWeight(); + desc->mPort = srvRecord.GetPort(); + desc->mUpdateTime = aMetadata.mRxTime; } else if (record.GetType() == Dns::ResourceRecord::kTypeTxt) { - VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed); + VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed); desc = aHost.FindServiceDescription(name); VerifyOrExit(desc != nullptr, error = kErrorFailed); - aOffset += sizeof(record); - SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, aOffset, record.GetLength())); - aOffset += record.GetLength(); + offset += sizeof(record); + SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, offset, record.GetLength())); + offset += record.GetLength(); } else { - aOffset += record.GetSize(); + offset += record.GetSize(); } } // Verify that all service descriptions on `aHost` are updated. Note - // that `mTimeLastUpdate` on a new `Service::Description` is set to + // that `mUpdateTime` on a new `Service::Description` is set to // `GetNow().GetDistantPast()`. for (Service::Description &desc : aHost.mServiceDescriptions) { - VerifyOrExit(desc.mTimeLastUpdate == now, error = kErrorFailed); + VerifyOrExit(desc.mUpdateTime == aMetadata.mRxTime, error = kErrorFailed); // Check that either both `mPort` and `mTxtData` are set // (i.e., we saw both SRV and TXT record) or both are default @@ -977,6 +982,8 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHo VerifyOrExit((desc.mPort == 0) == (desc.mTxtData == nullptr), error = kErrorFailed); } + aMetadata.mOffset = offset; + exit: return error; } @@ -987,32 +994,30 @@ bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord) aRecord.GetTtl() == 0 && aRecord.GetLength() == 0; } -Error Server::ProcessAdditionalSection(Host * aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - uint16_t & aOffset) const +Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const { Error error = kErrorNone; Dns::OptRecord optRecord; Dns::LeaseOption leaseOption; Dns::SigRecord sigRecord; char name[2]; // The root domain name (".") is expected. + uint16_t offset = aMetadata.mOffset; uint16_t sigOffset; uint16_t sigRdataOffset; char signerName[Dns::Name::kMaxNameSize]; uint16_t signatureLength; - VerifyOrExit(aDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed); + VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed); // EDNS(0) Update Lease Option. - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name))); - SuccessOrExit(error = aMessage.Read(aOffset, optRecord)); - SuccessOrExit(error = aMessage.Read(aOffset + sizeof(optRecord), leaseOption)); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = aMessage.Read(offset, optRecord)); + SuccessOrExit(error = aMessage.Read(offset + sizeof(optRecord), leaseOption)); VerifyOrExit(leaseOption.IsValid(), error = kErrorFailed); VerifyOrExit(optRecord.GetSize() == sizeof(optRecord) + sizeof(leaseOption), error = kErrorParse); - aOffset += optRecord.GetSize(); + offset += optRecord.GetSize(); aHost->SetLease(leaseOption.GetLeaseInterval()); aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval()); @@ -1029,22 +1034,22 @@ Error Server::ProcessAdditionalSection(Host * aHost, // SIG(0). - sigOffset = aOffset; - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name))); - SuccessOrExit(error = aMessage.Read(aOffset, sigRecord)); + sigOffset = offset; + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name))); + SuccessOrExit(error = aMessage.Read(offset, sigRecord)); VerifyOrExit(sigRecord.IsValid(), error = kErrorParse); - sigRdataOffset = aOffset + sizeof(Dns::ResourceRecord); - aOffset += sizeof(sigRecord); + sigRdataOffset = offset + sizeof(Dns::ResourceRecord); + offset += sizeof(sigRecord); // TODO: Verify that the signature doesn't expire. This is not // implemented because the end device may not be able to get // the synchronized date/time. - SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, signerName, sizeof(signerName))); + SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName, sizeof(signerName))); - signatureLength = sigRecord.GetLength() - (aOffset - sigRdataOffset); - aOffset += signatureLength; + signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset); + offset += signatureLength; // Verify the signature. Currently supports only ECDSA. @@ -1052,9 +1057,11 @@ Error Server::ProcessAdditionalSection(Host * aHost, VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed); VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse); - SuccessOrExit(error = VerifySignature(*aHost->GetKey(), aMessage, aDnsHeader, sigOffset, sigRdataOffset, + SuccessOrExit(error = VerifySignature(*aHost->GetKey(), aMessage, aMetadata.mDnsHeader, sigOffset, sigRdataOffset, sigRecord.GetLength(), signerName)); + aMetadata.mOffset = offset; + exit: return error; } @@ -1106,7 +1113,7 @@ exit: return error; } -void Server::HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host &aHost, const Ip6::MessageInfo &aMessageInfo) +void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata) { Error error = kErrorNone; Host *existingHost; @@ -1133,33 +1140,29 @@ void Server::HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host &aHost, cons if (aHost.FindService(service.GetServiceName(), service.GetInstanceName()) == nullptr) { - Service *newService = - aHost.AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType()); + Service *newService = aHost.AddNewService(service.GetServiceName(), service.GetInstanceName(), + service.IsSubType(), aMetadata.mRxTime); VerifyOrExit(newService != nullptr, error = kErrorNoBufs); - newService->mDescription.mTimeLastUpdate = TimerMilli::GetNow(); - newService->mIsDeleted = true; + newService->mDescription.mUpdateTime = aMetadata.mRxTime; + newService->mIsDeleted = true; } } exit: - if (error != kErrorNone) + if ((error == kErrorNone) && (mServiceUpdateHandler != nullptr)) { - CommitSrpUpdate(error, aDnsHeader, aHost, aMessageInfo); - } - else if (mServiceUpdateHandler != nullptr) - { - UpdateMetadata *update = UpdateMetadata::New(GetInstance(), aDnsHeader, &aHost, aMessageInfo); + UpdateMetadata *update = UpdateMetadata::New(GetInstance(), aHost, aMetadata); - IgnoreError(mOutstandingUpdates.Add(*update)); - mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0); + mOutstandingUpdates.Push(*update); + mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime()); otLogInfoSrp("[server] SRP update handler is notified (updatedId = %u)", update->GetId()); mServiceUpdateHandler(update->GetId(), &aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext); } else { - CommitSrpUpdate(kErrorNone, aDnsHeader, aHost, aMessageInfo); + CommitSrpUpdate(error, aHost, aMetadata); } } @@ -1263,25 +1266,29 @@ void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { - Error error; - Dns::UpdateHeader dnsHeader; - uint16_t offset = aMessage.GetOffset(); + return ProcessMessage(aMessage, TimerMilli::GetNow(), mLeaseConfig, &aMessageInfo); +} - SuccessOrExit(error = aMessage.Read(offset, dnsHeader)); - offset += sizeof(dnsHeader); +Error Server::ProcessMessage(Message & aMessage, + TimeMilli aRxTime, + const LeaseConfig & aLeaseConfig, + const Ip6::MessageInfo *aMessageInfo) +{ + Error error; + MessageMetadata metadata; - // Handles only queries. - VerifyOrExit(dnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop); + metadata.mOffset = aMessage.GetOffset(); + metadata.mRxTime = aRxTime; + metadata.mLeaseConfig = aLeaseConfig; + metadata.mMessageInfo = aMessageInfo; - switch (dnsHeader.GetQueryType()) - { - case Dns::UpdateHeader::kQueryTypeUpdate: - ProcessDnsUpdate(aMessage, aMessageInfo, dnsHeader, offset); - break; - default: - error = kErrorDrop; - break; - } + SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader)); + metadata.mOffset += sizeof(Dns::UpdateHeader); + + VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop); + VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop); + + ProcessDnsUpdate(aMessage, metadata); exit: return error; @@ -1437,7 +1444,10 @@ const char *Server::AddressModeToString(AddressMode aMode) //--------------------------------------------------------------------------------------------------------------------- // Server::Service -Server::Service *Server::Service::New(const char *aServiceName, Description &aDescription, bool aIsSubType) +Server::Service *Server::Service::New(const char * aServiceName, + Description &aDescription, + bool aIsSubType, + TimeMilli aUpdateTime) { void * buf; Service *service = nullptr; @@ -1445,7 +1455,7 @@ Server::Service *Server::Service::New(const char *aServiceName, Description &aDe buf = Heap::CAlloc(1, sizeof(Service)); VerifyOrExit(buf != nullptr); - service = new (buf) Service(aDescription, aIsSubType); + service = new (buf) Service(aDescription, aIsSubType, aUpdateTime); if (service->mServiceName.Set(aServiceName) != kErrorNone) { @@ -1462,10 +1472,10 @@ void Server::Service::Free(void) Heap::Free(this); } -Server::Service::Service(Description &aDescription, bool aIsSubType) +Server::Service::Service(Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime) : mDescription(aDescription) , mNext(nullptr) - , mTimeLastUpdate(TimerMilli::GetNow()) + , mUpdateTime(aUpdateTime) , mIsDeleted(false) , mIsSubType(aIsSubType) , mIsCommitted(false) @@ -1507,12 +1517,12 @@ TimeMilli Server::Service::GetExpireTime(void) const OT_ASSERT(!mIsDeleted); OT_ASSERT(!GetHost().IsDeleted()); - return mTimeLastUpdate + Time::SecToMsec(mDescription.mLease); + return mUpdateTime + Time::SecToMsec(mDescription.mLease); } TimeMilli Server::Service::GetKeyExpireTime(void) const { - return mTimeLastUpdate + Time::SecToMsec(mDescription.mKeyLease); + return mUpdateTime + Time::SecToMsec(mDescription.mKeyLease); } bool Server::Service::MatchesFlags(Flags aFlags) const @@ -1622,7 +1632,7 @@ Server::Service::Description::Description(Host &aHost) , mTxtData(nullptr) , mLease(0) , mKeyLease(0) - , mTimeLastUpdate(TimerMilli::GetNow().GetDistantPast()) + , mUpdateTime(TimerMilli::GetNow().GetDistantPast()) { } @@ -1648,9 +1658,9 @@ void Server::Service::Description::TakeResourcesFrom(Description &aDescription) mWeight = aDescription.mWeight; mPort = aDescription.mPort; - mLease = aDescription.mLease; - mKeyLease = aDescription.mKeyLease; - mTimeLastUpdate = TimerMilli::GetNow(); + mLease = aDescription.mLease; + mKeyLease = aDescription.mKeyLease; + mUpdateTime = TimerMilli::GetNow(); } Error Server::Service::Description::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength) @@ -1680,7 +1690,7 @@ exit: //--------------------------------------------------------------------------------------------------------------------- // Server::Host -Server::Host *Server::Host::New(Instance &aInstance) +Server::Host *Server::Host::New(Instance &aInstance, TimeMilli aUpdateTime) { void *buf; Host *host = nullptr; @@ -1688,7 +1698,7 @@ Server::Host *Server::Host::New(Instance &aInstance) buf = Heap::CAlloc(1, sizeof(Host)); VerifyOrExit(buf != nullptr); - host = new (buf) Host(aInstance); + host = new (buf) Host(aInstance, aUpdateTime); exit: return host; @@ -1701,12 +1711,12 @@ void Server::Host::Free(void) Heap::Free(this); } -Server::Host::Host(Instance &aInstance) +Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime) : InstanceLocator(aInstance) , mNext(nullptr) , mLease(0) , mKeyLease(0) - , mTimeLastUpdate(TimerMilli::GetNow()) + , mUpdateTime(aUpdateTime) { mKey.Clear(); } @@ -1742,12 +1752,12 @@ TimeMilli Server::Host::GetExpireTime(void) const { OT_ASSERT(!IsDeleted()); - return mTimeLastUpdate + Time::SecToMsec(mLease); + return mUpdateTime + Time::SecToMsec(mLease); } TimeMilli Server::Host::GetKeyExpireTime(void) const { - return mTimeLastUpdate + Time::SecToMsec(mKeyLease); + return mUpdateTime + Time::SecToMsec(mKeyLease); } const Server::Service *Server::Host::FindNextService(const Service *aPrevService, @@ -1780,7 +1790,10 @@ const Server::Service *Server::Host::FindNextService(const Service *aPrevService return service; } -Server::Service *Server::Host::AddNewService(const char *aServiceName, const char *aInstanceName, bool aIsSubType) +Server::Service *Server::Host::AddNewService(const char *aServiceName, + const char *aInstanceName, + bool aIsSubType, + TimeMilli aUpdateTime) { Service * service = nullptr; Service::Description *desc; @@ -1794,7 +1807,7 @@ Server::Service *Server::Host::AddNewService(const char *aServiceName, const cha mServiceDescriptions.Push(*desc); } - service = Service::New(aServiceName, *desc, aIsSubType); + service = Service::New(aServiceName, *desc, aIsSubType, aUpdateTime); VerifyOrExit(service != nullptr); mServices.Push(*service); @@ -1886,11 +1899,11 @@ Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost) otLogInfoSrp("[server] update host %s", GetFullName()); - mAddresses = aHost.mAddresses; - mKey = aHost.mKey; - mLease = aHost.mLease; - mKeyLease = aHost.mKeyLease; - mTimeLastUpdate = TimerMilli::GetNow(); + mAddresses = aHost.mAddresses; + mKey = aHost.mKey; + mLease = aHost.mLease; + mKeyLease = aHost.mKeyLease; + mUpdateTime = TimerMilli::GetNow(); for (Service &service : aHost.mServices) { @@ -1906,15 +1919,15 @@ Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost) // Add/Merge `service` into the existing service or a allocate a new one - newService = (existingService != nullptr) - ? existingService - : AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType()); + newService = (existingService != nullptr) ? existingService + : AddNewService(service.GetServiceName(), service.GetInstanceName(), + service.IsSubType(), service.GetUpdateTime()); VerifyOrExit(newService != nullptr, error = kErrorNoBufs); - newService->mIsDeleted = false; - newService->mIsCommitted = true; - newService->mTimeLastUpdate = TimerMilli::GetNow(); + newService->mIsDeleted = false; + newService->mIsCommitted = true; + newService->mUpdateTime = TimerMilli::GetNow(); if (!service.mIsSubType) { @@ -1979,10 +1992,9 @@ exit: //--------------------------------------------------------------------------------------------------------------------- // Server::UpdateMetadata -Server::UpdateMetadata *Server::UpdateMetadata::New(Instance & aInstance, - const Dns::UpdateHeader &aHeader, - Host * aHost, - const Ip6::MessageInfo & aMessageInfo) +Server::UpdateMetadata *Server::UpdateMetadata::New(Instance & aInstance, + Host & aHost, + const MessageMetadata &aMessageMetadata) { void * buf; UpdateMetadata *update = nullptr; @@ -1990,7 +2002,7 @@ Server::UpdateMetadata *Server::UpdateMetadata::New(Instance & aIn buf = Heap::CAlloc(1, sizeof(UpdateMetadata)); VerifyOrExit(buf != nullptr); - update = new (buf) UpdateMetadata(aInstance, aHeader, aHost, aMessageInfo); + update = new (buf) UpdateMetadata(aInstance, aHost, aMessageMetadata); exit: return update; @@ -2001,18 +2013,20 @@ void Server::UpdateMetadata::Free(void) Heap::Free(this); } -Server::UpdateMetadata::UpdateMetadata(Instance & aInstance, - const Dns::UpdateHeader &aHeader, - Host * aHost, - const Ip6::MessageInfo & aMessageInfo) +Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata) : InstanceLocator(aInstance) - , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout) - , mDnsHeader(aHeader) - , mId(Get().AllocateId()) - , mHost(aHost) - , mMessageInfo(aMessageInfo) , mNext(nullptr) + , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout) + , mDnsHeader(aMessageMetadata.mDnsHeader) + , mId(Get().AllocateId()) + , mLeaseConfig(aMessageMetadata.mLeaseConfig) + , mHost(aHost) + , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient()) { + if (aMessageMetadata.mMessageInfo != nullptr) + { + mMessageInfo = *aMessageMetadata.mMessageInfo; + } } } // namespace Srp diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index a11d742e3..296fa97b8 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -358,7 +358,7 @@ public: uint8_t * mTxtData; uint32_t mLease; // The LEASE time in seconds. uint32_t mKeyLease; // The KEY-LEASE time in seconds. - TimeMilli mTimeLastUpdate; + TimeMilli mUpdateTime; }; enum Action : uint8_t @@ -371,18 +371,22 @@ public: kKeyLeaseExpired, }; - static Service *New(const char *aServiceName, Description &aDescription, bool aIsSubType); + static Service *New(const char * aServiceName, + Description &aDescription, + bool aIsSubType, + TimeMilli aUpdateTime); - Service(Description &aDescription, bool aIsSubType); + Service(Description &aDescription, bool aIsSubType, TimeMilli aUpdateTime); - void Free(void); - bool MatchesFlags(Flags aFlags) const; - void Log(Action aAction) const; + void Free(void); + bool MatchesFlags(Flags aFlags) const; + const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; } + void Log(Action aAction) const; Heap::String mServiceName; Description &mDescription; Service * mNext; - TimeMilli mTimeLastUpdate; + TimeMilli mUpdateTime; bool mIsDeleted : 1; bool mIsSubType : 1; bool mIsCommitted : 1; @@ -509,16 +513,19 @@ public: private: static constexpr uint16_t kMaxAddresses = OPENTHREAD_CONFIG_SRP_SERVER_MAX_ADDRESSES_NUM; - static Host *New(Instance &aInstance); + static Host *New(Instance &aInstance, TimeMilli aUpdateTime); - explicit Host(Instance &aInstance); + Host(Instance &aInstance, TimeMilli aUpdateTime); void Free(void); Error SetFullName(const char *aFullName); void SetKey(Dns::Ecdsa256KeyRecord &aKey); void SetLease(uint32_t aLease) { mLease = aLease; } void SetKeyLease(uint32_t aKeyLease) { mKeyLease = aKeyLease; } LinkedList &GetServices(void) { return mServices; } - Service * AddNewService(const char *aServiceName, const char *aInstanceName, bool aIsSubType); + Service * AddNewService(const char *aServiceName, + const char *aInstanceName, + bool aIsSubType, + TimeMilli aUpdateTime); void RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler); void FreeAllServices(void); void FreeUnusedServiceDescriptions(void); @@ -536,7 +543,7 @@ public: Dns::Ecdsa256KeyRecord mKey; uint32_t mLease; // The LEASE time in seconds. uint32_t mKeyLease; // The KEY-LEASE time in seconds. - TimeMilli mTimeLastUpdate; + TimeMilli mUpdateTime; LinkedList mServices; LinkedList mServiceDescriptions; }; @@ -762,6 +769,21 @@ private: static constexpr uint16_t kAnycastAddressModePort = 53; + // Metdata for a received SRP Update message. + struct MessageMetadata + { + // Indicates whether the `Message` is received directly from a + // client or from an SRPL partner. + bool IsDirectRxFromClient(void) const { return (mMessageInfo != nullptr); } + + Dns::UpdateHeader mDnsHeader; + Dns::Zone mDnsZone; + uint16_t mOffset; + TimeMilli mRxTime; + LeaseConfig mLeaseConfig; + const Ip6::MessageInfo *mMessageInfo; // Set to `nullptr` when from SRPL. + }; + // This class includes metadata for processing a SRP update (register, deregister) // and sending DNS response to the client. class UpdateMetadata : public InstanceLocator, public LinkedListEntry @@ -769,30 +791,28 @@ private: friend class LinkedListEntry; public: - static UpdateMetadata * New(Instance & aInstance, - const Dns::UpdateHeader &aHeader, - Host * aHost, - const Ip6::MessageInfo & aMessageInfo); + static UpdateMetadata * New(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata); void Free(void); TimeMilli GetExpireTime(void) const { return mExpireTime; } const Dns::UpdateHeader &GetDnsHeader(void) const { return mDnsHeader; } ServiceUpdateId GetId(void) const { return mId; } - Host & GetHost(void) { return *mHost; } + const LeaseConfig & GetLeaseConfig(void) const { return mLeaseConfig; } + Host & GetHost(void) { return mHost; } const Ip6::MessageInfo & GetMessageInfo(void) const { return mMessageInfo; } + bool IsDirectRxFromClient(void) const { return mIsDirectRxFromClient; } bool Matches(ServiceUpdateId aId) const { return mId == aId; } private: - UpdateMetadata(Instance & aInstance, - const Dns::UpdateHeader &aHeader, - Host * aHost, - const Ip6::MessageInfo & aMessageInfo); + UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata); + UpdateMetadata * mNext; TimeMilli mExpireTime; Dns::UpdateHeader mDnsHeader; ServiceUpdateId mId; // The ID of this service update transaction. - Host * mHost; // The host will be updated. The UpdateMetadata has no ownership of this host. - Ip6::MessageInfo mMessageInfo; // The message info of the DNS update request. - UpdateMetadata * mNext; + LeaseConfig mLeaseConfig; // Lease config to use when processing the message. + Host & mHost; // The `UpdateMetadata` has no ownership of this host. + Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true. + bool mIsDirectRxFromClient; }; void Start(void); @@ -810,24 +830,21 @@ private: ServiceUpdateId AllocateId(void) { return mServiceUpdateId++; } + void CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata); + void CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata); void CommitSrpUpdate(Error aError, - const Dns::UpdateHeader &aDnsHeader, Host & aHost, - const Ip6::MessageInfo & aMessageInfo); + const Dns::UpdateHeader &aDnsHeader, + const Ip6::MessageInfo * aMessageInfo, + const LeaseConfig & aLeaseConfig); Error ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo); - void ProcessDnsUpdate(Message & aMessage, - const Ip6::MessageInfo & aMessageInfo, - const Dns::UpdateHeader &aDnsHeader, - uint16_t aOffset); - Error ProcessUpdateSection(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t & aOffset) const; - Error ProcessAdditionalSection(Host * aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - uint16_t & aOffset) const; + Error ProcessMessage(Message & aMessage, + TimeMilli aRxTime, + const LeaseConfig & aLeaseConfig, + const Ip6::MessageInfo *aMessageInfo); + void ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata); + Error ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const; + Error ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const; Error VerifySignature(const Dns::Ecdsa256KeyRecord &aKey, const Message & aMessage, Dns::UpdateHeader aDnsHeader, @@ -835,29 +852,18 @@ private: uint16_t aSigRdataOffset, uint16_t aSigRdataLength, const char * aSignerName) const; - Error ProcessZoneSection(const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - uint16_t & aOffset, - Dns::Zone & aZone) const; - Error ProcessHostDescriptionInstruction(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t aOffset) const; - Error ProcessServiceDiscoveryInstructions(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t aOffset) const; - Error ProcessServiceDescriptionInstructions(Host & aHost, - const Message & aMessage, - const Dns::UpdateHeader &aDnsHeader, - const Dns::Zone & aZone, - uint16_t & aOffset) const; + Error ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const; + Error ProcessHostDescriptionInstruction(Host & aHost, + const Message & aMessage, + const MessageMetadata &aMetadata) const; + Error ProcessServiceDiscoveryInstructions(Host & aHost, + const Message & aMessage, + const MessageMetadata &aMetadata) const; + Error ProcessServiceDescriptionInstructions(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const; static bool IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord); - void HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host &aHost, const Ip6::MessageInfo &aMessageInfo); + void HandleUpdate(Host &aHost, const MessageMetadata &aMetadata); void AddHost(Host &aHost); void RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler); bool HasNameConflictsWith(Host &aHost) const; @@ -876,7 +882,7 @@ private: void HandleOutstandingUpdatesTimer(void); void HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError); - const UpdateMetadata *FindOutstandingUpdate(const Ip6::MessageInfo &aMessageInfo, uint16_t aDnsMessageId); + const UpdateMetadata *FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const; static const char * AddressModeToString(AddressMode aMode); Ip6::Udp::Socket mSocket;