• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(kUninitializedPort)
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 = AllocateServiceUpdateId();
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 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
343     else
344     {
345         Get<AdvertisingProxy>().AdvertiseRemovalOf(*aHost);
346     }
347 #endif
348 
349     if (!aRetainName)
350     {
351         aHost->Free();
352     }
353 
354 exit:
355     return;
356 }
357 
HasNameConflictsWith(Host & aHost) const358 bool Server::HasNameConflictsWith(Host &aHost) const
359 {
360     bool        hasConflicts = false;
361     const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
362 
363     if ((existingHost != nullptr) && (aHost.mKey != existingHost->mKey))
364     {
365         LogWarn("Name conflict: host name %s has already been allocated", aHost.GetFullName());
366         ExitNow(hasConflicts = true);
367     }
368 
369     for (const Service &service : aHost.mServices)
370     {
371         // Check on all hosts for a matching service with the same
372         // instance name and if found, verify that it has the same
373         // key.
374 
375         for (const Host &host : mHosts)
376         {
377             if (host.HasService(service.GetInstanceName()) && (aHost.mKey != host.mKey))
378             {
379                 LogWarn("Name conflict: service name %s has already been allocated", service.GetInstanceName());
380                 ExitNow(hasConflicts = true);
381             }
382         }
383     }
384 
385 exit:
386     return hasConflicts;
387 }
388 
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)389 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
390 {
391     UpdateMetadata *update = mOutstandingUpdates.RemoveMatching(aId);
392 
393     if (update == nullptr)
394     {
395         LogInfo("Delayed SRP host update result, the SRP update has been committed (updateId = %lu)", ToUlong(aId));
396         ExitNow();
397     }
398 
399     update->SetError(aError);
400 
401     LogInfo("Handler result of SRP update (id = %lu) is received: %s", ToUlong(update->GetId()), ErrorToString(aError));
402 
403     // We add new `update` at the tail of the `mCompletedUpdates` list
404     // so that updates are processed in the order we receive the
405     // `HandleServiceUpdateResult()` callbacks for them. The
406     // completed updates are processed from `mCompletedUpdateTask`
407     // and `ProcessCompletedUpdates()`.
408 
409     mCompletedUpdates.PushAfterTail(*update);
410     mCompletedUpdateTask.Post();
411 
412     if (mOutstandingUpdates.IsEmpty())
413     {
414         mOutstandingUpdatesTimer.Stop();
415     }
416     else
417     {
418         mOutstandingUpdatesTimer.FireAt(mOutstandingUpdates.GetTail()->GetExpireTime());
419     }
420 
421 exit:
422     return;
423 }
424 
ProcessCompletedUpdates(void)425 void Server::ProcessCompletedUpdates(void)
426 {
427     UpdateMetadata *update;
428 
429     while ((update = mCompletedUpdates.Pop()) != nullptr)
430     {
431         CommitSrpUpdate(*update);
432     }
433 }
434 
CommitSrpUpdate(Error aError,Host & aHost,const MessageMetadata & aMessageMetadata)435 void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
436 {
437     CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
438                     aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
439 }
440 
CommitSrpUpdate(UpdateMetadata & aUpdateMetadata)441 void Server::CommitSrpUpdate(UpdateMetadata &aUpdateMetadata)
442 {
443     CommitSrpUpdate(aUpdateMetadata.GetError(), aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
444                     aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
445                     aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
446 
447     aUpdateMetadata.Free();
448 }
449 
CommitSrpUpdate(Error aError,Host & aHost,const Dns::UpdateHeader & aDnsHeader,const Ip6::MessageInfo * aMessageInfo,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig)450 void Server::CommitSrpUpdate(Error                    aError,
451                              Host                    &aHost,
452                              const Dns::UpdateHeader &aDnsHeader,
453                              const Ip6::MessageInfo  *aMessageInfo,
454                              const TtlConfig         &aTtlConfig,
455                              const LeaseConfig       &aLeaseConfig)
456 {
457     Host    *existingHost    = nullptr;
458     uint32_t grantedTtl      = 0;
459     uint32_t hostLease       = 0;
460     uint32_t hostKeyLease    = 0;
461     uint32_t grantedLease    = 0;
462     uint32_t grantedKeyLease = 0;
463     bool     useShortLease   = aHost.ShouldUseShortLeaseOption();
464 
465     if (aError != kErrorNone || (mState != kStateRunning))
466     {
467         aHost.Free();
468         ExitNow();
469     }
470 
471     hostLease       = aHost.GetLease();
472     hostKeyLease    = aHost.GetKeyLease();
473     grantedLease    = aLeaseConfig.GrantLease(hostLease);
474     grantedKeyLease = useShortLease ? grantedLease : aLeaseConfig.GrantKeyLease(hostKeyLease);
475     grantedTtl      = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
476 
477     existingHost = mHosts.RemoveMatching(aHost.GetFullName());
478 
479     LogInfo("Committing update for %s host %s", (existingHost != nullptr) ? "existing" : "new", aHost.GetFullName());
480     LogInfo("    Granted lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(grantedLease), ToUlong(grantedKeyLease),
481             ToUlong(grantedTtl));
482 
483     aHost.SetLease(grantedLease);
484     aHost.SetKeyLease(grantedKeyLease);
485     aHost.SetTtl(grantedTtl);
486 
487     if (grantedKeyLease == 0)
488     {
489         VerifyOrExit(existingHost != nullptr);
490         LogInfo("Fully remove host %s", aHost.GetFullName());
491         aHost.Free();
492         ExitNow();
493     }
494 
495     mHosts.Push(aHost);
496 
497     for (Service &service : aHost.mServices)
498     {
499         service.mLease       = grantedLease;
500         service.mKeyLease    = grantedKeyLease;
501         service.mTtl         = grantedTtl;
502         service.mIsCommitted = true;
503 
504 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
505         {
506             Service::Action action = Service::kAddNew;
507 
508             if (service.mIsDeleted)
509             {
510                 action = Service::kRemoveButRetainName;
511             }
512             else if ((existingHost != nullptr) && existingHost->HasService(service.GetInstanceName()))
513             {
514                 action = Service::kUpdateExisting;
515             }
516 
517             service.Log(action);
518         }
519 #endif
520     }
521 
522     if (existingHost != nullptr)
523     {
524         // Move any existing service that is not included in the new
525         // update into `aHost`.
526 
527         Service *existingService;
528 
529         while ((existingService = existingHost->mServices.Pop()) != nullptr)
530         {
531             if (!aHost.HasService(existingService->GetInstanceName()))
532             {
533                 aHost.AddService(*existingService);
534 
535                 // If host is deleted we make sure to add any existing
536                 // service that is not already included as deleted.
537                 // When processing an SRP update message that removes
538                 // a host, we construct `aHost` and add any existing
539                 // services that we have for the same host name as
540                 // deleted. However, due to asynchronous nature
541                 // of "update handler" (advertising proxy), by the
542                 // time we get the callback to commit `aHost`, there
543                 // may be new services added that were not included
544                 // when constructing `aHost`.
545 
546                 if (aHost.IsDeleted() && !existingService->IsDeleted())
547                 {
548                     existingService->mIsDeleted = true;
549                     existingService->Log(Service::kRemoveButRetainName);
550                 }
551                 else
552                 {
553                     existingService->Log(Service::kKeepUnchanged);
554                 }
555             }
556             else
557             {
558                 existingService->Free();
559             }
560         }
561     }
562 
563 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
564     if (!mHasRegisteredAnyService && (mAddressMode == kAddressModeUnicast))
565     {
566         Settings::SrpServerInfo info;
567 
568         mHasRegisteredAnyService = true;
569         info.SetPort(GetSocket().mSockName.mPort);
570         IgnoreError(Get<Settings>().Save(info));
571     }
572 #endif
573 
574     if (!aHost.IsDeleted())
575     {
576         mLeaseTimer.FireAtIfEarlier(Min(aHost.GetExpireTime(), aHost.GetKeyExpireTime()));
577     }
578 
579 exit:
580     if (aMessageInfo != nullptr)
581     {
582         if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
583         {
584             SendResponse(aDnsHeader, grantedLease, grantedKeyLease, useShortLease, *aMessageInfo);
585         }
586         else
587         {
588             SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), *aMessageInfo);
589         }
590     }
591 
592     if (existingHost != nullptr)
593     {
594         existingHost->Free();
595     }
596 }
597 
InitPort(void)598 void Server::InitPort(void)
599 {
600     mPort = kUdpPortMin;
601 
602 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
603     {
604         Settings::SrpServerInfo info;
605 
606         if (Get<Settings>().Read(info) == kErrorNone)
607         {
608             mPort = info.GetPort();
609         }
610     }
611 #endif
612 }
613 
SelectPort(void)614 void Server::SelectPort(void)
615 {
616     if (mPort == kUninitializedPort)
617     {
618         InitPort();
619     }
620     ++mPort;
621     if (mPort < kUdpPortMin || mPort > kUdpPortMax)
622     {
623         mPort = kUdpPortMin;
624     }
625 
626     LogInfo("Selected port %u", mPort);
627 }
628 
Start(void)629 void Server::Start(void)
630 {
631     Error error = kErrorNone;
632 
633     VerifyOrExit(mState == kStateStopped);
634 
635     mState = kStateRunning;
636     SuccessOrExit(error = PrepareSocket());
637     LogInfo("Start listening on port %u", mPort);
638 
639 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
640     Get<AdvertisingProxy>().HandleServerStateChange();
641 #endif
642 
643 exit:
644     // Re-enable server to select a new port.
645     if (error != kErrorNone)
646     {
647         Disable();
648         Enable();
649     }
650 }
651 
PrepareSocket(void)652 Error Server::PrepareSocket(void)
653 {
654     Error error = kErrorNone;
655 
656 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
657     Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
658 
659     if (dnsSocket.GetSockName().GetPort() == mPort)
660     {
661         // If the DNS-SD socket matches our port number, we use the
662         // same socket so we close our own socket (in case it was
663         // open). `GetSocket()` will now return the DNS-SD socket.
664 
665         IgnoreError(mSocket.Close());
666         ExitNow();
667     }
668 #endif
669 
670     VerifyOrExit(!mSocket.IsOpen());
671     SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
672     error = mSocket.Bind(mPort, Ip6::kNetifThread);
673 
674 exit:
675     if (error != kErrorNone)
676     {
677         LogWarnOnError(error, "prepare socket");
678         IgnoreError(mSocket.Close());
679         Stop();
680     }
681 
682     return error;
683 }
684 
GetSocket(void)685 Ip6::Udp::Socket &Server::GetSocket(void)
686 {
687     Ip6::Udp::Socket *socket = &mSocket;
688 
689 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
690     Ip6::Udp::Socket &dnsSocket = Get<Dns::ServiceDiscovery::Server>().mSocket;
691 
692     if (dnsSocket.GetSockName().GetPort() == mPort)
693     {
694         socket = &dnsSocket;
695     }
696 #endif
697 
698     return *socket;
699 }
700 
701 #if OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
702 
HandleDnssdServerStateChange(void)703 void Server::HandleDnssdServerStateChange(void)
704 {
705     // This is called from` Dns::ServiceDiscovery::Server` to notify
706     // that it has started or stopped. We check whether we need to
707     // share the socket.
708 
709     if (mState == kStateRunning)
710     {
711         IgnoreError(PrepareSocket());
712     }
713 }
714 
HandleDnssdServerUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)715 Error Server::HandleDnssdServerUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
716 {
717     // This is called from` Dns::ServiceDiscovery::Server` when a UDP
718     // message is received on its socket. We check whether we are
719     // sharing socket and if so we process the received message. We
720     // return `kErrorNone` to indicate that message was successfully
721     // processed by `Srp::Server`, otherwise `kErrorDrop` is returned.
722 
723     Error error = kErrorDrop;
724 
725     VerifyOrExit((mState == kStateRunning) && !mSocket.IsOpen());
726 
727     error = ProcessMessage(aMessage, aMessageInfo);
728 
729 exit:
730     return error;
731 }
732 
733 #endif // OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE
734 
Stop(void)735 void Server::Stop(void)
736 {
737     VerifyOrExit(mState == kStateRunning);
738 
739     mState = kStateStopped;
740 
741     while (!mHosts.IsEmpty())
742     {
743         RemoveHost(mHosts.GetHead(), kDeleteName);
744     }
745 
746     // TODO: We should cancel any outstanding service updates, but current
747     // OTBR mDNS publisher cannot properly handle it.
748     while (!mOutstandingUpdates.IsEmpty())
749     {
750         mOutstandingUpdates.Pop()->Free();
751     }
752 
753     mLeaseTimer.Stop();
754     mOutstandingUpdatesTimer.Stop();
755 
756     LogInfo("Stop listening on %u", mPort);
757     IgnoreError(mSocket.Close());
758     mHasRegisteredAnyService = false;
759 
760 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
761     Get<AdvertisingProxy>().HandleServerStateChange();
762 #endif
763 
764 exit:
765     return;
766 }
767 
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)768 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
769 {
770     switch (aEvent)
771     {
772     case NetworkData::Publisher::kEventEntryAdded:
773         Start();
774         break;
775 
776     case NetworkData::Publisher::kEventEntryRemoved:
777         Stop();
778         break;
779     }
780 }
781 
FindOutstandingUpdate(const MessageMetadata & aMessageMetadata) const782 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const MessageMetadata &aMessageMetadata) const
783 {
784     const UpdateMetadata *ret = nullptr;
785 
786     VerifyOrExit(aMessageMetadata.IsDirectRxFromClient());
787 
788     for (const UpdateMetadata &update : mOutstandingUpdates)
789     {
790         if (aMessageMetadata.mDnsHeader.GetMessageId() == update.GetDnsHeader().GetMessageId() &&
791             aMessageMetadata.mMessageInfo->GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
792             aMessageMetadata.mMessageInfo->GetPeerPort() == update.GetMessageInfo().GetPeerPort())
793         {
794             ExitNow(ret = &update);
795         }
796     }
797 
798 exit:
799     return ret;
800 }
801 
ProcessDnsUpdate(Message & aMessage,MessageMetadata & aMetadata)802 void Server::ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata)
803 {
804     Error error = kErrorNone;
805     Host *host  = nullptr;
806 
807     LogInfo("Received DNS update from %s", aMetadata.IsDirectRxFromClient()
808                                                ? aMetadata.mMessageInfo->GetPeerAddr().ToString().AsCString()
809                                                : "an SRPL Partner");
810 
811     SuccessOrExit(error = ProcessZoneSection(aMessage, aMetadata));
812 
813     if (FindOutstandingUpdate(aMetadata) != nullptr)
814     {
815         LogInfo("Drop duplicated SRP update request: MessageId=%u", aMetadata.mDnsHeader.GetMessageId());
816 
817         // Silently drop duplicate requests.
818         // This could rarely happen, because the outstanding SRP update timer should
819         // be shorter than the SRP update retransmission timer.
820         ExitNow(error = kErrorNone);
821     }
822 
823     // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
824     VerifyOrExit(aMetadata.mDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
825 
826     host = Host::Allocate(GetInstance(), aMetadata.mRxTime);
827     VerifyOrExit(host != nullptr, error = kErrorNoBufs);
828     SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aMetadata));
829 
830     // Parse lease time and validate signature.
831     SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aMetadata));
832 
833 #if OPENTHREAD_FTD
834     if (aMetadata.IsDirectRxFromClient())
835     {
836         UpdateAddrResolverCacheTable(*aMetadata.mMessageInfo, *host);
837     }
838 #endif
839 
840     HandleUpdate(*host, aMetadata);
841 
842 exit:
843     if (error != kErrorNone)
844     {
845         if (host != nullptr)
846         {
847             host->Free();
848         }
849 
850         if (aMetadata.IsDirectRxFromClient())
851         {
852             SendResponse(aMetadata.mDnsHeader, ErrorToDnsResponseCode(error), *aMetadata.mMessageInfo);
853         }
854     }
855 }
856 
ProcessZoneSection(const Message & aMessage,MessageMetadata & aMetadata) const857 Error Server::ProcessZoneSection(const Message &aMessage, MessageMetadata &aMetadata) const
858 {
859     Error             error = kErrorNone;
860     Dns::Name::Buffer name;
861     uint16_t          offset = aMetadata.mOffset;
862 
863     VerifyOrExit(aMetadata.mDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
864 
865     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
866     // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
867     VerifyOrExit(StringMatch(name, GetDomain(), kStringCaseInsensitiveMatch), error = kErrorSecurity);
868     SuccessOrExit(error = aMessage.Read(offset, aMetadata.mDnsZone));
869     offset += sizeof(Dns::Zone);
870 
871     VerifyOrExit(aMetadata.mDnsZone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
872     aMetadata.mOffset = offset;
873 
874 exit:
875     LogWarnOnError(error, "process DNS Zone section");
876     return error;
877 }
878 
ProcessUpdateSection(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const879 Error Server::ProcessUpdateSection(Host &aHost, const Message &aMessage, MessageMetadata &aMetadata) const
880 {
881     Error error = kErrorNone;
882 
883     // Process Service Discovery, Host and Service Description Instructions with
884     // 3 times iterations over all DNS update RRs. The order of those processes matters.
885 
886     // 0. Enumerate over all Service Discovery Instructions before processing any other records.
887     // So that we will know whether a name is a hostname or service instance name when processing
888     // a "Delete All RRsets from a name" record.
889     SuccessOrExit(error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aMetadata));
890 
891     // 1. Enumerate over all RRs to build the Host Description Instruction.
892     SuccessOrExit(error = ProcessHostDescriptionInstruction(aHost, aMessage, aMetadata));
893 
894     // 2. Enumerate over all RRs to build the Service Description Instructions.
895     SuccessOrExit(error = ProcessServiceDescriptionInstructions(aHost, aMessage, aMetadata));
896 
897     // 3. Verify that there are no name conflicts.
898     VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
899 
900 exit:
901     LogWarnOnError(error, "Process DNS Update section");
902     return error;
903 }
904 
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const905 Error Server::ProcessHostDescriptionInstruction(Host                  &aHost,
906                                                 const Message         &aMessage,
907                                                 const MessageMetadata &aMetadata) const
908 {
909     Error    error  = kErrorNone;
910     uint16_t offset = aMetadata.mOffset;
911 
912     OT_ASSERT(aHost.GetFullName() == nullptr);
913 
914     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
915     {
916         Dns::Name::Buffer   name;
917         Dns::ResourceRecord record;
918 
919         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
920 
921         SuccessOrExit(error = aMessage.Read(offset, record));
922 
923         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
924         {
925             // Delete All RRsets from a name.
926             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
927 
928             // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
929 
930             if (!aHost.HasService(name))
931             {
932                 // If host name is already set to a different name, `SetFullName()`
933                 // will return `kErrorFailed`.
934                 SuccessOrExit(error = aHost.SetFullName(name));
935                 aHost.ClearResources();
936             }
937         }
938         else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
939         {
940             Dns::AaaaRecord aaaaRecord;
941 
942             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
943 
944             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
945 
946             SuccessOrExit(error = aHost.SetFullName(name));
947 
948             SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
949             VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
950 
951             // Tolerate kErrorDrop for AAAA Resources.
952             VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
953         }
954         else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
955         {
956             // We currently support only ECDSA P-256.
957             Dns::Ecdsa256KeyRecord keyRecord;
958 
959             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
960 
961             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
962 
963             SuccessOrExit(error = aMessage.Read(offset, keyRecord));
964             VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
965 
966             if (aHost.mParsedKey)
967             {
968                 VerifyOrExit(aHost.mKey == keyRecord.GetKey(), error = kErrorSecurity);
969             }
970             else
971             {
972                 aHost.mParsedKey = true;
973                 aHost.mKey       = keyRecord.GetKey();
974             }
975         }
976 
977         offset += record.GetSize();
978     }
979 
980     // Verify that we have a complete Host Description Instruction.
981 
982     VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
983     VerifyOrExit(aHost.mParsedKey, error = kErrorFailed);
984 
985     // We check the number of host addresses after processing of the
986     // Lease Option in the Addition Section and determining whether
987     // the host is being removed or registered.
988 
989 exit:
990     LogWarnOnError(error, "process Host Description instructions");
991     return error;
992 }
993 
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const MessageMetadata & aMetadata) const994 Error Server::ProcessServiceDiscoveryInstructions(Host                  &aHost,
995                                                   const Message         &aMessage,
996                                                   const MessageMetadata &aMetadata) const
997 {
998     Error    error  = kErrorNone;
999     uint16_t offset = aMetadata.mOffset;
1000 
1001     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
1002     {
1003         Dns::Name::Buffer               serviceName;
1004         Dns::Name::LabelBuffer          instanceLabel;
1005         Dns::Name::Buffer               instanceServiceName;
1006         String<Dns::Name::kMaxNameSize> instanceName;
1007         Dns::PtrRecord                  ptrRecord;
1008         const char                     *subServiceName;
1009         Service                        *service;
1010         bool                            isSubType;
1011         bool                            isDelete;
1012 
1013         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, serviceName));
1014         VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
1015 
1016         error = Dns::ResourceRecord::ReadRecord(aMessage, offset, ptrRecord);
1017 
1018         if (error == kErrorNotFound)
1019         {
1020             // `ReadRecord()` updates `aOffset` to skip over a
1021             // non-matching record.
1022             error = kErrorNone;
1023             continue;
1024         }
1025 
1026         SuccessOrExit(error);
1027 
1028         SuccessOrExit(error = ptrRecord.ReadPtrName(aMessage, offset, instanceLabel, instanceServiceName));
1029         instanceName.Append("%s.%s", instanceLabel, instanceServiceName);
1030 
1031         // Class None indicates "Delete an RR from an RRset".
1032         isDelete = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
1033 
1034         VerifyOrExit(isDelete || ptrRecord.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorParse);
1035 
1036         // Check if the `serviceName` is a sub-type with name
1037         // format: "<sub-label>._sub.<service-labels>.<domain>."
1038 
1039         subServiceName = StringFind(serviceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1040         isSubType      = (subServiceName != nullptr);
1041 
1042         if (isSubType)
1043         {
1044             // Skip over the "._sub." label to get to the base
1045             // service name.
1046             subServiceName += sizeof(kServiceSubTypeLabel) - 1;
1047         }
1048 
1049         // Verify that instance name and service name are related.
1050         VerifyOrExit(Dns::Name::IsSubDomainOf(instanceName.AsCString(), isSubType ? subServiceName : serviceName),
1051                      error = kErrorFailed);
1052 
1053         // Find a matching existing service or allocate a new one.
1054 
1055         service = aHost.FindService(instanceName.AsCString());
1056 
1057         if (service == nullptr)
1058         {
1059             service = aHost.AddNewService(instanceName.AsCString(), instanceLabel, aMetadata.mRxTime);
1060             VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1061         }
1062 
1063         if (isSubType)
1064         {
1065             VerifyOrExit(!service->HasSubTypeServiceName(serviceName), error = kErrorFailed);
1066 
1067             // Ignore a sub-type service delete.
1068 
1069             if (!isDelete)
1070             {
1071                 Heap::String *newSubTypeLabel = service->mSubTypes.PushBack();
1072 
1073                 VerifyOrExit(newSubTypeLabel != nullptr, error = kErrorNoBufs);
1074                 SuccessOrExit(error = newSubTypeLabel->Set(serviceName));
1075             }
1076         }
1077         else
1078         {
1079             // Processed PTR record is the base service (not a
1080             // sub-type). `mServiceName` is only set when base
1081             // service is processed.
1082 
1083             VerifyOrExit(service->mServiceName.IsNull(), error = kErrorFailed);
1084             SuccessOrExit(error = service->mServiceName.Set(serviceName));
1085             service->mIsDeleted = isDelete;
1086         }
1087 
1088         if (!isDelete)
1089         {
1090             SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
1091         }
1092     }
1093 
1094     // Verify that for all services, a PTR record was processed for
1095     // the base service (`mServiceName` is set), and for a deleted
1096     // service, no PTR record was seen adding a sub-type.
1097 
1098     for (const Service &service : aHost.mServices)
1099     {
1100         VerifyOrExit(!service.mServiceName.IsNull(), error = kErrorParse);
1101 
1102         if (service.mIsDeleted)
1103         {
1104             VerifyOrExit(service.mSubTypes.GetLength() == 0, error = kErrorParse);
1105         }
1106     }
1107 
1108 exit:
1109     LogWarnOnError(error, "process Service Discovery instructions");
1110     return error;
1111 }
1112 
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,MessageMetadata & aMetadata) const1113 Error Server::ProcessServiceDescriptionInstructions(Host            &aHost,
1114                                                     const Message   &aMessage,
1115                                                     MessageMetadata &aMetadata) const
1116 {
1117     Error    error  = kErrorNone;
1118     uint16_t offset = aMetadata.mOffset;
1119 
1120     for (uint16_t numRecords = aMetadata.mDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
1121     {
1122         Dns::Name::Buffer   name;
1123         Dns::ResourceRecord record;
1124         Service            *service;
1125 
1126         SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1127         SuccessOrExit(error = aMessage.Read(offset, record));
1128 
1129         if (record.GetClass() == Dns::ResourceRecord::kClassAny)
1130         {
1131             // Delete All RRsets from a name.
1132             VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
1133 
1134             service = aHost.FindService(name);
1135 
1136             if (service != nullptr)
1137             {
1138                 VerifyOrExit(!service->mParsedDeleteAllRrset);
1139                 service->mParsedDeleteAllRrset = true;
1140             }
1141 
1142             offset += record.GetSize();
1143             continue;
1144         }
1145 
1146         if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
1147         {
1148             Dns::SrvRecord    srvRecord;
1149             Dns::Name::Buffer hostName;
1150 
1151             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1152 
1153             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1154 
1155             SuccessOrExit(error = aMessage.Read(offset, srvRecord));
1156             offset += sizeof(srvRecord);
1157 
1158             SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, hostName));
1159             VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
1160             VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
1161 
1162             service = aHost.FindService(name);
1163             VerifyOrExit(service != nullptr, error = kErrorFailed);
1164 
1165             VerifyOrExit(!service->mParsedSrv, error = kErrorParse);
1166             service->mParsedSrv = true;
1167 
1168             service->mTtl      = srvRecord.GetTtl();
1169             service->mPriority = srvRecord.GetPriority();
1170             service->mWeight   = srvRecord.GetWeight();
1171             service->mPort     = srvRecord.GetPort();
1172         }
1173         else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
1174         {
1175             VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
1176 
1177             SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
1178 
1179             service = aHost.FindService(name);
1180             VerifyOrExit(service != nullptr, error = kErrorFailed);
1181 
1182             service->mParsedTxt = true;
1183 
1184             offset += sizeof(record);
1185             SuccessOrExit(error = service->SetTxtDataFromMessage(aMessage, offset, record.GetLength()));
1186             offset += record.GetLength();
1187         }
1188         else
1189         {
1190             offset += record.GetSize();
1191         }
1192     }
1193 
1194     for (const Service &service : aHost.mServices)
1195     {
1196         VerifyOrExit(service.mParsedDeleteAllRrset, error = kErrorFailed);
1197         VerifyOrExit(service.mParsedSrv == service.mParsedTxt, error = kErrorFailed);
1198 
1199         if (!service.mIsDeleted)
1200         {
1201             VerifyOrExit(service.mParsedSrv, error = kErrorFailed);
1202         }
1203     }
1204 
1205     aMetadata.mOffset = offset;
1206 
1207 exit:
1208     LogWarnOnError(error, "process Service Description instructions");
1209     return error;
1210 }
1211 
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)1212 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
1213 {
1214     return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
1215            aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
1216 }
1217 
ProcessAdditionalSection(Host * aHost,const Message & aMessage,MessageMetadata & aMetadata) const1218 Error Server::ProcessAdditionalSection(Host *aHost, const Message &aMessage, MessageMetadata &aMetadata) const
1219 {
1220     Error             error = kErrorNone;
1221     Dns::OptRecord    optRecord;
1222     Dns::LeaseOption  leaseOption;
1223     Dns::SigRecord    sigRecord;
1224     char              name[2]; // The root domain name (".") is expected.
1225     uint16_t          offset = aMetadata.mOffset;
1226     uint16_t          sigOffset;
1227     uint16_t          sigRdataOffset;
1228     Dns::Name::Buffer signerName;
1229     uint16_t          signatureLength;
1230 
1231     VerifyOrExit(aMetadata.mDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
1232 
1233     // EDNS(0) Update Lease Option.
1234 
1235     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1236     SuccessOrExit(error = aMessage.Read(offset, optRecord));
1237 
1238     SuccessOrExit(error = leaseOption.ReadFrom(aMessage, offset + sizeof(optRecord), optRecord.GetLength()));
1239 
1240     offset += optRecord.GetSize();
1241 
1242     aHost->SetLease(leaseOption.GetLeaseInterval());
1243     aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
1244 
1245     for (Service &service : aHost->mServices)
1246     {
1247         if (aHost->GetLease() == 0)
1248         {
1249             service.mIsDeleted = true;
1250         }
1251 
1252         service.mLease    = service.mIsDeleted ? 0 : leaseOption.GetLeaseInterval();
1253         service.mKeyLease = leaseOption.GetKeyLeaseInterval();
1254     }
1255 
1256     // If the client included the short variant of Lease Option,
1257     // server must also use the short variant in its response.
1258     aHost->SetUseShortLeaseOption(leaseOption.IsShortVariant());
1259 
1260     if (aHost->GetLease() > 0)
1261     {
1262         // There MUST be at least one valid address if we have nonzero lease.
1263         VerifyOrExit(aHost->mAddresses.GetLength() > 0, error = kErrorFailed);
1264     }
1265 
1266     // SIG(0).
1267 
1268     sigOffset = offset;
1269     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, name));
1270     SuccessOrExit(error = aMessage.Read(offset, sigRecord));
1271     VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
1272 
1273     sigRdataOffset = offset + sizeof(Dns::ResourceRecord);
1274     offset += sizeof(sigRecord);
1275 
1276     // TODO: Verify that the signature doesn't expire. This is not
1277     // implemented because the end device may not be able to get
1278     // the synchronized date/time.
1279 
1280     SuccessOrExit(error = Dns::Name::ReadName(aMessage, offset, signerName));
1281 
1282     signatureLength = sigRecord.GetLength() - (offset - sigRdataOffset);
1283     offset += signatureLength;
1284 
1285     // Verify the signature. Currently supports only ECDSA.
1286 
1287     VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
1288     VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
1289     VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
1290 
1291     SuccessOrExit(error = VerifySignature(aHost->mKey, aMessage, aMetadata.mDnsHeader, sigOffset, sigRdataOffset,
1292                                           sigRecord.GetLength(), signerName));
1293 
1294     aMetadata.mOffset = offset;
1295 
1296 exit:
1297     LogWarnOnError(error, "process DNS Additional section");
1298     return error;
1299 }
1300 
VerifySignature(const Host::Key & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const1301 Error Server::VerifySignature(const Host::Key  &aKey,
1302                               const Message    &aMessage,
1303                               Dns::UpdateHeader aDnsHeader,
1304                               uint16_t          aSigOffset,
1305                               uint16_t          aSigRdataOffset,
1306                               uint16_t          aSigRdataLength,
1307                               const char       *aSignerName) const
1308 {
1309     Error                          error;
1310     uint16_t                       offset = aMessage.GetOffset();
1311     uint16_t                       signatureOffset;
1312     Crypto::Sha256                 sha256;
1313     Crypto::Sha256::Hash           hash;
1314     Crypto::Ecdsa::P256::Signature signature;
1315     Message                       *signerNameMessage = nullptr;
1316 
1317     VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
1318 
1319     sha256.Start();
1320 
1321     // SIG RDATA less signature.
1322     sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
1323 
1324     // The uncompressed (canonical) form of the signer name should be used for signature
1325     // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
1326     signerNameMessage = Get<Ip6::Udp>().NewMessage();
1327     VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
1328     SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
1329     sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
1330 
1331     // We need the DNS header before appending the SIG RR.
1332     aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
1333     sha256.Update(aDnsHeader);
1334     sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
1335 
1336     sha256.Finish(hash);
1337 
1338     signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
1339     SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
1340 
1341     error = aKey.Verify(hash, signature);
1342 
1343 exit:
1344     LogWarnOnError(error, "verify message signature");
1345     FreeMessage(signerNameMessage);
1346     return error;
1347 }
1348 
HandleUpdate(Host & aHost,const MessageMetadata & aMetadata)1349 void Server::HandleUpdate(Host &aHost, const MessageMetadata &aMetadata)
1350 {
1351     Error error = kErrorNone;
1352     Host *existingHost;
1353 
1354     // Check whether the SRP update wants to remove `aHost`.
1355 
1356     VerifyOrExit(aHost.GetLease() == 0);
1357 
1358     aHost.ClearResources();
1359 
1360     existingHost = mHosts.FindMatching(aHost.GetFullName());
1361     VerifyOrExit(existingHost != nullptr);
1362 
1363     // The client may not include all services it has registered before
1364     // when removing a host. We copy and append any missing services to
1365     // `aHost` from the `existingHost` and mark them as deleted.
1366 
1367     for (const Service &existingService : existingHost->mServices)
1368     {
1369         Service *service;
1370 
1371         if (existingService.mIsDeleted || aHost.HasService(existingService.GetInstanceName()))
1372         {
1373             continue;
1374         }
1375 
1376         service = aHost.AddNewService(existingService.GetInstanceName(), existingService.GetInstanceLabel(),
1377                                       aMetadata.mRxTime);
1378         VerifyOrExit(service != nullptr, error = kErrorNoBufs);
1379 
1380         SuccessOrExit(error = service->mServiceName.Set(existingService.GetServiceName()));
1381         service->mIsDeleted = true;
1382         service->mKeyLease  = existingService.mKeyLease;
1383     }
1384 
1385 exit:
1386     InformUpdateHandlerOrCommit(error, aHost, aMetadata);
1387 }
1388 
InformUpdateHandlerOrCommit(Error aError,Host & aHost,const MessageMetadata & aMetadata)1389 void Server::InformUpdateHandlerOrCommit(Error aError, Host &aHost, const MessageMetadata &aMetadata)
1390 {
1391 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1392     if (aError == kErrorNone)
1393     {
1394         uint8_t             numAddrs;
1395         const Ip6::Address *addrs;
1396 
1397         LogInfo("Processed SRP update info");
1398         LogInfo("    Host:%s", aHost.GetFullName());
1399         LogInfo("    Lease:%lu, key-lease:%lu, ttl:%lu", ToUlong(aHost.GetLease()), ToUlong(aHost.GetKeyLease()),
1400                 ToUlong(aHost.GetTtl()));
1401 
1402         addrs = aHost.GetAddresses(numAddrs);
1403 
1404         if (numAddrs == 0)
1405         {
1406             LogInfo("    No host address");
1407         }
1408         else
1409         {
1410             LogInfo("    %d host address(es):", numAddrs);
1411 
1412             for (; numAddrs > 0; addrs++, numAddrs--)
1413             {
1414                 LogInfo("      %s", addrs->ToString().AsCString());
1415             }
1416         }
1417 
1418         for (const Service &service : aHost.mServices)
1419         {
1420             LogInfo("    %s service '%s'", service.IsDeleted() ? "Deleting" : "Adding", service.GetInstanceName());
1421 
1422             for (const Heap::String &subType : service.mSubTypes)
1423             {
1424                 Dns::Name::LabelBuffer label;
1425 
1426                 IgnoreError(Service::ParseSubTypeServiceName(subType.AsCString(), label));
1427                 LogInfo("      sub-type: %s", label);
1428             }
1429         }
1430     }
1431     else
1432     {
1433         LogInfo("Error %s processing received SRP update", ErrorToString(aError));
1434     }
1435 #endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1436 
1437     if ((aError == kErrorNone) && mServiceUpdateHandler.IsSet())
1438     {
1439         UpdateMetadata *update = UpdateMetadata::Allocate(GetInstance(), aHost, aMetadata);
1440 
1441         if (update != nullptr)
1442         {
1443             mOutstandingUpdates.Push(*update);
1444             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1445 
1446             LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(update->GetId()));
1447             mServiceUpdateHandler.Invoke(update->GetId(), &aHost, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
1448             ExitNow();
1449         }
1450 
1451         aError = kErrorNoBufs;
1452     }
1453 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
1454     else if (aError == kErrorNone)
1455     {
1456         // Ask `AdvertisingProxy` to advertise the new update.
1457         // Proxy will report the outcome by calling
1458         // `Server::CommitSrpUpdate()` directly.
1459 
1460         Get<AdvertisingProxy>().Advertise(aHost, aMetadata);
1461         ExitNow();
1462     }
1463 #endif
1464 
1465     CommitSrpUpdate(aError, aHost, aMetadata);
1466 
1467 exit:
1468     return;
1469 }
1470 
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1471 void Server::SendResponse(const Dns::UpdateHeader    &aHeader,
1472                           Dns::UpdateHeader::Response aResponseCode,
1473                           const Ip6::MessageInfo     &aMessageInfo)
1474 {
1475     Error             error    = kErrorNone;
1476     Message          *response = nullptr;
1477     Dns::UpdateHeader header;
1478 
1479     VerifyOrExit(mState == kStateRunning, error = kErrorInvalidState);
1480 
1481     response = GetSocket().NewMessage();
1482     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1483 
1484     header.SetMessageId(aHeader.GetMessageId());
1485     header.SetType(Dns::UpdateHeader::kTypeResponse);
1486     header.SetQueryType(aHeader.GetQueryType());
1487     header.SetResponseCode(aResponseCode);
1488     SuccessOrExit(error = response->Append(header));
1489 
1490     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1491 
1492     if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1493     {
1494         LogWarn("Send fail response: %d", aResponseCode);
1495     }
1496     else
1497     {
1498         LogInfo("Send success response");
1499     }
1500 
1501     UpdateResponseCounters(aResponseCode);
1502 
1503 exit:
1504     LogWarnOnError(error, "send response");
1505     FreeMessageOnError(response, error);
1506 }
1507 
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,bool mUseShortLeaseOption,const Ip6::MessageInfo & aMessageInfo)1508 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1509                           uint32_t                 aLease,
1510                           uint32_t                 aKeyLease,
1511                           bool                     mUseShortLeaseOption,
1512                           const Ip6::MessageInfo  &aMessageInfo)
1513 {
1514     Error             error;
1515     Message          *response = nullptr;
1516     Dns::UpdateHeader header;
1517     Dns::OptRecord    optRecord;
1518     Dns::LeaseOption  leaseOption;
1519     uint16_t          optionSize;
1520 
1521     response = GetSocket().NewMessage();
1522     VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1523 
1524     header.SetMessageId(aHeader.GetMessageId());
1525     header.SetType(Dns::UpdateHeader::kTypeResponse);
1526     header.SetQueryType(aHeader.GetQueryType());
1527     header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1528     header.SetAdditionalRecordCount(1);
1529     SuccessOrExit(error = response->Append(header));
1530 
1531     // Append the root domain (".").
1532     SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1533 
1534     optRecord.Init();
1535     optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1536     optRecord.SetDnsSecurityFlag();
1537 
1538     if (mUseShortLeaseOption)
1539     {
1540         leaseOption.InitAsShortVariant(aLease);
1541     }
1542     else
1543     {
1544         leaseOption.InitAsLongVariant(aLease, aKeyLease);
1545     }
1546 
1547     optionSize = static_cast<uint16_t>(leaseOption.GetSize());
1548     optRecord.SetLength(optionSize);
1549 
1550     SuccessOrExit(error = response->Append(optRecord));
1551     SuccessOrExit(error = response->AppendBytes(&leaseOption, optionSize));
1552 
1553     SuccessOrExit(error = GetSocket().SendTo(*response, aMessageInfo));
1554 
1555     LogInfo("Send success response with granted lease: %lu and key lease: %lu", ToUlong(aLease), ToUlong(aKeyLease));
1556 
1557     UpdateResponseCounters(Dns::UpdateHeader::kResponseSuccess);
1558 
1559 exit:
1560     LogWarnOnError(error, "send response");
1561     FreeMessageOnError(response, error);
1562 }
1563 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1564 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1565 {
1566     static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
1567 }
1568 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1569 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1570 {
1571     Error error = ProcessMessage(aMessage, aMessageInfo);
1572 
1573     LogWarnOnError(error, "handle DNS message");
1574     OT_UNUSED_VARIABLE(error);
1575 }
1576 
ProcessMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1577 Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1578 {
1579     return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
1580 }
1581 
ProcessMessage(Message & aMessage,TimeMilli aRxTime,const TtlConfig & aTtlConfig,const LeaseConfig & aLeaseConfig,const Ip6::MessageInfo * aMessageInfo)1582 Error Server::ProcessMessage(Message                &aMessage,
1583                              TimeMilli               aRxTime,
1584                              const TtlConfig        &aTtlConfig,
1585                              const LeaseConfig      &aLeaseConfig,
1586                              const Ip6::MessageInfo *aMessageInfo)
1587 {
1588     Error           error;
1589     MessageMetadata metadata;
1590 
1591     metadata.mOffset      = aMessage.GetOffset();
1592     metadata.mRxTime      = aRxTime;
1593     metadata.mTtlConfig   = aTtlConfig;
1594     metadata.mLeaseConfig = aLeaseConfig;
1595     metadata.mMessageInfo = aMessageInfo;
1596 
1597     SuccessOrExit(error = aMessage.Read(metadata.mOffset, metadata.mDnsHeader));
1598     metadata.mOffset += sizeof(Dns::UpdateHeader);
1599 
1600     VerifyOrExit(metadata.mDnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1601     VerifyOrExit(metadata.mDnsHeader.GetQueryType() == Dns::UpdateHeader::kQueryTypeUpdate, error = kErrorDrop);
1602 
1603     ProcessDnsUpdate(aMessage, metadata);
1604 
1605 exit:
1606     return error;
1607 }
1608 
HandleLeaseTimer(void)1609 void Server::HandleLeaseTimer(void)
1610 {
1611     TimeMilli now                = TimerMilli::GetNow();
1612     TimeMilli earliestExpireTime = now.GetDistantFuture();
1613     Host     *nextHost;
1614 
1615     for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1616     {
1617         nextHost = host->GetNext();
1618 
1619         if (host->GetKeyExpireTime() <= now)
1620         {
1621             LogInfo("KEY LEASE of host %s expired", host->GetFullName());
1622 
1623             // Removes the whole host and all services if the KEY RR expired.
1624             RemoveHost(host, kDeleteName);
1625         }
1626         else if (host->IsDeleted())
1627         {
1628             // The host has been deleted, but the hostname & service instance names retain.
1629 
1630             Service *next;
1631 
1632             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1633 
1634             // Check if any service instance name expired.
1635             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1636             {
1637                 next = service->GetNext();
1638 
1639                 OT_ASSERT(service->mIsDeleted);
1640 
1641                 if (service->GetKeyExpireTime() <= now)
1642                 {
1643                     service->Log(Service::kKeyLeaseExpired);
1644                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1645                 }
1646                 else
1647                 {
1648                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1649                 }
1650             }
1651         }
1652         else if (host->GetExpireTime() <= now)
1653         {
1654             LogInfo("LEASE of host %s expired", host->GetFullName());
1655 
1656             // If the host expired, delete all resources of this host and its services.
1657             for (Service &service : host->mServices)
1658             {
1659                 // Don't need to notify the service handler as `RemoveHost` at below will do.
1660                 host->RemoveService(&service, kRetainName, kDoNotNotifyServiceHandler);
1661             }
1662 
1663             RemoveHost(host, kRetainName);
1664 
1665             earliestExpireTime = Min(earliestExpireTime, host->GetKeyExpireTime());
1666         }
1667         else
1668         {
1669             // The host doesn't expire, check if any service expired or is explicitly removed.
1670 
1671             Service *next;
1672 
1673             OT_ASSERT(!host->IsDeleted());
1674 
1675             earliestExpireTime = Min(earliestExpireTime, host->GetExpireTime());
1676 
1677             for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1678             {
1679                 next = service->GetNext();
1680 
1681                 if (service->GetKeyExpireTime() <= now)
1682                 {
1683                     service->Log(Service::kKeyLeaseExpired);
1684                     host->RemoveService(service, kDeleteName, kNotifyServiceHandler);
1685                 }
1686                 else if (service->mIsDeleted)
1687                 {
1688                     // The service has been deleted but the name retains.
1689                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1690                 }
1691                 else if (service->GetExpireTime() <= now)
1692                 {
1693                     service->Log(Service::kLeaseExpired);
1694 
1695                     // The service is expired, delete it.
1696                     host->RemoveService(service, kRetainName, kNotifyServiceHandler);
1697                     earliestExpireTime = Min(earliestExpireTime, service->GetKeyExpireTime());
1698                 }
1699                 else
1700                 {
1701                     earliestExpireTime = Min(earliestExpireTime, service->GetExpireTime());
1702                 }
1703             }
1704         }
1705     }
1706 
1707     if (earliestExpireTime != now.GetDistantFuture())
1708     {
1709         OT_ASSERT(earliestExpireTime >= now);
1710         if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1711         {
1712             LogInfo("Lease timer is scheduled for %lu seconds", ToUlong(Time::MsecToSec(earliestExpireTime - now)));
1713             mLeaseTimer.StartAt(earliestExpireTime, 0);
1714         }
1715     }
1716     else
1717     {
1718         LogInfo("Lease timer is stopped");
1719         mLeaseTimer.Stop();
1720     }
1721 }
1722 
HandleOutstandingUpdatesTimer(void)1723 void Server::HandleOutstandingUpdatesTimer(void)
1724 {
1725     TimeMilli       now = TimerMilli::GetNow();
1726     UpdateMetadata *update;
1727 
1728     while ((update = mOutstandingUpdates.GetTail()) != nullptr)
1729     {
1730         if (update->GetExpireTime() > now)
1731         {
1732             mOutstandingUpdatesTimer.FireAtIfEarlier(update->GetExpireTime());
1733             break;
1734         }
1735 
1736         LogInfo("Outstanding service update timeout (updateId = %lu)", ToUlong(update->GetId()));
1737 
1738         IgnoreError(mOutstandingUpdates.Remove(*update));
1739         update->SetError(kErrorResponseTimeout);
1740         CommitSrpUpdate(*update);
1741     }
1742 }
1743 
AddressModeToString(AddressMode aMode)1744 const char *Server::AddressModeToString(AddressMode aMode)
1745 {
1746     static const char *const kAddressModeStrings[] = {
1747         "unicast", // (0) kAddressModeUnicast
1748         "anycast", // (1) kAddressModeAnycast
1749     };
1750 
1751     static_assert(kAddressModeUnicast == 0, "kAddressModeUnicast value is incorrect");
1752     static_assert(kAddressModeAnycast == 1, "kAddressModeAnycast value is incorrect");
1753 
1754     return kAddressModeStrings[aMode];
1755 }
1756 
UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)1757 void Server::UpdateResponseCounters(Dns::UpdateHeader::Response aResponseCode)
1758 {
1759     switch (aResponseCode)
1760     {
1761     case Dns::UpdateHeader::kResponseSuccess:
1762         ++mResponseCounters.mSuccess;
1763         break;
1764     case Dns::UpdateHeader::kResponseServerFailure:
1765         ++mResponseCounters.mServerFailure;
1766         break;
1767     case Dns::UpdateHeader::kResponseFormatError:
1768         ++mResponseCounters.mFormatError;
1769         break;
1770     case Dns::UpdateHeader::kResponseNameExists:
1771         ++mResponseCounters.mNameExists;
1772         break;
1773     case Dns::UpdateHeader::kResponseRefused:
1774         ++mResponseCounters.mRefused;
1775         break;
1776     default:
1777         ++mResponseCounters.mOther;
1778         break;
1779     }
1780 }
1781 
1782 #if OPENTHREAD_FTD
UpdateAddrResolverCacheTable(const Ip6::MessageInfo & aMessageInfo,const Host & aHost)1783 void Server::UpdateAddrResolverCacheTable(const Ip6::MessageInfo &aMessageInfo, const Host &aHost)
1784 {
1785     // If message is from a client on mesh, we add all registered
1786     // addresses as snooped entries in the address resolver cache
1787     // table. We associate the registered addresses with the same
1788     // RLOC16 (if any) as the received message's peer IPv6 address.
1789 
1790     uint16_t rloc16;
1791 
1792     VerifyOrExit(aHost.GetLease() != 0);
1793     VerifyOrExit(aHost.GetTtl() > 0);
1794 
1795     // If the `LookUp()` call succeeds, the cache entry will be marked
1796     // as "cached and in-use". We can mark it as "in-use" early since
1797     // the entry will be needed and used soon when sending the SRP
1798     // response. This also prevents a snooped cache entry (added for
1799     // `GetPeerAddr()` due to rx of the SRP update message) from
1800     // being overwritten by `UpdateSnoopedCacheEntry()` calls when
1801     // there are limited snoop entries available.
1802 
1803     rloc16 = Get<AddressResolver>().LookUp(aMessageInfo.GetPeerAddr());
1804 
1805     VerifyOrExit(rloc16 != Mac::kShortAddrInvalid);
1806 
1807     for (const Ip6::Address &address : aHost.mAddresses)
1808     {
1809         Get<AddressResolver>().UpdateSnoopedCacheEntry(address, rloc16, Get<Mle::Mle>().GetRloc16());
1810     }
1811 
1812 exit:
1813     return;
1814 }
1815 #endif
1816 
1817 //---------------------------------------------------------------------------------------------------------------------
1818 // Server::Service
1819 
Init(const char * aInstanceName,const char * aInstanceLabel,Host & aHost,TimeMilli aUpdateTime)1820 Error Server::Service::Init(const char *aInstanceName, const char *aInstanceLabel, Host &aHost, TimeMilli aUpdateTime)
1821 {
1822     Error error;
1823 
1824     mNext        = nullptr;
1825     mHost        = &aHost;
1826     mPriority    = 0;
1827     mWeight      = 0;
1828     mTtl         = 0;
1829     mPort        = 0;
1830     mLease       = 0;
1831     mKeyLease    = 0;
1832     mUpdateTime  = aUpdateTime;
1833     mIsDeleted   = false;
1834     mIsCommitted = false;
1835 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
1836     mIsRegistered      = false;
1837     mIsKeyRegistered   = false;
1838     mIsReplaced        = false;
1839     mShouldAdvertise   = false;
1840     mShouldRegisterKey = false;
1841     mAdvId             = kInvalidRequestId;
1842     mKeyAdvId          = kInvalidRequestId;
1843 #endif
1844 
1845     mParsedDeleteAllRrset = false;
1846     mParsedSrv            = false;
1847     mParsedTxt            = false;
1848 
1849     SuccessOrExit(error = mInstanceLabel.Set(aInstanceLabel));
1850     error = mInstanceName.Set(aInstanceName);
1851 
1852 exit:
1853     return error;
1854 }
1855 
GetSubTypeServiceNameAt(uint16_t aIndex) const1856 const char *Server::Service::GetSubTypeServiceNameAt(uint16_t aIndex) const
1857 {
1858     const Heap::String *subType = mSubTypes.At(aIndex);
1859 
1860     return (subType == nullptr) ? nullptr : subType->AsCString();
1861 }
1862 
ParseSubTypeServiceName(const char * aSubTypeServiceName,char * aLabel,uint8_t aLabelSize)1863 Error Server::Service::ParseSubTypeServiceName(const char *aSubTypeServiceName, char *aLabel, uint8_t aLabelSize)
1864 {
1865     Error       error = kErrorNone;
1866     const char *subPos;
1867     uint8_t     labelLength;
1868 
1869     aLabel[0] = kNullChar;
1870 
1871     subPos = StringFind(aSubTypeServiceName, kServiceSubTypeLabel, kStringCaseInsensitiveMatch);
1872     VerifyOrExit(subPos != nullptr, error = kErrorInvalidArgs);
1873 
1874     if (subPos - aSubTypeServiceName < aLabelSize)
1875     {
1876         labelLength = static_cast<uint8_t>(subPos - aSubTypeServiceName);
1877     }
1878     else
1879     {
1880         labelLength = aLabelSize - 1;
1881         error       = kErrorNoBufs;
1882     }
1883 
1884     memcpy(aLabel, aSubTypeServiceName, labelLength);
1885     aLabel[labelLength] = kNullChar;
1886 
1887 exit:
1888     return error;
1889 }
1890 
GetExpireTime(void) const1891 TimeMilli Server::Service::GetExpireTime(void) const
1892 {
1893     OT_ASSERT(!mIsDeleted);
1894     OT_ASSERT(!GetHost().IsDeleted());
1895 
1896     return mUpdateTime + Time::SecToMsec(mLease);
1897 }
1898 
GetKeyExpireTime(void) const1899 TimeMilli Server::Service::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
1900 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const1901 void Server::Service::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
1902 {
1903     TimeMilli now           = TimerMilli::GetNow();
1904     TimeMilli keyExpireTime = GetKeyExpireTime();
1905 
1906     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
1907     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
1908     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
1909 
1910     if (!mIsDeleted)
1911     {
1912         TimeMilli expireTime = GetExpireTime();
1913 
1914         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
1915     }
1916     else
1917     {
1918         aLeaseInfo.mRemainingLease = 0;
1919     }
1920 }
1921 
MatchesInstanceName(const char * aInstanceName) const1922 bool Server::Service::MatchesInstanceName(const char *aInstanceName) const { return Matches(aInstanceName); }
1923 
MatchesServiceName(const char * aServiceName) const1924 bool Server::Service::MatchesServiceName(const char *aServiceName) const
1925 {
1926     return StringMatch(mServiceName.AsCString(), aServiceName, kStringCaseInsensitiveMatch);
1927 }
1928 
Matches(const char * aInstanceName) const1929 bool Server::Service::Matches(const char *aInstanceName) const
1930 {
1931     return StringMatch(mInstanceName.AsCString(), aInstanceName, kStringCaseInsensitiveMatch);
1932 }
1933 
HasSubTypeServiceName(const char * aSubTypeServiceName) const1934 bool Server::Service::HasSubTypeServiceName(const char *aSubTypeServiceName) const
1935 {
1936     bool has = false;
1937 
1938     for (const Heap::String &subType : mSubTypes)
1939     {
1940         if (StringMatch(subType.AsCString(), aSubTypeServiceName, kStringCaseInsensitiveMatch))
1941         {
1942             has = true;
1943             break;
1944         }
1945     }
1946 
1947     return has;
1948 }
1949 
1950 #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
Log(Action aAction) const1951 void Server::Service::Log(Action aAction) const
1952 {
1953     static const char *const kActionStrings[] = {
1954         "Add new",                   // (0) kAddNew
1955         "Update existing",           // (1) kUpdateExisting
1956         "Keep unchanged",            // (2) kKeepUnchanged
1957         "Remove but retain name of", // (3) kRemoveButRetainName
1958         "Fully remove",              // (4) kFullyRemove
1959         "LEASE expired for",         // (5) kLeaseExpired
1960         "KEY LEASE expired for",     // (6) kKeyLeaseExpired
1961     };
1962 
1963     static_assert(0 == kAddNew, "kAddNew value is incorrect");
1964     static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1965     static_assert(2 == kKeepUnchanged, "kKeepUnchanged value is incorrect");
1966     static_assert(3 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1967     static_assert(4 == kFullyRemove, "kFullyRemove value is incorrect");
1968     static_assert(5 == kLeaseExpired, "kLeaseExpired value is incorrect");
1969     static_assert(6 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1970 
1971     // We only log if the `Service` is marked as committed. This
1972     // ensures that temporary `Service` entries associated with a
1973     // newly received SRP update message are not logged (e.g., when
1974     // associated `Host` is being freed).
1975 
1976     if (mIsCommitted)
1977     {
1978         LogInfo("%s service '%s'", kActionStrings[aAction], GetInstanceName());
1979 
1980         for (const Heap::String &subType : mSubTypes)
1981         {
1982             Dns::Name::LabelBuffer label;
1983 
1984             IgnoreError(ParseSubTypeServiceName(subType.AsCString(), label));
1985             LogInfo("  sub-type: %s", subType.AsCString());
1986         }
1987     }
1988 }
1989 #else
Log(Action) const1990 void Server::Service::Log(Action) const {}
1991 #endif // #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
1992 
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1993 Error Server::Service::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1994 {
1995     Error error;
1996 
1997     SuccessOrExit(error = mTxtData.SetFrom(aMessage, aOffset, aLength));
1998     VerifyOrExit(Dns::TxtRecord::VerifyTxtData(mTxtData.GetBytes(), mTxtData.GetLength(), /* aAllowEmpty */ false),
1999                  error = kErrorParse);
2000 
2001 exit:
2002     if (error != kErrorNone)
2003     {
2004         mTxtData.Free();
2005     }
2006 
2007     return error;
2008 }
2009 
2010 //---------------------------------------------------------------------------------------------------------------------
2011 // Server::Host
2012 
Host(Instance & aInstance,TimeMilli aUpdateTime)2013 Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
2014     : InstanceLocator(aInstance)
2015     , mNext(nullptr)
2016     , mTtl(0)
2017     , mLease(0)
2018     , mKeyLease(0)
2019     , mUpdateTime(aUpdateTime)
2020     , mParsedKey(false)
2021     , mUseShortLeaseOption(false)
2022 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
2023     , mIsRegistered(false)
2024     , mIsKeyRegistered(false)
2025     , mIsReplaced(false)
2026     , mShouldAdvertise(false)
2027     , mShouldRegisterKey(false)
2028     , mAdvId(kInvalidRequestId)
2029     , mKeyAdvId(kInvalidRequestId)
2030 #endif
2031 {
2032 }
2033 
~Host(void)2034 Server::Host::~Host(void) { FreeAllServices(); }
2035 
SetFullName(const char * aFullName)2036 Error Server::Host::SetFullName(const char *aFullName)
2037 {
2038     // `mFullName` becomes immutable after it is set, so if it is
2039     // already set, we only accept a `aFullName` that matches the
2040     // current name.
2041 
2042     Error error;
2043 
2044     if (mFullName.IsNull())
2045     {
2046         error = mFullName.Set(aFullName);
2047     }
2048     else
2049     {
2050         error = Matches(aFullName) ? kErrorNone : kErrorFailed;
2051     }
2052 
2053     return error;
2054 }
2055 
Matches(const char * aFullName) const2056 bool Server::Host::Matches(const char *aFullName) const
2057 {
2058     return StringMatch(mFullName.AsCString(), aFullName, kStringCaseInsensitiveMatch);
2059 }
2060 
GetExpireTime(void) const2061 TimeMilli Server::Host::GetExpireTime(void) const
2062 {
2063     OT_ASSERT(!IsDeleted());
2064 
2065     return mUpdateTime + Time::SecToMsec(mLease);
2066 }
2067 
GetKeyExpireTime(void) const2068 TimeMilli Server::Host::GetKeyExpireTime(void) const { return mUpdateTime + Time::SecToMsec(mKeyLease); }
2069 
GetLeaseInfo(LeaseInfo & aLeaseInfo) const2070 void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
2071 {
2072     TimeMilli now           = TimerMilli::GetNow();
2073     TimeMilli keyExpireTime = GetKeyExpireTime();
2074 
2075     aLeaseInfo.mLease             = Time::SecToMsec(GetLease());
2076     aLeaseInfo.mKeyLease          = Time::SecToMsec(GetKeyLease());
2077     aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
2078 
2079     if (!IsDeleted())
2080     {
2081         TimeMilli expireTime = GetExpireTime();
2082 
2083         aLeaseInfo.mRemainingLease = (now <= expireTime) ? (expireTime - now) : 0;
2084     }
2085     else
2086     {
2087         aLeaseInfo.mRemainingLease = 0;
2088     }
2089 }
2090 
ProcessTtl(uint32_t aTtl)2091 Error Server::Host::ProcessTtl(uint32_t aTtl)
2092 {
2093     // This method processes the TTL value received in a resource record.
2094     //
2095     // If no TTL value is stored, this method will set the stored value to @p aTtl and return `kErrorNone`.
2096     // If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
2097     // Otherwise, this method returns `kErrorRejected`.
2098 
2099     Error error = kErrorRejected;
2100 
2101     VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
2102 
2103     mTtl = aTtl;
2104 
2105     error = kErrorNone;
2106 
2107 exit:
2108     return error;
2109 }
2110 
GetNextService(const Service * aPrevService) const2111 const Server::Service *Server::Host::GetNextService(const Service *aPrevService) const
2112 {
2113     return (aPrevService == nullptr) ? mServices.GetHead() : aPrevService->GetNext();
2114 }
2115 
AddNewService(const char * aInstanceName,const char * aInstanceLabel,TimeMilli aUpdateTime)2116 Server::Service *Server::Host::AddNewService(const char *aInstanceName,
2117                                              const char *aInstanceLabel,
2118                                              TimeMilli   aUpdateTime)
2119 {
2120     Service *service = Service::AllocateAndInit(aInstanceName, aInstanceLabel, *this, aUpdateTime);
2121 
2122     VerifyOrExit(service != nullptr);
2123     AddService(*service);
2124 
2125 exit:
2126     return service;
2127 }
2128 
AddService(Service & aService)2129 void Server::Host::AddService(Service &aService)
2130 {
2131     aService.mHost = this;
2132     mServices.Push(aService);
2133 }
2134 
RemoveService(Service * aService,RetainName aRetainName,NotifyMode aNotifyServiceHandler)2135 void Server::Host::RemoveService(Service *aService, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
2136 {
2137     Server &server = Get<Server>();
2138 
2139     VerifyOrExit(aService != nullptr);
2140 
2141     aService->mIsDeleted = true;
2142     aService->mLease     = 0;
2143 
2144     if (!aRetainName)
2145     {
2146         aService->mKeyLease = 0;
2147     }
2148 
2149     aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
2150 
2151     if (aNotifyServiceHandler && server.mServiceUpdateHandler.IsSet())
2152     {
2153         uint32_t updateId = server.AllocateServiceUpdateId();
2154 
2155         LogInfo("SRP update handler is notified (updatedId = %lu)", ToUlong(updateId));
2156         server.mServiceUpdateHandler.Invoke(updateId, this, static_cast<uint32_t>(kDefaultEventsHandlerTimeout));
2157         // We don't wait for the reply from the service update handler,
2158         // but always remove the service regardless of service update result.
2159         // Because removing a service should fail only when there is system
2160         // failure of the platform mDNS implementation and in which case the
2161         // service is not expected to be still registered.
2162     }
2163 #if OPENTHREAD_CONFIG_SRP_SERVER_ADVERTISING_PROXY_ENABLE
2164     else if (aNotifyServiceHandler)
2165     {
2166         Get<AdvertisingProxy>().AdvertiseRemovalOf(*aService);
2167     }
2168 #endif
2169 
2170     if (!aRetainName)
2171     {
2172         IgnoreError(mServices.Remove(*aService));
2173         aService->Free();
2174     }
2175 
2176 exit:
2177     return;
2178 }
2179 
FreeAllServices(void)2180 void Server::Host::FreeAllServices(void)
2181 {
2182     while (!mServices.IsEmpty())
2183     {
2184         RemoveService(mServices.GetHead(), kDeleteName, kDoNotNotifyServiceHandler);
2185     }
2186 }
2187 
ClearResources(void)2188 void Server::Host::ClearResources(void) { mAddresses.Free(); }
2189 
FindService(const char * aInstanceName)2190 Server::Service *Server::Host::FindService(const char *aInstanceName) { return mServices.FindMatching(aInstanceName); }
2191 
FindService(const char * aInstanceName) const2192 const Server::Service *Server::Host::FindService(const char *aInstanceName) const
2193 {
2194     return mServices.FindMatching(aInstanceName);
2195 }
2196 
HasService(const char * aInstanceName) const2197 bool Server::Host::HasService(const char *aInstanceName) const { return mServices.ContainsMatching(aInstanceName); }
2198 
AddIp6Address(const Ip6::Address & aIp6Address)2199 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
2200 {
2201     Error error = kErrorNone;
2202 
2203     if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
2204     {
2205         // We don't like those address because they cannot be used
2206         // for communication with exterior devices.
2207         ExitNow(error = kErrorDrop);
2208     }
2209 
2210     // Drop duplicate addresses.
2211     VerifyOrExit(!mAddresses.Contains(aIp6Address), error = kErrorDrop);
2212 
2213     error = mAddresses.PushBack(aIp6Address);
2214 
2215     if (error == kErrorNoBufs)
2216     {
2217         LogWarn("Too many addresses for host %s", GetFullName());
2218     }
2219 
2220 exit:
2221     return error;
2222 }
2223 
2224 //---------------------------------------------------------------------------------------------------------------------
2225 // Server::UpdateMetadata
2226 
UpdateMetadata(Instance & aInstance,Host & aHost,const MessageMetadata & aMessageMetadata)2227 Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const MessageMetadata &aMessageMetadata)
2228     : InstanceLocator(aInstance)
2229     , mNext(nullptr)
2230     , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
2231     , mDnsHeader(aMessageMetadata.mDnsHeader)
2232     , mId(Get<Server>().AllocateServiceUpdateId())
2233     , mTtlConfig(aMessageMetadata.mTtlConfig)
2234     , mLeaseConfig(aMessageMetadata.mLeaseConfig)
2235     , mHost(aHost)
2236     , mError(kErrorNone)
2237     , mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
2238 {
2239     if (aMessageMetadata.mMessageInfo != nullptr)
2240     {
2241         mMessageInfo = *aMessageMetadata.mMessageInfo;
2242     }
2243 }
2244 
2245 } // namespace Srp
2246 } // namespace ot
2247 
2248 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
2249