From fcbc4bef9b634a4d3987fde9ed7f3a954970cd58 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 20 May 2022 15:34:50 -0700 Subject: [PATCH] [srp-client] add API to specify TTL (#7735) --- include/openthread/instance.h | 2 +- include/openthread/srp_client.h | 28 +++++++++++++++++++ src/cli/README_SRP_CLIENT.md | 22 +++++++++++++++ src/cli/cli_srp_client.cpp | 7 ++++- src/core/api/srp_client_api.cpp | 10 +++++++ src/core/net/srp_client.cpp | 9 +++--- src/core/net/srp_client.hpp | 26 +++++++++++++++++ tests/scripts/thread-cert/node.py | 10 +++++++ .../test_srp_client_change_lease.py | 14 ++++++++++ 9 files changed, 122 insertions(+), 6 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index d11583e36..c946217c5 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (210) +#define OPENTHREAD_API_VERSION (211) /** * @addtogroup api-instance diff --git a/include/openthread/srp_client.h b/include/openthread/srp_client.h index 72c03610a..1dc0c9e3e 100644 --- a/include/openthread/srp_client.h +++ b/include/openthread/srp_client.h @@ -315,6 +315,34 @@ void otSrpClientDisableAutoStartMode(otInstance *aInstance); */ bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance); +/** + * This function gets the TTL value in every record included in SRP update requests. + * + * Note that this is the TTL requested by the SRP client. The server may choose to accept a different TTL. + * + * By default, the TTL will equal the lease interval. Passing 0 or a value larger than the lease interval via + * `otSrpClientSetTtl()` will also cause the TTL to equal the lease interval. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * + * @returns The TTL (in seconds). + * + */ +uint32_t otSrpClientGetTtl(otInstance *aInstance); + +/** + * This function sets the TTL value in every record included in SRP update requests. + * + * Changing the TTL does not impact the TTL of already registered services/host-info. + * It only affects future SRP update messages (i.e., adding new services and/or refreshes of the existing services). + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in] aTtl The TTL (in seconds). If value is zero or greater than lease interval, the TTL is set to the + * lease interval. + * + */ +void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl); + /** * This function gets the lease interval used in SRP update requests. * diff --git a/src/cli/README_SRP_CLIENT.md b/src/cli/README_SRP_CLIENT.md index 5cbe94fac..ab5dcdb77 100644 --- a/src/cli/README_SRP_CLIENT.md +++ b/src/cli/README_SRP_CLIENT.md @@ -15,6 +15,7 @@ Usage : `srp client [command] ...` - [start](#start) - [state](#state) - [stop](#stop) +- [ttl](#ttl) ## Command Details @@ -36,6 +37,7 @@ service start state stop +ttl Done ``` @@ -409,3 +411,23 @@ Stop the SRP client. > srp client stop Done ``` + +### ttl + +Usage: `srp client ttl [value]` + +Get the TTL (in seconds). + +```bash +> srp client ttl +7200 +Done +> +``` + +Set the TTL. + +```bash +> srp client ttl 3600 +Done +``` diff --git a/src/cli/cli_srp_client.cpp b/src/cli/cli_srp_client.cpp index fa1b740b1..4d81cd901 100644 --- a/src/cli/cli_srp_client.cpp +++ b/src/cli/cli_srp_client.cpp @@ -525,6 +525,11 @@ exit: return error; } +template <> otError SrpClient::Process(Arg aArgs[]) +{ + return Interpreter::GetInterpreter().ProcessGetSet(aArgs, otSrpClientGetTtl, otSrpClientSetTtl); +} + void SrpClient::HandleCallback(otError aError, const otSrpClientHostInfo *aHostInfo, const otSrpClientService * aServices, @@ -578,7 +583,7 @@ otError SrpClient::Process(Arg aArgs[]) static constexpr Command kCommands[] = { CmdEntry("autostart"), CmdEntry("callback"), CmdEntry("host"), CmdEntry("keyleaseinterval"), CmdEntry("leaseinterval"), CmdEntry("server"), CmdEntry("service"), CmdEntry("start"), - CmdEntry("state"), CmdEntry("stop"), + CmdEntry("state"), CmdEntry("stop"), CmdEntry("ttl"), }; static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted"); diff --git a/src/core/api/srp_client_api.cpp b/src/core/api/srp_client_api.cpp index 304a2fe2d..a0c16e3d9 100644 --- a/src/core/api/srp_client_api.cpp +++ b/src/core/api/srp_client_api.cpp @@ -84,6 +84,16 @@ bool otSrpClientIsAutoStartModeEnabled(otInstance *aInstance) } #endif // OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE +uint32_t otSrpClientGetTtl(otInstance *aInstance) +{ + return AsCoreType(aInstance).Get().GetTtl(); +} + +void otSrpClientSetTtl(otInstance *aInstance, uint32_t aTtl) +{ + return AsCoreType(aInstance).Get().SetTtl(aTtl); +} + uint32_t otSrpClientGetLeaseInterval(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetLeaseInterval(); diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 0667d3096..f9fad2e4b 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -245,6 +245,7 @@ Client::Client(Instance &aInstance) , mUpdateMessageId(0) , mRetryWaitInterval(kMinRetryWaitInterval) , mAcceptedLeaseInterval(0) + , mTtl(0) , mLeaseInterval(kDefaultLease) , mKeyLeaseInterval(kDefaultKeyLease) , mSocket(aInstance) @@ -911,7 +912,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In // to NONE and TTL to zero (RFC 2136 - section 2.5.4). rr.Init(Dns::ResourceRecord::kTypePtr, removing ? Dns::PtrRecord::kClassNone : Dns::PtrRecord::kClassInternet); - rr.SetTtl(removing ? 0 : mLeaseInterval); + rr.SetTtl(removing ? 0 : GetTtl()); offset = aMessage.GetLength(); SuccessOrExit(error = aMessage.Append(rr)); @@ -970,7 +971,7 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In SuccessOrExit(error = Dns::Name::AppendPointerLabel(instanceNameOffset, aMessage)); srv.Init(); - srv.SetTtl(mLeaseInterval); + srv.SetTtl(GetTtl()); srv.SetPriority(aService.GetPriority()); srv.SetWeight(aService.GetWeight()); srv.SetPort(aService.GetPort()); @@ -1024,7 +1025,7 @@ Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) c // AAAA RRs rr.Init(Dns::ResourceRecord::kTypeAaaa); - rr.SetTtl(mLeaseInterval); + rr.SetTtl(GetTtl()); rr.SetLength(sizeof(Ip6::Address)); for (uint8_t index = 0; index < mHostInfo.GetNumAddresses(); index++) @@ -1051,7 +1052,7 @@ Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const Crypto::Ecdsa::P256::PublicKey publicKey; key.Init(); - key.SetTtl(mLeaseInterval); + key.SetTtl(GetTtl()); key.SetFlags(Dns::KeyRecord::kAuthConfidPermitted, Dns::KeyRecord::kOwnerNonZone, Dns::KeyRecord::kSignatoryFlagGeneral); key.SetProtocol(Dns::KeyRecord::kProtocolDnsSec); diff --git a/src/core/net/srp_client.hpp b/src/core/net/srp_client.hpp index 80b381ffd..8e7cca7dc 100644 --- a/src/core/net/srp_client.hpp +++ b/src/core/net/srp_client.hpp @@ -410,6 +410,31 @@ public: */ void SetCallback(Callback aCallback, void *aContext); + /** + * This method gets the TTL used in SRP update requests. + * + * Note that this is the TTL requested by the SRP client. The server may choose to accept a different TTL. + * + * By default, the TTL will equal the lease interval. Passing 0 or a value larger than the lease interval via + * `otSrpClientSetTtl()` will also cause the TTL to equal the lease interval. + * + * @returns The TTL (in seconds). + * + */ + uint32_t GetTtl(void) const { return (0 < mTtl && mTtl < mLeaseInterval) ? mTtl : mLeaseInterval; } + + /** + * This method sets the TTL used in SRP update requests. + * + * Changing the TTL does not impact the TTL of already registered services/host-info. + * It only changes any future SRP update messages (i.e adding new services and/or refreshes of existing services). + * + * @param[in] aTtl The TTL (in seconds). If value is zero or greater than lease interval, the TTL is set to the + * lease interval. + * + */ + void SetTtl(uint32_t aTtl) { mTtl = aTtl; } + /** * This method gets the lease interval used in SRP update requests. * @@ -922,6 +947,7 @@ private: TimeMilli mLeaseRenewTime; uint32_t mAcceptedLeaseInterval; + uint32_t mTtl; uint32_t mLeaseInterval; uint32_t mKeyLeaseInterval; diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 21bb6bed2..add478fa5 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -1156,6 +1156,16 @@ class NodeImpl: self.send_command(cmd) return int(self._expect_result('\d+')) + def srp_client_set_ttl(self, ttl: int): + cmd = f'srp client ttl {ttl}' + self.send_command(cmd) + self._expect_done() + + def srp_client_get_ttl(self) -> int: + cmd = 'srp client ttl' + self.send_command(cmd) + return int(self._expect_result('\d+')) + # # TREL utilities # diff --git a/tests/scripts/thread-cert/test_srp_client_change_lease.py b/tests/scripts/thread-cert/test_srp_client_change_lease.py index 532194a3d..5c1245da0 100755 --- a/tests/scripts/thread-cert/test_srp_client_change_lease.py +++ b/tests/scripts/thread-cert/test_srp_client_change_lease.py @@ -50,9 +50,11 @@ DEFAULT_LEASE_TIME = 7200 LEASE_TIME = 60 NEW_LEASE_TIME = 120 KEY_LEASE_TIME = 240 +NEW_TTL = 10 assert LEASE_TIME < KEY_LEASE_TIME assert NEW_LEASE_TIME < KEY_LEASE_TIME +assert NEW_TTL < NEW_LEASE_TIME class SrpClientChangeLeaseTime(thread_cert.TestCase): @@ -112,6 +114,14 @@ class SrpClientChangeLeaseTime(thread_cert.TestCase): self.simulator.go(KEY_LEASE_TIME * 2) self.assertEqual(client.srp_client_get_host_state(), 'Registered') + client.srp_client_set_ttl(NEW_TTL) + self.simulator.go(NEW_LEASE_TIME) + self.assertEqual(client.srp_client_get_host_state(), 'Registered') + + client.srp_client_set_ttl(0) + self.simulator.go(NEW_LEASE_TIME) + self.assertEqual(client.srp_client_get_host_state(), 'Registered') + def verify(self, pv): pkts: PacketFilter = pv.pkts pv.summary.show() @@ -122,6 +132,10 @@ class SrpClientChangeLeaseTime(thread_cert.TestCase): DEFAULT_LEASE_TIME=DEFAULT_LEASE_TIME).must_next() pkts.filter_wpan_src64(CLIENT_SRC64).filter('dns.flags.response == 0 and dns.resp.ttl == {NEW_LEASE_TIME}', NEW_LEASE_TIME=NEW_LEASE_TIME).must_next() + pkts.filter_wpan_src64(CLIENT_SRC64).filter('dns.flags.response == 0 and dns.resp.ttl == {NEW_TTL}', + NEW_TTL=NEW_TTL).must_next() + pkts.filter_wpan_src64(CLIENT_SRC64).filter('dns.flags.response == 0 and dns.resp.ttl == {NEW_LEASE_TIME}', + NEW_LEASE_TIME=NEW_LEASE_TIME).must_next() def check_host_and_service(self, server, client): """Check that we have properly registered host and service instance.