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/as_core_type.hpp"
39 #include "common/const_cast.hpp"
40 #include "common/locator_getters.hpp"
41 #include "common/log.hpp"
42 #include "common/new.hpp"
43 #include "common/num_utils.hpp"
44 #include "common/random.hpp"
45 #include "common/string.hpp"
46 #include "instance/instance.hpp"
47 #include "net/dns_types.hpp"
48 #include "thread/thread_netif.hpp"
49 
50 namespace ot {
51 namespace Srp {
52 
53 RegisterLogModule("SrpServer");
54 
55 static const char kDefaultDomain[]       = "default.service.arpa.";
56 static const char kServiceSubTypeLabel[] = "._sub.";
57 
ErrorToDnsResponseCode(Error aError)58 static Dns::UpdateHeader::Response ErrorToDnsResponseCode(Error aError)
59 {
60     Dns::UpdateHeader::Response responseCode;
61 
62     switch (aError)
63     {
64     case kErrorNone:
65         responseCode = Dns::UpdateHeader::kResponseSuccess;
66         break;
67     case kErrorNoBufs:
68         responseCode = Dns::UpdateHeader::kResponseServerFailure;
69         break;
70     case kErrorParse:
71         responseCode = Dns::UpdateHeader::kResponseFormatError;
72         break;
73     case kErrorDuplicated:
74         responseCode = Dns::UpdateHeader::kResponseNameExists;
75         break;
76     default:
77         responseCode = Dns::UpdateHeader::kResponseRefused;
78         break;
79     }
80 
81     return responseCode;
82 }
83 
84 //---------------------------------------------------------------------------------------------------------------------
85 // Server
86 
Server(Instance & aInstance)87 Server::Server(Instance &aInstance)
88     : InstanceLocator(aInstance)
89     , mSocket(aInstance)
90     , mLeaseTimer(aInstance)
91     , mOutstandingUpdatesTimer(aInstance)
92     , mCompletedUpdateTask(aInstance)
93     , mServiceUpdateId(Random::NonCrypto::GetUint32())
94     , mPort(kUdpPortMin)
95     , mState(kStateDisabled)
96     , mAddressMode(kDefaultAddressMode)
97     , mAnycastSequenceNumber(0)
98     , mHasRegisteredAnyService(false)
99 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
100     , mAutoEnable(false)
101 #endif
102 {
103     IgnoreError(SetDomain(kDefaultDomain));
104 }
105 
SetAddressMode(AddressMode aMode)106 Error Server::SetAddressMode(AddressMode aMode)
107 {
108     Error error = kErrorNone;
109 
110     VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
111     VerifyOrExit(mAddressMode != aMode);
112     LogInfo("Address Mode: %s -> %s", AddressModeToString(mAddressMode), AddressModeToString(aMode));
113     mAddressMode = aMode;
114 
115 exit:
116     return error;
117 }
118 
SetAnycastModeSequenceNumber(uint8_t aSequenceNumber)119 Error Server::SetAnycastModeSequenceNumber(uint8_t aSequenceNumber)
120 {
121     Error error = kErrorNone;
122 
123     VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
124     mAnycastSequenceNumber = aSequenceNumber;
125 
126     LogInfo("Set Anycast Address Mode Seq Number to %d", aSequenceNumber);
127 
128 exit:
129     return error;
130 }
131 
SetEnabled(bool aEnabled)132 void Server::SetEnabled(bool aEnabled)
133 {
134 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
135     mAutoEnable = false;
136 #endif
137 
138     if (aEnabled)
139     {
140         Enable();
141     }
142     else
143     {
144         Disable();
145     }
146 }
147 
Enable(void)148 void Server::Enable(void)
149 {
150     VerifyOrExit(mState == kStateDisabled);
151     mState = kStateStopped;
152 
153     // Request publishing of "DNS/SRP Address Service" entry in the
154     // Thread Network Data based of `mAddressMode`. Then wait for
155     // callback `HandleNetDataPublisherEntryChange()` from the
156     // `Publisher` to start the SRP server.
157 
158     switch (mAddressMode)
159     {
160     case kAddressModeUnicast:
161         SelectPort();
162         Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(mPort);
163         break;
164 
165     case kAddressModeAnycast:
166         mPort = kAnycastAddressModePort;
167         Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber);
168         break;
169     }
170 
171 exit:
172     return;
173 }
174 
Disable(void)175 void Server::Disable(void)
176 {
177     VerifyOrExit(mState != kStateDisabled);
178     Get<NetworkData::Publisher>().UnpublishDnsSrpService();
179     Stop();
180     mState = kStateDisabled;
181 
182 exit:
183     return;
184 }
185 
186 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
SetAutoEnableMode(bool aEnabled)187 void Server::SetAutoEnableMode(bool aEnabled)
188 {
189     VerifyOrExit(mAutoEnable != aEnabled);
190     mAutoEnable = aEnabled;
191 
192     Get<BorderRouter::RoutingManager>().HandleSrpServerAutoEnableMode();
193 
194 exit:
195     return;
196 }
197 #endif
198 
TtlConfig(void)199 Server::TtlConfig::TtlConfig(void)
200 {
201     mMinTtl = kDefaultMinTtl;
202     mMaxTtl = kDefaultMaxTtl;
203 }
204 
SetTtlConfig(const TtlConfig & aTtlConfig)205 Error Server::SetTtlConfig(const TtlConfig &aTtlConfig)
206 {
207     Error error = kErrorNone;
208 
209     VerifyOrExit(aTtlConfig.IsValid(), error = kErrorInvalidArgs);
210     mTtlConfig = aTtlConfig;
211 
212 exit:
213     return error;
214 }
215 
GrantTtl(uint32_t aLease,uint32_t aTtl) const216 uint32_t Server::TtlConfig::GrantTtl(uint32_t aLease, uint32_t aTtl) const
217 {
218     OT_ASSERT(mMinTtl <= mMaxTtl);
219 
220     return Clamp(Min(aTtl, aLease), mMinTtl, mMaxTtl);
221 }
222 
LeaseConfig(void)223 Server::LeaseConfig::LeaseConfig(void)
224 {
225     mMinLease    = kDefaultMinLease;
226     mMaxLease    = kDefaultMaxLease;
227     mMinKeyLease = kDefaultMinKeyLease;
228     mMaxKeyLease = kDefaultMaxKeyLease;
229 }
230 
IsValid(void) const231 bool Server::LeaseConfig::IsValid(void) const
232 {
233     bool valid = false;
234 
235     // TODO: Support longer LEASE.
236     // We use milliseconds timer for LEASE & KEY-LEASE, this is to avoid overflow.
237     VerifyOrExit(mMaxKeyLease <= Time::MsecToSec(TimerMilli::kMaxDelay));
238     VerifyOrExit(mMinLease <= mMaxLease);
239     VerifyOrExit(mMinKeyLease <= mMaxKeyLease);
240     VerifyOrExit(mMinLease <= mMinKeyLease);
241     VerifyOrExit(mMaxLease <= mMaxKeyLease);
242 
243     valid = true;
244 
245 exit:
246     return valid;
247 }
248 
GrantLease(uint32_t aLease) const249 uint32_t Server::LeaseConfig::GrantLease(uint32_t aLease) const
250 {
251     OT_ASSERT(mMinLease <= mMaxLease);
252 
253     return (aLease == 0) ? 0 : Clamp(aLease, mMinLease, mMaxLease);
254 }
255 
GrantKeyLease(uint32_t aKeyLease) const256 uint32_t Server::LeaseConfig::GrantKeyLease(uint32_t aKeyLease) const
257 {
258     OT_ASSERT(mMinKeyLease <= mMaxKeyLease);
259 
260     return (aKeyLease == 0) ? 0 : Clamp(aKeyLease, mMinKeyLease, mMaxKeyLease);
261 }
262 
SetLeaseConfig(const LeaseConfig & aLeaseConfig)263 Error Server::SetLeaseConfig(const LeaseConfig &aLeaseConfig)
264 {
265     Error error = kErrorNone;
266 
267     VerifyOrExit(aLeaseConfig.IsValid(), error = kErrorInvalidArgs);
268     mLeaseConfig = aLeaseConfig;
269 
270 exit:
271     return error;
272 }
273 
SetDomain(const char * aDomain)274 Error Server::SetDomain(const char *aDomain)
275 {
276     Error    error = kErrorNone;
277     uint16_t length;
278 
279     VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
280 
281     length = StringLength(aDomain, Dns::Name::kMaxNameSize);
282     VerifyOrExit((length > 0) && (length < Dns::Name::kMaxNameSize), error = kErrorInvalidArgs);
283 
284     if (aDomain[length - 1] == '.')
285     {
286         error = mDomain.Set(aDomain);
287     }
288     else
289     {
290         // Need to append dot at the end
291 
292         char buf[Dns::Name::kMaxNameSize];
293 
294         VerifyOrExit(length < Dns::Name::kMaxNameSize - 1, error = kErrorInvalidArgs);
295 
296         memcpy(buf, aDomain, length);
297         buf[length]     = '.';
298         buf[length + 1] = '\0';
299 
300         error = mDomain.Set(buf);
301     }
302 
303 exit:
304     return error;
305 }
306 
GetNextHost(const Server::Host * aHost)307 const Server::Host *Server::GetNextHost(const Server::Host *aHost)
308 {
309     return (aHost == nullptr) ? mHosts.GetHead() : aHost->GetNext();
310 }
311 
RemoveHost(Host * aHost,RetainName aRetainName)312 void Server::RemoveHost(Host *aHost, RetainName aRetainName)
313 {
314     VerifyOrExit(aHost != nullptr);
315 
316     aHost->mLease = 0;
317     aHost->ClearResources();
318 
319     if (aRetainName)
320     {
321         LogInfo("Remove host %s (but retain its name)", aHost->GetFullName());
322     }
323     else
324     {
325         aHost->mKeyLease = 0;
326         IgnoreError(mHosts.Remove(*aHost));
327         LogInfo("Fully remove host %s", aHost->GetFullName());
328     }
329 
330     if (mServiceUpdateHandler.IsSet())
331     {
332         uint32_t updateId = AllocateId();
333 
334         LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
335         mServiceUpdateHandler.Invoke(updateId, aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
336         // We don't wait for the reply from the service update handler,
337         // but always remove the host (and its services) regardless of
338         // host/service update result. Because removing a host should fail
339         // only when there is system failure of the platform mDNS implementation
340         // and in which case the host is not expected to be still registered.
341     }
342 
343     if (!aRetainName)
344     {
345         aHost->Free();
346     }
347 
348 exit:
349     return;
350 }
351 
HasNameConflictsWith(Host & aHost) const352 bool Server::HasNameConflictsWith(Host &aHost) const
353 {
354     bool        hasConflicts = false;
355     const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
356 
357     if ((existingHost != nullptr) && (aHost.mKey != existingHost->mKey))
358     {
359         LogWarn("Name conflict: host name %s has already been allocated", aHost.GetFullName());
360         ExitNow(hasConflicts = true);
361     }
362 
363     for (const Service &service : aHost.mServices)
364     {
365         // Check on all hosts for a matching service with the same
366         // instance name and if found, verify that it has the same
367         // key.
368 
369         for (const Host &host : mHosts)
370         {
371             if (host.HasService(service.GetInstanceName()) && (aHost.mKey != host.mKey))
372             {
373                 LogWarn("Name conflict: service name %s has already been allocated", service.GetInstanceName());
374                 ExitNow(hasConflicts = true);
375             }
376         }
377     }
378 
379 exit:
380     return hasConflicts;
381 }
382 
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)383 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
384 {
385     UpdateMetadata *update = mOutstandingUpdates.RemoveMatching(aId);
386 
387     if (update == nullptr)
388     {
389         LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
390         ExitNow();
391     }
392 
393     update->SetError(aError);
394 
395     LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(update->GetId()), ErrorToString(aError));
396 
397     // We add new `update` at the tail of the `mCompletedUpdates` list
398     // so that updates are processed in the order we receive the
399     // `HandleServiceUpdateResult()` callbacks for them. The
400     // completed updates are processed from `mCompletedUpdateTask`
401     // and `ProcessCompletedUpdates()`.
402 
403     mCompletedUpdates.PushAfterTail(*update);
404     mCompletedUpdateTask.Post();
405 
406     if (mOutstandingUpdates.IsEmpty())
407     {
408         mOutstandingUpdatesTimer.Stop();
409     }
410     else
411     {
412         mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
413     }
414 
415 exit:
416     return;
417 }
418 
ProcessCompletedUpdates(void)419 void Server::ProcessCompletedUpdates(void)
420 {
421     UpdateMetadata *update;
422 
423     while ((update = mCompletedUpdates.Pop()) != nullptr)
424     {
425         CommitSrpUpdate(*update);
426     }
427 }
428 
CommitSrpUpdate(Error aError,Host & aHost,const MessageMetadata & aMessageMetadata)429 void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
430 {
431     CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
432                     aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
433 }
434 
CommitSrpUpdate(UpdateMetadata & aUpdateMetadata)435 void Server::CommitSrpUpdate(UpdateMetadata &aUpdateMetadata)
436 {
437     CommitSrpUpdate(aUpdateMetadata.GetError(), aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
438                     aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
439                     aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
440 
441     aUpdateMetadata.Free();
442 }
443 
CommitSrpUpdate(Error aError,Host & aHost,const Dns::UpdateHeader & aDnsHeader,const Ip6::MessageInfo * aMessageInfo,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig)444 void Server::CommitSrpUpdate(Error                    aError,
445                              Host                    &aHost,
446                              const Dns::UpdateHeader &aDnsHeader,
447                              const Ip6::MessageInfo  *aMessageInfo,
448                              const TtlConfig         &aTtlConfig,
449                              const LeaseConfig       &aLeaseConfig)
450 {
451     Host    *existingHost    = nullptr;
452     uint32_t grantedTtl      = 0;
453     uint32_t hostLease       = 0;
454     uint32_t hostKeyLease    = 0;
455     uint32_t grantedLease    = 0;
456     uint32_t grantedKeyLease = 0;
457     bool     useShortLease   = aHost.ShouldUseShortLeaseOption();
458 
459     if (aError != kErrorNone)
460     {
461         aHost.Free();
462         ExitNow();
463     }
464 
465     hostLease       = aHost.GetLease();
466     hostKeyLease    = aHost.GetKeyLease();
467     grantedLease    = aLeaseConfig.GrantLease(hostLease);
468     grantedKeyLease = useShortLease ? grantedLease : aLeaseConfig.GrantKeyLease(hostKeyLease);
469     grantedTtl      = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
470 
471     existingHost = mHosts.RemoveMatching(aHost.GetFullName());
472 
473     LogInfo("Committing update for %s host %s", (existingHost != nullptr) ? "existing" : "new", aHost.GetFullName());
474     LogInfo("    Granted lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(grantedLease), ToUlong(grantedKeyLease),
475             ToUlong(grantedTtl));
476 
477     aHost.SetLease(grantedLease);
478     aHost.SetKeyLease(grantedKeyLease);
479     aHost.SetTtl(grantedTtl);
480 
481     if (grantedKeyLease == 0)
482     {
483         VerifyOrExit(existingHost != nullptr);
484         LogInfo("Fully remove host %s", aHost.GetFullName());
485         aHost.Free();
486         ExitNow();
487     }
488 
489     mHosts.Push(aHost);
490 
491     for (Service &service : aHost.mServices)
492     {
493         service.mLease       = grantedLease;
494         service.mKeyLease    = grantedKeyLease;
495         service.mTtl         = grantedTtl;
496         service.mIsCommitted = true;
497 
498 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
499         {
500             Service::Action action = Service::kAddNew;
501 
502             if (service.mIsDeleted)
503             {
504                 action = Service::kRemoveButRetainName;
505             }
506             else if ((existingHost != nullptr) && existingHost->HasService(service.GetInstanceName()))
507             {
508                 action = Service::kUpdateExisting;
509             }
510 
511             service.Log(action);
512         }
513 #endif
514     }
515 
516     if (existingHost != nullptr)
517     {
518         // Move any existing service that is not included in the new
519         // update into `aHost`.
520 
521         Service *existingService;
522 
523         while ((existingService = existingHost->mServices.Pop()) != nullptr)
524         {
525             if (!aHost.HasService(existingService->GetInstanceName()))
526             {
527                 aHost.AddService(*existingService);
528                 existingService->Log(Service::kKeepUnchanged);
529             }
530             else
531             {
532                 existingService->Free();
533             }
534         }
535     }
536 
537 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
538     if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast))
539     {
540         Settings::SrpServerInfo info;
541 
542         mHasRegisteredAnyService = true;
543         info.SetPort(GetSocket().mSockName.mPort);
544         IgnoreError(Get<Settings>().Save(info));
545     }
546 #endif
547 
548     if (!aHost.IsDeleted())
549     {
550         mLeaseTimer.FireAtIfEarlier(Min(aHost.GetExpireTime(), aHost.GetKeyExpireTime()));
551     }
552 
553 exit:
554     if (aMessageInfo != nullptr)
555     {
556         if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
557         {
558             SendResponse(aDnsHeader, grantedLease, grantedKeyLease, useShortLease, *aMessageInfo);
559         }
560         else
561         {
562             SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), *aMessageInfo);
563         }
564     }
565 
566     if (existingHost != nullptr)
567     {
568         existingHost->Free();
569     }
570 }
571 
SelectPort(void)572 void Server::SelectPort(void)
573 {
574     mPort = kUdpPortMin;
575 
576 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
577     {
578         Settings::SrpServerInfo info;
579 
580         if (Get<Settings>().Read(info) == kErrorNone)
581         {
582             mPort = info.GetPort() + 1;
583             if (mPort < kUdpPortMin || mPort > kUdpPortMax)
584             {
585                 mPort = kUdpPortMin;
586             }
587         }
588     }
589 #endif
590 
591     LogInfo("Selected port %u", mPort);
592 }
593 
Start(void)594 void Server::Start(void)
595 {
596     VerifyOrExit(mState == kStateStopped);
597 
598     mState = kStateRunning;
599     PrepareSocket();
600     LogInfo("Start listening on port %u", mPort);
601 
602 exit:
603     return;
604 }
605 
PrepareSocket(void)606 void Server::PrepareSocket(void)
607 {
608     Error error = kErrorNone;
609 
610 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
611     Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
612 
613     if (dnsSocket.GetSockName().GetPort() == mPort)
614     {
615         // If the DNS-SD socket matches our port number, we use the
616         // same socket so we close our own socket (in case it was
617         // open). `GetSocket()` will now return the DNS-SD socket.
618 
619         IgnoreError(mSocket.Close());
620         ExitNow();
621     }
622 #endif
623 
624     VerifyOrExit(!mSocket.IsOpen());
625     SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
626     error = mSocket.Bind(mPort, Ip6::kNetifThread);
627 
628 exit:
629     if (error != kErrorNone)
630     {
631         LogCrit("Failed to prepare socket: %s", ErrorToString(error));
632         Stop();
633     }
634 }
635 
GetSocket(void)636 Ip6::Udp::Socket &Server::GetSocket(void)
637 {
638     Ip6::Udp::Socket *socket = &mSocket;
639 
640 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
641     Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
642 
643     if (dnsSocket.GetSockName().GetPort() == mPort)
644     {
645         socket = &dnsSocket;
646     }
647 #endif
648 
649     return *socket;
650 }
651 
652 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
653 
HandleDnssdServerStateChange(void)654 void Server::HandleDnssdServerStateChange(void)
655 {
656     // This is called from` Dns::ServiceDiscovery::Server` to notify
657     // that it has started or stopped. We check whether we need to
658     // share the socket.
659 
660     if (mState == kStateRunning)
661     {
662         PrepareSocket();
663     }
664 }
665 
HandleDnssdServerUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)666 Error Server::HandleDnssdServerUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
667 {
668     // This is called from` Dns::ServiceDiscovery::Server` when a UDP
669     // message is received on its socket. We check whether we are
670     // sharing socket and if so we process the received message. We
671     // return `kErrorNone` to indicate that message was successfully
672     // processed by `Srp::Server`, otherwise `kErrorDrop` is returned.
673 
674     Error error = kErrorDrop;
675 
676     VerifyOrExit((mState == kStateRunning) && !mSocket.IsOpen());
677 
678     error = ProcessMessage(aMessage, aMessageInfo);
679 
680 exit:
681     return error;
682 }
683 
684 #endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
685 
Stop(void)686 void Server::Stop(void)
687 {
688     VerifyOrExit(mState == kStateRunning);
689 
690     mState = kStateStopped;
691 
692     while (!mHosts.IsEmpty())
693     {
694         RemoveHost(mHosts.GetHead(), kDeleteName);
695     }
696 
697     // TODO: We should cancel any outstanding service updates, but current
698     // OTBR mDNS publisher cannot properly handle it.
699     while (!mOutstandingUpdates.IsEmpty())
700     {
701         mOutstandingUpdates.Pop()->Free();
702     }
703 
704     mLeaseTimer.Stop();
705     mOutstandingUpdatesTimer.Stop();
706 
707     LogInfo("Stop listening on %u", mPort);
708     IgnoreError(mSocket.Close());
709     mHasRegisteredAnyService = false;
710 
711 exit:
712     return;
713 }
714 
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)715 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
716 {
717     switch (aEvent)
718     {
719     case NetworkData::Publisher::kEventEntryAdded:
720         Start();
721         break;
722 
723     case NetworkData::Publisher::kEventEntryRemoved:
724         Stop();
725         break;
726     }
727 }
728 
FindOutstandingUpdate(const MessageMetadata & aMessageMetadata) const729 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const
730 {
731     const UpdateMetadata *ret = nullptr;
732 
733     VerifyOrExit(aMessageMetadata.IsDirectRxFromClient());
734 
735     for (const UpdateMetadata &update : mOutstandingUpdates)
736     {
737         if (aMessageMetadata.mDnsHeader.GetMessageId() == update.GetDnsHeader().GetMessageId() &&
738             aMessageMetadata.mMessageInfo->GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
739             aMessageMetadata.mMessageInfo->GetPeerPort() == update.GetMessageInfo().GetPeerPort())
740         {
741             ExitNow(ret = &update);
742         }
743     }
744 
745 exit:
746     return ret;
747 }
748 
ProcessDnsUpdate(Message & aMessage,MessageMetadata & aMetadata)749 void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata)
750 {
751     Error error = kErrorNone;
752     Host *host  = nullptr;
753 
754     LogInfo("Received DNS update from %s", aMetadata.IsDirectRxFromClient()
755                                                ? aMetadata.mMessageInfo->GetPeerAddr().ToString().AsCString()
756                                                : "an SRPL Partner");
757 
758     SuccessOrExit(error = ProcessZoneSection(aMessage, aMetadata));
759 
760     if (FindOutstandingUpdate(aMetadata) != nullptr)
761     {
762         LogInfo("Drop duplicated SRP update request: MessageId=%u", aMetadata.mDnsHeader.GetMessageId());
763 
764         // Silently drop duplicate requests.
765         // This could rarely happen, because the outstanding SRP update timer should
766         // be shorter than the SRP update retransmission timer.
767         ExitNow(error = kErrorNone);
768     }
769 
770     // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
771     VerifyOrExit(aMetadata.mDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
772 
773     host = Host::Allocate(GetInstance(), aMetadata.mRxTime);
774     VerifyOrExit(host != nullptr, error = kErrorNoBufs);
775     SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aMetadata));
776 
777     // Parse lease time and validate signature.
778     SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata));
779 
780     HandleUpdate(*host, aMetadata);
781 
782 exit:
783     if (error != kErrorNone)
784     {
785         if (host != nullptr)
786         {
787             host->Free();
788         }
789 
790         if (aMetadata.IsDirectRxFromClient())
791         {
792             SendResponse(aMetadata.mDnsHeader, ErrorToDnsResponseCode(error), *aMetadata.mMessageInfo);
793         }
794     }
795 }
796 
ProcessZoneSection(const Message & aMessage,MessageMetadata & aMetadata) const797 Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const
798 {
799     Error             error = kErrorNone;
800     Dns::Name::Buffer name;
801     uint16_t          offset = aMetadata.mOffset;
802 
803     VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
804 
805     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
806     // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
807     VerifyOrExit(StringMatch(name, GetDomain(), kStringCaseInsensitiveMatch), error = kErrorSecurity);
808     SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone));
809     offset += sizeof(Dns::Zone);
810 
811     VerifyOrExit(aMetadata.mDnsZone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
812     aMetadata.mOffset = offset;
813 
814 exit:
815     if (error != kErrorNone)
816     {
817         LogWarn("Failed to process DNS Zone section: %s", ErrorToString(error));
818     }
819 
820     return error;
821 }
822 
ProcessUpdateSection(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const823 Error Server::ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const
824 {
825     Error error = kErrorNone;
826 
827     // Process Service Discovery, Host and Service Description Instructions with
828     // 3 times iterations over all DNS update RRs. The order of those processes matters.
829 
830     // 0. Enumerate over all Service Discovery Instructions before processing any other records.
831     // So that we will know whether a name is a hostname or service instance name when processing
832     // a "Delete All RRsets from a name" record.
833     SuccessOrExit(error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aMetadata));
834 
835     // 1. Enumerate over all RRs to build the Host Description Instruction.
836     SuccessOrExit(error = ProcessHostDescriptionInstruction(aHost, aMessage, aMetadata));
837 
838     // 2. Enumerate over all RRs to build the Service Description Instructions.
839     SuccessOrExit(error = ProcessServiceDescriptionInstructions(aHost, aMessage, aMetadata));
840 
841     // 3. Verify that there are no name conflicts.
842     VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
843 
844 exit:
845     if (error != kErrorNone)
846     {
847         LogWarn("Failed to process DNS Update section: %s", ErrorToString(error));
848     }
849 
850     return error;
851 }
852 
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const853 Error Server::ProcessHostDescriptionInstruction(Host                  &aHost,
854                                                 const Message         &aMessage,
855                                                 const MessageMetadata &aMetadata) const
856 {
857     Error    error  = kErrorNone;
858     uint16_t offset = aMetadata.mOffset;
859 
860     OT_ASSERT(aHost.GetFullName() == nullptr);
861 
862     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
863     {
864         Dns::Name::Buffer   name;
865         Dns::ResourceRecord record;
866 
867         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
868 
869         SuccessOrExit(error = aMessage.Read(offset, record));
870 
871         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
872         {
873             // Delete All RRsets from a name.
874             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
875 
876             // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
877 
878             if (!aHost.HasService(name))
879             {
880                 // If host name is already set to a different name, `SetFullName()`
881                 // will return `kErrorFailed`.
882                 SuccessOrExit(error = aHost.SetFullName(name));
883                 aHost.ClearResources();
884             }
885         }
886         else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
887         {
888             Dns::AaaaRecord aaaaRecord;
889 
890             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
891 
892             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
893 
894             SuccessOrExit(error = aHost.SetFullName(name));
895 
896             SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
897             VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
898 
899             // Tolerate kErrorDrop for AAAA Resources.
900             VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
901         }
902         else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
903         {
904             // We currently support only ECDSA P-256.
905             Dns::Ecdsa256KeyRecord keyRecord;
906 
907             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
908 
909             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
910 
911             SuccessOrExit(error = aMessage.Read(offset, keyRecord));
912             VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
913 
914             if (aHost.mParsedKey)
915             {
916                 VerifyOrExit(aHost.mKey == keyRecord.GetKey(), error = kErrorSecurity);
917             }
918             else
919             {
920                 aHost.mParsedKey = true;
921                 aHost.mKey       = keyRecord.GetKey();
922             }
923         }
924 
925         offset += record.GetSize();
926     }
927 
928     // Verify that we have a complete Host Description Instruction.
929 
930     VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
931     VerifyOrExit(aHost.mParsedKey, error = kErrorFailed);
932 
933     // We check the number of host addresses after processing of the
934     // Lease Option in the Addition Section and determining whether
935     // the host is being removed or registered.
936 
937 exit:
938     if (error != kErrorNone)
939     {
940         LogWarn("Failed to process Host Description instructions: %s", ErrorToString(error));
941     }
942 
943     return error;
944 }
945 
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const946 Error Server::ProcessServiceDiscoveryInstructions(Host                  &aHost,
947                                                   const Message         &aMessage,
948                                                   const MessageMetadata &aMetadata) const
949 {
950     Error    error  = kErrorNone;
951     uint16_t offset = aMetadata.mOffset;
952 
953     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
954     {
955         Dns::Name::Buffer               serviceName;
956         Dns::Name::LabelBuffer          instanceLabel;
957         Dns::Name::Buffer               instanceServiceName;
958         String<Dns::Name::kMaxNameSize> instanceName;
959         Dns::PtrRecord                  ptrRecord;
960         const char                     *subServiceName;
961         Service                        *service;
962         bool                            isSubType;
963         bool                            isDelete;
964 
965         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName));
966         VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
967 
968         error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord);
969 
970         if (error == kErrorNotFound)
971         {
972             // `ReadRecord()` updates `aOffset` to skip over a
973             // non-matching record.
974             error = kErrorNone;
975             continue;
976         }
977 
978         SuccessOrExit(error);
979 
980         SuccessOrExit(error = ptrRecord.ReadPtrName(aMessage, offset, instanceLabel, instanceServiceName));
981         instanceName.Append("%s.%s", instanceLabel, instanceServiceName);
982 
983         // Class None indicates "Delete an RR from an RRset".
984         isDelete = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
985 
986         VerifyOrExit(isDelete || ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorParse);
987 
988         // Check if the `serviceName` is a sub-type with name
989         // format: "<sub-label>._sub.<service-labels>.<domain>."
990 
991         subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
992         isSubType      = (subServiceName != nullptr);
993 
994         if (isSubType)
995         {
996             // Skip over the "._sub." label to get to the base
997             // service name.
998             subServiceName += sizeof(kServiceSubTypeLabel) - 1;
999         }
1000 
1001         // Verify that instance name and service name are related.
1002         VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName.AsCString(), isSubType ? subServiceName : serviceName),
1003                      error = kErrorFailed);
1004 
1005         // Find a matching existing service or allocate a new one.
1006 
1007         service = aHost.FindService(instanceName.AsCString());
1008 
1009         if (service == nullptr)
1010         {
1011             service = aHost.AddNewService(instanceName.AsCString(), instanceLabel, aMetadata.mRxTime);
1012             VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1013         }
1014 
1015         if (isSubType)
1016         {
1017             VerifyOrExit(!service->HasSubTypeServiceName(serviceName), error = kErrorFailed);
1018 
1019             // Ignore a sub-type service delete.
1020 
1021             if (!isDelete)
1022             {
1023                 Heap::String *newSubTypeLabel = service->mSubTypes.PushBack();
1024 
1025                 VerifyOrExit(newSubTypeLabel != nullptr, error = kErrorNoBufs);
1026                 SuccessOrExit(error = newSubTypeLabel->Set(serviceName));
1027             }
1028         }
1029         else
1030         {
1031             // Processed PTR record is the base service (not a
1032             // sub-type). `mServiceName` is only set when base
1033             // service is processed.
1034 
1035             VerifyOrExit(service->mServiceName.IsNull(), error = kErrorFailed);
1036             SuccessOrExit(error = service->mServiceName.Set(serviceName));
1037             service->mIsDeleted = isDelete;
1038         }
1039 
1040         if (!isDelete)
1041         {
1042             SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
1043         }
1044     }
1045 
1046     // Verify that for all services, a PTR record was processed for
1047     // the base service (`mServiceName` is set), and for a deleted
1048     // service, no PTR record was seen adding a sub-type.
1049 
1050     for (const Service &service : aHost.mServices)
1051     {
1052         VerifyOrExit(!service.mServiceName.IsNull(), error = kErrorParse);
1053 
1054         if (service.mIsDeleted)
1055         {
1056             VerifyOrExit(service.mSubTypes.GetLength() == 0, error = kErrorParse);
1057         }
1058     }
1059 
1060 exit:
1061     if (error != kErrorNone)
1062     {
1063         LogWarn("Failed to process Service Discovery instructions: %s", ErrorToString(error));
1064     }
1065 
1066     return error;
1067 }
1068 
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const1069 Error Server::ProcessServiceDescriptionInstructions(Host            &aHost,
1070                                                     const Message   &aMessage,
1071                                                     MessageMetadata &aMetadata) const
1072 {
1073     Error    error  = kErrorNone;
1074     uint16_t offset = aMetadata.mOffset;
1075 
1076     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
1077     {
1078         Dns::Name::Buffer   name;
1079         Dns::ResourceRecord record;
1080         Service            *service;
1081 
1082         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1083         SuccessOrExit(error = aMessage.Read(offset, record));
1084 
1085         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
1086         {
1087             // Delete All RRsets from a name.
1088             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
1089 
1090             service = aHost.FindService(name);
1091 
1092             if (service != nullptr)
1093             {
1094                 VerifyOrExit(!service->mParsedDeleteAllRrset);
1095                 service->mParsedDeleteAllRrset = true;
1096             }
1097 
1098             offset += record.GetSize();
1099             continue;
1100         }
1101 
1102         if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
1103         {
1104             Dns::SrvRecord    srvRecord;
1105             Dns::Name::Buffer hostName;
1106 
1107             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1108 
1109             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1110 
1111             SuccessOrExit(error = aMessage.Read(offset, srvRecord));
1112             offset += sizeof(srvRecord);
1113 
1114             SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName));
1115             VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
1116             VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
1117 
1118             service = aHost.FindService(name);
1119             VerifyOrExit(service != nullptr, error = kErrorFailed);
1120 
1121             VerifyOrExit(!service->mParsedSrv, error = kErrorParse);
1122             service->mParsedSrv = true;
1123 
1124             service->mTtl      = srvRecord.GetTtl();
1125             service->mPriority = srvRecord.GetPriority();
1126             service->mWeight   = srvRecord.GetWeight();
1127             service->mPort     = srvRecord.GetPort();
1128         }
1129         else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
1130         {
1131             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1132 
1133             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1134 
1135             service = aHost.FindService(name);
1136             VerifyOrExit(service != nullptr, error = kErrorFailed);
1137 
1138             service->mParsedTxt = true;
1139 
1140             offset += sizeof(record);
1141             SuccessOrExit(error = service->SetTxtDataFromMessage(aMessage, offset, record.GetLength()));
1142             offset += record.GetLength();
1143         }
1144         else
1145         {
1146             offset += record.GetSize();
1147         }
1148     }
1149 
1150     for (const Service &service : aHost.mServices)
1151     {
1152         VerifyOrExit(service.mParsedDeleteAllRrset, error = kErrorFailed);
1153         VerifyOrExit(service.mParsedSrv == service.mParsedTxt, error = kErrorFailed);
1154 
1155         if (!service.mIsDeleted)
1156         {
1157             VerifyOrExit(service.mParsedSrv, error = kErrorFailed);
1158         }
1159     }
1160 
1161     aMetadata.mOffset = offset;
1162 
1163 exit:
1164     if (error != kErrorNone)
1165     {
1166         LogWarn("Failed to process Service Description instructions: %s", ErrorToString(error));
1167     }
1168 
1169     return error;
1170 }
1171 
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)1172 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
1173 {
1174     return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
1175            aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
1176 }
1177 
ProcessAdditionalSection(Host * aHost,const Message & aMessage,MessageMetadata & aMetadata) const1178 Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const
1179 {
1180     Error             error = kErrorNone;
1181     Dns::OptRecord    optRecord;
1182     Dns::LeaseOption  leaseOption;
1183     Dns::SigRecord    sigRecord;
1184     char              name[2]; // The root domain name (".") is expected.
1185     uint16_t          offset = aMetadata.mOffset;
1186     uint16_t          sigOffset;
1187     uint16_t          sigRdataOffset;
1188     Dns::Name::Buffer signerName;
1189     uint16_t          signatureLength;
1190 
1191     VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
1192 
1193     // EDNS(0) Update Lease Option.
1194 
1195     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1196     SuccessOrExit(error = aMessage.Read(offset, optRecord));
1197 
1198     SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength()));
1199 
1200     offset += optRecord.GetSize();
1201 
1202     aHost->SetLease(leaseOption.GetLeaseInterval());
1203     aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
1204 
1205     // If the client included the short variant of Lease Option,
1206     // server must also use the short variant in its response.
1207     aHost->SetUseShortLeaseOption(leaseOption.IsShortVariant());
1208 
1209     if (aHost->GetLease() > 0)
1210     {
1211         uint8_t hostAddressesNum;
1212 
1213         aHost->GetAddresses(hostAddressesNum);
1214 
1215         // There MUST be at least one valid address if we have nonzero lease.
1216         VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
1217     }
1218 
1219     // SIG(0).
1220 
1221     sigOffset = offset;
1222     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1223     SuccessOrExit(error = aMessage.Read(offset, sigRecord));
1224     VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
1225 
1226     sigRdataOffset = offset + sizeof(Dns::ResourceRecord);
1227     offset += sizeof(sigRecord);
1228 
1229     // TODO: Verify that the signature doesn't expire. This is not
1230     // implemented because the end device may not be able to get
1231     // the synchronized date/time.
1232 
1233     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName));
1234 
1235     signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset);
1236     offset += signatureLength;
1237 
1238     // Verify the signature. Currently supports only ECDSA.
1239 
1240     VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
1241     VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
1242     VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
1243 
1244     SuccessOrExit(error = VerifySignature(aHost->mKey, aMessage, aMetadata.mDnsHeader, sigOffset, sigRdataOffset,
1245                                           sigRecord.GetLength(), signerName));
1246 
1247     aMetadata.mOffset = offset;
1248 
1249 exit:
1250     if (error != kErrorNone)
1251     {
1252         LogWarn("Failed to process DNS Additional section: %s", ErrorToString(error));
1253     }
1254 
1255     return error;
1256 }
1257 
VerifySignature(const Host::Key & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const1258 Error Server::VerifySignature(const Host::Key  &aKey,
1259                               const Message    &aMessage,
1260                               Dns::UpdateHeader aDnsHeader,
1261                               uint16_t          aSigOffset,
1262                               uint16_t          aSigRdataOffset,
1263                               uint16_t          aSigRdataLength,
1264                               const char       *aSignerName) const
1265 {
1266     Error                          error;
1267     uint16_t                       offset = aMessage.GetOffset();
1268     uint16_t                       signatureOffset;
1269     Crypto::Sha256                 sha256;
1270     Crypto::Sha256::Hash           hash;
1271     Crypto::Ecdsa::P256::Signature signature;
1272     Message                       *signerNameMessage = nullptr;
1273 
1274     VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
1275 
1276     sha256.Start();
1277 
1278     // SIG RDATA less signature.
1279     sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
1280 
1281     // The uncompressed (canonical) form of the signer name should be used for signature
1282     // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
1283     signerNameMessage = Get<Ip6::Udp>().NewMessage();
1284     VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
1285     SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
1286     sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
1287 
1288     // We need the DNS header before appending the SIG RR.
1289     aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
1290     sha256.Update(aDnsHeader);
1291     sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
1292 
1293     sha256.Finish(hash);
1294 
1295     signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
1296     SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
1297 
1298     error = aKey.Verify(hash, signature);
1299 
1300 exit:
1301     if (error != kErrorNone)
1302     {
1303         LogWarn("Failed to verify message signature: %s", ErrorToString(error));
1304     }
1305 
1306     FreeMessage(signerNameMessage);
1307     return error;
1308 }
1309 
HandleUpdate(Host & aHost,const MessageMetadata & aMetadata)1310 void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
1311 {
1312     Error error = kErrorNone;
1313     Host *existingHost;
1314 
1315     // Check whether the SRP update wants to remove `aHost`.
1316 
1317     VerifyOrExit(aHost.GetLease() == 0);
1318 
1319     aHost.ClearResources();
1320 
1321     existingHost = mHosts.FindMatching(aHost.GetFullName());
1322     VerifyOrExit(existingHost != nullptr);
1323 
1324     // The client may not include all services it has registered before
1325     // when removing a host. We copy and append any missing services to
1326     // `aHost` from the `existingHost` and mark them as deleted.
1327 
1328     for (const Service &existingService : existingHost->mServices)
1329     {
1330         Service *service;
1331 
1332         if (existingService.mIsDeleted || aHost.HasService(existingService.GetInstanceName()))
1333         {
1334             continue;
1335         }
1336 
1337         service = aHost.AddNewService(existingService.GetInstanceName(), existingService.GetInstanceLabel(),
1338                                       aMetadata.mRxTime);
1339         VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1340 
1341         SuccessOrExit(error = service->mServiceName.Set(existingService.GetServiceName()));
1342         service->mIsDeleted = true;
1343     }
1344 
1345 exit:
1346     InformUpdateHandlerOrCommit(error, aHost, aMetadata);
1347 }
1348 
InformUpdateHandlerOrCommit(Error aError,Host & aHost,const MessageMetadata & aMetadata)1349 void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
1350 {
1351 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1352     if (aError == kErrorNone)
1353     {
1354         uint8_t             numAddrs;
1355         const Ip6::Address *addrs;
1356 
1357         LogInfo("Processed SRP update info");
1358         LogInfo("    Host:%s", aHost.GetFullName());
1359         LogInfo("    Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()),
1360                 ToUlong(aHost.GetTtl()));
1361 
1362         addrs = aHost.GetAddresses(numAddrs);
1363 
1364         if (numAddrs == 0)
1365         {
1366             LogInfo("    No host address");
1367         }
1368         else
1369         {
1370             LogInfo("    %d host address(es):", numAddrs);
1371 
1372             for (; numAddrs > 0; addrs++, numAddrs--)
1373             {
1374                 LogInfo("      %s", addrs->ToString().AsCString());
1375             }
1376         }
1377 
1378         for (const Service &service : aHost.mServices)
1379         {
1380             LogInfo("    %s service '%s'", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName());
1381 
1382             for (const Heap::String &subType : service.mSubTypes)
1383             {
1384                 Dns::Name::LabelBuffer label;
1385 
1386                 IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label));
1387                 LogInfo("      sub-type: %s", label);
1388             }
1389         }
1390     }
1391     else
1392     {
1393         LogInfo("Error %s processing received SRP update", ErrorToString(aError));
1394     }
1395 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1396 
1397     if ((aError == kErrorNone) && mServiceUpdateHandler.IsSet())
1398     {
1399         UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
1400 
1401         if (update != nullptr)
1402         {
1403             mOutstandingUpdates.Push(*update);
1404             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1405 
1406             LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(update->GetId()));
1407             mServiceUpdateHandler.Invoke(update->GetId(), &aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
1408             ExitNow();
1409         }
1410 
1411         aError = kErrorNoBufs;
1412     }
1413 
1414     CommitSrpUpdate(aError, aHost, aMetadata);
1415 
1416 exit:
1417     return;
1418 }
1419 
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1420 void Server::SendResponse(const Dns::UpdateHeader    &aHeader,
1421                           Dns::UpdateHeader::Response aResponseCode,
1422                           const Ip6::MessageInfo     &aMessageInfo)
1423 {
1424     Error             error;
1425     Message          *response = nullptr;
1426     Dns::UpdateHeader header;
1427 
1428     response = GetSocket().NewMessage();
1429     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1430 
1431     header.SetMessageId(aHeader.GetMessageId());
1432     header.SetType(Dns::UpdateHeader::kTypeResponse);
1433     header.SetQueryType(aHeader.GetQueryType());
1434     header.SetResponseCode(aResponseCode);
1435     SuccessOrExit(error = response->Append(header));
1436 
1437     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1438 
1439     if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1440     {
1441         LogWarn("Send fail response: %d", aResponseCode);
1442     }
1443     else
1444     {
1445         LogInfo("Send success response");
1446     }
1447 
1448     UpdateResponseCounters(aResponseCode);
1449 
1450 exit:
1451     if (error != kErrorNone)
1452     {
1453         LogWarn("Failed to send response: %s", ErrorToString(error));
1454         FreeMessage(response);
1455     }
1456 }
1457 
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,bool mUseShortLeaseOption,const Ip6::MessageInfo & aMessageInfo)1458 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1459                           uint32_t                 aLease,
1460                           uint32_t                 aKeyLease,
1461                           bool                     mUseShortLeaseOption,
1462                           const Ip6::MessageInfo  &aMessageInfo)
1463 {
1464     Error             error;
1465     Message          *response = nullptr;
1466     Dns::UpdateHeader header;
1467     Dns::OptRecord    optRecord;
1468     Dns::LeaseOption  leaseOption;
1469     uint16_t          optionSize;
1470 
1471     response = GetSocket().NewMessage();
1472     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1473 
1474     header.SetMessageId(aHeader.GetMessageId());
1475     header.SetType(Dns::UpdateHeader::kTypeResponse);
1476     header.SetQueryType(aHeader.GetQueryType());
1477     header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1478     header.SetAdditionalRecordCount(1);
1479     SuccessOrExit(error = response->Append(header));
1480 
1481     // Append the root domain (".").
1482     SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1483 
1484     optRecord.Init();
1485     optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1486     optRecord.SetDnsSecurityFlag();
1487 
1488     if (mUseShortLeaseOption)
1489     {
1490         leaseOption.InitAsShortVariant(aLease);
1491     }
1492     else
1493     {
1494         leaseOption.InitAsLongVariant(aLease, aKeyLease);
1495     }
1496 
1497     optionSize = static_cast<uint16_t>(leaseOption.GetSize());
1498     optRecord.SetLength(optionSize);
1499 
1500     SuccessOrExit(error = response->Append(optRecord));
1501     SuccessOrExit(error = response->AppendBytes(&leaseOption, optionSize));
1502 
1503     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1504 
1505     LogInfo("Send success response with granted lease: %lu and key lease: %lu", ToUlong(aLease), ToUlong(aKeyLease));
1506 
1507     UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
1508 
1509 exit:
1510     if (error != kErrorNone)
1511     {
1512         LogWarn("Failed to send response: %s", ErrorToString(error));
1513         FreeMessage(response);
1514     }
1515 }
1516 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1517 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1518 {
1519     static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
1520 }
1521 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1522 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1523 {
1524     Error error = ProcessMessage(aMessage, aMessageInfo);
1525 
1526     if (error != kErrorNone)
1527     {
1528         LogInfo("Failed to handle DNS message: %s", ErrorToString(error));
1529     }
1530 }
1531 
ProcessMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1532 Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1533 {
1534     return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
1535 }
1536 
ProcessMessage(Message & aMessage,TimeMilli aRxTime,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig,const Ip6::MessageInfo * aMessageInfo)1537 Error Server::ProcessMessage(Message                &aMessage,
1538                              TimeMilli               aRxTime,
1539                              const TtlConfig        &aTtlConfig,
1540                              const LeaseConfig      &aLeaseConfig,
1541                              const Ip6::MessageInfo *aMessageInfo)
1542 {
1543     Error           error;
1544     MessageMetadata metadata;
1545 
1546     metadata.mOffset      = aMessage.GetOffset();
1547     metadata.mRxTime      = aRxTime;
1548     metadata.mTtlConfig   = aTtlConfig;
1549     metadata.mLeaseConfig = aLeaseConfig;
1550     metadata.mMessageInfo = aMessageInfo;
1551 
1552     SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader));
1553     metadata.mOffset += sizeof(Dns::UpdateHeader);
1554 
1555     VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1556     VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop);
1557 
1558     ProcessDnsUpdate(aMessage, metadata);
1559 
1560 exit:
1561     return error;
1562 }
1563 
HandleLeaseTimer(void)1564 void Server::HandleLeaseTimer(void)
1565 {
1566     TimeMilli now                = TimerMilli::GetNow();
1567     TimeMilli earliestExpireTime = now.GetDistantFuture();
1568     Host     *nextHost;
1569 
1570     for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1571     {
1572         nextHost = host->GetNext();
1573 
1574         if (host->GetKeyExpireTime() <= now)
1575         {
1576             LogInfo("KEY LEASE of host %s expired", host->GetFullName());
1577 
1578             // Removes the whole host and all services if the KEY RR expired.
1579             RemoveHost(host, kDeleteName);
1580         }
1581         else if (host->IsDeleted())
1582         {
1583             // The host has been deleted, but the hostname & service instance names retain.
1584 
1585             Service *next;
1586 
1587             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1588 
1589             // Check if any service instance name expired.
1590             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1591             {
1592                 next = service->GetNext();
1593 
1594                 OT_ASSERT(service->mIsDeleted);
1595 
1596                 if (service->GetKeyExpireTime() <= now)
1597                 {
1598                     service->Log(Service::kKeyLeaseExpired);
1599                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1600                 }
1601                 else
1602                 {
1603                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1604                 }
1605             }
1606         }
1607         else if (host->GetExpireTime() <= now)
1608         {
1609             LogInfo("LEASE of host %s expired", host->GetFullName());
1610 
1611             // If the host expired, delete all resources of this host and its services.
1612             for (Service &service : host->mServices)
1613             {
1614                 // Don't need to notify the service handler as `RemoveHost` at below will do.
1615                 host->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
1616             }
1617 
1618             RemoveHost(host, kRetainName);
1619 
1620             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1621         }
1622         else
1623         {
1624             // The host doesn't expire, check if any service expired or is explicitly removed.
1625 
1626             Service *next;
1627 
1628             OT_ASSERT(!host->IsDeleted());
1629 
1630             earliestExpireTime = Min(earliestExpireTime, host->GetExpireTime());
1631 
1632             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1633             {
1634                 next = service->GetNext();
1635 
1636                 if (service->GetKeyExpireTime() <= now)
1637                 {
1638                     service->Log(Service::kKeyLeaseExpired);
1639                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1640                 }
1641                 else if (service->mIsDeleted)
1642                 {
1643                     // The service has been deleted but the name retains.
1644                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1645                 }
1646                 else if (service->GetExpireTime() <= now)
1647                 {
1648                     service->Log(Service::kLeaseExpired);
1649 
1650                     // The service is expired, delete it.
1651                     host->RemoveService(service, kRetainName, kNotifyServiceHandler);
1652                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1653                 }
1654                 else
1655                 {
1656                     earliestExpireTime = Min(earliestExpireTime, service->GetExpireTime());
1657                 }
1658             }
1659         }
1660     }
1661 
1662     if (earliestExpireTime != now.GetDistantFuture())
1663     {
1664         OT_ASSERT(earliestExpireTime >= now);
1665         if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1666         {
1667             LogInfo("Lease timer is scheduled for %lu seconds", ToUlong(Time::MsecToSec(earliestExpireTime - now)));
1668             mLeaseTimer.StartAt(earliestExpireTime, 0);
1669         }
1670     }
1671     else
1672     {
1673         LogInfo("Lease timer is stopped");
1674         mLeaseTimer.Stop();
1675     }
1676 }
1677 
HandleOutstandingUpdatesTimer(void)1678 void Server::HandleOutstandingUpdatesTimer(void)
1679 {
1680     TimeMilli       now = TimerMilli::GetNow();
1681     UpdateMetadata *update;
1682 
1683     while ((update = mOutstandingUpdates.GetTail()) != nullptr)
1684     {
1685         if (update->GetExpireTime() > now)
1686         {
1687             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1688             break;
1689         }
1690 
1691         LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(update->GetId()));
1692 
1693         IgnoreError(mOutstandingUpdates.Remove(*update));
1694         update->SetError(kErrorResponseTimeout);
1695         CommitSrpUpdate(*update);
1696     }
1697 }
1698 
AddressModeToString(AddressMode aMode)1699 const char *Server::AddressModeToString(AddressMode aMode)
1700 {
1701     static const char *const kAddressModeStrings[] = {
1702         "unicast", // (0) kAddressModeUnicast
1703         "anycast", // (1) kAddressModeAnycast
1704     };
1705 
1706     static_assert(kAddressModeUnicast == 0, "kAddressModeUnicast value is incorrect");
1707     static_assert(kAddressModeAnycast == 1, "kAddressModeAnycast value is incorrect");
1708 
1709     return kAddressModeStrings[aMode];
1710 }
1711 
UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)1712 void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
1713 {
1714     switch (aResponseCode)
1715     {
1716     case Dns::UpdateHeader::kResponseSuccess:
1717         ++mResponseCounters.mSuccess;
1718         break;
1719     case Dns::UpdateHeader::kResponseServerFailure:
1720         ++mResponseCounters.mServerFailure;
1721         break;
1722     case Dns::UpdateHeader::kResponseFormatError:
1723         ++mResponseCounters.mFormatError;
1724         break;
1725     case Dns::UpdateHeader::kResponseNameExists:
1726         ++mResponseCounters.mNameExists;
1727         break;
1728     case Dns::UpdateHeader::kResponseRefused:
1729         ++mResponseCounters.mRefused;
1730         break;
1731     default:
1732         ++mResponseCounters.mOther;
1733         break;
1734     }
1735 }
1736 
1737 //---------------------------------------------------------------------------------------------------------------------
1738 // Server::Service
1739 
Init(const char * aInstanceName,const char * aInstanceLabel,Host & aHost,TimeMilli aUpdateTime)1740 Error Server::Service::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime)
1741 {
1742     Error error;
1743 
1744     mNext        = nullptr;
1745     mHost        = &aHost;
1746     mPriority    = 0;
1747     mWeight      = 0;
1748     mTtl         = 0;
1749     mPort        = 0;
1750     mLease       = 0;
1751     mKeyLease    = 0;
1752     mUpdateTime  = aUpdateTime;
1753     mIsDeleted   = false;
1754     mIsCommitted = false;
1755 
1756     mParsedDeleteAllRrset = false;
1757     mParsedSrv            = false;
1758     mParsedTxt            = false;
1759 
1760     SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel));
1761     error = mInstanceName.Set(aInstanceName);
1762 
1763 exit:
1764     return error;
1765 }
1766 
GetSubTypeServiceNameAt(uint16_t aIndex) const1767 const char *Server::Service::GetSubTypeServiceNameAt(uint16_t aIndex) const
1768 {
1769     const Heap::String *subType = mSubTypes.At(aIndex);
1770 
1771     return (subType == nullptr) ? nullptr : subType->AsCString();
1772 }
1773 
ParseSubTypeServiceName(const char * aSubTypeServiceName,char * aLabel,uint8_t aLabelSize)1774 Error Server::Service::ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize)
1775 {
1776     Error       error = kErrorNone;
1777     const char *subPos;
1778     uint8_t     labelLength;
1779 
1780     aLabel[0] = kNullChar;
1781 
1782     subPos = StringFind(aSubTypeServiceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1783     VerifyOrExit(subPos != nullptr, error = kErrorInvalidArgs);
1784 
1785     if (subPos - aSubTypeServiceName < aLabelSize)
1786     {
1787         labelLength = static_cast<uint8_t>(subPos - aSubTypeServiceName);
1788     }
1789     else
1790     {
1791         labelLength = aLabelSize - 1;
1792         error       = kErrorNoBufs;
1793     }
1794 
1795     memcpy(aLabel, aSubTypeServiceName, labelLength);
1796     aLabel[labelLength] = kNullChar;
1797 
1798 exit:
1799     return error;
1800 }
1801 
GetExpireTime(void) const1802 TimeMilli Server::Service::GetExpireTime(void) const
1803 {
1804     OT_ASSERT(!mIsDeleted);
1805     OT_ASSERT(!GetHost().IsDeleted());
1806 
1807     return mUpdateTime + Time::SecToMsec(mLease);
1808 }
1809 
GetKeyExpireTime(void) const1810 TimeMilli Server::Service::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1811 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1812 void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1813 {
1814     TimeMilli now           = TimerMilli::GetNow();
1815     TimeMilli keyExpireTime = GetKeyExpireTime();
1816 
1817     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
1818     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
1819     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1820 
1821     if (!mIsDeleted)
1822     {
1823         TimeMilli expireTime = GetExpireTime();
1824 
1825         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1826     }
1827     else
1828     {
1829         aLeaseInfo.mRemainingLease = 0;
1830     }
1831 }
1832 
MatchesInstanceName(const char * aInstanceName) const1833 bool Server::Service::MatchesInstanceName(const char *aInstanceName) const { return Matches(aInstanceName); }
1834 
MatchesServiceName(const char * aServiceName) const1835 bool Server::Service::MatchesServiceName(const char *aServiceName) const
1836 {
1837     return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch);
1838 }
1839 
Matches(const char * aInstanceName) const1840 bool Server::Service::Matches(const char *aInstanceName) const
1841 {
1842     return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1843 }
1844 
HasSubTypeServiceName(const char * aSubTypeServiceName) const1845 bool Server::Service::HasSubTypeServiceName(const char *aSubTypeServiceName) const
1846 {
1847     bool has = false;
1848 
1849     for (const Heap::String &subType : mSubTypes)
1850     {
1851         if (StringMatch(subType.AsCString(), aSubTypeServiceName, kStringCaseInsensitiveMatch))
1852         {
1853             has = true;
1854             break;
1855         }
1856     }
1857 
1858     return has;
1859 }
1860 
1861 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(Action aAction) const1862 void Server::Service::Log(Action aAction) const
1863 {
1864     static const char *const kActionStrings[] = {
1865         "Add new",                   // (0) kAddNew
1866         "Update existing",           // (1) kUpdateExisting
1867         "Keep unchanged",            // (2) kKeepUnchanged
1868         "Remove but retain name of", // (3) kRemoveButRetainName
1869         "Fully remove",              // (4) kFullyRemove
1870         "LEASE expired for",         // (5) kLeaseExpired
1871         "KEY LEASE expired for",     // (6) kKeyLeaseExpired
1872     };
1873 
1874     static_assert(0 == kAddNew, "kAddNew value is incorrect");
1875     static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1876     static_assert(2 == kKeepUnchanged, "kKeepUnchanged value is incorrect");
1877     static_assert(3 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1878     static_assert(4 == kFullyRemove, "kFullyRemove value is incorrect");
1879     static_assert(5 == kLeaseExpired, "kLeaseExpired value is incorrect");
1880     static_assert(6 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1881 
1882     // We only log if the `Service` is marked as committed. This
1883     // ensures that temporary `Service` entries associated with a
1884     // newly received SRP update message are not logged (e.g., when
1885     // associated `Host` is being freed).
1886 
1887     if (mIsCommitted)
1888     {
1889         LogInfo("%s service '%s'", kActionStrings[aAction], GetInstanceName());
1890 
1891         for (const Heap::String &subType : mSubTypes)
1892         {
1893             Dns::Name::LabelBuffer label;
1894 
1895             IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label));
1896             LogInfo("  sub-type: %s", subType.AsCString());
1897         }
1898     }
1899 }
1900 #else
Log(Action) const1901 void Server::Service::Log(Action) const {}
1902 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1903 
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1904 Error Server::Service::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1905 {
1906     Error error;
1907 
1908     SuccessOrExit(error = mTxtData.SetFrom(aMessage, aOffset, aLength));
1909     VerifyOrExit(Dns::TxtRecord::VerifyTxtData(mTxtData.GetBytes(), mTxtData.GetLength(), /* aAllowEmpty */ false),
1910                  error = kErrorParse);
1911 
1912 exit:
1913     if (error != kErrorNone)
1914     {
1915         mTxtData.Free();
1916     }
1917 
1918     return error;
1919 }
1920 
1921 //---------------------------------------------------------------------------------------------------------------------
1922 // Server::Host
1923 
Host(Instance & aInstance,TimeMilli aUpdateTime)1924 Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
1925     : InstanceLocator(aInstance)
1926     , mNext(nullptr)
1927     , mTtl(0)
1928     , mLease(0)
1929     , mKeyLease(0)
1930     , mUpdateTime(aUpdateTime)
1931     , mParsedKey(false)
1932     , mUseShortLeaseOption(false)
1933 {
1934 }
1935 
~Host(void)1936 Server::Host::~Host(void) { FreeAllServices(); }
1937 
SetFullName(const char * aFullName)1938 Error Server::Host::SetFullName(const char *aFullName)
1939 {
1940     // `mFullName` becomes immutable after it is set, so if it is
1941     // already set, we only accept a `aFullName` that matches the
1942     // current name.
1943 
1944     Error error;
1945 
1946     if (mFullName.IsNull())
1947     {
1948         error = mFullName.Set(aFullName);
1949     }
1950     else
1951     {
1952         error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1953     }
1954 
1955     return error;
1956 }
1957 
Matches(const char * aFullName) const1958 bool Server::Host::Matches(const char *aFullName) const
1959 {
1960     return StringMatch(mFullName.AsCString(), aFullName, kStringCaseInsensitiveMatch);
1961 }
1962 
GetExpireTime(void) const1963 TimeMilli Server::Host::GetExpireTime(void) const
1964 {
1965     OT_ASSERT(!IsDeleted());
1966 
1967     return mUpdateTime + Time::SecToMsec(mLease);
1968 }
1969 
GetKeyExpireTime(void) const1970 TimeMilli Server::Host::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1971 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1972 void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1973 {
1974     TimeMilli now           = TimerMilli::GetNow();
1975     TimeMilli keyExpireTime = GetKeyExpireTime();
1976 
1977     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
1978     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
1979     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1980 
1981     if (!IsDeleted())
1982     {
1983         TimeMilli expireTime = GetExpireTime();
1984 
1985         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1986     }
1987     else
1988     {
1989         aLeaseInfo.mRemainingLease = 0;
1990     }
1991 }
1992 
ProcessTtl(uint32_t aTtl)1993 Error Server::Host::ProcessTtl(uint32_t aTtl)
1994 {
1995     // This method processes the TTL value received in a resource record.
1996     //
1997     // If no TTL value is stored, this method will set the stored value to @p aTtl and return `kErrorNone`.
1998     // If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
1999     // Otherwise, this method returns `kErrorRejected`.
2000 
2001     Error error = kErrorRejected;
2002 
2003     VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
2004 
2005     mTtl = aTtl;
2006 
2007     error = kErrorNone;
2008 
2009 exit:
2010     return error;
2011 }
2012 
GetNextService(const Service * aPrevService) const2013 const Server::Service *Server::Host::GetNextService(const Service *aPrevService) const
2014 {
2015     return (aPrevService == nullptr) ? mServices.GetHead() : aPrevService->GetNext();
2016 }
2017 
AddNewService(const char * aInstanceName,const char * aInstanceLabel,TimeMilli aUpdateTime)2018 Server::Service *Server::Host::AddNewService(const char *aInstanceName,
2019                                              const char *aInstanceLabel,
2020                                              TimeMilli   aUpdateTime)
2021 {
2022     Service *service = Service::AllocateAndInit(aInstanceName, aInstanceLabel, *this, aUpdateTime);
2023 
2024     VerifyOrExit(service != nullptr);
2025     AddService(*service);
2026 
2027 exit:
2028     return service;
2029 }
2030 
AddService(Service & aService)2031 void Server::Host::AddService(Service &aService)
2032 {
2033     aService.mHost = this;
2034     mServices.Push(aService);
2035 }
2036 
RemoveService(Service * aService,RetainName aRetainName,NotifyMode aNotifyServiceHandler)2037 void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
2038 {
2039     Server &server = Get<Server>();
2040 
2041     VerifyOrExit(aService != nullptr);
2042 
2043     aService->mIsDeleted = true;
2044 
2045     aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
2046 
2047     if (aNotifyServiceHandler && server.mServiceUpdateHandler.IsSet())
2048     {
2049         uint32_t updateId = server.AllocateId();
2050 
2051         LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
2052         server.mServiceUpdateHandler.Invoke(updateId, this, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
2053         // We don't wait for the reply from the service update handler,
2054         // but always remove the service regardless of service update result.
2055         // Because removing a service should fail only when there is system
2056         // failure of the platform mDNS implementation and in which case the
2057         // service is not expected to be still registered.
2058     }
2059 
2060     if (!aRetainName)
2061     {
2062         IgnoreError(mServices.Remove(*aService));
2063         aService->Free();
2064     }
2065 
2066 exit:
2067     return;
2068 }
2069 
FreeAllServices(void)2070 void Server::Host::FreeAllServices(void)
2071 {
2072     while (!mServices.IsEmpty())
2073     {
2074         RemoveService(mServices.GetHead(), kDeleteName, kDoNotNotifyServiceHandler);
2075     }
2076 }
2077 
ClearResources(void)2078 void Server::Host::ClearResources(void) { mAddresses.Free(); }
2079 
FindService(const char * aInstanceName)2080 Server::Service *Server::Host::FindService(const char *aInstanceName) { return mServices.FindMatching(aInstanceName); }
2081 
FindService(const char * aInstanceName) const2082 const Server::Service *Server::Host::FindService(const char *aInstanceName) const
2083 {
2084     return mServices.FindMatching(aInstanceName);
2085 }
2086 
HasService(const char * aInstanceName) const2087 bool Server::Host::HasService(const char *aInstanceName) const { return mServices.ContainsMatching(aInstanceName); }
2088 
AddIp6Address(const Ip6::Address & aIp6Address)2089 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
2090 {
2091     Error error = kErrorNone;
2092 
2093     if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
2094     {
2095         // We don't like those address because they cannot be used
2096         // for communication with exterior devices.
2097         ExitNow(error = kErrorDrop);
2098     }
2099 
2100     // Drop duplicate addresses.
2101     VerifyOrExit(!mAddresses.Contains(aIp6Address), error = kErrorDrop);
2102 
2103     error = mAddresses.PushBack(aIp6Address);
2104 
2105     if (error == kErrorNoBufs)
2106     {
2107         LogWarn("Too many addresses for host %s", GetFullName());
2108     }
2109 
2110 exit:
2111     return error;
2112 }
2113 
2114 //---------------------------------------------------------------------------------------------------------------------
2115 // Server::UpdateMetadata
2116 
UpdateMetadata(Instance & aInstance,Host & aHost,const MessageMetadata & aMessageMetadata)2117 Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
2118     : InstanceLocator(aInstance)
2119     , mNext(nullptr)
2120     , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
2121     , mDnsHeader(aMessageMetadata.mDnsHeader)
2122     , mId(Get<Server>().AllocateId())
2123     , mTtlConfig(aMessageMetadata.mTtlConfig)
2124     , mLeaseConfig(aMessageMetadata.mLeaseConfig)
2125     , mHost(aHost)
2126     , mError(kErrorNone)
2127     , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
2128 {
2129     if (aMessageMetadata.mMessageInfo != nullptr)
2130     {
2131         mMessageInfo = *aMessageMetadata.mMessageInfo;
2132     }
2133 }
2134 
2135 } // namespace Srp
2136 } // namespace ot
2137 
2138 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2139