mirror of
https://github.com/espressif/openthread.git
synced 2026-07-31 16:17:47 +00:00
[srp-server] implement TTL processing (#7738)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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: ");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Executable
+151
@@ -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()
|
||||
@@ -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(',')
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user