diff --git a/node/AES.cpp b/node/AES.cpp index 511cd246a..b2e53ed57 100644 --- a/node/AES.cpp +++ b/node/AES.cpp @@ -353,53 +353,72 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept const __m128i h = _aes._k.ni.h; y = _mm_xor_si128(y,_mm_set_epi64x(0LL,(long long)Utils::hton((uint64_t)_len << 3U))); y = _mm_shuffle_epi8(y,s_shuf); + __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast(_iv)),k[0]); + __m128i t1 = _mm_clmulepi64_si128(h,y,0x00); __m128i t2 = _mm_clmulepi64_si128(h,y,0x01); __m128i t3 = _mm_clmulepi64_si128(h,y,0x10); __m128i t4 = _mm_clmulepi64_si128(h,y,0x11); + encIV = _mm_aesenc_si128(encIV,k[1]); + encIV = _mm_aesenc_si128(encIV,k[2]); + t2 = _mm_xor_si128(t2,t3); t3 = _mm_slli_si128(t2,8); - encIV = _mm_aesenc_si128(encIV,k[2]); t2 = _mm_srli_si128(t2,8); t1 = _mm_xor_si128(t1,t3); + encIV = _mm_aesenc_si128(encIV,k[3]); + t4 = _mm_xor_si128(t4,t2); __m128i t5 = _mm_srli_epi32(t1,31); - encIV = _mm_aesenc_si128(encIV,k[4]); t1 = _mm_slli_epi32(t1,1); __m128i t6 = _mm_srli_epi32(t4,31); - encIV = _mm_aesenc_si128(encIV,k[5]); + + encIV = _mm_aesenc_si128(encIV,k[4]); + t4 = _mm_slli_epi32(t4,1); t3 = _mm_srli_si128(t5,12); - encIV = _mm_aesenc_si128(encIV,k[6]); t6 = _mm_slli_si128(t6,4); t5 = _mm_slli_si128(t5,4); - encIV = _mm_aesenc_si128(encIV,k[7]); + + encIV = _mm_aesenc_si128(encIV,k[5]); + t1 = _mm_or_si128(t1,t5); t4 = _mm_or_si128(t4,t6); - encIV = _mm_aesenc_si128(encIV,k[8]); + + encIV = _mm_aesenc_si128(encIV,k[6]); + encIV = _mm_aesenc_si128(encIV,k[7]); + t4 = _mm_or_si128(t4,t3); t5 = _mm_slli_epi32(t1,31); - encIV = _mm_aesenc_si128(encIV,k[9]); t6 = _mm_slli_epi32(t1,30); t3 = _mm_slli_epi32(t1,25); - encIV = _mm_aesenc_si128(encIV,k[10]); + + encIV = _mm_aesenc_si128(encIV,k[8]); + encIV = _mm_aesenc_si128(encIV,k[9]); + t5 = _mm_xor_si128(t5,t6); t5 = _mm_xor_si128(t5,t3); + + encIV = _mm_aesenc_si128(encIV,k[10]); encIV = _mm_aesenc_si128(encIV,k[11]); + t6 = _mm_srli_si128(t5,4); t4 = _mm_xor_si128(t4,t6); - encIV = _mm_aesenc_si128(encIV,k[12]); t5 = _mm_slli_si128(t5,12); t1 = _mm_xor_si128(t1,t5); - encIV = _mm_aesenc_si128(encIV,k[13]); + t4 = _mm_xor_si128(t4,t1); t5 = _mm_srli_epi32(t1,1); t2 = _mm_srli_epi32(t1,2); t3 = _mm_srli_epi32(t1,7); + + encIV = _mm_aesenc_si128(encIV,k[12]); + encIV = _mm_aesenc_si128(encIV,k[13]); encIV = _mm_aesenclast_si128(encIV,k[14]); + t4 = _mm_xor_si128(t4,t2); t4 = _mm_xor_si128(t4,t3); t4 = _mm_xor_si128(t4,t5); diff --git a/node/Buf.hpp b/node/Buf.hpp index b14ebaba2..fd8d3c28a 100644 --- a/node/Buf.hpp +++ b/node/Buf.hpp @@ -79,7 +79,7 @@ namespace ZeroTier { */ class Buf { - friend class SharedPtr< Buf >; + friend class SharedPtr; public: // New and delete operators that allocate Buf instances from a shared lock-free memory pool. diff --git a/node/LZ4.cpp b/node/LZ4.cpp index 6f76655f9..50532609a 100644 --- a/node/LZ4.cpp +++ b/node/LZ4.cpp @@ -750,7 +750,7 @@ FORCE_INLINE int LZ4_decompress_generic( } // anonymous namespace -int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) noexcept { #if (HEAPMODE) void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ @@ -767,7 +767,7 @@ int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutp return result; } -int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) +int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) noexcept { return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, endOnInputSize, full, 0, noDict, (BYTE*)dest, NULL, 0); } diff --git a/node/LZ4.hpp b/node/LZ4.hpp index 45db20c48..227dce627 100644 --- a/node/LZ4.hpp +++ b/node/LZ4.hpp @@ -18,8 +18,8 @@ namespace ZeroTier { -int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1); -int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize); +int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept; +int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept; } // namespace ZeroTier diff --git a/node/Locator.cpp b/node/Locator.cpp index 35577ccb4..94ad49b8c 100644 --- a/node/Locator.cpp +++ b/node/Locator.cpp @@ -15,7 +15,7 @@ namespace ZeroTier { -bool Locator::sign(const int64_t ts,const Identity &id) +bool Locator::sign(const int64_t ts,const Identity &id) noexcept { uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX]; if (!id.hasPrivate()) @@ -28,7 +28,7 @@ bool Locator::sign(const int64_t ts,const Identity &id) return (_signatureLength > 0); } -bool Locator::verify(const Identity &id) const +bool Locator::verify(const Identity &id) const noexcept { if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) return false; @@ -37,7 +37,7 @@ bool Locator::verify(const Identity &id) const return id.verify(signData,signLen,_signature,_signatureLength); } -int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const +int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const noexcept { if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) return -1; @@ -69,7 +69,7 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud return p; } -int Locator::unmarshal(const uint8_t *restrict data,const int len) +int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept { if (len <= (8 + 2 + 48)) return -1; diff --git a/node/Locator.hpp b/node/Locator.hpp index c365d06ca..8041a3338 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -37,42 +37,42 @@ namespace ZeroTier { class Locator : public TriviallyCopyable { public: - ZT_ALWAYS_INLINE Locator() { this->clear(); } + ZT_ALWAYS_INLINE Locator() noexcept { memoryZero(this); } /** * Zero the Locator data structure */ - ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast(this),0,sizeof(Locator)); } + ZT_ALWAYS_INLINE void clear() noexcept { memoryZero(this); } /** * @return Timestamp (a.k.a. revision number) set by Location signer */ - ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; } + ZT_ALWAYS_INLINE int64_t timestamp() const noexcept { return _ts; } /** * @return True if locator is signed */ - ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); } + ZT_ALWAYS_INLINE bool isSigned() const noexcept { return (_signatureLength > 0); } /** * @return Length of signature in bytes or 0 if none */ - ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; } + ZT_ALWAYS_INLINE unsigned int signatureLength() const noexcept { return _signatureLength; } /** * @return Pointer to signature bytes */ - ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; } + ZT_ALWAYS_INLINE const uint8_t *signature() const noexcept { return _signature; } /** * @return Number of endpoints in this locator */ - ZT_ALWAYS_INLINE unsigned int endpointCount() const { return _endpointCount; } + ZT_ALWAYS_INLINE unsigned int endpointCount() const noexcept { return _endpointCount; } /** * @return Pointer to array of endpoints */ - ZT_ALWAYS_INLINE const Endpoint *endpoints() const { return _at; } + ZT_ALWAYS_INLINE const Endpoint *endpoints() const noexcept { return _at; } /** * Add an endpoint to this locator @@ -83,7 +83,7 @@ public: * @param ep Endpoint to add * @return True if endpoint was added (or already present), false if locator is full */ - ZT_ALWAYS_INLINE bool add(const Endpoint &ep) + ZT_ALWAYS_INLINE bool add(const Endpoint &ep) noexcept { if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS) return false; @@ -100,7 +100,7 @@ public: * @param id Identity that includes private key * @return True if signature successful */ - bool sign(int64_t ts,const Identity &id); + bool sign(int64_t ts,const Identity &id) noexcept; /** * Verify this Locator's validity and signature @@ -108,13 +108,13 @@ public: * @param id Identity corresponding to hash * @return True if valid and signature checks out */ - bool verify(const Identity &id) const; + bool verify(const Identity &id) const noexcept; - explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); } + explicit ZT_ALWAYS_INLINE operator bool() const noexcept { return (_ts != 0); } - static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; } - int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const; - int unmarshal(const uint8_t *restrict data,int len); + 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; private: int64_t _ts; diff --git a/node/Membership.cpp b/node/Membership.cpp index f2b47e4a7..8e9831f80 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -17,7 +17,6 @@ #include "RuntimeEnvironment.hpp" #include "Peer.hpp" #include "Topology.hpp" -#include "Switch.hpp" #include "Node.hpp" namespace ZeroTier { @@ -33,6 +32,10 @@ Membership::Membership() : { } +Membership::~Membership() +{ +} + void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf) { const Capability *sendCaps[ZT_MAX_NETWORK_CAPABILITIES]; @@ -218,7 +221,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme } } -bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const +bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept { if ((ip.isV6())&&(nconf.ndpEmulation())) { const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt())); diff --git a/node/Membership.hpp b/node/Membership.hpp index 046553c4c..3d05b5cf8 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -49,6 +49,7 @@ public: }; Membership(); + ~Membership(); /** * Send COM and other credentials to this peer @@ -64,7 +65,7 @@ public: /** * @return Time we last pushed credentials to this member */ - ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const { return _lastPushedCredentials; } + ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const noexcept { return _lastPushedCredentials; } /** * Check whether the peer represented by this Membership should be allowed on this network at all @@ -72,7 +73,7 @@ public: * @param nconf Our network config * @return True if this peer is allowed on this network at all */ - ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const + ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const noexcept { if (nconf.isPublic()) return true; // public network if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked @@ -88,7 +89,7 @@ public: * @return True if this peer has a certificate of ownership for the given resource */ template - ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const + ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const noexcept { if (_isUnspoofableAddress(nconf,r)) return true; @@ -109,7 +110,7 @@ public: * @param id Tag ID * @return Pointer to tag or NULL if not found */ - ZT_ALWAYS_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const + ZT_ALWAYS_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const noexcept { const Tag *const t = _remoteTags.get(id); return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0); @@ -138,13 +139,13 @@ private: // This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to // always return true for them. A certificate is not required for these. - ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; } - bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const; + ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const noexcept { return false; } + bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept; // This compares the remote credential's timestamp to the timestamp in our network config // plus or minus the permitted maximum timestamp delta. template - ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const + ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const noexcept { const int64_t ts = remoteCredential.timestamp(); if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { @@ -190,7 +191,7 @@ public: class CapabilityIterator { public: - ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) : + ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) noexcept : _hti(m._remoteCaps), _k(nullptr), _c(nullptr), @@ -199,7 +200,7 @@ public: { } - ZT_ALWAYS_INLINE Capability *next() + ZT_ALWAYS_INLINE Capability *next() noexcept { while (_hti.next(_k,_c)) { if (_m._isCredentialTimestampValid(_nconf,*_c)) diff --git a/node/Meter.hpp b/node/Meter.hpp index bf2cf78c3..056277994 100644 --- a/node/Meter.hpp +++ b/node/Meter.hpp @@ -17,58 +17,79 @@ #include "Constants.hpp" #include "Mutex.hpp" -#define ZT_METER_HISTORY_LENGTH 4 -#define ZT_METER_HISTORY_TICK_DURATION 1000 +#include namespace ZeroTier { /** - * Transfer rate meter (thread-safe) + * Transfer rate and total transferred amount meter + * + * @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second) + * @tparam LSIZE Log size in units of time (default: 60 for one minute worth of data) */ +template class Meter { public: - ZT_ALWAYS_INLINE Meter() noexcept - { - for(int i=0;i ZT_ALWAYS_INLINE void log(const int64_t now,I count) noexcept { - const int64_t since = now - _ts; - if (since >= ZT_METER_HISTORY_TICK_DURATION) { - _ts = now; - _history[++_hptr % ZT_METER_HISTORY_LENGTH] = (double)_count / ((double)since / 1000.0); - _count = (uint64_t)count; - } else { - _count += (uint64_t)count; - } + _total += (uint64_t)count; + + // We log by choosing a log bucket based on the current time in units modulo + // the log size and then if it's a new bucket setting it or otherwise adding + // to it. + const unsigned long bucket = ((unsigned int)((uint64_t)(now / TUNIT))) % LSIZE; + const unsigned long prevBucket = _bucket.exchange(bucket); + if (prevBucket != bucket) + _counts[bucket].store((uint64_t)count); + else _counts[bucket].fetch_add((uint64_t)count); } - ZT_ALWAYS_INLINE double perSecond(const int64_t now) const noexcept + /** + * Get rate per TUNIT time + * + * @param now Current time + * @return Count per TUNIT time (rate) + */ + ZT_ALWAYS_INLINE double rate(const int64_t now) const noexcept { - double r = 0.0,n = 0.0; - const int64_t since = (now - _ts); - if (since >= ZT_METER_HISTORY_TICK_DURATION) { - r += (double)_count / ((double)since / 1000.0); - n += 1.0; - } - for(int i=0;i _hptr; + const int64_t startTime; + std::atomic _total; + std::atomic _counts[LSIZE]; + std::atomic _bucket; }; } // namespace ZeroTier diff --git a/node/Protocol.hpp b/node/Protocol.hpp index 210c0a37d..e4d2cde43 100644 --- a/node/Protocol.hpp +++ b/node/Protocol.hpp @@ -263,6 +263,13 @@ namespace Protocol { */ enum Verb { + /** + * No operation + * + * This packet does nothing, but it is sometimes sent as a probe to + * trigger a HELLO exchange as the code will attempt HELLO when it + * receives a packet from an unidentified source. + */ VERB_NOP = 0x00, /** @@ -280,8 +287,8 @@ enum Verb * <[2] 16-bit length of meta-data dictionary> * <[...] meta-data dictionary> * <[2] 16-bit length of any additional fields> - * <[48] HMAC-SHA384 of full plaintext payload> * [... end encrypted region ...] + * <[48] HMAC-SHA384 of full plaintext payload> * * HELLO is sent with authentication but without the usual encryption so * that peers can exchange identities.