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/instance.hpp"
41 #include "common/locator_getters.hpp"
42 #include "common/log.hpp"
43 #include "common/new.hpp"
44 #include "common/num_utils.hpp"
45 #include "common/random.hpp"
46 #include "common/string.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     char     name[Dns::Name::kMaxNameSize];
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, sizeof(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         char                name[Dns::Name::kMaxNameSize];
865         Dns::ResourceRecord record;
866 
867         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(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         char                            serviceName[Dns::Name::kMaxNameSize];
956         char                            instanceLabel[Dns::Name::kMaxLabelSize];
957         char                            instanceServiceName[Dns::Name::kMaxNameSize];
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, sizeof(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, sizeof(instanceLabel),
981                                                     instanceServiceName, sizeof(instanceServiceName)));
982         instanceName.Append("%s.%s", instanceLabel, instanceServiceName);
983 
984         // Class None indicates "Delete an RR from an RRset".
985         isDelete = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
986 
987         VerifyOrExit(isDelete || ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorParse);
988 
989         // Check if the `serviceName` is a sub-type with name
990         // format: "<sub-label>._sub.<service-labels>.<domain>."
991 
992         subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
993         isSubType      = (subServiceName != nullptr);
994 
995         if (isSubType)
996         {
997             // Skip over the "._sub." label to get to the base
998             // service name.
999             subServiceName += sizeof(kServiceSubTypeLabel) - 1;
1000         }
1001 
1002         // Verify that instance name and service name are related.
1003         VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName.AsCString(), isSubType ? subServiceName : serviceName),
1004                      error = kErrorFailed);
1005 
1006         // Find a matching existing service or allocate a new one.
1007 
1008         service = aHost.FindService(instanceName.AsCString());
1009 
1010         if (service == nullptr)
1011         {
1012             service = aHost.AddNewService(instanceName.AsCString(), instanceLabel, aMetadata.mRxTime);
1013             VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1014         }
1015 
1016         if (isSubType)
1017         {
1018             VerifyOrExit(!service->HasSubTypeServiceName(serviceName), error = kErrorFailed);
1019 
1020             // Ignore a sub-type service delete.
1021 
1022             if (!isDelete)
1023             {
1024                 Heap::String *newSubTypeLabel = service->mSubTypes.PushBack();
1025 
1026                 VerifyOrExit(newSubTypeLabel != nullptr, error = kErrorNoBufs);
1027                 SuccessOrExit(error = newSubTypeLabel->Set(serviceName));
1028             }
1029         }
1030         else
1031         {
1032             // Processed PTR record is the base service (not a
1033             // sub-type). `mServiceName` is only set when base
1034             // service is processed.
1035 
1036             VerifyOrExit(service->mServiceName.IsNull(), error = kErrorFailed);
1037             SuccessOrExit(error = service->mServiceName.Set(serviceName));
1038             service->mIsDeleted = isDelete;
1039         }
1040 
1041         if (!isDelete)
1042         {
1043             SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
1044         }
1045     }
1046 
1047     // Verify that for all services, a PTR record was processed for
1048     // the base service (`mServiceName` is set), and for a deleted
1049     // service, no PTR record was seen adding a sub-type.
1050 
1051     for (const Service &service : aHost.mServices)
1052     {
1053         VerifyOrExit(!service.mServiceName.IsNull(), error = kErrorParse);
1054 
1055         if (service.mIsDeleted)
1056         {
1057             VerifyOrExit(service.mSubTypes.GetLength() == 0, error = kErrorParse);
1058         }
1059     }
1060 
1061 exit:
1062     if (error != kErrorNone)
1063     {
1064         LogWarn("Failed to process Service Discovery instructions: %s", ErrorToString(error));
1065     }
1066 
1067     return error;
1068 }
1069 
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const1070 Error Server::ProcessServiceDescriptionInstructions(Host            &aHost,
1071                                                     const Message   &aMessage,
1072                                                     MessageMetadata &aMetadata) const
1073 {
1074     Error    error  = kErrorNone;
1075     uint16_t offset = aMetadata.mOffset;
1076 
1077     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
1078     {
1079         char                name[Dns::Name::kMaxNameSize];
1080         Dns::ResourceRecord record;
1081         Service            *service;
1082 
1083         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1084         SuccessOrExit(error = aMessage.Read(offset, record));
1085 
1086         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
1087         {
1088             // Delete All RRsets from a name.
1089             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
1090 
1091             service = aHost.FindService(name);
1092 
1093             if (service != nullptr)
1094             {
1095                 VerifyOrExit(!service->mParsedDeleteAllRrset);
1096                 service->mParsedDeleteAllRrset = true;
1097             }
1098 
1099             offset += record.GetSize();
1100             continue;
1101         }
1102 
1103         if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
1104         {
1105             Dns::SrvRecord srvRecord;
1106             char           hostName[Dns::Name::kMaxNameSize];
1107             uint16_t       hostNameLength = sizeof(hostName);
1108 
1109             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1110 
1111             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1112 
1113             SuccessOrExit(error = aMessage.Read(offset, srvRecord));
1114             offset += sizeof(srvRecord);
1115 
1116             SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName, hostNameLength));
1117             VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
1118             VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
1119 
1120             service = aHost.FindService(name);
1121             VerifyOrExit(service != nullptr, error = kErrorFailed);
1122 
1123             VerifyOrExit(!service->mParsedSrv, error = kErrorParse);
1124             service->mParsedSrv = true;
1125 
1126             service->mTtl      = srvRecord.GetTtl();
1127             service->mPriority = srvRecord.GetPriority();
1128             service->mWeight   = srvRecord.GetWeight();
1129             service->mPort     = srvRecord.GetPort();
1130         }
1131         else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
1132         {
1133             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1134 
1135             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1136 
1137             service = aHost.FindService(name);
1138             VerifyOrExit(service != nullptr, error = kErrorFailed);
1139 
1140             service->mParsedTxt = true;
1141 
1142             offset += sizeof(record);
1143             SuccessOrExit(error = service->SetTxtDataFromMessage(aMessage, offset, record.GetLength()));
1144             offset += record.GetLength();
1145         }
1146         else
1147         {
1148             offset += record.GetSize();
1149         }
1150     }
1151 
1152     for (const Service &service : aHost.mServices)
1153     {
1154         VerifyOrExit(service.mParsedDeleteAllRrset, error = kErrorFailed);
1155         VerifyOrExit(service.mParsedSrv == service.mParsedTxt, error = kErrorFailed);
1156 
1157         if (!service.mIsDeleted)
1158         {
1159             VerifyOrExit(service.mParsedSrv, error = kErrorFailed);
1160         }
1161     }
1162 
1163     aMetadata.mOffset = offset;
1164 
1165 exit:
1166     if (error != kErrorNone)
1167     {
1168         LogWarn("Failed to process Service Description instructions: %s", ErrorToString(error));
1169     }
1170 
1171     return error;
1172 }
1173 
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)1174 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
1175 {
1176     return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
1177            aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
1178 }
1179 
ProcessAdditionalSection(Host * aHost,const Message & aMessage,MessageMetadata & aMetadata) const1180 Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const
1181 {
1182     Error            error = kErrorNone;
1183     Dns::OptRecord   optRecord;
1184     Dns::LeaseOption leaseOption;
1185     Dns::SigRecord   sigRecord;
1186     char             name[2]; // The root domain name (".") is expected.
1187     uint16_t         offset = aMetadata.mOffset;
1188     uint16_t         sigOffset;
1189     uint16_t         sigRdataOffset;
1190     char             signerName[Dns::Name::kMaxNameSize];
1191     uint16_t         signatureLength;
1192 
1193     VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
1194 
1195     // EDNS(0) Update Lease Option.
1196 
1197     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1198     SuccessOrExit(error = aMessage.Read(offset, optRecord));
1199 
1200     SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength()));
1201 
1202     offset += optRecord.GetSize();
1203 
1204     aHost->SetLease(leaseOption.GetLeaseInterval());
1205     aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
1206 
1207     // If the client included the short variant of Lease Option,
1208     // server must also use the short variant in its response.
1209     aHost->SetUseShortLeaseOption(leaseOption.IsShortVariant());
1210 
1211     if (aHost->GetLease() > 0)
1212     {
1213         uint8_t hostAddressesNum;
1214 
1215         aHost->GetAddresses(hostAddressesNum);
1216 
1217         // There MUST be at least one valid address if we have nonzero lease.
1218         VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
1219     }
1220 
1221     // SIG(0).
1222 
1223     sigOffset = offset;
1224     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name, sizeof(name)));
1225     SuccessOrExit(error = aMessage.Read(offset, sigRecord));
1226     VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
1227 
1228     sigRdataOffset = offset + sizeof(Dns::ResourceRecord);
1229     offset += sizeof(sigRecord);
1230 
1231     // TODO: Verify that the signature doesn't expire. This is not
1232     // implemented because the end device may not be able to get
1233     // the synchronized date/time.
1234 
1235     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName, sizeof(signerName)));
1236 
1237     signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset);
1238     offset += signatureLength;
1239 
1240     // Verify the signature. Currently supports only ECDSA.
1241 
1242     VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
1243     VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
1244     VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
1245 
1246     SuccessOrExit(error = VerifySignature(aHost->mKey, aMessage, aMetadata.mDnsHeader, sigOffset, sigRdataOffset,
1247                                           sigRecord.GetLength(), signerName));
1248 
1249     aMetadata.mOffset = offset;
1250 
1251 exit:
1252     if (error != kErrorNone)
1253     {
1254         LogWarn("Failed to process DNS Additional section: %s", ErrorToString(error));
1255     }
1256 
1257     return error;
1258 }
1259 
VerifySignature(const Host::Key & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const1260 Error Server::VerifySignature(const Host::Key  &aKey,
1261                               const Message    &aMessage,
1262                               Dns::UpdateHeader aDnsHeader,
1263                               uint16_t          aSigOffset,
1264                               uint16_t          aSigRdataOffset,
1265                               uint16_t          aSigRdataLength,
1266                               const char       *aSignerName) const
1267 {
1268     Error                          error;
1269     uint16_t                       offset = aMessage.GetOffset();
1270     uint16_t                       signatureOffset;
1271     Crypto::Sha256                 sha256;
1272     Crypto::Sha256::Hash           hash;
1273     Crypto::Ecdsa::P256::Signature signature;
1274     Message                       *signerNameMessage = nullptr;
1275 
1276     VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
1277 
1278     sha256.Start();
1279 
1280     // SIG RDATA less signature.
1281     sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
1282 
1283     // The uncompressed (canonical) form of the signer name should be used for signature
1284     // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
1285     signerNameMessage = Get<Ip6::Udp>().NewMessage();
1286     VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
1287     SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
1288     sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
1289 
1290     // We need the DNS header before appending the SIG RR.
1291     aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
1292     sha256.Update(aDnsHeader);
1293     sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
1294 
1295     sha256.Finish(hash);
1296 
1297     signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
1298     SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
1299 
1300     error = aKey.Verify(hash, signature);
1301 
1302 exit:
1303     if (error != kErrorNone)
1304     {
1305         LogWarn("Failed to verify message signature: %s", ErrorToString(error));
1306     }
1307 
1308     FreeMessage(signerNameMessage);
1309     return error;
1310 }
1311 
HandleUpdate(Host & aHost,const MessageMetadata & aMetadata)1312 void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
1313 {
1314     Error error = kErrorNone;
1315     Host *existingHost;
1316 
1317     // Check whether the SRP update wants to remove `aHost`.
1318 
1319     VerifyOrExit(aHost.GetLease() == 0);
1320 
1321     aHost.ClearResources();
1322 
1323     existingHost = mHosts.FindMatching(aHost.GetFullName());
1324     VerifyOrExit(existingHost != nullptr);
1325 
1326     // The client may not include all services it has registered before
1327     // when removing a host. We copy and append any missing services to
1328     // `aHost` from the `existingHost` and mark them as deleted.
1329 
1330     for (const Service &existingService : existingHost->mServices)
1331     {
1332         Service *service;
1333 
1334         if (existingService.mIsDeleted || aHost.HasService(existingService.GetInstanceName()))
1335         {
1336             continue;
1337         }
1338 
1339         service = aHost.AddNewService(existingService.GetInstanceName(), existingService.GetInstanceLabel(),
1340                                       aMetadata.mRxTime);
1341         VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1342 
1343         SuccessOrExit(error = service->mServiceName.Set(existingService.GetServiceName()));
1344         service->mIsDeleted = true;
1345     }
1346 
1347 exit:
1348     InformUpdateHandlerOrCommit(error, aHost, aMetadata);
1349 }
1350 
InformUpdateHandlerOrCommit(Error aError,Host & aHost,const MessageMetadata & aMetadata)1351 void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
1352 {
1353 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1354     if (aError == kErrorNone)
1355     {
1356         uint8_t             numAddrs;
1357         const Ip6::Address *addrs;
1358 
1359         LogInfo("Processed SRP update info");
1360         LogInfo("    Host:%s", aHost.GetFullName());
1361         LogInfo("    Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()),
1362                 ToUlong(aHost.GetTtl()));
1363 
1364         addrs = aHost.GetAddresses(numAddrs);
1365 
1366         if (numAddrs == 0)
1367         {
1368             LogInfo("    No host address");
1369         }
1370         else
1371         {
1372             LogInfo("    %d host address(es):", numAddrs);
1373 
1374             for (; numAddrs > 0; addrs++, numAddrs--)
1375             {
1376                 LogInfo("      %s", addrs->ToString().AsCString());
1377             }
1378         }
1379 
1380         for (const Service &service : aHost.mServices)
1381         {
1382             LogInfo("    %s service '%s'", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName());
1383 
1384             for (const Heap::String &subType : service.mSubTypes)
1385             {
1386                 char label[Dns::Name::kMaxLabelSize];
1387 
1388                 IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label)));
1389                 LogInfo("      sub-type: %s", label);
1390             }
1391         }
1392     }
1393     else
1394     {
1395         LogInfo("Error %s processing received SRP update", ErrorToString(aError));
1396     }
1397 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1398 
1399     if ((aError == kErrorNone) && mServiceUpdateHandler.IsSet())
1400     {
1401         UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
1402 
1403         if (update != nullptr)
1404         {
1405             mOutstandingUpdates.Push(*update);
1406             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1407 
1408             LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(update->GetId()));
1409             mServiceUpdateHandler.Invoke(update->GetId(), &aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
1410             ExitNow();
1411         }
1412 
1413         aError = kErrorNoBufs;
1414     }
1415 
1416     CommitSrpUpdate(aError, aHost, aMetadata);
1417 
1418 exit:
1419     return;
1420 }
1421 
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1422 void Server::SendResponse(const Dns::UpdateHeader    &aHeader,
1423                           Dns::UpdateHeader::Response aResponseCode,
1424                           const Ip6::MessageInfo     &aMessageInfo)
1425 {
1426     Error             error;
1427     Message          *response = nullptr;
1428     Dns::UpdateHeader header;
1429 
1430     response = GetSocket().NewMessage();
1431     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1432 
1433     header.SetMessageId(aHeader.GetMessageId());
1434     header.SetType(Dns::UpdateHeader::kTypeResponse);
1435     header.SetQueryType(aHeader.GetQueryType());
1436     header.SetResponseCode(aResponseCode);
1437     SuccessOrExit(error = response->Append(header));
1438 
1439     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1440 
1441     if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1442     {
1443         LogWarn("Send fail response: %d", aResponseCode);
1444     }
1445     else
1446     {
1447         LogInfo("Send success response");
1448     }
1449 
1450     UpdateResponseCounters(aResponseCode);
1451 
1452 exit:
1453     if (error != kErrorNone)
1454     {
1455         LogWarn("Failed to send response: %s", ErrorToString(error));
1456         FreeMessage(response);
1457     }
1458 }
1459 
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,bool mUseShortLeaseOption,const Ip6::MessageInfo & aMessageInfo)1460 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1461                           uint32_t                 aLease,
1462                           uint32_t                 aKeyLease,
1463                           bool                     mUseShortLeaseOption,
1464                           const Ip6::MessageInfo  &aMessageInfo)
1465 {
1466     Error             error;
1467     Message          *response = nullptr;
1468     Dns::UpdateHeader header;
1469     Dns::OptRecord    optRecord;
1470     Dns::LeaseOption  leaseOption;
1471     uint16_t          optionSize;
1472 
1473     response = GetSocket().NewMessage();
1474     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1475 
1476     header.SetMessageId(aHeader.GetMessageId());
1477     header.SetType(Dns::UpdateHeader::kTypeResponse);
1478     header.SetQueryType(aHeader.GetQueryType());
1479     header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1480     header.SetAdditionalRecordCount(1);
1481     SuccessOrExit(error = response->Append(header));
1482 
1483     // Append the root domain (".").
1484     SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1485 
1486     optRecord.Init();
1487     optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1488     optRecord.SetDnsSecurityFlag();
1489 
1490     if (mUseShortLeaseOption)
1491     {
1492         leaseOption.InitAsShortVariant(aLease);
1493     }
1494     else
1495     {
1496         leaseOption.InitAsLongVariant(aLease, aKeyLease);
1497     }
1498 
1499     optionSize = static_cast<uint16_t>(leaseOption.GetSize());
1500     optRecord.SetLength(optionSize);
1501 
1502     SuccessOrExit(error = response->Append(optRecord));
1503     SuccessOrExit(error = response->AppendBytes(&leaseOption, optionSize));
1504 
1505     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1506 
1507     LogInfo("Send success response with granted lease: %lu and key lease: %lu", ToUlong(aLease), ToUlong(aKeyLease));
1508 
1509     UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
1510 
1511 exit:
1512     if (error != kErrorNone)
1513     {
1514         LogWarn("Failed to send response: %s", ErrorToString(error));
1515         FreeMessage(response);
1516     }
1517 }
1518 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1519 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1520 {
1521     static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
1522 }
1523 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1524 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1525 {
1526     Error error = ProcessMessage(aMessage, aMessageInfo);
1527 
1528     if (error != kErrorNone)
1529     {
1530         LogInfo("Failed to handle DNS message: %s", ErrorToString(error));
1531     }
1532 }
1533 
ProcessMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1534 Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1535 {
1536     return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
1537 }
1538 
ProcessMessage(Message & aMessage,TimeMilli aRxTime,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig,const Ip6::MessageInfo * aMessageInfo)1539 Error Server::ProcessMessage(Message                &aMessage,
1540                              TimeMilli               aRxTime,
1541                              const TtlConfig        &aTtlConfig,
1542                              const LeaseConfig      &aLeaseConfig,
1543                              const Ip6::MessageInfo *aMessageInfo)
1544 {
1545     Error           error;
1546     MessageMetadata metadata;
1547 
1548     metadata.mOffset      = aMessage.GetOffset();
1549     metadata.mRxTime      = aRxTime;
1550     metadata.mTtlConfig   = aTtlConfig;
1551     metadata.mLeaseConfig = aLeaseConfig;
1552     metadata.mMessageInfo = aMessageInfo;
1553 
1554     SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader));
1555     metadata.mOffset += sizeof(Dns::UpdateHeader);
1556 
1557     VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1558     VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop);
1559 
1560     ProcessDnsUpdate(aMessage, metadata);
1561 
1562 exit:
1563     return error;
1564 }
1565 
HandleLeaseTimer(void)1566 void Server::HandleLeaseTimer(void)
1567 {
1568     TimeMilli now                = TimerMilli::GetNow();
1569     TimeMilli earliestExpireTime = now.GetDistantFuture();
1570     Host     *nextHost;
1571 
1572     for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1573     {
1574         nextHost = host->GetNext();
1575 
1576         if (host->GetKeyExpireTime() <= now)
1577         {
1578             LogInfo("KEY LEASE of host %s expired", host->GetFullName());
1579 
1580             // Removes the whole host and all services if the KEY RR expired.
1581             RemoveHost(host, kDeleteName);
1582         }
1583         else if (host->IsDeleted())
1584         {
1585             // The host has been deleted, but the hostname & service instance names retain.
1586 
1587             Service *next;
1588 
1589             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1590 
1591             // Check if any service instance name expired.
1592             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1593             {
1594                 next = service->GetNext();
1595 
1596                 OT_ASSERT(service->mIsDeleted);
1597 
1598                 if (service->GetKeyExpireTime() <= now)
1599                 {
1600                     service->Log(Service::kKeyLeaseExpired);
1601                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1602                 }
1603                 else
1604                 {
1605                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1606                 }
1607             }
1608         }
1609         else if (host->GetExpireTime() <= now)
1610         {
1611             LogInfo("LEASE of host %s expired", host->GetFullName());
1612 
1613             // If the host expired, delete all resources of this host and its services.
1614             for (Service &service : host->mServices)
1615             {
1616                 // Don't need to notify the service handler as `RemoveHost` at below will do.
1617                 host->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
1618             }
1619 
1620             RemoveHost(host, kRetainName);
1621 
1622             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1623         }
1624         else
1625         {
1626             // The host doesn't expire, check if any service expired or is explicitly removed.
1627 
1628             Service *next;
1629 
1630             OT_ASSERT(!host->IsDeleted());
1631 
1632             earliestExpireTime = Min(earliestExpireTime, host->GetExpireTime());
1633 
1634             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1635             {
1636                 next = service->GetNext();
1637 
1638                 if (service->GetKeyExpireTime() <= now)
1639                 {
1640                     service->Log(Service::kKeyLeaseExpired);
1641                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1642                 }
1643                 else if (service->mIsDeleted)
1644                 {
1645                     // The service has been deleted but the name retains.
1646                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1647                 }
1648                 else if (service->GetExpireTime() <= now)
1649                 {
1650                     service->Log(Service::kLeaseExpired);
1651 
1652                     // The service is expired, delete it.
1653                     host->RemoveService(service, kRetainName, kNotifyServiceHandler);
1654                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1655                 }
1656                 else
1657                 {
1658                     earliestExpireTime = Min(earliestExpireTime, service->GetExpireTime());
1659                 }
1660             }
1661         }
1662     }
1663 
1664     if (earliestExpireTime != now.GetDistantFuture())
1665     {
1666         OT_ASSERT(earliestExpireTime >= now);
1667         if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1668         {
1669             LogInfo("Lease timer is scheduled for %lu seconds", ToUlong(Time::MsecToSec(earliestExpireTime - now)));
1670             mLeaseTimer.StartAt(earliestExpireTime, 0);
1671         }
1672     }
1673     else
1674     {
1675         LogInfo("Lease timer is stopped");
1676         mLeaseTimer.Stop();
1677     }
1678 }
1679 
HandleOutstandingUpdatesTimer(void)1680 void Server::HandleOutstandingUpdatesTimer(void)
1681 {
1682     TimeMilli       now = TimerMilli::GetNow();
1683     UpdateMetadata *update;
1684 
1685     while ((update = mOutstandingUpdates.GetTail()) != nullptr)
1686     {
1687         if (update->GetExpireTime() > now)
1688         {
1689             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1690             break;
1691         }
1692 
1693         LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(update->GetId()));
1694 
1695         IgnoreError(mOutstandingUpdates.Remove(*update));
1696         update->SetError(kErrorResponseTimeout);
1697         CommitSrpUpdate(*update);
1698     }
1699 }
1700 
AddressModeToString(AddressMode aMode)1701 const char *Server::AddressModeToString(AddressMode aMode)
1702 {
1703     static const char *const kAddressModeStrings[] = {
1704         "unicast", // (0) kAddressModeUnicast
1705         "anycast", // (1) kAddressModeAnycast
1706     };
1707 
1708     static_assert(kAddressModeUnicast == 0, "kAddressModeUnicast value is incorrect");
1709     static_assert(kAddressModeAnycast == 1, "kAddressModeAnycast value is incorrect");
1710 
1711     return kAddressModeStrings[aMode];
1712 }
1713 
UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)1714 void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
1715 {
1716     switch (aResponseCode)
1717     {
1718     case Dns::UpdateHeader::kResponseSuccess:
1719         ++mResponseCounters.mSuccess;
1720         break;
1721     case Dns::UpdateHeader::kResponseServerFailure:
1722         ++mResponseCounters.mServerFailure;
1723         break;
1724     case Dns::UpdateHeader::kResponseFormatError:
1725         ++mResponseCounters.mFormatError;
1726         break;
1727     case Dns::UpdateHeader::kResponseNameExists:
1728         ++mResponseCounters.mNameExists;
1729         break;
1730     case Dns::UpdateHeader::kResponseRefused:
1731         ++mResponseCounters.mRefused;
1732         break;
1733     default:
1734         ++mResponseCounters.mOther;
1735         break;
1736     }
1737 }
1738 
1739 //---------------------------------------------------------------------------------------------------------------------
1740 // Server::Service
1741 
Init(const char * aInstanceName,const char * aInstanceLabel,Host & aHost,TimeMilli aUpdateTime)1742 Error Server::Service::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime)
1743 {
1744     Error error;
1745 
1746     mNext        = nullptr;
1747     mHost        = &aHost;
1748     mPriority    = 0;
1749     mWeight      = 0;
1750     mTtl         = 0;
1751     mPort        = 0;
1752     mLease       = 0;
1753     mKeyLease    = 0;
1754     mUpdateTime  = aUpdateTime;
1755     mIsDeleted   = false;
1756     mIsCommitted = false;
1757 
1758     mParsedDeleteAllRrset = false;
1759     mParsedSrv            = false;
1760     mParsedTxt            = false;
1761 
1762     SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel));
1763     error = mInstanceName.Set(aInstanceName);
1764 
1765 exit:
1766     return error;
1767 }
1768 
GetSubTypeServiceNameAt(uint16_t aIndex) const1769 const char *Server::Service::GetSubTypeServiceNameAt(uint16_t aIndex) const
1770 {
1771     const Heap::String *subType = mSubTypes.At(aIndex);
1772 
1773     return (subType == nullptr) ? nullptr : subType->AsCString();
1774 }
1775 
ParseSubTypeServiceName(const char * aSubTypeServiceName,char * aLabel,uint8_t aLabelSize)1776 Error Server::Service::ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize)
1777 {
1778     Error       error = kErrorNone;
1779     const char *subPos;
1780     uint8_t     labelLength;
1781 
1782     aLabel[0] = kNullChar;
1783 
1784     subPos = StringFind(aSubTypeServiceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1785     VerifyOrExit(subPos != nullptr, error = kErrorInvalidArgs);
1786 
1787     if (subPos - aSubTypeServiceName < aLabelSize)
1788     {
1789         labelLength = static_cast<uint8_t>(subPos - aSubTypeServiceName);
1790     }
1791     else
1792     {
1793         labelLength = aLabelSize - 1;
1794         error       = kErrorNoBufs;
1795     }
1796 
1797     memcpy(aLabel, aSubTypeServiceName, labelLength);
1798     aLabel[labelLength] = kNullChar;
1799 
1800 exit:
1801     return error;
1802 }
1803 
GetExpireTime(void) const1804 TimeMilli Server::Service::GetExpireTime(void) const
1805 {
1806     OT_ASSERT(!mIsDeleted);
1807     OT_ASSERT(!GetHost().IsDeleted());
1808 
1809     return mUpdateTime + Time::SecToMsec(mLease);
1810 }
1811 
GetKeyExpireTime(void) const1812 TimeMilli Server::Service::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1813 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1814 void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1815 {
1816     TimeMilli now           = TimerMilli::GetNow();
1817     TimeMilli keyExpireTime = GetKeyExpireTime();
1818 
1819     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
1820     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
1821     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1822 
1823     if (!mIsDeleted)
1824     {
1825         TimeMilli expireTime = GetExpireTime();
1826 
1827         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1828     }
1829     else
1830     {
1831         aLeaseInfo.mRemainingLease = 0;
1832     }
1833 }
1834 
MatchesInstanceName(const char * aInstanceName) const1835 bool Server::Service::MatchesInstanceName(const char *aInstanceName) const { return Matches(aInstanceName); }
1836 
MatchesServiceName(const char * aServiceName) const1837 bool Server::Service::MatchesServiceName(const char *aServiceName) const
1838 {
1839     return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch);
1840 }
1841 
Matches(const char * aInstanceName) const1842 bool Server::Service::Matches(const char *aInstanceName) const
1843 {
1844     return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1845 }
1846 
HasSubTypeServiceName(const char * aSubTypeServiceName) const1847 bool Server::Service::HasSubTypeServiceName(const char *aSubTypeServiceName) const
1848 {
1849     bool has = false;
1850 
1851     for (const Heap::String &subType : mSubTypes)
1852     {
1853         if (StringMatch(subType.AsCString(), aSubTypeServiceName, kStringCaseInsensitiveMatch))
1854         {
1855             has = true;
1856             break;
1857         }
1858     }
1859 
1860     return has;
1861 }
1862 
1863 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(Action aAction) const1864 void Server::Service::Log(Action aAction) const
1865 {
1866     static const char *const kActionStrings[] = {
1867         "Add new",                   // (0) kAddNew
1868         "Update existing",           // (1) kUpdateExisting
1869         "Keep unchanged",            // (2) kKeepUnchanged
1870         "Remove but retain name of", // (3) kRemoveButRetainName
1871         "Fully remove",              // (4) kFullyRemove
1872         "LEASE expired for",         // (5) kLeaseExpired
1873         "KEY LEASE expired for",     // (6) kKeyLeaseExpired
1874     };
1875 
1876     static_assert(0 == kAddNew, "kAddNew value is incorrect");
1877     static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1878     static_assert(2 == kKeepUnchanged, "kKeepUnchanged value is incorrect");
1879     static_assert(3 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1880     static_assert(4 == kFullyRemove, "kFullyRemove value is incorrect");
1881     static_assert(5 == kLeaseExpired, "kLeaseExpired value is incorrect");
1882     static_assert(6 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1883 
1884     // We only log if the `Service` is marked as committed. This
1885     // ensures that temporary `Service` entries associated with a
1886     // newly received SRP update message are not logged (e.g., when
1887     // associated `Host` is being freed).
1888 
1889     if (mIsCommitted)
1890     {
1891         LogInfo("%s service '%s'", kActionStrings[aAction], GetInstanceName());
1892 
1893         for (const Heap::String &subType : mSubTypes)
1894         {
1895             char label[Dns::Name::kMaxLabelSize];
1896 
1897             IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label, sizeof(label)));
1898             LogInfo("  sub-type: %s", subType.AsCString());
1899         }
1900     }
1901 }
1902 #else
Log(Action) const1903 void Server::Service::Log(Action) const {}
1904 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1905 
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1906 Error Server::Service::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1907 {
1908     Error error;
1909 
1910     SuccessOrExit(error = mTxtData.SetFrom(aMessage, aOffset, aLength));
1911     VerifyOrExit(Dns::TxtRecord::VerifyTxtData(mTxtData.GetBytes(), mTxtData.GetLength(), /* aAllowEmpty */ false),
1912                  error = kErrorParse);
1913 
1914 exit:
1915     if (error != kErrorNone)
1916     {
1917         mTxtData.Free();
1918     }
1919 
1920     return error;
1921 }
1922 
1923 //---------------------------------------------------------------------------------------------------------------------
1924 // Server::Host
1925 
Host(Instance & aInstance,TimeMilli aUpdateTime)1926 Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
1927     : InstanceLocator(aInstance)
1928     , mNext(nullptr)
1929     , mTtl(0)
1930     , mLease(0)
1931     , mKeyLease(0)
1932     , mUpdateTime(aUpdateTime)
1933     , mParsedKey(false)
1934     , mUseShortLeaseOption(false)
1935 {
1936 }
1937 
~Host(void)1938 Server::Host::~Host(void) { FreeAllServices(); }
1939 
SetFullName(const char * aFullName)1940 Error Server::Host::SetFullName(const char *aFullName)
1941 {
1942     // `mFullName` becomes immutable after it is set, so if it is
1943     // already set, we only accept a `aFullName` that matches the
1944     // current name.
1945 
1946     Error error;
1947 
1948     if (mFullName.IsNull())
1949     {
1950         error = mFullName.Set(aFullName);
1951     }
1952     else
1953     {
1954         error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1955     }
1956 
1957     return error;
1958 }
1959 
Matches(const char * aFullName) const1960 bool Server::Host::Matches(const char *aFullName) const
1961 {
1962     return StringMatch(mFullName.AsCString(), aFullName, kStringCaseInsensitiveMatch);
1963 }
1964 
GetExpireTime(void) const1965 TimeMilli Server::Host::GetExpireTime(void) const
1966 {
1967     OT_ASSERT(!IsDeleted());
1968 
1969     return mUpdateTime + Time::SecToMsec(mLease);
1970 }
1971 
GetKeyExpireTime(void) const1972 TimeMilli Server::Host::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1973 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1974 void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1975 {
1976     TimeMilli now           = TimerMilli::GetNow();
1977     TimeMilli keyExpireTime = GetKeyExpireTime();
1978 
1979     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
1980     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
1981     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1982 
1983     if (!IsDeleted())
1984     {
1985         TimeMilli expireTime = GetExpireTime();
1986 
1987         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1988     }
1989     else
1990     {
1991         aLeaseInfo.mRemainingLease = 0;
1992     }
1993 }
1994 
ProcessTtl(uint32_t aTtl)1995 Error Server::Host::ProcessTtl(uint32_t aTtl)
1996 {
1997     // This method processes the TTL value received in a resource record.
1998     //
1999     // If no TTL value is stored, this method will set the stored value to @p aTtl and return `kErrorNone`.
2000     // If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
2001     // Otherwise, this method returns `kErrorRejected`.
2002 
2003     Error error = kErrorRejected;
2004 
2005     VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
2006 
2007     mTtl = aTtl;
2008 
2009     error = kErrorNone;
2010 
2011 exit:
2012     return error;
2013 }
2014 
GetNextService(const Service * aPrevService) const2015 const Server::Service *Server::Host::GetNextService(const Service *aPrevService) const
2016 {
2017     return (aPrevService == nullptr) ? mServices.GetHead() : aPrevService->GetNext();
2018 }
2019 
AddNewService(const char * aInstanceName,const char * aInstanceLabel,TimeMilli aUpdateTime)2020 Server::Service *Server::Host::AddNewService(const char *aInstanceName,
2021                                              const char *aInstanceLabel,
2022                                              TimeMilli   aUpdateTime)
2023 {
2024     Service *service = Service::AllocateAndInit(aInstanceName, aInstanceLabel, *this, aUpdateTime);
2025 
2026     VerifyOrExit(service != nullptr);
2027     AddService(*service);
2028 
2029 exit:
2030     return service;
2031 }
2032 
AddService(Service & aService)2033 void Server::Host::AddService(Service &aService)
2034 {
2035     aService.mHost = this;
2036     mServices.Push(aService);
2037 }
2038 
RemoveService(Service * aService,RetainName aRetainName,NotifyMode aNotifyServiceHandler)2039 void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
2040 {
2041     Server &server = Get<Server>();
2042 
2043     VerifyOrExit(aService != nullptr);
2044 
2045     aService->mIsDeleted = true;
2046 
2047     aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
2048 
2049     if (aNotifyServiceHandler && server.mServiceUpdateHandler.IsSet())
2050     {
2051         uint32_t updateId = server.AllocateId();
2052 
2053         LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
2054         server.mServiceUpdateHandler.Invoke(updateId, this, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
2055         // We don't wait for the reply from the service update handler,
2056         // but always remove the service regardless of service update result.
2057         // Because removing a service should fail only when there is system
2058         // failure of the platform mDNS implementation and in which case the
2059         // service is not expected to be still registered.
2060     }
2061 
2062     if (!aRetainName)
2063     {
2064         IgnoreError(mServices.Remove(*aService));
2065         aService->Free();
2066     }
2067 
2068 exit:
2069     return;
2070 }
2071 
FreeAllServices(void)2072 void Server::Host::FreeAllServices(void)
2073 {
2074     while (!mServices.IsEmpty())
2075     {
2076         RemoveService(mServices.GetHead(), kDeleteName, kDoNotNotifyServiceHandler);
2077     }
2078 }
2079 
ClearResources(void)2080 void Server::Host::ClearResources(void) { mAddresses.Free(); }
2081 
FindService(const char * aInstanceName)2082 Server::Service *Server::Host::FindService(const char *aInstanceName) { return mServices.FindMatching(aInstanceName); }
2083 
FindService(const char * aInstanceName) const2084 const Server::Service *Server::Host::FindService(const char *aInstanceName) const
2085 {
2086     return mServices.FindMatching(aInstanceName);
2087 }
2088 
HasService(const char * aInstanceName) const2089 bool Server::Host::HasService(const char *aInstanceName) const { return mServices.ContainsMatching(aInstanceName); }
2090 
AddIp6Address(const Ip6::Address & aIp6Address)2091 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
2092 {
2093     Error error = kErrorNone;
2094 
2095     if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
2096     {
2097         // We don't like those address because they cannot be used
2098         // for communication with exterior devices.
2099         ExitNow(error = kErrorDrop);
2100     }
2101 
2102     // Drop duplicate addresses.
2103     VerifyOrExit(!mAddresses.Contains(aIp6Address), error = kErrorDrop);
2104 
2105     error = mAddresses.PushBack(aIp6Address);
2106 
2107     if (error == kErrorNoBufs)
2108     {
2109         LogWarn("Too many addresses for host %s", GetFullName());
2110     }
2111 
2112 exit:
2113     return error;
2114 }
2115 
2116 //---------------------------------------------------------------------------------------------------------------------
2117 // Server::UpdateMetadata
2118 
UpdateMetadata(Instance & aInstance,Host & aHost,const MessageMetadata & aMessageMetadata)2119 Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
2120     : InstanceLocator(aInstance)
2121     , mNext(nullptr)
2122     , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
2123     , mDnsHeader(aMessageMetadata.mDnsHeader)
2124     , mId(Get<Server>().AllocateId())
2125     , mTtlConfig(aMessageMetadata.mTtlConfig)
2126     , mLeaseConfig(aMessageMetadata.mLeaseConfig)
2127     , mHost(aHost)
2128     , mError(kErrorNone)
2129     , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
2130 {
2131     if (aMessageMetadata.mMessageInfo != nullptr)
2132     {
2133         mMessageInfo = *aMessageMetadata.mMessageInfo;
2134     }
2135 }
2136 
2137 } // namespace Srp
2138 } // namespace ot
2139 
2140 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2141