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/instance.hpp"
39 #include "common/locator_getters.hpp"
40 #include "common/logging.hpp"
41 #include "common/new.hpp"
42 #include "common/random.hpp"
43 #include "net/dns_types.hpp"
44 #include "thread/thread_netif.hpp"
45
46 namespace ot {
47 namespace Srp {
48
49 static const char kDefaultDomain[] = "default.service.arpa.";
50 static const char kServiceSubTypeLabel[] = "._sub.";
51
ErrorToDnsResponseCode(Error aError)52 static Dns::UpdateHeader::Response ErrorToDnsResponseCode(Error aError)
53 {
54 Dns::UpdateHeader::Response responseCode;
55
56 switch (aError)
57 {
58 case kErrorNone:
59 responseCode = Dns::UpdateHeader::kResponseSuccess;
60 break;
61 case kErrorNoBufs:
62 responseCode = Dns::UpdateHeader::kResponseServerFailure;
63 break;
64 case kErrorParse:
65 responseCode = Dns::UpdateHeader::kResponseFormatError;
66 break;
67 case kErrorDuplicated:
68 responseCode = Dns::UpdateHeader::kResponseNameExists;
69 break;
70 default:
71 responseCode = Dns::UpdateHeader::kResponseRefused;
72 break;
73 }
74
75 return responseCode;
76 }
77
78 //---------------------------------------------------------------------------------------------------------------------
79 // Server
80
Server(Instance & aInstance)81 Server::Server(Instance &aInstance)
82 : InstanceLocator(aInstance)
83 , mSocket(aInstance)
84 , mServiceUpdateHandler(nullptr)
85 , mServiceUpdateHandlerContext(nullptr)
86 , mLeaseTimer(aInstance, HandleLeaseTimer)
87 , mOutstandingUpdatesTimer(aInstance, HandleOutstandingUpdatesTimer)
88 , mServiceUpdateId(Random::NonCrypto::GetUint32())
89 , mPort(kUdpPortMin)
90 , mState(kStateDisabled)
91 , mHasRegisteredAnyService(false)
92 {
93 IgnoreError(SetDomain(kDefaultDomain));
94 }
95
SetServiceHandler(otSrpServerServiceUpdateHandler aServiceHandler,void * aServiceHandlerContext)96 void Server::SetServiceHandler(otSrpServerServiceUpdateHandler aServiceHandler, void *aServiceHandlerContext)
97 {
98 mServiceUpdateHandler = aServiceHandler;
99 mServiceUpdateHandlerContext = aServiceHandlerContext;
100 }
101
SetEnabled(bool aEnabled)102 void Server::SetEnabled(bool aEnabled)
103 {
104 if (aEnabled)
105 {
106 VerifyOrExit(mState == kStateDisabled);
107 mState = kStateStopped;
108
109 // Select a port and then publish "DNS/SRP Unicast Address
110 // Service" in Thread Network Data using the device's
111 // mesh-local EID as the address. Then wait for callback
112 // `HandleNetDataPublisherEntryChange()` from to `Publisher` to
113 // start server operation when entry is published (i.e., added
114 // to the Network Data).
115
116 SelectPort();
117 Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(mPort);
118 }
119 else
120 {
121 VerifyOrExit(mState != kStateDisabled);
122 Get<NetworkData::Publisher>().UnpublishDnsSrpService();
123 Stop();
124 mState = kStateDisabled;
125 }
126
127 exit:
128 return;
129 }
130
LeaseConfig(void)131 Server::LeaseConfig::LeaseConfig(void)
132 {
133 mMinLease = kDefaultMinLease;
134 mMaxLease = kDefaultMaxLease;
135 mMinKeyLease = kDefaultMinKeyLease;
136 mMaxKeyLease = kDefaultMaxKeyLease;
137 }
138
IsValid(void) const139 bool Server::LeaseConfig::IsValid(void) const
140 {
141 bool valid = false;
142
143 // TODO: Support longer LEASE.
144 // We use milliseconds timer for LEASE & KEY-LEASE, this is to avoid overflow.
145 VerifyOrExit(mMaxKeyLease <= Time::MsecToSec(TimerMilli::kMaxDelay));
146 VerifyOrExit(mMinLease <= mMaxLease);
147 VerifyOrExit(mMinKeyLease <= mMaxKeyLease);
148 VerifyOrExit(mMinLease <= mMinKeyLease);
149 VerifyOrExit(mMaxLease <= mMaxKeyLease);
150
151 valid = true;
152
153 exit:
154 return valid;
155 }
156
GrantLease(uint32_t aLease) const157 uint32_t Server::LeaseConfig::GrantLease(uint32_t aLease) const
158 {
159 OT_ASSERT(mMinLease <= mMaxLease);
160
161 return (aLease == 0) ? 0 : OT_MAX(mMinLease, OT_MIN(mMaxLease, aLease));
162 }
163
GrantKeyLease(uint32_t aKeyLease) const164 uint32_t Server::LeaseConfig::GrantKeyLease(uint32_t aKeyLease) const
165 {
166 OT_ASSERT(mMinKeyLease <= mMaxKeyLease);
167
168 return (aKeyLease == 0) ? 0 : OT_MAX(mMinKeyLease, OT_MIN(mMaxKeyLease, aKeyLease));
169 }
170
SetLeaseConfig(const LeaseConfig & aLeaseConfig)171 Error Server::SetLeaseConfig(const LeaseConfig &aLeaseConfig)
172 {
173 Error error = kErrorNone;
174
175 VerifyOrExit(aLeaseConfig.IsValid(), error = kErrorInvalidArgs);
176 mLeaseConfig = aLeaseConfig;
177
178 exit:
179 return error;
180 }
181
SetDomain(const char * aDomain)182 Error Server::SetDomain(const char *aDomain)
183 {
184 Error error = kErrorNone;
185 uint16_t length;
186
187 VerifyOrExit(mState == kStateDisabled, error = kErrorInvalidState);
188
189 length = StringLength(aDomain, Dns::Name::kMaxNameSize);
190 VerifyOrExit((length > 0) && (length < Dns::Name::kMaxNameSize), error = kErrorInvalidArgs);
191
192 if (aDomain[length - 1] == '.')
193 {
194 error = mDomain.Set(aDomain);
195 }
196 else
197 {
198 // Need to append dot at the end
199
200 char buf[Dns::Name::kMaxNameSize];
201
202 VerifyOrExit(length < Dns::Name::kMaxNameSize - 1, error = kErrorInvalidArgs);
203
204 memcpy(buf, aDomain, length);
205 buf[length] = '.';
206 buf[length + 1] = '\0';
207
208 error = mDomain.Set(buf);
209 }
210
211 exit:
212 return error;
213 }
214
GetNextHost(const Server::Host * aHost)215 const Server::Host *Server::GetNextHost(const Server::Host *aHost)
216 {
217 return (aHost == nullptr) ? mHosts.GetHead() : aHost->GetNext();
218 }
219
220 // This method adds a SRP service host and takes ownership of it.
221 // The caller MUST make sure that there is no existing host with the same hostname.
AddHost(Host & aHost)222 void Server::AddHost(Host &aHost)
223 {
224 OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr);
225 IgnoreError(mHosts.Add(aHost));
226 }
227
RemoveHost(Host * aHost,bool aRetainName,bool aNotifyServiceHandler)228 void Server::RemoveHost(Host *aHost, bool aRetainName, bool aNotifyServiceHandler)
229 {
230 VerifyOrExit(aHost != nullptr);
231
232 aHost->mLease = 0;
233 aHost->ClearResources();
234
235 if (aRetainName)
236 {
237 otLogInfoSrp("[server] remove host '%s' (but retain its name)", aHost->GetFullName());
238 }
239 else
240 {
241 aHost->mKeyLease = 0;
242 IgnoreError(mHosts.Remove(*aHost));
243 otLogInfoSrp("[server] fully remove host '%s'", aHost->GetFullName());
244 }
245
246 if (aNotifyServiceHandler && mServiceUpdateHandler != nullptr)
247 {
248 mServiceUpdateHandler(AllocateId(), aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
249 // We don't wait for the reply from the service update handler,
250 // but always remove the host (and its services) regardless of
251 // host/service update result. Because removing a host should fail
252 // only when there is system failure of the platform mDNS implementation
253 // and in which case the host is not expected to be still registered.
254 }
255
256 if (!aRetainName)
257 {
258 aHost->Free();
259 }
260
261 exit:
262 return;
263 }
264
HasNameConflictsWith(Host & aHost) const265 bool Server::HasNameConflictsWith(Host &aHost) const
266 {
267 bool hasConflicts = false;
268 const Host *existingHost = mHosts.FindMatching(aHost.GetFullName());
269
270 if (existingHost != nullptr && *aHost.GetKey() != *existingHost->GetKey())
271 {
272 ExitNow(hasConflicts = true);
273 }
274
275 for (const Service::Description &desc : aHost.mServiceDescriptions)
276 {
277 // Check on all hosts for a matching service description with
278 // the same instance name and if found, verify that it has the
279 // same key.
280
281 for (const Host &host : mHosts)
282 {
283 if (host.FindServiceDescription(desc.GetInstanceName()) != nullptr)
284 {
285 VerifyOrExit(*aHost.GetKey() == *host.GetKey(), hasConflicts = true);
286 }
287 }
288 }
289
290 exit:
291 return hasConflicts;
292 }
293
HandleServiceUpdateResult(ServiceUpdateId aId,Error aError)294 void Server::HandleServiceUpdateResult(ServiceUpdateId aId, Error aError)
295 {
296 UpdateMetadata *update = mOutstandingUpdates.FindMatching(aId);
297
298 if (update != nullptr)
299 {
300 HandleServiceUpdateResult(update, aError);
301 }
302 else
303 {
304 otLogInfoSrp("[server] delayed SRP host update result, the SRP update has been committed");
305 }
306 }
307
HandleServiceUpdateResult(UpdateMetadata * aUpdate,Error aError)308 void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
309 {
310 IgnoreError(mOutstandingUpdates.Remove(*aUpdate));
311 CommitSrpUpdate(aError, aUpdate->GetDnsHeader(), aUpdate->GetHost(), aUpdate->GetMessageInfo());
312 aUpdate->Free();
313
314 if (mOutstandingUpdates.IsEmpty())
315 {
316 mOutstandingUpdatesTimer.Stop();
317 }
318 else
319 {
320 mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0);
321 }
322 }
323
CommitSrpUpdate(Error aError,const Dns::UpdateHeader & aDnsHeader,Host & aHost,const Ip6::MessageInfo & aMessageInfo)324 void Server::CommitSrpUpdate(Error aError,
325 const Dns::UpdateHeader &aDnsHeader,
326 Host & aHost,
327 const Ip6::MessageInfo & aMessageInfo)
328 {
329 Host * existingHost;
330 uint32_t hostLease;
331 uint32_t hostKeyLease;
332 uint32_t grantedLease;
333 uint32_t grantedKeyLease;
334 bool shouldFreeHost = true;
335
336 SuccessOrExit(aError);
337
338 hostLease = aHost.GetLease();
339 hostKeyLease = aHost.GetKeyLease();
340 grantedLease = mLeaseConfig.GrantLease(hostLease);
341 grantedKeyLease = mLeaseConfig.GrantKeyLease(hostKeyLease);
342
343 aHost.SetLease(grantedLease);
344 aHost.SetKeyLease(grantedKeyLease);
345
346 for (Service::Description &desc : aHost.mServiceDescriptions)
347 {
348 desc.mLease = grantedLease;
349 desc.mKeyLease = grantedKeyLease;
350 }
351
352 existingHost = mHosts.FindMatching(aHost.GetFullName());
353
354 if (aHost.GetLease() == 0)
355 {
356 if (aHost.GetKeyLease() == 0)
357 {
358 otLogInfoSrp("[server] remove key of host %s", aHost.GetFullName());
359 RemoveHost(existingHost, /* aRetainName */ false, /* aNotifyServiceHandler */ false);
360 }
361 else if (existingHost != nullptr)
362 {
363 existingHost->SetKeyLease(aHost.GetKeyLease());
364 RemoveHost(existingHost, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
365
366 for (Service &service : existingHost->mServices)
367 {
368 existingHost->RemoveService(&service, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
369 }
370 }
371 }
372 else if (existingHost != nullptr)
373 {
374 SuccessOrExit(aError = existingHost->MergeServicesAndResourcesFrom(aHost));
375 }
376 else
377 {
378 otLogInfoSrp("[server] add new host %s", aHost.GetFullName());
379
380 for (Service &service : aHost.GetServices())
381 {
382 service.mIsCommitted = true;
383 service.Log(Service::kAddNew);
384 }
385
386 AddHost(aHost);
387 shouldFreeHost = false;
388
389 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
390 if (!mHasRegisteredAnyService)
391 {
392 Settings::SrpServerInfo info;
393
394 mHasRegisteredAnyService = true;
395 info.SetPort(mSocket.mSockName.mPort);
396 IgnoreError(Get<Settings>().Save(info));
397 }
398 #endif
399 }
400
401 // Re-schedule the lease timer.
402 HandleLeaseTimer();
403
404 exit:
405 if (aError == kErrorNone && !(grantedLease == hostLease && grantedKeyLease == hostKeyLease))
406 {
407 SendResponse(aDnsHeader, grantedLease, grantedKeyLease, aMessageInfo);
408 }
409 else
410 {
411 SendResponse(aDnsHeader, ErrorToDnsResponseCode(aError), aMessageInfo);
412 }
413
414 if (shouldFreeHost)
415 {
416 aHost.Free();
417 }
418 }
419
SelectPort(void)420 void Server::SelectPort(void)
421 {
422 mPort = kUdpPortMin;
423
424 #if OPENTHREAD_CONFIG_SRP_SERVER_PORT_SWITCH_ENABLE
425 {
426 Settings::SrpServerInfo info;
427
428 if (Get<Settings>().Read(info) == kErrorNone)
429 {
430 mPort = info.GetPort() + 1;
431 if (mPort < kUdpPortMin || mPort > kUdpPortMax)
432 {
433 mPort = kUdpPortMin;
434 }
435 }
436 }
437 #endif
438
439 otLogInfoSrp("[server] selected port %u", mPort);
440 }
441
Start(void)442 void Server::Start(void)
443 {
444 Error error = kErrorNone;
445
446 VerifyOrExit(mState == kStateStopped);
447
448 mState = kStateRunning;
449
450 SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
451 SuccessOrExit(error = mSocket.Bind(mPort, OT_NETIF_THREAD));
452
453 otLogInfoSrp("[server] start listening on port %u", mPort);
454
455 exit:
456 if (error != kErrorNone)
457 {
458 otLogCritSrp("[server] failed to start: %s", ErrorToString(error));
459 Stop();
460 }
461 }
462
Stop(void)463 void Server::Stop(void)
464 {
465 VerifyOrExit(mState == kStateRunning);
466
467 mState = kStateStopped;
468
469 while (!mHosts.IsEmpty())
470 {
471 RemoveHost(mHosts.GetHead(), /* aRetainName */ false, /* aNotifyServiceHandler */ true);
472 }
473
474 // TODO: We should cancel any outstanding service updates, but current
475 // OTBR mDNS publisher cannot properly handle it.
476 while (!mOutstandingUpdates.IsEmpty())
477 {
478 mOutstandingUpdates.Pop()->Free();
479 }
480
481 mLeaseTimer.Stop();
482 mOutstandingUpdatesTimer.Stop();
483
484 otLogInfoSrp("[server] stop listening on %u", mPort);
485 IgnoreError(mSocket.Close());
486 mHasRegisteredAnyService = false;
487
488 exit:
489 return;
490 }
491
HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)492 void Server::HandleNetDataPublisherEvent(NetworkData::Publisher::Event aEvent)
493 {
494 switch (aEvent)
495 {
496 case NetworkData::Publisher::kEventEntryAdded:
497 Start();
498 break;
499
500 case NetworkData::Publisher::kEventEntryRemoved:
501 Stop();
502 break;
503 }
504 }
505
FindOutstandingUpdate(const Ip6::MessageInfo & aMessageInfo,uint16_t aDnsMessageId)506 const Server::UpdateMetadata *Server::FindOutstandingUpdate(const Ip6::MessageInfo &aMessageInfo,
507 uint16_t aDnsMessageId)
508 {
509 const UpdateMetadata *ret = nullptr;
510
511 for (const UpdateMetadata &update : mOutstandingUpdates)
512 {
513 if (aDnsMessageId == update.GetDnsHeader().GetMessageId() &&
514 aMessageInfo.GetPeerAddr() == update.GetMessageInfo().GetPeerAddr() &&
515 aMessageInfo.GetPeerPort() == update.GetMessageInfo().GetPeerPort())
516 {
517 ExitNow(ret = &update);
518 }
519 }
520
521 exit:
522 return ret;
523 }
524
HandleDnsUpdate(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Dns::UpdateHeader & aDnsHeader,uint16_t aOffset)525 void Server::HandleDnsUpdate(Message & aMessage,
526 const Ip6::MessageInfo & aMessageInfo,
527 const Dns::UpdateHeader &aDnsHeader,
528 uint16_t aOffset)
529 {
530 Error error = kErrorNone;
531 Dns::Zone zone;
532 Host * host = nullptr;
533
534 otLogInfoSrp("[server] receive DNS update from %s", aMessageInfo.GetPeerAddr().ToString().AsCString());
535
536 SuccessOrExit(error = ProcessZoneSection(aMessage, aDnsHeader, aOffset, zone));
537
538 if (FindOutstandingUpdate(aMessageInfo, aDnsHeader.GetMessageId()) != nullptr)
539 {
540 otLogInfoSrp("[server] drop duplicated SRP update request: messageId=%hu", aDnsHeader.GetMessageId());
541
542 // Silently drop duplicate requests.
543 // This could rarely happen, because the outstanding SRP update timer should
544 // be shorter than the SRP update retransmission timer.
545 ExitNow(error = kErrorNone);
546 }
547
548 // Per 2.3.2 of SRP draft 6, no prerequisites should be included in a SRP update.
549 VerifyOrExit(aDnsHeader.GetPrerequisiteRecordCount() == 0, error = kErrorFailed);
550
551 host = Host::New(GetInstance());
552 VerifyOrExit(host != nullptr, error = kErrorNoBufs);
553 SuccessOrExit(error = ProcessUpdateSection(*host, aMessage, aDnsHeader, zone, aOffset));
554
555 // Parse lease time and validate signature.
556 SuccessOrExit(error = ProcessAdditionalSection(host, aMessage, aDnsHeader, aOffset));
557
558 HandleUpdate(aDnsHeader, *host, aMessageInfo);
559
560 exit:
561 if (error != kErrorNone)
562 {
563 if (host != nullptr)
564 {
565 host->Free();
566 }
567
568 SendResponse(aDnsHeader, ErrorToDnsResponseCode(error), aMessageInfo);
569 }
570 }
571
ProcessZoneSection(const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,uint16_t & aOffset,Dns::Zone & aZone) const572 Error Server::ProcessZoneSection(const Message & aMessage,
573 const Dns::UpdateHeader &aDnsHeader,
574 uint16_t & aOffset,
575 Dns::Zone & aZone) const
576 {
577 Error error = kErrorNone;
578 char name[Dns::Name::kMaxNameSize];
579 Dns::Zone zone;
580
581 VerifyOrExit(aDnsHeader.GetZoneRecordCount() == 1, error = kErrorParse);
582
583 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
584 // TODO: return `Dns::kResponseNotAuth` for not authorized zone names.
585 VerifyOrExit(strcmp(name, GetDomain()) == 0, error = kErrorSecurity);
586 SuccessOrExit(error = aMessage.Read(aOffset, zone));
587 aOffset += sizeof(zone);
588
589 VerifyOrExit(zone.GetType() == Dns::ResourceRecord::kTypeSoa, error = kErrorParse);
590 aZone = zone;
591
592 exit:
593 return error;
594 }
595
ProcessUpdateSection(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t & aOffset) const596 Error Server::ProcessUpdateSection(Host & aHost,
597 const Message & aMessage,
598 const Dns::UpdateHeader &aDnsHeader,
599 const Dns::Zone & aZone,
600 uint16_t & aOffset) const
601 {
602 Error error = kErrorNone;
603
604 // Process Service Discovery, Host and Service Description Instructions with
605 // 3 times iterations over all DNS update RRs. The order of those processes matters.
606
607 // 0. Enumerate over all Service Discovery Instructions before processing any other records.
608 // So that we will know whether a name is a hostname or service instance name when processing
609 // a "Delete All RRsets from a name" record.
610 error = ProcessServiceDiscoveryInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset);
611 SuccessOrExit(error);
612
613 // 1. Enumerate over all RRs to build the Host Description Instruction.
614 error = ProcessHostDescriptionInstruction(aHost, aMessage, aDnsHeader, aZone, aOffset);
615 SuccessOrExit(error);
616
617 // 2. Enumerate over all RRs to build the Service Description Instructions.
618 error = ProcessServiceDescriptionInstructions(aHost, aMessage, aDnsHeader, aZone, aOffset);
619 SuccessOrExit(error);
620
621 // 3. Verify that there are no name conflicts.
622 VerifyOrExit(!HasNameConflictsWith(aHost), error = kErrorDuplicated);
623
624 exit:
625 return error;
626 }
627
ProcessHostDescriptionInstruction(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t aOffset) const628 Error Server::ProcessHostDescriptionInstruction(Host & aHost,
629 const Message & aMessage,
630 const Dns::UpdateHeader &aDnsHeader,
631 const Dns::Zone & aZone,
632 uint16_t aOffset) const
633 {
634 Error error;
635
636 OT_ASSERT(aHost.GetFullName() == nullptr);
637
638 for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
639 {
640 char name[Dns::Name::kMaxNameSize];
641 Dns::ResourceRecord record;
642
643 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
644
645 SuccessOrExit(error = aMessage.Read(aOffset, record));
646
647 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
648 {
649 // Delete All RRsets from a name.
650 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
651
652 // A "Delete All RRsets from a name" RR can only apply to a Service or Host Description.
653
654 if (aHost.FindServiceDescription(name) == nullptr)
655 {
656 // If host name is already set to a different name, `SetFullName()`
657 // will return `kErrorFailed`.
658 SuccessOrExit(error = aHost.SetFullName(name));
659 aHost.ClearResources();
660 }
661 }
662 else if (record.GetType() == Dns::ResourceRecord::kTypeAaaa)
663 {
664 Dns::AaaaRecord aaaaRecord;
665
666 VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
667
668 SuccessOrExit(error = aHost.SetFullName(name));
669
670 SuccessOrExit(error = aMessage.Read(aOffset, aaaaRecord));
671 VerifyOrExit(aaaaRecord.IsValid(), error = kErrorParse);
672
673 // Tolerate kErrorDrop for AAAA Resources.
674 VerifyOrExit(aHost.AddIp6Address(aaaaRecord.GetAddress()) != kErrorNoBufs, error = kErrorNoBufs);
675 }
676 else if (record.GetType() == Dns::ResourceRecord::kTypeKey)
677 {
678 // We currently support only ECDSA P-256.
679 Dns::Ecdsa256KeyRecord key;
680
681 VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
682 SuccessOrExit(error = aMessage.Read(aOffset, key));
683 VerifyOrExit(key.IsValid(), error = kErrorParse);
684
685 VerifyOrExit(aHost.GetKey() == nullptr || *aHost.GetKey() == key, error = kErrorSecurity);
686 aHost.SetKey(key);
687 }
688
689 aOffset += record.GetSize();
690 }
691
692 // Verify that we have a complete Host Description Instruction.
693
694 VerifyOrExit(aHost.GetFullName() != nullptr, error = kErrorFailed);
695 VerifyOrExit(aHost.GetKey() != nullptr, error = kErrorFailed);
696
697 // We check the number of host addresses after processing of the
698 // Lease Option in the Addition Section and determining whether
699 // the host is being removed or registered.
700
701 exit:
702 return error;
703 }
704
ProcessServiceDiscoveryInstructions(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t aOffset) const705 Error Server::ProcessServiceDiscoveryInstructions(Host & aHost,
706 const Message & aMessage,
707 const Dns::UpdateHeader &aDnsHeader,
708 const Dns::Zone & aZone,
709 uint16_t aOffset) const
710 {
711 Error error = kErrorNone;
712
713 for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
714 {
715 char serviceName[Dns::Name::kMaxNameSize];
716 char instanceName[Dns::Name::kMaxNameSize];
717 Dns::PtrRecord ptrRecord;
718 const char * subServiceName;
719 Service * service;
720 bool isSubType;
721
722 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, serviceName, sizeof(serviceName)));
723 VerifyOrExit(Dns::Name::IsSubDomainOf(serviceName, GetDomain()), error = kErrorSecurity);
724
725 error = Dns::ResourceRecord::ReadRecord(aMessage, aOffset, ptrRecord);
726
727 if (error == kErrorNotFound)
728 {
729 // `ReadRecord()` updates `aOffset` to skip over a
730 // non-matching record.
731 error = kErrorNone;
732 continue;
733 }
734
735 SuccessOrExit(error);
736
737 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, instanceName, sizeof(instanceName)));
738
739 VerifyOrExit(ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone ||
740 ptrRecord.GetClass() == aZone.GetClass(),
741 error = kErrorFailed);
742
743 // Check if the `serviceName` is a subtype with the name
744 // format: "<sub-label>._sub.<service-labels>.<domain>."
745
746 subServiceName = StringFind(serviceName, kServiceSubTypeLabel);
747 isSubType = (subServiceName != nullptr);
748
749 if (isSubType)
750 {
751 // Skip over the "._sub." label to get to the base
752 // service name.
753 subServiceName += sizeof(kServiceSubTypeLabel) - 1;
754 }
755
756 // Verify that instance name and service name are related.
757
758 VerifyOrExit(StringEndsWith(instanceName, isSubType ? subServiceName : serviceName), error = kErrorFailed);
759
760 // Ensure the same service does not exist already.
761 VerifyOrExit(aHost.FindService(serviceName, instanceName) == nullptr, error = kErrorFailed);
762
763 service = aHost.AddNewService(serviceName, instanceName, isSubType);
764 VerifyOrExit(service != nullptr, error = kErrorNoBufs);
765
766 // This RR is a "Delete an RR from an RRset" update when the CLASS is NONE.
767 service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
768 }
769
770 exit:
771 return error;
772 }
773
ProcessServiceDescriptionInstructions(Host & aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,const Dns::Zone & aZone,uint16_t & aOffset) const774 Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
775 const Message & aMessage,
776 const Dns::UpdateHeader &aDnsHeader,
777 const Dns::Zone & aZone,
778 uint16_t & aOffset) const
779 {
780 Error error = kErrorNone;
781 TimeMilli now = TimerMilli::GetNow();
782
783 for (uint16_t numRecords = aDnsHeader.GetUpdateRecordCount(); numRecords > 0; numRecords--)
784 {
785 Service::Description *desc;
786 char name[Dns::Name::kMaxNameSize];
787 Dns::ResourceRecord record;
788
789 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
790 SuccessOrExit(error = aMessage.Read(aOffset, record));
791
792 if (record.GetClass() == Dns::ResourceRecord::kClassAny)
793 {
794 // Delete All RRsets from a name.
795 VerifyOrExit(IsValidDeleteAllRecord(record), error = kErrorFailed);
796
797 desc = aHost.FindServiceDescription(name);
798
799 if (desc != nullptr)
800 {
801 desc->ClearResources();
802 desc->mTimeLastUpdate = now;
803 }
804
805 aOffset += record.GetSize();
806 continue;
807 }
808
809 if (record.GetType() == Dns::ResourceRecord::kTypeSrv)
810 {
811 Dns::SrvRecord srvRecord;
812 char hostName[Dns::Name::kMaxNameSize];
813 uint16_t hostNameLength = sizeof(hostName);
814
815 VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
816 SuccessOrExit(error = aMessage.Read(aOffset, srvRecord));
817 aOffset += sizeof(srvRecord);
818
819 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, hostName, hostNameLength));
820 VerifyOrExit(Dns::Name::IsSubDomainOf(name, GetDomain()), error = kErrorSecurity);
821 VerifyOrExit(aHost.Matches(hostName), error = kErrorFailed);
822
823 desc = aHost.FindServiceDescription(name);
824 VerifyOrExit(desc != nullptr, error = kErrorFailed);
825
826 // Make sure that this is the first SRV RR for this service description
827 VerifyOrExit(desc->mPort == 0, error = kErrorFailed);
828 desc->mPriority = srvRecord.GetPriority();
829 desc->mWeight = srvRecord.GetWeight();
830 desc->mPort = srvRecord.GetPort();
831 desc->mTimeLastUpdate = now;
832 }
833 else if (record.GetType() == Dns::ResourceRecord::kTypeTxt)
834 {
835 VerifyOrExit(record.GetClass() == aZone.GetClass(), error = kErrorFailed);
836
837 desc = aHost.FindServiceDescription(name);
838 VerifyOrExit(desc != nullptr, error = kErrorFailed);
839
840 aOffset += sizeof(record);
841 SuccessOrExit(error = desc->SetTxtDataFromMessage(aMessage, aOffset, record.GetLength()));
842 aOffset += record.GetLength();
843 }
844 else
845 {
846 aOffset += record.GetSize();
847 }
848 }
849
850 // Verify that all service descriptions on `aHost` are updated. Note
851 // that `mTimeLastUpdate` on a new `Service::Description` is set to
852 // `GetNow().GetDistantPast()`.
853
854 for (Service::Description &desc : aHost.mServiceDescriptions)
855 {
856 VerifyOrExit(desc.mTimeLastUpdate == now, error = kErrorFailed);
857
858 // Check that either both `mPort` and `mTxtData` are set
859 // (i.e., we saw both SRV and TXT record) or both are default
860 // (cleared) value (i.e., we saw neither of them).
861
862 VerifyOrExit((desc.mPort == 0) == (desc.mTxtData == nullptr), error = kErrorFailed);
863 }
864
865 exit:
866 return error;
867 }
868
IsValidDeleteAllRecord(const Dns::ResourceRecord & aRecord)869 bool Server::IsValidDeleteAllRecord(const Dns::ResourceRecord &aRecord)
870 {
871 return aRecord.GetClass() == Dns::ResourceRecord::kClassAny && aRecord.GetType() == Dns::ResourceRecord::kTypeAny &&
872 aRecord.GetTtl() == 0 && aRecord.GetLength() == 0;
873 }
874
ProcessAdditionalSection(Host * aHost,const Message & aMessage,const Dns::UpdateHeader & aDnsHeader,uint16_t & aOffset) const875 Error Server::ProcessAdditionalSection(Host * aHost,
876 const Message & aMessage,
877 const Dns::UpdateHeader &aDnsHeader,
878 uint16_t & aOffset) const
879 {
880 Error error = kErrorNone;
881 Dns::OptRecord optRecord;
882 Dns::LeaseOption leaseOption;
883 Dns::SigRecord sigRecord;
884 char name[2]; // The root domain name (".") is expected.
885 uint16_t sigOffset;
886 uint16_t sigRdataOffset;
887 char signerName[Dns::Name::kMaxNameSize];
888 uint16_t signatureLength;
889
890 VerifyOrExit(aDnsHeader.GetAdditionalRecordCount() == 2, error = kErrorFailed);
891
892 // EDNS(0) Update Lease Option.
893
894 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
895 SuccessOrExit(error = aMessage.Read(aOffset, optRecord));
896 SuccessOrExit(error = aMessage.Read(aOffset + sizeof(optRecord), leaseOption));
897 VerifyOrExit(leaseOption.IsValid(), error = kErrorFailed);
898 VerifyOrExit(optRecord.GetSize() == sizeof(optRecord) + sizeof(leaseOption), error = kErrorParse);
899
900 aOffset += optRecord.GetSize();
901
902 aHost->SetLease(leaseOption.GetLeaseInterval());
903 aHost->SetKeyLease(leaseOption.GetKeyLeaseInterval());
904
905 if (aHost->GetLease() > 0)
906 {
907 uint8_t hostAddressesNum;
908
909 aHost->GetAddresses(hostAddressesNum);
910
911 // There MUST be at least one valid address if we have nonzero lease.
912 VerifyOrExit(hostAddressesNum > 0, error = kErrorFailed);
913 }
914
915 // SIG(0).
916
917 sigOffset = aOffset;
918 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, name, sizeof(name)));
919 SuccessOrExit(error = aMessage.Read(aOffset, sigRecord));
920 VerifyOrExit(sigRecord.IsValid(), error = kErrorParse);
921
922 sigRdataOffset = aOffset + sizeof(Dns::ResourceRecord);
923 aOffset += sizeof(sigRecord);
924
925 // TODO: Verify that the signature doesn't expire. This is not
926 // implemented because the end device may not be able to get
927 // the synchronized date/time.
928
929 SuccessOrExit(error = Dns::Name::ReadName(aMessage, aOffset, signerName, sizeof(signerName)));
930
931 signatureLength = sigRecord.GetLength() - (aOffset - sigRdataOffset);
932 aOffset += signatureLength;
933
934 // Verify the signature. Currently supports only ECDSA.
935
936 VerifyOrExit(sigRecord.GetAlgorithm() == Dns::KeyRecord::kAlgorithmEcdsaP256Sha256, error = kErrorFailed);
937 VerifyOrExit(sigRecord.GetTypeCovered() == 0, error = kErrorFailed);
938 VerifyOrExit(signatureLength == Crypto::Ecdsa::P256::Signature::kSize, error = kErrorParse);
939
940 SuccessOrExit(error = VerifySignature(*aHost->GetKey(), aMessage, aDnsHeader, sigOffset, sigRdataOffset,
941 sigRecord.GetLength(), signerName));
942
943 exit:
944 return error;
945 }
946
VerifySignature(const Dns::Ecdsa256KeyRecord & aKey,const Message & aMessage,Dns::UpdateHeader aDnsHeader,uint16_t aSigOffset,uint16_t aSigRdataOffset,uint16_t aSigRdataLength,const char * aSignerName) const947 Error Server::VerifySignature(const Dns::Ecdsa256KeyRecord &aKey,
948 const Message & aMessage,
949 Dns::UpdateHeader aDnsHeader,
950 uint16_t aSigOffset,
951 uint16_t aSigRdataOffset,
952 uint16_t aSigRdataLength,
953 const char * aSignerName) const
954 {
955 Error error;
956 uint16_t offset = aMessage.GetOffset();
957 uint16_t signatureOffset;
958 Crypto::Sha256 sha256;
959 Crypto::Sha256::Hash hash;
960 Crypto::Ecdsa::P256::Signature signature;
961 Message * signerNameMessage = nullptr;
962
963 VerifyOrExit(aSigRdataLength >= Crypto::Ecdsa::P256::Signature::kSize, error = kErrorInvalidArgs);
964
965 sha256.Start();
966
967 // SIG RDATA less signature.
968 sha256.Update(aMessage, aSigRdataOffset, sizeof(Dns::SigRecord) - sizeof(Dns::ResourceRecord));
969
970 // The uncompressed (canonical) form of the signer name should be used for signature
971 // verification. See https://tools.ietf.org/html/rfc2931#section-3.1 for details.
972 signerNameMessage = Get<Ip6::Udp>().NewMessage(0);
973 VerifyOrExit(signerNameMessage != nullptr, error = kErrorNoBufs);
974 SuccessOrExit(error = Dns::Name::AppendName(aSignerName, *signerNameMessage));
975 sha256.Update(*signerNameMessage, signerNameMessage->GetOffset(), signerNameMessage->GetLength());
976
977 // We need the DNS header before appending the SIG RR.
978 aDnsHeader.SetAdditionalRecordCount(aDnsHeader.GetAdditionalRecordCount() - 1);
979 sha256.Update(aDnsHeader);
980 sha256.Update(aMessage, offset + sizeof(aDnsHeader), aSigOffset - offset - sizeof(aDnsHeader));
981
982 sha256.Finish(hash);
983
984 signatureOffset = aSigRdataOffset + aSigRdataLength - Crypto::Ecdsa::P256::Signature::kSize;
985 SuccessOrExit(error = aMessage.Read(signatureOffset, signature));
986
987 error = aKey.GetKey().Verify(hash, signature);
988
989 exit:
990 FreeMessage(signerNameMessage);
991 return error;
992 }
993
HandleUpdate(const Dns::UpdateHeader & aDnsHeader,Host & aHost,const Ip6::MessageInfo & aMessageInfo)994 void Server::HandleUpdate(const Dns::UpdateHeader &aDnsHeader, Host &aHost, const Ip6::MessageInfo &aMessageInfo)
995 {
996 Error error = kErrorNone;
997 Host *existingHost;
998
999 // Check whether the SRP update wants to remove `aHost`.
1000
1001 VerifyOrExit(aHost.GetLease() == 0);
1002
1003 aHost.ClearResources();
1004
1005 existingHost = mHosts.FindMatching(aHost.GetFullName());
1006 VerifyOrExit(existingHost != nullptr);
1007
1008 // The client may not include all services it has registered before
1009 // when removing a host. We copy and append any missing services to
1010 // `aHost` from the `existingHost` and mark them as deleted.
1011
1012 for (Service &service : existingHost->mServices)
1013 {
1014 if (service.mIsDeleted)
1015 {
1016 continue;
1017 }
1018
1019 if (aHost.FindService(service.GetServiceName(), service.GetInstanceName()) == nullptr)
1020 {
1021 Service *newService =
1022 aHost.AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType());
1023
1024 VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
1025 newService->mDescription.mTimeLastUpdate = TimerMilli::GetNow();
1026 newService->mIsDeleted = true;
1027 }
1028 }
1029
1030 exit:
1031 if (error != kErrorNone)
1032 {
1033 CommitSrpUpdate(error, aDnsHeader, aHost, aMessageInfo);
1034 }
1035 else if (mServiceUpdateHandler != nullptr)
1036 {
1037 UpdateMetadata *update = UpdateMetadata::New(GetInstance(), aDnsHeader, &aHost, aMessageInfo);
1038
1039 IgnoreError(mOutstandingUpdates.Add(*update));
1040 mOutstandingUpdatesTimer.StartAt(mOutstandingUpdates.GetTail()->GetExpireTime(), 0);
1041
1042 mServiceUpdateHandler(update->GetId(), &aHost, kDefaultEventsHandlerTimeout, mServiceUpdateHandlerContext);
1043 }
1044 else
1045 {
1046 CommitSrpUpdate(kErrorNone, aDnsHeader, aHost, aMessageInfo);
1047 }
1048 }
1049
SendResponse(const Dns::UpdateHeader & aHeader,Dns::UpdateHeader::Response aResponseCode,const Ip6::MessageInfo & aMessageInfo)1050 void Server::SendResponse(const Dns::UpdateHeader & aHeader,
1051 Dns::UpdateHeader::Response aResponseCode,
1052 const Ip6::MessageInfo & aMessageInfo)
1053 {
1054 Error error;
1055 Message * response = nullptr;
1056 Dns::UpdateHeader header;
1057
1058 response = mSocket.NewMessage(0);
1059 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1060
1061 header.SetMessageId(aHeader.GetMessageId());
1062 header.SetType(Dns::UpdateHeader::kTypeResponse);
1063 header.SetQueryType(aHeader.GetQueryType());
1064 header.SetResponseCode(aResponseCode);
1065 SuccessOrExit(error = response->Append(header));
1066
1067 SuccessOrExit(error = mSocket.SendTo(*response, aMessageInfo));
1068
1069 if (aResponseCode != Dns::UpdateHeader::kResponseSuccess)
1070 {
1071 otLogInfoSrp("[server] send fail response: %d", aResponseCode);
1072 }
1073 else
1074 {
1075 otLogInfoSrp("[server] send success response");
1076 }
1077
1078 exit:
1079 if (error != kErrorNone)
1080 {
1081 otLogWarnSrp("[server] failed to send response: %s", ErrorToString(error));
1082 FreeMessage(response);
1083 }
1084 }
1085
SendResponse(const Dns::UpdateHeader & aHeader,uint32_t aLease,uint32_t aKeyLease,const Ip6::MessageInfo & aMessageInfo)1086 void Server::SendResponse(const Dns::UpdateHeader &aHeader,
1087 uint32_t aLease,
1088 uint32_t aKeyLease,
1089 const Ip6::MessageInfo & aMessageInfo)
1090 {
1091 Error error;
1092 Message * response = nullptr;
1093 Dns::UpdateHeader header;
1094 Dns::OptRecord optRecord;
1095 Dns::LeaseOption leaseOption;
1096
1097 response = mSocket.NewMessage(0);
1098 VerifyOrExit(response != nullptr, error = kErrorNoBufs);
1099
1100 header.SetMessageId(aHeader.GetMessageId());
1101 header.SetType(Dns::UpdateHeader::kTypeResponse);
1102 header.SetQueryType(aHeader.GetQueryType());
1103 header.SetResponseCode(Dns::UpdateHeader::kResponseSuccess);
1104 header.SetAdditionalRecordCount(1);
1105 SuccessOrExit(error = response->Append(header));
1106
1107 // Append the root domain (".").
1108 SuccessOrExit(error = Dns::Name::AppendTerminator(*response));
1109
1110 optRecord.Init();
1111 optRecord.SetUdpPayloadSize(kUdpPayloadSize);
1112 optRecord.SetDnsSecurityFlag();
1113 optRecord.SetLength(sizeof(Dns::LeaseOption));
1114 SuccessOrExit(error = response->Append(optRecord));
1115
1116 leaseOption.Init();
1117 leaseOption.SetLeaseInterval(aLease);
1118 leaseOption.SetKeyLeaseInterval(aKeyLease);
1119 SuccessOrExit(error = response->Append(leaseOption));
1120
1121 SuccessOrExit(error = mSocket.SendTo(*response, aMessageInfo));
1122
1123 otLogInfoSrp("[server] send response with granted lease: %u and key lease: %u", aLease, aKeyLease);
1124
1125 exit:
1126 if (error != kErrorNone)
1127 {
1128 otLogWarnSrp("[server] failed to send response: %s", ErrorToString(error));
1129 FreeMessage(response);
1130 }
1131 }
1132
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1133 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1134 {
1135 static_cast<Server *>(aContext)->HandleUdpReceive(*static_cast<Message *>(aMessage),
1136 *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
1137 }
1138
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1139 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1140 {
1141 Error error;
1142 Dns::UpdateHeader dnsHeader;
1143 uint16_t offset = aMessage.GetOffset();
1144
1145 SuccessOrExit(error = aMessage.Read(offset, dnsHeader));
1146 offset += sizeof(dnsHeader);
1147
1148 // Handles only queries.
1149 VerifyOrExit(dnsHeader.GetType() == Dns::UpdateHeader::Type::kTypeQuery, error = kErrorDrop);
1150
1151 switch (dnsHeader.GetQueryType())
1152 {
1153 case Dns::UpdateHeader::kQueryTypeUpdate:
1154 HandleDnsUpdate(aMessage, aMessageInfo, dnsHeader, offset);
1155 break;
1156 default:
1157 error = kErrorDrop;
1158 break;
1159 }
1160
1161 exit:
1162 if (error != kErrorNone)
1163 {
1164 otLogInfoSrp("[server] failed to handle DNS message: %s", ErrorToString(error));
1165 }
1166 }
1167
HandleLeaseTimer(Timer & aTimer)1168 void Server::HandleLeaseTimer(Timer &aTimer)
1169 {
1170 aTimer.Get<Server>().HandleLeaseTimer();
1171 }
1172
HandleLeaseTimer(void)1173 void Server::HandleLeaseTimer(void)
1174 {
1175 TimeMilli now = TimerMilli::GetNow();
1176 TimeMilli earliestExpireTime = now.GetDistantFuture();
1177 Host * nextHost;
1178
1179 for (Host *host = mHosts.GetHead(); host != nullptr; host = nextHost)
1180 {
1181 nextHost = host->GetNext();
1182
1183 if (host->GetKeyExpireTime() <= now)
1184 {
1185 otLogInfoSrp("[server] KEY LEASE of host %s expired", host->GetFullName());
1186
1187 // Removes the whole host and all services if the KEY RR expired.
1188 RemoveHost(host, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1189 }
1190 else if (host->IsDeleted())
1191 {
1192 // The host has been deleted, but the hostname & service instance names retain.
1193
1194 Service *next;
1195
1196 earliestExpireTime = OT_MIN(earliestExpireTime, host->GetKeyExpireTime());
1197
1198 // Check if any service instance name expired.
1199 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1200 {
1201 next = service->GetNext();
1202
1203 OT_ASSERT(service->mIsDeleted);
1204
1205 if (service->GetKeyExpireTime() <= now)
1206 {
1207 service->Log(Service::kKeyLeaseExpired);
1208 host->RemoveService(service, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1209 }
1210 else
1211 {
1212 earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1213 }
1214 }
1215 }
1216 else if (host->GetExpireTime() <= now)
1217 {
1218 otLogInfoSrp("[server] LEASE of host %s expired", host->GetFullName());
1219
1220 // If the host expired, delete all resources of this host and its services.
1221 for (Service &service : host->mServices)
1222 {
1223 // Don't need to notify the service handler as `RemoveHost` at below will do.
1224 host->RemoveService(&service, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
1225 }
1226
1227 RemoveHost(host, /* aRetainName */ true, /* aNotifyServiceHandler */ true);
1228
1229 earliestExpireTime = OT_MIN(earliestExpireTime, host->GetKeyExpireTime());
1230 }
1231 else
1232 {
1233 // The host doesn't expire, check if any service expired or is explicitly removed.
1234
1235 Service *next;
1236
1237 OT_ASSERT(!host->IsDeleted());
1238
1239 earliestExpireTime = OT_MIN(earliestExpireTime, host->GetExpireTime());
1240
1241 for (Service *service = host->mServices.GetHead(); service != nullptr; service = next)
1242 {
1243 next = service->GetNext();
1244
1245 if (service->GetKeyExpireTime() <= now)
1246 {
1247 service->Log(Service::kKeyLeaseExpired);
1248 host->RemoveService(service, /* aRetainName */ false, /* aNotifyServiceHandler */ true);
1249 }
1250 else if (service->mIsDeleted)
1251 {
1252 // The service has been deleted but the name retains.
1253 earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1254 }
1255 else if (service->GetExpireTime() <= now)
1256 {
1257 service->Log(Service::kLeaseExpired);
1258
1259 // The service is expired, delete it.
1260 host->RemoveService(service, /* aRetainName */ true, /* aNotifyServiceHandler */ true);
1261 earliestExpireTime = OT_MIN(earliestExpireTime, service->GetKeyExpireTime());
1262 }
1263 else
1264 {
1265 earliestExpireTime = OT_MIN(earliestExpireTime, service->GetExpireTime());
1266 }
1267 }
1268 }
1269 }
1270
1271 if (earliestExpireTime != now.GetDistantFuture())
1272 {
1273 OT_ASSERT(earliestExpireTime >= now);
1274 if (!mLeaseTimer.IsRunning() || earliestExpireTime <= mLeaseTimer.GetFireTime())
1275 {
1276 otLogInfoSrp("[server] lease timer is scheduled for %u seconds", Time::MsecToSec(earliestExpireTime - now));
1277 mLeaseTimer.StartAt(earliestExpireTime, 0);
1278 }
1279 }
1280 else
1281 {
1282 otLogInfoSrp("[server] lease timer is stopped");
1283 mLeaseTimer.Stop();
1284 }
1285 }
1286
HandleOutstandingUpdatesTimer(Timer & aTimer)1287 void Server::HandleOutstandingUpdatesTimer(Timer &aTimer)
1288 {
1289 aTimer.Get<Server>().HandleOutstandingUpdatesTimer();
1290 }
1291
HandleOutstandingUpdatesTimer(void)1292 void Server::HandleOutstandingUpdatesTimer(void)
1293 {
1294 otLogInfoSrp("[server] outstanding service update timeout");
1295 while (!mOutstandingUpdates.IsEmpty() && mOutstandingUpdates.GetTail()->GetExpireTime() <= TimerMilli::GetNow())
1296 {
1297 HandleServiceUpdateResult(mOutstandingUpdates.GetTail(), kErrorResponseTimeout);
1298 }
1299 }
1300
1301 //---------------------------------------------------------------------------------------------------------------------
1302 // Server::Service
1303
New(const char * aServiceName,Description & aDescription,bool aIsSubType)1304 Server::Service *Server::Service::New(const char *aServiceName, Description &aDescription, bool aIsSubType)
1305 {
1306 void * buf;
1307 Service *service = nullptr;
1308
1309 buf = Instance::HeapCAlloc(1, sizeof(Service));
1310 VerifyOrExit(buf != nullptr);
1311
1312 service = new (buf) Service(aDescription, aIsSubType);
1313
1314 if (service->mServiceName.Set(aServiceName) != kErrorNone)
1315 {
1316 service->Free();
1317 service = nullptr;
1318 }
1319
1320 exit:
1321 return service;
1322 }
1323
Free(void)1324 void Server::Service::Free(void)
1325 {
1326 Instance::HeapFree(this);
1327 }
1328
Service(Description & aDescription,bool aIsSubType)1329 Server::Service::Service(Description &aDescription, bool aIsSubType)
1330 : mDescription(aDescription)
1331 , mNext(nullptr)
1332 , mTimeLastUpdate(TimerMilli::GetNow())
1333 , mIsDeleted(false)
1334 , mIsSubType(aIsSubType)
1335 , mIsCommitted(false)
1336 {
1337 }
1338
GetServiceSubTypeLabel(char * aLabel,uint8_t aMaxSize) const1339 Error Server::Service::GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const
1340 {
1341 Error error = kErrorNone;
1342 const char *serviceName = GetServiceName();
1343 const char *subServiceName;
1344 uint8_t labelLength;
1345
1346 memset(aLabel, 0, aMaxSize);
1347
1348 VerifyOrExit(IsSubType(), error = kErrorInvalidArgs);
1349
1350 subServiceName = StringFind(serviceName, kServiceSubTypeLabel);
1351 OT_ASSERT(subServiceName != nullptr);
1352
1353 if (subServiceName - serviceName < aMaxSize)
1354 {
1355 labelLength = static_cast<uint8_t>(subServiceName - serviceName);
1356 }
1357 else
1358 {
1359 labelLength = aMaxSize - 1;
1360 error = kErrorNoBufs;
1361 }
1362
1363 memcpy(aLabel, serviceName, labelLength);
1364
1365 exit:
1366 return error;
1367 }
1368
GetExpireTime(void) const1369 TimeMilli Server::Service::GetExpireTime(void) const
1370 {
1371 OT_ASSERT(!mIsDeleted);
1372 OT_ASSERT(!GetHost().IsDeleted());
1373
1374 return mTimeLastUpdate + Time::SecToMsec(mDescription.mLease);
1375 }
1376
GetKeyExpireTime(void) const1377 TimeMilli Server::Service::GetKeyExpireTime(void) const
1378 {
1379 return mTimeLastUpdate + Time::SecToMsec(mDescription.mKeyLease);
1380 }
1381
MatchesFlags(Flags aFlags) const1382 bool Server::Service::MatchesFlags(Flags aFlags) const
1383 {
1384 bool matches = false;
1385
1386 if (IsSubType())
1387 {
1388 VerifyOrExit(aFlags & kFlagSubType);
1389 }
1390 else
1391 {
1392 VerifyOrExit(aFlags & kFlagBaseType);
1393 }
1394
1395 if (IsDeleted())
1396 {
1397 VerifyOrExit(aFlags & kFlagDeleted);
1398 }
1399 else
1400 {
1401 VerifyOrExit(aFlags & kFlagActive);
1402 }
1403
1404 matches = true;
1405
1406 exit:
1407 return matches;
1408 }
1409
1410 #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_SRP
Log(Action aAction) const1411 void Server::Service::Log(Action aAction) const
1412 {
1413 static const char *const kActionStrings[] = {
1414 "add new", // (0) kAddNew
1415 "update existing", // (1) kUpdateExisting
1416 "remove but retain name of", // (2) kRemoveButRetainName
1417 "full remove", // (3) kFullyRemove
1418 "LEASE expired for ", // (4) kLeaseExpired
1419 "KEY LEASE expired for", // (5) kKeyLeaseExpired
1420 };
1421
1422 char subLabel[Dns::Name::kMaxLabelSize];
1423
1424 static_assert(0 == kAddNew, "kAddNew value is incorrect");
1425 static_assert(1 == kUpdateExisting, "kUpdateExisting value is incorrect");
1426 static_assert(2 == kRemoveButRetainName, "kRemoveButRetainName value is incorrect");
1427 static_assert(3 == kFullyRemove, "kFullyRemove value is incorrect");
1428 static_assert(4 == kLeaseExpired, "kLeaseExpired value is incorrect");
1429 static_assert(5 == kKeyLeaseExpired, "kKeyLeaseExpired value is incorrect");
1430
1431 // We only log if the `Service` is marked as committed. This
1432 // ensures that temporary `Service` entries associated with a
1433 // newly received SRP update message are not logged (e.g., when
1434 // associated `Host` is being freed).
1435
1436 if (mIsCommitted)
1437 {
1438 IgnoreError(GetServiceSubTypeLabel(subLabel, sizeof(subLabel)));
1439
1440 otLogInfoSrp("[server] %s service '%s'%s%s", kActionStrings[aAction], GetInstanceName(),
1441 IsSubType() ? " subtype:" : "", subLabel);
1442 }
1443 }
1444 #else
Log(Action) const1445 void Server::Service::Log(Action) const
1446 {
1447 }
1448 #endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && OPENTHREAD_CONFIG_LOG_SRP
1449
1450 //---------------------------------------------------------------------------------------------------------------------
1451 // Server::Service::Description
1452
New(const char * aInstanceName,Host & aHost)1453 Server::Service::Description *Server::Service::Description::New(const char *aInstanceName, Host &aHost)
1454 {
1455 void * buf;
1456 Description *desc = nullptr;
1457
1458 buf = Instance::HeapCAlloc(1, sizeof(Description));
1459 VerifyOrExit(buf != nullptr);
1460
1461 desc = new (buf) Description(aHost);
1462
1463 if (desc->mInstanceName.Set(aInstanceName) != kErrorNone)
1464 {
1465 desc->Free();
1466 desc = nullptr;
1467 }
1468
1469 exit:
1470 return desc;
1471 }
1472
Free(void)1473 void Server::Service::Description::Free(void)
1474 {
1475 mInstanceName.Free();
1476 Instance::HeapFree(this);
1477 }
1478
Description(Host & aHost)1479 Server::Service::Description::Description(Host &aHost)
1480 : mNext(nullptr)
1481 , mHost(aHost)
1482 , mPriority(0)
1483 , mWeight(0)
1484 , mPort(0)
1485 , mTxtLength(0)
1486 , mTxtData(nullptr)
1487 , mLease(0)
1488 , mKeyLease(0)
1489 , mTimeLastUpdate(TimerMilli::GetNow().GetDistantPast())
1490 {
1491 }
1492
ClearResources(void)1493 void Server::Service::Description::ClearResources(void)
1494 {
1495 mPort = 0;
1496 Instance::HeapFree(mTxtData);
1497 mTxtData = nullptr;
1498 mTxtLength = 0;
1499 }
1500
TakeResourcesFrom(Description & aDescription)1501 void Server::Service::Description::TakeResourcesFrom(Description &aDescription)
1502 {
1503 // Take ownership and move the heap allocated `mTxtData` buffer
1504 // from `aDescription
1505 Instance::HeapFree(mTxtData);
1506 mTxtData = aDescription.mTxtData;
1507 mTxtLength = aDescription.mTxtLength;
1508 aDescription.mTxtData = nullptr;
1509 aDescription.mTxtLength = 0;
1510
1511 mPriority = aDescription.mPriority;
1512 mWeight = aDescription.mWeight;
1513 mPort = aDescription.mPort;
1514
1515 mLease = aDescription.mLease;
1516 mKeyLease = aDescription.mKeyLease;
1517 mTimeLastUpdate = TimerMilli::GetNow();
1518 }
1519
SetTxtDataFromMessage(const Message & aMessage,uint16_t aOffset,uint16_t aLength)1520 Error Server::Service::Description::SetTxtDataFromMessage(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
1521 {
1522 Error error = kErrorNone;
1523 uint8_t *txtData;
1524
1525 txtData = static_cast<uint8_t *>(Instance::HeapCAlloc(1, aLength));
1526 VerifyOrExit(txtData != nullptr, error = kErrorNoBufs);
1527
1528 VerifyOrExit(aMessage.ReadBytes(aOffset, txtData, aLength) == aLength, error = kErrorParse);
1529 VerifyOrExit(Dns::TxtRecord::VerifyTxtData(txtData, aLength), error = kErrorParse);
1530
1531 Instance::HeapFree(mTxtData);
1532 mTxtData = txtData;
1533 mTxtLength = aLength;
1534
1535 exit:
1536 if (error != kErrorNone)
1537 {
1538 Instance::HeapFree(txtData);
1539 }
1540
1541 return error;
1542 }
1543
1544 //---------------------------------------------------------------------------------------------------------------------
1545 // Server::Host
1546
New(Instance & aInstance)1547 Server::Host *Server::Host::New(Instance &aInstance)
1548 {
1549 void *buf;
1550 Host *host = nullptr;
1551
1552 buf = Instance::HeapCAlloc(1, sizeof(Host));
1553 VerifyOrExit(buf != nullptr);
1554
1555 host = new (buf) Host(aInstance);
1556
1557 exit:
1558 return host;
1559 }
1560
Free(void)1561 void Server::Host::Free(void)
1562 {
1563 FreeAllServices();
1564 mFullName.Free();
1565 Instance::HeapFree(this);
1566 }
1567
Host(Instance & aInstance)1568 Server::Host::Host(Instance &aInstance)
1569 : InstanceLocator(aInstance)
1570 , mAddressesNum(0)
1571 , mNext(nullptr)
1572 , mLease(0)
1573 , mKeyLease(0)
1574 , mTimeLastUpdate(TimerMilli::GetNow())
1575 {
1576 mKey.Clear();
1577 }
1578
SetFullName(const char * aFullName)1579 Error Server::Host::SetFullName(const char *aFullName)
1580 {
1581 // `mFullName` becomes immutable after it is set, so if it is
1582 // already set, we only accept a `aFullName` that matches the
1583 // current name.
1584
1585 Error error;
1586
1587 if (mFullName.IsNull())
1588 {
1589 error = mFullName.Set(aFullName);
1590 }
1591 else
1592 {
1593 error = Matches(aFullName) ? kErrorNone : kErrorFailed;
1594 }
1595
1596 return error;
1597 }
1598
SetKey(Dns::Ecdsa256KeyRecord & aKey)1599 void Server::Host::SetKey(Dns::Ecdsa256KeyRecord &aKey)
1600 {
1601 OT_ASSERT(aKey.IsValid());
1602
1603 mKey = aKey;
1604 }
1605
GetExpireTime(void) const1606 TimeMilli Server::Host::GetExpireTime(void) const
1607 {
1608 OT_ASSERT(!IsDeleted());
1609
1610 return mTimeLastUpdate + Time::SecToMsec(mLease);
1611 }
1612
GetKeyExpireTime(void) const1613 TimeMilli Server::Host::GetKeyExpireTime(void) const
1614 {
1615 return mTimeLastUpdate + Time::SecToMsec(mKeyLease);
1616 }
1617
FindNextService(const Service * aPrevService,Service::Flags aFlags,const char * aServiceName,const char * aInstanceName) const1618 const Server::Service *Server::Host::FindNextService(const Service *aPrevService,
1619 Service::Flags aFlags,
1620 const char * aServiceName,
1621 const char * aInstanceName) const
1622 {
1623 const Service *service = (aPrevService == nullptr) ? GetServices().GetHead() : aPrevService->GetNext();
1624
1625 for (; service != nullptr; service = service->GetNext())
1626 {
1627 if (!service->MatchesFlags(aFlags))
1628 {
1629 continue;
1630 }
1631
1632 if ((aServiceName != nullptr) && !service->MatchesServiceName(aServiceName))
1633 {
1634 continue;
1635 }
1636
1637 if ((aInstanceName != nullptr) && !service->MatchesInstanceName(aInstanceName))
1638 {
1639 continue;
1640 }
1641
1642 break;
1643 }
1644
1645 return service;
1646 }
1647
AddNewService(const char * aServiceName,const char * aInstanceName,bool aIsSubType)1648 Server::Service *Server::Host::AddNewService(const char *aServiceName, const char *aInstanceName, bool aIsSubType)
1649 {
1650 Service * service = nullptr;
1651 Service::Description *desc;
1652
1653 desc = FindServiceDescription(aInstanceName);
1654
1655 if (desc == nullptr)
1656 {
1657 desc = Service::Description::New(aInstanceName, *this);
1658 VerifyOrExit(desc != nullptr);
1659 mServiceDescriptions.Push(*desc);
1660 }
1661
1662 service = Service::New(aServiceName, *desc, aIsSubType);
1663 VerifyOrExit(service != nullptr);
1664
1665 mServices.Push(*service);
1666
1667 exit:
1668 return service;
1669 }
1670
RemoveService(Service * aService,bool aRetainName,bool aNotifyServiceHandler)1671 void Server::Host::RemoveService(Service *aService, bool aRetainName, bool aNotifyServiceHandler)
1672 {
1673 Server &server = Get<Server>();
1674
1675 VerifyOrExit(aService != nullptr);
1676
1677 aService->mIsDeleted = true;
1678
1679 aService->Log(aRetainName ? Service::kRemoveButRetainName : Service::kFullyRemove);
1680
1681 if (aNotifyServiceHandler && server.mServiceUpdateHandler != nullptr)
1682 {
1683 server.mServiceUpdateHandler(server.AllocateId(), this, kDefaultEventsHandlerTimeout,
1684 server.mServiceUpdateHandlerContext);
1685 // We don't wait for the reply from the service update handler,
1686 // but always remove the service regardless of service update result.
1687 // Because removing a service should fail only when there is system
1688 // failure of the platform mDNS implementation and in which case the
1689 // service is not expected to be still registered.
1690 }
1691
1692 if (!aRetainName)
1693 {
1694 IgnoreError(mServices.Remove(*aService));
1695 aService->Free();
1696 FreeUnusedServiceDescriptions();
1697 }
1698
1699 exit:
1700 return;
1701 }
1702
FreeAllServices(void)1703 void Server::Host::FreeAllServices(void)
1704 {
1705 while (!mServices.IsEmpty())
1706 {
1707 RemoveService(mServices.GetHead(), /* aRetainName */ false, /* aNotifyServiceHandler */ false);
1708 }
1709 }
1710
FreeUnusedServiceDescriptions(void)1711 void Server::Host::FreeUnusedServiceDescriptions(void)
1712 {
1713 Service::Description *desc;
1714 Service::Description *prev;
1715 Service::Description *next;
1716
1717 for (prev = nullptr, desc = mServiceDescriptions.GetHead(); desc != nullptr; desc = next)
1718 {
1719 next = desc->GetNext();
1720
1721 if (FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, /* aServiceName */ nullptr,
1722 desc->GetInstanceName()) == nullptr)
1723 {
1724 mServiceDescriptions.PopAfter(prev);
1725 desc->Free();
1726
1727 // When the `desc` is removed from the list
1728 // we keep the `prev` pointer same as before.
1729 }
1730 else
1731 {
1732 prev = desc;
1733 }
1734 }
1735 }
1736
ClearResources(void)1737 void Server::Host::ClearResources(void)
1738 {
1739 mAddressesNum = 0;
1740 }
1741
MergeServicesAndResourcesFrom(Host & aHost)1742 Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
1743 {
1744 // This method merges services, service descriptions, and other
1745 // resources from another `aHost` into current host. It can
1746 // possibly take ownership of some items from `aHost`.
1747
1748 Error error = kErrorNone;
1749
1750 otLogInfoSrp("[server] update host %s", GetFullName());
1751
1752 memcpy(mAddresses, aHost.mAddresses, aHost.mAddressesNum * sizeof(mAddresses[0]));
1753 mAddressesNum = aHost.mAddressesNum;
1754 mKey = aHost.mKey;
1755 mLease = aHost.mLease;
1756 mKeyLease = aHost.mKeyLease;
1757 mTimeLastUpdate = TimerMilli::GetNow();
1758
1759 for (Service &service : aHost.mServices)
1760 {
1761 Service *existingService = FindService(service.GetServiceName(), service.GetInstanceName());
1762 Service *newService;
1763
1764 if (service.mIsDeleted)
1765 {
1766 // `RemoveService()` does nothing if `exitsingService` is `nullptr`.
1767 RemoveService(existingService, /* aRetainName */ true, /* aNotifyServiceHandler */ false);
1768 continue;
1769 }
1770
1771 // Add/Merge `service` into the existing service or a allocate a new one
1772
1773 newService = (existingService != nullptr)
1774 ? existingService
1775 : AddNewService(service.GetServiceName(), service.GetInstanceName(), service.IsSubType());
1776
1777 VerifyOrExit(newService != nullptr, error = kErrorNoBufs);
1778
1779 newService->mIsDeleted = false;
1780 newService->mIsCommitted = true;
1781 newService->mTimeLastUpdate = TimerMilli::GetNow();
1782
1783 if (!service.mIsSubType)
1784 {
1785 // (1) Service description is shared across a base type and all its subtypes.
1786 // (2) `TakeResourcesFrom()` releases resources pinned to its argument.
1787 // Therefore, make sure the function is called only for the base type.
1788 newService->mDescription.TakeResourcesFrom(service.mDescription);
1789 }
1790
1791 newService->Log((existingService != nullptr) ? Service::kUpdateExisting : Service::kAddNew);
1792 }
1793
1794 exit:
1795 return error;
1796 }
1797
FindServiceDescription(const char * aInstanceName) const1798 const Server::Service::Description *Server::Host::FindServiceDescription(const char *aInstanceName) const
1799 {
1800 return mServiceDescriptions.FindMatching(aInstanceName);
1801 }
1802
FindServiceDescription(const char * aInstanceName)1803 Server::Service::Description *Server::Host::FindServiceDescription(const char *aInstanceName)
1804 {
1805 return const_cast<Service::Description *>(const_cast<const Host *>(this)->FindServiceDescription(aInstanceName));
1806 }
1807
FindService(const char * aServiceName,const char * aInstanceName) const1808 const Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName) const
1809 {
1810 return FindNextService(/* aPrevService */ nullptr, kFlagsAnyService, aServiceName, aInstanceName);
1811 }
1812
FindService(const char * aServiceName,const char * aInstanceName)1813 Server::Service *Server::Host::FindService(const char *aServiceName, const char *aInstanceName)
1814 {
1815 return const_cast<Service *>(const_cast<const Host *>(this)->FindService(aServiceName, aInstanceName));
1816 }
1817
AddIp6Address(const Ip6::Address & aIp6Address)1818 Error Server::Host::AddIp6Address(const Ip6::Address &aIp6Address)
1819 {
1820 Error error = kErrorNone;
1821
1822 if (aIp6Address.IsMulticast() || aIp6Address.IsUnspecified() || aIp6Address.IsLoopback())
1823 {
1824 // We don't like those address because they cannot be used
1825 // for communication with exterior devices.
1826 ExitNow(error = kErrorDrop);
1827 }
1828
1829 for (const Ip6::Address &addr : mAddresses)
1830 {
1831 if (aIp6Address == addr)
1832 {
1833 // Drop duplicate addresses.
1834 ExitNow(error = kErrorDrop);
1835 }
1836 }
1837
1838 if (mAddressesNum >= kMaxAddressesNum)
1839 {
1840 otLogWarnSrp("[server] too many addresses for host %s", GetFullName());
1841 ExitNow(error = kErrorNoBufs);
1842 }
1843
1844 mAddresses[mAddressesNum++] = aIp6Address;
1845
1846 exit:
1847 return error;
1848 }
1849
1850 //---------------------------------------------------------------------------------------------------------------------
1851 // Server::UpdateMetadata
1852
New(Instance & aInstance,const Dns::UpdateHeader & aHeader,Host * aHost,const Ip6::MessageInfo & aMessageInfo)1853 Server::UpdateMetadata *Server::UpdateMetadata::New(Instance & aInstance,
1854 const Dns::UpdateHeader &aHeader,
1855 Host * aHost,
1856 const Ip6::MessageInfo & aMessageInfo)
1857 {
1858 void * buf;
1859 UpdateMetadata *update = nullptr;
1860
1861 buf = Instance::HeapCAlloc(1, sizeof(UpdateMetadata));
1862 VerifyOrExit(buf != nullptr);
1863
1864 update = new (buf) UpdateMetadata(aInstance, aHeader, aHost, aMessageInfo);
1865
1866 exit:
1867 return update;
1868 }
1869
Free(void)1870 void Server::UpdateMetadata::Free(void)
1871 {
1872 Instance::HeapFree(this);
1873 }
1874
UpdateMetadata(Instance & aInstance,const Dns::UpdateHeader & aHeader,Host * aHost,const Ip6::MessageInfo & aMessageInfo)1875 Server::UpdateMetadata::UpdateMetadata(Instance & aInstance,
1876 const Dns::UpdateHeader &aHeader,
1877 Host * aHost,
1878 const Ip6::MessageInfo & aMessageInfo)
1879 : InstanceLocator(aInstance)
1880 , mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
1881 , mDnsHeader(aHeader)
1882 , mId(Get<Server>().AllocateId())
1883 , mHost(aHost)
1884 , mMessageInfo(aMessageInfo)
1885 , mNext(nullptr)
1886 {
1887 }
1888
1889 } // namespace Srp
1890 } // namespace ot
1891
1892 #endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
1893