[srp-server] implement TTL processing (#7738)

This commit is contained in:
Jonathan Hui
2022-05-31 22:01:27 -07:00
committed by GitHub
parent 11eb753484
commit 33cc75ed3b
12 changed files with 399 additions and 14 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (214)
#define OPENTHREAD_API_VERSION (215)
/**
* @addtogroup api-instance
+44
View File
@@ -155,6 +155,16 @@ typedef enum otSrpServerAddressMode
OT_SRP_SERVER_ADDRESS_MODE_ANYCAST = 1, ///< Anycast address mode.
} otSrpServerAddressMode;
/**
* This structure includes SRP server TTL configurations.
*
*/
typedef struct otSrpServerTtlConfig
{
uint32_t mMinTtl; ///< The minimum TTL in seconds.
uint32_t mMaxTtl; ///< The maximum TTL in seconds.
} otSrpServerTtlConfig;
/**
* This structure includes SRP server LEASE and KEY-LEASE configurations.
*
@@ -298,6 +308,30 @@ otError otSrpServerSetAnycastModeSequenceNumber(otInstance *aInstance, uint8_t a
*/
void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled);
/**
* This function returns SRP server TTL configuration.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[out] aTtlConfig A pointer to an `otSrpServerTtlConfig` instance.
*
*/
void otSrpServerGetTtlConfig(otInstance *aInstance, otSrpServerTtlConfig *aTtlConfig);
/**
* This function sets SRP server TTL configuration.
*
* The granted TTL will always be no greater than the max lease interval configured via `otSrpServerSetLeaseConfig()`,
* regardless of the minimum and maximum TTL configuration.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aTtlConfig A pointer to an `otSrpServerTtlConfig` instance.
*
* @retval OT_ERROR_NONE Successfully set the TTL configuration.
* @retval OT_ERROR_INVALID_ARGS The TTL configuration is not valid.
*
*/
otError otSrpServerSetTtlConfig(otInstance *aInstance, const otSrpServerTtlConfig *aTtlConfig);
/**
* This function returns SRP server LEASE and KEY-LEASE configurations.
*
@@ -617,6 +651,16 @@ uint16_t otSrpServerServiceGetWeight(const otSrpServerService *aService);
*/
uint16_t otSrpServerServiceGetPriority(const otSrpServerService *aService);
/**
* This function returns the TTL of the service instance.
*
* @param[in] aService A pointer to the SRP service.
*
* @returns The TTL of the service instance..
*
*/
uint32_t otSrpServerServiceGetTtl(const otSrpServerService *aService);
/**
* This function returns the TXT record data of the service instance.
*
+25
View File
@@ -149,6 +149,30 @@ otError SrpServer::ProcessDisable(Arg aArgs[])
return OT_ERROR_NONE;
}
otError SrpServer::ProcessTtl(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
otSrpServerTtlConfig ttlConfig;
if (aArgs[0].IsEmpty())
{
otSrpServerGetTtlConfig(GetInstancePtr(), &ttlConfig);
OutputLine("min ttl: %u", ttlConfig.mMinTtl);
OutputLine("max ttl: %u", ttlConfig.mMaxTtl);
}
else
{
SuccessOrExit(error = aArgs[0].ParseAsUint32(ttlConfig.mMinTtl));
SuccessOrExit(error = aArgs[1].ParseAsUint32(ttlConfig.mMaxTtl));
VerifyOrExit(aArgs[2].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
error = otSrpServerSetTtlConfig(GetInstancePtr(), &ttlConfig);
}
exit:
return error;
}
otError SrpServer::ProcessLease(Arg aArgs[])
{
otError error = OT_ERROR_NONE;
@@ -289,6 +313,7 @@ otError SrpServer::ProcessService(Arg aArgs[])
OutputLine(kIndentSize, "port: %hu", otSrpServerServiceGetPort(service));
OutputLine(kIndentSize, "priority: %hu", otSrpServerServiceGetPriority(service));
OutputLine(kIndentSize, "weight: %hu", otSrpServerServiceGetWeight(service));
OutputLine(kIndentSize, "ttl: %hu", otSrpServerServiceGetTtl(service));
txtData = otSrpServerServiceGetTxtData(service, &txtDataLength);
OutputFormat(kIndentSize, "TXT: ");
+2
View File
@@ -90,6 +90,7 @@ private:
otError ProcessHost(Arg aArgs[]);
otError ProcessService(Arg aArgs[]);
otError ProcessSeqNum(Arg aArgs[]);
otError ProcessTtl(Arg aArgs[]);
otError ProcessHelp(Arg aArgs[]);
void OutputHostAddresses(const otSrpServerHost *aHost);
@@ -100,6 +101,7 @@ private:
{"help", &SrpServer::ProcessHelp}, {"host", &SrpServer::ProcessHost},
{"lease", &SrpServer::ProcessLease}, {"seqnum", &SrpServer::ProcessSeqNum},
{"service", &SrpServer::ProcessService}, {"state", &SrpServer::ProcessState},
{"ttl", &SrpServer::ProcessTtl},
};
static_assert(BinarySearch::IsSorted(sCommands), "Command Table is not sorted");
+15
View File
@@ -87,6 +87,16 @@ void otSrpServerSetEnabled(otInstance *aInstance, bool aEnabled)
AsCoreType(aInstance).Get<Srp::Server>().SetEnabled(aEnabled);
}
void otSrpServerGetTtlConfig(otInstance *aInstance, otSrpServerTtlConfig *aTtlConfig)
{
AsCoreType(aInstance).Get<Srp::Server>().GetTtlConfig(AsCoreType(aTtlConfig));
}
otError otSrpServerSetTtlConfig(otInstance *aInstance, const otSrpServerTtlConfig *aTtlConfig)
{
return AsCoreType(aInstance).Get<Srp::Server>().SetTtlConfig(AsCoreType(aTtlConfig));
}
void otSrpServerGetLeaseConfig(otInstance *aInstance, otSrpServerLeaseConfig *aLeaseConfig)
{
AsCoreType(aInstance).Get<Srp::Server>().GetLeaseConfig(AsCoreType(aLeaseConfig));
@@ -204,6 +214,11 @@ uint16_t otSrpServerServiceGetPriority(const otSrpServerService *aService)
return AsCoreType(aService).GetPriority();
}
uint32_t otSrpServerServiceGetTtl(const otSrpServerService *aService)
{
return AsCoreType(aService).GetTtl();
}
const uint8_t *otSrpServerServiceGetTxtData(const otSrpServerService *aService, uint16_t *aDataLength)
{
*aDataLength = AsCoreType(aService).GetTxtDataLength();
+75 -4
View File
@@ -168,6 +168,30 @@ exit:
return;
}
Server::TtlConfig::TtlConfig(void)
{
mMinTtl = kDefaultMinTtl;
mMaxTtl = kDefaultMaxTtl;
}
Error Server::SetTtlConfig(const TtlConfig &aTtlConfig)
{
Error error = kErrorNone;
VerifyOrExit(aTtlConfig.IsValid(), error = kErrorInvalidArgs);
mTtlConfig = aTtlConfig;
exit:
return error;
}
uint32_t Server::TtlConfig::GrantTtl(uint32_t aLease, uint32_t aTtl) const
{
OT_ASSERT(mMinTtl <= mMaxTtl);
return OT_MAX(mMinTtl, OT_MIN(OT_MIN(mMaxTtl, aLease), aTtl));
}
Server::LeaseConfig::LeaseConfig(void)
{
mMinLease = kDefaultMinLease;
@@ -266,7 +290,6 @@ void Server::AddHost(Host &aHost)
OT_ASSERT(mHosts.FindMatching(aHost.GetFullName()) == nullptr);
IgnoreError(mHosts.Add(aHost));
}
void Server::RemoveHost(Host *aHost, RetainName aRetainName, NotifyMode aNotifyServiceHandler)
{
VerifyOrExit(aHost != nullptr);
@@ -374,20 +397,21 @@ void Server::HandleServiceUpdateResult(UpdateMetadata *aUpdate, Error aError)
void Server::CommitSrpUpdate(Error aError, Host &aHost, const MessageMetadata &aMessageMetadata)
{
CommitSrpUpdate(aError, aHost, aMessageMetadata.mDnsHeader, aMessageMetadata.mMessageInfo,
aMessageMetadata.mLeaseConfig);
aMessageMetadata.mTtlConfig, aMessageMetadata.mLeaseConfig);
}
void Server::CommitSrpUpdate(Error aError, UpdateMetadata &aUpdateMetadata)
{
CommitSrpUpdate(aError, aUpdateMetadata.GetHost(), aUpdateMetadata.GetDnsHeader(),
aUpdateMetadata.IsDirectRxFromClient() ? &aUpdateMetadata.GetMessageInfo() : nullptr,
aUpdateMetadata.GetLeaseConfig());
aUpdateMetadata.GetTtlConfig(), aUpdateMetadata.GetLeaseConfig());
}
void Server::CommitSrpUpdate(Error aError,
Host & aHost,
const Dns::UpdateHeader &aDnsHeader,
const Ip6::MessageInfo * aMessageInfo,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig)
{
Host * existingHost;
@@ -395,6 +419,7 @@ void Server::CommitSrpUpdate(Error aError,
uint32_t hostKeyLease;
uint32_t grantedLease;
uint32_t grantedKeyLease;
uint32_t grantedTtl;
bool shouldFreeHost = true;
SuccessOrExit(aError);
@@ -403,14 +428,17 @@ void Server::CommitSrpUpdate(Error aError,
hostKeyLease = aHost.GetKeyLease();
grantedLease = aLeaseConfig.GrantLease(hostLease);
grantedKeyLease = aLeaseConfig.GrantKeyLease(hostKeyLease);
grantedTtl = aTtlConfig.GrantTtl(grantedLease, aHost.GetTtl());
aHost.SetLease(grantedLease);
aHost.SetKeyLease(grantedKeyLease);
aHost.SetTtl(grantedTtl);
for (Service &service : aHost.mServices)
{
service.mDescription->mLease = grantedLease;
service.mDescription->mKeyLease = grantedKeyLease;
service.mDescription->mTtl = grantedTtl;
}
existingHost = mHosts.FindMatching(aHost.GetFullName());
@@ -802,6 +830,8 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost,
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aHost.SetFullName(name));
SuccessOrExit(error = aMessage.Read(offset, aaaaRecord));
@@ -816,6 +846,9 @@ Error Server::ProcessHostDescriptionInstruction(Host & aHost,
Dns::Ecdsa256KeyRecord keyRecord;
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aMessage.Read(offset, keyRecord));
VerifyOrExit(keyRecord.IsValid(), error = kErrorParse);
@@ -908,6 +941,11 @@ Error Server::ProcessServiceDiscoveryInstructions(Host & aHost,
// This RR is a "Delete an RR from an RRset" update when the CLASS is NONE.
service->mIsDeleted = (ptrRecord.GetClass() == Dns::ResourceRecord::kClassNone);
if (!service->mIsDeleted)
{
SuccessOrExit(error = aHost.ProcessTtl(ptrRecord.GetTtl()));
}
}
exit:
@@ -959,6 +997,9 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
uint16_t hostNameLength = sizeof(hostName);
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
SuccessOrExit(error = aMessage.Read(offset, srvRecord));
offset += sizeof(srvRecord);
@@ -971,6 +1012,7 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
// Make sure that this is the first SRV RR for this service description
VerifyOrExit(desc->mPort == 0, error = kErrorFailed);
desc->mTtl = srvRecord.GetTtl();
desc->mPriority = srvRecord.GetPriority();
desc->mWeight = srvRecord.GetWeight();
desc->mPort = srvRecord.GetPort();
@@ -980,6 +1022,8 @@ Error Server::ProcessServiceDescriptionInstructions(Host & aHost,
{
VerifyOrExit(record.GetClass() == aMetadata.mDnsZone.GetClass(), error = kErrorFailed);
SuccessOrExit(error = aHost.ProcessTtl(record.GetTtl()));
desc = aHost.FindServiceDescription(name);
VerifyOrExit(desc != nullptr, error = kErrorFailed);
@@ -1324,11 +1368,12 @@ void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessag
Error Server::ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
return ProcessMessage(aMessage, TimerMilli::GetNow(), mLeaseConfig, &aMessageInfo);
return ProcessMessage(aMessage, TimerMilli::GetNow(), mTtlConfig, mLeaseConfig, &aMessageInfo);
}
Error Server::ProcessMessage(Message & aMessage,
TimeMilli aRxTime,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig,
const Ip6::MessageInfo *aMessageInfo)
{
@@ -1337,6 +1382,7 @@ Error Server::ProcessMessage(Message & aMessage,
metadata.mOffset = aMessage.GetOffset();
metadata.mRxTime = aRxTime;
metadata.mTtlConfig = aTtlConfig;
metadata.mLeaseConfig = aLeaseConfig;
metadata.mMessageInfo = aMessageInfo;
@@ -1680,6 +1726,7 @@ Error Server::Service::Description::Init(const char *aInstanceName, Host &aHost)
mHost = &aHost;
mPriority = 0;
mWeight = 0;
mTtl = 0;
mPort = 0;
mLease = 0;
mKeyLease = 0;
@@ -1708,6 +1755,7 @@ void Server::Service::Description::TakeResourcesFrom(Description &aDescription)
mWeight = aDescription.mWeight;
mPort = aDescription.mPort;
mTtl = aDescription.mTtl;
mLease = aDescription.mLease;
mKeyLease = aDescription.mKeyLease;
mUpdateTime = TimerMilli::GetNow();
@@ -1736,6 +1784,7 @@ exit:
Server::Host::Host(Instance &aInstance, TimeMilli aUpdateTime)
: InstanceLocator(aInstance)
, mNext(nullptr)
, mTtl(0)
, mLease(0)
, mKeyLease(0)
, mUpdateTime(aUpdateTime)
@@ -1804,6 +1853,26 @@ void Server::Host::GetLeaseInfo(LeaseInfo &aLeaseInfo) const
aLeaseInfo.mRemainingKeyLease = (now <= keyExpireTime) ? (keyExpireTime - now) : 0;
}
Error Server::Host::ProcessTtl(uint32_t aTtl)
{
// This method processes the TTL value received in a resource record.
//
// If no TTL value is stored, this method wil set the stored value to @p aTtl and return `kErrorNone`.
// If a TTL value is stored and @p aTtl equals the stored value, this method returns `kErrorNone`.
// Otherwise, this method returns `kErrorRejected`.
Error error = kErrorRejected;
VerifyOrExit(aTtl && (mTtl == 0 || mTtl == aTtl));
mTtl = aTtl;
error = kErrorNone;
exit:
return error;
}
const Server::Service *Server::Host::FindNextService(const Service *aPrevService,
Service::Flags aFlags,
const char * aServiceName,
@@ -1915,6 +1984,7 @@ Error Server::Host::MergeServicesAndResourcesFrom(Host &aHost)
mAddresses.TakeFrom(static_cast<Heap::Array<Ip6::Address> &&>(aHost.mAddresses));
mKeyRecord = aHost.mKeyRecord;
mTtl = aHost.mTtl;
mLease = aHost.mLease;
mKeyLease = aHost.mKeyLease;
mUpdateTime = TimerMilli::GetNow();
@@ -2028,6 +2098,7 @@ Server::UpdateMetadata::UpdateMetadata(Instance &aInstance, Host &aHost, const M
, mExpireTime(TimerMilli::GetNow() + kDefaultEventsHandlerTimeout)
, mDnsHeader(aMessageMetadata.mDnsHeader)
, mId(Get<Server>().AllocateId())
, mTtlConfig(aMessageMetadata.mTtlConfig)
, mLeaseConfig(aMessageMetadata.mLeaseConfig)
, mHost(aHost)
, mIsDirectRxFromClient(aMessageMetadata.IsDirectRxFromClient())
+73 -4
View File
@@ -259,6 +259,14 @@ public:
*/
Error GetServiceSubTypeLabel(char *aLabel, uint8_t aMaxSize) const;
/**
* This method returns the TTL of the service instance.
*
* @returns The TTL of the service instance.
*
*/
uint32_t GetTtl(void) const { return mDescription->mTtl; }
/**
* This method returns the port of the service instance.
*
@@ -390,6 +398,7 @@ public:
uint16_t mPriority;
uint16_t mWeight;
uint16_t mPort;
uint32_t mTtl; // The TTL in seconds.
uint32_t mLease; // The LEASE time in seconds.
uint32_t mKeyLease; // The KEY-LEASE time in seconds.
TimeMilli mUpdateTime;
@@ -467,6 +476,14 @@ public:
return mAddresses.AsCArray();
}
/**
* This method returns the TTL of the host.
*
* @returns The TTL of the host.
*
*/
uint32_t GetTtl(void) const { return mTtl; }
/**
* This method returns the LEASE time of the host.
*
@@ -555,10 +572,13 @@ public:
Host(Instance &aInstance, TimeMilli aUpdateTime);
~Host(void);
Error SetFullName(const char *aFullName);
void SetKeyRecord(Dns::Ecdsa256KeyRecord &aKeyRecord);
void SetLease(uint32_t aLease) { mLease = aLease; }
void SetKeyLease(uint32_t aKeyLease) { mKeyLease = aKeyLease; }
Error SetFullName(const char *aFullName);
void SetKeyRecord(Dns::Ecdsa256KeyRecord &aKeyRecord);
void SetTtl(uint32_t aTtl) { mTtl = aTtl; }
void SetLease(uint32_t aLease) { mLease = aLease; }
void SetKeyLease(uint32_t aKeyLease) { mKeyLease = aKeyLease; }
Error ProcessTtl(uint32_t aTtl);
LinkedList<Service> &GetServices(void) { return mServices; }
Service * AddNewService(const char *aServiceName,
const char *aInstanceName,
@@ -582,12 +602,33 @@ public:
// TODO(wgtdkp): there is no necessary to save the entire resource
// record, saving only the ECDSA-256 public key should be enough.
Dns::Ecdsa256KeyRecord mKeyRecord;
uint32_t mTtl; // The TTL in seconds.
uint32_t mLease; // The LEASE time in seconds.
uint32_t mKeyLease; // The KEY-LEASE time in seconds.
TimeMilli mUpdateTime;
LinkedList<Service> mServices;
};
/**
* This class handles TTL configuration.
*
*/
class TtlConfig : public otSrpServerTtlConfig
{
friend class Server;
public:
/**
* This constructor initializes to default TTL configuration.
*
*/
TtlConfig(void);
private:
bool IsValid(void) const { return mMinTtl <= mMaxTtl; }
uint32_t GrantTtl(uint32_t aLease, uint32_t aTtl) const;
};
/**
* This class handles LEASE and KEY-LEASE configurations.
*
@@ -760,6 +801,25 @@ public:
*/
void SetEnabled(bool aEnabled);
/**
* This method returns the TTL configuration.
*
* @param[out] aTtlConfig A reference to the `TtlConfig` instance.
*
*/
void GetTtlConfig(TtlConfig &aTtlConfig) const { aTtlConfig = mTtlConfig; }
/**
* This method sets the TTL configuration.
*
* @param[in] aTtlConfig A reference to the `TtlConfig` instance.
*
* @retval kErrorNone Successfully set the TTL configuration
* @retval kErrorInvalidArgs The TTL range is not valid.
*
*/
Error SetTtlConfig(const TtlConfig &aTtlConfig);
/**
* This method returns the LEASE and KEY-LEASE configurations.
*
@@ -814,6 +874,8 @@ public:
private:
static constexpr uint16_t kUdpPayloadSize = Ip6::kMaxDatagramLength - sizeof(Ip6::Udp::Header);
static constexpr uint32_t kDefaultMinTtl = 60u; // 1 min (in seconds).
static constexpr uint32_t kDefaultMaxTtl = 3600u * 2; // 2 hours (in seconds).
static constexpr uint32_t kDefaultMinLease = 60u * 30; // 30 min (in seconds).
static constexpr uint32_t kDefaultMaxLease = 3600u * 2; // 2 hours (in seconds).
static constexpr uint32_t kDefaultMinKeyLease = 3600u * 24; // 1 day (in seconds).
@@ -836,6 +898,7 @@ private:
Dns::Zone mDnsZone;
uint16_t mOffset;
TimeMilli mRxTime;
TtlConfig mTtlConfig;
LeaseConfig mLeaseConfig;
const Ip6::MessageInfo *mMessageInfo; // Set to `nullptr` when from SRPL.
};
@@ -853,6 +916,7 @@ private:
TimeMilli GetExpireTime(void) const { return mExpireTime; }
const Dns::UpdateHeader &GetDnsHeader(void) const { return mDnsHeader; }
ServiceUpdateId GetId(void) const { return mId; }
const TtlConfig & GetTtlConfig(void) const { return mTtlConfig; }
const LeaseConfig & GetLeaseConfig(void) const { return mLeaseConfig; }
Host & GetHost(void) { return mHost; }
const Ip6::MessageInfo & GetMessageInfo(void) const { return mMessageInfo; }
@@ -866,6 +930,7 @@ private:
TimeMilli mExpireTime;
Dns::UpdateHeader mDnsHeader;
ServiceUpdateId mId; // The ID of this service update transaction.
TtlConfig mTtlConfig; // TTL config to use when processing the message.
LeaseConfig mLeaseConfig; // Lease config to use when processing the message.
Host & mHost; // The `UpdateMetadata` has no ownership of this host.
Ip6::MessageInfo mMessageInfo; // Valid when `mIsDirectRxFromClient` is true.
@@ -894,10 +959,12 @@ private:
Host & aHost,
const Dns::UpdateHeader &aDnsHeader,
const Ip6::MessageInfo * aMessageInfo,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig);
Error ProcessMessage(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
Error ProcessMessage(Message & aMessage,
TimeMilli aRxTime,
const TtlConfig & aTtlConfig,
const LeaseConfig & aLeaseConfig,
const Ip6::MessageInfo *aMessageInfo);
void ProcessDnsUpdate(Message &aMessage, MessageMetadata &aMetadata);
@@ -951,6 +1018,7 @@ private:
Heap::String mDomain;
TtlConfig mTtlConfig;
LeaseConfig mLeaseConfig;
LinkedList<Host> mHosts;
@@ -971,6 +1039,7 @@ private:
} // namespace Srp
DefineCoreType(otSrpServerTtlConfig, Srp::Server::TtlConfig);
DefineCoreType(otSrpServerLeaseConfig, Srp::Server::LeaseConfig);
DefineCoreType(otSrpServerHost, Srp::Server::Host);
DefineCoreType(otSrpServerService, Srp::Server::Service);
+2
View File
@@ -196,6 +196,7 @@ EXTRA_DIST = \
test_srp_server_anycast_mode.py \
test_srp_server_reboot_port.py \
test_srp_sub_type.py \
test_srp_ttl.py \
test_zero_len_external_route.py \
thread_cert.py \
tlvs_parsing.py \
@@ -270,6 +271,7 @@ check_SCRIPTS = \
test_srp_server_anycast_mode.py \
test_srp_server_reboot_port.py \
test_srp_sub_type.py \
test_srp_ttl.py \
test_zero_len_external_route.py \
Cert_5_1_01_RouterAttach.py \
Cert_5_1_02_ChildAddressTimeout.py \
+7 -2
View File
@@ -929,6 +929,10 @@ class NodeImpl:
self.send_command(f'srp server lease {min_lease} {max_lease} {min_key_lease} {max_key_lease}')
self._expect_done()
def srp_server_set_ttl_range(self, min_ttl, max_ttl):
self.send_command(f'srp server ttl {min_ttl} {max_ttl}')
self._expect_done()
def srp_server_get_hosts(self):
"""Returns the host list on the SRP server as a list of property
dictionary.
@@ -989,6 +993,7 @@ class NodeImpl:
'port': '12345',
'priority': '0',
'weight': '0',
'ttl': '7200',
'TXT': ['abc=010203'],
'host_fullname': 'my-host.default.service.arpa.',
'host': 'my-host',
@@ -1015,8 +1020,8 @@ class NodeImpl:
service_list.append(service)
continue
# 'subtypes', port', 'priority', 'weight'
for i in range(0, 4):
# 'subtypes', port', 'priority', 'weight', 'ttl'
for i in range(0, 5):
key_value = lines.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
+151
View File
@@ -0,0 +1,151 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
import ipaddress
import unittest
import command
import config
import thread_cert
# Test description:
# This test verifies the SRP server and client properly handle SRP host
# and service instance TTLs.
#
# Topology:
# LEADER (SRP server)
# |
# |
# ROUTER (SRP client)
#
SERVER = 1
CLIENT = 2
KEY_LEASE = 240 # Seconds
class SrpTtl(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
SERVER: {
'name': 'SRP_SERVER',
'mode': 'rdn',
},
CLIENT: {
'name': 'SRP_CLIENT',
'mode': 'rdn',
},
}
def test(self):
server = self.nodes[SERVER]
client = self.nodes[CLIENT]
#
# Start the server and client devices.
#
server.srp_server_set_enabled(True)
server.srp_server_set_lease_range(120, 240, KEY_LEASE, KEY_LEASE)
server.start()
self.simulator.go(5)
self.assertEqual(server.get_state(), 'leader')
self.simulator.go(5)
client.srp_server_set_enabled(False)
client.start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(client.get_state(), 'router')
client.srp_client_set_host_name('my-host')
client.srp_client_set_host_address('2001::1')
client.srp_client_start(server.get_addrs()[0], client.get_srp_server_port())
client.srp_client_add_service('my-service', '_ipps._tcp', 12345)
self.simulator.go(2)
#
# CLIENT_TTL < TTL_MIN < LEASE_MAX ==> TTL_MIN
#
client.srp_client_set_ttl(100)
server.srp_server_set_ttl_range(120, 240)
server.srp_server_set_lease_range(120, 240, KEY_LEASE, KEY_LEASE)
self.simulator.go(KEY_LEASE)
self.check_ttl(120)
#
# TTL_MIN < CLIENT_TTL < TTL_MAX < LEASE_MAX ==> CLIENT_TTL
#
client.srp_client_set_ttl(100)
server.srp_server_set_ttl_range(60, 120)
server.srp_server_set_lease_range(120, 240, KEY_LEASE, KEY_LEASE)
self.simulator.go(KEY_LEASE)
self.check_ttl(100)
#
# TTL_MAX < LEASE_MAX < CLIENT_TTL ==> TTL_MAX
#
client.srp_client_set_ttl(240)
server.srp_server_set_ttl_range(60, 120)
server.srp_server_set_lease_range(120, 240, KEY_LEASE, KEY_LEASE)
self.simulator.go(KEY_LEASE)
self.check_ttl(120)
#
# LEASE_MAX < TTL_MAX < CLIENT_TTL ==> LEASE_MAX
#
client.srp_client_set_ttl(240)
server.srp_server_set_ttl_range(60, 120)
server.srp_server_set_lease_range(30, 60, KEY_LEASE, KEY_LEASE)
self.simulator.go(KEY_LEASE)
self.check_ttl(60)
def check_ttl(self, ttl):
"""Check that we have properly registered host and service instance.
"""
server = self.nodes[SERVER]
server_services = server.srp_server_get_services()
print(server_services)
self.assertEqual(len(server_services), 1)
server_service = server_services[0]
# Verify that the server accepted the SRP registration and stored
# the same service resources.
self.assertEqual(int(server_service['ttl']), ttl)
if __name__ == '__main__':
unittest.main()
+3 -2
View File
@@ -458,6 +458,7 @@ class Node(object):
'port': '12345',
'priority': '0',
'weight': '0',
'ttl': '7200',
'TXT': ['abc=010203'],
'host_fullname': 'my-host.default.service.arpa.',
'host': 'my-host',
@@ -478,8 +479,8 @@ class Node(object):
if service['deleted'] == 'true':
service_list.append(service)
continue
# 'subtypes', port', 'priority', 'weight'
for i in range(0, 4):
# 'subtypes', port', 'priority', 'weight', 'ttl'
for i in range(0, 5):
key_value = outputs.pop(0).strip().split(':')
service[key_value[0].strip()] = key_value[1].strip()
txt_entries = outputs.pop(0).strip().split('[')[1].strip(' ]').split(',')
+1 -1
View File
@@ -976,7 +976,7 @@ class OTCI(object):
info['addresses'] = list(map(Ip6Addr, v.split(', ')))
elif k == 'subtypes':
info[k] = list() if v == '(null)' else list(v.split(','))
elif k in ('port', 'weight', 'priority'):
elif k in ('port', 'weight', 'priority', 'ttl'):
info[k] = int(v)
elif k in ('host',):
info[k] = v