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