From 44046b7b685cec6363ff8358f89cb3a4cb115332 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 22 Jul 2025 11:00:43 -0700 Subject: [PATCH] [history-tracker] add Network Data DNS/SRP address entry tracking (#11685) This commit introduces a new feature in `HistoryTracker` to track Network Data DNS/SRP unicast/anycast address entries. This new functionality records when different Border Routers add or remove these entries in the Network Data. This change also introduces new public APIs and CLI command `history dnssrpaddr` to expose this information. --- include/openthread/history_tracker.h | 45 +++++++ include/openthread/instance.h | 2 +- src/cli/README_HISTORY.md | 43 +++++++ src/cli/cli_history.cpp | 122 ++++++++++++++++++- src/cli/cli_history.hpp | 1 + src/core/api/history_tracker_api.cpp | 10 ++ src/core/config/history_tracker.h | 11 ++ src/core/thread/network_data_service.cpp | 6 + src/core/thread/network_data_service.hpp | 6 +- src/core/utils/history_tracker.cpp | 148 ++++++++++++++++++++++- src/core/utils/history_tracker.hpp | 29 ++++- 11 files changed, 414 insertions(+), 9 deletions(-) diff --git a/include/openthread/history_tracker.h b/include/openthread/history_tracker.h index 8f38d7f06..a96f192d3 100644 --- a/include/openthread/history_tracker.h +++ b/include/openthread/history_tracker.h @@ -240,6 +240,35 @@ typedef struct otHistoryTrackerExternalRouteInfo otHistoryTrackerNetDataEvent mEvent; ///< Indicates the event (added/removed). } otHistoryTrackerExternalRouteInfo; +/** + * Represents the DNS/SRP server address type parsed from Network Data service entries. + */ +typedef enum +{ + OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_LOCAL, ///< Unicast address type local (in server data). + OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_INFRA, ///< Unicast address type infrastructure (in service data). + OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST, ///< Anycast address type. +} otHistoryTrackerDnsSrpAddrType; + +/** + * Represents DNS/SRP server address information parsed from a Network Data service entry. + * + * The `mType` field specifies the entry type. Some fields are only applicable to specific types. + * - The `mPort` field is only applicable for `OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_*` types. + * - The `mSequenceNumber` field is only applicable for the `OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST` type. + * - Other fields are common and used for all address types. + */ +typedef struct otHistoryTrackerDnsSrpAddrInfo +{ + otIp6Address mAddress; ///< The server address. + uint16_t mRloc16; ///< The RLOC16 of the Border Router adding/removing the entry. + uint16_t mPort; ///< Port number. + uint8_t mSequenceNumber; ///< Anycast sequence number. + uint8_t mVersion; ///< Version number. + otHistoryTrackerDnsSrpAddrType mType; ///< Address type. + otHistoryTrackerNetDataEvent mEvent; ///< Indicates the event (added/removed). +} otHistoryTrackerDnsSrpAddrInfo; + /** * Represents events during the Border Agent's ePSKc journey. */ @@ -422,6 +451,22 @@ const otHistoryTrackerExternalRouteInfo *otHistoryTrackerIterateExternalRouteHis otHistoryTrackerIterator *aIterator, uint32_t *aEntryAge); +/** + * Iterates over the entries in the Network Data SRP/DNS address history list. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in,out] aIterator A pointer to an iterator. MUST be initialized or the behavior is undefined. + * @param[out] aEntryAge A pointer to a variable to output the entry's age. MUST NOT be NULL. + * Age is provided as the duration (in milliseconds) from when entry was recorded to + * @p aIterator initialization time. It is set to `OT_HISTORY_TRACKER_MAX_AGE` for entries + * older than max age. + * + * @returns The `otHistoryTrackerDnsSrpAddrInfo` entry or `NULL` if no more entries in the list. + */ +const otHistoryTrackerDnsSrpAddrInfo *otHistoryTrackerIterateDnsSrpAddrHistory(otInstance *aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t *aEntryAge); + /** * Iterates over the entries in the Border Agent ePSKc history list. * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index b5e220323..0c7effe83 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (519) +#define OPENTHREAD_API_VERSION (520) /** * @addtogroup api-instance diff --git a/src/cli/README_HISTORY.md b/src/cli/README_HISTORY.md index 21f2dc5e3..fc46cedc8 100644 --- a/src/cli/README_HISTORY.md +++ b/src/cli/README_HISTORY.md @@ -11,6 +11,7 @@ The number of entries recorded for each history list is configurable through a s Usage : `history [command] ...` - [help](#help) +- [dnssrpaddr](#dnssrpaddr) - [ipaddr](#ipaddr) - [ipmaddr](#ipmaddr) - [neighbor](#neighbor) @@ -65,6 +66,48 @@ Done > ``` +### dnssrpaddr + +Usage `history dnssrpaddr [list] []` + +Print the network data DNS/SRP address history. Each entry provides: + +- Event: Possible values are `Added` or `Removed`. +- Address of DNS/SRP server. +- Address type: `uni-local` unicast address local (address in server data) or `uni-infra` infrastructure server (addr in service data), or `anycast`. +- Port: Server port number, only applicable when address type is unicast. +- Sequence Number: Anycast sequence number, only applicable when address type is anycast. +- Version number. +- RLOC16 of the BR adding/removing this entry in Network Data. + +```bash +> history dnssrpaddr +| Age | Event | Address | Type |Port/Seq| Ver | RLOC16 | ++----------------------+---------+-----------------------------------------+-----------+--------+-----+--------+ +| 00:00:07.150 | Added | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 1234 | 0 | 0x0000 | +| 00:00:09.351 | Removed | fd00:0:0:0:0:0:0:1234 | uni-infra | 51525 | 1 | 0x0000 | +| 00:00:28.479 | Added | fd00:0:0:0:0:0:0:1234 | uni-infra | 51525 | 1 | 0x0000 | +| 00:00:30.133 | Removed | fd4f:59ae:348a:aa48:0:ff:fe00:fc10 | anycast | 1 | 2 | 0x0000 | +| 00:01:02.609 | Added | fd4f:59ae:348a:aa48:0:ff:fe00:fc10 | anycast | 1 | 2 | 0x0000 | +| 00:01:03.574 | Removed | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 50152 | 2 | 0x0000 | +| 00:01:33.631 | Added | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 50152 | 2 | 0x0000 | +Done +``` + +Print the history as a list. + +```bash +> history dnssrpaddr list +00:00:19.646 -> event:Added addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:1234 ver:0 rloc16:0x0000 +00:00:21.847 -> event:Removed addr:fd00:0:0:0:0:0:0:1234 type:uni-infra port:51525 ver:1 rloc16:0x0000 +00:00:40.975 -> event:Added addr:fd00:0:0:0:0:0:0:1234 type:uni-infra port:51525 ver:1 rloc16:0x0000 +00:00:42.629 -> event:Removed addr:fd4f:59ae:348a:aa48:0:ff:fe00:fc10 type:anycast seqno:1 ver:2 rloc16:0x0000 +00:01:15.105 -> event:Added addr:fd4f:59ae:348a:aa48:0:ff:fe00:fc10 type:anycast seqno:1 ver:2 rloc16:0x0000 +00:01:16.070 -> event:Removed addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:50152 ver:2 rloc16:0x0000 +00:01:46.127 -> event:Added addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:50152 ver:2 rloc16:0x0000 +Done +``` + ### ipaddr Usage `history ipaddr [list] []` diff --git a/src/cli/cli_history.cpp b/src/cli/cli_history.cpp index f0964fdba..d800758e6 100644 --- a/src/cli/cli_history.cpp +++ b/src/cli/cli_history.cpp @@ -1437,6 +1437,123 @@ exit: return error; } +// clang-format off +/** + * @cli history dnssrpaddr + * @code + * history dnssrpaddr + * | Age | Event | Address | Type |Port/Seq| Ver | RLOC16 | + * +----------------------+---------+-----------------------------------------+-----------+--------+-----+--------+ + * | 00:00:07.150 | Added | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 1234 | 0 | 0x0000 | + * | 00:00:09.351 | Removed | fd00:0:0:0:0:0:0:1234 | uni-infra | 51525 | 1 | 0x0000 | + * | 00:00:28.479 | Added | fd00:0:0:0:0:0:0:1234 | uni-infra | 51525 | 1 | 0x0000 | + * | 00:00:30.133 | Removed | fd4f:59ae:348a:aa48:0:ff:fe00:fc10 | anycast | 1 | 2 | 0x0000 | + * | 00:01:02.609 | Added | fd4f:59ae:348a:aa48:0:ff:fe00:fc10 | anycast | 1 | 2 | 0x0000 | + * | 00:01:03.574 | Removed | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 50152 | 2 | 0x0000 | + * | 00:01:33.631 | Added | fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb | uni-local | 50152 | 2 | 0x0000 | + * Done + * @endcode + * @code + * history dnssrpaddr list + * 00:00:19.646 -> event:Added addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:1234 ver:0 rloc16:0x0000 + * 00:00:21.847 -> event:Removed addr:fd00:0:0:0:0:0:0:1234 type:uni-infra port:51525 ver:1 rloc16:0x0000 + * 00:00:40.975 -> event:Added addr:fd00:0:0:0:0:0:0:1234 type:uni-infra port:51525 ver:1 rloc16:0x0000 + * 00:00:42.629 -> event:Removed addr:fd4f:59ae:348a:aa48:0:ff:fe00:fc10 type:anycast seqno:1 ver:2 rloc16:0x0000 + * 00:01:15.105 -> event:Added addr:fd4f:59ae:348a:aa48:0:ff:fe00:fc10 type:anycast seqno:1 ver:2 rloc16:0x0000 + * 00:01:16.070 -> event:Removed addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:50152 ver:2 rloc16:0x0000 + * 00:01:46.127 -> event:Added addr:fd4f:59ae:348a:aa48:74a4:6de9:7a30:5dfb type:uni-local port:50152 ver:2 rloc16:0x0000 + * Done + * @endcode + * @cparam history dnssrpaddr [@ca{list}] [@ca{num-entries}] + * * Use the `list` option to display the output in list format. Otherwise, the output is shown in table format. + * * Use the `num-entries` option to limit the output to the number of most-recent entries specified. If this option + * is not used, all stored entries are shown in the output. + * @par + * Displays the network data DNS/SRP address history in table or list format. + * @par + * Each table or list entry provides: + * * Age: Time elapsed since the command was issued, and given in the format: + * `hours`:`minutes`:`seconds`:`milliseconds` + * * Event: Possible values are `Added` or `Removed`. + * * Address of DNS/SRP server. + * * Address type: `uni-local` unicast address local (address in server data) or `uni-infra` infrastructure server + * (address in service data), or `anycast`. + * * Port or SeqNumber: Port if address is unicast, seq number for anycast address type. + * * Version number. + * * RLOC16 of the BR adding/removing this entry in Network Data. + * @sa otHistoryTrackerIterateDnsSrpAddrHistory + */ +// clang-format on +template <> otError History::Process(Arg aArgs[]) +{ + otError error; + bool isList; + uint16_t numEntries; + otHistoryTrackerIterator iterator; + const otHistoryTrackerDnsSrpAddrInfo *info; + uint32_t entryAge; + char ageString[OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE]; + char addrString[OT_IP6_ADDRESS_STRING_SIZE]; + + SuccessOrExit(error = ParseArgs(aArgs, isList, numEntries)); + + if (!isList) + { + static const char *const kTitles[] = {"Age", "Event", "Address", "Type", "Port/Seq", "Ver", "RLOC16"}; + static const uint8_t kColumnWidths[] = {22, 9, 41, 11, 8, 5, 8}; + + OutputTableHeader(kTitles, kColumnWidths); + } + + otHistoryTrackerInitIterator(&iterator); + + for (uint16_t index = 0; (numEntries == 0) || (index < numEntries); index++) + { + bool isAnycast; + + info = otHistoryTrackerIterateDnsSrpAddrHistory(GetInstancePtr(), &iterator, &entryAge); + VerifyOrExit(info != nullptr); + + otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString)); + + otIp6AddressToString(&info->mAddress, addrString, sizeof(addrString)); + + isAnycast = info->mType == OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST; + + if (isList) + { + OutputLine("%s -> event:%s addr:%s type:%s %s:%u ver:%u rloc16:0x%04x", ageString, + Stringify(info->mEvent, kSimpleEventStrings), addrString, DnsSrpAddrTypeToString(info->mType), + isAnycast ? "seqno" : "port", isAnycast ? info->mSequenceNumber : info->mPort, info->mVersion, + info->mRloc16); + } + else + { + OutputLine("| %20s | %-7s | %-39s | %9s | %6u | %3u | 0x%04x |", ageString, + Stringify(info->mEvent, kSimpleEventStrings), addrString, DnsSrpAddrTypeToString(info->mType), + isAnycast ? info->mSequenceNumber : info->mPort, info->mVersion, info->mRloc16); + } + } + +exit: + return error; +} + +const char *History::DnsSrpAddrTypeToString(otHistoryTrackerDnsSrpAddrType aType) +{ + static const char *const kAddrTypeStrings[] = { + "uni-local", // (0) OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_LOCAL + "uni-infra", // (1) OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_INFRA + "anycast", // (2) OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST + }; + + static_assert(0 == OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_LOCAL, "ADDR_TYPE_UNICAST_LOCAL is incorrect"); + static_assert(1 == OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_INFRA, "ADDR_TYPE_UNICAST_INFRA is incorrect"); + static_assert(2 == OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST, "ADDR_TYPE_ANYCAST is incorrect"); + + return Stringify(aType, kAddrTypeStrings, "--"); +} + otError History::Process(Arg aArgs[]) { #define CmdEntry(aCommandString) \ @@ -1445,8 +1562,9 @@ otError History::Process(Arg aArgs[]) } static constexpr Command kCommands[] = { - CmdEntry("ipaddr"), CmdEntry("ipmaddr"), CmdEntry("neighbor"), CmdEntry("netinfo"), CmdEntry("prefix"), - CmdEntry("route"), CmdEntry("router"), CmdEntry("rx"), CmdEntry("rxtx"), CmdEntry("tx"), + CmdEntry("dnssrpaddr"), CmdEntry("ipaddr"), CmdEntry("ipmaddr"), CmdEntry("neighbor"), + CmdEntry("netinfo"), CmdEntry("prefix"), CmdEntry("route"), CmdEntry("router"), + CmdEntry("rx"), CmdEntry("rxtx"), CmdEntry("tx"), }; #undef CmdEntry diff --git a/src/cli/cli_history.hpp b/src/cli/cli_history.hpp index ee70166db..0ae8e3a0d 100644 --- a/src/cli/cli_history.hpp +++ b/src/cli/cli_history.hpp @@ -100,6 +100,7 @@ private: static const char *MessagePriorityToString(uint8_t aPriority); static const char *RadioTypeToString(const otHistoryTrackerMessageInfo &aInfo); static const char *MessageTypeToString(const otHistoryTrackerMessageInfo &aInfo); + static const char *DnsSrpAddrTypeToString(otHistoryTrackerDnsSrpAddrType aType); }; } // namespace Cli diff --git a/src/core/api/history_tracker_api.cpp b/src/core/api/history_tracker_api.cpp index 5a002f7d3..73bdf7249 100644 --- a/src/core/api/history_tracker_api.cpp +++ b/src/core/api/history_tracker_api.cpp @@ -129,6 +129,16 @@ const otHistoryTrackerExternalRouteInfo *otHistoryTrackerIterateExternalRouteHis *aEntryAge); } +const otHistoryTrackerDnsSrpAddrInfo *otHistoryTrackerIterateDnsSrpAddrHistory(otInstance *aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t *aEntryAge) +{ + AssertPointerIsNotNull(aEntryAge); + + return AsCoreType(aInstance).Get().IterateDnsSrpAddrHistory(AsCoreType(aIterator), + *aEntryAge); +} + #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE const otHistoryTrackerBorderAgentEpskcEvent *otHistoryTrackerIterateBorderAgentEpskcEventHistory( otInstance *aInstance, diff --git a/src/core/config/history_tracker.h b/src/core/config/history_tracker.h index ef9c63721..090c975d3 100644 --- a/src/core/config/history_tracker.h +++ b/src/core/config/history_tracker.h @@ -160,6 +160,17 @@ #define OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE 32 #endif +/** + * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_DNSSRP_ADDR_LIST_SIZE + * + * Specifies the maximum number of entries in Network Data DNS/SRP Address history list. + * + * Set to zero to prevent the History Tracker module from collecting this info. + */ +#ifndef OPENTHREAD_CONFIG_HISTORY_TRACKER_DNSSRP_ADDR_LIST_SIZE +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_DNSSRP_ADDR_LIST_SIZE 32 +#endif + /** * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_EPSKC_EVENT_SIZE * diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 6d72bc62b..53ceba22b 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -181,6 +181,8 @@ Error Iterator::GetNextDnsSrpAnycastInfo(DnsSrpAnycastInfo &aInfo) Error error = kErrorNone; uint8_t serviceNumber = Manager::kDnsSrpAnycastServiceNumber; + aInfo.Clear(); + do { ServiceData serviceData; @@ -229,6 +231,8 @@ Error Manager::FindPreferredDnsSrpAnycastInfo(DnsSrpAnycastInfo &aInfo) const DnsSrpAnycastInfo info; DnsSrpAnycastInfo maxNumericalSeqNumInfo; + aInfo.Clear(); + // Determine the entry with largest seq number in two ways: // `aInfo` will track the largest using serial number arithmetic // comparison, while `maxNumericalSeqNumInfo` tracks the largest @@ -321,6 +325,8 @@ Error Iterator::GetNextDnsSrpUnicastInfo(DnsSrpUnicastType aType, DnsSrpUnicastI Error error = kErrorNone; uint8_t serviceNumber = Manager::kDnsSrpUnicastServiceNumber; + aInfo.Clear(); + do { ServiceData serviceData; diff --git a/src/core/thread/network_data_service.hpp b/src/core/thread/network_data_service.hpp index 901911090..beca23e0c 100644 --- a/src/core/thread/network_data_service.hpp +++ b/src/core/thread/network_data_service.hpp @@ -39,7 +39,9 @@ #include #include "backbone_router/bbr_leader.hpp" +#include "common/clearable.hpp" #include "common/encoding.hpp" +#include "common/equatable.hpp" #include "common/locator.hpp" #include "common/non_copyable.hpp" #include "common/serial_number.hpp" @@ -55,7 +57,7 @@ const uint32_t kThreadEnterpriseNumber = ServiceTlv::kThreadEnterpriseNumber; // /** * Represents information about an DNS/SRP server parsed from related Network Data service entries. */ -struct DnsSrpAnycastInfo +struct DnsSrpAnycastInfo : public Clearable, public Equatable { Ip6::Address mAnycastAddress; ///< The anycast address associated with the DNS/SRP servers. uint8_t mSequenceNumber; ///< Sequence number used to notify SRP client if they need to re-register. @@ -75,7 +77,7 @@ enum DnsSrpUnicastType : uint8_t /** * Represents information about an DNS/SRP server parsed from related Network Data service entries. */ -struct DnsSrpUnicastInfo +struct DnsSrpUnicastInfo : public Clearable, public Equatable { Ip6::SockAddr mSockAddr; ///< The socket address (IPv6 address and port) of the DNS/SRP server. uint8_t mVersion; ///< Version number. diff --git a/src/core/utils/history_tracker.cpp b/src/core/utils/history_tracker.cpp index 87060618e..21e650370 100644 --- a/src/core/utils/history_tracker.cpp +++ b/src/core/utils/history_tracker.cpp @@ -348,9 +348,18 @@ void HistoryTracker::RecordRouterTableChange(void) #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA void HistoryTracker::RecordNetworkDataChange(void) { - NetworkData::Iterator iterator; - NetworkData::OnMeshPrefixConfig prefix; - NetworkData::ExternalRouteConfig route; + static const NetworkData::Service::DnsSrpUnicastType kDnsSrpUnicastTypes[] = { + NetworkData::Service::kAddrInServiceData, + NetworkData::Service::kAddrInServerData, + }; + + NetworkData::Iterator iterator; + NetworkData::OnMeshPrefixConfig prefix; + NetworkData::ExternalRouteConfig route; + NetworkData::Service::DnsSrpUnicastInfo unicastInfo; + NetworkData::Service::DnsSrpAnycastInfo anycastInfo; + NetworkData::Service::Iterator newDataIterator(GetInstance(), Get()); + NetworkData::Service::Iterator prvDataIterator(GetInstance(), mPreviousNetworkData); // On mesh prefix entries @@ -396,6 +405,51 @@ void HistoryTracker::RecordNetworkDataChange(void) } } + // DNS/SRP Unicast/Anycast entries + + for (NetworkData::Service::DnsSrpUnicastType type : kDnsSrpUnicastTypes) + { + prvDataIterator.Reset(); + + while (prvDataIterator.GetNextDnsSrpUnicastInfo(type, unicastInfo) == kErrorNone) + { + if (!NetDataContainsDnsSrpUnicast(Get(), unicastInfo, type)) + { + RecordDnsSrpAddrEvent(kNetDataEntryRemoved, unicastInfo, type); + } + } + + newDataIterator.Reset(); + + while (newDataIterator.GetNextDnsSrpUnicastInfo(type, unicastInfo) == kErrorNone) + { + if (!NetDataContainsDnsSrpUnicast(mPreviousNetworkData, unicastInfo, type)) + { + RecordDnsSrpAddrEvent(kNetDataEntryAdded, unicastInfo, type); + } + } + } + + prvDataIterator.Reset(); + + while (prvDataIterator.GetNextDnsSrpAnycastInfo(anycastInfo) == kErrorNone) + { + if (!NetDataContainsDnsSrpAnycast(Get(), anycastInfo)) + { + RecordDnsSrpAddrEvent(kNetDataEntryRemoved, anycastInfo); + } + } + + newDataIterator.Reset(); + + while (newDataIterator.GetNextDnsSrpAnycastInfo(anycastInfo) == kErrorNone) + { + if (!NetDataContainsDnsSrpAnycast(mPreviousNetworkData, anycastInfo)) + { + RecordDnsSrpAddrEvent(kNetDataEntryAdded, anycastInfo); + } + } + SuccessOrAssert(Get().CopyNetworkData(NetworkData::kFullSet, mPreviousNetworkData)); } @@ -423,6 +477,93 @@ exit: return; } +void HistoryTracker::RecordDnsSrpAddrEvent(NetDataEvent aEvent, + const NetworkData::Service::DnsSrpUnicastInfo &aUnicastInfo, + NetworkData::Service::DnsSrpUnicastType aType) +{ + DnsSrpAddrInfo *entry = mDnsSrpAddrHistory.AddNewEntry(); + + VerifyOrExit(entry != nullptr); + + entry->mAddress = aUnicastInfo.mSockAddr.mAddress; + entry->mRloc16 = aUnicastInfo.mRloc16; + entry->mPort = aUnicastInfo.mSockAddr.mPort; + entry->mSequenceNumber = 0; + entry->mVersion = aUnicastInfo.mVersion; + entry->mEvent = aEvent; + + switch (aType) + { + case NetworkData::Service::kAddrInServerData: + entry->mType = kDnsSrpAddrTypeUnicastLocal; + break; + case NetworkData::Service::kAddrInServiceData: + entry->mType = kDnsSrpAddrTypeUnicastInfra; + break; + } + +exit: + return; +} + +void HistoryTracker::RecordDnsSrpAddrEvent(NetDataEvent aEvent, + const NetworkData::Service::DnsSrpAnycastInfo &aAnycastInfo) +{ + DnsSrpAddrInfo *entry = mDnsSrpAddrHistory.AddNewEntry(); + + VerifyOrExit(entry != nullptr); + + entry->mAddress = aAnycastInfo.mAnycastAddress; + entry->mRloc16 = aAnycastInfo.mRloc16; + entry->mPort = kAnycastServerPort; + entry->mSequenceNumber = aAnycastInfo.mSequenceNumber; + entry->mVersion = aAnycastInfo.mVersion; + entry->mEvent = aEvent; + entry->mType = kDnsSrpAddrTypeAnycast; + +exit: + return; +} + +bool HistoryTracker::NetDataContainsDnsSrpUnicast(const NetworkData::NetworkData &aNetworkData, + const NetworkData::Service::DnsSrpUnicastInfo &aUnicastInfo, + NetworkData::Service::DnsSrpUnicastType aType) const +{ + bool contains = false; + NetworkData::Service::Iterator iterator(GetInstance(), aNetworkData); + NetworkData::Service::DnsSrpUnicastInfo unicastInfo; + + while (iterator.GetNextDnsSrpUnicastInfo(aType, unicastInfo) == kErrorNone) + { + if (unicastInfo == aUnicastInfo) + { + contains = true; + break; + } + } + + return contains; +} + +bool HistoryTracker::NetDataContainsDnsSrpAnycast(const NetworkData::NetworkData &aNetworkData, + const NetworkData::Service::DnsSrpAnycastInfo &aAnycastInfo) const +{ + bool contains = false; + NetworkData::Service::Iterator iterator(GetInstance(), aNetworkData); + NetworkData::Service::DnsSrpAnycastInfo anycastInfo; + + while (iterator.GetNextDnsSrpAnycastInfo(anycastInfo) == kErrorNone) + { + if (anycastInfo == aAnycastInfo) + { + contains = true; + break; + } + } + + return contains; +} + #endif // OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE @@ -464,6 +605,7 @@ void HistoryTracker::HandleTimer(void) mNeighborHistory.UpdateAgedEntries(); mOnMeshPrefixHistory.UpdateAgedEntries(); mExternalRouteHistory.UpdateAgedEntries(); + mDnsSrpAddrHistory.UpdateAgedEntries(); #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE mEpskcEventHistory.UpdateAgedEntries(); #endif diff --git a/src/core/utils/history_tracker.hpp b/src/core/utils/history_tracker.hpp index c869f00ec..817b2e006 100644 --- a/src/core/utils/history_tracker.hpp +++ b/src/core/utils/history_tracker.hpp @@ -55,6 +55,7 @@ #include "thread/mle_types.hpp" #include "thread/neighbor_table.hpp" #include "thread/network_data.hpp" +#include "thread/network_data_service.hpp" #include "thread/router_table.hpp" namespace ot { @@ -68,7 +69,8 @@ namespace Utils { #define OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA \ ((OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE > 0) || \ - (OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE > 0)) + (OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE > 0) || \ + (OPENTHREAD_CONFIG_HISTORY_TRACKER_DNSSRP_ADDR_LIST_SIZE > 0)) /** * Implements History Tracker. @@ -140,6 +142,7 @@ public: typedef otHistoryTrackerRouterInfo RouterInfo; ///< Router info. typedef otHistoryTrackerOnMeshPrefixInfo OnMeshPrefixInfo; ///< Network Data on mesh prefix info. typedef otHistoryTrackerExternalRouteInfo ExternalRouteInfo; ///< Network Data external route info + typedef otHistoryTrackerDnsSrpAddrInfo DnsSrpAddrInfo; ///< Network Data SRP/DNS address info. #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE typedef otHistoryTrackerBorderAgentEpskcEvent EpskcEvent; ///< Border Agent ePSKc Event. #endif @@ -251,6 +254,11 @@ public: return mExternalRouteHistory.Iterate(aIterator, aEntryAge); } + const DnsSrpAddrInfo *IterateDnsSrpAddrHistory(Iterator &aIterator, uint32_t &aEntryAge) const + { + return mDnsSrpAddrHistory.Iterate(aIterator, aEntryAge); + } + #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE const EpskcEvent *IterateEpskcEventHistory(Iterator &aIterator, uint32_t &aEntryAge) const { @@ -289,6 +297,7 @@ private: static constexpr uint16_t kRouterListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE; static constexpr uint16_t kOnMeshPrefixListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE; static constexpr uint16_t kExternalRouteListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE; + static constexpr uint16_t kDnsSrpAddrListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_DNSSRP_ADDR_LIST_SIZE; static constexpr uint16_t kEpskcEventListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EPSKC_EVENT_SIZE; typedef otHistoryTrackerAddressEvent AddressEvent; @@ -317,6 +326,14 @@ private: static constexpr NetDataEvent kNetDataEntryAdded = OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED; static constexpr NetDataEvent kNetDataEntryRemoved = OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED; + typedef otHistoryTrackerDnsSrpAddrType DnsSrpAddrType; + + static constexpr DnsSrpAddrType kDnsSrpAddrTypeUnicastLocal = OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_LOCAL; + static constexpr DnsSrpAddrType kDnsSrpAddrTypeUnicastInfra = OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_UNICAST_INFRA; + static constexpr DnsSrpAddrType kDnsSrpAddrTypeAnycast = OT_HISTORY_TRACKER_DNS_SRP_ADDR_TYPE_ANYCAST; + + static constexpr uint16_t kAnycastServerPort = 53; + #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE #define DefineEpskcEvent(aName, aPublicEnumName) \ static constexpr EpskcEvent kEpskc##aName = OT_HISTORY_TRACKER_BORDER_AGENT_EPSKC_EVENT_##aPublicEnumName @@ -446,6 +463,15 @@ private: void RecordNetworkDataChange(void); void RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix); void RecordExternalRouteEvent(NetDataEvent aEvent, const NetworkData::ExternalRouteConfig &aRoute); + void RecordDnsSrpAddrEvent(NetDataEvent aEvent, + const NetworkData::Service::DnsSrpUnicastInfo &aUnicastInfo, + NetworkData::Service::DnsSrpUnicastType aType); + void RecordDnsSrpAddrEvent(NetDataEvent aEvent, const NetworkData::Service::DnsSrpAnycastInfo &aAnycastInfo); + bool NetDataContainsDnsSrpUnicast(const NetworkData::NetworkData &aNetworkData, + const NetworkData::Service::DnsSrpUnicastInfo &aUnicastInfo, + NetworkData::Service::DnsSrpUnicastType aType) const; + bool NetDataContainsDnsSrpAnycast(const NetworkData::NetworkData &aNetworkData, + const NetworkData::Service::DnsSrpAnycastInfo &aAnycastInfo) const; #endif #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE void RecordEpskcEvent(EpskcEvent aEvent); @@ -462,6 +488,7 @@ private: EntryList mRouterHistory; EntryList mOnMeshPrefixHistory; EntryList mExternalRouteHistory; + EntryList mDnsSrpAddrHistory; #if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE && OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE EntryList mEpskcEventHistory; #endif