/* * Copyright (c)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2024-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ /****/ #ifndef ZT_LOCATOR_HPP #define ZT_LOCATOR_HPP #include #include #include #include "Constants.hpp" #include "Endpoint.hpp" #include "Identity.hpp" #include "TriviallyCopyable.hpp" #define ZT_LOCATOR_MAX_ENDPOINTS 8 #define ZT_LOCATOR_MARSHAL_SIZE_MAX (1 + 8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) namespace ZeroTier { /** * Signed information about a node's location on the network * * A locator contains long-lived endpoints for a node such as IP/port pairs, * URLs, or other nodes, and is signed by the node it describes. */ class Locator : public TriviallyCopyable { public: ZT_INLINE Locator() noexcept { memoryZero(this); } /** * Zero the Locator data structure */ ZT_INLINE void clear() noexcept { memoryZero(this); } /** * @return Timestamp (a.k.a. revision number) set by Location signer */ ZT_INLINE int64_t timestamp() const noexcept { return m_ts; } /** * @return True if locator is signed */ ZT_INLINE bool isSigned() const noexcept { return m_signatureLength > 0; } /** * @return Length of signature in bytes or 0 if none */ ZT_INLINE unsigned int signatureLength() const noexcept { return m_signatureLength; } /** * @return Pointer to signature bytes */ ZT_INLINE const uint8_t *signature() const noexcept { return m_signature; } /** * @return Number of endpoints in this locator */ ZT_INLINE unsigned int endpointCount() const noexcept { return m_endpointCount; } /** * @return Pointer to array of endpoints */ ZT_INLINE const Endpoint *endpoints() const noexcept { return m_at; } /** * Add an endpoint to this locator * * This doesn't check for the presence of the endpoint, so take * care not to add duplicates. * * @param ep Endpoint to add * @return True if endpoint was added (or already present), false if locator is full */ ZT_INLINE bool add(const Endpoint &ep) noexcept { if (m_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS) return false; m_at[m_endpointCount++] = ep; return true; } /** * Sign this locator * * This sets timestamp, sorts endpoints so that the same set of endpoints * will always produce the same locator, and signs. * * @param id Identity that includes private key * @return True if signature successful */ bool sign(int64_t ts,const Identity &id) noexcept; /** * Verify this Locator's validity and signature * * @param id Identity corresponding to hash * @return True if valid and signature checks out */ bool verify(const Identity &id) const noexcept; explicit ZT_INLINE operator bool() const noexcept { return m_ts != 0; } static constexpr int marshalSizeMax() noexcept { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const noexcept; int unmarshal(const uint8_t *restrict data,int len) noexcept; /** * Create a signed Locator and package it with the root's identity to make a root spec * * @param id Identity (must have secret) * @param ts Timestamp * @param endpoints Endpoints * @param rootSpecBuf Buffer to store identity and locator into * @param rootSpecBufSize Size of buffer * @return Bytes written to buffer or -1 on error */ static int makeRootSpecification(const Identity &id,int64_t ts,const Vector &endpoints,void *rootSpecBuf,unsigned int rootSpecBufSize); /** * Parse a root specification and decode the identity and locator * * @param rootSpec Root spec bytes * @param rootSpecSize Size in bytes * @return Identity and locator, with identity NULL if an error occurs */ static std::pair parseRootSpecification(const void *rootSpec,unsigned int rootSpecSize); private: int64_t m_ts; unsigned int m_endpointCount; unsigned int m_signatureLength; Endpoint m_at[ZT_LOCATOR_MAX_ENDPOINTS]; uint16_t m_flags; uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE]; }; } // namespace ZeroTier #endif