/* * Copyright (c)2013-2021 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: 2026-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 "Constants.hpp" #include "Containers.hpp" #include "Dictionary.hpp" #include "Endpoint.hpp" #include "FCV.hpp" #include "Identity.hpp" #include "SharedPtr.hpp" #include "TriviallyCopyable.hpp" /** * Maximum size of endpoint attributes dictionary plus one byte for size. * * This cannot be (easily) changed. */ #define ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE 256 /** * Maximum number of endpoints, which can be increased. */ #define ZT_LOCATOR_MAX_ENDPOINTS 16 #define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + ZT_ADDRESS_LENGTH + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * (ZT_ENDPOINT_MARSHAL_SIZE_MAX + ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE)) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) /** * Maximum size of a string format Locator (this is way larger than needed) */ #define ZT_LOCATOR_STRING_SIZE_MAX 16384 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 { friend class SharedPtr; friend class SharedPtr; public: /** * Attributes of an endpoint in this locator * * This is specified for future use, but there are currently no attributes * defined. A Dictionary is used for serialization for extensibility. */ struct EndpointAttributes { friend class SharedPtr; friend class SharedPtr; /** * Default endpoint attributes */ static const SharedPtr DEFAULT; /** * Raw attributes data in the form of a dictionary prefixed by its size. * * The maximum size of attributes is 255, which is more than enough for * tiny things like bandwidth and priority. */ uint8_t data[ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE]; ZT_INLINE EndpointAttributes() noexcept { Utils::zero(data); } ZT_INLINE bool operator==(const EndpointAttributes &a) const noexcept { return ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) == 0)); } ZT_INLINE bool operator<(const EndpointAttributes &a) const noexcept { return ((data[0] < a.data[0]) || ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) < 0))); } ZT_INLINE bool operator!=(const EndpointAttributes &a) const noexcept { return !(*this == a); } ZT_INLINE bool operator>(const EndpointAttributes &a) const noexcept { return (a < *this); } ZT_INLINE bool operator<=(const EndpointAttributes &a) const noexcept { return !(a < *this); } ZT_INLINE bool operator>=(const EndpointAttributes &a) const noexcept { return !(*this < a); } private: std::atomic __refCount; }; ZT_INLINE Locator() noexcept : m_revision(0) {} ZT_INLINE Locator(const Locator &l) noexcept : m_revision(l.m_revision), m_signer(l.m_signer), m_endpoints(l.m_endpoints), m_signature(l.m_signature), __refCount(0) {} explicit Locator(const char *const str) noexcept; static ZT_INLINE Locator *from(ZT_Locator *const loc) noexcept { return reinterpret_cast(loc); } static ZT_INLINE const Locator *from(const ZT_Locator *const loc) noexcept { return reinterpret_cast(loc); } /** * @return Timestamp (a.k.a. revision number) set by Location signer */ ZT_INLINE int64_t revision() const noexcept { return m_revision; } /** * @return ZeroTier address of signer */ ZT_INLINE Address signer() const noexcept { return m_signer; } /** * @return Endpoints specified in locator */ ZT_INLINE const Vector>> &endpoints() const noexcept { return m_endpoints; } /** * @return Signature data */ ZT_INLINE const FCV &signature() const noexcept { return m_signature; } /** * 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 * @param a Endpoint attributes or NULL to use default * @return True if endpoint was added (or already present), false if locator is full */ bool add(const Endpoint &ep, const SharedPtr &a); /** * 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 rev, 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; /** * Convert this locator to a string * * @param s String buffer * @return Pointer to buffer */ char *toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept; ZT_INLINE String toString() const { char tmp[ZT_LOCATOR_STRING_SIZE_MAX]; return String(toString(tmp)); } /** * Decode a string format locator * * @param s Locator from toString() * @return True if format was valid */ bool fromString(const char *s) noexcept; explicit ZT_INLINE operator bool() const noexcept { return m_revision > 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 *data, int len) noexcept; ZT_INLINE bool operator==(const Locator &l) const noexcept { const unsigned long es = (unsigned long)m_endpoints.size(); if ((m_revision == l.m_revision) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size()) && (m_signature == l.m_signature)) { for (unsigned long i = 0; i < es; ++i) { if (m_endpoints[i].first != l.m_endpoints[i].first) return false; if (!m_endpoints[i].second) { if (l.m_endpoints[i].second) return false; } else { if ((!l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second))) return false; } } return true; } return false; } ZT_INLINE bool operator!=(const Locator &l) const noexcept { return !(*this == l); } private: void m_sortEndpoints() noexcept; int64_t m_revision; Address m_signer; Vector>> m_endpoints; FCV m_signature; std::atomic __refCount; }; } // namespace ZeroTier #endif