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