From a2f63e524d9fc93d074479eb32b83f3ff8581ea3 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 1 Apr 2021 21:41:24 -0700 Subject: [PATCH] [srp-client] add "service key record inclusion" mode for testing (#6361) This commit adds support for "service key record inclusion" mode in SRP client. When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages that it sends. KEY record is optional in Service Description Instruction (it is required and always included in the Host Description Instruction). The default behavior of SRP client is to not include it. This feature is intended to override the default behavior for testing only and is is available under the reference device configuration build (i.e., when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` is enabled). This commit also add a CLI command for this feature as `srp client service key [enable/disable]` and updates the `README_SRP_CLIENT.md`. Finally, this commit adds new spinel property for SRP client "service key record inclusion" mode along with its get/set handlers in NCP build. --- include/openthread/instance.h | 2 +- include/openthread/srp_client.h | 30 ++++++++++++++++++++++++++++++ src/cli/README_SRP_CLIENT.md | 27 +++++++++++++++++++++++++++ src/cli/cli_srp_client.cpp | 31 +++++++++++++++++++++++++++++++ src/core/api/srp_client_api.cpp | 16 ++++++++++++++++ src/core/net/srp_client.cpp | 33 +++++++++++++++++++++++++++++---- src/core/net/srp_client.hpp | 29 +++++++++++++++++++++++++++++ src/lib/spinel/spinel.c | 3 +++ src/lib/spinel/spinel.h | 17 +++++++++++++++++ src/ncp/ncp_base.cpp | 4 ++++ src/ncp/ncp_base_dispatcher.cpp | 6 ++++++ src/ncp/ncp_base_mtd.cpp | 19 +++++++++++++++++++ 12 files changed, 212 insertions(+), 5 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 330bda2de..00f5e317f 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 (91) +#define OPENTHREAD_API_VERSION (92) /** * @addtogroup api-instance diff --git a/include/openthread/srp_client.h b/include/openthread/srp_client.h index 2f7b9df79..28be22966 100644 --- a/include/openthread/srp_client.h +++ b/include/openthread/srp_client.h @@ -561,6 +561,36 @@ otError otSrpClientSetDomainName(otInstance *aInstance, const char *aName); */ const char *otSrpClientItemStateToString(otSrpClientItemState aItemState); +/** + * This function enables/disables "service key record inclusion" mode. + * + * When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages + * that it sends. + * + * This function is available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` configuration is enabled. + * + * @note KEY record is optional in Service Description Instruction (it is required and always included in the Host + * Description Instruction). The default behavior of SRP client is to not include it. This function is intended to + * override the default behavior for testing only. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in] aEnabled TRUE to enable, FALSE to disable the "service key record inclusion" mode. + * + */ +void otSrpClientSetServiceKeyRecordEnabled(otInstance *aInstance, bool aEnabled); + +/** + * This method indicates whether the "service key record inclusion" mode is enabled or disabled. + * + * This function is available when `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` configuration is enabled. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * + * @returns TRUE if "service key record inclusion" mode is enabled, FALSE otherwise. + * + */ +bool otSrpClientIsServiceKeyRecordEnabled(otInstance *aInstance); + /** * @} * diff --git a/src/cli/README_SRP_CLIENT.md b/src/cli/README_SRP_CLIENT.md index 0baa1f561..913279f29 100644 --- a/src/cli/README_SRP_CLIENT.md +++ b/src/cli/README_SRP_CLIENT.md @@ -328,6 +328,33 @@ Remove a service with a give instance name and service name. Done ``` +### service key + +Usage `srp client service key [enable|disable]` + +Enable/Disable "service key record inclusion" mode in SRP client. This command requires `OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE` feature to be enabled. + +KEY record is optional in Service Description Instruction (it is required and always included in the Host Description Instruction). The default behavior of SRP client is to not include it. This command is intended to override the default behavior for testing only (in a `REFERENCE_DEVICE` build). + +Get the current "service key record inclusion" mode. + +```bash +> srp client service key +Disabled +Done +``` + +Set the "service key record inclusion" mode. + +```bash +> srp client service key enable +Done + +> srp client service key +Enabled +Done +``` + ### start Usage: `srp client start ` diff --git a/src/cli/cli_srp_client.cpp b/src/cli/cli_srp_client.cpp index 4b9114c67..c50799da2 100644 --- a/src/cli/cli_srp_client.cpp +++ b/src/cli/cli_srp_client.cpp @@ -383,6 +383,37 @@ otError SrpClient::ProcessService(uint8_t aArgsLength, char *aArgs[]) error = otSrpClientRemoveService(mInterpreter.mInstance, const_cast(service)); } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + else if (strcmp(aArgs[0], "key") == 0) + { + // `key [enable/disable]` + + bool enable; + + if (aArgsLength == 1) + { + mInterpreter.OutputEnabledDisabledStatus(otSrpClientIsServiceKeyRecordEnabled(mInterpreter.mInstance)); + ExitNow(); + } + + VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS); + + if (strcmp(aArgs[1], "enable") == 0) + { + enable = true; + } + else if (strcmp(aArgs[1], "disable") == 0) + { + enable = false; + } + else + { + ExitNow(error = OT_ERROR_INVALID_COMMAND); + } + + otSrpClientSetServiceKeyRecordEnabled(mInterpreter.mInstance, enable); + } +#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE else { error = OT_ERROR_INVALID_COMMAND; diff --git a/src/core/api/srp_client_api.cpp b/src/core/api/srp_client_api.cpp index 0417d7587..45a192129 100644 --- a/src/core/api/srp_client_api.cpp +++ b/src/core/api/srp_client_api.cpp @@ -209,4 +209,20 @@ const char *otSrpClientItemStateToString(otSrpClientItemState aItemState) return Srp::Client::ItemStateToString(static_cast(aItemState)); } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +void otSrpClientSetServiceKeyRecordEnabled(otInstance *aInstance, bool aEnabled) +{ + Instance &instance = *static_cast(aInstance); + + instance.Get().SetServiceKeyRecordEnabled(aEnabled); +} + +bool otSrpClientIsServiceKeyRecordEnabled(otInstance *aInstance) +{ + Instance &instance = *static_cast(aInstance); + + return instance.Get().IsServiceKeyRecordEnabled(); +} +#endif + #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 27f69aaf3..235a24cbd 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -140,6 +140,9 @@ Client::Client(Instance &aInstance) #if OPENTHREAD_CONFIG_SRP_CLIENT_AUTO_START_API_ENABLE , mAutoStartModeEnabled(kAutoStartDefaultMode) , mAutoStartDidSelectServer(false) +#endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + , mServiceKeyRecordEnabled(false) #endif , mUpdateMessageId(0) , mRetryWaitInterval(kMinRetryWaitInterval) @@ -810,16 +813,26 @@ Error Client::AppendServiceInstructions(Service &aService, Message &aMessage, In UpdateRecordLengthInMessage(rr, offset, aMessage); aInfo.mRecordCount++; +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + if (mServiceKeyRecordEnabled) + { + // KEY RR is optional in "Service Description Instruction". It + // is added here under `REFERENCE_DEVICE` config and is intended + // for testing only. + + SuccessOrExit(error = Dns::Name::AppendPointerLabel(instanceNameOffset, aMessage)); + SuccessOrExit(error = AppendKeyRecord(aMessage, aInfo)); + } +#endif + exit: return error; } Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const { - Error error = kErrorNone; - Dns::ResourceRecord rr; - Dns::KeyRecord key; - Crypto::Ecdsa::P256::PublicKey publicKey; + Error error = kErrorNone; + Dns::ResourceRecord rr; //---------------------------------- // Host Description Instruction @@ -847,6 +860,18 @@ Error Client::AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) c // KEY RR SuccessOrExit(error = AppendHostName(aMessage, aInfo)); + SuccessOrExit(error = AppendKeyRecord(aMessage, aInfo)); + +exit: + return error; +} + +Error Client::AppendKeyRecord(Message &aMessage, Info &aInfo) const +{ + Error error; + Dns::KeyRecord key; + Crypto::Ecdsa::P256::PublicKey publicKey; + key.Init(); key.SetTtl(mLeaseInterval); key.SetFlags(Dns::KeyRecord::kAuthConfidPermitted, Dns::KeyRecord::kOwnerNonZone, diff --git a/src/core/net/srp_client.hpp b/src/core/net/srp_client.hpp index 939558ac5..070513df7 100644 --- a/src/core/net/srp_client.hpp +++ b/src/core/net/srp_client.hpp @@ -572,6 +572,31 @@ public: */ static const char *ItemStateToString(ItemState aState); +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + /** + * This method enables/disables "service key record inclusion" mode. + * + * When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages + * that it sends. + * + * @note KEY record is optional in Service Description Instruction (it is required and always included in the Host + * Description Instruction). The default behavior of SRP client is to not include it. This method is added under + * `REFERENCE_DEVICE` config and is intended to override the default behavior for testing only. + * + * @param[in] aEnabled TRUE to enable, FALSE to disable the "service key record inclusion" mode. + * + */ + void SetServiceKeyRecordEnabled(bool aEnabled) { mServiceKeyRecordEnabled = aEnabled; } + + /** + * This method indicates whether the "service key record inclusion" mode is enabled or disabled. + * + * @returns TRUE if "service key record inclusion" mode is enabled, FALSE otherwise. + * + */ + bool IsServiceKeyRecordEnabled(void) const { return mServiceKeyRecordEnabled; } +#endif // OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + private: enum : uint8_t { @@ -726,6 +751,7 @@ private: Error ReadOrGenerateKey(Crypto::Ecdsa::P256::KeyPair &aKeyPair); Error AppendServiceInstructions(Service &aService, Message &aMessage, Info &aInfo); Error AppendHostDescriptionInstruction(Message &aMessage, Info &aInfo) const; + Error AppendKeyRecord(Message &aMessage, Info &aInfo) const; Error AppendDeleteAllRrsets(Message &aMessage) const; Error AppendHostName(Message &aMessage, Info &aInfo, bool aDoNotCompress = false) const; Error AppendUpdateLeaseOptRecord(Message &aMessage) const; @@ -767,6 +793,9 @@ private: bool mAutoStartModeEnabled : 1; bool mAutoStartDidSelectServer : 1; #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + bool mServiceKeyRecordEnabled : 1; +#endif uint16_t mUpdateMessageId; uint32_t mRetryWaitInterval; diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index 9181e6e74..f14652cc0 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1412,6 +1412,7 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) SPINEL_PROP_CSTR(SRP_CLIENT_HOST_SERVICES_REMOVE), SPINEL_PROP_CSTR(SRP_CLIENT_HOST_SERVICES_CLEAR), SPINEL_PROP_CSTR(SRP_CLIENT_EVENT), + SPINEL_PROP_CSTR(SRP_CLIENT_SERVICE_KEY_ENABLED), SPINEL_PROP_CSTR(SERVER_ALLOW_LOCAL_DATA_CHANGE), SPINEL_PROP_CSTR(SERVER_SERVICES), SPINEL_PROP_CSTR(SERVER_LEADER_SERVICES), @@ -1615,6 +1616,8 @@ const char *spinel_capability_to_cstr(spinel_capability_t capability) SPINEL_CAP_CSTR(MAC_RETRY_HISTOGRAM), SPINEL_CAP_CSTR(MULTI_RADIO), SPINEL_CAP_CSTR(SRP_CLIENT), + SPINEL_CAP_CSTR(DUA), + SPINEL_CAP_CSTR(REFERENCE_DEVICE), SPINEL_CAP_CSTR(ERROR_RATE_TRACKING), SPINEL_CAP_CSTR(THREAD_COMMISSIONER), SPINEL_CAP_CSTR(THREAD_TMF_PROXY), diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 3658e3e5d..db1b6169e 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -1205,6 +1205,7 @@ enum SPINEL_CAP_MULTI_RADIO = (SPINEL_CAP_OPENTHREAD__BEGIN + 13), SPINEL_CAP_SRP_CLIENT = (SPINEL_CAP_OPENTHREAD__BEGIN + 14), SPINEL_CAP_DUA = (SPINEL_CAP_OPENTHREAD__BEGIN + 15), + SPINEL_CAP_REFERENCE_DEVICE = (SPINEL_CAP_OPENTHREAD__BEGIN + 16), SPINEL_CAP_OPENTHREAD__END = 640, SPINEL_CAP_THREAD__BEGIN = 1024, @@ -3979,6 +3980,22 @@ enum */ SPINEL_PROP_SRP_CLIENT_EVENT = SPINEL_PROP_OPENTHREAD__BEGIN + 26, + /// SRP Client Service Key Inclusion Enabled + /** Format `b` : Read-Write + * Required capability: `SPINEL_CAP_SRP_CLIENT` & `SPINEL_CAP_REFERENCE_DEVICE`. + * + * This boolean property indicates whether the "service key record inclusion" mode is enabled or not. + * + * When enabled, SRP client will include KEY record in Service Description Instructions in the SRP update messages + * that it sends. + * + * KEY record is optional in Service Description Instruction (it is required and always included in the Host + * Description Instruction). The default behavior of SRP client is to not include it. This function is intended to + * override the default behavior for testing only. + * + */ + SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED = SPINEL_PROP_OPENTHREAD__BEGIN + 27, + SPINEL_PROP_OPENTHREAD__END = 0x2000, SPINEL_PROP_SERVER__BEGIN = 0xA0, diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index fd4a0d7e3..a03d4519f 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -1930,6 +1930,10 @@ template <> otError NcpBase::HandlePropertyGet(void) SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_DUA)); #endif +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_REFERENCE_DEVICE)); +#endif + #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_BACKBONE_ROUTER)); #endif diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 313a6a3bc..8a583e794 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -359,6 +359,9 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_HOST_NAME), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_SERVICES), +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED), +#endif #endif #if OPENTHREAD_CONFIG_LEGACY_ENABLE @@ -604,6 +607,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_HOST_ADDRESSES), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_REMOVE), OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_HOST_SERVICES_CLEAR), +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_SRP_CLIENT_SERVICE_KEY_ENABLED), +#endif #endif #if OPENTHREAD_CONFIG_LEGACY_ENABLE OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_NEST_LEGACY_ULA_PREFIX), diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 7f200e854..b4ff507a1 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -3833,6 +3833,25 @@ exit: } } +#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteBool(otSrpClientIsServiceKeyRecordEnabled(mInstance)); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + bool enabled; + + SuccessOrExit(error = mDecoder.ReadBool(enabled)); + otSrpClientSetServiceKeyRecordEnabled(mInstance, enabled); + +exit: + return error; +} +#endif + #endif // OPENTHREAD_CONFIG_SRP_CLIENT_ENABLE #if OPENTHREAD_CONFIG_LEGACY_ENABLE