1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes implementation for SRP server.
32  */
33 
34 #include "srp_server.hpp"
35 
36 #if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
37 
38 #include "common/instance.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/logging.hpp"
41 #include "common/new.hpp"
42 #include "common/random.hpp"
43 #include "net/dns_types.hpp"
44 #include "thread/thread_netif.hpp"
45 
46 namespace ot {
47 namespace Srp {
48 
49 static const char kDefaultDomain[]       = "default.service.arpa.";
50 static const char kServiceSubTypeLabel[] = "._sub.";
51 
ErrorToDnsResponseCode(Error aError)52 static Dns::UpdateHeader::Response ErrorToDnsResponseCode(Error aError)
53 {
54     Dns::UpdateHeader::Response responseCode;
55 
56     switch (aError)
57     {
58     case kErrorNone:
59         responseCode = Dns::UpdateHeader::kResponseSuccess;
60         break;
61     case kErrorNoBufs:
62         responseCode = Dns::UpdateHeader::kResponseServerFailure;
63         break;
64     case kErrorParse:
65         responseCode = Dns::UpdateHeader::kResponseFormatError;
66         break;
67     case kErrorDuplicated:
68         responseCode = Dns::UpdateHeader::kResponseNameExists;
69         break;
70     default:
71         responseCode = Dns::UpdateHeader::kResponseRefused;
72         break;
73     }
74 
75     return responseCode;
76 }
77 
78 //---------------------------------------------------------------------------------------------------------------------
79 // Server
80 
Server(Instance & aInstance)81 Server::Server(Instance &aInstance)
82     : InstanceLocator(aInstance)
83     , mSocket(aInstance)
84     , mServiceUpdateHandler(nullptr)
85     , mServiceUpdateHandlerContext(nullptr)
86     , mLeaseTimer(aInstance, HandleLeaseTimer)
87     , mOutstandingUpdatesTimer(aInstance, HandleOutstandingUpdatesTimer)
88     , mServiceUpdateId(Random::NonCrypto::GetUint32())
89     , mPort(kUdpPortMin)
90     , mState(kStateDisabled)
91     , mHasRegisteredAnyService(false)
92 {
93     IgnoreError(SetDomain(kDefaultDomain));
94 }
95 
SetServiceHandler(otSrpServerServiceUpdateHandler aServiceHandler,void * aServiceHandlerContext)96 void Server::SetServiceHandler(otSrpServerServiceUpdateHandler aServiceHandler, void *aServiceHandlerContext)
97 {
98     mServiceUpdateHandler        = aServiceHandler;
99     mServiceUpdateHandlerContext = aServiceHandlerContext;
100 }
101 
SetEnabled(bool aEnabled)102 void Server::SetEnabled(bool aEnabled)
103 {
104     if (aEnabled)
105     {
106         VerifyOrExit(mState == kStateDisabled);
107         mState = kStateStopped;
108 
109         // Select a port and then publish "DNS/SRP Unicast Address
110         // Service" in Thread Network Data using the device's
111         // mesh-local EID as the address. Then wait for callback
112         // `HandleNetDataPublisherEntryChange()` from to `Publisher` to
113         // start server operation when entry is published (i.e., added
114         // to the Network Data).
115 
116         SelectPort();
117         Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(mPort);
118     }
119     else
120     {
121         VerifyOrExit(mState != kStateDisabled);
122         Get<NetworkData::Publisher>().UnpublishDnsSrpService();
123         Stop();
124         mState = kStateDisabled;
125     }
126 
127 exit:
128     return;
129 }
130 
LeaseConfig(void)131 Server::LeaseConfig::LeaseConfig(void)
132 {
133     mMinLease    = kDefaultMinLease;
134     mMaxLease    = kDefaultMaxLease;
135     mMinKeyLease = kDefaultMinKeyLease;
136     mMaxKeyLease = kDefaultMaxKeyLease;
137 }
138 
IsValid(void) const139 bool Server::LeaseConfig::IsValid(void) const
140 {
141     bool valid = false;
142 
143     // TODO: Support longer LEASE.
144     // We use milliseconds timer for LEASE & KEY-LEASE, this is to avoid overflow.
145     VerifyOrExit(mMaxKeyLease <= Time::MsecToSec(TimerMilli::kMaxDelay));
146     VerifyOrExit(mMinLease <= mMaxLease);
147     VerifyOrExit(mMinKeyLease <= mMaxKeyLease);
148     VerifyOrExit(mMinLease <= mMinKeyLease);
149     VerifyOrExit(mMaxLease <= mMaxKeyLease);
150 
151     valid = true;
152 
153 exit:
154     return valid;
155 }
156 
GrantLease(uint32_t aLease) const157 uint32_t Server::LeaseConfig::GrantLease(uint32_t aLease) const
158 {
159     OT_ASSERT(mMinLease <= mMaxLease);
160 
161     return (aLease == 0) ? 0 : OT_MAX(mMinLease, OT_MIN(mMaxLease, aLease));
162 }
163 
GrantKeyLease(uint32_t aKeyLease) const164 uint32_t Server::LeaseConfig::GrantKeyLease(uint32_t aKeyLease) const
165 {
166     OT_ASSERT(mMinKeyLease <= mMaxKeyLease);
167 
168     return (aKeyLease == 0) ? 0 : OT_MAX(mMinKeyLease, OT_MIN(mMaxKeyLease, aKeyLease));
169 }
170 
SetLeaseConfig(const LeaseConfig & aLeaseConfig)171 Error Server::SetLeaseConfig(const LeaseConfig &aLeaseConfig)
172 {
173     Error error = kErrorNone;
174 
175     VerifyOrExit(aLeaseConfig.IsValid(), error = kErrorInvalidArgs);
176     mLeaseConfig = aLeaseConfig;
177 
178 exit:
179     return error;
180 }
181 
SetDomain(const char * aDomain)182 Error Server::SetDomain(const char *aDomain)
183 {
184     Error    error = kErrorNone;
185     uint16_t length;
186 
187     VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
188 
189     length = StringLength(aDomain, Dns::Name::kMaxNameSize);
190     VerifyOrExit((length > 0) && (length < Dns::Name::kMaxNameSize), error = kErrorInvalidArgs);
191 
192     if (aDomain[length - 1] == '.')
193     {
194         error = mDomain.Set(aDomain);
195     }
196     else
197     {
198         // Need to append dot at the end
199 
200         char buf[Dns::Name::kMaxNameSize];
201 
202         VerifyOrExit(length < Dns::Name::kMaxNameSize - 1, error = kErrorInvalidArgs);
203 
204         memcpy(buf, aDomain, length);
205         buf[length]     = '.';
206         buf[length + 1] = '\0';
207 
208         error = mDomain.Set(buf);
209     }
210 
211 exit:
212     return error;
213 }
214 
GetNextHost(const Server::Host * aHost)215 const Server::Host *Server::GetNextHost(const Server::Host *aHost)
216 {
217     return (aHost == nullptr) ? mHosts.GetHead() : aHost->GetNext();
218 }
219 
220 // This method adds a SRP service host and takes ownership of it.
221 // The caller MUST make sure that there is no existing host with the same hostname.
AddHost(Host & aHost)222 void Server::AddHost(Host &aHost)
223 {
224     OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr);
225     IgnoreError(mHosts.Add(aHost));
226 }
227 
RemoveHost(Host * aHost,bool aRetainName,bool aNotifyServiceHandler)228 void Server::RemoveHost(Host *aHost, bool aRetainName, bool aNotifyServiceHandler)
229 {
230     VerifyOrExit(aHost != nullptr);
231 
232     aHost->mLease = 0;
233     aHost->ClearResources();
234 
235     if (aRetainName)
236     {
237         otLogInfoSrp("[server] remove host '%s' (but retain its name)", aHost->GetFullName());
238     }
239     else
240     {
241         aHost->mKeyLease = 0;
242         IgnoreError(mHosts.Remove(*aHost));
243         otLogInfoSrp("[server] fully remove host '%s'", aHost->GetFullName());
244     }
245 
246     if (aNotifyServiceHandler && mServiceUpdateHandler != nullptr)
247     {
248         mServiceUpdateHandler(AllocateId(), aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
249         // We don't wait for the reply from the service update handler,
250         // but always remove the host (and its services) regardless of
251         // host/service update result. Because removing a host should fail
252         // only when there is system failure of the platform mDNS implementation
253         // and in which case the host is not expected to be still registered.
254     }
255 
256     if (!aRetainName)
257     {
258         aHost->Free();
259     }
260 
261 exit:
262     return;
263 }
264 
HasNameConflictsWith(Host & aHost) const265 bool Server::HasNameConflictsWith(Host &aHost) const
266 {
267     bool        hasConflicts = false;
268     const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
269 
270     if (existingHost != nullptr && *aHost.GetKey() != *existingHost->GetKey())
271     {
272         ExitNow(hasConflicts = true);
273     }
274 
275     for (const Service::Description &desc : aHost.mServiceDescriptions)
276     {
277         // Check on all hosts for a matching service description with
278         // the same instance name and if found, verify that it has the
279         // same key.
280 
281         for (const Host &host : mHosts)
282         {
283             if (host.FindServiceDescription(desc.GetInstanceName()) != nullptr)
284             {
285                 VerifyOrExit(*aHost.GetKey() == *host.GetKey(), hasConflicts = true);
286             }
287         }
288     }
289 
290 exit:
291     return hasConflicts;
292 }
293 
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)294 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
295 {
296     UpdateMetadata *update = mOutstandingUpdates.FindMatching(aId);
297 
298     if (update != nullptr)
299     {
300         HandleServiceUpdateResult(update, aError);
301     }
302     else
303     {
304         otLogInfoSrp("[server] delayed SRP host update result, the SRP update has been committed");
305     }
306 }
307 
HandleServiceUpdateResult(UpdateMetadata * aUpdate,Error aError)308 void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
309 {
310     IgnoreError(mOutstandingUpdates.Remove(*aUpdate));
311     CommitSrpUpdate(aError, aUpdate->GetDnsHeader(), aUpdate->GetHost(), aUpdate->GetMessageInfo());
312     aUpdate->Free();
313 
314     if (mOutstandingUpdates.IsEmpty())
315     {
316         mOutstandingUpdatesTimer.Stop();
317     }
318     else
319     {
320         mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0);
321     }
322 }
323 
CommitSrpUpdate(Error aError,const Dns::UpdateHeader & aDnsHeader,Host & aHost,const Ip6::MessageInfo & aMessageInfo)324 void Server::CommitSrpUpdate(Error                    aError,
325                              const Dns::UpdateHeader &aDnsHeader,
326                              Host &                   aHost,
327                              const Ip6::MessageInfo & aMessageInfo)
328 {
329     Host *   existingHost;
330     uint32_t hostLease;
331     uint32_t hostKeyLease;
332     uint32_t grantedLease;
333     uint32_t grantedKeyLease;
334     bool     shouldFreeHost = true;
335 
336     SuccessOrExit(aError);
337 
338     hostLease       = aHost.GetLease();
339     hostKeyLease    = aHost.GetKeyLease();
340     grantedLease    = mLeaseConfig.GrantLease(hostLease);
341     grantedKeyLease = mLeaseConfig.GrantKeyLease(hostKeyLease);
342 
343     aHost.SetLease(grantedLease);
344     aHost.SetKeyLease(grantedKeyLease);
345 
346     for (Service::Description &desc : aHost.mServiceDescriptions)
347     {
348         desc.mLease    = grantedLease;
349         desc.mKeyLease = grantedKeyLease;
350     }
351 
352     existingHost = mHosts.FindMatching(aHost.GetFullName());
353 
354     if (aHost.GetLease() == 0)
355     {
356         if (aHost.GetKeyLease() == 0)
357         {
358             otLogInfoSrp("[server] remove key of host %s", aHost.GetFullName());
359             RemoveHost(existingHost, /* aRetainName */ false, /* aNotifyServiceHandler */ false);
360         }
361         else if (existingHost != nullptr)
362         {
363             existingHost->SetKeyLease(aHost.GetKeyLease());
364             RemoveHost(existingHost, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
365 
366             for (Service &service : existingHost->mServices)
367             {
368                 existingHost->RemoveService(&service, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
369             }
370         }
371     }
372     else if (existingHost != nullptr)
373     {
374         SuccessOrExit(aError = existingHost->MergeServicesAndResourcesFrom(aHost));
375     }
376     else
377     {
378         otLogInfoSrp("[server] add new host %s", aHost.GetFullName());
379 
380         for (Service &service : aHost.GetServices())
381         {
382             service.mIsCommitted = true;
383             service.Log(Service::kAddNew);
384         }
385 
386         AddHost(aHost);
387         shouldFreeHost = false;
388 
389 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
390         if (!mHasRegisteredAnyService)
391         {
392             Settings::SrpServerInfo info;
393 
394             mHasRegisteredAnyService = true;
395             info.SetPort(mSocket.mSockName.mPort);
396             IgnoreError(Get<Settings>().Save(info));
397         }
398 #endif
399     }
400 
401     // Re-schedule the lease timer.
402     HandleLeaseTimer();
403 
404 exit:
405     if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
406     {
407         SendResponse(aDnsHeader, grantedLease, grantedKeyLease, aMessageInfo);
408     }
409     else
410     {
411         SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), aMessageInfo);
412     }
413 
414     if (shouldFreeHost)
415     {
416         aHost.Free();
417     }
418 }
419 
SelectPort(void)420 void Server::SelectPort(void)
421 {
422     mPort = kUdpPortMin;
423 
424 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
425     {
426         Settings::SrpServerInfo info;
427 
428         if (Get<Settings>().Read(info) == kErrorNone)
429         {
430             mPort = info.GetPort() + 1;
431             if (mPort < kUdpPortMin || mPort > kUdpPortMax)
432             {
433                 mPort = kUdpPortMin;
434             }
435         }
436     }
437 #endif
438 
439     otLogInfoSrp("[server] selected port %u", mPort);
440 }
441 
Start(void)442 void Server::Start(void)
443 {
444     Error error = kErrorNone;
445 
446     VerifyOrExit(mState == kStateStopped);
447 
448     mState = kStateRunning;
449 
450     SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
451     SuccessOrExit(error = mSocket.Bind(mPort, OT_NETIF_THREAD));
452 
453     otLogInfoSrp("[server] start listening on port %u", mPort);
454 
455 exit:
456     if (error != kErrorNone)
457     {
458         otLogCritSrp("[server] failed to start: %s", ErrorToString(error));
459         Stop();
460     }
461 }
462 
Stop(void)463 void Server::Stop(void)
464 {
465     VerifyOrExit(mState == kStateRunning);
466 
467     mState = kStateStopped;
468 
469     while (!mHosts.IsEmpty())
470     {
471         RemoveHost(mHosts.GetHead(), /* aRetainName */ false, /* aNotifyServiceHandler */ true);
472     }
473 
474     // TODO: We should cancel any outstanding service updates, but current
475     // OTBR mDNS publisher cannot properly handle it.
476     while (!mOutstandingUpdates.IsEmpty())
477     {
478         mOutstandingUpdates.Pop()->Free();
479     }
480 
481     mLeaseTimer.Stop();
482     mOutstandingUpdatesTimer.Stop();
483 
484     otLogInfoSrp("[server] stop listening on %u", mPort);
485     IgnoreError(mSocket.Close());
486     mHasRegisteredAnyService = false;
487 
488 exit:
489     return;
490 }
491 
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)492 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
493 {
494     switch (aEvent)
495     {
496     case NetworkData::Publisher::kEventEntryAdded:
497         Start();
498         break;
499 
500     case NetworkData::Publisher::kEventEntryRemoved:
501         Stop();
502         break;
503     }
504 }
505 
FindOutstandingUpdate(const Ip6::MessageInfo & aMessageInfo,uint16_t aDnsMessageId)506 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const Ip6::MessageInfo &aMessageInfo,
507                                                             uint16_t                aDnsMessageId)
508 {
509     const UpdateMetadata *ret = nullptr;
510 
511     for (const UpdateMetadata &update : mOutstandingUpdates)
512     {
513         if (aDnsMessageId == update.GetDnsHeader().GetMessageId() &&
514             aMessageInfo.GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
515             aMessageInfo.GetPeerPort() == update.GetMessageInfo().GetPeerPort())
516         {
517             ExitNow(ret = &update);
518         }
519     }
520 
521 exit:
522     return ret;
523 }
524 
HandleDnsUpdate(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Dns::UpdateHeader & aDnsHeader,uint16_t aOffset)525 void Server::HandleDnsUpdate(Message &                aMessage,
526                              const Ip6::MessageInfo & aMessageInfo,
527                              const Dns::UpdateHeader &aDnsHeader,
528                              uint16_t                 aOffset)
529 {
530     Error     error = kErrorNone;
531     Dns::Zone zone;
532     Host *    host = nullptr;
533 
534     otLogInfoSrp("[server] receive DNS update from %s", aMessageInfo.GetPeerAddr().ToString().AsCString());
535 
536     SuccessOrExit(error = ProcessZoneSection(aMessage, aDnsHeader, aOffset, zone));
537 
538     if (FindOutstandingUpdate(aMessageInfo, aDnsHeader.GetMessageId()) != nullptr)
539     {
540         otLogInfoSrp("[server] drop duplicated SRP update request: messageId=%hu", aDnsHeader.GetMessageId());
541 
542         // Silently drop duplicate requests.
543         // This could rarely happen, because the outstanding SRP update timer should
544         // be shorter than the SRP update retransmission timer.
545         ExitNow(error = kErrorNone);
546     }
547 
548     // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
549     VerifyOrExit(aDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
550 
551     host = Host::New(GetInstance());
552     VerifyOrExit(host != nullptr, error = kErrorNoBufs);
553     SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aDnsHeader, zone, aOffset));
554 
555     // Parse lease time and validate signature.
556     SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aDnsHeader, aOffset));
557 
558     HandleUpdate(aDnsHeader, *host, aMessageInfo);
559 
560 exit:
561     if (error != kErrorNone)
562     {
563         if (host != nullptr)
564         {
565             host->Free();
566         }
567 
568         SendResponse(aDnsHeader, ErrorToDnsResponseCode(error), aMessageInfo);
569     }
570 }
571 
ProcessZoneSection(const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,uint16_t & aOffset,Dns::Zone & aZone) const572 Error Server::ProcessZoneSection(const Message &          aMessage,
573                                  const Dns::UpdateHeader &aDnsHeader,
574                                  uint16_t &               aOffset,
575                                  Dns::Zone &              aZone) const
576 {
577     Error     error = kErrorNone;
578     char      name[Dns::Name::kMaxNameSize];
579     Dns::Zone zone;
580 
581     VerifyOrExit(aDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
582 
583     SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
584     // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
585     VerifyOrExit(strcmp(name, GetDomain()) == 0, error = kErrorSecurity);
586     SuccessOrExit(error = aMessage.Read(aOffset, zone));
587     aOffset += sizeof(zone);
588 
589     VerifyOrExit(zone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
590     aZone = zone;
591 
592 exit:
593     return error;
594 }
595 
ProcessUpdateSection(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t & aOffset) const596 Error Server::ProcessUpdateSection(Host &                   aHost,
597                                    const Message &          aMessage,
598                                    const Dns::UpdateHeader &aDnsHeader,
599                                    const Dns::Zone &        aZone,
600                                    uint16_t &               aOffset) const
601 {
602     Error error = kErrorNone;
603 
604     // Process Service Discovery, Host and Service Description Instructions with
605     // 3 times iterations over all DNS update RRs. The order of those processes matters.
606 
607     // 0. Enumerate over all Service Discovery Instructions before processing any other records.
608     // So that we will know whether a name is a hostname or service instance name when processing
609     // a "Delete All RRsets from a name" record.
610     error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset);
611     SuccessOrExit(error);
612 
613     // 1. Enumerate over all RRs to build the Host Description Instruction.
614     error = ProcessHostDescriptionInstruction(aHost, aMessage, aDnsHeader, aZone, aOffset);
615     SuccessOrExit(error);
616 
617     // 2. Enumerate over all RRs to build the Service Description Instructions.
618     error = ProcessServiceDescriptionInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset);
619     SuccessOrExit(error);
620 
621     // 3. Verify that there are no name conflicts.
622     VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
623 
624 exit:
625     return error;
626 }
627 
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t aOffset) const628 Error Server::ProcessHostDescriptionInstruction(Host &                   aHost,
629                                                 const Message &          aMessage,
630                                                 const Dns::UpdateHeader &aDnsHeader,
631                                                 const Dns::Zone &        aZone,
632                                                 uint16_t                 aOffset) const
633 {
634     Error error;
635 
636     OT_ASSERT(aHost.GetFullName() == nullptr);
637 
638     for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
639     {
640         char                name[Dns::Name::kMaxNameSize];
641         Dns::ResourceRecord record;
642 
643         SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
644 
645         SuccessOrExit(error = aMessage.Read(aOffset, record));
646 
647         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
648         {
649             // Delete All RRsets from a name.
650             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
651 
652             // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
653 
654             if (aHost.FindServiceDescription(name) == nullptr)
655             {
656                 // If host name is already set to a different name, `SetFullName()`
657                 // will return `kErrorFailed`.
658                 SuccessOrExit(error = aHost.SetFullName(name));
659                 aHost.ClearResources();
660             }
661         }
662         else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
663         {
664             Dns::AaaaRecord aaaaRecord;
665 
666             VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
667 
668             SuccessOrExit(error = aHost.SetFullName(name));
669 
670             SuccessOrExit(error = aMessage.Read(aOffset, aaaaRecord));
671             VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
672 
673             // Tolerate kErrorDrop for AAAA Resources.
674             VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
675         }
676         else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
677         {
678             // We currently support only ECDSA P-256.
679             Dns::Ecdsa256KeyRecord key;
680 
681             VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
682             SuccessOrExit(error = aMessage.Read(aOffset, key));
683             VerifyOrExit(key.IsValid(), error = kErrorParse);
684 
685             VerifyOrExit(aHost.GetKey() == nullptr || *aHost.GetKey() == key, error = kErrorSecurity);
686             aHost.SetKey(key);
687         }
688 
689         aOffset += record.GetSize();
690     }
691 
692     // Verify that we have a complete Host Description Instruction.
693 
694     VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
695     VerifyOrExit(aHost.GetKey() != nullptr, error = kErrorFailed);
696 
697     // We check the number of host addresses after processing of the
698     // Lease Option in the Addition Section and determining whether
699     // the host is being removed or registered.
700 
701 exit:
702     return error;
703 }
704 
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t aOffset) const705 Error Server::ProcessServiceDiscoveryInstructions(Host &                   aHost,
706                                                   const Message &          aMessage,
707                                                   const Dns::UpdateHeader &aDnsHeader,
708                                                   const Dns::Zone &        aZone,
709                                                   uint16_t                 aOffset) const
710 {
711     Error error = kErrorNone;
712 
713     for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
714     {
715         char           serviceName[Dns::Name::kMaxNameSize];
716         char           instanceName[Dns::Name::kMaxNameSize];
717         Dns::PtrRecord ptrRecord;
718         const char *   subServiceName;
719         Service *      service;
720         bool           isSubType;
721 
722         SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, serviceName, sizeof(serviceName)));
723         VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
724 
725         error = Dns::ResourceRecord::ReadRecord(aMessage, aOffset, ptrRecord);
726 
727         if (error == kErrorNotFound)
728         {
729             // `ReadRecord()` updates `aOffset` to skip over a
730             // non-matching record.
731             error = kErrorNone;
732             continue;
733         }
734 
735         SuccessOrExit(error);
736 
737         SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, instanceName, sizeof(instanceName)));
738 
739         VerifyOrExit(ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone ||
740                          ptrRecord.GetClass() == aZone.GetClass(),
741                      error = kErrorFailed);
742 
743         // Check if the `serviceName` is a subtype with the name
744         // format: "<sub-label>._sub.<service-labels>.<domain>."
745 
746         subServiceName = StringFind(serviceName, kServiceSubTypeLabel);
747         isSubType      = (subServiceName != nullptr);
748 
749         if (isSubType)
750         {
751             // Skip over the "._sub." label to get to the base
752             // service name.
753             subServiceName += sizeof(kServiceSubTypeLabel) - 1;
754         }
755 
756         // Verify that instance name and service name are related.
757 
758         VerifyOrExit(StringEndsWith(instanceName, isSubType ? subServiceName : serviceName), error = kErrorFailed);
759 
760         // Ensure the same service does not exist already.
761         VerifyOrExit(aHost.FindService(serviceName, instanceName) == nullptr, error = kErrorFailed);
762 
763         service = aHost.AddNewService(serviceName, instanceName, isSubType);
764         VerifyOrExit(service != nullptr, error = kErrorNoBufs);
765 
766         // This RR is a "Delete an RR from an RRset" update when the CLASS is NONE.
767         service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
768     }
769 
770 exit:
771     return error;
772 }
773 
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t & aOffset) const774 Error Server::ProcessServiceDescriptionInstructions(Host &                   aHost,
775                                                     const Message &          aMessage,
776                                                     const Dns::UpdateHeader &aDnsHeader,
777                                                     const Dns::Zone &        aZone,
778                                                     uint16_t &               aOffset) const
779 {
780     Error     error = kErrorNone;
781     TimeMilli now   = TimerMilli::GetNow();
782 
783     for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
784     {
785         Service::Description *desc;
786         char                  name[Dns::Name::kMaxNameSize];
787         Dns::ResourceRecord   record;
788 
789         SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
790         SuccessOrExit(error = aMessage.Read(aOffset, record));
791 
792         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
793         {
794             // Delete All RRsets from a name.
795             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
796 
797             desc = aHost.FindServiceDescription(name);
798 
799             if (desc != nullptr)
800             {
801                 desc->ClearResources();
802                 desc->mTimeLastUpdate = now;
803             }
804 
805             aOffset += record.GetSize();
806             continue;
807         }
808 
809         if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
810         {
811             Dns::SrvRecord srvRecord;
812             char           hostName[Dns::Name::kMaxNameSize];
813             uint16_t       hostNameLength = sizeof(hostName);
814 
815             VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
816             SuccessOrExit(error = aMessage.Read(aOffset, srvRecord));
817             aOffset += sizeof(srvRecord);
818 
819             SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, hostName, hostNameLength));
820             VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
821             VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
822 
823             desc = aHost.FindServiceDescription(name);
824             VerifyOrExit(desc != nullptr, error = kErrorFailed);
825 
826             // Make sure that this is the first SRV RR for this service description
827             VerifyOrExit(desc->mPort == 0, error = kErrorFailed);
828             desc->mPriority       = srvRecord.GetPriority();
829             desc->mWeight         = srvRecord.GetWeight();
830             desc->mPort           = srvRecord.GetPort();
831             desc->mTimeLastUpdate = now;
832         }
833         else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
834         {
835             VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
836 
837             desc = aHost.FindServiceDescription(name);
838             VerifyOrExit(desc != nullptr, error = kErrorFailed);
839 
840             aOffset += sizeof(record);
841             SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, aOffset, record.GetLength()));
842             aOffset += record.GetLength();
843         }
844         else
845         {
846             aOffset += record.GetSize();
847         }
848     }
849 
850     // Verify that all service descriptions on `aHost` are updated. Note
851     // that `mTimeLastUpdate` on a new `Service::Description` is set to
852     // `GetNow().GetDistantPast()`.
853 
854     for (Service::Description &desc : aHost.mServiceDescriptions)
855     {
856         VerifyOrExit(desc.mTimeLastUpdate == now, error = kErrorFailed);
857 
858         // Check that either both `mPort` and `mTxtData` are set
859         // (i.e., we saw both SRV and TXT record) or both are default
860         // (cleared) value (i.e., we saw neither of them).
861 
862         VerifyOrExit((desc.mPort == 0) == (desc.mTxtData == nullptr), error = kErrorFailed);
863     }
864 
865 exit:
866     return error;
867 }
868 
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)869 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
870 {
871     return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
872            aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
873 }
874 
ProcessAdditionalSection(Host * aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,uint16_t & aOffset) const875 Error Server::ProcessAdditionalSection(Host *                   aHost,
876                                        const Message &          aMessage,
877                                        const Dns::UpdateHeader &aDnsHeader,
878                                        uint16_t &               aOffset) const
879 {
880     Error            error = kErrorNone;
881     Dns::OptRecord   optRecord;
882     Dns::LeaseOption leaseOption;
883     Dns::SigRecord   sigRecord;
884     char             name[2]; // The root domain name (".") is expected.
885     uint16_t         sigOffset;
886     uint16_t         sigRdataOffset;
887     char             signerName[Dns::Name::kMaxNameSize];
888     uint16_t         signatureLength;
889 
890     VerifyOrExit(aDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
891 
892     // EDNS(0) Update Lease Option.
893 
894     SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
895     SuccessOrExit(error = aMessage.Read(aOffset, optRecord));
896     SuccessOrExit(error = aMessage.Read(aOffset + sizeof(optRecord), leaseOption));
897     VerifyOrExit(leaseOption.IsValid(), error = kErrorFailed);
898     VerifyOrExit(optRecord.GetSize() == sizeof(optRecord) + sizeof(leaseOption), error = kErrorParse);
899 
900     aOffset += optRecord.GetSize();
901 
902     aHost->SetLease(leaseOption.GetLeaseInterval());
903     aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
904 
905     if (aHost->GetLease() > 0)
906     {
907         uint8_t hostAddressesNum;
908 
909         aHost->GetAddresses(hostAddressesNum);
910 
911         // There MUST be at least one valid address if we have nonzero lease.
912         VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
913     }
914 
915     // SIG(0).
916 
917     sigOffset = aOffset;
918     SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
919     SuccessOrExit(error = aMessage.Read(aOffset, sigRecord));
920     VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
921 
922     sigRdataOffset = aOffset + sizeof(Dns::ResourceRecord);
923     aOffset += sizeof(sigRecord);
924 
925     // TODO: Verify that the signature doesn't expire. This is not
926     // implemented because the end device may not be able to get
927     // the synchronized date/time.
928 
929     SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, signerName, sizeof(signerName)));
930 
931     signatureLength = sigRecord.GetLength() - (aOffset - sigRdataOffset);
932     aOffset += signatureLength;
933 
934     // Verify the signature. Currently supports only ECDSA.
935 
936     VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
937     VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
938     VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
939 
940     SuccessOrExit(error = VerifySignature(*aHost->GetKey(), aMessage, aDnsHeader, sigOffset, sigRdataOffset,
941                                           sigRecord.GetLength(), signerName));
942 
943 exit:
944     return error;
945 }
946 
VerifySignature(const Dns::Ecdsa256KeyRecord & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const947 Error Server::VerifySignature(const Dns::Ecdsa256KeyRecord &aKey,
948                               const Message &               aMessage,
949                               Dns::UpdateHeader             aDnsHeader,
950                               uint16_t                      aSigOffset,
951                               uint16_t                      aSigRdataOffset,
952                               uint16_t                      aSigRdataLength,
953                               const char *                  aSignerName) const
954 {
955     Error                          error;
956     uint16_t                       offset = aMessage.GetOffset();
957     uint16_t                       signatureOffset;
958     Crypto::Sha256                 sha256;
959     Crypto::Sha256::Hash           hash;
960     Crypto::Ecdsa::P256::Signature signature;
961     Message *                      signerNameMessage = nullptr;
962 
963     VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
964 
965     sha256.Start();
966 
967     // SIG RDATA less signature.
968     sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
969 
970     // The uncompressed (canonical) form of the signer name should be used for signature
971     // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
972     signerNameMessage = Get<Ip6::Udp>().NewMessage(0);
973     VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
974     SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
975     sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
976 
977     // We need the DNS header before appending the SIG RR.
978     aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
979     sha256.Update(aDnsHeader);
980     sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
981 
982     sha256.Finish(hash);
983 
984     signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
985     SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
986 
987     error = aKey.GetKey().Verify(hash, signature);
988 
989 exit:
990     FreeMessage(signerNameMessage);
991     return error;
992 }
993 
HandleUpdate(const Dns::UpdateHeader & aDnsHeader,Host & aHost,const Ip6::MessageInfo & aMessageInfo)994 void Server::HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host &aHost, const Ip6::MessageInfo &aMessageInfo)
995 {
996     Error error = kErrorNone;
997     Host *existingHost;
998 
999     // Check whether the SRP update wants to remove `aHost`.
1000 
1001     VerifyOrExit(aHost.GetLease() == 0);
1002 
1003     aHost.ClearResources();
1004 
1005     existingHost = mHosts.FindMatching(aHost.GetFullName());
1006     VerifyOrExit(existingHost != nullptr);
1007 
1008     // The client may not include all services it has registered before
1009     // when removing a host. We copy and append any missing services to
1010     // `aHost` from the `existingHost` and mark them as deleted.
1011 
1012     for (Service &service : existingHost->mServices)
1013     {
1014         if (service.mIsDeleted)
1015         {
1016             continue;
1017         }
1018 
1019         if (aHost.FindService(service.GetServiceName(), service.GetInstanceName()) == nullptr)
1020         {
1021             Service *newService =
1022                 aHost.AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType());
1023 
1024             VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
1025             newService->mDescription.mTimeLastUpdate = TimerMilli::GetNow();
1026             newService->mIsDeleted                   = true;
1027         }
1028     }
1029 
1030 exit:
1031     if (error != kErrorNone)
1032     {
1033         CommitSrpUpdate(error, aDnsHeader, aHost, aMessageInfo);
1034     }
1035     else if (mServiceUpdateHandler != nullptr)
1036     {
1037         UpdateMetadata *update = UpdateMetadata::New(GetInstance(), aDnsHeader, &aHost, aMessageInfo);
1038 
1039         IgnoreError(mOutstandingUpdates.Add(*update));
1040         mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0);
1041 
1042         mServiceUpdateHandler(update->GetId(), &aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
1043     }
1044     else
1045     {
1046         CommitSrpUpdate(kErrorNone, aDnsHeader, aHost, aMessageInfo);
1047     }
1048 }
1049 
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1050 void Server::SendResponse(const Dns::UpdateHeader &   aHeader,
1051                           Dns::UpdateHeader::Response aResponseCode,
1052                           const Ip6::MessageInfo &    aMessageInfo)
1053 {
1054     Error             error;
1055     Message *         response = nullptr;
1056     Dns::UpdateHeader header;
1057 
1058     response = mSocket.NewMessage(0);
1059     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1060 
1061     header.SetMessageId(aHeader.GetMessageId());
1062     header.SetType(Dns::UpdateHeader::kTypeResponse);
1063     header.SetQueryType(aHeader.GetQueryType());
1064     header.SetResponseCode(aResponseCode);
1065     SuccessOrExit(error = response->Append(header));
1066 
1067     SuccessOrExit(error = mSocket.SendTo(*response, aMessageInfo));
1068 
1069     if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1070     {
1071         otLogInfoSrp("[server] send fail response: %d", aResponseCode);
1072     }
1073     else
1074     {
1075         otLogInfoSrp("[server] send success response");
1076     }
1077 
1078 exit:
1079     if (error != kErrorNone)
1080     {
1081         otLogWarnSrp("[server] failed to send response: %s", ErrorToString(error));
1082         FreeMessage(response);
1083     }
1084 }
1085 
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,const Ip6::MessageInfo & aMessageInfo)1086 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1087                           uint32_t                 aLease,
1088                           uint32_t                 aKeyLease,
1089                           const Ip6::MessageInfo & aMessageInfo)
1090 {
1091     Error             error;
1092     Message *         response = nullptr;
1093     Dns::UpdateHeader header;
1094     Dns::OptRecord    optRecord;
1095     Dns::LeaseOption  leaseOption;
1096 
1097     response = mSocket.NewMessage(0);
1098     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1099 
1100     header.SetMessageId(aHeader.GetMessageId());
1101     header.SetType(Dns::UpdateHeader::kTypeResponse);
1102     header.SetQueryType(aHeader.GetQueryType());
1103     header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1104     header.SetAdditionalRecordCount(1);
1105     SuccessOrExit(error = response->Append(header));
1106 
1107     // Append the root domain (".").
1108     SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1109 
1110     optRecord.Init();
1111     optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1112     optRecord.SetDnsSecurityFlag();
1113     optRecord.SetLength(sizeof(Dns::LeaseOption));
1114     SuccessOrExit(error = response->Append(optRecord));
1115 
1116     leaseOption.Init();
1117     leaseOption.SetLeaseInterval(aLease);
1118     leaseOption.SetKeyLeaseInterval(aKeyLease);
1119     SuccessOrExit(error = response->Append(leaseOption));
1120 
1121     SuccessOrExit(error = mSocket.SendTo(*response, aMessageInfo));
1122 
1123     otLogInfoSrp("[server] send response with granted lease: %u and key lease: %u", aLease, aKeyLease);
1124 
1125 exit:
1126     if (error != kErrorNone)
1127     {
1128         otLogWarnSrp("[server] failed to send response: %s", ErrorToString(error));
1129         FreeMessage(response);
1130     }
1131 }
1132 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1133 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1134 {
1135     static_cast<Server *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
1136                                                       *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
1137 }
1138 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1139 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1140 {
1141     Error             error;
1142     Dns::UpdateHeader dnsHeader;
1143     uint16_t          offset = aMessage.GetOffset();
1144 
1145     SuccessOrExit(error = aMessage.Read(offset, dnsHeader));
1146     offset += sizeof(dnsHeader);
1147 
1148     // Handles only queries.
1149     VerifyOrExit(dnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1150 
1151     switch (dnsHeader.GetQueryType())
1152     {
1153     case Dns::UpdateHeader::kQueryTypeUpdate:
1154         HandleDnsUpdate(aMessage, aMessageInfo, dnsHeader, offset);
1155         break;
1156     default:
1157         error = kErrorDrop;
1158         break;
1159     }
1160 
1161 exit:
1162     if (error != kErrorNone)
1163     {
1164         otLogInfoSrp("[server] failed to handle DNS message: %s", ErrorToString(error));
1165     }
1166 }
1167 
HandleLeaseTimer(Timer & aTimer)1168 void Server::HandleLeaseTimer(Timer &aTimer)
1169 {
1170     aTimer.Get<Server>().HandleLeaseTimer();
1171 }
1172 
HandleLeaseTimer(void)1173 void Server::HandleLeaseTimer(void)
1174 {
1175     TimeMilli now                = TimerMilli::GetNow();
1176     TimeMilli earliestExpireTime = now.GetDistantFuture();
1177     Host *    nextHost;
1178 
1179     for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1180     {
1181         nextHost = host->GetNext();
1182 
1183         if (host->GetKeyExpireTime() <= now)
1184         {
1185             otLogInfoSrp("[server] KEY LEASE of host %s expired", host->GetFullName());
1186 
1187             // Removes the whole host and all services if the KEY RR expired.
1188             RemoveHost(host, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1189         }
1190         else if (host->IsDeleted())
1191         {
1192             // The host has been deleted, but the hostname & service instance names retain.
1193 
1194             Service *next;
1195 
1196             earliestExpireTime = OT_MIN(earliestExpireTime, host->GetKeyExpireTime());
1197 
1198             // Check if any service instance name expired.
1199             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1200             {
1201                 next = service->GetNext();
1202 
1203                 OT_ASSERT(service->mIsDeleted);
1204 
1205                 if (service->GetKeyExpireTime() <= now)
1206                 {
1207                     service->Log(Service::kKeyLeaseExpired);
1208                     host->RemoveService(service, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1209                 }
1210                 else
1211                 {
1212                     earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1213                 }
1214             }
1215         }
1216         else if (host->GetExpireTime() <= now)
1217         {
1218             otLogInfoSrp("[server] LEASE of host %s expired", host->GetFullName());
1219 
1220             // If the host expired, delete all resources of this host and its services.
1221             for (Service &service : host->mServices)
1222             {
1223                 // Don't need to notify the service handler as `RemoveHost` at below will do.
1224                 host->RemoveService(&service, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
1225             }
1226 
1227             RemoveHost(host, /* aRetainName */ true, /* aNotifyServiceHandler */ true);
1228 
1229             earliestExpireTime = OT_MIN(earliestExpireTime, host->GetKeyExpireTime());
1230         }
1231         else
1232         {
1233             // The host doesn't expire, check if any service expired or is explicitly removed.
1234 
1235             Service *next;
1236 
1237             OT_ASSERT(!host->IsDeleted());
1238 
1239             earliestExpireTime = OT_MIN(earliestExpireTime, host->GetExpireTime());
1240 
1241             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1242             {
1243                 next = service->GetNext();
1244 
1245                 if (service->GetKeyExpireTime() <= now)
1246                 {
1247                     service->Log(Service::kKeyLeaseExpired);
1248                     host->RemoveService(service, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1249                 }
1250                 else if (service->mIsDeleted)
1251                 {
1252                     // The service has been deleted but the name retains.
1253                     earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1254                 }
1255                 else if (service->GetExpireTime() <= now)
1256                 {
1257                     service->Log(Service::kLeaseExpired);
1258 
1259                     // The service is expired, delete it.
1260                     host->RemoveService(service, /* aRetainName */ true, /* aNotifyServiceHandler */ true);
1261                     earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1262                 }
1263                 else
1264                 {
1265                     earliestExpireTime = OT_MIN(earliestExpireTime, service->GetExpireTime());
1266                 }
1267             }
1268         }
1269     }
1270 
1271     if (earliestExpireTime != now.GetDistantFuture())
1272     {
1273         OT_ASSERT(earliestExpireTime >= now);
1274         if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1275         {
1276             otLogInfoSrp("[server] lease timer is scheduled for %u seconds", Time::MsecToSec(earliestExpireTime - now));
1277             mLeaseTimer.StartAt(earliestExpireTime, 0);
1278         }
1279     }
1280     else
1281     {
1282         otLogInfoSrp("[server] lease timer is stopped");
1283         mLeaseTimer.Stop();
1284     }
1285 }
1286 
HandleOutstandingUpdatesTimer(Timer & aTimer)1287 void Server::HandleOutstandingUpdatesTimer(Timer &aTimer)
1288 {
1289     aTimer.Get<Server>().HandleOutstandingUpdatesTimer();
1290 }
1291 
HandleOutstandingUpdatesTimer(void)1292 void Server::HandleOutstandingUpdatesTimer(void)
1293 {
1294     otLogInfoSrp("[server] outstanding service update timeout");
1295     while (!mOutstandingUpdates.IsEmpty() && mOutstandingUpdates.GetTail()->GetExpireTime() <= TimerMilli::GetNow())
1296     {
1297         HandleServiceUpdateResult(mOutstandingUpdates.GetTail(), kErrorResponseTimeout);
1298     }
1299 }
1300 
1301 //---------------------------------------------------------------------------------------------------------------------
1302 // Server::Service
1303 
New(const char * aServiceName,Description & aDescription,bool aIsSubType)1304 Server::Service *Server::Service::New(const char *aServiceName, Description &aDescription, bool aIsSubType)
1305 {
1306     void *   buf;
1307     Service *service = nullptr;
1308 
1309     buf = Instance::HeapCAlloc(1, sizeof(Service));
1310     VerifyOrExit(buf != nullptr);
1311 
1312     service = new (buf) Service(aDescription, aIsSubType);
1313 
1314     if (service->mServiceName.Set(aServiceName) != kErrorNone)
1315     {
1316         service->Free();
1317         service = nullptr;
1318     }
1319 
1320 exit:
1321     return service;
1322 }
1323 
Free(void)1324 void Server::Service::Free(void)
1325 {
1326     Instance::HeapFree(this);
1327 }
1328 
Service(Description & aDescription,bool aIsSubType)1329 Server::Service::Service(Description &aDescription, bool aIsSubType)
1330     : mDescription(aDescription)
1331     , mNext(nullptr)
1332     , mTimeLastUpdate(TimerMilli::GetNow())
1333     , mIsDeleted(false)
1334     , mIsSubType(aIsSubType)
1335     , mIsCommitted(false)
1336 {
1337 }
1338 
GetServiceSubTypeLabel(char * aLabel,uint8_t aMaxSize) const1339 Error Server::Service::GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const
1340 {
1341     Error       error       = kErrorNone;
1342     const char *serviceName = GetServiceName();
1343     const char *subServiceName;
1344     uint8_t     labelLength;
1345 
1346     memset(aLabel, 0, aMaxSize);
1347 
1348     VerifyOrExit(IsSubType(), error = kErrorInvalidArgs);
1349 
1350     subServiceName = StringFind(serviceName, kServiceSubTypeLabel);
1351     OT_ASSERT(subServiceName != nullptr);
1352 
1353     if (subServiceName - serviceName < aMaxSize)
1354     {
1355         labelLength = static_cast<uint8_t>(subServiceName - serviceName);
1356     }
1357     else
1358     {
1359         labelLength = aMaxSize - 1;
1360         error       = kErrorNoBufs;
1361     }
1362 
1363     memcpy(aLabel, serviceName, labelLength);
1364 
1365 exit:
1366     return error;
1367 }
1368 
GetExpireTime(void) const1369 TimeMilli Server::Service::GetExpireTime(void) const
1370 {
1371     OT_ASSERT(!mIsDeleted);
1372     OT_ASSERT(!GetHost().IsDeleted());
1373 
1374     return mTimeLastUpdate + Time::SecToMsec(mDescription.mLease);
1375 }
1376 
GetKeyExpireTime(void) const1377 TimeMilli Server::Service::GetKeyExpireTime(void) const
1378 {
1379     return mTimeLastUpdate + Time::SecToMsec(mDescription.mKeyLease);
1380 }
1381 
MatchesFlags(Flags aFlags) const1382 bool Server::Service::MatchesFlags(Flags aFlags) const
1383 {
1384     bool matches = false;
1385 
1386     if (IsSubType())
1387     {
1388         VerifyOrExit(aFlags & kFlagSubType);
1389     }
1390     else
1391     {
1392         VerifyOrExit(aFlags & kFlagBaseType);
1393     }
1394 
1395     if (IsDeleted())
1396     {
1397         VerifyOrExit(aFlags & kFlagDeleted);
1398     }
1399     else
1400     {
1401         VerifyOrExit(aFlags & kFlagActive);
1402     }
1403 
1404     matches = true;
1405 
1406 exit:
1407     return matches;
1408 }
1409 
1410 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_SRP
Log(Action aAction) const1411 void Server::Service::Log(Action aAction) const
1412 {
1413     static const char *const kActionStrings[] = {
1414         "add new",                   // (0) kAddNew
1415         "update existing",           // (1) kUpdateExisting
1416         "remove but retain name of", // (2) kRemoveButRetainName
1417         "full remove",               // (3) kFullyRemove
1418         "LEASE expired for ",        // (4) kLeaseExpired
1419         "KEY LEASE expired for",     // (5) kKeyLeaseExpired
1420     };
1421 
1422     char subLabel[Dns::Name::kMaxLabelSize];
1423 
1424     static_assert(0 == kAddNew, "kAddNew value is incorrect");
1425     static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1426     static_assert(2 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1427     static_assert(3 == kFullyRemove, "kFullyRemove value is incorrect");
1428     static_assert(4 == kLeaseExpired, "kLeaseExpired value is incorrect");
1429     static_assert(5 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1430 
1431     // We only log if the `Service` is marked as committed. This
1432     // ensures that temporary `Service` entries associated with a
1433     // newly received SRP update message are not logged (e.g., when
1434     // associated `Host` is being freed).
1435 
1436     if (mIsCommitted)
1437     {
1438         IgnoreError(GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
1439 
1440         otLogInfoSrp("[server] %s service '%s'%s%s", kActionStrings[aAction], GetInstanceName(),
1441                      IsSubType() ? " subtype:" : "", subLabel);
1442     }
1443 }
1444 #else
Log(Action) const1445 void Server::Service::Log(Action) const
1446 {
1447 }
1448 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_SRP
1449 
1450 //---------------------------------------------------------------------------------------------------------------------
1451 // Server::Service::Description
1452 
New(const char * aInstanceName,Host & aHost)1453 Server::Service::Description *Server::Service::Description::New(const char *aInstanceName, Host &aHost)
1454 {
1455     void *       buf;
1456     Description *desc = nullptr;
1457 
1458     buf = Instance::HeapCAlloc(1, sizeof(Description));
1459     VerifyOrExit(buf != nullptr);
1460 
1461     desc = new (buf) Description(aHost);
1462 
1463     if (desc->mInstanceName.Set(aInstanceName) != kErrorNone)
1464     {
1465         desc->Free();
1466         desc = nullptr;
1467     }
1468 
1469 exit:
1470     return desc;
1471 }
1472 
Free(void)1473 void Server::Service::Description::Free(void)
1474 {
1475     mInstanceName.Free();
1476     Instance::HeapFree(this);
1477 }
1478 
Description(Host & aHost)1479 Server::Service::Description::Description(Host &aHost)
1480     : mNext(nullptr)
1481     , mHost(aHost)
1482     , mPriority(0)
1483     , mWeight(0)
1484     , mPort(0)
1485     , mTxtLength(0)
1486     , mTxtData(nullptr)
1487     , mLease(0)
1488     , mKeyLease(0)
1489     , mTimeLastUpdate(TimerMilli::GetNow().GetDistantPast())
1490 {
1491 }
1492 
ClearResources(void)1493 void Server::Service::Description::ClearResources(void)
1494 {
1495     mPort = 0;
1496     Instance::HeapFree(mTxtData);
1497     mTxtData   = nullptr;
1498     mTxtLength = 0;
1499 }
1500 
TakeResourcesFrom(Description & aDescription)1501 void Server::Service::Description::TakeResourcesFrom(Description &aDescription)
1502 {
1503     // Take ownership and move the heap allocated `mTxtData` buffer
1504     // from `aDescription
1505     Instance::HeapFree(mTxtData);
1506     mTxtData                = aDescription.mTxtData;
1507     mTxtLength              = aDescription.mTxtLength;
1508     aDescription.mTxtData   = nullptr;
1509     aDescription.mTxtLength = 0;
1510 
1511     mPriority = aDescription.mPriority;
1512     mWeight   = aDescription.mWeight;
1513     mPort     = aDescription.mPort;
1514 
1515     mLease          = aDescription.mLease;
1516     mKeyLease       = aDescription.mKeyLease;
1517     mTimeLastUpdate = TimerMilli::GetNow();
1518 }
1519 
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1520 Error Server::Service::Description::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1521 {
1522     Error    error = kErrorNone;
1523     uint8_t *txtData;
1524 
1525     txtData = static_cast<uint8_t *>(Instance::HeapCAlloc(1, aLength));
1526     VerifyOrExit(txtData != nullptr, error = kErrorNoBufs);
1527 
1528     VerifyOrExit(aMessage.ReadBytes(aOffset, txtData, aLength) == aLength, error = kErrorParse);
1529     VerifyOrExit(Dns::TxtRecord::VerifyTxtData(txtData, aLength), error = kErrorParse);
1530 
1531     Instance::HeapFree(mTxtData);
1532     mTxtData   = txtData;
1533     mTxtLength = aLength;
1534 
1535 exit:
1536     if (error != kErrorNone)
1537     {
1538         Instance::HeapFree(txtData);
1539     }
1540 
1541     return error;
1542 }
1543 
1544 //---------------------------------------------------------------------------------------------------------------------
1545 // Server::Host
1546 
New(Instance & aInstance)1547 Server::Host *Server::Host::New(Instance &aInstance)
1548 {
1549     void *buf;
1550     Host *host = nullptr;
1551 
1552     buf = Instance::HeapCAlloc(1, sizeof(Host));
1553     VerifyOrExit(buf != nullptr);
1554 
1555     host = new (buf) Host(aInstance);
1556 
1557 exit:
1558     return host;
1559 }
1560 
Free(void)1561 void Server::Host::Free(void)
1562 {
1563     FreeAllServices();
1564     mFullName.Free();
1565     Instance::HeapFree(this);
1566 }
1567 
Host(Instance & aInstance)1568 Server::Host::Host(Instance &aInstance)
1569     : InstanceLocator(aInstance)
1570     , mAddressesNum(0)
1571     , mNext(nullptr)
1572     , mLease(0)
1573     , mKeyLease(0)
1574     , mTimeLastUpdate(TimerMilli::GetNow())
1575 {
1576     mKey.Clear();
1577 }
1578 
SetFullName(const char * aFullName)1579 Error Server::Host::SetFullName(const char *aFullName)
1580 {
1581     // `mFullName` becomes immutable after it is set, so if it is
1582     // already set, we only accept a `aFullName` that matches the
1583     // current name.
1584 
1585     Error error;
1586 
1587     if (mFullName.IsNull())
1588     {
1589         error = mFullName.Set(aFullName);
1590     }
1591     else
1592     {
1593         error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1594     }
1595 
1596     return error;
1597 }
1598 
SetKey(Dns::Ecdsa256KeyRecord & aKey)1599 void Server::Host::SetKey(Dns::Ecdsa256KeyRecord &aKey)
1600 {
1601     OT_ASSERT(aKey.IsValid());
1602 
1603     mKey = aKey;
1604 }
1605 
GetExpireTime(void) const1606 TimeMilli Server::Host::GetExpireTime(void) const
1607 {
1608     OT_ASSERT(!IsDeleted());
1609 
1610     return mTimeLastUpdate + Time::SecToMsec(mLease);
1611 }
1612 
GetKeyExpireTime(void) const1613 TimeMilli Server::Host::GetKeyExpireTime(void) const
1614 {
1615     return mTimeLastUpdate + Time::SecToMsec(mKeyLease);
1616 }
1617 
FindNextService(const Service * aPrevService,Service::Flags aFlags,const char * aServiceName,const char * aInstanceName) const1618 const Server::Service *Server::Host::FindNextService(const Service *aPrevService,
1619                                                      Service::Flags aFlags,
1620                                                      const char *   aServiceName,
1621                                                      const char *   aInstanceName) const
1622 {
1623     const Service *service = (aPrevService == nullptr) ? GetServices().GetHead() : aPrevService->GetNext();
1624 
1625     for (; service != nullptr; service = service->GetNext())
1626     {
1627         if (!service->MatchesFlags(aFlags))
1628         {
1629             continue;
1630         }
1631 
1632         if ((aServiceName != nullptr) && !service->MatchesServiceName(aServiceName))
1633         {
1634             continue;
1635         }
1636 
1637         if ((aInstanceName != nullptr) && !service->MatchesInstanceName(aInstanceName))
1638         {
1639             continue;
1640         }
1641 
1642         break;
1643     }
1644 
1645     return service;
1646 }
1647 
AddNewService(const char * aServiceName,const char * aInstanceName,bool aIsSubType)1648 Server::Service *Server::Host::AddNewService(const char *aServiceName, const char *aInstanceName, bool aIsSubType)
1649 {
1650     Service *             service = nullptr;
1651     Service::Description *desc;
1652 
1653     desc = FindServiceDescription(aInstanceName);
1654 
1655     if (desc == nullptr)
1656     {
1657         desc = Service::Description::New(aInstanceName, *this);
1658         VerifyOrExit(desc != nullptr);
1659         mServiceDescriptions.Push(*desc);
1660     }
1661 
1662     service = Service::New(aServiceName, *desc, aIsSubType);
1663     VerifyOrExit(service != nullptr);
1664 
1665     mServices.Push(*service);
1666 
1667 exit:
1668     return service;
1669 }
1670 
RemoveService(Service * aService,bool aRetainName,bool aNotifyServiceHandler)1671 void Server::Host::RemoveService(Service *aService, bool aRetainName, bool aNotifyServiceHandler)
1672 {
1673     Server &server = Get<Server>();
1674 
1675     VerifyOrExit(aService != nullptr);
1676 
1677     aService->mIsDeleted = true;
1678 
1679     aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
1680 
1681     if (aNotifyServiceHandler && server.mServiceUpdateHandler != nullptr)
1682     {
1683         server.mServiceUpdateHandler(server.AllocateId(), this, kDefaultEventsHandlerTimeout,
1684                                      server.mServiceUpdateHandlerContext);
1685         // We don't wait for the reply from the service update handler,
1686         // but always remove the service regardless of service update result.
1687         // Because removing a service should fail only when there is system
1688         // failure of the platform mDNS implementation and in which case the
1689         // service is not expected to be still registered.
1690     }
1691 
1692     if (!aRetainName)
1693     {
1694         IgnoreError(mServices.Remove(*aService));
1695         aService->Free();
1696         FreeUnusedServiceDescriptions();
1697     }
1698 
1699 exit:
1700     return;
1701 }
1702 
FreeAllServices(void)1703 void Server::Host::FreeAllServices(void)
1704 {
1705     while (!mServices.IsEmpty())
1706     {
1707         RemoveService(mServices.GetHead(), /* aRetainName */ false, /* aNotifyServiceHandler */ false);
1708     }
1709 }
1710 
FreeUnusedServiceDescriptions(void)1711 void Server::Host::FreeUnusedServiceDescriptions(void)
1712 {
1713     Service::Description *desc;
1714     Service::Description *prev;
1715     Service::Description *next;
1716 
1717     for (prev = nullptr, desc = mServiceDescriptions.GetHead(); desc != nullptr; desc = next)
1718     {
1719         next = desc->GetNext();
1720 
1721         if (FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, /* aServiceName */ nullptr,
1722                             desc->GetInstanceName()) == nullptr)
1723         {
1724             mServiceDescriptions.PopAfter(prev);
1725             desc->Free();
1726 
1727             // When the `desc` is removed from the list
1728             // we keep the `prev` pointer same as before.
1729         }
1730         else
1731         {
1732             prev = desc;
1733         }
1734     }
1735 }
1736 
ClearResources(void)1737 void Server::Host::ClearResources(void)
1738 {
1739     mAddressesNum = 0;
1740 }
1741 
MergeServicesAndResourcesFrom(Host & aHost)1742 Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
1743 {
1744     // This method merges services, service descriptions, and other
1745     // resources from another `aHost` into current host. It can
1746     // possibly take ownership of some items from `aHost`.
1747 
1748     Error error = kErrorNone;
1749 
1750     otLogInfoSrp("[server] update host %s", GetFullName());
1751 
1752     memcpy(mAddresses, aHost.mAddresses, aHost.mAddressesNum * sizeof(mAddresses[0]));
1753     mAddressesNum   = aHost.mAddressesNum;
1754     mKey            = aHost.mKey;
1755     mLease          = aHost.mLease;
1756     mKeyLease       = aHost.mKeyLease;
1757     mTimeLastUpdate = TimerMilli::GetNow();
1758 
1759     for (Service &service : aHost.mServices)
1760     {
1761         Service *existingService = FindService(service.GetServiceName(), service.GetInstanceName());
1762         Service *newService;
1763 
1764         if (service.mIsDeleted)
1765         {
1766             // `RemoveService()` does nothing if `exitsingService` is `nullptr`.
1767             RemoveService(existingService, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
1768             continue;
1769         }
1770 
1771         // Add/Merge `service` into the existing service or a allocate a new one
1772 
1773         newService = (existingService != nullptr)
1774                          ? existingService
1775                          : AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType());
1776 
1777         VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
1778 
1779         newService->mIsDeleted      = false;
1780         newService->mIsCommitted    = true;
1781         newService->mTimeLastUpdate = TimerMilli::GetNow();
1782 
1783         if (!service.mIsSubType)
1784         {
1785             // (1) Service description is shared across a base type and all its subtypes.
1786             // (2) `TakeResourcesFrom()` releases resources pinned to its argument.
1787             // Therefore, make sure the function is called only for the base type.
1788             newService->mDescription.TakeResourcesFrom(service.mDescription);
1789         }
1790 
1791         newService->Log((existingService != nullptr) ? Service::kUpdateExisting : Service::kAddNew);
1792     }
1793 
1794 exit:
1795     return error;
1796 }
1797 
FindServiceDescription(const char * aInstanceName) const1798 const Server::Service::Description *Server::Host::FindServiceDescription(const char *aInstanceName) const
1799 {
1800     return mServiceDescriptions.FindMatching(aInstanceName);
1801 }
1802 
FindServiceDescription(const char * aInstanceName)1803 Server::Service::Description *Server::Host::FindServiceDescription(const char *aInstanceName)
1804 {
1805     return const_cast<Service::Description *>(const_cast<const Host *>(this)->FindServiceDescription(aInstanceName));
1806 }
1807 
FindService(const char * aServiceName,const char * aInstanceName) const1808 const Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName) const
1809 {
1810     return FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, aServiceName, aInstanceName);
1811 }
1812 
FindService(const char * aServiceName,const char * aInstanceName)1813 Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName)
1814 {
1815     return const_cast<Service *>(const_cast<const Host *>(this)->FindService(aServiceName, aInstanceName));
1816 }
1817 
AddIp6Address(const Ip6::Address & aIp6Address)1818 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
1819 {
1820     Error error = kErrorNone;
1821 
1822     if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
1823     {
1824         // We don't like those address because they cannot be used
1825         // for communication with exterior devices.
1826         ExitNow(error = kErrorDrop);
1827     }
1828 
1829     for (const Ip6::Address &addr : mAddresses)
1830     {
1831         if (aIp6Address == addr)
1832         {
1833             // Drop duplicate addresses.
1834             ExitNow(error = kErrorDrop);
1835         }
1836     }
1837 
1838     if (mAddressesNum >= kMaxAddressesNum)
1839     {
1840         otLogWarnSrp("[server] too many addresses for host %s", GetFullName());
1841         ExitNow(error = kErrorNoBufs);
1842     }
1843 
1844     mAddresses[mAddressesNum++] = aIp6Address;
1845 
1846 exit:
1847     return error;
1848 }
1849 
1850 //---------------------------------------------------------------------------------------------------------------------
1851 // Server::UpdateMetadata
1852 
New(Instance & aInstance,const Dns::UpdateHeader & aHeader,Host * aHost,const Ip6::MessageInfo & aMessageInfo)1853 Server::UpdateMetadata *Server::UpdateMetadata::New(Instance &               aInstance,
1854                                                     const Dns::UpdateHeader &aHeader,
1855                                                     Host *                   aHost,
1856                                                     const Ip6::MessageInfo & aMessageInfo)
1857 {
1858     void *          buf;
1859     UpdateMetadata *update = nullptr;
1860 
1861     buf = Instance::HeapCAlloc(1, sizeof(UpdateMetadata));
1862     VerifyOrExit(buf != nullptr);
1863 
1864     update = new (buf) UpdateMetadata(aInstance, aHeader, aHost, aMessageInfo);
1865 
1866 exit:
1867     return update;
1868 }
1869 
Free(void)1870 void Server::UpdateMetadata::Free(void)
1871 {
1872     Instance::HeapFree(this);
1873 }
1874 
UpdateMetadata(Instance & aInstance,const Dns::UpdateHeader & aHeader,Host * aHost,const Ip6::MessageInfo & aMessageInfo)1875 Server::UpdateMetadata::UpdateMetadata(Instance &               aInstance,
1876                                        const Dns::UpdateHeader &aHeader,
1877                                        Host *                   aHost,
1878                                        const Ip6::MessageInfo & aMessageInfo)
1879     : InstanceLocator(aInstance)
1880     , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
1881     , mDnsHeader(aHeader)
1882     , mId(Get<Server>().AllocateId())
1883     , mHost(aHost)
1884     , mMessageInfo(aMessageInfo)
1885     , mNext(nullptr)
1886 {
1887 }
1888 
1889 } // namespace Srp
1890 } // namespace ot
1891 
1892 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
1893