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