summaryrefslogtreecommitdiff
path: root/zerotierone/node
diff options
context:
space:
mode:
Diffstat (limited to 'zerotierone/node')
-rw-r--r--zerotierone/node/Address.hpp239
-rw-r--r--zerotierone/node/Array.hpp107
-rw-r--r--zerotierone/node/AtomicCounter.hpp113
-rw-r--r--zerotierone/node/BinarySemaphore.hpp97
-rw-r--r--zerotierone/node/Buffer.hpp514
-rw-r--r--zerotierone/node/C25519.cpp2398
-rw-r--r--zerotierone/node/C25519.hpp213
-rw-r--r--zerotierone/node/CertificateOfMembership.cpp230
-rw-r--r--zerotierone/node/CertificateOfMembership.hpp432
-rw-r--r--zerotierone/node/Cluster.cpp913
-rw-r--r--zerotierone/node/Cluster.hpp406
-rw-r--r--zerotierone/node/Constants.hpp396
-rw-r--r--zerotierone/node/DeferredPackets.cpp100
-rw-r--r--zerotierone/node/DeferredPackets.hpp85
-rw-r--r--zerotierone/node/Dictionary.cpp245
-rw-r--r--zerotierone/node/Dictionary.hpp280
-rw-r--r--zerotierone/node/Hashtable.hpp415
-rw-r--r--zerotierone/node/Identity.cpp190
-rw-r--r--zerotierone/node/Identity.hpp318
-rw-r--r--zerotierone/node/IncomingPacket.cpp1349
-rw-r--r--zerotierone/node/IncomingPacket.hpp195
-rw-r--r--zerotierone/node/InetAddress.cpp446
-rw-r--r--zerotierone/node/InetAddress.hpp506
-rw-r--r--zerotierone/node/MAC.hpp264
-rw-r--r--zerotierone/node/MulticastGroup.hpp158
-rw-r--r--zerotierone/node/Multicaster.cpp369
-rw-r--r--zerotierone/node/Multicaster.hpp194
-rw-r--r--zerotierone/node/Mutex.hpp186
-rw-r--r--zerotierone/node/Network.cpp513
-rw-r--r--zerotierone/node/Network.hpp353
-rw-r--r--zerotierone/node/NetworkConfig.cpp180
-rw-r--r--zerotierone/node/NetworkConfig.hpp750
-rw-r--r--zerotierone/node/NetworkConfigRequestMetaData.hpp196
-rw-r--r--zerotierone/node/NetworkController.hpp84
-rw-r--r--zerotierone/node/Node.cpp1031
-rw-r--r--zerotierone/node/Node.hpp319
-rw-r--r--zerotierone/node/NonCopyable.hpp38
-rw-r--r--zerotierone/node/OutboundMulticast.cpp113
-rw-r--r--zerotierone/node/OutboundMulticast.hpp145
-rw-r--r--zerotierone/node/Packet.cpp157
-rw-r--r--zerotierone/node/Packet.hpp1342
-rw-r--r--zerotierone/node/Path.cpp34
-rw-r--r--zerotierone/node/Path.hpp365
-rw-r--r--zerotierone/node/Peer.cpp558
-rw-r--r--zerotierone/node/Peer.hpp614
-rw-r--r--zerotierone/node/Poly1305.cpp628
-rw-r--r--zerotierone/node/Poly1305.hpp55
-rw-r--r--zerotierone/node/RuntimeEnvironment.hpp98
-rw-r--r--zerotierone/node/SHA512.cpp352
-rw-r--r--zerotierone/node/SHA512.hpp37
-rw-r--r--zerotierone/node/Salsa20.cpp1358
-rw-r--r--zerotierone/node/Salsa20.hpp115
-rw-r--r--zerotierone/node/SelfAwareness.cpp187
-rw-r--r--zerotierone/node/SelfAwareness.hpp98
-rw-r--r--zerotierone/node/SharedPtr.hpp154
-rw-r--r--zerotierone/node/Switch.cpp862
-rw-r--r--zerotierone/node/Switch.hpp268
-rw-r--r--zerotierone/node/Topology.cpp363
-rw-r--r--zerotierone/node/Topology.hpp272
-rw-r--r--zerotierone/node/Utils.cpp283
-rw-r--r--zerotierone/node/Utils.hpp392
-rw-r--r--zerotierone/node/World.hpp232
62 files changed, 23904 insertions, 0 deletions
diff --git a/zerotierone/node/Address.hpp b/zerotierone/node/Address.hpp
new file mode 100644
index 0000000..9bf5605
--- /dev/null
+++ b/zerotierone/node/Address.hpp
@@ -0,0 +1,239 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_ADDRESS_HPP
+#define ZT_ADDRESS_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+
+#include "Constants.hpp"
+#include "Utils.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A ZeroTier address
+ */
+class Address
+{
+public:
+ Address()
+ throw() :
+ _a(0)
+ {
+ }
+
+ Address(const Address &a)
+ throw() :
+ _a(a._a)
+ {
+ }
+
+ Address(uint64_t a)
+ throw() :
+ _a(a & 0xffffffffffULL)
+ {
+ }
+
+ Address(const char *s)
+ throw()
+ {
+ unsigned char foo[ZT_ADDRESS_LENGTH];
+ setTo(foo,Utils::unhex(s,foo,ZT_ADDRESS_LENGTH));
+ }
+
+ Address(const std::string &s)
+ throw()
+ {
+ unsigned char foo[ZT_ADDRESS_LENGTH];
+ setTo(foo,Utils::unhex(s.c_str(),foo,ZT_ADDRESS_LENGTH));
+ }
+
+ /**
+ * @param bits Raw address -- 5 bytes, big-endian byte order
+ * @param len Length of array
+ */
+ Address(const void *bits,unsigned int len)
+ throw()
+ {
+ setTo(bits,len);
+ }
+
+ inline Address &operator=(const Address &a)
+ throw()
+ {
+ _a = a._a;
+ return *this;
+ }
+
+ inline Address &operator=(const uint64_t a)
+ throw()
+ {
+ _a = (a & 0xffffffffffULL);
+ return *this;
+ }
+
+ /**
+ * @param bits Raw address -- 5 bytes, big-endian byte order
+ * @param len Length of array
+ */
+ inline void setTo(const void *bits,unsigned int len)
+ throw()
+ {
+ if (len < ZT_ADDRESS_LENGTH) {
+ _a = 0;
+ return;
+ }
+ const unsigned char *b = (const unsigned char *)bits;
+ uint64_t a = ((uint64_t)*b++) << 32;
+ a |= ((uint64_t)*b++) << 24;
+ a |= ((uint64_t)*b++) << 16;
+ a |= ((uint64_t)*b++) << 8;
+ a |= ((uint64_t)*b);
+ _a = a;
+ }
+
+ /**
+ * @param bits Buffer to hold 5-byte address in big-endian byte order
+ * @param len Length of array
+ */
+ inline void copyTo(void *bits,unsigned int len) const
+ throw()
+ {
+ if (len < ZT_ADDRESS_LENGTH)
+ return;
+ unsigned char *b = (unsigned char *)bits;
+ *(b++) = (unsigned char)((_a >> 32) & 0xff);
+ *(b++) = (unsigned char)((_a >> 24) & 0xff);
+ *(b++) = (unsigned char)((_a >> 16) & 0xff);
+ *(b++) = (unsigned char)((_a >> 8) & 0xff);
+ *b = (unsigned char)(_a & 0xff);
+ }
+
+ /**
+ * Append to a buffer in big-endian byte order
+ *
+ * @param b Buffer to append to
+ */
+ template<unsigned int C>
+ inline void appendTo(Buffer<C> &b) const
+ throw(std::out_of_range)
+ {
+ unsigned char *p = (unsigned char *)b.appendField(ZT_ADDRESS_LENGTH);
+ *(p++) = (unsigned char)((_a >> 32) & 0xff);
+ *(p++) = (unsigned char)((_a >> 24) & 0xff);
+ *(p++) = (unsigned char)((_a >> 16) & 0xff);
+ *(p++) = (unsigned char)((_a >> 8) & 0xff);
+ *p = (unsigned char)(_a & 0xff);
+ }
+
+ /**
+ * @return Integer containing address (0 to 2^40)
+ */
+ inline uint64_t toInt() const
+ throw()
+ {
+ return _a;
+ }
+
+ /**
+ * @return Hash code for use with Hashtable
+ */
+ inline unsigned long hashCode() const
+ throw()
+ {
+ return (unsigned long)_a;
+ }
+
+ /**
+ * @return Hexadecimal string
+ */
+ inline std::string toString() const
+ {
+ char buf[16];
+ Utils::snprintf(buf,sizeof(buf),"%.10llx",(unsigned long long)_a);
+ return std::string(buf);
+ };
+
+ /**
+ * @param buf Buffer to fill
+ * @param len Length of buffer
+ */
+ inline void toString(char *buf,unsigned int len) const
+ {
+ Utils::snprintf(buf,len,"%.10llx",(unsigned long long)_a);
+ }
+
+ /**
+ * @return True if this address is not zero
+ */
+ inline operator bool() const throw() { return (_a != 0); }
+
+ /**
+ * Set to null/zero
+ */
+ inline void zero() throw() { _a = 0; }
+
+ /**
+ * Check if this address is reserved
+ *
+ * The all-zero null address and any address beginning with 0xff are
+ * reserved. (0xff is reserved for future use to designate possibly
+ * longer addresses, addresses based on IPv6 innards, etc.)
+ *
+ * @return True if address is reserved and may not be used
+ */
+ inline bool isReserved() const
+ throw()
+ {
+ return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX));
+ }
+
+ /**
+ * @param i Value from 0 to 4 (inclusive)
+ * @return Byte at said position (address interpreted in big-endian order)
+ */
+ inline unsigned char operator[](unsigned int i) const throw() { return (unsigned char)((_a >> (32 - (i * 8))) & 0xff); }
+
+ inline bool operator==(const uint64_t &a) const throw() { return (_a == (a & 0xffffffffffULL)); }
+ inline bool operator!=(const uint64_t &a) const throw() { return (_a != (a & 0xffffffffffULL)); }
+ inline bool operator>(const uint64_t &a) const throw() { return (_a > (a & 0xffffffffffULL)); }
+ inline bool operator<(const uint64_t &a) const throw() { return (_a < (a & 0xffffffffffULL)); }
+ inline bool operator>=(const uint64_t &a) const throw() { return (_a >= (a & 0xffffffffffULL)); }
+ inline bool operator<=(const uint64_t &a) const throw() { return (_a <= (a & 0xffffffffffULL)); }
+
+ inline bool operator==(const Address &a) const throw() { return (_a == a._a); }
+ inline bool operator!=(const Address &a) const throw() { return (_a != a._a); }
+ inline bool operator>(const Address &a) const throw() { return (_a > a._a); }
+ inline bool operator<(const Address &a) const throw() { return (_a < a._a); }
+ inline bool operator>=(const Address &a) const throw() { return (_a >= a._a); }
+ inline bool operator<=(const Address &a) const throw() { return (_a <= a._a); }
+
+private:
+ uint64_t _a;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Array.hpp b/zerotierone/node/Array.hpp
new file mode 100644
index 0000000..19b29eb
--- /dev/null
+++ b/zerotierone/node/Array.hpp
@@ -0,0 +1,107 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_ARRAY_HPP
+#define ZT_ARRAY_HPP
+
+#include <string>
+#include <algorithm>
+
+namespace ZeroTier {
+
+/**
+ * Static array -- a simple thing that's belonged in STL since the time of the dinosaurs
+ */
+template<typename T,std::size_t S>
+class Array
+{
+public:
+ Array() throw() {}
+
+ Array(const Array &a)
+ {
+ for(std::size_t i=0;i<S;++i)
+ data[i] = a.data[i];
+ }
+
+ Array(const T *ptr)
+ {
+ for(std::size_t i=0;i<S;++i)
+ data[i] = ptr[i];
+ }
+
+ inline Array &operator=(const Array &a)
+ {
+ for(std::size_t i=0;i<S;++i)
+ data[i] = a.data[i];
+ return *this;
+ }
+
+ typedef T value_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ inline iterator begin() throw() { return data; }
+ inline iterator end() throw() { return &(data[S]); }
+ inline const_iterator begin() const throw() { return data; }
+ inline const_iterator end() const throw() { return &(data[S]); }
+
+ inline reverse_iterator rbegin() throw() { return reverse_iterator(begin()); }
+ inline reverse_iterator rend() throw() { return reverse_iterator(end()); }
+ inline const_reverse_iterator rbegin() const throw() { return const_reverse_iterator(begin()); }
+ inline const_reverse_iterator rend() const throw() { return const_reverse_iterator(end()); }
+
+ inline std::size_t size() const throw() { return S; }
+ inline std::size_t max_size() const throw() { return S; }
+
+ inline reference operator[](const std::size_t n) throw() { return data[n]; }
+ inline const_reference operator[](const std::size_t n) const throw() { return data[n]; }
+
+ inline reference front() throw() { return data[0]; }
+ inline const_reference front() const throw() { return data[0]; }
+ inline reference back() throw() { return data[S-1]; }
+ inline const_reference back() const throw() { return data[S-1]; }
+
+ inline bool operator==(const Array &k) const throw()
+ {
+ for(unsigned long i=0;i<S;++i) {
+ if (data[i] != k.data[i])
+ return false;
+ }
+ return true;
+ }
+ inline bool operator<(const Array &k) const throw() { return std::lexicographical_compare(begin(),end(),k.begin(),k.end()); }
+ inline bool operator!=(const Array &k) const throw() { return !(*this == k); }
+ inline bool operator>(const Array &k) const throw() { return (k < *this); }
+ inline bool operator<=(const Array &k) const throw() { return !(k < *this); }
+ inline bool operator>=(const Array &k) const throw() { return !(*this < k); }
+
+ T data[S];
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/AtomicCounter.hpp b/zerotierone/node/AtomicCounter.hpp
new file mode 100644
index 0000000..b499377
--- /dev/null
+++ b/zerotierone/node/AtomicCounter.hpp
@@ -0,0 +1,113 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_ATOMICCOUNTER_HPP
+#define ZT_ATOMICCOUNTER_HPP
+
+#include "Constants.hpp"
+#include "Mutex.hpp"
+#include "NonCopyable.hpp"
+
+#ifdef __WINDOWS__
+// <atomic> will replace this whole class eventually once it's ubiquitous
+#include <atomic>
+#endif
+
+namespace ZeroTier {
+
+/**
+ * Simple atomic counter supporting increment and decrement
+ */
+class AtomicCounter : NonCopyable
+{
+public:
+ /**
+ * Initialize counter at zero
+ */
+ AtomicCounter()
+ throw()
+ {
+ _v = 0;
+ }
+
+ inline operator int() const
+ throw()
+ {
+#ifdef __GNUC__
+ return __sync_or_and_fetch(const_cast <volatile int *>(&_v),0);
+#else
+#ifdef __WINDOWS__
+ return (int)_v;
+#else
+ _l.lock();
+ int v = _v;
+ _l.unlock();
+ return v;
+#endif
+#endif
+ }
+
+ inline int operator++()
+ throw()
+ {
+#ifdef __GNUC__
+ return __sync_add_and_fetch(&_v,1);
+#else
+#ifdef __WINDOWS__
+ return ++_v;
+#else
+ _l.lock();
+ int v = ++_v;
+ _l.unlock();
+ return v;
+#endif
+#endif
+ }
+
+ inline int operator--()
+ throw()
+ {
+#ifdef __GNUC__
+ return __sync_sub_and_fetch(&_v,1);
+#else
+#ifdef __WINDOWS__
+ return --_v;
+#else
+ _l.lock();
+ int v = --_v;
+ _l.unlock();
+ return v;
+#endif
+#endif
+ }
+
+private:
+#ifdef __WINDOWS__
+ std::atomic_int _v;
+#else
+ int _v;
+#ifndef __GNUC__
+#warning Neither __WINDOWS__ nor __GNUC__ so AtomicCounter using Mutex
+ Mutex _l;
+#endif
+#endif
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/BinarySemaphore.hpp b/zerotierone/node/BinarySemaphore.hpp
new file mode 100644
index 0000000..315d2b0
--- /dev/null
+++ b/zerotierone/node/BinarySemaphore.hpp
@@ -0,0 +1,97 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_BINARYSEMAPHORE_HPP
+#define ZT_BINARYSEMAPHORE_HPP
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "Constants.hpp"
+#include "NonCopyable.hpp"
+
+#ifdef __WINDOWS__
+
+#include <Windows.h>
+
+namespace ZeroTier {
+
+class BinarySemaphore : NonCopyable
+{
+public:
+ BinarySemaphore() throw() { _sem = CreateSemaphore(NULL,0,1,NULL); }
+ ~BinarySemaphore() { CloseHandle(_sem); }
+ inline void wait() { WaitForSingleObject(_sem,INFINITE); }
+ inline void post() { ReleaseSemaphore(_sem,1,NULL); }
+private:
+ HANDLE _sem;
+};
+
+} // namespace ZeroTier
+
+#else // !__WINDOWS__
+
+#include <pthread.h>
+
+namespace ZeroTier {
+
+class BinarySemaphore : NonCopyable
+{
+public:
+ BinarySemaphore()
+ {
+ pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
+ pthread_cond_init(&_cond,(const pthread_condattr_t *)0);
+ _f = false;
+ }
+
+ ~BinarySemaphore()
+ {
+ pthread_cond_destroy(&_cond);
+ pthread_mutex_destroy(&_mh);
+ }
+
+ inline void wait()
+ {
+ pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
+ while (!_f)
+ pthread_cond_wait(const_cast <pthread_cond_t *>(&_cond),const_cast <pthread_mutex_t *>(&_mh));
+ _f = false;
+ pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
+ }
+
+ inline void post()
+ {
+ pthread_mutex_lock(const_cast <pthread_mutex_t *>(&_mh));
+ _f = true;
+ pthread_mutex_unlock(const_cast <pthread_mutex_t *>(&_mh));
+ pthread_cond_signal(const_cast <pthread_cond_t *>(&_cond));
+ }
+
+private:
+ pthread_cond_t _cond;
+ pthread_mutex_t _mh;
+ volatile bool _f;
+};
+
+} // namespace ZeroTier
+
+#endif // !__WINDOWS__
+
+#endif
diff --git a/zerotierone/node/Buffer.hpp b/zerotierone/node/Buffer.hpp
new file mode 100644
index 0000000..0b17159
--- /dev/null
+++ b/zerotierone/node/Buffer.hpp
@@ -0,0 +1,514 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_BUFFER_HPP
+#define ZT_BUFFER_HPP
+
+#include <string.h>
+#include <stdint.h>
+
+#include <stdexcept>
+#include <string>
+#include <algorithm>
+#include <utility>
+
+#include "Constants.hpp"
+#include "Utils.hpp"
+
+#if defined(__GNUC__) && (!defined(ZT_NO_TYPE_PUNNING))
+#define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
+#else
+#define ZT_VAR_MAY_ALIAS
+#endif
+
+namespace ZeroTier {
+
+/**
+ * A variable length but statically allocated buffer
+ *
+ * Bounds-checking is done everywhere, since this is used in security
+ * critical code. This supports construction and assignment from buffers
+ * of differing capacities, provided the data actually in them fits.
+ * It throws std::out_of_range on any boundary violation.
+ *
+ * The at(), append(), etc. methods encode integers larger than 8-bit in
+ * big-endian (network) byte order.
+ *
+ * @tparam C Total capacity
+ */
+template<unsigned int C>
+class Buffer
+{
+ // I love me!
+ template <unsigned int C2> friend class Buffer;
+
+public:
+ // STL container idioms
+ typedef unsigned char value_type;
+ typedef unsigned char * pointer;
+ typedef const unsigned char * const_pointer;
+ typedef unsigned char & reference;
+ typedef const unsigned char & const_reference;
+ typedef unsigned char * iterator;
+ typedef const unsigned char * const_iterator;
+ typedef unsigned int size_type;
+ typedef int difference_type;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ inline iterator begin() { return _b; }
+ inline iterator end() { return (_b + _l); }
+ inline const_iterator begin() const { return _b; }
+ inline const_iterator end() const { return (_b + _l); }
+ inline reverse_iterator rbegin() { return reverse_iterator(begin()); }
+ inline reverse_iterator rend() { return reverse_iterator(end()); }
+ inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
+ inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
+
+ Buffer()
+ throw() :
+ _l(0)
+ {
+ }
+
+ Buffer(unsigned int l)
+ throw(std::out_of_range)
+ {
+ if (l > C)
+ throw std::out_of_range("Buffer: construct with size larger than capacity");
+ _l = l;
+ }
+
+ template<unsigned int C2>
+ Buffer(const Buffer<C2> &b)
+ throw(std::out_of_range)
+ {
+ *this = b;
+ }
+
+ Buffer(const void *b,unsigned int l)
+ throw(std::out_of_range)
+ {
+ copyFrom(b,l);
+ }
+
+ Buffer(const std::string &s)
+ throw(std::out_of_range)
+ {
+ copyFrom(s.data(),s.length());
+ }
+
+ template<unsigned int C2>
+ inline Buffer &operator=(const Buffer<C2> &b)
+ throw(std::out_of_range)
+ {
+ if (b._l > C)
+ throw std::out_of_range("Buffer: assignment from buffer larger than capacity");
+ memcpy(_b,b._b,_l = b._l);
+ return *this;
+ }
+
+ inline Buffer &operator=(const std::string &s)
+ throw(std::out_of_range)
+ {
+ copyFrom(s.data(),s.length());
+ return *this;
+ }
+
+ inline void copyFrom(const void *b,unsigned int l)
+ throw(std::out_of_range)
+ {
+ if (l > C)
+ throw std::out_of_range("Buffer: set from C array larger than capacity");
+ _l = l;
+ memcpy(_b,b,l);
+ }
+
+ unsigned char operator[](const unsigned int i) const
+ throw(std::out_of_range)
+ {
+ if (i >= _l)
+ throw std::out_of_range("Buffer: [] beyond end of data");
+ return (unsigned char)_b[i];
+ }
+
+ unsigned char &operator[](const unsigned int i)
+ throw(std::out_of_range)
+ {
+ if (i >= _l)
+ throw std::out_of_range("Buffer: [] beyond end of data");
+ return ((unsigned char *)_b)[i];
+ }
+
+ /**
+ * Get a raw pointer to a field with bounds checking
+ *
+ * This isn't perfectly safe in that the caller could still overflow
+ * the pointer, but its use provides both a sanity check and
+ * documentation / reminder to the calling code to treat the returned
+ * pointer as being of size [l].
+ *
+ * @param i Index of field in buffer
+ * @param l Length of field in bytes
+ * @return Pointer to field data
+ * @throws std::out_of_range Field extends beyond data size
+ */
+ unsigned char *field(unsigned int i,unsigned int l)
+ throw(std::out_of_range)
+ {
+ if ((i + l) > _l)
+ throw std::out_of_range("Buffer: field() beyond end of data");
+ return (unsigned char *)(_b + i);
+ }
+ const unsigned char *field(unsigned int i,unsigned int l) const
+ throw(std::out_of_range)
+ {
+ if ((i + l) > _l)
+ throw std::out_of_range("Buffer: field() beyond end of data");
+ return (const unsigned char *)(_b + i);
+ }
+
+ /**
+ * Place a primitive integer value at a given position
+ *
+ * @param i Index to place value
+ * @param v Value
+ * @tparam T Integer type (e.g. uint16_t, int64_t)
+ */
+ template<typename T>
+ inline void setAt(unsigned int i,const T v)
+ throw(std::out_of_range)
+ {
+ if ((i + sizeof(T)) > _l)
+ throw std::out_of_range("Buffer: setAt() beyond end of data");
+#ifdef ZT_NO_TYPE_PUNNING
+ uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
+ for(unsigned int x=1;x<=sizeof(T);++x)
+ *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
+#else
+ T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + i);
+ *p = Utils::hton(v);
+#endif
+ }
+
+ /**
+ * Get a primitive integer value at a given position
+ *
+ * @param i Index to get integer
+ * @tparam T Integer type (e.g. uint16_t, int64_t)
+ * @return Integer value
+ */
+ template<typename T>
+ inline T at(unsigned int i) const
+ throw(std::out_of_range)
+ {
+ if ((i + sizeof(T)) > _l)
+ throw std::out_of_range("Buffer: at() beyond end of data");
+#ifdef ZT_NO_TYPE_PUNNING
+ T v = 0;
+ const uint8_t *p = reinterpret_cast<const uint8_t *>(_b + i);
+ for(unsigned int x=0;x<sizeof(T);++x) {
+ v <<= 8;
+ v |= (T)*(p++);
+ }
+ return v;
+#else
+ const T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T *>(_b + i);
+ return Utils::ntoh(*p);
+#endif
+ }
+
+ /**
+ * Append an integer type to this buffer
+ *
+ * @param v Value to append
+ * @tparam T Integer type (e.g. uint16_t, int64_t)
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ template<typename T>
+ inline void append(const T v)
+ throw(std::out_of_range)
+ {
+ if ((_l + sizeof(T)) > C)
+ throw std::out_of_range("Buffer: append beyond capacity");
+#ifdef ZT_NO_TYPE_PUNNING
+ uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
+ for(unsigned int x=1;x<=sizeof(T);++x)
+ *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
+#else
+ T *const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T *>(_b + _l);
+ *p = Utils::hton(v);
+#endif
+ _l += sizeof(T);
+ }
+
+ /**
+ * Append a run of bytes
+ *
+ * @param c Character value to append
+ * @param n Number of times to append
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ inline void append(unsigned char c,unsigned int n)
+ throw(std::out_of_range)
+ {
+ if ((_l + n) > C)
+ throw std::out_of_range("Buffer: append beyond capacity");
+ for(unsigned int i=0;i<n;++i)
+ _b[_l++] = (char)c;
+ }
+
+ /**
+ * Append a C-array of bytes
+ *
+ * @param b Data
+ * @param l Length
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ inline void append(const void *b,unsigned int l)
+ throw(std::out_of_range)
+ {
+ if ((_l + l) > C)
+ throw std::out_of_range("Buffer: append beyond capacity");
+ memcpy(_b + _l,b,l);
+ _l += l;
+ }
+
+ /**
+ * Append a string
+ *
+ * @param s String to append
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ inline void append(const std::string &s)
+ throw(std::out_of_range)
+ {
+ append(s.data(),(unsigned int)s.length());
+ }
+
+ /**
+ * Append a C string including null termination byte
+ *
+ * @param s C string
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ inline void appendCString(const char *s)
+ throw(std::out_of_range)
+ {
+ for(;;) {
+ if (_l >= C)
+ throw std::out_of_range("Buffer: append beyond capacity");
+ if (!(_b[_l++] = *(s++)))
+ break;
+ }
+ }
+
+ /**
+ * Append a buffer
+ *
+ * @param b Buffer to append
+ * @tparam C2 Capacity of second buffer (typically inferred)
+ * @throws std::out_of_range Attempt to append beyond capacity
+ */
+ template<unsigned int C2>
+ inline void append(const Buffer<C2> &b)
+ throw(std::out_of_range)
+ {
+ append(b._b,b._l);
+ }
+
+ /**
+ * Increment size and return pointer to field of specified size
+ *
+ * Nothing is actually written to the memory. This is a shortcut
+ * for addSize() followed by field() to reference the previous
+ * position and the new size.
+ *
+ * @param l Length of field to append
+ * @return Pointer to beginning of appended field of length 'l'
+ */
+ inline char *appendField(unsigned int l)
+ throw(std::out_of_range)
+ {
+ if ((_l + l) > C)
+ throw std::out_of_range("Buffer: append beyond capacity");
+ char *r = _b + _l;
+ _l += l;
+ return r;
+ }
+
+ /**
+ * Increment size by a given number of bytes
+ *
+ * The contents of new space are undefined.
+ *
+ * @param i Bytes to increment
+ * @throws std::out_of_range Capacity exceeded
+ */
+ inline void addSize(unsigned int i)
+ throw(std::out_of_range)
+ {
+ if ((i + _l) > C)
+ throw std::out_of_range("Buffer: setSize to larger than capacity");
+ _l += i;
+ }
+
+ /**
+ * Set size of data in buffer
+ *
+ * The contents of new space are undefined.
+ *
+ * @param i New size
+ * @throws std::out_of_range Size larger than capacity
+ */
+ inline void setSize(const unsigned int i)
+ throw(std::out_of_range)
+ {
+ if (i > C)
+ throw std::out_of_range("Buffer: setSize to larger than capacity");
+ _l = i;
+ }
+
+ /**
+ * Move everything after 'at' to the buffer's front and truncate
+ *
+ * @param at Truncate before this position
+ * @throw std::out_of_range Position is beyond size of buffer
+ */
+ inline void behead(const unsigned int at)
+ throw(std::out_of_range)
+ {
+ if (!at)
+ return;
+ if (at > _l)
+ throw std::out_of_range("Buffer: behead() beyond capacity");
+ ::memmove(_b,_b + at,_l -= at);
+ }
+
+ /**
+ * Erase something from the middle of the buffer
+ *
+ * @param start Starting position
+ * @param length Length of block to erase
+ * @throw std::out_of_range Position plus length is beyond size of buffer
+ */
+ inline void erase(const unsigned int at,const unsigned int length)
+ throw(std::out_of_range)
+ {
+ const unsigned int endr = at + length;
+ if (endr > _l)
+ throw std::out_of_range("Buffer: erase() range beyond end of buffer");
+ ::memmove(_b + at,_b + endr,_l - endr);
+ _l -= length;
+ }
+
+ /**
+ * Set buffer data length to zero
+ */
+ inline void clear()
+ throw()
+ {
+ _l = 0;
+ }
+
+ /**
+ * Zero buffer up to size()
+ */
+ inline void zero()
+ throw()
+ {
+ memset(_b,0,_l);
+ }
+
+ /**
+ * Zero unused capacity area
+ */
+ inline void zeroUnused()
+ throw()
+ {
+ memset(_b + _l,0,C - _l);
+ }
+
+ /**
+ * Unconditionally and securely zero buffer's underlying memory
+ */
+ inline void burn()
+ throw()
+ {
+ Utils::burn(_b,sizeof(_b));
+ }
+
+ /**
+ * @return Constant pointer to data in buffer
+ */
+ inline const void *data() const throw() { return _b; }
+
+ /**
+ * @return Size of data in buffer
+ */
+ inline unsigned int size() const throw() { return _l; }
+
+ /**
+ * @return Capacity of buffer
+ */
+ inline unsigned int capacity() const throw() { return C; }
+
+ template<unsigned int C2>
+ inline bool operator==(const Buffer<C2> &b) const
+ throw()
+ {
+ return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
+ }
+ template<unsigned int C2>
+ inline bool operator!=(const Buffer<C2> &b) const
+ throw()
+ {
+ return ((_l != b._l)||(memcmp(_b,b._b,_l)));
+ }
+ template<unsigned int C2>
+ inline bool operator<(const Buffer<C2> &b) const
+ throw()
+ {
+ return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
+ }
+ template<unsigned int C2>
+ inline bool operator>(const Buffer<C2> &b) const
+ throw()
+ {
+ return (b < *this);
+ }
+ template<unsigned int C2>
+ inline bool operator<=(const Buffer<C2> &b) const
+ throw()
+ {
+ return !(b < *this);
+ }
+ template<unsigned int C2>
+ inline bool operator>=(const Buffer<C2> &b) const
+ throw()
+ {
+ return !(*this < b);
+ }
+
+private:
+ unsigned int _l;
+ char ZT_VAR_MAY_ALIAS _b[C];
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/C25519.cpp b/zerotierone/node/C25519.cpp
new file mode 100644
index 0000000..e9ffecc
--- /dev/null
+++ b/zerotierone/node/C25519.cpp
@@ -0,0 +1,2398 @@
+// Code taken from NaCl by D. J. Bernstein and others
+
+/*
+Matthew Dempsky
+Public domain.
+Derived from public domain code by D. J. Bernstein.
+*/
+
+// Modified very slightly for ZeroTier One by Adam Ierymenko
+// (no functional changes)
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Constants.hpp"
+#include "C25519.hpp"
+#include "SHA512.hpp"
+#include "Buffer.hpp"
+
+#ifdef __WINDOWS__
+#pragma warning(disable: 4146)
+#endif
+
+namespace ZeroTier {
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+#define crypto_int32 int32_t
+#define crypto_uint32 uint32_t
+#define crypto_int64 int64_t
+#define crypto_uint64 uint64_t
+#define crypto_hash_sha512_BYTES 64
+
+static inline void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+ unsigned int j;
+ unsigned int u;
+ u = 0;
+ for (j = 0;j < 31;++j) { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
+ u += a[31] + b[31]; out[31] = u;
+}
+
+static inline void sub(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+ unsigned int j;
+ unsigned int u;
+ u = 218;
+ for (j = 0;j < 31;++j) {
+ u += a[j] + 65280 - b[j];
+ out[j] = u & 255;
+ u >>= 8;
+ }
+ u += a[31] - b[31];
+ out[31] = u;
+}
+
+static inline void squeeze(unsigned int a[32])
+{
+ unsigned int j;
+ unsigned int u;
+ u = 0;
+ for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
+ u += a[31]; a[31] = u & 127;
+ u = 19 * (u >> 7);
+ for (j = 0;j < 31;++j) { u += a[j]; a[j] = u & 255; u >>= 8; }
+ u += a[31]; a[31] = u;
+}
+
+static const unsigned int minusp[32] = {
+ 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128
+} ;
+
+static inline void freeze(unsigned int a[32])
+{
+ unsigned int aorig[32];
+ unsigned int j;
+ unsigned int negative;
+
+ for (j = 0;j < 32;++j) aorig[j] = a[j];
+ add(a,a,minusp);
+ negative = -((a[31] >> 7) & 1);
+ for (j = 0;j < 32;++j) a[j] ^= negative & (aorig[j] ^ a[j]);
+}
+
+static inline void mult(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int u;
+
+ for (i = 0;i < 32;++i) {
+ u = 0;
+ for (j = 0;j <= i;++j) u += a[j] * b[i - j];
+ for (j = i + 1;j < 32;++j) u += 38 * a[j] * b[i + 32 - j];
+ out[i] = u;
+ }
+ squeeze(out);
+}
+
+static inline void mult121665(unsigned int out[32],const unsigned int a[32])
+{
+ unsigned int j;
+ unsigned int u;
+
+ u = 0;
+ for (j = 0;j < 31;++j) { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
+ u += 121665 * a[31]; out[31] = u & 127;
+ u = 19 * (u >> 7);
+ for (j = 0;j < 31;++j) { u += out[j]; out[j] = u & 255; u >>= 8; }
+ u += out[j]; out[j] = u;
+}
+
+static inline void square(unsigned int out[32],const unsigned int a[32])
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int u;
+
+ for (i = 0;i < 32;++i) {
+ u = 0;
+ for (j = 0;j < i - j;++j) u += a[j] * a[i - j];
+ for (j = i + 1;j < i + 32 - j;++j) u += 38 * a[j] * a[i + 32 - j];
+ u *= 2;
+ if ((i & 1) == 0) {
+ u += a[i / 2] * a[i / 2];
+ u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
+ }
+ out[i] = u;
+ }
+ squeeze(out);
+}
+
+static inline void select(unsigned int p[64],unsigned int q[64],const unsigned int r[64],const unsigned int s[64],unsigned int b)
+{
+ unsigned int j;
+ unsigned int t;
+ unsigned int bminus1;
+
+ bminus1 = b - 1;
+ for (j = 0;j < 64;++j) {
+ t = bminus1 & (r[j] ^ s[j]);
+ p[j] = s[j] ^ t;
+ q[j] = r[j] ^ t;
+ }
+}
+
+static void mainloop(unsigned int work[64],const unsigned char e[32])
+{
+ unsigned int xzm1[64];
+ unsigned int xzm[64];
+ unsigned int xzmb[64];
+ unsigned int xzm1b[64];
+ unsigned int xznb[64];
+ unsigned int xzn1b[64];
+ unsigned int a0[64];
+ unsigned int a1[64];
+ unsigned int b0[64];
+ unsigned int b1[64];
+ unsigned int c1[64];
+ unsigned int r[32];
+ unsigned int s[32];
+ unsigned int t[32];
+ unsigned int u[32];
+ //unsigned int i;
+ unsigned int j;
+ unsigned int b;
+ int pos;
+
+ for (j = 0;j < 32;++j) xzm1[j] = work[j];
+ xzm1[32] = 1;
+ for (j = 33;j < 64;++j) xzm1[j] = 0;
+
+ xzm[0] = 1;
+ for (j = 1;j < 64;++j) xzm[j] = 0;
+
+ for (pos = 254;pos >= 0;--pos) {
+ b = e[pos / 8] >> (pos & 7);
+ b &= 1;
+ select(xzmb,xzm1b,xzm,xzm1,b);
+ add(a0,xzmb,xzmb + 32);
+ sub(a0 + 32,xzmb,xzmb + 32);
+ add(a1,xzm1b,xzm1b + 32);
+ sub(a1 + 32,xzm1b,xzm1b + 32);
+ square(b0,a0);
+ square(b0 + 32,a0 + 32);
+ mult(b1,a1,a0 + 32);
+ mult(b1 + 32,a1 + 32,a0);
+ add(c1,b1,b1 + 32);
+ sub(c1 + 32,b1,b1 + 32);
+ square(r,c1 + 32);
+ sub(s,b0,b0 + 32);
+ mult121665(t,s);
+ add(u,t,b0);
+ mult(xznb,b0,b0 + 32);
+ mult(xznb + 32,s,u);
+ square(xzn1b,c1);
+ mult(xzn1b + 32,r,work);
+ select(xzm,xzm1,xznb,xzn1b,b);
+ }
+
+ for (j = 0;j < 64;++j) work[j] = xzm[j];
+}
+
+static void recip(unsigned int out[32],const unsigned int z[32])
+{
+ unsigned int z2[32];
+ unsigned int z9[32];
+ unsigned int z11[32];
+ unsigned int z2_5_0[32];
+ unsigned int z2_10_0[32];
+ unsigned int z2_20_0[32];
+ unsigned int z2_50_0[32];
+ unsigned int z2_100_0[32];
+ unsigned int t0[32];
+ unsigned int t1[32];
+ int i;
+
+ /* 2 */ square(z2,z);
+ /* 4 */ square(t1,z2);
+ /* 8 */ square(t0,t1);
+ /* 9 */ mult(z9,t0,z);
+ /* 11 */ mult(z11,z9,z2);
+ /* 22 */ square(t0,z11);
+ /* 2^5 - 2^0 = 31 */ mult(z2_5_0,t0,z9);
+
+ /* 2^6 - 2^1 */ square(t0,z2_5_0);
+ /* 2^7 - 2^2 */ square(t1,t0);
+ /* 2^8 - 2^3 */ square(t0,t1);
+ /* 2^9 - 2^4 */ square(t1,t0);
+ /* 2^10 - 2^5 */ square(t0,t1);
+ /* 2^10 - 2^0 */ mult(z2_10_0,t0,z2_5_0);
+
+ /* 2^11 - 2^1 */ square(t0,z2_10_0);
+ /* 2^12 - 2^2 */ square(t1,t0);
+ /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t0,t1); square(t1,t0); }
+ /* 2^20 - 2^0 */ mult(z2_20_0,t1,z2_10_0);
+
+ /* 2^21 - 2^1 */ square(t0,z2_20_0);
+ /* 2^22 - 2^2 */ square(t1,t0);
+ /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { square(t0,t1); square(t1,t0); }
+ /* 2^40 - 2^0 */ mult(t0,t1,z2_20_0);
+
+ /* 2^41 - 2^1 */ square(t1,t0);
+ /* 2^42 - 2^2 */ square(t0,t1);
+ /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { square(t1,t0); square(t0,t1); }
+ /* 2^50 - 2^0 */ mult(z2_50_0,t0,z2_10_0);
+
+ /* 2^51 - 2^1 */ square(t0,z2_50_0);
+ /* 2^52 - 2^2 */ square(t1,t0);
+ /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
+ /* 2^100 - 2^0 */ mult(z2_100_0,t1,z2_50_0);
+
+ /* 2^101 - 2^1 */ square(t1,z2_100_0);
+ /* 2^102 - 2^2 */ square(t0,t1);
+ /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { square(t1,t0); square(t0,t1); }
+ /* 2^200 - 2^0 */ mult(t1,t0,z2_100_0);
+
+ /* 2^201 - 2^1 */ square(t0,t1);
+ /* 2^202 - 2^2 */ square(t1,t0);
+ /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { square(t0,t1); square(t1,t0); }
+ /* 2^250 - 2^0 */ mult(t0,t1,z2_50_0);
+
+ /* 2^251 - 2^1 */ square(t1,t0);
+ /* 2^252 - 2^2 */ square(t0,t1);
+ /* 2^253 - 2^3 */ square(t1,t0);
+ /* 2^254 - 2^4 */ square(t0,t1);
+ /* 2^255 - 2^5 */ square(t1,t0);
+ /* 2^255 - 21 */ mult(out,t1,z11);
+}
+
+static inline int crypto_scalarmult(unsigned char *q,
+ const unsigned char *n,
+ const unsigned char *p)
+{
+ unsigned int work[96];
+ unsigned char e[32];
+ unsigned int i;
+ for (i = 0;i < 32;++i) e[i] = n[i];
+ e[0] &= 248;
+ e[31] &= 127;
+ e[31] |= 64;
+ for (i = 0;i < 32;++i) work[i] = p[i];
+ mainloop(work,e);
+ recip(work + 32,work + 32);
+ mult(work + 64,work,work + 32);
+ freeze(work + 64);
+ for (i = 0;i < 32;++i) q[i] = work[64 + i];
+ return 0;
+}
+
+static const unsigned char base[32] = {9};
+
+static inline int crypto_scalarmult_base(unsigned char *q,
+ const unsigned char *n)
+{
+ return crypto_scalarmult(q,n,base);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// This is the Ed25519 stuff from SUPERCOP:
+// http://bench.cr.yp.to/supercop.html
+
+// Also public domain, newer version than the Ed25519 found in NaCl
+
+typedef struct
+{
+ crypto_uint32 v[32];
+}
+fe25519;
+
+static void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y);
+
+static inline crypto_uint32 equal(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
+{
+ crypto_uint32 x = a ^ b; /* 0: yes; 1..65535: no */
+ x -= 1; /* 4294967295: yes; 0..65534: no */
+ x >>= 31; /* 1: yes; 0: no */
+ return x;
+}
+
+static inline crypto_uint32 ge(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
+{
+ unsigned int x = a;
+ x -= (unsigned int) b; /* 0..65535: yes; 4294901761..4294967295: no */
+ x >>= 31; /* 0: yes; 1: no */
+ x ^= 1; /* 1: yes; 0: no */
+ return x;
+}
+
+static inline crypto_uint32 times19(crypto_uint32 a)
+{
+ return (a << 4) + (a << 1) + a;
+}
+
+static inline crypto_uint32 times38(crypto_uint32 a)
+{
+ return (a << 5) + (a << 2) + (a << 1);
+}
+
+static inline void reduce_add_sub(fe25519 *r)
+{
+ crypto_uint32 t;
+ int i,rep;
+
+ for(rep=0;rep<4;rep++)
+ {
+ t = r->v[31] >> 7;
+ r->v[31] &= 127;
+ t = times19(t);
+ r->v[0] += t;
+ for(i=0;i<31;i++)
+ {
+ t = r->v[i] >> 8;
+ r->v[i+1] += t;
+ r->v[i] &= 255;
+ }
+ }
+}
+
+static inline void reduce_mul(fe25519 *r)
+{
+ crypto_uint32 t;
+ int i,rep;
+
+ for(rep=0;rep<2;rep++)
+ {
+ t = r->v[31] >> 7;
+ r->v[31] &= 127;
+ t = times19(t);
+ r->v[0] += t;
+ for(i=0;i<31;i++)
+ {
+ t = r->v[i] >> 8;
+ r->v[i+1] += t;
+ r->v[i] &= 255;
+ }
+ }
+}
+
+/* reduction modulo 2^255-19 */
+static inline void fe25519_freeze(fe25519 *r)
+{
+ int i;
+ crypto_uint32 m = equal(r->v[31],127);
+ for(i=30;i>0;i--)
+ m &= equal(r->v[i],255);
+ m &= ge(r->v[0],237);
+
+ m = -m;
+
+ r->v[31] -= m&127;
+ for(i=30;i>0;i--)
+ r->v[i] -= m&255;
+ r->v[0] -= m&237;
+}
+
+static inline void fe25519_unpack(fe25519 *r, const unsigned char x[32])
+{
+ int i;
+ for(i=0;i<32;i++) r->v[i] = x[i];
+ r->v[31] &= 127;
+}
+
+/* Assumes input x being reduced below 2^255 */
+static inline void fe25519_pack(unsigned char r[32], const fe25519 *x)
+{
+ int i;
+ fe25519 y = *x;
+ fe25519_freeze(&y);
+ for(i=0;i<32;i++)
+ r[i] = y.v[i];
+}
+
+#if 0
+static int fe25519_iszero(const fe25519 *x)
+{
+ int i;
+ int r;
+ fe25519 t = *x;
+ fe25519_freeze(&t);
+ r = equal(t.v[0],0);
+ for(i=1;i<32;i++)
+ r &= equal(t.v[i],0);
+ return r;
+}
+#endif
+
+static inline int fe25519_iseq_vartime(const fe25519 *x, const fe25519 *y)
+{
+ int i;
+ fe25519 t1 = *x;
+ fe25519 t2 = *y;
+ fe25519_freeze(&t1);
+ fe25519_freeze(&t2);
+ for(i=0;i<32;i++)
+ if(t1.v[i] != t2.v[i]) return 0;
+ return 1;
+}
+
+static inline void fe25519_cmov(fe25519 *r, const fe25519 *x, unsigned char b)
+{
+ int i;
+ crypto_uint32 mask = b;
+ mask = -mask;
+ for(i=0;i<32;i++) r->v[i] ^= mask & (x->v[i] ^ r->v[i]);
+}
+
+static inline unsigned char fe25519_getparity(const fe25519 *x)
+{
+ fe25519 t = *x;
+ fe25519_freeze(&t);
+ return t.v[0] & 1;
+}
+
+static inline void fe25519_setone(fe25519 *r)
+{
+ int i;
+ r->v[0] = 1;
+ for(i=1;i<32;i++) r->v[i]=0;
+}
+
+static inline void fe25519_setzero(fe25519 *r)
+{
+ int i;
+ for(i=0;i<32;i++) r->v[i]=0;
+}
+
+static inline void fe25519_neg(fe25519 *r, const fe25519 *x)
+{
+ fe25519 t;
+ int i;
+ for(i=0;i<32;i++) t.v[i]=x->v[i];
+ fe25519_setzero(r);
+ fe25519_sub(r, r, &t);
+}
+
+static inline void fe25519_add(fe25519 *r, const fe25519 *x, const fe25519 *y)
+{
+ int i;
+ for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
+ reduce_add_sub(r);
+}
+
+static inline void fe25519_sub(fe25519 *r, const fe25519 *x, const fe25519 *y)
+{
+ int i;
+ crypto_uint32 t[32];
+ t[0] = x->v[0] + 0x1da;
+ t[31] = x->v[31] + 0xfe;
+ for(i=1;i<31;i++) t[i] = x->v[i] + 0x1fe;
+ for(i=0;i<32;i++) r->v[i] = t[i] - y->v[i];
+ reduce_add_sub(r);
+}
+
+static inline void fe25519_mul(fe25519 *r, const fe25519 *x, const fe25519 *y)
+{
+ int i,j;
+ crypto_uint32 t[63];
+ for(i=0;i<63;i++)t[i] = 0;
+
+ for(i=0;i<32;i++)
+ for(j=0;j<32;j++)
+ t[i+j] += x->v[i] * y->v[j];
+
+ for(i=32;i<63;i++)
+ r->v[i-32] = t[i-32] + times38(t[i]);
+ r->v[31] = t[31]; /* result now in r[0]...r[31] */
+
+ reduce_mul(r);
+}
+
+static inline void fe25519_square(fe25519 *r, const fe25519 *x)
+{
+ fe25519_mul(r, x, x);
+}
+
+static void fe25519_invert(fe25519 *r, const fe25519 *x)
+{
+ fe25519 z2;
+ fe25519 z9;
+ fe25519 z11;
+ fe25519 z2_5_0;
+ fe25519 z2_10_0;
+ fe25519 z2_20_0;
+ fe25519 z2_50_0;
+ fe25519 z2_100_0;
+ fe25519 t0;
+ fe25519 t1;
+ int i;
+
+ /* 2 */ fe25519_square(&z2,x);
+ /* 4 */ fe25519_square(&t1,&z2);
+ /* 8 */ fe25519_square(&t0,&t1);
+ /* 9 */ fe25519_mul(&z9,&t0,x);
+ /* 11 */ fe25519_mul(&z11,&z9,&z2);
+ /* 22 */ fe25519_square(&t0,&z11);
+ /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t0,&z9);
+
+ /* 2^6 - 2^1 */ fe25519_square(&t0,&z2_5_0);
+ /* 2^7 - 2^2 */ fe25519_square(&t1,&t0);
+ /* 2^8 - 2^3 */ fe25519_square(&t0,&t1);
+ /* 2^9 - 2^4 */ fe25519_square(&t1,&t0);
+ /* 2^10 - 2^5 */ fe25519_square(&t0,&t1);
+ /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t0,&z2_5_0);
+
+ /* 2^11 - 2^1 */ fe25519_square(&t0,&z2_10_0);
+ /* 2^12 - 2^2 */ fe25519_square(&t1,&t0);
+ /* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
+ /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t1,&z2_10_0);
+
+ /* 2^21 - 2^1 */ fe25519_square(&t0,&z2_20_0);
+ /* 2^22 - 2^2 */ fe25519_square(&t1,&t0);
+ /* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
+ /* 2^40 - 2^0 */ fe25519_mul(&t0,&t1,&z2_20_0);
+
+ /* 2^41 - 2^1 */ fe25519_square(&t1,&t0);
+ /* 2^42 - 2^2 */ fe25519_square(&t0,&t1);
+ /* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); }
+ /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t0,&z2_10_0);
+
+ /* 2^51 - 2^1 */ fe25519_square(&t0,&z2_50_0);
+ /* 2^52 - 2^2 */ fe25519_square(&t1,&t0);
+ /* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
+ /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t1,&z2_50_0);
+
+ /* 2^101 - 2^1 */ fe25519_square(&t1,&z2_100_0);
+ /* 2^102 - 2^2 */ fe25519_square(&t0,&t1);
+ /* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fe25519_square(&t1,&t0); fe25519_square(&t0,&t1); }
+ /* 2^200 - 2^0 */ fe25519_mul(&t1,&t0,&z2_100_0);
+
+ /* 2^201 - 2^1 */ fe25519_square(&t0,&t1);
+ /* 2^202 - 2^2 */ fe25519_square(&t1,&t0);
+ /* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fe25519_square(&t0,&t1); fe25519_square(&t1,&t0); }
+ /* 2^250 - 2^0 */ fe25519_mul(&t0,&t1,&z2_50_0);
+
+ /* 2^251 - 2^1 */ fe25519_square(&t1,&t0);
+ /* 2^252 - 2^2 */ fe25519_square(&t0,&t1);
+ /* 2^253 - 2^3 */ fe25519_square(&t1,&t0);
+ /* 2^254 - 2^4 */ fe25519_square(&t0,&t1);
+ /* 2^255 - 2^5 */ fe25519_square(&t1,&t0);
+ /* 2^255 - 21 */ fe25519_mul(r,&t1,&z11);
+}
+
+static void fe25519_pow2523(fe25519 *r, const fe25519 *x)
+{
+ fe25519 z2;
+ fe25519 z9;
+ fe25519 z11;
+ fe25519 z2_5_0;
+ fe25519 z2_10_0;
+ fe25519 z2_20_0;
+ fe25519 z2_50_0;
+ fe25519 z2_100_0;
+ fe25519 t;
+ int i;
+
+ /* 2 */ fe25519_square(&z2,x);
+ /* 4 */ fe25519_square(&t,&z2);
+ /* 8 */ fe25519_square(&t,&t);
+ /* 9 */ fe25519_mul(&z9,&t,x);
+ /* 11 */ fe25519_mul(&z11,&z9,&z2);
+ /* 22 */ fe25519_square(&t,&z11);
+ /* 2^5 - 2^0 = 31 */ fe25519_mul(&z2_5_0,&t,&z9);
+
+ /* 2^6 - 2^1 */ fe25519_square(&t,&z2_5_0);
+ /* 2^10 - 2^5 */ for (i = 1;i < 5;i++) { fe25519_square(&t,&t); }
+ /* 2^10 - 2^0 */ fe25519_mul(&z2_10_0,&t,&z2_5_0);
+
+ /* 2^11 - 2^1 */ fe25519_square(&t,&z2_10_0);
+ /* 2^20 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); }
+ /* 2^20 - 2^0 */ fe25519_mul(&z2_20_0,&t,&z2_10_0);
+
+ /* 2^21 - 2^1 */ fe25519_square(&t,&z2_20_0);
+ /* 2^40 - 2^20 */ for (i = 1;i < 20;i++) { fe25519_square(&t,&t); }
+ /* 2^40 - 2^0 */ fe25519_mul(&t,&t,&z2_20_0);
+
+ /* 2^41 - 2^1 */ fe25519_square(&t,&t);
+ /* 2^50 - 2^10 */ for (i = 1;i < 10;i++) { fe25519_square(&t,&t); }
+ /* 2^50 - 2^0 */ fe25519_mul(&z2_50_0,&t,&z2_10_0);
+
+ /* 2^51 - 2^1 */ fe25519_square(&t,&z2_50_0);
+ /* 2^100 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); }
+ /* 2^100 - 2^0 */ fe25519_mul(&z2_100_0,&t,&z2_50_0);
+
+ /* 2^101 - 2^1 */ fe25519_square(&t,&z2_100_0);
+ /* 2^200 - 2^100 */ for (i = 1;i < 100;i++) { fe25519_square(&t,&t); }
+ /* 2^200 - 2^0 */ fe25519_mul(&t,&t,&z2_100_0);
+
+ /* 2^201 - 2^1 */ fe25519_square(&t,&t);
+ /* 2^250 - 2^50 */ for (i = 1;i < 50;i++) { fe25519_square(&t,&t); }
+ /* 2^250 - 2^0 */ fe25519_mul(&t,&t,&z2_50_0);
+
+ /* 2^251 - 2^1 */ fe25519_square(&t,&t);
+ /* 2^252 - 2^2 */ fe25519_square(&t,&t);
+ /* 2^252 - 3 */ fe25519_mul(r,&t,x);
+}
+
+typedef struct
+{
+ crypto_uint32 v[32];
+}
+sc25519;
+
+typedef struct
+{
+ crypto_uint32 v[16];
+}
+shortsc25519;
+
+static const crypto_uint32 m[32] = {0xED, 0xD3, 0xF5, 0x5C, 0x1A, 0x63, 0x12, 0x58, 0xD6, 0x9C, 0xF7, 0xA2, 0xDE, 0xF9, 0xDE, 0x14,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+static const crypto_uint32 mu[33] = {0x1B, 0x13, 0x2C, 0x0A, 0xA3, 0xE5, 0x9C, 0xED, 0xA7, 0x29, 0x63, 0x08, 0x5D, 0x21, 0x06, 0x21,
+ 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F};
+
+static inline crypto_uint32 lt(crypto_uint32 a,crypto_uint32 b) /* 16-bit inputs */
+{
+ unsigned int x = a;
+ x -= (unsigned int) b; /* 0..65535: no; 4294901761..4294967295: yes */
+ x >>= 31; /* 0: no; 1: yes */
+ return x;
+}
+
+/* Reduce coefficients of r before calling reduce_add_sub */
+static inline void reduce_add_sub(sc25519 *r)
+{
+ crypto_uint32 pb = 0;
+ crypto_uint32 b;
+ crypto_uint32 mask;
+ int i;
+ unsigned char t[32];
+
+ for(i=0;i<32;i++)
+ {
+ pb += m[i];
+ b = lt(r->v[i],pb);
+ t[i] = r->v[i]-pb+(b<<8);
+ pb = b;
+ }
+ mask = b - 1;
+ for(i=0;i<32;i++)
+ r->v[i] ^= mask & (r->v[i] ^ t[i]);
+}
+
+/* Reduce coefficients of x before calling barrett_reduce */
+static inline void barrett_reduce(sc25519 *r, const crypto_uint32 x[64])
+{
+ /* See HAC, Alg. 14.42 */
+ int i,j;
+ crypto_uint32 q2[66];
+ crypto_uint32 *q3 = q2 + 33;
+ crypto_uint32 r1[33];
+ crypto_uint32 r2[33];
+ crypto_uint32 carry;
+ crypto_uint32 pb = 0;
+ crypto_uint32 b;
+
+ for (i = 0;i < 66;++i) q2[i] = 0;
+ for (i = 0;i < 33;++i) r2[i] = 0;
+
+ for(i=0;i<33;i++)
+ for(j=0;j<33;j++)
+ if(i+j >= 31) q2[i+j] += mu[i]*x[j+31];
+ carry = q2[31] >> 8;
+ q2[32] += carry;
+ carry = q2[32] >> 8;
+ q2[33] += carry;
+
+ for(i=0;i<33;i++)r1[i] = x[i];
+ for(i=0;i<32;i++)
+ for(j=0;j<33;j++)
+ if(i+j < 33) r2[i+j] += m[i]*q3[j];
+
+ for(i=0;i<32;i++)
+ {
+ carry = r2[i] >> 8;
+ r2[i+1] += carry;
+ r2[i] &= 0xff;
+ }
+
+ for(i=0;i<32;i++)
+ {
+ pb += r2[i];
+ b = lt(r1[i],pb);
+ r->v[i] = r1[i]-pb+(b<<8);
+ pb = b;
+ }
+
+ /* XXX: Can it really happen that r<0?, See HAC, Alg 14.42, Step 3
+ * If so: Handle it here!
+ */
+
+ reduce_add_sub(r);
+ reduce_add_sub(r);
+}
+
+static inline void sc25519_from32bytes(sc25519 *r, const unsigned char x[32])
+{
+ int i;
+ crypto_uint32 t[64];
+ for(i=0;i<32;i++) t[i] = x[i];
+ for(i=32;i<64;++i) t[i] = 0;
+ barrett_reduce(r, t);
+}
+
+#if 0
+static void shortsc25519_from16bytes(shortsc25519 *r, const unsigned char x[16])
+{
+ int i;
+ for(i=0;i<16;i++) r->v[i] = x[i];
+}
+#endif
+
+static inline void sc25519_from64bytes(sc25519 *r, const unsigned char x[64])
+{
+ int i;
+ crypto_uint32 t[64];
+ for(i=0;i<64;i++) t[i] = x[i];
+ barrett_reduce(r, t);
+}
+
+#if 0
+static void sc25519_from_shortsc(sc25519 *r, const shortsc25519 *x)
+{
+ int i;
+ for(i=0;i<16;i++)
+ r->v[i] = x->v[i];
+ for(i=0;i<16;i++)
+ r->v[16+i] = 0;
+}
+#endif
+
+static inline void sc25519_to32bytes(unsigned char r[32], const sc25519 *x)
+{
+ int i;
+ for(i=0;i<32;i++) r[i] = x->v[i];
+}
+
+#if 0
+static int sc25519_iszero_vartime(const sc25519 *x)
+{
+ int i;
+ for(i=0;i<32;i++)
+ if(x->v[i] != 0) return 0;
+ return 1;
+}
+#endif
+
+#if 0
+static int sc25519_isshort_vartime(const sc25519 *x)
+{
+ int i;
+ for(i=31;i>15;i--)
+ if(x->v[i] != 0) return 0;
+ return 1;
+}
+#endif
+
+#if 0
+static int sc25519_lt_vartime(const sc25519 *x, const sc25519 *y)
+{
+ int i;
+ for(i=31;i>=0;i--)
+ {
+ if(x->v[i] < y->v[i]) return 1;
+ if(x->v[i] > y->v[i]) return 0;
+ }
+ return 0;
+}
+#endif
+
+static inline void sc25519_add(sc25519 *r, const sc25519 *x, const sc25519 *y)
+{
+ int i, carry;
+ for(i=0;i<32;i++) r->v[i] = x->v[i] + y->v[i];
+ for(i=0;i<31;i++)
+ {
+ carry = r->v[i] >> 8;
+ r->v[i+1] += carry;
+ r->v[i] &= 0xff;
+ }
+ reduce_add_sub(r);
+}
+
+#if 0
+static void sc25519_sub_nored(sc25519 *r, const sc25519 *x, const sc25519 *y)
+{
+ crypto_uint32 b = 0;
+ crypto_uint32 t;
+ int i;
+ for(i=0;i<32;i++)
+ {
+ t = x->v[i] - y->v[i] - b;
+ r->v[i] = t & 255;
+ b = (t >> 8) & 1;
+ }
+}
+#endif
+
+static inline void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
+{
+ int i,j,carry;
+ crypto_uint32 t[64];
+ for(i=0;i<64;i++)t[i] = 0;
+
+ for(i=0;i<32;i++)
+ for(j=0;j<32;j++)
+ t[i+j] += x->v[i] * y->v[j];
+
+ /* Reduce coefficients */
+ for(i=0;i<63;i++)
+ {
+ carry = t[i] >> 8;
+ t[i+1] += carry;
+ t[i] &= 0xff;
+ }
+
+ barrett_reduce(r, t);
+}
+
+#if 0
+static void sc25519_mul_shortsc(sc25519 *r, const sc25519 *x, const shortsc25519 *y)
+{
+ sc25519 t;
+ sc25519_from_shortsc(&t, y);
+ sc25519_mul(r, x, &t);
+}
+#endif
+
+static inline void sc25519_window3(signed char r[85], const sc25519 *s)
+{
+ char carry;
+ int i;
+ for(i=0;i<10;i++)
+ {
+ r[8*i+0] = s->v[3*i+0] & 7;
+ r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
+ r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
+ r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
+ r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
+ r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
+ r[8*i+5] = (s->v[3*i+1] >> 7) & 7;
+ r[8*i+5] ^= (s->v[3*i+2] << 1) & 7;
+ r[8*i+6] = (s->v[3*i+2] >> 2) & 7;
+ r[8*i+7] = (s->v[3*i+2] >> 5) & 7;
+ }
+ r[8*i+0] = s->v[3*i+0] & 7;
+ r[8*i+1] = (s->v[3*i+0] >> 3) & 7;
+ r[8*i+2] = (s->v[3*i+0] >> 6) & 7;
+ r[8*i+2] ^= (s->v[3*i+1] << 2) & 7;
+ r[8*i+3] = (s->v[3*i+1] >> 1) & 7;
+ r[8*i+4] = (s->v[3*i+1] >> 4) & 7;
+
+ /* Making it signed */
+ carry = 0;
+ for(i=0;i<84;i++)
+ {
+ r[i] += carry;
+ r[i+1] += r[i] >> 3;
+ r[i] &= 7;
+ carry = r[i] >> 2;
+ r[i] -= carry<<3;
+ }
+ r[84] += carry;
+}
+
+#if 0
+static void sc25519_window5(signed char r[51], const sc25519 *s)
+{
+ char carry;
+ int i;
+ for(i=0;i<6;i++)
+ {
+ r[8*i+0] = s->v[5*i+0] & 31;
+ r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
+ r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
+ r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
+ r[8*i+3] = (s->v[5*i+1] >> 7) & 31;
+ r[8*i+3] ^= (s->v[5*i+2] << 1) & 31;
+ r[8*i+4] = (s->v[5*i+2] >> 4) & 31;
+ r[8*i+4] ^= (s->v[5*i+3] << 4) & 31;
+ r[8*i+5] = (s->v[5*i+3] >> 1) & 31;
+ r[8*i+6] = (s->v[5*i+3] >> 6) & 31;
+ r[8*i+6] ^= (s->v[5*i+4] << 2) & 31;
+ r[8*i+7] = (s->v[5*i+4] >> 3) & 31;
+ }
+ r[8*i+0] = s->v[5*i+0] & 31;
+ r[8*i+1] = (s->v[5*i+0] >> 5) & 31;
+ r[8*i+1] ^= (s->v[5*i+1] << 3) & 31;
+ r[8*i+2] = (s->v[5*i+1] >> 2) & 31;
+
+ /* Making it signed */
+ carry = 0;
+ for(i=0;i<50;i++)
+ {
+ r[i] += carry;
+ r[i+1] += r[i] >> 5;
+ r[i] &= 31;
+ carry = r[i] >> 4;
+ r[i] -= carry<<5;
+ }
+ r[50] += carry;
+}
+#endif
+
+static inline void sc25519_2interleave2(unsigned char r[127], const sc25519 *s1, const sc25519 *s2)
+{
+ int i;
+ for(i=0;i<31;i++)
+ {
+ r[4*i] = ( s1->v[i] & 3) ^ (( s2->v[i] & 3) << 2);
+ r[4*i+1] = ((s1->v[i] >> 2) & 3) ^ (((s2->v[i] >> 2) & 3) << 2);
+ r[4*i+2] = ((s1->v[i] >> 4) & 3) ^ (((s2->v[i] >> 4) & 3) << 2);
+ r[4*i+3] = ((s1->v[i] >> 6) & 3) ^ (((s2->v[i] >> 6) & 3) << 2);
+ }
+ r[124] = ( s1->v[31] & 3) ^ (( s2->v[31] & 3) << 2);
+ r[125] = ((s1->v[31] >> 2) & 3) ^ (((s2->v[31] >> 2) & 3) << 2);
+ r[126] = ((s1->v[31] >> 4) & 3) ^ (((s2->v[31] >> 4) & 3) << 2);
+}
+
+typedef struct
+{
+ fe25519 x;
+ fe25519 y;
+ fe25519 z;
+ fe25519 t;
+} ge25519;
+
+/* d */
+static const fe25519 ge25519_ecd = {{0xA3, 0x78, 0x59, 0x13, 0xCA, 0x4D, 0xEB, 0x75, 0xAB, 0xD8, 0x41, 0x41, 0x4D, 0x0A, 0x70, 0x00,
+ 0x98, 0xE8, 0x79, 0x77, 0x79, 0x40, 0xC7, 0x8C, 0x73, 0xFE, 0x6F, 0x2B, 0xEE, 0x6C, 0x03, 0x52}};
+/* 2*d */
+static const fe25519 ge25519_ec2d = {{0x59, 0xF1, 0xB2, 0x26, 0x94, 0x9B, 0xD6, 0xEB, 0x56, 0xB1, 0x83, 0x82, 0x9A, 0x14, 0xE0, 0x00,
+ 0x30, 0xD1, 0xF3, 0xEE, 0xF2, 0x80, 0x8E, 0x19, 0xE7, 0xFC, 0xDF, 0x56, 0xDC, 0xD9, 0x06, 0x24}};
+/* sqrt(-1) */
+static const fe25519 ge25519_sqrtm1 = {{0xB0, 0xA0, 0x0E, 0x4A, 0x27, 0x1B, 0xEE, 0xC4, 0x78, 0xE4, 0x2F, 0xAD, 0x06, 0x18, 0x43, 0x2F,
+ 0xA7, 0xD7, 0xFB, 0x3D, 0x99, 0x00, 0x4D, 0x2B, 0x0B, 0xDF, 0xC1, 0x4F, 0x80, 0x24, 0x83, 0x2B}};
+
+#define ge25519_p3 ge25519
+
+typedef struct
+{
+ fe25519 x;
+ fe25519 z;
+ fe25519 y;
+ fe25519 t;
+} ge25519_p1p1;
+
+typedef struct
+{
+ fe25519 x;
+ fe25519 y;
+ fe25519 z;
+} ge25519_p2;
+
+typedef struct
+{
+ fe25519 x;
+ fe25519 y;
+} ge25519_aff;
+
+
+/* Packed coordinates of the base point */
+static const ge25519 ge25519_base = {{{0x1A, 0xD5, 0x25, 0x8F, 0x60, 0x2D, 0x56, 0xC9, 0xB2, 0xA7, 0x25, 0x95, 0x60, 0xC7, 0x2C, 0x69,
+ 0x5C, 0xDC, 0xD6, 0xFD, 0x31, 0xE2, 0xA4, 0xC0, 0xFE, 0x53, 0x6E, 0xCD, 0xD3, 0x36, 0x69, 0x21}},
+ {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0xA3, 0xDD, 0xB7, 0xA5, 0xB3, 0x8A, 0xDE, 0x6D, 0xF5, 0x52, 0x51, 0x77, 0x80, 0x9F, 0xF0, 0x20,
+ 0x7D, 0xE3, 0xAB, 0x64, 0x8E, 0x4E, 0xEA, 0x66, 0x65, 0x76, 0x8B, 0xD7, 0x0F, 0x5F, 0x87, 0x67}}};
+
+/* Multiples of the base point in affine representation */
+static const ge25519_aff ge25519_base_multiples_affine[425] = {
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21}} ,
+ {{0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}}},
+{{{0x0e, 0xce, 0x43, 0x28, 0x4e, 0xa1, 0xc5, 0x83, 0x5f, 0xa4, 0xd7, 0x15, 0x45, 0x8e, 0x0d, 0x08, 0xac, 0xe7, 0x33, 0x18, 0x7d, 0x3b, 0x04, 0x3d, 0x6c, 0x04, 0x5a, 0x9f, 0x4c, 0x38, 0xab, 0x36}} ,
+ {{0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0x0e, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22}}},
+{{{0x5c, 0xe2, 0xf8, 0xd3, 0x5f, 0x48, 0x62, 0xac, 0x86, 0x48, 0x62, 0x81, 0x19, 0x98, 0x43, 0x63, 0x3a, 0xc8, 0xda, 0x3e, 0x74, 0xae, 0xf4, 0x1f, 0x49, 0x8f, 0x92, 0x22, 0x4a, 0x9c, 0xae, 0x67}} ,
+ {{0xd4, 0xb4, 0xf5, 0x78, 0x48, 0x68, 0xc3, 0x02, 0x04, 0x03, 0x24, 0x67, 0x17, 0xec, 0x16, 0x9f, 0xf7, 0x9e, 0x26, 0x60, 0x8e, 0xa1, 0x26, 0xa1, 0xab, 0x69, 0xee, 0x77, 0xd1, 0xb1, 0x67, 0x12}}},
+{{{0x70, 0xf8, 0xc9, 0xc4, 0x57, 0xa6, 0x3a, 0x49, 0x47, 0x15, 0xce, 0x93, 0xc1, 0x9e, 0x73, 0x1a, 0xf9, 0x20, 0x35, 0x7a, 0xb8, 0xd4, 0x25, 0x83, 0x46, 0xf1, 0xcf, 0x56, 0xdb, 0xa8, 0x3d, 0x20}} ,
+ {{0x2f, 0x11, 0x32, 0xca, 0x61, 0xab, 0x38, 0xdf, 0xf0, 0x0f, 0x2f, 0xea, 0x32, 0x28, 0xf2, 0x4c, 0x6c, 0x71, 0xd5, 0x80, 0x85, 0xb8, 0x0e, 0x47, 0xe1, 0x95, 0x15, 0xcb, 0x27, 0xe8, 0xd0, 0x47}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xc8, 0x84, 0xa5, 0x08, 0xbc, 0xfd, 0x87, 0x3b, 0x99, 0x8b, 0x69, 0x80, 0x7b, 0xc6, 0x3a, 0xeb, 0x93, 0xcf, 0x4e, 0xf8, 0x5c, 0x2d, 0x86, 0x42, 0xb6, 0x71, 0xd7, 0x97, 0x5f, 0xe1, 0x42, 0x67}} ,
+ {{0xb4, 0xb9, 0x37, 0xfc, 0xa9, 0x5b, 0x2f, 0x1e, 0x93, 0xe4, 0x1e, 0x62, 0xfc, 0x3c, 0x78, 0x81, 0x8f, 0xf3, 0x8a, 0x66, 0x09, 0x6f, 0xad, 0x6e, 0x79, 0x73, 0xe5, 0xc9, 0x00, 0x06, 0xd3, 0x21}}},
+{{{0xf8, 0xf9, 0x28, 0x6c, 0x6d, 0x59, 0xb2, 0x59, 0x74, 0x23, 0xbf, 0xe7, 0x33, 0x8d, 0x57, 0x09, 0x91, 0x9c, 0x24, 0x08, 0x15, 0x2b, 0xe2, 0xb8, 0xee, 0x3a, 0xe5, 0x27, 0x06, 0x86, 0xa4, 0x23}} ,
+ {{0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70}}},
+{{{0x81, 0x6b, 0x88, 0xe8, 0x1e, 0xc7, 0x77, 0x96, 0x0e, 0xa1, 0xa9, 0x52, 0xe0, 0xd8, 0x0e, 0x61, 0x9e, 0x79, 0x2d, 0x95, 0x9c, 0x8d, 0x96, 0xe0, 0x06, 0x40, 0x5d, 0x87, 0x28, 0x5f, 0x98, 0x70}} ,
+ {{0xf1, 0x79, 0x7b, 0xed, 0x4f, 0x44, 0xb2, 0xe7, 0x08, 0x0d, 0xc2, 0x08, 0x12, 0xd2, 0x9f, 0xdf, 0xcd, 0x93, 0x20, 0x8a, 0xcf, 0x33, 0xca, 0x6d, 0x89, 0xb9, 0x77, 0xc8, 0x93, 0x1b, 0x4e, 0x60}}},
+{{{0x26, 0x4f, 0x7e, 0x97, 0xf6, 0x40, 0xdd, 0x4f, 0xfc, 0x52, 0x78, 0xf9, 0x90, 0x31, 0x03, 0xe6, 0x7d, 0x56, 0x39, 0x0b, 0x1d, 0x56, 0x82, 0x85, 0xf9, 0x1a, 0x42, 0x17, 0x69, 0x6c, 0xcf, 0x39}} ,
+ {{0x69, 0xd2, 0x06, 0x3a, 0x4f, 0x39, 0x2d, 0xf9, 0x38, 0x40, 0x8c, 0x4c, 0xe7, 0x05, 0x12, 0xb4, 0x78, 0x8b, 0xf8, 0xc0, 0xec, 0x93, 0xde, 0x7a, 0x6b, 0xce, 0x2c, 0xe1, 0x0e, 0xa9, 0x34, 0x44}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x0b, 0xa4, 0x3c, 0xb0, 0x0f, 0x7a, 0x51, 0xf1, 0x78, 0xd6, 0xd9, 0x6a, 0xfd, 0x46, 0xe8, 0xb8, 0xa8, 0x79, 0x1d, 0x87, 0xf9, 0x90, 0xf2, 0x9c, 0x13, 0x29, 0xf8, 0x0b, 0x20, 0x64, 0xfa, 0x05}} ,
+ {{0x26, 0x09, 0xda, 0x17, 0xaf, 0x95, 0xd6, 0xfb, 0x6a, 0x19, 0x0d, 0x6e, 0x5e, 0x12, 0xf1, 0x99, 0x4c, 0xaa, 0xa8, 0x6f, 0x79, 0x86, 0xf4, 0x72, 0x28, 0x00, 0x26, 0xf9, 0xea, 0x9e, 0x19, 0x3d}}},
+{{{0x87, 0xdd, 0xcf, 0xf0, 0x5b, 0x49, 0xa2, 0x5d, 0x40, 0x7a, 0x23, 0x26, 0xa4, 0x7a, 0x83, 0x8a, 0xb7, 0x8b, 0xd2, 0x1a, 0xbf, 0xea, 0x02, 0x24, 0x08, 0x5f, 0x7b, 0xa9, 0xb1, 0xbe, 0x9d, 0x37}} ,
+ {{0xfc, 0x86, 0x4b, 0x08, 0xee, 0xe7, 0xa0, 0xfd, 0x21, 0x45, 0x09, 0x34, 0xc1, 0x61, 0x32, 0x23, 0xfc, 0x9b, 0x55, 0x48, 0x53, 0x99, 0xf7, 0x63, 0xd0, 0x99, 0xce, 0x01, 0xe0, 0x9f, 0xeb, 0x28}}},
+{{{0x47, 0xfc, 0xab, 0x5a, 0x17, 0xf0, 0x85, 0x56, 0x3a, 0x30, 0x86, 0x20, 0x28, 0x4b, 0x8e, 0x44, 0x74, 0x3a, 0x6e, 0x02, 0xf1, 0x32, 0x8f, 0x9f, 0x3f, 0x08, 0x35, 0xe9, 0xca, 0x16, 0x5f, 0x6e}} ,
+ {{0x1c, 0x59, 0x1c, 0x65, 0x5d, 0x34, 0xa4, 0x09, 0xcd, 0x13, 0x9c, 0x70, 0x7d, 0xb1, 0x2a, 0xc5, 0x88, 0xaf, 0x0b, 0x60, 0xc7, 0x9f, 0x34, 0x8d, 0xd6, 0xb7, 0x7f, 0xea, 0x78, 0x65, 0x8d, 0x77}}},
+{{{0x56, 0xa5, 0xc2, 0x0c, 0xdd, 0xbc, 0xb8, 0x20, 0x6d, 0x57, 0x61, 0xb5, 0xfb, 0x78, 0xb5, 0xd4, 0x49, 0x54, 0x90, 0x26, 0xc1, 0xcb, 0xe9, 0xe6, 0xbf, 0xec, 0x1d, 0x4e, 0xed, 0x07, 0x7e, 0x5e}} ,
+ {{0xc7, 0xf6, 0x6c, 0x56, 0x31, 0x20, 0x14, 0x0e, 0xa8, 0xd9, 0x27, 0xc1, 0x9a, 0x3d, 0x1b, 0x7d, 0x0e, 0x26, 0xd3, 0x81, 0xaa, 0xeb, 0xf5, 0x6b, 0x79, 0x02, 0xf1, 0x51, 0x5c, 0x75, 0x55, 0x0f}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x0a, 0x34, 0xcd, 0x82, 0x3c, 0x33, 0x09, 0x54, 0xd2, 0x61, 0x39, 0x30, 0x9b, 0xfd, 0xef, 0x21, 0x26, 0xd4, 0x70, 0xfa, 0xee, 0xf9, 0x31, 0x33, 0x73, 0x84, 0xd0, 0xb3, 0x81, 0xbf, 0xec, 0x2e}} ,
+ {{0xe8, 0x93, 0x8b, 0x00, 0x64, 0xf7, 0x9c, 0xb8, 0x74, 0xe0, 0xe6, 0x49, 0x48, 0x4d, 0x4d, 0x48, 0xb6, 0x19, 0xa1, 0x40, 0xb7, 0xd9, 0x32, 0x41, 0x7c, 0x82, 0x37, 0xa1, 0x2d, 0xdc, 0xd2, 0x54}}},
+{{{0x68, 0x2b, 0x4a, 0x5b, 0xd5, 0xc7, 0x51, 0x91, 0x1d, 0xe1, 0x2a, 0x4b, 0xc4, 0x47, 0xf1, 0xbc, 0x7a, 0xb3, 0xcb, 0xc8, 0xb6, 0x7c, 0xac, 0x90, 0x05, 0xfd, 0xf3, 0xf9, 0x52, 0x3a, 0x11, 0x6b}} ,
+ {{0x3d, 0xc1, 0x27, 0xf3, 0x59, 0x43, 0x95, 0x90, 0xc5, 0x96, 0x79, 0xf5, 0xf4, 0x95, 0x65, 0x29, 0x06, 0x9c, 0x51, 0x05, 0x18, 0xda, 0xb8, 0x2e, 0x79, 0x7e, 0x69, 0x59, 0x71, 0x01, 0xeb, 0x1a}}},
+{{{0x15, 0x06, 0x49, 0xb6, 0x8a, 0x3c, 0xea, 0x2f, 0x34, 0x20, 0x14, 0xc3, 0xaa, 0xd6, 0xaf, 0x2c, 0x3e, 0xbd, 0x65, 0x20, 0xe2, 0x4d, 0x4b, 0x3b, 0xeb, 0x9f, 0x4a, 0xc3, 0xad, 0xa4, 0x3b, 0x60}} ,
+ {{0xbc, 0x58, 0xe6, 0xc0, 0x95, 0x2a, 0x2a, 0x81, 0x9a, 0x7a, 0xf3, 0xd2, 0x06, 0xbe, 0x48, 0xbc, 0x0c, 0xc5, 0x46, 0xe0, 0x6a, 0xd4, 0xac, 0x0f, 0xd9, 0xcc, 0x82, 0x34, 0x2c, 0xaf, 0xdb, 0x1f}}},
+{{{0xf7, 0x17, 0x13, 0xbd, 0xfb, 0xbc, 0xd2, 0xec, 0x45, 0xb3, 0x15, 0x31, 0xe9, 0xaf, 0x82, 0x84, 0x3d, 0x28, 0xc6, 0xfc, 0x11, 0xf5, 0x41, 0xb5, 0x8b, 0xd3, 0x12, 0x76, 0x52, 0xe7, 0x1a, 0x3c}} ,
+ {{0x4e, 0x36, 0x11, 0x07, 0xa2, 0x15, 0x20, 0x51, 0xc4, 0x2a, 0xc3, 0x62, 0x8b, 0x5e, 0x7f, 0xa6, 0x0f, 0xf9, 0x45, 0x85, 0x6c, 0x11, 0x86, 0xb7, 0x7e, 0xe5, 0xd7, 0xf9, 0xc3, 0x91, 0x1c, 0x05}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xea, 0xd6, 0xde, 0x29, 0x3a, 0x00, 0xb9, 0x02, 0x59, 0xcb, 0x26, 0xc4, 0xba, 0x99, 0xb1, 0x97, 0x2f, 0x8e, 0x00, 0x92, 0x26, 0x4f, 0x52, 0xeb, 0x47, 0x1b, 0x89, 0x8b, 0x24, 0xc0, 0x13, 0x7d}} ,
+ {{0xd5, 0x20, 0x5b, 0x80, 0xa6, 0x80, 0x20, 0x95, 0xc3, 0xe9, 0x9f, 0x8e, 0x87, 0x9e, 0x1e, 0x9e, 0x7a, 0xc7, 0xcc, 0x75, 0x6c, 0xa5, 0xf1, 0x91, 0x1a, 0xa8, 0x01, 0x2c, 0xab, 0x76, 0xa9, 0x59}}},
+{{{0xde, 0xc9, 0xb1, 0x31, 0x10, 0x16, 0xaa, 0x35, 0x14, 0x6a, 0xd4, 0xb5, 0x34, 0x82, 0x71, 0xd2, 0x4a, 0x5d, 0x9a, 0x1f, 0x53, 0x26, 0x3c, 0xe5, 0x8e, 0x8d, 0x33, 0x7f, 0xff, 0xa9, 0xd5, 0x17}} ,
+ {{0x89, 0xaf, 0xf6, 0xa4, 0x64, 0xd5, 0x10, 0xe0, 0x1d, 0xad, 0xef, 0x44, 0xbd, 0xda, 0x83, 0xac, 0x7a, 0xa8, 0xf0, 0x1c, 0x07, 0xf9, 0xc3, 0x43, 0x6c, 0x3f, 0xb7, 0xd3, 0x87, 0x22, 0x02, 0x73}}},
+{{{0x64, 0x1d, 0x49, 0x13, 0x2f, 0x71, 0xec, 0x69, 0x87, 0xd0, 0x42, 0xee, 0x13, 0xec, 0xe3, 0xed, 0x56, 0x7b, 0xbf, 0xbd, 0x8c, 0x2f, 0x7d, 0x7b, 0x9d, 0x28, 0xec, 0x8e, 0x76, 0x2f, 0x6f, 0x08}} ,
+ {{0x22, 0xf5, 0x5f, 0x4d, 0x15, 0xef, 0xfc, 0x4e, 0x57, 0x03, 0x36, 0x89, 0xf0, 0xeb, 0x5b, 0x91, 0xd6, 0xe2, 0xca, 0x01, 0xa5, 0xee, 0x52, 0xec, 0xa0, 0x3c, 0x8f, 0x33, 0x90, 0x5a, 0x94, 0x72}}},
+{{{0x8a, 0x4b, 0xe7, 0x38, 0xbc, 0xda, 0xc2, 0xb0, 0x85, 0xe1, 0x4a, 0xfe, 0x2d, 0x44, 0x84, 0xcb, 0x20, 0x6b, 0x2d, 0xbf, 0x11, 0x9c, 0xd7, 0xbe, 0xd3, 0x3e, 0x5f, 0xbf, 0x68, 0xbc, 0xa8, 0x07}} ,
+ {{0x01, 0x89, 0x28, 0x22, 0x6a, 0x78, 0xaa, 0x29, 0x03, 0xc8, 0x74, 0x95, 0x03, 0x3e, 0xdc, 0xbd, 0x07, 0x13, 0xa8, 0xa2, 0x20, 0x2d, 0xb3, 0x18, 0x70, 0x42, 0xfd, 0x7a, 0xc4, 0xd7, 0x49, 0x72}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x02, 0xff, 0x32, 0x2b, 0x5c, 0x93, 0x54, 0x32, 0xe8, 0x57, 0x54, 0x1a, 0x8b, 0x33, 0x60, 0x65, 0xd3, 0x67, 0xa4, 0xc1, 0x26, 0xc4, 0xa4, 0x34, 0x1f, 0x9b, 0xa7, 0xa9, 0xf4, 0xd9, 0x4f, 0x5b}} ,
+ {{0x46, 0x8d, 0xb0, 0x33, 0x54, 0x26, 0x5b, 0x68, 0xdf, 0xbb, 0xc5, 0xec, 0xc2, 0xf9, 0x3c, 0x5a, 0x37, 0xc1, 0x8e, 0x27, 0x47, 0xaa, 0x49, 0x5a, 0xf8, 0xfb, 0x68, 0x04, 0x23, 0xd1, 0xeb, 0x40}}},
+{{{0x65, 0xa5, 0x11, 0x84, 0x8a, 0x67, 0x9d, 0x9e, 0xd1, 0x44, 0x68, 0x7a, 0x34, 0xe1, 0x9f, 0xa3, 0x54, 0xcd, 0x07, 0xca, 0x79, 0x1f, 0x54, 0x2f, 0x13, 0x70, 0x4e, 0xee, 0xa2, 0xfa, 0xe7, 0x5d}} ,
+ {{0x36, 0xec, 0x54, 0xf8, 0xce, 0xe4, 0x85, 0xdf, 0xf6, 0x6f, 0x1d, 0x90, 0x08, 0xbc, 0xe8, 0xc0, 0x92, 0x2d, 0x43, 0x6b, 0x92, 0xa9, 0x8e, 0xab, 0x0a, 0x2e, 0x1c, 0x1e, 0x64, 0x23, 0x9f, 0x2c}}},
+{{{0xa7, 0xd6, 0x2e, 0xd5, 0xcc, 0xd4, 0xcb, 0x5a, 0x3b, 0xa7, 0xf9, 0x46, 0x03, 0x1d, 0xad, 0x2b, 0x34, 0x31, 0x90, 0x00, 0x46, 0x08, 0x82, 0x14, 0xc4, 0xe0, 0x9c, 0xf0, 0xe3, 0x55, 0x43, 0x31}} ,
+ {{0x60, 0xd6, 0xdd, 0x78, 0xe6, 0xd4, 0x22, 0x42, 0x1f, 0x00, 0xf9, 0xb1, 0x6a, 0x63, 0xe2, 0x92, 0x59, 0xd1, 0x1a, 0xb7, 0x00, 0x54, 0x29, 0xc9, 0xc1, 0xf6, 0x6f, 0x7a, 0xc5, 0x3c, 0x5f, 0x65}}},
+{{{0x27, 0x4f, 0xd0, 0x72, 0xb1, 0x11, 0x14, 0x27, 0x15, 0x94, 0x48, 0x81, 0x7e, 0x74, 0xd8, 0x32, 0xd5, 0xd1, 0x11, 0x28, 0x60, 0x63, 0x36, 0x32, 0x37, 0xb5, 0x13, 0x1c, 0xa0, 0x37, 0xe3, 0x74}} ,
+ {{0xf1, 0x25, 0x4e, 0x11, 0x96, 0x67, 0xe6, 0x1c, 0xc2, 0xb2, 0x53, 0xe2, 0xda, 0x85, 0xee, 0xb2, 0x9f, 0x59, 0xf3, 0xba, 0xbd, 0xfa, 0xcf, 0x6e, 0xf9, 0xda, 0xa4, 0xb3, 0x02, 0x8f, 0x64, 0x08}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x34, 0x94, 0xf2, 0x64, 0x54, 0x47, 0x37, 0x07, 0x40, 0x8a, 0x20, 0xba, 0x4a, 0x55, 0xd7, 0x3f, 0x47, 0xba, 0x25, 0x23, 0x14, 0xb0, 0x2c, 0xe8, 0x55, 0xa8, 0xa6, 0xef, 0x51, 0xbd, 0x6f, 0x6a}} ,
+ {{0x71, 0xd6, 0x16, 0x76, 0xb2, 0x06, 0xea, 0x79, 0xf5, 0xc4, 0xc3, 0x52, 0x7e, 0x61, 0xd1, 0xe1, 0xad, 0x70, 0x78, 0x1d, 0x16, 0x11, 0xf8, 0x7c, 0x2b, 0xfc, 0x55, 0x9f, 0x52, 0xf8, 0xf5, 0x16}}},
+{{{0x34, 0x96, 0x9a, 0xf6, 0xc5, 0xe0, 0x14, 0x03, 0x24, 0x0e, 0x4c, 0xad, 0x9e, 0x9a, 0x70, 0x23, 0x96, 0xb2, 0xf1, 0x2e, 0x9d, 0xc3, 0x32, 0x9b, 0x54, 0xa5, 0x73, 0xde, 0x88, 0xb1, 0x3e, 0x24}} ,
+ {{0xf6, 0xe2, 0x4c, 0x1f, 0x5b, 0xb2, 0xaf, 0x82, 0xa5, 0xcf, 0x81, 0x10, 0x04, 0xef, 0xdb, 0xa2, 0xcc, 0x24, 0xb2, 0x7e, 0x0b, 0x7a, 0xeb, 0x01, 0xd8, 0x52, 0xf4, 0x51, 0x89, 0x29, 0x79, 0x37}}},
+{{{0x74, 0xde, 0x12, 0xf3, 0x68, 0xb7, 0x66, 0xc3, 0xee, 0x68, 0xdc, 0x81, 0xb5, 0x55, 0x99, 0xab, 0xd9, 0x28, 0x63, 0x6d, 0x8b, 0x40, 0x69, 0x75, 0x6c, 0xcd, 0x5c, 0x2a, 0x7e, 0x32, 0x7b, 0x29}} ,
+ {{0x02, 0xcc, 0x22, 0x74, 0x4d, 0x19, 0x07, 0xc0, 0xda, 0xb5, 0x76, 0x51, 0x2a, 0xaa, 0xa6, 0x0a, 0x5f, 0x26, 0xd4, 0xbc, 0xaf, 0x48, 0x88, 0x7f, 0x02, 0xbc, 0xf2, 0xe1, 0xcf, 0xe9, 0xdd, 0x15}}},
+{{{0xed, 0xb5, 0x9a, 0x8c, 0x9a, 0xdd, 0x27, 0xf4, 0x7f, 0x47, 0xd9, 0x52, 0xa7, 0xcd, 0x65, 0xa5, 0x31, 0x22, 0xed, 0xa6, 0x63, 0x5b, 0x80, 0x4a, 0xad, 0x4d, 0xed, 0xbf, 0xee, 0x49, 0xb3, 0x06}} ,
+ {{0xf8, 0x64, 0x8b, 0x60, 0x90, 0xe9, 0xde, 0x44, 0x77, 0xb9, 0x07, 0x36, 0x32, 0xc2, 0x50, 0xf5, 0x65, 0xdf, 0x48, 0x4c, 0x37, 0xaa, 0x68, 0xab, 0x9a, 0x1f, 0x3e, 0xff, 0x89, 0x92, 0xa0, 0x07}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x7d, 0x4f, 0x9c, 0x19, 0xc0, 0x4a, 0x31, 0xec, 0xf9, 0xaa, 0xeb, 0xb2, 0x16, 0x9c, 0xa3, 0x66, 0x5f, 0xd1, 0xd4, 0xed, 0xb8, 0x92, 0x1c, 0xab, 0xda, 0xea, 0xd9, 0x57, 0xdf, 0x4c, 0x2a, 0x48}} ,
+ {{0x4b, 0xb0, 0x4e, 0x6e, 0x11, 0x3b, 0x51, 0xbd, 0x6a, 0xfd, 0xe4, 0x25, 0xa5, 0x5f, 0x11, 0x3f, 0x98, 0x92, 0x51, 0x14, 0xc6, 0x5f, 0x3c, 0x0b, 0xa8, 0xf7, 0xc2, 0x81, 0x43, 0xde, 0x91, 0x73}}},
+{{{0x3c, 0x8f, 0x9f, 0x33, 0x2a, 0x1f, 0x43, 0x33, 0x8f, 0x68, 0xff, 0x1f, 0x3d, 0x73, 0x6b, 0xbf, 0x68, 0xcc, 0x7d, 0x13, 0x6c, 0x24, 0x4b, 0xcc, 0x4d, 0x24, 0x0d, 0xfe, 0xde, 0x86, 0xad, 0x3b}} ,
+ {{0x79, 0x51, 0x81, 0x01, 0xdc, 0x73, 0x53, 0xe0, 0x6e, 0x9b, 0xea, 0x68, 0x3f, 0x5c, 0x14, 0x84, 0x53, 0x8d, 0x4b, 0xc0, 0x9f, 0x9f, 0x89, 0x2b, 0x8c, 0xba, 0x86, 0xfa, 0xf2, 0xcd, 0xe3, 0x2d}}},
+{{{0x06, 0xf9, 0x29, 0x5a, 0xdb, 0x3d, 0x84, 0x52, 0xab, 0xcc, 0x6b, 0x60, 0x9d, 0xb7, 0x4a, 0x0e, 0x36, 0x63, 0x91, 0xad, 0xa0, 0x95, 0xb0, 0x97, 0x89, 0x4e, 0xcf, 0x7d, 0x3c, 0xe5, 0x7c, 0x28}} ,
+ {{0x2e, 0x69, 0x98, 0xfd, 0xc6, 0xbd, 0xcc, 0xca, 0xdf, 0x9a, 0x44, 0x7e, 0x9d, 0xca, 0x89, 0x6d, 0xbf, 0x27, 0xc2, 0xf8, 0xcd, 0x46, 0x00, 0x2b, 0xb5, 0x58, 0x4e, 0xb7, 0x89, 0x09, 0xe9, 0x2d}}},
+{{{0x54, 0xbe, 0x75, 0xcb, 0x05, 0xb0, 0x54, 0xb7, 0xe7, 0x26, 0x86, 0x4a, 0xfc, 0x19, 0xcf, 0x27, 0x46, 0xd4, 0x22, 0x96, 0x5a, 0x11, 0xe8, 0xd5, 0x1b, 0xed, 0x71, 0xc5, 0x5d, 0xc8, 0xaf, 0x45}} ,
+ {{0x40, 0x7b, 0x77, 0x57, 0x49, 0x9e, 0x80, 0x39, 0x23, 0xee, 0x81, 0x0b, 0x22, 0xcf, 0xdb, 0x7a, 0x2f, 0x14, 0xb8, 0x57, 0x8f, 0xa1, 0x39, 0x1e, 0x77, 0xfc, 0x0b, 0xa6, 0xbf, 0x8a, 0x0c, 0x6c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x77, 0x3a, 0xd4, 0xd8, 0x27, 0xcf, 0xe8, 0xa1, 0x72, 0x9d, 0xca, 0xdd, 0x0d, 0x96, 0xda, 0x79, 0xed, 0x56, 0x42, 0x15, 0x60, 0xc7, 0x1c, 0x6b, 0x26, 0x30, 0xf6, 0x6a, 0x95, 0x67, 0xf3, 0x0a}} ,
+ {{0xc5, 0x08, 0xa4, 0x2b, 0x2f, 0xbd, 0x31, 0x81, 0x2a, 0xa6, 0xb6, 0xe4, 0x00, 0x91, 0xda, 0x3d, 0xb2, 0xb0, 0x96, 0xce, 0x8a, 0xd2, 0x8d, 0x70, 0xb3, 0xd3, 0x34, 0x01, 0x90, 0x8d, 0x10, 0x21}}},
+{{{0x33, 0x0d, 0xe7, 0xba, 0x4f, 0x07, 0xdf, 0x8d, 0xea, 0x7d, 0xa0, 0xc5, 0xd6, 0xb1, 0xb0, 0xe5, 0x57, 0x1b, 0x5b, 0xf5, 0x45, 0x13, 0x14, 0x64, 0x5a, 0xeb, 0x5c, 0xfc, 0x54, 0x01, 0x76, 0x2b}} ,
+ {{0x02, 0x0c, 0xc2, 0xaf, 0x96, 0x36, 0xfe, 0x4a, 0xe2, 0x54, 0x20, 0x6a, 0xeb, 0xb2, 0x9f, 0x62, 0xd7, 0xce, 0xa2, 0x3f, 0x20, 0x11, 0x34, 0x37, 0xe0, 0x42, 0xed, 0x6f, 0xf9, 0x1a, 0xc8, 0x7d}}},
+{{{0xd8, 0xb9, 0x11, 0xe8, 0x36, 0x3f, 0x42, 0xc1, 0xca, 0xdc, 0xd3, 0xf1, 0xc8, 0x23, 0x3d, 0x4f, 0x51, 0x7b, 0x9d, 0x8d, 0xd8, 0xe4, 0xa0, 0xaa, 0xf3, 0x04, 0xd6, 0x11, 0x93, 0xc8, 0x35, 0x45}} ,
+ {{0x61, 0x36, 0xd6, 0x08, 0x90, 0xbf, 0xa7, 0x7a, 0x97, 0x6c, 0x0f, 0x84, 0xd5, 0x33, 0x2d, 0x37, 0xc9, 0x6a, 0x80, 0x90, 0x3d, 0x0a, 0xa2, 0xaa, 0xe1, 0xb8, 0x84, 0xba, 0x61, 0x36, 0xdd, 0x69}}},
+{{{0x6b, 0xdb, 0x5b, 0x9c, 0xc6, 0x92, 0xbc, 0x23, 0xaf, 0xc5, 0xb8, 0x75, 0xf8, 0x42, 0xfa, 0xd6, 0xb6, 0x84, 0x94, 0x63, 0x98, 0x93, 0x48, 0x78, 0x38, 0xcd, 0xbb, 0x18, 0x34, 0xc3, 0xdb, 0x67}} ,
+ {{0x96, 0xf3, 0x3a, 0x09, 0x56, 0xb0, 0x6f, 0x7c, 0x51, 0x1e, 0x1b, 0x39, 0x48, 0xea, 0xc9, 0x0c, 0x25, 0xa2, 0x7a, 0xca, 0xe7, 0x92, 0xfc, 0x59, 0x30, 0xa3, 0x89, 0x85, 0xdf, 0x6f, 0x43, 0x38}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x79, 0x84, 0x44, 0x19, 0xbd, 0xe9, 0x54, 0xc4, 0xc0, 0x6e, 0x2a, 0xa8, 0xa8, 0x9b, 0x43, 0xd5, 0x71, 0x22, 0x5f, 0xdc, 0x01, 0xfa, 0xdf, 0xb3, 0xb8, 0x47, 0x4b, 0x0a, 0xa5, 0x44, 0xea, 0x29}} ,
+ {{0x05, 0x90, 0x50, 0xaf, 0x63, 0x5f, 0x9d, 0x9e, 0xe1, 0x9d, 0x38, 0x97, 0x1f, 0x6c, 0xac, 0x30, 0x46, 0xb2, 0x6a, 0x19, 0xd1, 0x4b, 0xdb, 0xbb, 0x8c, 0xda, 0x2e, 0xab, 0xc8, 0x5a, 0x77, 0x6c}}},
+{{{0x2b, 0xbe, 0xaf, 0xa1, 0x6d, 0x2f, 0x0b, 0xb1, 0x8f, 0xe3, 0xe0, 0x38, 0xcd, 0x0b, 0x41, 0x1b, 0x4a, 0x15, 0x07, 0xf3, 0x6f, 0xdc, 0xb8, 0xe9, 0xde, 0xb2, 0xa3, 0x40, 0x01, 0xa6, 0x45, 0x1e}} ,
+ {{0x76, 0x0a, 0xda, 0x8d, 0x2c, 0x07, 0x3f, 0x89, 0x7d, 0x04, 0xad, 0x43, 0x50, 0x6e, 0xd2, 0x47, 0xcb, 0x8a, 0xe6, 0x85, 0x1a, 0x24, 0xf3, 0xd2, 0x60, 0xfd, 0xdf, 0x73, 0xa4, 0x0d, 0x73, 0x0e}}},
+{{{0xfd, 0x67, 0x6b, 0x71, 0x9b, 0x81, 0x53, 0x39, 0x39, 0xf4, 0xb8, 0xd5, 0xc3, 0x30, 0x9b, 0x3b, 0x7c, 0xa3, 0xf0, 0xd0, 0x84, 0x21, 0xd6, 0xbf, 0xb7, 0x4c, 0x87, 0x13, 0x45, 0x2d, 0xa7, 0x55}} ,
+ {{0x5d, 0x04, 0xb3, 0x40, 0x28, 0x95, 0x2d, 0x30, 0x83, 0xec, 0x5e, 0xe4, 0xff, 0x75, 0xfe, 0x79, 0x26, 0x9d, 0x1d, 0x36, 0xcd, 0x0a, 0x15, 0xd2, 0x24, 0x14, 0x77, 0x71, 0xd7, 0x8a, 0x1b, 0x04}}},
+{{{0x5d, 0x93, 0xc9, 0xbe, 0xaa, 0x90, 0xcd, 0x9b, 0xfb, 0x73, 0x7e, 0xb0, 0x64, 0x98, 0x57, 0x44, 0x42, 0x41, 0xb1, 0xaf, 0xea, 0xc1, 0xc3, 0x22, 0xff, 0x60, 0x46, 0xcb, 0x61, 0x81, 0x70, 0x61}} ,
+ {{0x0d, 0x82, 0xb9, 0xfe, 0x21, 0xcd, 0xc4, 0xf5, 0x98, 0x0c, 0x4e, 0x72, 0xee, 0x87, 0x49, 0xf8, 0xa1, 0x95, 0xdf, 0x8f, 0x2d, 0xbd, 0x21, 0x06, 0x7c, 0x15, 0xe8, 0x12, 0x6d, 0x93, 0xd6, 0x38}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x91, 0xf7, 0x51, 0xd9, 0xef, 0x7d, 0x42, 0x01, 0x13, 0xe9, 0xb8, 0x7f, 0xa6, 0x49, 0x17, 0x64, 0x21, 0x80, 0x83, 0x2c, 0x63, 0x4c, 0x60, 0x09, 0x59, 0x91, 0x92, 0x77, 0x39, 0x51, 0xf4, 0x48}} ,
+ {{0x60, 0xd5, 0x22, 0x83, 0x08, 0x2f, 0xff, 0x99, 0x3e, 0x69, 0x6d, 0x88, 0xda, 0xe7, 0x5b, 0x52, 0x26, 0x31, 0x2a, 0xe5, 0x89, 0xde, 0x68, 0x90, 0xb6, 0x22, 0x5a, 0xbd, 0xd3, 0x85, 0x53, 0x31}}},
+{{{0xd8, 0xce, 0xdc, 0xf9, 0x3c, 0x4b, 0xa2, 0x1d, 0x2c, 0x2f, 0x36, 0xbe, 0x7a, 0xfc, 0xcd, 0xbc, 0xdc, 0xf9, 0x30, 0xbd, 0xff, 0x05, 0xc7, 0xe4, 0x8e, 0x17, 0x62, 0xf8, 0x4d, 0xa0, 0x56, 0x79}} ,
+ {{0x82, 0xe7, 0xf6, 0xba, 0x53, 0x84, 0x0a, 0xa3, 0x34, 0xff, 0x3c, 0xa3, 0x6a, 0xa1, 0x37, 0xea, 0xdd, 0xb6, 0x95, 0xb3, 0x78, 0x19, 0x76, 0x1e, 0x55, 0x2f, 0x77, 0x2e, 0x7f, 0xc1, 0xea, 0x5e}}},
+{{{0x83, 0xe1, 0x6e, 0xa9, 0x07, 0x33, 0x3e, 0x83, 0xff, 0xcb, 0x1c, 0x9f, 0xb1, 0xa3, 0xb4, 0xc9, 0xe1, 0x07, 0x97, 0xff, 0xf8, 0x23, 0x8f, 0xce, 0x40, 0xfd, 0x2e, 0x5e, 0xdb, 0x16, 0x43, 0x2d}} ,
+ {{0xba, 0x38, 0x02, 0xf7, 0x81, 0x43, 0x83, 0xa3, 0x20, 0x4f, 0x01, 0x3b, 0x8a, 0x04, 0x38, 0x31, 0xc6, 0x0f, 0xc8, 0xdf, 0xd7, 0xfa, 0x2f, 0x88, 0x3f, 0xfc, 0x0c, 0x76, 0xc4, 0xa6, 0x45, 0x72}}},
+{{{0xbb, 0x0c, 0xbc, 0x6a, 0xa4, 0x97, 0x17, 0x93, 0x2d, 0x6f, 0xde, 0x72, 0x10, 0x1c, 0x08, 0x2c, 0x0f, 0x80, 0x32, 0x68, 0x27, 0xd4, 0xab, 0xdd, 0xc5, 0x58, 0x61, 0x13, 0x6d, 0x11, 0x1e, 0x4d}} ,
+ {{0x1a, 0xb9, 0xc9, 0x10, 0xfb, 0x1e, 0x4e, 0xf4, 0x84, 0x4b, 0x8a, 0x5e, 0x7b, 0x4b, 0xe8, 0x43, 0x8c, 0x8f, 0x00, 0xb5, 0x54, 0x13, 0xc5, 0x5c, 0xb6, 0x35, 0x4e, 0x9d, 0xe4, 0x5b, 0x41, 0x6d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x15, 0x7d, 0x12, 0x48, 0x82, 0x14, 0x42, 0xcd, 0x32, 0xd4, 0x4b, 0xc1, 0x72, 0x61, 0x2a, 0x8c, 0xec, 0xe2, 0xf8, 0x24, 0x45, 0x94, 0xe3, 0xbe, 0xdd, 0x67, 0xa8, 0x77, 0x5a, 0xae, 0x5b, 0x4b}} ,
+ {{0xcb, 0x77, 0x9a, 0x20, 0xde, 0xb8, 0x23, 0xd9, 0xa0, 0x0f, 0x8c, 0x7b, 0xa5, 0xcb, 0xae, 0xb6, 0xec, 0x42, 0x67, 0x0e, 0x58, 0xa4, 0x75, 0x98, 0x21, 0x71, 0x84, 0xb3, 0xe0, 0x76, 0x94, 0x73}}},
+{{{0xdf, 0xfc, 0x69, 0x28, 0x23, 0x3f, 0x5b, 0xf8, 0x3b, 0x24, 0x37, 0xf3, 0x1d, 0xd5, 0x22, 0x6b, 0xd0, 0x98, 0xa8, 0x6c, 0xcf, 0xff, 0x06, 0xe1, 0x13, 0xdf, 0xb9, 0xc1, 0x0c, 0xa9, 0xbf, 0x33}} ,
+ {{0xd9, 0x81, 0xda, 0xb2, 0x4f, 0x82, 0x9d, 0x43, 0x81, 0x09, 0xf1, 0xd2, 0x01, 0xef, 0xac, 0xf4, 0x2d, 0x7d, 0x01, 0x09, 0xf1, 0xff, 0xa5, 0x9f, 0xe5, 0xca, 0x27, 0x63, 0xdb, 0x20, 0xb1, 0x53}}},
+{{{0x67, 0x02, 0xe8, 0xad, 0xa9, 0x34, 0xd4, 0xf0, 0x15, 0x81, 0xaa, 0xc7, 0x4d, 0x87, 0x94, 0xea, 0x75, 0xe7, 0x4c, 0x94, 0x04, 0x0e, 0x69, 0x87, 0xe7, 0x51, 0x91, 0x10, 0x03, 0xc7, 0xbe, 0x56}} ,
+ {{0x32, 0xfb, 0x86, 0xec, 0x33, 0x6b, 0x2e, 0x51, 0x2b, 0xc8, 0xfa, 0x6c, 0x70, 0x47, 0x7e, 0xce, 0x05, 0x0c, 0x71, 0xf3, 0xb4, 0x56, 0xa6, 0xdc, 0xcc, 0x78, 0x07, 0x75, 0xd0, 0xdd, 0xb2, 0x6a}}},
+{{{0xc6, 0xef, 0xb9, 0xc0, 0x2b, 0x22, 0x08, 0x1e, 0x71, 0x70, 0xb3, 0x35, 0x9c, 0x7a, 0x01, 0x92, 0x44, 0x9a, 0xf6, 0xb0, 0x58, 0x95, 0xc1, 0x9b, 0x02, 0xed, 0x2d, 0x7c, 0x34, 0x29, 0x49, 0x44}} ,
+ {{0x45, 0x62, 0x1d, 0x2e, 0xff, 0x2a, 0x1c, 0x21, 0xa4, 0x25, 0x7b, 0x0d, 0x8c, 0x15, 0x39, 0xfc, 0x8f, 0x7c, 0xa5, 0x7d, 0x1e, 0x25, 0xa3, 0x45, 0xd6, 0xab, 0xbd, 0xcb, 0xc5, 0x5e, 0x78, 0x77}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xd0, 0xd3, 0x42, 0xed, 0x1d, 0x00, 0x3c, 0x15, 0x2c, 0x9c, 0x77, 0x81, 0xd2, 0x73, 0xd1, 0x06, 0xd5, 0xc4, 0x7f, 0x94, 0xbb, 0x92, 0x2d, 0x2c, 0x4b, 0x45, 0x4b, 0xe9, 0x2a, 0x89, 0x6b, 0x2b}} ,
+ {{0xd2, 0x0c, 0x88, 0xc5, 0x48, 0x4d, 0xea, 0x0d, 0x4a, 0xc9, 0x52, 0x6a, 0x61, 0x79, 0xe9, 0x76, 0xf3, 0x85, 0x52, 0x5c, 0x1b, 0x2c, 0xe1, 0xd6, 0xc4, 0x0f, 0x18, 0x0e, 0x4e, 0xf6, 0x1c, 0x7f}}},
+{{{0xb4, 0x04, 0x2e, 0x42, 0xcb, 0x1f, 0x2b, 0x11, 0x51, 0x7b, 0x08, 0xac, 0xaa, 0x3e, 0x9e, 0x52, 0x60, 0xb7, 0xc2, 0x61, 0x57, 0x8c, 0x84, 0xd5, 0x18, 0xa6, 0x19, 0xfc, 0xb7, 0x75, 0x91, 0x1b}} ,
+ {{0xe8, 0x68, 0xca, 0x44, 0xc8, 0x38, 0x38, 0xcc, 0x53, 0x0a, 0x32, 0x35, 0xcc, 0x52, 0xcb, 0x0e, 0xf7, 0xc5, 0xe7, 0xec, 0x3d, 0x85, 0xcc, 0x58, 0xe2, 0x17, 0x47, 0xff, 0x9f, 0xa5, 0x30, 0x17}}},
+{{{0xe3, 0xae, 0xc8, 0xc1, 0x71, 0x75, 0x31, 0x00, 0x37, 0x41, 0x5c, 0x0e, 0x39, 0xda, 0x73, 0xa0, 0xc7, 0x97, 0x36, 0x6c, 0x5b, 0xf2, 0xee, 0x64, 0x0a, 0x3d, 0x89, 0x1e, 0x1d, 0x49, 0x8c, 0x37}} ,
+ {{0x4c, 0xe6, 0xb0, 0xc1, 0xa5, 0x2a, 0x82, 0x09, 0x08, 0xad, 0x79, 0x9c, 0x56, 0xf6, 0xf9, 0xc1, 0xd7, 0x7c, 0x39, 0x7f, 0x93, 0xca, 0x11, 0x55, 0xbf, 0x07, 0x1b, 0x82, 0x29, 0x69, 0x95, 0x5c}}},
+{{{0x87, 0xee, 0xa6, 0x56, 0x9e, 0xc2, 0x9a, 0x56, 0x24, 0x42, 0x85, 0x4d, 0x98, 0x31, 0x1e, 0x60, 0x4d, 0x87, 0x85, 0x04, 0xae, 0x46, 0x12, 0xf9, 0x8e, 0x7f, 0xe4, 0x7f, 0xf6, 0x1c, 0x37, 0x01}} ,
+ {{0x73, 0x4c, 0xb6, 0xc5, 0xc4, 0xe9, 0x6c, 0x85, 0x48, 0x4a, 0x5a, 0xac, 0xd9, 0x1f, 0x43, 0xf8, 0x62, 0x5b, 0xee, 0x98, 0x2a, 0x33, 0x8e, 0x79, 0xce, 0x61, 0x06, 0x35, 0xd8, 0xd7, 0xca, 0x71}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x72, 0xd3, 0xae, 0xa6, 0xca, 0x8f, 0xcd, 0xcc, 0x78, 0x8e, 0x19, 0x4d, 0xa7, 0xd2, 0x27, 0xe9, 0xa4, 0x3c, 0x16, 0x5b, 0x84, 0x80, 0xf9, 0xd0, 0xcc, 0x6a, 0x1e, 0xca, 0x1e, 0x67, 0xbd, 0x63}} ,
+ {{0x7b, 0x6e, 0x2a, 0xd2, 0x87, 0x48, 0xff, 0xa1, 0xca, 0xe9, 0x15, 0x85, 0xdc, 0xdb, 0x2c, 0x39, 0x12, 0x91, 0xa9, 0x20, 0xaa, 0x4f, 0x29, 0xf4, 0x15, 0x7a, 0xd2, 0xf5, 0x32, 0xcc, 0x60, 0x04}}},
+{{{0xe5, 0x10, 0x47, 0x3b, 0xfa, 0x90, 0xfc, 0x30, 0xb5, 0xea, 0x6f, 0x56, 0x8f, 0xfb, 0x0e, 0xa7, 0x3b, 0xc8, 0xb2, 0xff, 0x02, 0x7a, 0x33, 0x94, 0x93, 0x2a, 0x03, 0xe0, 0x96, 0x3a, 0x6c, 0x0f}} ,
+ {{0x5a, 0x63, 0x67, 0xe1, 0x9b, 0x47, 0x78, 0x9f, 0x38, 0x79, 0xac, 0x97, 0x66, 0x1d, 0x5e, 0x51, 0xee, 0x24, 0x42, 0xe8, 0x58, 0x4b, 0x8a, 0x03, 0x75, 0x86, 0x37, 0x86, 0xe2, 0x97, 0x4e, 0x3d}}},
+{{{0x3f, 0x75, 0x8e, 0xb4, 0xff, 0xd8, 0xdd, 0xd6, 0x37, 0x57, 0x9d, 0x6d, 0x3b, 0xbd, 0xd5, 0x60, 0x88, 0x65, 0x9a, 0xb9, 0x4a, 0x68, 0x84, 0xa2, 0x67, 0xdd, 0x17, 0x25, 0x97, 0x04, 0x8b, 0x5e}} ,
+ {{0xbb, 0x40, 0x5e, 0xbc, 0x16, 0x92, 0x05, 0xc4, 0xc0, 0x4e, 0x72, 0x90, 0x0e, 0xab, 0xcf, 0x8a, 0xed, 0xef, 0xb9, 0x2d, 0x3b, 0xf8, 0x43, 0x5b, 0xba, 0x2d, 0xeb, 0x2f, 0x52, 0xd2, 0xd1, 0x5a}}},
+{{{0x40, 0xb4, 0xab, 0xe6, 0xad, 0x9f, 0x46, 0x69, 0x4a, 0xb3, 0x8e, 0xaa, 0xea, 0x9c, 0x8a, 0x20, 0x16, 0x5d, 0x8c, 0x13, 0xbd, 0xf6, 0x1d, 0xc5, 0x24, 0xbd, 0x90, 0x2a, 0x1c, 0xc7, 0x13, 0x3b}} ,
+ {{0x54, 0xdc, 0x16, 0x0d, 0x18, 0xbe, 0x35, 0x64, 0x61, 0x52, 0x02, 0x80, 0xaf, 0x05, 0xf7, 0xa6, 0x42, 0xd3, 0x8f, 0x2e, 0x79, 0x26, 0xa8, 0xbb, 0xb2, 0x17, 0x48, 0xb2, 0x7a, 0x0a, 0x89, 0x14}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x20, 0xa8, 0x88, 0xe3, 0x91, 0xc0, 0x6e, 0xbb, 0x8a, 0x27, 0x82, 0x51, 0x83, 0xb2, 0x28, 0xa9, 0x83, 0xeb, 0xa6, 0xa9, 0x4d, 0x17, 0x59, 0x22, 0x54, 0x00, 0x50, 0x45, 0xcb, 0x48, 0x4b, 0x18}} ,
+ {{0x33, 0x7c, 0xe7, 0x26, 0xba, 0x4d, 0x32, 0xfe, 0x53, 0xf4, 0xfa, 0x83, 0xe3, 0xa5, 0x79, 0x66, 0x73, 0xef, 0x80, 0x23, 0x68, 0xc2, 0x60, 0xdd, 0xa9, 0x33, 0xdc, 0x03, 0x7a, 0xe0, 0xe0, 0x3e}}},
+{{{0x34, 0x5c, 0x13, 0xfb, 0xc0, 0xe3, 0x78, 0x2b, 0x54, 0x58, 0x22, 0x9b, 0x76, 0x81, 0x7f, 0x93, 0x9c, 0x25, 0x3c, 0xd2, 0xe9, 0x96, 0x21, 0x26, 0x08, 0xf5, 0xed, 0x95, 0x11, 0xae, 0x04, 0x5a}} ,
+ {{0xb9, 0xe8, 0xc5, 0x12, 0x97, 0x1f, 0x83, 0xfe, 0x3e, 0x94, 0x99, 0xd4, 0x2d, 0xf9, 0x52, 0x59, 0x5c, 0x82, 0xa6, 0xf0, 0x75, 0x7e, 0xe8, 0xec, 0xcc, 0xac, 0x18, 0x21, 0x09, 0x67, 0x66, 0x67}}},
+{{{0xb3, 0x40, 0x29, 0xd1, 0xcb, 0x1b, 0x08, 0x9e, 0x9c, 0xb7, 0x53, 0xb9, 0x3b, 0x71, 0x08, 0x95, 0x12, 0x1a, 0x58, 0xaf, 0x7e, 0x82, 0x52, 0x43, 0x4f, 0x11, 0x39, 0xf4, 0x93, 0x1a, 0x26, 0x05}} ,
+ {{0x6e, 0x44, 0xa3, 0xf9, 0x64, 0xaf, 0xe7, 0x6d, 0x7d, 0xdf, 0x1e, 0xac, 0x04, 0xea, 0x3b, 0x5f, 0x9b, 0xe8, 0x24, 0x9d, 0x0e, 0xe5, 0x2e, 0x3e, 0xdf, 0xa9, 0xf7, 0xd4, 0x50, 0x71, 0xf0, 0x78}}},
+{{{0x3e, 0xa8, 0x38, 0xc2, 0x57, 0x56, 0x42, 0x9a, 0xb1, 0xe2, 0xf8, 0x45, 0xaa, 0x11, 0x48, 0x5f, 0x17, 0xc4, 0x54, 0x27, 0xdc, 0x5d, 0xaa, 0xdd, 0x41, 0xbc, 0xdf, 0x81, 0xb9, 0x53, 0xee, 0x52}} ,
+ {{0xc3, 0xf1, 0xa7, 0x6d, 0xb3, 0x5f, 0x92, 0x6f, 0xcc, 0x91, 0xb8, 0x95, 0x05, 0xdf, 0x3c, 0x64, 0x57, 0x39, 0x61, 0x51, 0xad, 0x8c, 0x38, 0x7b, 0xc8, 0xde, 0x00, 0x34, 0xbe, 0xa1, 0xb0, 0x7e}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x25, 0x24, 0x1d, 0x8a, 0x67, 0x20, 0xee, 0x42, 0xeb, 0x38, 0xed, 0x0b, 0x8b, 0xcd, 0x46, 0x9d, 0x5e, 0x6b, 0x1e, 0x24, 0x9d, 0x12, 0x05, 0x1a, 0xcc, 0x05, 0x4e, 0x92, 0x38, 0xe1, 0x1f, 0x50}} ,
+ {{0x4e, 0xee, 0x1c, 0x91, 0xe6, 0x11, 0xbd, 0x8e, 0x55, 0x1a, 0x18, 0x75, 0x66, 0xaf, 0x4d, 0x7b, 0x0f, 0xae, 0x6d, 0x85, 0xca, 0x82, 0x58, 0x21, 0x9c, 0x18, 0xe0, 0xed, 0xec, 0x22, 0x80, 0x2f}}},
+{{{0x68, 0x3b, 0x0a, 0x39, 0x1d, 0x6a, 0x15, 0x57, 0xfc, 0xf0, 0x63, 0x54, 0xdb, 0x39, 0xdb, 0xe8, 0x5c, 0x64, 0xff, 0xa0, 0x09, 0x4f, 0x3b, 0xb7, 0x32, 0x60, 0x99, 0x94, 0xfd, 0x94, 0x82, 0x2d}} ,
+ {{0x24, 0xf6, 0x5a, 0x44, 0xf1, 0x55, 0x2c, 0xdb, 0xea, 0x7c, 0x84, 0x7c, 0x01, 0xac, 0xe3, 0xfd, 0xc9, 0x27, 0xc1, 0x5a, 0xb9, 0xde, 0x4f, 0x5a, 0x90, 0xdd, 0xc6, 0x67, 0xaa, 0x6f, 0x8a, 0x3a}}},
+{{{0x78, 0x52, 0x87, 0xc9, 0x97, 0x63, 0xb1, 0xdd, 0x54, 0x5f, 0xc1, 0xf8, 0xf1, 0x06, 0xa6, 0xa8, 0xa3, 0x88, 0x82, 0xd4, 0xcb, 0xa6, 0x19, 0xdd, 0xd1, 0x11, 0x87, 0x08, 0x17, 0x4c, 0x37, 0x2a}} ,
+ {{0xa1, 0x0c, 0xf3, 0x08, 0x43, 0xd9, 0x24, 0x1e, 0x83, 0xa7, 0xdf, 0x91, 0xca, 0xbd, 0x69, 0x47, 0x8d, 0x1b, 0xe2, 0xb9, 0x4e, 0xb5, 0xe1, 0x76, 0xb3, 0x1c, 0x93, 0x03, 0xce, 0x5f, 0xb3, 0x5a}}},
+{{{0x1d, 0xda, 0xe4, 0x61, 0x03, 0x50, 0xa9, 0x8b, 0x68, 0x18, 0xef, 0xb2, 0x1c, 0x84, 0x3b, 0xa2, 0x44, 0x95, 0xa3, 0x04, 0x3b, 0xd6, 0x99, 0x00, 0xaf, 0x76, 0x42, 0x67, 0x02, 0x7d, 0x85, 0x56}} ,
+ {{0xce, 0x72, 0x0e, 0x29, 0x84, 0xb2, 0x7d, 0xd2, 0x45, 0xbe, 0x57, 0x06, 0xed, 0x7f, 0xcf, 0xed, 0xcd, 0xef, 0x19, 0xd6, 0xbc, 0x15, 0x79, 0x64, 0xd2, 0x18, 0xe3, 0x20, 0x67, 0x3a, 0x54, 0x0b}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x52, 0xfd, 0x04, 0xc5, 0xfb, 0x99, 0xe7, 0xe8, 0xfb, 0x8c, 0xe1, 0x42, 0x03, 0xef, 0x9d, 0xd9, 0x9e, 0x4d, 0xf7, 0x80, 0xcf, 0x2e, 0xcc, 0x9b, 0x45, 0xc9, 0x7b, 0x7a, 0xbc, 0x37, 0xa8, 0x52}} ,
+ {{0x96, 0x11, 0x41, 0x8a, 0x47, 0x91, 0xfe, 0xb6, 0xda, 0x7a, 0x54, 0x63, 0xd1, 0x14, 0x35, 0x05, 0x86, 0x8c, 0xa9, 0x36, 0x3f, 0xf2, 0x85, 0x54, 0x4e, 0x92, 0xd8, 0x85, 0x01, 0x46, 0xd6, 0x50}}},
+{{{0x53, 0xcd, 0xf3, 0x86, 0x40, 0xe6, 0x39, 0x42, 0x95, 0xd6, 0xcb, 0x45, 0x1a, 0x20, 0xc8, 0x45, 0x4b, 0x32, 0x69, 0x04, 0xb1, 0xaf, 0x20, 0x46, 0xc7, 0x6b, 0x23, 0x5b, 0x69, 0xee, 0x30, 0x3f}} ,
+ {{0x70, 0x83, 0x47, 0xc0, 0xdb, 0x55, 0x08, 0xa8, 0x7b, 0x18, 0x6d, 0xf5, 0x04, 0x5a, 0x20, 0x0c, 0x4a, 0x8c, 0x60, 0xae, 0xae, 0x0f, 0x64, 0x55, 0x55, 0x2e, 0xd5, 0x1d, 0x53, 0x31, 0x42, 0x41}}},
+{{{0xca, 0xfc, 0x88, 0x6b, 0x96, 0x78, 0x0a, 0x8b, 0x83, 0xdc, 0xbc, 0xaf, 0x40, 0xb6, 0x8d, 0x7f, 0xef, 0xb4, 0xd1, 0x3f, 0xcc, 0xa2, 0x74, 0xc9, 0xc2, 0x92, 0x55, 0x00, 0xab, 0xdb, 0xbf, 0x4f}} ,
+ {{0x93, 0x1c, 0x06, 0x2d, 0x66, 0x65, 0x02, 0xa4, 0x97, 0x18, 0xfd, 0x00, 0xe7, 0xab, 0x03, 0xec, 0xce, 0xc1, 0xbf, 0x37, 0xf8, 0x13, 0x53, 0xa5, 0xe5, 0x0c, 0x3a, 0xa8, 0x55, 0xb9, 0xff, 0x68}}},
+{{{0xe4, 0xe6, 0x6d, 0x30, 0x7d, 0x30, 0x35, 0xc2, 0x78, 0x87, 0xf9, 0xfc, 0x6b, 0x5a, 0xc3, 0xb7, 0x65, 0xd8, 0x2e, 0xc7, 0xa5, 0x0c, 0xc6, 0xdc, 0x12, 0xaa, 0xd6, 0x4f, 0xc5, 0x38, 0xbc, 0x0e}} ,
+ {{0xe2, 0x3c, 0x76, 0x86, 0x38, 0xf2, 0x7b, 0x2c, 0x16, 0x78, 0x8d, 0xf5, 0xa4, 0x15, 0xda, 0xdb, 0x26, 0x85, 0xa0, 0x56, 0xdd, 0x1d, 0xe3, 0xb3, 0xfd, 0x40, 0xef, 0xf2, 0xd9, 0xa1, 0xb3, 0x04}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xdb, 0x49, 0x0e, 0xe6, 0x58, 0x10, 0x7a, 0x52, 0xda, 0xb5, 0x7d, 0x37, 0x6a, 0x3e, 0xa1, 0x78, 0xce, 0xc7, 0x1c, 0x24, 0x23, 0xdb, 0x7d, 0xfb, 0x8c, 0x8d, 0xdc, 0x30, 0x67, 0x69, 0x75, 0x3b}} ,
+ {{0xa9, 0xea, 0x6d, 0x16, 0x16, 0x60, 0xf4, 0x60, 0x87, 0x19, 0x44, 0x8c, 0x4a, 0x8b, 0x3e, 0xfb, 0x16, 0x00, 0x00, 0x54, 0xa6, 0x9e, 0x9f, 0xef, 0xcf, 0xd9, 0xd2, 0x4c, 0x74, 0x31, 0xd0, 0x34}}},
+{{{0xa4, 0xeb, 0x04, 0xa4, 0x8c, 0x8f, 0x71, 0x27, 0x95, 0x85, 0x5d, 0x55, 0x4b, 0xb1, 0x26, 0x26, 0xc8, 0xae, 0x6a, 0x7d, 0xa2, 0x21, 0xca, 0xce, 0x38, 0xab, 0x0f, 0xd0, 0xd5, 0x2b, 0x6b, 0x00}} ,
+ {{0xe5, 0x67, 0x0c, 0xf1, 0x3a, 0x9a, 0xea, 0x09, 0x39, 0xef, 0xd1, 0x30, 0xbc, 0x33, 0xba, 0xb1, 0x6a, 0xc5, 0x27, 0x08, 0x7f, 0x54, 0x80, 0x3d, 0xab, 0xf6, 0x15, 0x7a, 0xc2, 0x40, 0x73, 0x72}}},
+{{{0x84, 0x56, 0x82, 0xb6, 0x12, 0x70, 0x7f, 0xf7, 0xf0, 0xbd, 0x5b, 0xa9, 0xd5, 0xc5, 0x5f, 0x59, 0xbf, 0x7f, 0xb3, 0x55, 0x22, 0x02, 0xc9, 0x44, 0x55, 0x87, 0x8f, 0x96, 0x98, 0x64, 0x6d, 0x15}} ,
+ {{0xb0, 0x8b, 0xaa, 0x1e, 0xec, 0xc7, 0xa5, 0x8f, 0x1f, 0x92, 0x04, 0xc6, 0x05, 0xf6, 0xdf, 0xa1, 0xcc, 0x1f, 0x81, 0xf5, 0x0e, 0x9c, 0x57, 0xdc, 0xe3, 0xbb, 0x06, 0x87, 0x1e, 0xfe, 0x23, 0x6c}}},
+{{{0xd8, 0x2b, 0x5b, 0x16, 0xea, 0x20, 0xf1, 0xd3, 0x68, 0x8f, 0xae, 0x5b, 0xd0, 0xa9, 0x1a, 0x19, 0xa8, 0x36, 0xfb, 0x2b, 0x57, 0x88, 0x7d, 0x90, 0xd5, 0xa6, 0xf3, 0xdc, 0x38, 0x89, 0x4e, 0x1f}} ,
+ {{0xcc, 0x19, 0xda, 0x9b, 0x3b, 0x43, 0x48, 0x21, 0x2e, 0x23, 0x4d, 0x3d, 0xae, 0xf8, 0x8c, 0xfc, 0xdd, 0xa6, 0x74, 0x37, 0x65, 0xca, 0xee, 0x1a, 0x19, 0x8e, 0x9f, 0x64, 0x6f, 0x0c, 0x8b, 0x5a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x25, 0xb9, 0xc2, 0xf0, 0x72, 0xb8, 0x15, 0x16, 0xcc, 0x8d, 0x3c, 0x6f, 0x25, 0xed, 0xf4, 0x46, 0x2e, 0x0c, 0x60, 0x0f, 0xe2, 0x84, 0x34, 0x55, 0x89, 0x59, 0x34, 0x1b, 0xf5, 0x8d, 0xfe, 0x08}} ,
+ {{0xf8, 0xab, 0x93, 0xbc, 0x44, 0xba, 0x1b, 0x75, 0x4b, 0x49, 0x6f, 0xd0, 0x54, 0x2e, 0x63, 0xba, 0xb5, 0xea, 0xed, 0x32, 0x14, 0xc9, 0x94, 0xd8, 0xc5, 0xce, 0xf4, 0x10, 0x68, 0xe0, 0x38, 0x27}}},
+{{{0x74, 0x1c, 0x14, 0x9b, 0xd4, 0x64, 0x61, 0x71, 0x5a, 0xb6, 0x21, 0x33, 0x4f, 0xf7, 0x8e, 0xba, 0xa5, 0x48, 0x9a, 0xc7, 0xfa, 0x9a, 0xf0, 0xb4, 0x62, 0xad, 0xf2, 0x5e, 0xcc, 0x03, 0x24, 0x1a}} ,
+ {{0xf5, 0x76, 0xfd, 0xe4, 0xaf, 0xb9, 0x03, 0x59, 0xce, 0x63, 0xd2, 0x3b, 0x1f, 0xcd, 0x21, 0x0c, 0xad, 0x44, 0xa5, 0x97, 0xac, 0x80, 0x11, 0x02, 0x9b, 0x0c, 0xe5, 0x8b, 0xcd, 0xfb, 0x79, 0x77}}},
+{{{0x15, 0xbe, 0x9a, 0x0d, 0xba, 0x38, 0x72, 0x20, 0x8a, 0xf5, 0xbe, 0x59, 0x93, 0x79, 0xb7, 0xf6, 0x6a, 0x0c, 0x38, 0x27, 0x1a, 0x60, 0xf4, 0x86, 0x3b, 0xab, 0x5a, 0x00, 0xa0, 0xce, 0x21, 0x7d}} ,
+ {{0x6c, 0xba, 0x14, 0xc5, 0xea, 0x12, 0x9e, 0x2e, 0x82, 0x63, 0xce, 0x9b, 0x4a, 0xe7, 0x1d, 0xec, 0xf1, 0x2e, 0x51, 0x1c, 0xf4, 0xd0, 0x69, 0x15, 0x42, 0x9d, 0xa3, 0x3f, 0x0e, 0xbf, 0xe9, 0x5c}}},
+{{{0xe4, 0x0d, 0xf4, 0xbd, 0xee, 0x31, 0x10, 0xed, 0xcb, 0x12, 0x86, 0xad, 0xd4, 0x2f, 0x90, 0x37, 0x32, 0xc3, 0x0b, 0x73, 0xec, 0x97, 0x85, 0xa4, 0x01, 0x1c, 0x76, 0x35, 0xfe, 0x75, 0xdd, 0x71}} ,
+ {{0x11, 0xa4, 0x88, 0x9f, 0x3e, 0x53, 0x69, 0x3b, 0x1b, 0xe0, 0xf7, 0xba, 0x9b, 0xad, 0x4e, 0x81, 0x5f, 0xb5, 0x5c, 0xae, 0xbe, 0x67, 0x86, 0x37, 0x34, 0x8e, 0x07, 0x32, 0x45, 0x4a, 0x67, 0x39}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x90, 0x70, 0x58, 0x20, 0x03, 0x1e, 0x67, 0xb2, 0xc8, 0x9b, 0x58, 0xc5, 0xb1, 0xeb, 0x2d, 0x4a, 0xde, 0x82, 0x8c, 0xf2, 0xd2, 0x14, 0xb8, 0x70, 0x61, 0x4e, 0x73, 0xd6, 0x0b, 0x6b, 0x0d, 0x30}} ,
+ {{0x81, 0xfc, 0x55, 0x5c, 0xbf, 0xa7, 0xc4, 0xbd, 0xe2, 0xf0, 0x4b, 0x8f, 0xe9, 0x7d, 0x99, 0xfa, 0xd3, 0xab, 0xbc, 0xc7, 0x83, 0x2b, 0x04, 0x7f, 0x0c, 0x19, 0x43, 0x03, 0x3d, 0x07, 0xca, 0x40}}},
+{{{0xf9, 0xc8, 0xbe, 0x8c, 0x16, 0x81, 0x39, 0x96, 0xf6, 0x17, 0x58, 0xc8, 0x30, 0x58, 0xfb, 0xc2, 0x03, 0x45, 0xd2, 0x52, 0x76, 0xe0, 0x6a, 0x26, 0x28, 0x5c, 0x88, 0x59, 0x6a, 0x5a, 0x54, 0x42}} ,
+ {{0x07, 0xb5, 0x2e, 0x2c, 0x67, 0x15, 0x9b, 0xfb, 0x83, 0x69, 0x1e, 0x0f, 0xda, 0xd6, 0x29, 0xb1, 0x60, 0xe0, 0xb2, 0xba, 0x69, 0xa2, 0x9e, 0xbd, 0xbd, 0xe0, 0x1c, 0xbd, 0xcd, 0x06, 0x64, 0x70}}},
+{{{0x41, 0xfa, 0x8c, 0xe1, 0x89, 0x8f, 0x27, 0xc8, 0x25, 0x8f, 0x6f, 0x5f, 0x55, 0xf8, 0xde, 0x95, 0x6d, 0x2f, 0x75, 0x16, 0x2b, 0x4e, 0x44, 0xfd, 0x86, 0x6e, 0xe9, 0x70, 0x39, 0x76, 0x97, 0x7e}} ,
+ {{0x17, 0x62, 0x6b, 0x14, 0xa1, 0x7c, 0xd0, 0x79, 0x6e, 0xd8, 0x8a, 0xa5, 0x6d, 0x8c, 0x93, 0xd2, 0x3f, 0xec, 0x44, 0x8d, 0x6e, 0x91, 0x01, 0x8c, 0x8f, 0xee, 0x01, 0x8f, 0xc0, 0xb4, 0x85, 0x0e}}},
+{{{0x02, 0x3a, 0x70, 0x41, 0xe4, 0x11, 0x57, 0x23, 0xac, 0xe6, 0xfc, 0x54, 0x7e, 0xcd, 0xd7, 0x22, 0xcb, 0x76, 0x9f, 0x20, 0xce, 0xa0, 0x73, 0x76, 0x51, 0x3b, 0xa4, 0xf8, 0xe3, 0x62, 0x12, 0x6c}} ,
+ {{0x7f, 0x00, 0x9c, 0x26, 0x0d, 0x6f, 0x48, 0x7f, 0x3a, 0x01, 0xed, 0xc5, 0x96, 0xb0, 0x1f, 0x4f, 0xa8, 0x02, 0x62, 0x27, 0x8a, 0x50, 0x8d, 0x9a, 0x8b, 0x52, 0x0f, 0x1e, 0xcf, 0x41, 0x38, 0x19}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xf5, 0x6c, 0xd4, 0x2f, 0x0f, 0x69, 0x0f, 0x87, 0x3f, 0x61, 0x65, 0x1e, 0x35, 0x34, 0x85, 0xba, 0x02, 0x30, 0xac, 0x25, 0x3d, 0xe2, 0x62, 0xf1, 0xcc, 0xe9, 0x1b, 0xc2, 0xef, 0x6a, 0x42, 0x57}} ,
+ {{0x34, 0x1f, 0x2e, 0xac, 0xd1, 0xc7, 0x04, 0x52, 0x32, 0x66, 0xb2, 0x33, 0x73, 0x21, 0x34, 0x54, 0xf7, 0x71, 0xed, 0x06, 0xb0, 0xff, 0xa6, 0x59, 0x6f, 0x8a, 0x4e, 0xfb, 0x02, 0xb0, 0x45, 0x6b}}},
+{{{0xf5, 0x48, 0x0b, 0x03, 0xc5, 0x22, 0x7d, 0x80, 0x08, 0x53, 0xfe, 0x32, 0xb1, 0xa1, 0x8a, 0x74, 0x6f, 0xbd, 0x3f, 0x85, 0xf4, 0xcf, 0xf5, 0x60, 0xaf, 0x41, 0x7e, 0x3e, 0x46, 0xa3, 0x5a, 0x20}} ,
+ {{0xaa, 0x35, 0x87, 0x44, 0x63, 0x66, 0x97, 0xf8, 0x6e, 0x55, 0x0c, 0x04, 0x3e, 0x35, 0x50, 0xbf, 0x93, 0x69, 0xd2, 0x8b, 0x05, 0x55, 0x99, 0xbe, 0xe2, 0x53, 0x61, 0xec, 0xe8, 0x08, 0x0b, 0x32}}},
+{{{0xb3, 0x10, 0x45, 0x02, 0x69, 0x59, 0x2e, 0x97, 0xd9, 0x64, 0xf8, 0xdb, 0x25, 0x80, 0xdc, 0xc4, 0xd5, 0x62, 0x3c, 0xed, 0x65, 0x91, 0xad, 0xd1, 0x57, 0x81, 0x94, 0xaa, 0xa1, 0x29, 0xfc, 0x68}} ,
+ {{0xdd, 0xb5, 0x7d, 0xab, 0x5a, 0x21, 0x41, 0x53, 0xbb, 0x17, 0x79, 0x0d, 0xd1, 0xa8, 0x0c, 0x0c, 0x20, 0x88, 0x09, 0xe9, 0x84, 0xe8, 0x25, 0x11, 0x67, 0x7a, 0x8b, 0x1a, 0xe4, 0x5d, 0xe1, 0x5d}}},
+{{{0x37, 0xea, 0xfe, 0x65, 0x3b, 0x25, 0xe8, 0xe1, 0xc2, 0xc5, 0x02, 0xa4, 0xbe, 0x98, 0x0a, 0x2b, 0x61, 0xc1, 0x9b, 0xe2, 0xd5, 0x92, 0xe6, 0x9e, 0x7d, 0x1f, 0xca, 0x43, 0x88, 0x8b, 0x2c, 0x59}} ,
+ {{0xe0, 0xb5, 0x00, 0x1d, 0x2a, 0x6f, 0xaf, 0x79, 0x86, 0x2f, 0xa6, 0x5a, 0x93, 0xd1, 0xfe, 0xae, 0x3a, 0xee, 0xdb, 0x7c, 0x61, 0xbe, 0x7c, 0x01, 0xf9, 0xfe, 0x52, 0xdc, 0xd8, 0x52, 0xa3, 0x42}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x22, 0xaf, 0x13, 0x37, 0xbd, 0x37, 0x71, 0xac, 0x04, 0x46, 0x63, 0xac, 0xa4, 0x77, 0xed, 0x25, 0x38, 0xe0, 0x15, 0xa8, 0x64, 0x00, 0x0d, 0xce, 0x51, 0x01, 0xa9, 0xbc, 0x0f, 0x03, 0x1c, 0x04}} ,
+ {{0x89, 0xf9, 0x80, 0x07, 0xcf, 0x3f, 0xb3, 0xe9, 0xe7, 0x45, 0x44, 0x3d, 0x2a, 0x7c, 0xe9, 0xe4, 0x16, 0x5c, 0x5e, 0x65, 0x1c, 0xc7, 0x7d, 0xc6, 0x7a, 0xfb, 0x43, 0xee, 0x25, 0x76, 0x46, 0x72}}},
+{{{0x02, 0xa2, 0xed, 0xf4, 0x8f, 0x6b, 0x0b, 0x3e, 0xeb, 0x35, 0x1a, 0xd5, 0x7e, 0xdb, 0x78, 0x00, 0x96, 0x8a, 0xa0, 0xb4, 0xcf, 0x60, 0x4b, 0xd4, 0xd5, 0xf9, 0x2d, 0xbf, 0x88, 0xbd, 0x22, 0x62}} ,
+ {{0x13, 0x53, 0xe4, 0x82, 0x57, 0xfa, 0x1e, 0x8f, 0x06, 0x2b, 0x90, 0xba, 0x08, 0xb6, 0x10, 0x54, 0x4f, 0x7c, 0x1b, 0x26, 0xed, 0xda, 0x6b, 0xdd, 0x25, 0xd0, 0x4e, 0xea, 0x42, 0xbb, 0x25, 0x03}}},
+{{{0x51, 0x16, 0x50, 0x7c, 0xd5, 0x5d, 0xf6, 0x99, 0xe8, 0x77, 0x72, 0x4e, 0xfa, 0x62, 0xcb, 0x76, 0x75, 0x0c, 0xe2, 0x71, 0x98, 0x92, 0xd5, 0xfa, 0x45, 0xdf, 0x5c, 0x6f, 0x1e, 0x9e, 0x28, 0x69}} ,
+ {{0x0d, 0xac, 0x66, 0x6d, 0xc3, 0x8b, 0xba, 0x16, 0xb5, 0xe2, 0xa0, 0x0d, 0x0c, 0xbd, 0xa4, 0x8e, 0x18, 0x6c, 0xf2, 0xdc, 0xf9, 0xdc, 0x4a, 0x86, 0x25, 0x95, 0x14, 0xcb, 0xd8, 0x1a, 0x04, 0x0f}}},
+{{{0x97, 0xa5, 0xdb, 0x8b, 0x2d, 0xaa, 0x42, 0x11, 0x09, 0xf2, 0x93, 0xbb, 0xd9, 0x06, 0x84, 0x4e, 0x11, 0xa8, 0xa0, 0x25, 0x2b, 0xa6, 0x5f, 0xae, 0xc4, 0xb4, 0x4c, 0xc8, 0xab, 0xc7, 0x3b, 0x02}} ,
+ {{0xee, 0xc9, 0x29, 0x0f, 0xdf, 0x11, 0x85, 0xed, 0xce, 0x0d, 0x62, 0x2c, 0x8f, 0x4b, 0xf9, 0x04, 0xe9, 0x06, 0x72, 0x1d, 0x37, 0x20, 0x50, 0xc9, 0x14, 0xeb, 0xec, 0x39, 0xa7, 0x97, 0x2b, 0x4d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x69, 0xd1, 0x39, 0xbd, 0xfb, 0x33, 0xbe, 0xc4, 0xf0, 0x5c, 0xef, 0xf0, 0x56, 0x68, 0xfc, 0x97, 0x47, 0xc8, 0x72, 0xb6, 0x53, 0xa4, 0x0a, 0x98, 0xa5, 0xb4, 0x37, 0x71, 0xcf, 0x66, 0x50, 0x6d}} ,
+ {{0x17, 0xa4, 0x19, 0x52, 0x11, 0x47, 0xb3, 0x5c, 0x5b, 0xa9, 0x2e, 0x22, 0xb4, 0x00, 0x52, 0xf9, 0x57, 0x18, 0xb8, 0xbe, 0x5a, 0xe3, 0xab, 0x83, 0xc8, 0x87, 0x0a, 0x2a, 0xd8, 0x8c, 0xbb, 0x54}}},
+{{{0xa9, 0x62, 0x93, 0x85, 0xbe, 0xe8, 0x73, 0x4a, 0x0e, 0xb0, 0xb5, 0x2d, 0x94, 0x50, 0xaa, 0xd3, 0xb2, 0xea, 0x9d, 0x62, 0x76, 0x3b, 0x07, 0x34, 0x4e, 0x2d, 0x70, 0xc8, 0x9a, 0x15, 0x66, 0x6b}} ,
+ {{0xc5, 0x96, 0xca, 0xc8, 0x22, 0x1a, 0xee, 0x5f, 0xe7, 0x31, 0x60, 0x22, 0x83, 0x08, 0x63, 0xce, 0xb9, 0x32, 0x44, 0x58, 0x5d, 0x3a, 0x9b, 0xe4, 0x04, 0xd5, 0xef, 0x38, 0xef, 0x4b, 0xdd, 0x19}}},
+{{{0x4d, 0xc2, 0x17, 0x75, 0xa1, 0x68, 0xcd, 0xc3, 0xc6, 0x03, 0x44, 0xe3, 0x78, 0x09, 0x91, 0x47, 0x3f, 0x0f, 0xe4, 0x92, 0x58, 0xfa, 0x7d, 0x1f, 0x20, 0x94, 0x58, 0x5e, 0xbc, 0x19, 0x02, 0x6f}} ,
+ {{0x20, 0xd6, 0xd8, 0x91, 0x54, 0xa7, 0xf3, 0x20, 0x4b, 0x34, 0x06, 0xfa, 0x30, 0xc8, 0x6f, 0x14, 0x10, 0x65, 0x74, 0x13, 0x4e, 0xf0, 0x69, 0x26, 0xce, 0xcf, 0x90, 0xf4, 0xd0, 0xc5, 0xc8, 0x64}}},
+{{{0x26, 0xa2, 0x50, 0x02, 0x24, 0x72, 0xf1, 0xf0, 0x4e, 0x2d, 0x93, 0xd5, 0x08, 0xe7, 0xae, 0x38, 0xf7, 0x18, 0xa5, 0x32, 0x34, 0xc2, 0xf0, 0xa6, 0xec, 0xb9, 0x61, 0x7b, 0x64, 0x99, 0xac, 0x71}} ,
+ {{0x25, 0xcf, 0x74, 0x55, 0x1b, 0xaa, 0xa9, 0x38, 0x41, 0x40, 0xd5, 0x95, 0x95, 0xab, 0x1c, 0x5e, 0xbc, 0x41, 0x7e, 0x14, 0x30, 0xbe, 0x13, 0x89, 0xf4, 0xe5, 0xeb, 0x28, 0xc0, 0xc2, 0x96, 0x3a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x2b, 0x77, 0x45, 0xec, 0x67, 0x76, 0x32, 0x4c, 0xb9, 0xdf, 0x25, 0x32, 0x6b, 0xcb, 0xe7, 0x14, 0x61, 0x43, 0xee, 0xba, 0x9b, 0x71, 0xef, 0xd2, 0x48, 0x65, 0xbb, 0x1b, 0x8a, 0x13, 0x1b, 0x22}} ,
+ {{0x84, 0xad, 0x0c, 0x18, 0x38, 0x5a, 0xba, 0xd0, 0x98, 0x59, 0xbf, 0x37, 0xb0, 0x4f, 0x97, 0x60, 0x20, 0xb3, 0x9b, 0x97, 0xf6, 0x08, 0x6c, 0xa4, 0xff, 0xfb, 0xb7, 0xfa, 0x95, 0xb2, 0x51, 0x79}}},
+{{{0x28, 0x5c, 0x3f, 0xdb, 0x6b, 0x18, 0x3b, 0x5c, 0xd1, 0x04, 0x28, 0xde, 0x85, 0x52, 0x31, 0xb5, 0xbb, 0xf6, 0xa9, 0xed, 0xbe, 0x28, 0x4f, 0xb3, 0x7e, 0x05, 0x6a, 0xdb, 0x95, 0x0d, 0x1b, 0x1c}} ,
+ {{0xd5, 0xc5, 0xc3, 0x9a, 0x0a, 0xd0, 0x31, 0x3e, 0x07, 0x36, 0x8e, 0xc0, 0x8a, 0x62, 0xb1, 0xca, 0xd6, 0x0e, 0x1e, 0x9d, 0xef, 0xab, 0x98, 0x4d, 0xbb, 0x6c, 0x05, 0xe0, 0xe4, 0x5d, 0xbd, 0x57}}},
+{{{0xcc, 0x21, 0x27, 0xce, 0xfd, 0xa9, 0x94, 0x8e, 0xe1, 0xab, 0x49, 0xe0, 0x46, 0x26, 0xa1, 0xa8, 0x8c, 0xa1, 0x99, 0x1d, 0xb4, 0x27, 0x6d, 0x2d, 0xc8, 0x39, 0x30, 0x5e, 0x37, 0x52, 0xc4, 0x6e}} ,
+ {{0xa9, 0x85, 0xf4, 0xe7, 0xb0, 0x15, 0x33, 0x84, 0x1b, 0x14, 0x1a, 0x02, 0xd9, 0x3b, 0xad, 0x0f, 0x43, 0x6c, 0xea, 0x3e, 0x0f, 0x7e, 0xda, 0xdd, 0x6b, 0x4c, 0x7f, 0x6e, 0xd4, 0x6b, 0xbf, 0x0f}}},
+{{{0x47, 0x9f, 0x7c, 0x56, 0x7c, 0x43, 0x91, 0x1c, 0xbb, 0x4e, 0x72, 0x3e, 0x64, 0xab, 0xa0, 0xa0, 0xdf, 0xb4, 0xd8, 0x87, 0x3a, 0xbd, 0xa8, 0x48, 0xc9, 0xb8, 0xef, 0x2e, 0xad, 0x6f, 0x84, 0x4f}} ,
+ {{0x2d, 0x2d, 0xf0, 0x1b, 0x7e, 0x2a, 0x6c, 0xf8, 0xa9, 0x6a, 0xe1, 0xf0, 0x99, 0xa1, 0x67, 0x9a, 0xd4, 0x13, 0xca, 0xca, 0xba, 0x27, 0x92, 0xaa, 0xa1, 0x5d, 0x50, 0xde, 0xcc, 0x40, 0x26, 0x0a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x9f, 0x3e, 0xf2, 0xb2, 0x90, 0xce, 0xdb, 0x64, 0x3e, 0x03, 0xdd, 0x37, 0x36, 0x54, 0x70, 0x76, 0x24, 0xb5, 0x69, 0x03, 0xfc, 0xa0, 0x2b, 0x74, 0xb2, 0x05, 0x0e, 0xcc, 0xd8, 0x1f, 0x6a, 0x1f}} ,
+ {{0x19, 0x5e, 0x60, 0x69, 0x58, 0x86, 0xa0, 0x31, 0xbd, 0x32, 0xe9, 0x2c, 0x5c, 0xd2, 0x85, 0xba, 0x40, 0x64, 0xa8, 0x74, 0xf8, 0x0e, 0x1c, 0xb3, 0xa9, 0x69, 0xe8, 0x1e, 0x40, 0x64, 0x99, 0x77}}},
+{{{0x6c, 0x32, 0x4f, 0xfd, 0xbb, 0x5c, 0xbb, 0x8d, 0x64, 0x66, 0x4a, 0x71, 0x1f, 0x79, 0xa3, 0xad, 0x8d, 0xf9, 0xd4, 0xec, 0xcf, 0x67, 0x70, 0xfa, 0x05, 0x4a, 0x0f, 0x6e, 0xaf, 0x87, 0x0a, 0x6f}} ,
+ {{0xc6, 0x36, 0x6e, 0x6c, 0x8c, 0x24, 0x09, 0x60, 0xbe, 0x26, 0xd2, 0x4c, 0x5e, 0x17, 0xca, 0x5f, 0x1d, 0xcc, 0x87, 0xe8, 0x42, 0x6a, 0xcb, 0xcb, 0x7d, 0x92, 0x05, 0x35, 0x81, 0x13, 0x60, 0x6b}}},
+{{{0xf4, 0x15, 0xcd, 0x0f, 0x0a, 0xaf, 0x4e, 0x6b, 0x51, 0xfd, 0x14, 0xc4, 0x2e, 0x13, 0x86, 0x74, 0x44, 0xcb, 0x66, 0x6b, 0xb6, 0x9d, 0x74, 0x56, 0x32, 0xac, 0x8d, 0x8e, 0x8c, 0x8c, 0x8c, 0x39}} ,
+ {{0xca, 0x59, 0x74, 0x1a, 0x11, 0xef, 0x6d, 0xf7, 0x39, 0x5c, 0x3b, 0x1f, 0xfa, 0xe3, 0x40, 0x41, 0x23, 0x9e, 0xf6, 0xd1, 0x21, 0xa2, 0xbf, 0xad, 0x65, 0x42, 0x6b, 0x59, 0x8a, 0xe8, 0xc5, 0x7f}}},
+{{{0x64, 0x05, 0x7a, 0x84, 0x4a, 0x13, 0xc3, 0xf6, 0xb0, 0x6e, 0x9a, 0x6b, 0x53, 0x6b, 0x32, 0xda, 0xd9, 0x74, 0x75, 0xc4, 0xba, 0x64, 0x3d, 0x3b, 0x08, 0xdd, 0x10, 0x46, 0xef, 0xc7, 0x90, 0x1f}} ,
+ {{0x7b, 0x2f, 0x3a, 0xce, 0xc8, 0xa1, 0x79, 0x3c, 0x30, 0x12, 0x44, 0x28, 0xf6, 0xbc, 0xff, 0xfd, 0xf4, 0xc0, 0x97, 0xb0, 0xcc, 0xc3, 0x13, 0x7a, 0xb9, 0x9a, 0x16, 0xe4, 0xcb, 0x4c, 0x34, 0x63}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x07, 0x4e, 0xd3, 0x2d, 0x09, 0x33, 0x0e, 0xd2, 0x0d, 0xbe, 0x3e, 0xe7, 0xe4, 0xaa, 0xb7, 0x00, 0x8b, 0xe8, 0xad, 0xaa, 0x7a, 0x8d, 0x34, 0x28, 0xa9, 0x81, 0x94, 0xc5, 0xe7, 0x42, 0xac, 0x47}} ,
+ {{0x24, 0x89, 0x7a, 0x8f, 0xb5, 0x9b, 0xf0, 0xc2, 0x03, 0x64, 0xd0, 0x1e, 0xf5, 0xa4, 0xb2, 0xf3, 0x74, 0xe9, 0x1a, 0x16, 0xfd, 0xcb, 0x15, 0xea, 0xeb, 0x10, 0x6c, 0x35, 0xd1, 0xc1, 0xa6, 0x28}}},
+{{{0xcc, 0xd5, 0x39, 0xfc, 0xa5, 0xa4, 0xad, 0x32, 0x15, 0xce, 0x19, 0xe8, 0x34, 0x2b, 0x1c, 0x60, 0x91, 0xfc, 0x05, 0xa9, 0xb3, 0xdc, 0x80, 0x29, 0xc4, 0x20, 0x79, 0x06, 0x39, 0xc0, 0xe2, 0x22}} ,
+ {{0xbb, 0xa8, 0xe1, 0x89, 0x70, 0x57, 0x18, 0x54, 0x3c, 0xf6, 0x0d, 0x82, 0x12, 0x05, 0x87, 0x96, 0x06, 0x39, 0xe3, 0xf8, 0xb3, 0x95, 0xe5, 0xd7, 0x26, 0xbf, 0x09, 0x5a, 0x94, 0xf9, 0x1c, 0x63}}},
+{{{0x2b, 0x8c, 0x2d, 0x9a, 0x8b, 0x84, 0xf2, 0x56, 0xfb, 0xad, 0x2e, 0x7f, 0xb7, 0xfc, 0x30, 0xe1, 0x35, 0x89, 0xba, 0x4d, 0xa8, 0x6d, 0xce, 0x8c, 0x8b, 0x30, 0xe0, 0xda, 0x29, 0x18, 0x11, 0x17}} ,
+ {{0x19, 0xa6, 0x5a, 0x65, 0x93, 0xc3, 0xb5, 0x31, 0x22, 0x4f, 0xf3, 0xf6, 0x0f, 0xeb, 0x28, 0xc3, 0x7c, 0xeb, 0xce, 0x86, 0xec, 0x67, 0x76, 0x6e, 0x35, 0x45, 0x7b, 0xd8, 0x6b, 0x92, 0x01, 0x65}}},
+{{{0x3d, 0xd5, 0x9a, 0x64, 0x73, 0x36, 0xb1, 0xd6, 0x86, 0x98, 0x42, 0x3f, 0x8a, 0xf1, 0xc7, 0xf5, 0x42, 0xa8, 0x9c, 0x52, 0xa8, 0xdc, 0xf9, 0x24, 0x3f, 0x4a, 0xa1, 0xa4, 0x5b, 0xe8, 0x62, 0x1a}} ,
+ {{0xc5, 0xbd, 0xc8, 0x14, 0xd5, 0x0d, 0xeb, 0xe1, 0xa5, 0xe6, 0x83, 0x11, 0x09, 0x00, 0x1d, 0x55, 0x83, 0x51, 0x7e, 0x75, 0x00, 0x81, 0xb9, 0xcb, 0xd8, 0xc5, 0xe5, 0xa1, 0xd9, 0x17, 0x6d, 0x1f}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xea, 0xf9, 0xe4, 0xe9, 0xe1, 0x52, 0x3f, 0x51, 0x19, 0x0d, 0xdd, 0xd9, 0x9d, 0x93, 0x31, 0x87, 0x23, 0x09, 0xd5, 0x83, 0xeb, 0x92, 0x09, 0x76, 0x6e, 0xe3, 0xf8, 0xc0, 0xa2, 0x66, 0xb5, 0x36}} ,
+ {{0x3a, 0xbb, 0x39, 0xed, 0x32, 0x02, 0xe7, 0x43, 0x7a, 0x38, 0x14, 0x84, 0xe3, 0x44, 0xd2, 0x5e, 0x94, 0xdd, 0x78, 0x89, 0x55, 0x4c, 0x73, 0x9e, 0xe1, 0xe4, 0x3e, 0x43, 0xd0, 0x4a, 0xde, 0x1b}}},
+{{{0xb2, 0xe7, 0x8f, 0xe3, 0xa3, 0xc5, 0xcb, 0x72, 0xee, 0x79, 0x41, 0xf8, 0xdf, 0xee, 0x65, 0xc5, 0x45, 0x77, 0x27, 0x3c, 0xbd, 0x58, 0xd3, 0x75, 0xe2, 0x04, 0x4b, 0xbb, 0x65, 0xf3, 0xc8, 0x0f}} ,
+ {{0x24, 0x7b, 0x93, 0x34, 0xb5, 0xe2, 0x74, 0x48, 0xcd, 0xa0, 0x0b, 0x92, 0x97, 0x66, 0x39, 0xf4, 0xb0, 0xe2, 0x5d, 0x39, 0x6a, 0x5b, 0x45, 0x17, 0x78, 0x1e, 0xdb, 0x91, 0x81, 0x1c, 0xf9, 0x16}}},
+{{{0x16, 0xdf, 0xd1, 0x5a, 0xd5, 0xe9, 0x4e, 0x58, 0x95, 0x93, 0x5f, 0x51, 0x09, 0xc3, 0x2a, 0xc9, 0xd4, 0x55, 0x48, 0x79, 0xa4, 0xa3, 0xb2, 0xc3, 0x62, 0xaa, 0x8c, 0xe8, 0xad, 0x47, 0x39, 0x1b}} ,
+ {{0x46, 0xda, 0x9e, 0x51, 0x3a, 0xe6, 0xd1, 0xa6, 0xbb, 0x4d, 0x7b, 0x08, 0xbe, 0x8c, 0xd5, 0xf3, 0x3f, 0xfd, 0xf7, 0x44, 0x80, 0x2d, 0x53, 0x4b, 0xd0, 0x87, 0x68, 0xc1, 0xb5, 0xd8, 0xf7, 0x07}}},
+{{{0xf4, 0x10, 0x46, 0xbe, 0xb7, 0xd2, 0xd1, 0xce, 0x5e, 0x76, 0xa2, 0xd7, 0x03, 0xdc, 0xe4, 0x81, 0x5a, 0xf6, 0x3c, 0xde, 0xae, 0x7a, 0x9d, 0x21, 0x34, 0xa5, 0xf6, 0xa9, 0x73, 0xe2, 0x8d, 0x60}} ,
+ {{0xfa, 0x44, 0x71, 0xf6, 0x41, 0xd8, 0xc6, 0x58, 0x13, 0x37, 0xeb, 0x84, 0x0f, 0x96, 0xc7, 0xdc, 0xc8, 0xa9, 0x7a, 0x83, 0xb2, 0x2f, 0x31, 0xb1, 0x1a, 0xd8, 0x98, 0x3f, 0x11, 0xd0, 0x31, 0x3b}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x81, 0xd5, 0x34, 0x16, 0x01, 0xa3, 0x93, 0xea, 0x52, 0x94, 0xec, 0x93, 0xb7, 0x81, 0x11, 0x2d, 0x58, 0xf9, 0xb5, 0x0a, 0xaa, 0x4f, 0xf6, 0x2e, 0x3f, 0x36, 0xbf, 0x33, 0x5a, 0xe7, 0xd1, 0x08}} ,
+ {{0x1a, 0xcf, 0x42, 0xae, 0xcc, 0xb5, 0x77, 0x39, 0xc4, 0x5b, 0x5b, 0xd0, 0x26, 0x59, 0x27, 0xd0, 0x55, 0x71, 0x12, 0x9d, 0x88, 0x3d, 0x9c, 0xea, 0x41, 0x6a, 0xf0, 0x50, 0x93, 0x93, 0xdd, 0x47}}},
+{{{0x6f, 0xc9, 0x51, 0x6d, 0x1c, 0xaa, 0xf5, 0xa5, 0x90, 0x3f, 0x14, 0xe2, 0x6e, 0x8e, 0x64, 0xfd, 0xac, 0xe0, 0x4e, 0x22, 0xe5, 0xc1, 0xbc, 0x29, 0x0a, 0x6a, 0x9e, 0xa1, 0x60, 0xcb, 0x2f, 0x0b}} ,
+ {{0xdc, 0x39, 0x32, 0xf3, 0xa1, 0x44, 0xe9, 0xc5, 0xc3, 0x78, 0xfb, 0x95, 0x47, 0x34, 0x35, 0x34, 0xe8, 0x25, 0xde, 0x93, 0xc6, 0xb4, 0x76, 0x6d, 0x86, 0x13, 0xc6, 0xe9, 0x68, 0xb5, 0x01, 0x63}}},
+{{{0x1f, 0x9a, 0x52, 0x64, 0x97, 0xd9, 0x1c, 0x08, 0x51, 0x6f, 0x26, 0x9d, 0xaa, 0x93, 0x33, 0x43, 0xfa, 0x77, 0xe9, 0x62, 0x9b, 0x5d, 0x18, 0x75, 0xeb, 0x78, 0xf7, 0x87, 0x8f, 0x41, 0xb4, 0x4d}} ,
+ {{0x13, 0xa8, 0x82, 0x3e, 0xe9, 0x13, 0xad, 0xeb, 0x01, 0xca, 0xcf, 0xda, 0xcd, 0xf7, 0x6c, 0xc7, 0x7a, 0xdc, 0x1e, 0x6e, 0xc8, 0x4e, 0x55, 0x62, 0x80, 0xea, 0x78, 0x0c, 0x86, 0xb9, 0x40, 0x51}}},
+{{{0x27, 0xae, 0xd3, 0x0d, 0x4c, 0x8f, 0x34, 0xea, 0x7d, 0x3c, 0xe5, 0x8a, 0xcf, 0x5b, 0x92, 0xd8, 0x30, 0x16, 0xb4, 0xa3, 0x75, 0xff, 0xeb, 0x27, 0xc8, 0x5c, 0x6c, 0xc2, 0xee, 0x6c, 0x21, 0x0b}} ,
+ {{0xc3, 0xba, 0x12, 0x53, 0x2a, 0xaa, 0x77, 0xad, 0x19, 0x78, 0x55, 0x8a, 0x2e, 0x60, 0x87, 0xc2, 0x6e, 0x91, 0x38, 0x91, 0x3f, 0x7a, 0xc5, 0x24, 0x8f, 0x51, 0xc5, 0xde, 0xb0, 0x53, 0x30, 0x56}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x02, 0xfe, 0x54, 0x12, 0x18, 0xca, 0x7d, 0xa5, 0x68, 0x43, 0xa3, 0x6d, 0x14, 0x2a, 0x6a, 0xa5, 0x8e, 0x32, 0xe7, 0x63, 0x4f, 0xe3, 0xc6, 0x44, 0x3e, 0xab, 0x63, 0xca, 0x17, 0x86, 0x74, 0x3f}} ,
+ {{0x1e, 0x64, 0xc1, 0x7d, 0x52, 0xdc, 0x13, 0x5a, 0xa1, 0x9c, 0x4e, 0xee, 0x99, 0x28, 0xbb, 0x4c, 0xee, 0xac, 0xa9, 0x1b, 0x89, 0xa2, 0x38, 0x39, 0x7b, 0xc4, 0x0f, 0x42, 0xe6, 0x89, 0xed, 0x0f}}},
+{{{0xf3, 0x3c, 0x8c, 0x80, 0x83, 0x10, 0x8a, 0x37, 0x50, 0x9c, 0xb4, 0xdf, 0x3f, 0x8c, 0xf7, 0x23, 0x07, 0xd6, 0xff, 0xa0, 0x82, 0x6c, 0x75, 0x3b, 0xe4, 0xb5, 0xbb, 0xe4, 0xe6, 0x50, 0xf0, 0x08}} ,
+ {{0x62, 0xee, 0x75, 0x48, 0x92, 0x33, 0xf2, 0xf4, 0xad, 0x15, 0x7a, 0xa1, 0x01, 0x46, 0xa9, 0x32, 0x06, 0x88, 0xb6, 0x36, 0x47, 0x35, 0xb9, 0xb4, 0x42, 0x85, 0x76, 0xf0, 0x48, 0x00, 0x90, 0x38}}},
+{{{0x51, 0x15, 0x9d, 0xc3, 0x95, 0xd1, 0x39, 0xbb, 0x64, 0x9d, 0x15, 0x81, 0xc1, 0x68, 0xd0, 0xb6, 0xa4, 0x2c, 0x7d, 0x5e, 0x02, 0x39, 0x00, 0xe0, 0x3b, 0xa4, 0xcc, 0xca, 0x1d, 0x81, 0x24, 0x10}} ,
+ {{0xe7, 0x29, 0xf9, 0x37, 0xd9, 0x46, 0x5a, 0xcd, 0x70, 0xfe, 0x4d, 0x5b, 0xbf, 0xa5, 0xcf, 0x91, 0xf4, 0xef, 0xee, 0x8a, 0x29, 0xd0, 0xe7, 0xc4, 0x25, 0x92, 0x8a, 0xff, 0x36, 0xfc, 0xe4, 0x49}}},
+{{{0xbd, 0x00, 0xb9, 0x04, 0x7d, 0x35, 0xfc, 0xeb, 0xd0, 0x0b, 0x05, 0x32, 0x52, 0x7a, 0x89, 0x24, 0x75, 0x50, 0xe1, 0x63, 0x02, 0x82, 0x8e, 0xe7, 0x85, 0x0c, 0xf2, 0x56, 0x44, 0x37, 0x83, 0x25}} ,
+ {{0x8f, 0xa1, 0xce, 0xcb, 0x60, 0xda, 0x12, 0x02, 0x1e, 0x29, 0x39, 0x2a, 0x03, 0xb7, 0xeb, 0x77, 0x40, 0xea, 0xc9, 0x2b, 0x2c, 0xd5, 0x7d, 0x7e, 0x2c, 0xc7, 0x5a, 0xfd, 0xff, 0xc4, 0xd1, 0x62}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x1d, 0x88, 0x98, 0x5b, 0x4e, 0xfc, 0x41, 0x24, 0x05, 0xe6, 0x50, 0x2b, 0xae, 0x96, 0x51, 0xd9, 0x6b, 0x72, 0xb2, 0x33, 0x42, 0x98, 0x68, 0xbb, 0x10, 0x5a, 0x7a, 0x8c, 0x9d, 0x07, 0xb4, 0x05}} ,
+ {{0x2f, 0x61, 0x9f, 0xd7, 0xa8, 0x3f, 0x83, 0x8c, 0x10, 0x69, 0x90, 0xe6, 0xcf, 0xd2, 0x63, 0xa3, 0xe4, 0x54, 0x7e, 0xe5, 0x69, 0x13, 0x1c, 0x90, 0x57, 0xaa, 0xe9, 0x53, 0x22, 0x43, 0x29, 0x23}}},
+{{{0xe5, 0x1c, 0xf8, 0x0a, 0xfd, 0x2d, 0x7e, 0xf5, 0xf5, 0x70, 0x7d, 0x41, 0x6b, 0x11, 0xfe, 0xbe, 0x99, 0xd1, 0x55, 0x29, 0x31, 0xbf, 0xc0, 0x97, 0x6c, 0xd5, 0x35, 0xcc, 0x5e, 0x8b, 0xd9, 0x69}} ,
+ {{0x8e, 0x4e, 0x9f, 0x25, 0xf8, 0x81, 0x54, 0x2d, 0x0e, 0xd5, 0x54, 0x81, 0x9b, 0xa6, 0x92, 0xce, 0x4b, 0xe9, 0x8f, 0x24, 0x3b, 0xca, 0xe0, 0x44, 0xab, 0x36, 0xfe, 0xfb, 0x87, 0xd4, 0x26, 0x3e}}},
+{{{0x0f, 0x93, 0x9c, 0x11, 0xe7, 0xdb, 0xf1, 0xf0, 0x85, 0x43, 0x28, 0x15, 0x37, 0xdd, 0xde, 0x27, 0xdf, 0xad, 0x3e, 0x49, 0x4f, 0xe0, 0x5b, 0xf6, 0x80, 0x59, 0x15, 0x3c, 0x85, 0xb7, 0x3e, 0x12}} ,
+ {{0xf5, 0xff, 0xcc, 0xf0, 0xb4, 0x12, 0x03, 0x5f, 0xc9, 0x84, 0xcb, 0x1d, 0x17, 0xe0, 0xbc, 0xcc, 0x03, 0x62, 0xa9, 0x8b, 0x94, 0xa6, 0xaa, 0x18, 0xcb, 0x27, 0x8d, 0x49, 0xa6, 0x17, 0x15, 0x07}}},
+{{{0xd9, 0xb6, 0xd4, 0x9d, 0xd4, 0x6a, 0xaf, 0x70, 0x07, 0x2c, 0x10, 0x9e, 0xbd, 0x11, 0xad, 0xe4, 0x26, 0x33, 0x70, 0x92, 0x78, 0x1c, 0x74, 0x9f, 0x75, 0x60, 0x56, 0xf4, 0x39, 0xa8, 0xa8, 0x62}} ,
+ {{0x3b, 0xbf, 0x55, 0x35, 0x61, 0x8b, 0x44, 0x97, 0xe8, 0x3a, 0x55, 0xc1, 0xc8, 0x3b, 0xfd, 0x95, 0x29, 0x11, 0x60, 0x96, 0x1e, 0xcb, 0x11, 0x9d, 0xc2, 0x03, 0x8a, 0x1b, 0xc6, 0xd6, 0x45, 0x3d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x7e, 0x0e, 0x50, 0xb2, 0xcc, 0x0d, 0x6b, 0xa6, 0x71, 0x5b, 0x42, 0xed, 0xbd, 0xaf, 0xac, 0xf0, 0xfc, 0x12, 0xa2, 0x3f, 0x4e, 0xda, 0xe8, 0x11, 0xf3, 0x23, 0xe1, 0x04, 0x62, 0x03, 0x1c, 0x4e}} ,
+ {{0xc8, 0xb1, 0x1b, 0x6f, 0x73, 0x61, 0x3d, 0x27, 0x0d, 0x7d, 0x7a, 0x25, 0x5f, 0x73, 0x0e, 0x2f, 0x93, 0xf6, 0x24, 0xd8, 0x4f, 0x90, 0xac, 0xa2, 0x62, 0x0a, 0xf0, 0x61, 0xd9, 0x08, 0x59, 0x6a}}},
+{{{0x6f, 0x2d, 0x55, 0xf8, 0x2f, 0x8e, 0xf0, 0x18, 0x3b, 0xea, 0xdd, 0x26, 0x72, 0xd1, 0xf5, 0xfe, 0xe5, 0xb8, 0xe6, 0xd3, 0x10, 0x48, 0x46, 0x49, 0x3a, 0x9f, 0x5e, 0x45, 0x6b, 0x90, 0xe8, 0x7f}} ,
+ {{0xd3, 0x76, 0x69, 0x33, 0x7b, 0xb9, 0x40, 0x70, 0xee, 0xa6, 0x29, 0x6b, 0xdd, 0xd0, 0x5d, 0x8d, 0xc1, 0x3e, 0x4a, 0xea, 0x37, 0xb1, 0x03, 0x02, 0x03, 0x35, 0xf1, 0x28, 0x9d, 0xff, 0x00, 0x13}}},
+{{{0x7a, 0xdb, 0x12, 0xd2, 0x8a, 0x82, 0x03, 0x1b, 0x1e, 0xaf, 0xf9, 0x4b, 0x9c, 0xbe, 0xae, 0x7c, 0xe4, 0x94, 0x2a, 0x23, 0xb3, 0x62, 0x86, 0xe7, 0xfd, 0x23, 0xaa, 0x99, 0xbd, 0x2b, 0x11, 0x6c}} ,
+ {{0x8d, 0xa6, 0xd5, 0xac, 0x9d, 0xcc, 0x68, 0x75, 0x7f, 0xc3, 0x4d, 0x4b, 0xdd, 0x6c, 0xbb, 0x11, 0x5a, 0x60, 0xe5, 0xbd, 0x7d, 0x27, 0x8b, 0xda, 0xb4, 0x95, 0xf6, 0x03, 0x27, 0xa4, 0x92, 0x3f}}},
+{{{0x22, 0xd6, 0xb5, 0x17, 0x84, 0xbf, 0x12, 0xcc, 0x23, 0x14, 0x4a, 0xdf, 0x14, 0x31, 0xbc, 0xa1, 0xac, 0x6e, 0xab, 0xfa, 0x57, 0x11, 0x53, 0xb3, 0x27, 0xe6, 0xf9, 0x47, 0x33, 0x44, 0x34, 0x1e}} ,
+ {{0x79, 0xfc, 0xa6, 0xb4, 0x0b, 0x35, 0x20, 0xc9, 0x4d, 0x22, 0x84, 0xc4, 0xa9, 0x20, 0xec, 0x89, 0x94, 0xba, 0x66, 0x56, 0x48, 0xb9, 0x87, 0x7f, 0xca, 0x1e, 0x06, 0xed, 0xa5, 0x55, 0x59, 0x29}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x56, 0xe1, 0xf5, 0xf1, 0xd5, 0xab, 0xa8, 0x2b, 0xae, 0x89, 0xf3, 0xcf, 0x56, 0x9f, 0xf2, 0x4b, 0x31, 0xbc, 0x18, 0xa9, 0x06, 0x5b, 0xbe, 0xb4, 0x61, 0xf8, 0xb2, 0x06, 0x9c, 0x81, 0xab, 0x4c}} ,
+ {{0x1f, 0x68, 0x76, 0x01, 0x16, 0x38, 0x2b, 0x0f, 0x77, 0x97, 0x92, 0x67, 0x4e, 0x86, 0x6a, 0x8b, 0xe5, 0xe8, 0x0c, 0xf7, 0x36, 0x39, 0xb5, 0x33, 0xe6, 0xcf, 0x5e, 0xbd, 0x18, 0xfb, 0x10, 0x1f}}},
+{{{0x83, 0xf0, 0x0d, 0x63, 0xef, 0x53, 0x6b, 0xb5, 0x6b, 0xf9, 0x83, 0xcf, 0xde, 0x04, 0x22, 0x9b, 0x2c, 0x0a, 0xe0, 0xa5, 0xd8, 0xc7, 0x9c, 0xa5, 0xa3, 0xf6, 0x6f, 0xcf, 0x90, 0x6b, 0x68, 0x7c}} ,
+ {{0x33, 0x15, 0xd7, 0x7f, 0x1a, 0xd5, 0x21, 0x58, 0xc4, 0x18, 0xa5, 0xf0, 0xcc, 0x73, 0xa8, 0xfd, 0xfa, 0x18, 0xd1, 0x03, 0x91, 0x8d, 0x52, 0xd2, 0xa3, 0xa4, 0xd3, 0xb1, 0xea, 0x1d, 0x0f, 0x00}}},
+{{{0xcc, 0x48, 0x83, 0x90, 0xe5, 0xfd, 0x3f, 0x84, 0xaa, 0xf9, 0x8b, 0x82, 0x59, 0x24, 0x34, 0x68, 0x4f, 0x1c, 0x23, 0xd9, 0xcc, 0x71, 0xe1, 0x7f, 0x8c, 0xaf, 0xf1, 0xee, 0x00, 0xb6, 0xa0, 0x77}} ,
+ {{0xf5, 0x1a, 0x61, 0xf7, 0x37, 0x9d, 0x00, 0xf4, 0xf2, 0x69, 0x6f, 0x4b, 0x01, 0x85, 0x19, 0x45, 0x4d, 0x7f, 0x02, 0x7c, 0x6a, 0x05, 0x47, 0x6c, 0x1f, 0x81, 0x20, 0xd4, 0xe8, 0x50, 0x27, 0x72}}},
+{{{0x2c, 0x3a, 0xe5, 0xad, 0xf4, 0xdd, 0x2d, 0xf7, 0x5c, 0x44, 0xb5, 0x5b, 0x21, 0xa3, 0x89, 0x5f, 0x96, 0x45, 0xca, 0x4d, 0xa4, 0x21, 0x99, 0x70, 0xda, 0xc4, 0xc4, 0xa0, 0xe5, 0xf4, 0xec, 0x0a}} ,
+ {{0x07, 0x68, 0x21, 0x65, 0xe9, 0x08, 0xa0, 0x0b, 0x6a, 0x4a, 0xba, 0xb5, 0x80, 0xaf, 0xd0, 0x1b, 0xc5, 0xf5, 0x4b, 0x73, 0x50, 0x60, 0x2d, 0x71, 0x69, 0x61, 0x0e, 0xc0, 0x20, 0x40, 0x30, 0x19}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xd0, 0x75, 0x57, 0x3b, 0xeb, 0x5c, 0x14, 0x56, 0x50, 0xc9, 0x4f, 0xb8, 0xb8, 0x1e, 0xa3, 0xf4, 0xab, 0xf5, 0xa9, 0x20, 0x15, 0x94, 0x82, 0xda, 0x96, 0x1c, 0x9b, 0x59, 0x8c, 0xff, 0xf4, 0x51}} ,
+ {{0xc1, 0x3a, 0x86, 0xd7, 0xb0, 0x06, 0x84, 0x7f, 0x1b, 0xbd, 0xd4, 0x07, 0x78, 0x80, 0x2e, 0xb1, 0xb4, 0xee, 0x52, 0x38, 0xee, 0x9a, 0xf9, 0xf6, 0xf3, 0x41, 0x6e, 0xd4, 0x88, 0x95, 0xac, 0x35}}},
+{{{0x41, 0x97, 0xbf, 0x71, 0x6a, 0x9b, 0x72, 0xec, 0xf3, 0xf8, 0x6b, 0xe6, 0x0e, 0x6c, 0x69, 0xa5, 0x2f, 0x68, 0x52, 0xd8, 0x61, 0x81, 0xc0, 0x63, 0x3f, 0xa6, 0x3c, 0x13, 0x90, 0xe6, 0x8d, 0x56}} ,
+ {{0xe8, 0x39, 0x30, 0x77, 0x23, 0xb1, 0xfd, 0x1b, 0x3d, 0x3e, 0x74, 0x4d, 0x7f, 0xae, 0x5b, 0x3a, 0xb4, 0x65, 0x0e, 0x3a, 0x43, 0xdc, 0xdc, 0x41, 0x47, 0xe6, 0xe8, 0x92, 0x09, 0x22, 0x48, 0x4c}}},
+{{{0x85, 0x57, 0x9f, 0xb5, 0xc8, 0x06, 0xb2, 0x9f, 0x47, 0x3f, 0xf0, 0xfa, 0xe6, 0xa9, 0xb1, 0x9b, 0x6f, 0x96, 0x7d, 0xf9, 0xa4, 0x65, 0x09, 0x75, 0x32, 0xa6, 0x6c, 0x7f, 0x47, 0x4b, 0x2f, 0x4f}} ,
+ {{0x34, 0xe9, 0x59, 0x93, 0x9d, 0x26, 0x80, 0x54, 0xf2, 0xcc, 0x3c, 0xc2, 0x25, 0x85, 0xe3, 0x6a, 0xc1, 0x62, 0x04, 0xa7, 0x08, 0x32, 0x6d, 0xa1, 0x39, 0x84, 0x8a, 0x3b, 0x87, 0x5f, 0x11, 0x13}}},
+{{{0xda, 0x03, 0x34, 0x66, 0xc4, 0x0c, 0x73, 0x6e, 0xbc, 0x24, 0xb5, 0xf9, 0x70, 0x81, 0x52, 0xe9, 0xf4, 0x7c, 0x23, 0xdd, 0x9f, 0xb8, 0x46, 0xef, 0x1d, 0x22, 0x55, 0x7d, 0x71, 0xc4, 0x42, 0x33}} ,
+ {{0xc5, 0x37, 0x69, 0x5b, 0xa8, 0xc6, 0x9d, 0xa4, 0xfc, 0x61, 0x6e, 0x68, 0x46, 0xea, 0xd7, 0x1c, 0x67, 0xd2, 0x7d, 0xfa, 0xf1, 0xcc, 0x54, 0x8d, 0x36, 0x35, 0xc9, 0x00, 0xdf, 0x6c, 0x67, 0x50}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x9a, 0x4d, 0x42, 0x29, 0x5d, 0xa4, 0x6b, 0x6f, 0xa8, 0x8a, 0x4d, 0x91, 0x7b, 0xd2, 0xdf, 0x36, 0xef, 0x01, 0x22, 0xc5, 0xcc, 0x8d, 0xeb, 0x58, 0x3d, 0xb3, 0x50, 0xfc, 0x8b, 0x97, 0x96, 0x33}} ,
+ {{0x93, 0x33, 0x07, 0xc8, 0x4a, 0xca, 0xd0, 0xb1, 0xab, 0xbd, 0xdd, 0xa7, 0x7c, 0xac, 0x3e, 0x45, 0xcb, 0xcc, 0x07, 0x91, 0xbf, 0x35, 0x9d, 0xcb, 0x7d, 0x12, 0x3c, 0x11, 0x59, 0x13, 0xcf, 0x5c}}},
+{{{0x45, 0xb8, 0x41, 0xd7, 0xab, 0x07, 0x15, 0x00, 0x8e, 0xce, 0xdf, 0xb2, 0x43, 0x5c, 0x01, 0xdc, 0xf4, 0x01, 0x51, 0x95, 0x10, 0x5a, 0xf6, 0x24, 0x24, 0xa0, 0x19, 0x3a, 0x09, 0x2a, 0xaa, 0x3f}} ,
+ {{0xdc, 0x8e, 0xeb, 0xc6, 0xbf, 0xdd, 0x11, 0x7b, 0xe7, 0x47, 0xe6, 0xce, 0xe7, 0xb6, 0xc5, 0xe8, 0x8a, 0xdc, 0x4b, 0x57, 0x15, 0x3b, 0x66, 0xca, 0x89, 0xa3, 0xfd, 0xac, 0x0d, 0xe1, 0x1d, 0x7a}}},
+{{{0x89, 0xef, 0xbf, 0x03, 0x75, 0xd0, 0x29, 0x50, 0xcb, 0x7d, 0xd6, 0xbe, 0xad, 0x5f, 0x7b, 0x00, 0x32, 0xaa, 0x98, 0xed, 0x3f, 0x8f, 0x92, 0xcb, 0x81, 0x56, 0x01, 0x63, 0x64, 0xa3, 0x38, 0x39}} ,
+ {{0x8b, 0xa4, 0xd6, 0x50, 0xb4, 0xaa, 0x5d, 0x64, 0x64, 0x76, 0x2e, 0xa1, 0xa6, 0xb3, 0xb8, 0x7c, 0x7a, 0x56, 0xf5, 0x5c, 0x4e, 0x84, 0x5c, 0xfb, 0xdd, 0xca, 0x48, 0x8b, 0x48, 0xb9, 0xba, 0x34}}},
+{{{0xc5, 0xe3, 0xe8, 0xae, 0x17, 0x27, 0xe3, 0x64, 0x60, 0x71, 0x47, 0x29, 0x02, 0x0f, 0x92, 0x5d, 0x10, 0x93, 0xc8, 0x0e, 0xa1, 0xed, 0xba, 0xa9, 0x96, 0x1c, 0xc5, 0x76, 0x30, 0xcd, 0xf9, 0x30}} ,
+ {{0x95, 0xb0, 0xbd, 0x8c, 0xbc, 0xa7, 0x4f, 0x7e, 0xfd, 0x4e, 0x3a, 0xbf, 0x5f, 0x04, 0x79, 0x80, 0x2b, 0x5a, 0x9f, 0x4f, 0x68, 0x21, 0x19, 0x71, 0xc6, 0x20, 0x01, 0x42, 0xaa, 0xdf, 0xae, 0x2c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x90, 0x6e, 0x7e, 0x4b, 0x71, 0x93, 0xc0, 0x72, 0xed, 0xeb, 0x71, 0x24, 0x97, 0x26, 0x9c, 0xfe, 0xcb, 0x3e, 0x59, 0x19, 0xa8, 0x0f, 0x75, 0x7d, 0xbe, 0x18, 0xe6, 0x96, 0x1e, 0x95, 0x70, 0x60}} ,
+ {{0x89, 0x66, 0x3e, 0x1d, 0x4c, 0x5f, 0xfe, 0xc0, 0x04, 0x43, 0xd6, 0x44, 0x19, 0xb5, 0xad, 0xc7, 0x22, 0xdc, 0x71, 0x28, 0x64, 0xde, 0x41, 0x38, 0x27, 0x8f, 0x2c, 0x6b, 0x08, 0xb8, 0xb8, 0x7b}}},
+{{{0x3d, 0x70, 0x27, 0x9d, 0xd9, 0xaf, 0xb1, 0x27, 0xaf, 0xe3, 0x5d, 0x1e, 0x3a, 0x30, 0x54, 0x61, 0x60, 0xe8, 0xc3, 0x26, 0x3a, 0xbc, 0x7e, 0xf5, 0x81, 0xdd, 0x64, 0x01, 0x04, 0xeb, 0xc0, 0x1e}} ,
+ {{0xda, 0x2c, 0xa4, 0xd1, 0xa1, 0xc3, 0x5c, 0x6e, 0x32, 0x07, 0x1f, 0xb8, 0x0e, 0x19, 0x9e, 0x99, 0x29, 0x33, 0x9a, 0xae, 0x7a, 0xed, 0x68, 0x42, 0x69, 0x7c, 0x07, 0xb3, 0x38, 0x2c, 0xf6, 0x3d}}},
+{{{0x64, 0xaa, 0xb5, 0x88, 0x79, 0x65, 0x38, 0x8c, 0x94, 0xd6, 0x62, 0x37, 0x7d, 0x64, 0xcd, 0x3a, 0xeb, 0xff, 0xe8, 0x81, 0x09, 0xc7, 0x6a, 0x50, 0x09, 0x0d, 0x28, 0x03, 0x0d, 0x9a, 0x93, 0x0a}} ,
+ {{0x42, 0xa3, 0xf1, 0xc5, 0xb4, 0x0f, 0xd8, 0xc8, 0x8d, 0x15, 0x31, 0xbd, 0xf8, 0x07, 0x8b, 0xcd, 0x08, 0x8a, 0xfb, 0x18, 0x07, 0xfe, 0x8e, 0x52, 0x86, 0xef, 0xbe, 0xec, 0x49, 0x52, 0x99, 0x08}}},
+{{{0x0f, 0xa9, 0xd5, 0x01, 0xaa, 0x48, 0x4f, 0x28, 0x66, 0x32, 0x1a, 0xba, 0x7c, 0xea, 0x11, 0x80, 0x17, 0x18, 0x9b, 0x56, 0x88, 0x25, 0x06, 0x69, 0x12, 0x2c, 0xea, 0x56, 0x69, 0x41, 0x24, 0x19}} ,
+ {{0xde, 0x21, 0xf0, 0xda, 0x8a, 0xfb, 0xb1, 0xb8, 0xcd, 0xc8, 0x6a, 0x82, 0x19, 0x73, 0xdb, 0xc7, 0xcf, 0x88, 0xeb, 0x96, 0xee, 0x6f, 0xfb, 0x06, 0xd2, 0xcd, 0x7d, 0x7b, 0x12, 0x28, 0x8e, 0x0c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x93, 0x44, 0x97, 0xce, 0x28, 0xff, 0x3a, 0x40, 0xc4, 0xf5, 0xf6, 0x9b, 0xf4, 0x6b, 0x07, 0x84, 0xfb, 0x98, 0xd8, 0xec, 0x8c, 0x03, 0x57, 0xec, 0x49, 0xed, 0x63, 0xb6, 0xaa, 0xff, 0x98, 0x28}} ,
+ {{0x3d, 0x16, 0x35, 0xf3, 0x46, 0xbc, 0xb3, 0xf4, 0xc6, 0xb6, 0x4f, 0xfa, 0xf4, 0xa0, 0x13, 0xe6, 0x57, 0x45, 0x93, 0xb9, 0xbc, 0xd6, 0x59, 0xe7, 0x77, 0x94, 0x6c, 0xab, 0x96, 0x3b, 0x4f, 0x09}}},
+{{{0x5a, 0xf7, 0x6b, 0x01, 0x12, 0x4f, 0x51, 0xc1, 0x70, 0x84, 0x94, 0x47, 0xb2, 0x01, 0x6c, 0x71, 0xd7, 0xcc, 0x17, 0x66, 0x0f, 0x59, 0x5d, 0x5d, 0x10, 0x01, 0x57, 0x11, 0xf5, 0xdd, 0xe2, 0x34}} ,
+ {{0x26, 0xd9, 0x1f, 0x5c, 0x58, 0xac, 0x8b, 0x03, 0xd2, 0xc3, 0x85, 0x0f, 0x3a, 0xc3, 0x7f, 0x6d, 0x8e, 0x86, 0xcd, 0x52, 0x74, 0x8f, 0x55, 0x77, 0x17, 0xb7, 0x8e, 0xb7, 0x88, 0xea, 0xda, 0x1b}}},
+{{{0xb6, 0xea, 0x0e, 0x40, 0x93, 0x20, 0x79, 0x35, 0x6a, 0x61, 0x84, 0x5a, 0x07, 0x6d, 0xf9, 0x77, 0x6f, 0xed, 0x69, 0x1c, 0x0d, 0x25, 0x76, 0xcc, 0xf0, 0xdb, 0xbb, 0xc5, 0xad, 0xe2, 0x26, 0x57}} ,
+ {{0xcf, 0xe8, 0x0e, 0x6b, 0x96, 0x7d, 0xed, 0x27, 0xd1, 0x3c, 0xa9, 0xd9, 0x50, 0xa9, 0x98, 0x84, 0x5e, 0x86, 0xef, 0xd6, 0xf0, 0xf8, 0x0e, 0x89, 0x05, 0x2f, 0xd9, 0x5f, 0x15, 0x5f, 0x73, 0x79}}},
+{{{0xc8, 0x5c, 0x16, 0xfe, 0xed, 0x9f, 0x26, 0x56, 0xf6, 0x4b, 0x9f, 0xa7, 0x0a, 0x85, 0xfe, 0xa5, 0x8c, 0x87, 0xdd, 0x98, 0xce, 0x4e, 0xc3, 0x58, 0x55, 0xb2, 0x7b, 0x3d, 0xd8, 0x6b, 0xb5, 0x4c}} ,
+ {{0x65, 0x38, 0xa0, 0x15, 0xfa, 0xa7, 0xb4, 0x8f, 0xeb, 0xc4, 0x86, 0x9b, 0x30, 0xa5, 0x5e, 0x4d, 0xea, 0x8a, 0x9a, 0x9f, 0x1a, 0xd8, 0x5b, 0x53, 0x14, 0x19, 0x25, 0x63, 0xb4, 0x6f, 0x1f, 0x5d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xac, 0x8f, 0xbc, 0x1e, 0x7d, 0x8b, 0x5a, 0x0b, 0x8d, 0xaf, 0x76, 0x2e, 0x71, 0xe3, 0x3b, 0x6f, 0x53, 0x2f, 0x3e, 0x90, 0x95, 0xd4, 0x35, 0x14, 0x4f, 0x8c, 0x3c, 0xce, 0x57, 0x1c, 0x76, 0x49}} ,
+ {{0xa8, 0x50, 0xe1, 0x61, 0x6b, 0x57, 0x35, 0xeb, 0x44, 0x0b, 0x0c, 0x6e, 0xf9, 0x25, 0x80, 0x74, 0xf2, 0x8f, 0x6f, 0x7a, 0x3e, 0x7f, 0x2d, 0xf3, 0x4e, 0x09, 0x65, 0x10, 0x5e, 0x03, 0x25, 0x32}}},
+{{{0xa9, 0x60, 0xdc, 0x0f, 0x64, 0xe5, 0x1d, 0xe2, 0x8d, 0x4f, 0x79, 0x2f, 0x0e, 0x24, 0x02, 0x00, 0x05, 0x77, 0x43, 0x25, 0x3d, 0x6a, 0xc7, 0xb7, 0xbf, 0x04, 0x08, 0x65, 0xf4, 0x39, 0x4b, 0x65}} ,
+ {{0x96, 0x19, 0x12, 0x6b, 0x6a, 0xb7, 0xe3, 0xdc, 0x45, 0x9b, 0xdb, 0xb4, 0xa8, 0xae, 0xdc, 0xa8, 0x14, 0x44, 0x65, 0x62, 0xce, 0x34, 0x9a, 0x84, 0x18, 0x12, 0x01, 0xf1, 0xe2, 0x7b, 0xce, 0x50}}},
+{{{0x41, 0x21, 0x30, 0x53, 0x1b, 0x47, 0x01, 0xb7, 0x18, 0xd8, 0x82, 0x57, 0xbd, 0xa3, 0x60, 0xf0, 0x32, 0xf6, 0x5b, 0xf0, 0x30, 0x88, 0x91, 0x59, 0xfd, 0x90, 0xa2, 0xb9, 0x55, 0x93, 0x21, 0x34}} ,
+ {{0x97, 0x67, 0x9e, 0xeb, 0x6a, 0xf9, 0x6e, 0xd6, 0x73, 0xe8, 0x6b, 0x29, 0xec, 0x63, 0x82, 0x00, 0xa8, 0x99, 0x1c, 0x1d, 0x30, 0xc8, 0x90, 0x52, 0x90, 0xb6, 0x6a, 0x80, 0x4e, 0xff, 0x4b, 0x51}}},
+{{{0x0f, 0x7d, 0x63, 0x8c, 0x6e, 0x5c, 0xde, 0x30, 0xdf, 0x65, 0xfa, 0x2e, 0xb0, 0xa3, 0x25, 0x05, 0x54, 0xbd, 0x25, 0xba, 0x06, 0xae, 0xdf, 0x8b, 0xd9, 0x1b, 0xea, 0x38, 0xb3, 0x05, 0x16, 0x09}} ,
+ {{0xc7, 0x8c, 0xbf, 0x64, 0x28, 0xad, 0xf8, 0xa5, 0x5a, 0x6f, 0xc9, 0xba, 0xd5, 0x7f, 0xd5, 0xd6, 0xbd, 0x66, 0x2f, 0x3d, 0xaa, 0x54, 0xf6, 0xba, 0x32, 0x22, 0x9a, 0x1e, 0x52, 0x05, 0xf4, 0x1d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xaa, 0x1f, 0xbb, 0xeb, 0xfe, 0xe4, 0x87, 0xfc, 0xb1, 0x2c, 0xb7, 0x88, 0xf4, 0xc6, 0xb9, 0xf5, 0x24, 0x46, 0xf2, 0xa5, 0x9f, 0x8f, 0x8a, 0x93, 0x70, 0x69, 0xd4, 0x56, 0xec, 0xfd, 0x06, 0x46}} ,
+ {{0x4e, 0x66, 0xcf, 0x4e, 0x34, 0xce, 0x0c, 0xd9, 0xa6, 0x50, 0xd6, 0x5e, 0x95, 0xaf, 0xe9, 0x58, 0xfa, 0xee, 0x9b, 0xb8, 0xa5, 0x0f, 0x35, 0xe0, 0x43, 0x82, 0x6d, 0x65, 0xe6, 0xd9, 0x00, 0x0f}}},
+{{{0x7b, 0x75, 0x3a, 0xfc, 0x64, 0xd3, 0x29, 0x7e, 0xdd, 0x49, 0x9a, 0x59, 0x53, 0xbf, 0xb4, 0xa7, 0x52, 0xb3, 0x05, 0xab, 0xc3, 0xaf, 0x16, 0x1a, 0x85, 0x42, 0x32, 0xa2, 0x86, 0xfa, 0x39, 0x43}} ,
+ {{0x0e, 0x4b, 0xa3, 0x63, 0x8a, 0xfe, 0xa5, 0x58, 0xf1, 0x13, 0xbd, 0x9d, 0xaa, 0x7f, 0x76, 0x40, 0x70, 0x81, 0x10, 0x75, 0x99, 0xbb, 0xbe, 0x0b, 0x16, 0xe9, 0xba, 0x62, 0x34, 0xcc, 0x07, 0x6d}}},
+{{{0xc3, 0xf1, 0xc6, 0x93, 0x65, 0xee, 0x0b, 0xbc, 0xea, 0x14, 0xf0, 0xc1, 0xf8, 0x84, 0x89, 0xc2, 0xc9, 0xd7, 0xea, 0x34, 0xca, 0xa7, 0xc4, 0x99, 0xd5, 0x50, 0x69, 0xcb, 0xd6, 0x21, 0x63, 0x7c}} ,
+ {{0x99, 0xeb, 0x7c, 0x31, 0x73, 0x64, 0x67, 0x7f, 0x0c, 0x66, 0xaa, 0x8c, 0x69, 0x91, 0xe2, 0x26, 0xd3, 0x23, 0xe2, 0x76, 0x5d, 0x32, 0x52, 0xdf, 0x5d, 0xc5, 0x8f, 0xb7, 0x7c, 0x84, 0xb3, 0x70}}},
+{{{0xeb, 0x01, 0xc7, 0x36, 0x97, 0x4e, 0xb6, 0xab, 0x5f, 0x0d, 0x2c, 0xba, 0x67, 0x64, 0x55, 0xde, 0xbc, 0xff, 0xa6, 0xec, 0x04, 0xd3, 0x8d, 0x39, 0x56, 0x5e, 0xee, 0xf8, 0xe4, 0x2e, 0x33, 0x62}} ,
+ {{0x65, 0xef, 0xb8, 0x9f, 0xc8, 0x4b, 0xa7, 0xfd, 0x21, 0x49, 0x9b, 0x92, 0x35, 0x82, 0xd6, 0x0a, 0x9b, 0xf2, 0x79, 0xf1, 0x47, 0x2f, 0x6a, 0x7e, 0x9f, 0xcf, 0x18, 0x02, 0x3c, 0xfb, 0x1b, 0x3e}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x2f, 0x8b, 0xc8, 0x40, 0x51, 0xd1, 0xac, 0x1a, 0x0b, 0xe4, 0xa9, 0xa2, 0x42, 0x21, 0x19, 0x2f, 0x7b, 0x97, 0xbf, 0xf7, 0x57, 0x6d, 0x3f, 0x3d, 0x4f, 0x0f, 0xe2, 0xb2, 0x81, 0x00, 0x9e, 0x7b}} ,
+ {{0x8c, 0x85, 0x2b, 0xc4, 0xfc, 0xf1, 0xab, 0xe8, 0x79, 0x22, 0xc4, 0x84, 0x17, 0x3a, 0xfa, 0x86, 0xa6, 0x7d, 0xf9, 0xf3, 0x6f, 0x03, 0x57, 0x20, 0x4d, 0x79, 0xf9, 0x6e, 0x71, 0x54, 0x38, 0x09}}},
+{{{0x40, 0x29, 0x74, 0xa8, 0x2f, 0x5e, 0xf9, 0x79, 0xa4, 0xf3, 0x3e, 0xb9, 0xfd, 0x33, 0x31, 0xac, 0x9a, 0x69, 0x88, 0x1e, 0x77, 0x21, 0x2d, 0xf3, 0x91, 0x52, 0x26, 0x15, 0xb2, 0xa6, 0xcf, 0x7e}} ,
+ {{0xc6, 0x20, 0x47, 0x6c, 0xa4, 0x7d, 0xcb, 0x63, 0xea, 0x5b, 0x03, 0xdf, 0x3e, 0x88, 0x81, 0x6d, 0xce, 0x07, 0x42, 0x18, 0x60, 0x7e, 0x7b, 0x55, 0xfe, 0x6a, 0xf3, 0xda, 0x5c, 0x8b, 0x95, 0x10}}},
+{{{0x62, 0xe4, 0x0d, 0x03, 0xb4, 0xd7, 0xcd, 0xfa, 0xbd, 0x46, 0xdf, 0x93, 0x71, 0x10, 0x2c, 0xa8, 0x3b, 0xb6, 0x09, 0x05, 0x70, 0x84, 0x43, 0x29, 0xa8, 0x59, 0xf5, 0x8e, 0x10, 0xe4, 0xd7, 0x20}} ,
+ {{0x57, 0x82, 0x1c, 0xab, 0xbf, 0x62, 0x70, 0xe8, 0xc4, 0xcf, 0xf0, 0x28, 0x6e, 0x16, 0x3c, 0x08, 0x78, 0x89, 0x85, 0x46, 0x0f, 0xf6, 0x7f, 0xcf, 0xcb, 0x7e, 0xb8, 0x25, 0xe9, 0x5a, 0xfa, 0x03}}},
+{{{0xfb, 0x95, 0x92, 0x63, 0x50, 0xfc, 0x62, 0xf0, 0xa4, 0x5e, 0x8c, 0x18, 0xc2, 0x17, 0x24, 0xb7, 0x78, 0xc2, 0xa9, 0xe7, 0x6a, 0x32, 0xd6, 0x29, 0x85, 0xaf, 0xcb, 0x8d, 0x91, 0x13, 0xda, 0x6b}} ,
+ {{0x36, 0x0a, 0xc2, 0xb6, 0x4b, 0xa5, 0x5d, 0x07, 0x17, 0x41, 0x31, 0x5f, 0x62, 0x46, 0xf8, 0x92, 0xf9, 0x66, 0x48, 0x73, 0xa6, 0x97, 0x0d, 0x7d, 0x88, 0xee, 0x62, 0xb1, 0x03, 0xa8, 0x3f, 0x2c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x4a, 0xb1, 0x70, 0x8a, 0xa9, 0xe8, 0x63, 0x79, 0x00, 0xe2, 0x25, 0x16, 0xca, 0x4b, 0x0f, 0xa4, 0x66, 0xad, 0x19, 0x9f, 0x88, 0x67, 0x0c, 0x8b, 0xc2, 0x4a, 0x5b, 0x2b, 0x6d, 0x95, 0xaf, 0x19}} ,
+ {{0x8b, 0x9d, 0xb6, 0xcc, 0x60, 0xb4, 0x72, 0x4f, 0x17, 0x69, 0x5a, 0x4a, 0x68, 0x34, 0xab, 0xa1, 0x45, 0x32, 0x3c, 0x83, 0x87, 0x72, 0x30, 0x54, 0x77, 0x68, 0xae, 0xfb, 0xb5, 0x8b, 0x22, 0x5e}}},
+{{{0xf1, 0xb9, 0x87, 0x35, 0xc5, 0xbb, 0xb9, 0xcf, 0xf5, 0xd6, 0xcd, 0xd5, 0x0c, 0x7c, 0x0e, 0xe6, 0x90, 0x34, 0xfb, 0x51, 0x42, 0x1e, 0x6d, 0xac, 0x9a, 0x46, 0xc4, 0x97, 0x29, 0x32, 0xbf, 0x45}} ,
+ {{0x66, 0x9e, 0xc6, 0x24, 0xc0, 0xed, 0xa5, 0x5d, 0x88, 0xd4, 0xf0, 0x73, 0x97, 0x7b, 0xea, 0x7f, 0x42, 0xff, 0x21, 0xa0, 0x9b, 0x2f, 0x9a, 0xfd, 0x53, 0x57, 0x07, 0x84, 0x48, 0x88, 0x9d, 0x52}}},
+{{{0xc6, 0x96, 0x48, 0x34, 0x2a, 0x06, 0xaf, 0x94, 0x3d, 0xf4, 0x1a, 0xcf, 0xf2, 0xc0, 0x21, 0xc2, 0x42, 0x5e, 0xc8, 0x2f, 0x35, 0xa2, 0x3e, 0x29, 0xfa, 0x0c, 0x84, 0xe5, 0x89, 0x72, 0x7c, 0x06}} ,
+ {{0x32, 0x65, 0x03, 0xe5, 0x89, 0xa6, 0x6e, 0xb3, 0x5b, 0x8e, 0xca, 0xeb, 0xfe, 0x22, 0x56, 0x8b, 0x5d, 0x14, 0x4b, 0x4d, 0xf9, 0xbe, 0xb5, 0xf5, 0xe6, 0x5c, 0x7b, 0x8b, 0xf4, 0x13, 0x11, 0x34}}},
+{{{0x07, 0xc6, 0x22, 0x15, 0xe2, 0x9c, 0x60, 0xa2, 0x19, 0xd9, 0x27, 0xae, 0x37, 0x4e, 0xa6, 0xc9, 0x80, 0xa6, 0x91, 0x8f, 0x12, 0x49, 0xe5, 0x00, 0x18, 0x47, 0xd1, 0xd7, 0x28, 0x22, 0x63, 0x39}} ,
+ {{0xe8, 0xe2, 0x00, 0x7e, 0xf2, 0x9e, 0x1e, 0x99, 0x39, 0x95, 0x04, 0xbd, 0x1e, 0x67, 0x7b, 0xb2, 0x26, 0xac, 0xe6, 0xaa, 0xe2, 0x46, 0xd5, 0xe4, 0xe8, 0x86, 0xbd, 0xab, 0x7c, 0x55, 0x59, 0x6f}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x24, 0x64, 0x6e, 0x9b, 0x35, 0x71, 0x78, 0xce, 0x33, 0x03, 0x21, 0x33, 0x36, 0xf1, 0x73, 0x9b, 0xb9, 0x15, 0x8b, 0x2c, 0x69, 0xcf, 0x4d, 0xed, 0x4f, 0x4d, 0x57, 0x14, 0x13, 0x82, 0xa4, 0x4d}} ,
+ {{0x65, 0x6e, 0x0a, 0xa4, 0x59, 0x07, 0x17, 0xf2, 0x6b, 0x4a, 0x1f, 0x6e, 0xf6, 0xb5, 0xbc, 0x62, 0xe4, 0xb6, 0xda, 0xa2, 0x93, 0xbc, 0x29, 0x05, 0xd2, 0xd2, 0x73, 0x46, 0x03, 0x16, 0x40, 0x31}}},
+{{{0x4c, 0x73, 0x6d, 0x15, 0xbd, 0xa1, 0x4d, 0x5c, 0x13, 0x0b, 0x24, 0x06, 0x98, 0x78, 0x1c, 0x5b, 0xeb, 0x1f, 0x18, 0x54, 0x43, 0xd9, 0x55, 0x66, 0xda, 0x29, 0x21, 0xe8, 0xb8, 0x3c, 0x42, 0x22}} ,
+ {{0xb4, 0xcd, 0x08, 0x6f, 0x15, 0x23, 0x1a, 0x0b, 0x22, 0xed, 0xd1, 0xf1, 0xa7, 0xc7, 0x73, 0x45, 0xf3, 0x9e, 0xce, 0x76, 0xb7, 0xf6, 0x39, 0xb6, 0x8e, 0x79, 0xbe, 0xe9, 0x9b, 0xcf, 0x7d, 0x62}}},
+{{{0x92, 0x5b, 0xfc, 0x72, 0xfd, 0xba, 0xf1, 0xfd, 0xa6, 0x7c, 0x95, 0xe3, 0x61, 0x3f, 0xe9, 0x03, 0xd4, 0x2b, 0xd4, 0x20, 0xd9, 0xdb, 0x4d, 0x32, 0x3e, 0xf5, 0x11, 0x64, 0xe3, 0xb4, 0xbe, 0x32}} ,
+ {{0x86, 0x17, 0x90, 0xe7, 0xc9, 0x1f, 0x10, 0xa5, 0x6a, 0x2d, 0x39, 0xd0, 0x3b, 0xc4, 0xa6, 0xe9, 0x59, 0x13, 0xda, 0x1a, 0xe6, 0xa0, 0xb9, 0x3c, 0x50, 0xb8, 0x40, 0x7c, 0x15, 0x36, 0x5a, 0x42}}},
+{{{0xb4, 0x0b, 0x32, 0xab, 0xdc, 0x04, 0x51, 0x55, 0x21, 0x1e, 0x0b, 0x75, 0x99, 0x89, 0x73, 0x35, 0x3a, 0x91, 0x2b, 0xfe, 0xe7, 0x49, 0xea, 0x76, 0xc1, 0xf9, 0x46, 0xb9, 0x53, 0x02, 0x23, 0x04}} ,
+ {{0xfc, 0x5a, 0x1e, 0x1d, 0x74, 0x58, 0x95, 0xa6, 0x8f, 0x7b, 0x97, 0x3e, 0x17, 0x3b, 0x79, 0x2d, 0xa6, 0x57, 0xef, 0x45, 0x02, 0x0b, 0x4d, 0x6e, 0x9e, 0x93, 0x8d, 0x2f, 0xd9, 0x9d, 0xdb, 0x04}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xc0, 0xd7, 0x56, 0x97, 0x58, 0x91, 0xde, 0x09, 0x4f, 0x9f, 0xbe, 0x63, 0xb0, 0x83, 0x86, 0x43, 0x5d, 0xbc, 0xe0, 0xf3, 0xc0, 0x75, 0xbf, 0x8b, 0x8e, 0xaa, 0xf7, 0x8b, 0x64, 0x6e, 0xb0, 0x63}} ,
+ {{0x16, 0xae, 0x8b, 0xe0, 0x9b, 0x24, 0x68, 0x5c, 0x44, 0xc2, 0xd0, 0x08, 0xb7, 0x7b, 0x62, 0xfd, 0x7f, 0xd8, 0xd4, 0xb7, 0x50, 0xfd, 0x2c, 0x1b, 0xbf, 0x41, 0x95, 0xd9, 0x8e, 0xd8, 0x17, 0x1b}}},
+{{{0x86, 0x55, 0x37, 0x8e, 0xc3, 0x38, 0x48, 0x14, 0xb5, 0x97, 0xd2, 0xa7, 0x54, 0x45, 0xf1, 0x35, 0x44, 0x38, 0x9e, 0xf1, 0x1b, 0xb6, 0x34, 0x00, 0x3c, 0x96, 0xee, 0x29, 0x00, 0xea, 0x2c, 0x0b}} ,
+ {{0xea, 0xda, 0x99, 0x9e, 0x19, 0x83, 0x66, 0x6d, 0xe9, 0x76, 0x87, 0x50, 0xd1, 0xfd, 0x3c, 0x60, 0x87, 0xc6, 0x41, 0xd9, 0x8e, 0xdb, 0x5e, 0xde, 0xaa, 0x9a, 0xd3, 0x28, 0xda, 0x95, 0xea, 0x47}}},
+{{{0xd0, 0x80, 0xba, 0x19, 0xae, 0x1d, 0xa9, 0x79, 0xf6, 0x3f, 0xac, 0x5d, 0x6f, 0x96, 0x1f, 0x2a, 0xce, 0x29, 0xb2, 0xff, 0x37, 0xf1, 0x94, 0x8f, 0x0c, 0xb5, 0x28, 0xba, 0x9a, 0x21, 0xf6, 0x66}} ,
+ {{0x02, 0xfb, 0x54, 0xb8, 0x05, 0xf3, 0x81, 0x52, 0x69, 0x34, 0x46, 0x9d, 0x86, 0x76, 0x8f, 0xd7, 0xf8, 0x6a, 0x66, 0xff, 0xe6, 0xa7, 0x90, 0xf7, 0x5e, 0xcd, 0x6a, 0x9b, 0x55, 0xfc, 0x9d, 0x48}}},
+{{{0xbd, 0xaa, 0x13, 0xe6, 0xcd, 0x45, 0x4a, 0xa4, 0x59, 0x0a, 0x64, 0xb1, 0x98, 0xd6, 0x34, 0x13, 0x04, 0xe6, 0x97, 0x94, 0x06, 0xcb, 0xd4, 0x4e, 0xbb, 0x96, 0xcd, 0xd1, 0x57, 0xd1, 0xe3, 0x06}} ,
+ {{0x7a, 0x6c, 0x45, 0x27, 0xc4, 0x93, 0x7f, 0x7d, 0x7c, 0x62, 0x50, 0x38, 0x3a, 0x6b, 0xb5, 0x88, 0xc6, 0xd9, 0xf1, 0x78, 0x19, 0xb9, 0x39, 0x93, 0x3d, 0xc9, 0xe0, 0x9c, 0x3c, 0xce, 0xf5, 0x72}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x24, 0xea, 0x23, 0x7d, 0x56, 0x2c, 0xe2, 0x59, 0x0e, 0x85, 0x60, 0x04, 0x88, 0x5a, 0x74, 0x1e, 0x4b, 0xef, 0x13, 0xda, 0x4c, 0xff, 0x83, 0x45, 0x85, 0x3f, 0x08, 0x95, 0x2c, 0x20, 0x13, 0x1f}} ,
+ {{0x48, 0x5f, 0x27, 0x90, 0x5c, 0x02, 0x42, 0xad, 0x78, 0x47, 0x5c, 0xb5, 0x7e, 0x08, 0x85, 0x00, 0xfa, 0x7f, 0xfd, 0xfd, 0xe7, 0x09, 0x11, 0xf2, 0x7e, 0x1b, 0x38, 0x6c, 0x35, 0x6d, 0x33, 0x66}}},
+{{{0x93, 0x03, 0x36, 0x81, 0xac, 0xe4, 0x20, 0x09, 0x35, 0x4c, 0x45, 0xb2, 0x1e, 0x4c, 0x14, 0x21, 0xe6, 0xe9, 0x8a, 0x7b, 0x8d, 0xfe, 0x1e, 0xc6, 0x3e, 0xc1, 0x35, 0xfa, 0xe7, 0x70, 0x4e, 0x1d}} ,
+ {{0x61, 0x2e, 0xc2, 0xdd, 0x95, 0x57, 0xd1, 0xab, 0x80, 0xe8, 0x63, 0x17, 0xb5, 0x48, 0xe4, 0x8a, 0x11, 0x9e, 0x72, 0xbe, 0x85, 0x8d, 0x51, 0x0a, 0xf2, 0x9f, 0xe0, 0x1c, 0xa9, 0x07, 0x28, 0x7b}}},
+{{{0xbb, 0x71, 0x14, 0x5e, 0x26, 0x8c, 0x3d, 0xc8, 0xe9, 0x7c, 0xd3, 0xd6, 0xd1, 0x2f, 0x07, 0x6d, 0xe6, 0xdf, 0xfb, 0x79, 0xd6, 0x99, 0x59, 0x96, 0x48, 0x40, 0x0f, 0x3a, 0x7b, 0xb2, 0xa0, 0x72}} ,
+ {{0x4e, 0x3b, 0x69, 0xc8, 0x43, 0x75, 0x51, 0x6c, 0x79, 0x56, 0xe4, 0xcb, 0xf7, 0xa6, 0x51, 0xc2, 0x2c, 0x42, 0x0b, 0xd4, 0x82, 0x20, 0x1c, 0x01, 0x08, 0x66, 0xd7, 0xbf, 0x04, 0x56, 0xfc, 0x02}}},
+{{{0x24, 0xe8, 0xb7, 0x60, 0xae, 0x47, 0x80, 0xfc, 0xe5, 0x23, 0xe7, 0xc2, 0xc9, 0x85, 0xe6, 0x98, 0xa0, 0x29, 0x4e, 0xe1, 0x84, 0x39, 0x2d, 0x95, 0x2c, 0xf3, 0x45, 0x3c, 0xff, 0xaf, 0x27, 0x4c}} ,
+ {{0x6b, 0xa6, 0xf5, 0x4b, 0x11, 0xbd, 0xba, 0x5b, 0x9e, 0xc4, 0xa4, 0x51, 0x1e, 0xbe, 0xd0, 0x90, 0x3a, 0x9c, 0xc2, 0x26, 0xb6, 0x1e, 0xf1, 0x95, 0x7d, 0xc8, 0x6d, 0x52, 0xe6, 0x99, 0x2c, 0x5f}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x85, 0xe0, 0x24, 0x32, 0xb4, 0xd1, 0xef, 0xfc, 0x69, 0xa2, 0xbf, 0x8f, 0x72, 0x2c, 0x95, 0xf6, 0xe4, 0x6e, 0x7d, 0x90, 0xf7, 0x57, 0x81, 0xa0, 0xf7, 0xda, 0xef, 0x33, 0x07, 0xe3, 0x6b, 0x78}} ,
+ {{0x36, 0x27, 0x3e, 0xc6, 0x12, 0x07, 0xab, 0x4e, 0xbe, 0x69, 0x9d, 0xb3, 0xbe, 0x08, 0x7c, 0x2a, 0x47, 0x08, 0xfd, 0xd4, 0xcd, 0x0e, 0x27, 0x34, 0x5b, 0x98, 0x34, 0x2f, 0x77, 0x5f, 0x3a, 0x65}}},
+{{{0x13, 0xaa, 0x2e, 0x4c, 0xf0, 0x22, 0xb8, 0x6c, 0xb3, 0x19, 0x4d, 0xeb, 0x6b, 0xd0, 0xa4, 0xc6, 0x9c, 0xdd, 0xc8, 0x5b, 0x81, 0x57, 0x89, 0xdf, 0x33, 0xa9, 0x68, 0x49, 0x80, 0xe4, 0xfe, 0x21}} ,
+ {{0x00, 0x17, 0x90, 0x30, 0xe9, 0xd3, 0x60, 0x30, 0x31, 0xc2, 0x72, 0x89, 0x7a, 0x36, 0xa5, 0xbd, 0x39, 0x83, 0x85, 0x50, 0xa1, 0x5d, 0x6c, 0x41, 0x1d, 0xb5, 0x2c, 0x07, 0x40, 0x77, 0x0b, 0x50}}},
+{{{0x64, 0x34, 0xec, 0xc0, 0x9e, 0x44, 0x41, 0xaf, 0xa0, 0x36, 0x05, 0x6d, 0xea, 0x30, 0x25, 0x46, 0x35, 0x24, 0x9d, 0x86, 0xbd, 0x95, 0xf1, 0x6a, 0x46, 0xd7, 0x94, 0x54, 0xf9, 0x3b, 0xbd, 0x5d}} ,
+ {{0x77, 0x5b, 0xe2, 0x37, 0xc7, 0xe1, 0x7c, 0x13, 0x8c, 0x9f, 0x7b, 0x7b, 0x2a, 0xce, 0x42, 0xa3, 0xb9, 0x2a, 0x99, 0xa8, 0xc0, 0xd8, 0x3c, 0x86, 0xb0, 0xfb, 0xe9, 0x76, 0x77, 0xf7, 0xf5, 0x56}}},
+{{{0xdf, 0xb3, 0x46, 0x11, 0x6e, 0x13, 0xb7, 0x28, 0x4e, 0x56, 0xdd, 0xf1, 0xac, 0xad, 0x58, 0xc3, 0xf8, 0x88, 0x94, 0x5e, 0x06, 0x98, 0xa1, 0xe4, 0x6a, 0xfb, 0x0a, 0x49, 0x5d, 0x8a, 0xfe, 0x77}} ,
+ {{0x46, 0x02, 0xf5, 0xa5, 0xaf, 0xc5, 0x75, 0x6d, 0xba, 0x45, 0x35, 0x0a, 0xfe, 0xc9, 0xac, 0x22, 0x91, 0x8d, 0x21, 0x95, 0x33, 0x03, 0xc0, 0x8a, 0x16, 0xf3, 0x39, 0xe0, 0x01, 0x0f, 0x53, 0x3c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x34, 0x75, 0x37, 0x1f, 0x34, 0x4e, 0xa9, 0x1d, 0x68, 0x67, 0xf8, 0x49, 0x98, 0x96, 0xfc, 0x4c, 0x65, 0x97, 0xf7, 0x02, 0x4a, 0x52, 0x6c, 0x01, 0xbd, 0x48, 0xbb, 0x1b, 0xed, 0xa4, 0xe2, 0x53}} ,
+ {{0x59, 0xd5, 0x9b, 0x5a, 0xa2, 0x90, 0xd3, 0xb8, 0x37, 0x4c, 0x55, 0x82, 0x28, 0x08, 0x0f, 0x7f, 0xaa, 0x81, 0x65, 0xe0, 0x0c, 0x52, 0xc9, 0xa3, 0x32, 0x27, 0x64, 0xda, 0xfd, 0x34, 0x23, 0x5a}}},
+{{{0xb5, 0xb0, 0x0c, 0x4d, 0xb3, 0x7b, 0x23, 0xc8, 0x1f, 0x8a, 0x39, 0x66, 0xe6, 0xba, 0x4c, 0x10, 0x37, 0xca, 0x9c, 0x7c, 0x05, 0x9e, 0xff, 0xc0, 0xf8, 0x8e, 0xb1, 0x8f, 0x6f, 0x67, 0x18, 0x26}} ,
+ {{0x4b, 0x41, 0x13, 0x54, 0x23, 0x1a, 0xa4, 0x4e, 0xa9, 0x8b, 0x1e, 0x4b, 0xfc, 0x15, 0x24, 0xbb, 0x7e, 0xcb, 0xb6, 0x1e, 0x1b, 0xf5, 0xf2, 0xc8, 0x56, 0xec, 0x32, 0xa2, 0x60, 0x5b, 0xa0, 0x2a}}},
+{{{0xa4, 0x29, 0x47, 0x86, 0x2e, 0x92, 0x4f, 0x11, 0x4f, 0xf3, 0xb2, 0x5c, 0xd5, 0x3e, 0xa6, 0xb9, 0xc8, 0xe2, 0x33, 0x11, 0x1f, 0x01, 0x8f, 0xb0, 0x9b, 0xc7, 0xa5, 0xff, 0x83, 0x0f, 0x1e, 0x28}} ,
+ {{0x1d, 0x29, 0x7a, 0xa1, 0xec, 0x8e, 0xb5, 0xad, 0xea, 0x02, 0x68, 0x60, 0x74, 0x29, 0x1c, 0xa5, 0xcf, 0xc8, 0x3b, 0x7d, 0x8b, 0x2b, 0x7c, 0xad, 0xa4, 0x40, 0x17, 0x51, 0x59, 0x7c, 0x2e, 0x5d}}},
+{{{0x0a, 0x6c, 0x4f, 0xbc, 0x3e, 0x32, 0xe7, 0x4a, 0x1a, 0x13, 0xc1, 0x49, 0x38, 0xbf, 0xf7, 0xc2, 0xd3, 0x8f, 0x6b, 0xad, 0x52, 0xf7, 0xcf, 0xbc, 0x27, 0xcb, 0x40, 0x67, 0x76, 0xcd, 0x6d, 0x56}} ,
+ {{0xe5, 0xb0, 0x27, 0xad, 0xbe, 0x9b, 0xf2, 0xb5, 0x63, 0xde, 0x3a, 0x23, 0x95, 0xb7, 0x0a, 0x7e, 0xf3, 0x9e, 0x45, 0x6f, 0x19, 0x39, 0x75, 0x8f, 0x39, 0x3d, 0x0f, 0xc0, 0x9f, 0xf1, 0xe9, 0x51}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x88, 0xaa, 0x14, 0x24, 0x86, 0x94, 0x11, 0x12, 0x3e, 0x1a, 0xb5, 0xcc, 0xbb, 0xe0, 0x9c, 0xd5, 0x9c, 0x6d, 0xba, 0x58, 0x72, 0x8d, 0xfb, 0x22, 0x7b, 0x9f, 0x7c, 0x94, 0x30, 0xb3, 0x51, 0x21}} ,
+ {{0xf6, 0x74, 0x3d, 0xf2, 0xaf, 0xd0, 0x1e, 0x03, 0x7c, 0x23, 0x6b, 0xc9, 0xfc, 0x25, 0x70, 0x90, 0xdc, 0x9a, 0xa4, 0xfb, 0x49, 0xfc, 0x3d, 0x0a, 0x35, 0x38, 0x6f, 0xe4, 0x7e, 0x50, 0x01, 0x2a}}},
+{{{0xd6, 0xe3, 0x96, 0x61, 0x3a, 0xfd, 0xef, 0x9b, 0x1f, 0x90, 0xa4, 0x24, 0x14, 0x5b, 0xc8, 0xde, 0x50, 0xb1, 0x1d, 0xaf, 0xe8, 0x55, 0x8a, 0x87, 0x0d, 0xfe, 0xaa, 0x3b, 0x82, 0x2c, 0x8d, 0x7b}} ,
+ {{0x85, 0x0c, 0xaf, 0xf8, 0x83, 0x44, 0x49, 0xd9, 0x45, 0xcf, 0xf7, 0x48, 0xd9, 0x53, 0xb4, 0xf1, 0x65, 0xa0, 0xe1, 0xc3, 0xb3, 0x15, 0xed, 0x89, 0x9b, 0x4f, 0x62, 0xb3, 0x57, 0xa5, 0x45, 0x1c}}},
+{{{0x8f, 0x12, 0xea, 0xaf, 0xd1, 0x1f, 0x79, 0x10, 0x0b, 0xf6, 0xa3, 0x7b, 0xea, 0xac, 0x8b, 0x57, 0x32, 0x62, 0xe7, 0x06, 0x12, 0x51, 0xa0, 0x3b, 0x43, 0x5e, 0xa4, 0x20, 0x78, 0x31, 0xce, 0x0d}} ,
+ {{0x84, 0x7c, 0xc2, 0xa6, 0x91, 0x23, 0xce, 0xbd, 0xdc, 0xf9, 0xce, 0xd5, 0x75, 0x30, 0x22, 0xe6, 0xf9, 0x43, 0x62, 0x0d, 0xf7, 0x75, 0x9d, 0x7f, 0x8c, 0xff, 0x7d, 0xe4, 0x72, 0xac, 0x9f, 0x1c}}},
+{{{0x88, 0xc1, 0x99, 0xd0, 0x3c, 0x1c, 0x5d, 0xb4, 0xef, 0x13, 0x0f, 0x90, 0xb9, 0x36, 0x2f, 0x95, 0x95, 0xc6, 0xdc, 0xde, 0x0a, 0x51, 0xe2, 0x8d, 0xf3, 0xbc, 0x51, 0xec, 0xdf, 0xb1, 0xa2, 0x5f}} ,
+ {{0x2e, 0x68, 0xa1, 0x23, 0x7d, 0x9b, 0x40, 0x69, 0x85, 0x7b, 0x42, 0xbf, 0x90, 0x4b, 0xd6, 0x40, 0x2f, 0xd7, 0x52, 0x52, 0xb2, 0x21, 0xde, 0x64, 0xbd, 0x88, 0xc3, 0x6d, 0xa5, 0xfa, 0x81, 0x3f}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xfb, 0xfd, 0x47, 0x7b, 0x8a, 0x66, 0x9e, 0x79, 0x2e, 0x64, 0x82, 0xef, 0xf7, 0x21, 0xec, 0xf6, 0xd8, 0x86, 0x09, 0x31, 0x7c, 0xdd, 0x03, 0x6a, 0x58, 0xa0, 0x77, 0xb7, 0x9b, 0x8c, 0x87, 0x1f}} ,
+ {{0x55, 0x47, 0xe4, 0xa8, 0x3d, 0x55, 0x21, 0x34, 0xab, 0x1d, 0xae, 0xe0, 0xf4, 0xea, 0xdb, 0xc5, 0xb9, 0x58, 0xbf, 0xc4, 0x2a, 0x89, 0x31, 0x1a, 0xf4, 0x2d, 0xe1, 0xca, 0x37, 0x99, 0x47, 0x59}}},
+{{{0xc7, 0xca, 0x63, 0xc1, 0x49, 0xa9, 0x35, 0x45, 0x55, 0x7e, 0xda, 0x64, 0x32, 0x07, 0x50, 0xf7, 0x32, 0xac, 0xde, 0x75, 0x58, 0x9b, 0x11, 0xb2, 0x3a, 0x1f, 0xf5, 0xf7, 0x79, 0x04, 0xe6, 0x08}} ,
+ {{0x46, 0xfa, 0x22, 0x4b, 0xfa, 0xe1, 0xfe, 0x96, 0xfc, 0x67, 0xba, 0x67, 0x97, 0xc4, 0xe7, 0x1b, 0x86, 0x90, 0x5f, 0xee, 0xf4, 0x5b, 0x11, 0xb2, 0xcd, 0xad, 0xee, 0xc2, 0x48, 0x6c, 0x2b, 0x1b}}},
+{{{0xe3, 0x39, 0x62, 0xb4, 0x4f, 0x31, 0x04, 0xc9, 0xda, 0xd5, 0x73, 0x51, 0x57, 0xc5, 0xb8, 0xf3, 0xa3, 0x43, 0x70, 0xe4, 0x61, 0x81, 0x84, 0xe2, 0xbb, 0xbf, 0x4f, 0x9e, 0xa4, 0x5e, 0x74, 0x06}} ,
+ {{0x29, 0xac, 0xff, 0x27, 0xe0, 0x59, 0xbe, 0x39, 0x9c, 0x0d, 0x83, 0xd7, 0x10, 0x0b, 0x15, 0xb7, 0xe1, 0xc2, 0x2c, 0x30, 0x73, 0x80, 0x3a, 0x7d, 0x5d, 0xab, 0x58, 0x6b, 0xc1, 0xf0, 0xf4, 0x22}}},
+{{{0xfe, 0x7f, 0xfb, 0x35, 0x7d, 0xc6, 0x01, 0x23, 0x28, 0xc4, 0x02, 0xac, 0x1f, 0x42, 0xb4, 0x9d, 0xfc, 0x00, 0x94, 0xa5, 0xee, 0xca, 0xda, 0x97, 0x09, 0x41, 0x77, 0x87, 0x5d, 0x7b, 0x87, 0x78}} ,
+ {{0xf5, 0xfb, 0x90, 0x2d, 0x81, 0x19, 0x9e, 0x2f, 0x6d, 0x85, 0x88, 0x8c, 0x40, 0x5c, 0x77, 0x41, 0x4d, 0x01, 0x19, 0x76, 0x60, 0xe8, 0x4c, 0x48, 0xe4, 0x33, 0x83, 0x32, 0x6c, 0xb4, 0x41, 0x03}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xff, 0x10, 0xc2, 0x09, 0x4f, 0x6e, 0xf4, 0xd2, 0xdf, 0x7e, 0xca, 0x7b, 0x1c, 0x1d, 0xba, 0xa3, 0xb6, 0xda, 0x67, 0x33, 0xd4, 0x87, 0x36, 0x4b, 0x11, 0x20, 0x05, 0xa6, 0x29, 0xc1, 0x87, 0x17}} ,
+ {{0xf6, 0x96, 0xca, 0x2f, 0xda, 0x38, 0xa7, 0x1b, 0xfc, 0xca, 0x7d, 0xfe, 0x08, 0x89, 0xe2, 0x47, 0x2b, 0x6a, 0x5d, 0x4b, 0xfa, 0xa1, 0xb4, 0xde, 0xb6, 0xc2, 0x31, 0x51, 0xf5, 0xe0, 0xa4, 0x0b}}},
+{{{0x5c, 0xe5, 0xc6, 0x04, 0x8e, 0x2b, 0x57, 0xbe, 0x38, 0x85, 0x23, 0xcb, 0xb7, 0xbe, 0x4f, 0xa9, 0xd3, 0x6e, 0x12, 0xaa, 0xd5, 0xb2, 0x2e, 0x93, 0x29, 0x9a, 0x4a, 0x88, 0x18, 0x43, 0xf5, 0x01}} ,
+ {{0x50, 0xfc, 0xdb, 0xa2, 0x59, 0x21, 0x8d, 0xbd, 0x7e, 0x33, 0xae, 0x2f, 0x87, 0x1a, 0xd0, 0x97, 0xc7, 0x0d, 0x4d, 0x63, 0x01, 0xef, 0x05, 0x84, 0xec, 0x40, 0xdd, 0xa8, 0x0a, 0x4f, 0x70, 0x0b}}},
+{{{0x41, 0x69, 0x01, 0x67, 0x5c, 0xd3, 0x8a, 0xc5, 0xcf, 0x3f, 0xd1, 0x57, 0xd1, 0x67, 0x3e, 0x01, 0x39, 0xb5, 0xcb, 0x81, 0x56, 0x96, 0x26, 0xb6, 0xc2, 0xe7, 0x5c, 0xfb, 0x63, 0x97, 0x58, 0x06}} ,
+ {{0x0c, 0x0e, 0xf3, 0xba, 0xf0, 0xe5, 0xba, 0xb2, 0x57, 0x77, 0xc6, 0x20, 0x9b, 0x89, 0x24, 0xbe, 0xf2, 0x9c, 0x8a, 0xba, 0x69, 0xc1, 0xf1, 0xb0, 0x4f, 0x2a, 0x05, 0x9a, 0xee, 0x10, 0x7e, 0x36}}},
+{{{0x3f, 0x26, 0xe9, 0x40, 0xe9, 0x03, 0xad, 0x06, 0x69, 0x91, 0xe0, 0xd1, 0x89, 0x60, 0x84, 0x79, 0xde, 0x27, 0x6d, 0xe6, 0x76, 0xbd, 0xea, 0xe6, 0xae, 0x48, 0xc3, 0x67, 0xc0, 0x57, 0xcd, 0x2f}} ,
+ {{0x7f, 0xc1, 0xdc, 0xb9, 0xc7, 0xbc, 0x86, 0x3d, 0x55, 0x4b, 0x28, 0x7a, 0xfb, 0x4d, 0xc7, 0xf8, 0xbc, 0x67, 0x2a, 0x60, 0x4d, 0x8f, 0x07, 0x0b, 0x1a, 0x17, 0xbf, 0xfa, 0xac, 0xa7, 0x3d, 0x1a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x91, 0x3f, 0xed, 0x5e, 0x18, 0x78, 0x3f, 0x23, 0x2c, 0x0d, 0x8c, 0x44, 0x00, 0xe8, 0xfb, 0xe9, 0x8e, 0xd6, 0xd1, 0x36, 0x58, 0x57, 0x9e, 0xae, 0x4b, 0x5c, 0x0b, 0x07, 0xbc, 0x6b, 0x55, 0x2b}} ,
+ {{0x6f, 0x4d, 0x17, 0xd7, 0xe1, 0x84, 0xd9, 0x78, 0xb1, 0x90, 0xfd, 0x2e, 0xb3, 0xb5, 0x19, 0x3f, 0x1b, 0xfa, 0xc0, 0x68, 0xb3, 0xdd, 0x00, 0x2e, 0x89, 0xbd, 0x7e, 0x80, 0x32, 0x13, 0xa0, 0x7b}}},
+{{{0x1a, 0x6f, 0x40, 0xaf, 0x44, 0x44, 0xb0, 0x43, 0x8f, 0x0d, 0xd0, 0x1e, 0xc4, 0x0b, 0x19, 0x5d, 0x8e, 0xfe, 0xc1, 0xf3, 0xc5, 0x5c, 0x91, 0xf8, 0x04, 0x4e, 0xbe, 0x90, 0xb4, 0x47, 0x5c, 0x3f}} ,
+ {{0xb0, 0x3b, 0x2c, 0xf3, 0xfe, 0x32, 0x71, 0x07, 0x3f, 0xaa, 0xba, 0x45, 0x60, 0xa8, 0x8d, 0xea, 0x54, 0xcb, 0x39, 0x10, 0xb4, 0xf2, 0x8b, 0xd2, 0x14, 0x82, 0x42, 0x07, 0x8e, 0xe9, 0x7c, 0x53}}},
+{{{0xb0, 0xae, 0xc1, 0x8d, 0xc9, 0x8f, 0xb9, 0x7a, 0x77, 0xef, 0xba, 0x79, 0xa0, 0x3c, 0xa8, 0xf5, 0x6a, 0xe2, 0x3f, 0x5d, 0x00, 0xe3, 0x4b, 0x45, 0x24, 0x7b, 0x43, 0x78, 0x55, 0x1d, 0x2b, 0x1e}} ,
+ {{0x01, 0xb8, 0xd6, 0x16, 0x67, 0xa0, 0x15, 0xb9, 0xe1, 0x58, 0xa4, 0xa7, 0x31, 0x37, 0x77, 0x2f, 0x8b, 0x12, 0x9f, 0xf4, 0x3f, 0xc7, 0x36, 0x66, 0xd2, 0xa8, 0x56, 0xf7, 0x7f, 0x74, 0xc6, 0x41}}},
+{{{0x5d, 0xf8, 0xb4, 0xa8, 0x30, 0xdd, 0xcc, 0x38, 0xa5, 0xd3, 0xca, 0xd8, 0xd1, 0xf8, 0xb2, 0x31, 0x91, 0xd4, 0x72, 0x05, 0x57, 0x4a, 0x3b, 0x82, 0x4a, 0xc6, 0x68, 0x20, 0xe2, 0x18, 0x41, 0x61}} ,
+ {{0x19, 0xd4, 0x8d, 0x47, 0x29, 0x12, 0x65, 0xb0, 0x11, 0x78, 0x47, 0xb5, 0xcb, 0xa3, 0xa5, 0xfa, 0x05, 0x85, 0x54, 0xa9, 0x33, 0x97, 0x8d, 0x2b, 0xc2, 0xfe, 0x99, 0x35, 0x28, 0xe5, 0xeb, 0x63}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xb1, 0x3f, 0x3f, 0xef, 0xd8, 0xf4, 0xfc, 0xb3, 0xa0, 0x60, 0x50, 0x06, 0x2b, 0x29, 0x52, 0x70, 0x15, 0x0b, 0x24, 0x24, 0xf8, 0x5f, 0x79, 0x18, 0xcc, 0xff, 0x89, 0x99, 0x84, 0xa1, 0xae, 0x13}} ,
+ {{0x44, 0x1f, 0xb8, 0xc2, 0x01, 0xc1, 0x30, 0x19, 0x55, 0x05, 0x60, 0x10, 0xa4, 0x6c, 0x2d, 0x67, 0x70, 0xe5, 0x25, 0x1b, 0xf2, 0xbf, 0xdd, 0xfb, 0x70, 0x2b, 0xa1, 0x8c, 0x9c, 0x94, 0x84, 0x08}}},
+{{{0xe7, 0xc4, 0x43, 0x4d, 0xc9, 0x2b, 0x69, 0x5d, 0x1d, 0x3c, 0xaf, 0xbb, 0x43, 0x38, 0x4e, 0x98, 0x3d, 0xed, 0x0d, 0x21, 0x03, 0xfd, 0xf0, 0x99, 0x47, 0x04, 0xb0, 0x98, 0x69, 0x55, 0x72, 0x0f}} ,
+ {{0x5e, 0xdf, 0x15, 0x53, 0x3b, 0x86, 0x80, 0xb0, 0xf1, 0x70, 0x68, 0x8f, 0x66, 0x7c, 0x0e, 0x49, 0x1a, 0xd8, 0x6b, 0xfe, 0x4e, 0xef, 0xca, 0x47, 0xd4, 0x03, 0xc1, 0x37, 0x50, 0x9c, 0xc1, 0x16}}},
+{{{0xcd, 0x24, 0xc6, 0x3e, 0x0c, 0x82, 0x9b, 0x91, 0x2b, 0x61, 0x4a, 0xb2, 0x0f, 0x88, 0x55, 0x5f, 0x5a, 0x57, 0xff, 0xe5, 0x74, 0x0b, 0x13, 0x43, 0x00, 0xd8, 0x6b, 0xcf, 0xd2, 0x15, 0x03, 0x2c}} ,
+ {{0xdc, 0xff, 0x15, 0x61, 0x2f, 0x4a, 0x2f, 0x62, 0xf2, 0x04, 0x2f, 0xb5, 0x0c, 0xb7, 0x1e, 0x3f, 0x74, 0x1a, 0x0f, 0xd7, 0xea, 0xcd, 0xd9, 0x7d, 0xf6, 0x12, 0x0e, 0x2f, 0xdb, 0x5a, 0x3b, 0x16}}},
+{{{0x1b, 0x37, 0x47, 0xe3, 0xf5, 0x9e, 0xea, 0x2c, 0x2a, 0xe7, 0x82, 0x36, 0xf4, 0x1f, 0x81, 0x47, 0x92, 0x4b, 0x69, 0x0e, 0x11, 0x8c, 0x5d, 0x53, 0x5b, 0x81, 0x27, 0x08, 0xbc, 0xa0, 0xae, 0x25}} ,
+ {{0x69, 0x32, 0xa1, 0x05, 0x11, 0x42, 0x00, 0xd2, 0x59, 0xac, 0x4d, 0x62, 0x8b, 0x13, 0xe2, 0x50, 0x5d, 0xa0, 0x9d, 0x9b, 0xfd, 0xbb, 0x12, 0x41, 0x75, 0x41, 0x9e, 0xcc, 0xdc, 0xc7, 0xdc, 0x5d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xd9, 0xe3, 0x38, 0x06, 0x46, 0x70, 0x82, 0x5e, 0x28, 0x49, 0x79, 0xff, 0x25, 0xd2, 0x4e, 0x29, 0x8d, 0x06, 0xb0, 0x23, 0xae, 0x9b, 0x66, 0xe4, 0x7d, 0xc0, 0x70, 0x91, 0xa3, 0xfc, 0xec, 0x4e}} ,
+ {{0x62, 0x12, 0x37, 0x6a, 0x30, 0xf6, 0x1e, 0xfb, 0x14, 0x5c, 0x0d, 0x0e, 0xb7, 0x81, 0x6a, 0xe7, 0x08, 0x05, 0xac, 0xaa, 0x38, 0x46, 0xe2, 0x73, 0xea, 0x4b, 0x07, 0x81, 0x43, 0x7c, 0x9e, 0x5e}}},
+{{{0xfc, 0xf9, 0x21, 0x4f, 0x2e, 0x76, 0x9b, 0x1f, 0x28, 0x60, 0x77, 0x43, 0x32, 0x9d, 0xbe, 0x17, 0x30, 0x2a, 0xc6, 0x18, 0x92, 0x66, 0x62, 0x30, 0x98, 0x40, 0x11, 0xa6, 0x7f, 0x18, 0x84, 0x28}} ,
+ {{0x3f, 0xab, 0xd3, 0xf4, 0x8a, 0x76, 0xa1, 0x3c, 0xca, 0x2d, 0x49, 0xc3, 0xea, 0x08, 0x0b, 0x85, 0x17, 0x2a, 0xc3, 0x6c, 0x08, 0xfd, 0x57, 0x9f, 0x3d, 0x5f, 0xdf, 0x67, 0x68, 0x42, 0x00, 0x32}}},
+{{{0x51, 0x60, 0x1b, 0x06, 0x4f, 0x8a, 0x21, 0xba, 0x38, 0xa8, 0xba, 0xd6, 0x40, 0xf6, 0xe9, 0x9b, 0x76, 0x4d, 0x56, 0x21, 0x5b, 0x0a, 0x9b, 0x2e, 0x4f, 0x3d, 0x81, 0x32, 0x08, 0x9f, 0x97, 0x5b}} ,
+ {{0xe5, 0x44, 0xec, 0x06, 0x9d, 0x90, 0x79, 0x9f, 0xd3, 0xe0, 0x79, 0xaf, 0x8f, 0x10, 0xfd, 0xdd, 0x04, 0xae, 0x27, 0x97, 0x46, 0x33, 0x79, 0xea, 0xb8, 0x4e, 0xca, 0x5a, 0x59, 0x57, 0xe1, 0x0e}}},
+{{{0x1a, 0xda, 0xf3, 0xa5, 0x41, 0x43, 0x28, 0xfc, 0x7e, 0xe7, 0x71, 0xea, 0xc6, 0x3b, 0x59, 0xcc, 0x2e, 0xd3, 0x40, 0xec, 0xb3, 0x13, 0x6f, 0x44, 0xcd, 0x13, 0xb2, 0x37, 0xf2, 0x6e, 0xd9, 0x1c}} ,
+ {{0xe3, 0xdb, 0x60, 0xcd, 0x5c, 0x4a, 0x18, 0x0f, 0xef, 0x73, 0x36, 0x71, 0x8c, 0xf6, 0x11, 0xb4, 0xd8, 0xce, 0x17, 0x5e, 0x4f, 0x26, 0x77, 0x97, 0x5f, 0xcb, 0xef, 0x91, 0xeb, 0x6a, 0x62, 0x7a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x18, 0x4a, 0xa2, 0x97, 0x08, 0x81, 0x2d, 0x83, 0xc4, 0xcc, 0xf0, 0x83, 0x7e, 0xec, 0x0d, 0x95, 0x4c, 0x5b, 0xfb, 0xfa, 0x98, 0x80, 0x4a, 0x66, 0x56, 0x0c, 0x51, 0xb3, 0xf2, 0x04, 0x5d, 0x27}} ,
+ {{0x3b, 0xb9, 0xb8, 0x06, 0x5a, 0x2e, 0xfe, 0xc3, 0x82, 0x37, 0x9c, 0xa3, 0x11, 0x1f, 0x9c, 0xa6, 0xda, 0x63, 0x48, 0x9b, 0xad, 0xde, 0x2d, 0xa6, 0xbc, 0x6e, 0x32, 0xda, 0x27, 0x65, 0xdd, 0x57}}},
+{{{0x84, 0x4f, 0x37, 0x31, 0x7d, 0x2e, 0xbc, 0xad, 0x87, 0x07, 0x2a, 0x6b, 0x37, 0xfc, 0x5f, 0xeb, 0x4e, 0x75, 0x35, 0xa6, 0xde, 0xab, 0x0a, 0x19, 0x3a, 0xb7, 0xb1, 0xef, 0x92, 0x6a, 0x3b, 0x3c}} ,
+ {{0x3b, 0xb2, 0x94, 0x6d, 0x39, 0x60, 0xac, 0xee, 0xe7, 0x81, 0x1a, 0x3b, 0x76, 0x87, 0x5c, 0x05, 0x94, 0x2a, 0x45, 0xb9, 0x80, 0xe9, 0x22, 0xb1, 0x07, 0xcb, 0x40, 0x9e, 0x70, 0x49, 0x6d, 0x12}}},
+{{{0xfd, 0x18, 0x78, 0x84, 0xa8, 0x4c, 0x7d, 0x6e, 0x59, 0xa6, 0xe5, 0x74, 0xf1, 0x19, 0xa6, 0x84, 0x2e, 0x51, 0xc1, 0x29, 0x13, 0xf2, 0x14, 0x6b, 0x5d, 0x53, 0x51, 0xf7, 0xef, 0xbf, 0x01, 0x22}} ,
+ {{0xa4, 0x4b, 0x62, 0x4c, 0xe6, 0xfd, 0x72, 0x07, 0xf2, 0x81, 0xfc, 0xf2, 0xbd, 0x12, 0x7c, 0x68, 0x76, 0x2a, 0xba, 0xf5, 0x65, 0xb1, 0x1f, 0x17, 0x0a, 0x38, 0xb0, 0xbf, 0xc0, 0xf8, 0xf4, 0x2a}}},
+{{{0x55, 0x60, 0x55, 0x5b, 0xe4, 0x1d, 0x71, 0x4c, 0x9d, 0x5b, 0x9f, 0x70, 0xa6, 0x85, 0x9a, 0x2c, 0xa0, 0xe2, 0x32, 0x48, 0xce, 0x9e, 0x2a, 0xa5, 0x07, 0x3b, 0xc7, 0x6c, 0x86, 0x77, 0xde, 0x3c}} ,
+ {{0xf7, 0x18, 0x7a, 0x96, 0x7e, 0x43, 0x57, 0xa9, 0x55, 0xfc, 0x4e, 0xb6, 0x72, 0x00, 0xf2, 0xe4, 0xd7, 0x52, 0xd3, 0xd3, 0xb6, 0x85, 0xf6, 0x71, 0xc7, 0x44, 0x3f, 0x7f, 0xd7, 0xb3, 0xf2, 0x79}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x46, 0xca, 0xa7, 0x55, 0x7b, 0x79, 0xf3, 0xca, 0x5a, 0x65, 0xf6, 0xed, 0x50, 0x14, 0x7b, 0xe4, 0xc4, 0x2a, 0x65, 0x9e, 0xe2, 0xf9, 0xca, 0xa7, 0x22, 0x26, 0x53, 0xcb, 0x21, 0x5b, 0xa7, 0x31}} ,
+ {{0x90, 0xd7, 0xc5, 0x26, 0x08, 0xbd, 0xb0, 0x53, 0x63, 0x58, 0xc3, 0x31, 0x5e, 0x75, 0x46, 0x15, 0x91, 0xa6, 0xf8, 0x2f, 0x1a, 0x08, 0x65, 0x88, 0x2f, 0x98, 0x04, 0xf1, 0x7c, 0x6e, 0x00, 0x77}}},
+{{{0x81, 0x21, 0x61, 0x09, 0xf6, 0x4e, 0xf1, 0x92, 0xee, 0x63, 0x61, 0x73, 0x87, 0xc7, 0x54, 0x0e, 0x42, 0x4b, 0xc9, 0x47, 0xd1, 0xb8, 0x7e, 0x91, 0x75, 0x37, 0x99, 0x28, 0xb8, 0xdd, 0x7f, 0x50}} ,
+ {{0x89, 0x8f, 0xc0, 0xbe, 0x5d, 0xd6, 0x9f, 0xa0, 0xf0, 0x9d, 0x81, 0xce, 0x3a, 0x7b, 0x98, 0x58, 0xbb, 0xd7, 0x78, 0xc8, 0x3f, 0x13, 0xf1, 0x74, 0x19, 0xdf, 0xf8, 0x98, 0x89, 0x5d, 0xfa, 0x5f}}},
+{{{0x9e, 0x35, 0x85, 0x94, 0x47, 0x1f, 0x90, 0x15, 0x26, 0xd0, 0x84, 0xed, 0x8a, 0x80, 0xf7, 0x63, 0x42, 0x86, 0x27, 0xd7, 0xf4, 0x75, 0x58, 0xdc, 0x9c, 0xc0, 0x22, 0x7e, 0x20, 0x35, 0xfd, 0x1f}} ,
+ {{0x68, 0x0e, 0x6f, 0x97, 0xba, 0x70, 0xbb, 0xa3, 0x0e, 0xe5, 0x0b, 0x12, 0xf4, 0xa2, 0xdc, 0x47, 0xf8, 0xe6, 0xd0, 0x23, 0x6c, 0x33, 0xa8, 0x99, 0x46, 0x6e, 0x0f, 0x44, 0xba, 0x76, 0x48, 0x0f}}},
+{{{0xa3, 0x2a, 0x61, 0x37, 0xe2, 0x59, 0x12, 0x0e, 0x27, 0xba, 0x64, 0x43, 0xae, 0xc0, 0x42, 0x69, 0x79, 0xa4, 0x1e, 0x29, 0x8b, 0x15, 0xeb, 0xf8, 0xaf, 0xd4, 0xa2, 0x68, 0x33, 0xb5, 0x7a, 0x24}} ,
+ {{0x2c, 0x19, 0x33, 0xdd, 0x1b, 0xab, 0xec, 0x01, 0xb0, 0x23, 0xf8, 0x42, 0x2b, 0x06, 0x88, 0xea, 0x3d, 0x2d, 0x00, 0x2a, 0x78, 0x45, 0x4d, 0x38, 0xed, 0x2e, 0x2e, 0x44, 0x49, 0xed, 0xcb, 0x33}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xa0, 0x68, 0xe8, 0x41, 0x8f, 0x91, 0xf8, 0x11, 0x13, 0x90, 0x2e, 0xa7, 0xab, 0x30, 0xef, 0xad, 0xa0, 0x61, 0x00, 0x88, 0xef, 0xdb, 0xce, 0x5b, 0x5c, 0xbb, 0x62, 0xc8, 0x56, 0xf9, 0x00, 0x73}} ,
+ {{0x3f, 0x60, 0xc1, 0x82, 0x2d, 0xa3, 0x28, 0x58, 0x24, 0x9e, 0x9f, 0xe3, 0x70, 0xcc, 0x09, 0x4e, 0x1a, 0x3f, 0x11, 0x11, 0x15, 0x07, 0x3c, 0xa4, 0x41, 0xe0, 0x65, 0xa3, 0x0a, 0x41, 0x6d, 0x11}}},
+{{{0x31, 0x40, 0x01, 0x52, 0x56, 0x94, 0x5b, 0x28, 0x8a, 0xaa, 0x52, 0xee, 0xd8, 0x0a, 0x05, 0x8d, 0xcd, 0xb5, 0xaa, 0x2e, 0x38, 0xaa, 0xb7, 0x87, 0xf7, 0x2b, 0xfb, 0x04, 0xcb, 0x84, 0x3d, 0x54}} ,
+ {{0x20, 0xef, 0x59, 0xde, 0xa4, 0x2b, 0x93, 0x6e, 0x2e, 0xec, 0x42, 0x9a, 0xd4, 0x2d, 0xf4, 0x46, 0x58, 0x27, 0x2b, 0x18, 0x8f, 0x83, 0x3d, 0x69, 0x9e, 0xd4, 0x3e, 0xb6, 0xc5, 0xfd, 0x58, 0x03}}},
+{{{0x33, 0x89, 0xc9, 0x63, 0x62, 0x1c, 0x17, 0xb4, 0x60, 0xc4, 0x26, 0x68, 0x09, 0xc3, 0x2e, 0x37, 0x0f, 0x7b, 0xb4, 0x9c, 0xb6, 0xf9, 0xfb, 0xd4, 0x51, 0x78, 0xc8, 0x63, 0xea, 0x77, 0x47, 0x07}} ,
+ {{0x32, 0xb4, 0x18, 0x47, 0x79, 0xcb, 0xd4, 0x5a, 0x07, 0x14, 0x0f, 0xa0, 0xd5, 0xac, 0xd0, 0x41, 0x40, 0xab, 0x61, 0x23, 0xe5, 0x2a, 0x2a, 0x6f, 0xf7, 0xa8, 0xd4, 0x76, 0xef, 0xe7, 0x45, 0x6c}}},
+{{{0xa1, 0x5e, 0x60, 0x4f, 0xfb, 0xe1, 0x70, 0x6a, 0x1f, 0x55, 0x4f, 0x09, 0xb4, 0x95, 0x33, 0x36, 0xc6, 0x81, 0x01, 0x18, 0x06, 0x25, 0x27, 0xa4, 0xb4, 0x24, 0xa4, 0x86, 0x03, 0x4c, 0xac, 0x02}} ,
+ {{0x77, 0x38, 0xde, 0xd7, 0x60, 0x48, 0x07, 0xf0, 0x74, 0xa8, 0xff, 0x54, 0xe5, 0x30, 0x43, 0xff, 0x77, 0xfb, 0x21, 0x07, 0xff, 0xb2, 0x07, 0x6b, 0xe4, 0xe5, 0x30, 0xfc, 0x19, 0x6c, 0xa3, 0x01}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x13, 0xc5, 0x2c, 0xac, 0xd3, 0x83, 0x82, 0x7c, 0x29, 0xf7, 0x05, 0xa5, 0x00, 0xb6, 0x1f, 0x86, 0x55, 0xf4, 0xd6, 0x2f, 0x0c, 0x99, 0xd0, 0x65, 0x9b, 0x6b, 0x46, 0x0d, 0x43, 0xf8, 0x16, 0x28}} ,
+ {{0x1e, 0x7f, 0xb4, 0x74, 0x7e, 0xb1, 0x89, 0x4f, 0x18, 0x5a, 0xab, 0x64, 0x06, 0xdf, 0x45, 0x87, 0xe0, 0x6a, 0xc6, 0xf0, 0x0e, 0xc9, 0x24, 0x35, 0x38, 0xea, 0x30, 0x54, 0xb4, 0xc4, 0x52, 0x54}}},
+{{{0xe9, 0x9f, 0xdc, 0x3f, 0xc1, 0x89, 0x44, 0x74, 0x27, 0xe4, 0xc1, 0x90, 0xff, 0x4a, 0xa7, 0x3c, 0xee, 0xcd, 0xf4, 0x1d, 0x25, 0x94, 0x7f, 0x63, 0x16, 0x48, 0xbc, 0x64, 0xfe, 0x95, 0xc4, 0x0c}} ,
+ {{0x8b, 0x19, 0x75, 0x6e, 0x03, 0x06, 0x5e, 0x6a, 0x6f, 0x1a, 0x8c, 0xe3, 0xd3, 0x28, 0xf2, 0xe0, 0xb9, 0x7a, 0x43, 0x69, 0xe6, 0xd3, 0xc0, 0xfe, 0x7e, 0x97, 0xab, 0x6c, 0x7b, 0x8e, 0x13, 0x42}}},
+{{{0xd4, 0xca, 0x70, 0x3d, 0xab, 0xfb, 0x5f, 0x5e, 0x00, 0x0c, 0xcc, 0x77, 0x22, 0xf8, 0x78, 0x55, 0xae, 0x62, 0x35, 0xfb, 0x9a, 0xc6, 0x03, 0xe4, 0x0c, 0xee, 0xab, 0xc7, 0xc0, 0x89, 0x87, 0x54}} ,
+ {{0x32, 0xad, 0xae, 0x85, 0x58, 0x43, 0xb8, 0xb1, 0xe6, 0x3e, 0x00, 0x9c, 0x78, 0x88, 0x56, 0xdb, 0x9c, 0xfc, 0x79, 0xf6, 0xf9, 0x41, 0x5f, 0xb7, 0xbc, 0x11, 0xf9, 0x20, 0x36, 0x1c, 0x53, 0x2b}}},
+{{{0x5a, 0x20, 0x5b, 0xa1, 0xa5, 0x44, 0x91, 0x24, 0x02, 0x63, 0x12, 0x64, 0xb8, 0x55, 0xf6, 0xde, 0x2c, 0xdb, 0x47, 0xb8, 0xc6, 0x0a, 0xc3, 0x00, 0x78, 0x93, 0xd8, 0xf5, 0xf5, 0x18, 0x28, 0x0a}} ,
+ {{0xd6, 0x1b, 0x9a, 0x6c, 0xe5, 0x46, 0xea, 0x70, 0x96, 0x8d, 0x4e, 0x2a, 0x52, 0x21, 0x26, 0x4b, 0xb1, 0xbb, 0x0f, 0x7c, 0xa9, 0x9b, 0x04, 0xbb, 0x51, 0x08, 0xf1, 0x9a, 0xa4, 0x76, 0x7c, 0x18}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xfa, 0x94, 0xf7, 0x40, 0xd0, 0xd7, 0xeb, 0xa9, 0x82, 0x36, 0xd5, 0x15, 0xb9, 0x33, 0x7a, 0xbf, 0x8a, 0xf2, 0x63, 0xaa, 0x37, 0xf5, 0x59, 0xac, 0xbd, 0xbb, 0x32, 0x36, 0xbe, 0x73, 0x99, 0x38}} ,
+ {{0x2c, 0xb3, 0xda, 0x7a, 0xd8, 0x3d, 0x99, 0xca, 0xd2, 0xf4, 0xda, 0x99, 0x8e, 0x4f, 0x98, 0xb7, 0xf4, 0xae, 0x3e, 0x9f, 0x8e, 0x35, 0x60, 0xa4, 0x33, 0x75, 0xa4, 0x04, 0x93, 0xb1, 0x6b, 0x4d}}},
+{{{0x97, 0x9d, 0xa8, 0xcd, 0x97, 0x7b, 0x9d, 0xb9, 0xe7, 0xa5, 0xef, 0xfd, 0xa8, 0x42, 0x6b, 0xc3, 0x62, 0x64, 0x7d, 0xa5, 0x1b, 0xc9, 0x9e, 0xd2, 0x45, 0xb9, 0xee, 0x03, 0xb0, 0xbf, 0xc0, 0x68}} ,
+ {{0xed, 0xb7, 0x84, 0x2c, 0xf6, 0xd3, 0xa1, 0x6b, 0x24, 0x6d, 0x87, 0x56, 0x97, 0x59, 0x79, 0x62, 0x9f, 0xac, 0xed, 0xf3, 0xc9, 0x89, 0x21, 0x2e, 0x04, 0xb3, 0xcc, 0x2f, 0xbe, 0xd6, 0x0a, 0x4b}}},
+{{{0x39, 0x61, 0x05, 0xed, 0x25, 0x89, 0x8b, 0x5d, 0x1b, 0xcb, 0x0c, 0x55, 0xf4, 0x6a, 0x00, 0x8a, 0x46, 0xe8, 0x1e, 0xc6, 0x83, 0xc8, 0x5a, 0x76, 0xdb, 0xcc, 0x19, 0x7a, 0xcc, 0x67, 0x46, 0x0b}} ,
+ {{0x53, 0xcf, 0xc2, 0xa1, 0xad, 0x6a, 0xf3, 0xcd, 0x8f, 0xc9, 0xde, 0x1c, 0xf8, 0x6c, 0x8f, 0xf8, 0x76, 0x42, 0xe7, 0xfe, 0xb2, 0x72, 0x21, 0x0a, 0x66, 0x74, 0x8f, 0xb7, 0xeb, 0xe4, 0x6f, 0x01}}},
+{{{0x22, 0x8c, 0x6b, 0xbe, 0xfc, 0x4d, 0x70, 0x62, 0x6e, 0x52, 0x77, 0x99, 0x88, 0x7e, 0x7b, 0x57, 0x7a, 0x0d, 0xfe, 0xdc, 0x72, 0x92, 0xf1, 0x68, 0x1d, 0x97, 0xd7, 0x7c, 0x8d, 0x53, 0x10, 0x37}} ,
+ {{0x53, 0x88, 0x77, 0x02, 0xca, 0x27, 0xa8, 0xe5, 0x45, 0xe2, 0xa8, 0x48, 0x2a, 0xab, 0x18, 0xca, 0xea, 0x2d, 0x2a, 0x54, 0x17, 0x37, 0x32, 0x09, 0xdc, 0xe0, 0x4a, 0xb7, 0x7d, 0x82, 0x10, 0x7d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x8a, 0x64, 0x1e, 0x14, 0x0a, 0x57, 0xd4, 0xda, 0x5c, 0x96, 0x9b, 0x01, 0x4c, 0x67, 0xbf, 0x8b, 0x30, 0xfe, 0x08, 0xdb, 0x0d, 0xd5, 0xa8, 0xd7, 0x09, 0x11, 0x85, 0xa2, 0xd3, 0x45, 0xfb, 0x7e}} ,
+ {{0xda, 0x8c, 0xc2, 0xd0, 0xac, 0x18, 0xe8, 0x52, 0x36, 0xd4, 0x21, 0xa3, 0xdd, 0x57, 0x22, 0x79, 0xb7, 0xf8, 0x71, 0x9d, 0xc6, 0x91, 0x70, 0x86, 0x56, 0xbf, 0xa1, 0x11, 0x8b, 0x19, 0xe1, 0x0f}}},
+{{{0x18, 0x32, 0x98, 0x2c, 0x8f, 0x91, 0xae, 0x12, 0xf0, 0x8c, 0xea, 0xf3, 0x3c, 0xb9, 0x5d, 0xe4, 0x69, 0xed, 0xb2, 0x47, 0x18, 0xbd, 0xce, 0x16, 0x52, 0x5c, 0x23, 0xe2, 0xa5, 0x25, 0x52, 0x5d}} ,
+ {{0xb9, 0xb1, 0xe7, 0x5d, 0x4e, 0xbc, 0xee, 0xbb, 0x40, 0x81, 0x77, 0x82, 0x19, 0xab, 0xb5, 0xc6, 0xee, 0xab, 0x5b, 0x6b, 0x63, 0x92, 0x8a, 0x34, 0x8d, 0xcd, 0xee, 0x4f, 0x49, 0xe5, 0xc9, 0x7e}}},
+{{{0x21, 0xac, 0x8b, 0x22, 0xcd, 0xc3, 0x9a, 0xe9, 0x5e, 0x78, 0xbd, 0xde, 0xba, 0xad, 0xab, 0xbf, 0x75, 0x41, 0x09, 0xc5, 0x58, 0xa4, 0x7d, 0x92, 0xb0, 0x7f, 0xf2, 0xa1, 0xd1, 0xc0, 0xb3, 0x6d}} ,
+ {{0x62, 0x4f, 0xd0, 0x75, 0x77, 0xba, 0x76, 0x77, 0xd7, 0xb8, 0xd8, 0x92, 0x6f, 0x98, 0x34, 0x3d, 0xd6, 0x4e, 0x1c, 0x0f, 0xf0, 0x8f, 0x2e, 0xf1, 0xb3, 0xbd, 0xb1, 0xb9, 0xec, 0x99, 0xb4, 0x07}}},
+{{{0x60, 0x57, 0x2e, 0x9a, 0x72, 0x1d, 0x6b, 0x6e, 0x58, 0x33, 0x24, 0x8c, 0x48, 0x39, 0x46, 0x8e, 0x89, 0x6a, 0x88, 0x51, 0x23, 0x62, 0xb5, 0x32, 0x09, 0x36, 0xe3, 0x57, 0xf5, 0x98, 0xde, 0x6f}} ,
+ {{0x8b, 0x2c, 0x00, 0x48, 0x4a, 0xf9, 0x5b, 0x87, 0x69, 0x52, 0xe5, 0x5b, 0xd1, 0xb1, 0xe5, 0x25, 0x25, 0xe0, 0x9c, 0xc2, 0x13, 0x44, 0xe8, 0xb9, 0x0a, 0x70, 0xad, 0xbd, 0x0f, 0x51, 0x94, 0x69}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xa2, 0xdc, 0xab, 0xa9, 0x25, 0x2d, 0xac, 0x5f, 0x03, 0x33, 0x08, 0xe7, 0x7e, 0xfe, 0x95, 0x36, 0x3c, 0x5b, 0x3a, 0xd3, 0x05, 0x82, 0x1c, 0x95, 0x2d, 0xd8, 0x77, 0x7e, 0x02, 0xd9, 0x5b, 0x70}} ,
+ {{0xc2, 0xfe, 0x1b, 0x0c, 0x67, 0xcd, 0xd6, 0xe0, 0x51, 0x8e, 0x2c, 0xe0, 0x79, 0x88, 0xf0, 0xcf, 0x41, 0x4a, 0xad, 0x23, 0xd4, 0x46, 0xca, 0x94, 0xa1, 0xc3, 0xeb, 0x28, 0x06, 0xfa, 0x17, 0x14}}},
+{{{0x7b, 0xaa, 0x70, 0x0a, 0x4b, 0xfb, 0xf5, 0xbf, 0x80, 0xc5, 0xcf, 0x08, 0x7a, 0xdd, 0xa1, 0xf4, 0x9d, 0x54, 0x50, 0x53, 0x23, 0x77, 0x23, 0xf5, 0x34, 0xa5, 0x22, 0xd1, 0x0d, 0x96, 0x2e, 0x47}} ,
+ {{0xcc, 0xb7, 0x32, 0x89, 0x57, 0xd0, 0x98, 0x75, 0xe4, 0x37, 0x99, 0xa9, 0xe8, 0xba, 0xed, 0xba, 0xeb, 0xc7, 0x4f, 0x15, 0x76, 0x07, 0x0c, 0x4c, 0xef, 0x9f, 0x52, 0xfc, 0x04, 0x5d, 0x58, 0x10}}},
+{{{0xce, 0x82, 0xf0, 0x8f, 0x79, 0x02, 0xa8, 0xd1, 0xda, 0x14, 0x09, 0x48, 0xee, 0x8a, 0x40, 0x98, 0x76, 0x60, 0x54, 0x5a, 0xde, 0x03, 0x24, 0xf5, 0xe6, 0x2f, 0xe1, 0x03, 0xbf, 0x68, 0x82, 0x7f}} ,
+ {{0x64, 0xe9, 0x28, 0xc7, 0xa4, 0xcf, 0x2a, 0xf9, 0x90, 0x64, 0x72, 0x2c, 0x8b, 0xeb, 0xec, 0xa0, 0xf2, 0x7d, 0x35, 0xb5, 0x90, 0x4d, 0x7f, 0x5b, 0x4a, 0x49, 0xe4, 0xb8, 0x3b, 0xc8, 0xa1, 0x2f}}},
+{{{0x8b, 0xc5, 0xcc, 0x3d, 0x69, 0xa6, 0xa1, 0x18, 0x44, 0xbc, 0x4d, 0x77, 0x37, 0xc7, 0x86, 0xec, 0x0c, 0xc9, 0xd6, 0x44, 0xa9, 0x23, 0x27, 0xb9, 0x03, 0x34, 0xa7, 0x0a, 0xd5, 0xc7, 0x34, 0x37}} ,
+ {{0xf9, 0x7e, 0x3e, 0x66, 0xee, 0xf9, 0x99, 0x28, 0xff, 0xad, 0x11, 0xd8, 0xe2, 0x66, 0xc5, 0xcd, 0x0f, 0x0d, 0x0b, 0x6a, 0xfc, 0x7c, 0x24, 0xa8, 0x4f, 0xa8, 0x5e, 0x80, 0x45, 0x8b, 0x6c, 0x41}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xef, 0x1e, 0xec, 0xf7, 0x8d, 0x77, 0xf2, 0xea, 0xdb, 0x60, 0x03, 0x21, 0xc0, 0xff, 0x5e, 0x67, 0xc3, 0x71, 0x0b, 0x21, 0xb4, 0x41, 0xa0, 0x68, 0x38, 0xc6, 0x01, 0xa3, 0xd3, 0x51, 0x3c, 0x3c}} ,
+ {{0x92, 0xf8, 0xd6, 0x4b, 0xef, 0x42, 0x13, 0xb2, 0x4a, 0xc4, 0x2e, 0x72, 0x3f, 0xc9, 0x11, 0xbd, 0x74, 0x02, 0x0e, 0xf5, 0x13, 0x9d, 0x83, 0x1a, 0x1b, 0xd5, 0x54, 0xde, 0xc4, 0x1e, 0x16, 0x6c}}},
+{{{0x27, 0x52, 0xe4, 0x63, 0xaa, 0x94, 0xe6, 0xc3, 0x28, 0x9c, 0xc6, 0x56, 0xac, 0xfa, 0xb6, 0xbd, 0xe2, 0xcc, 0x76, 0xc6, 0x27, 0x27, 0xa2, 0x8e, 0x78, 0x2b, 0x84, 0x72, 0x10, 0xbd, 0x4e, 0x2a}} ,
+ {{0xea, 0xa7, 0x23, 0xef, 0x04, 0x61, 0x80, 0x50, 0xc9, 0x6e, 0xa5, 0x96, 0xd1, 0xd1, 0xc8, 0xc3, 0x18, 0xd7, 0x2d, 0xfd, 0x26, 0xbd, 0xcb, 0x7b, 0x92, 0x51, 0x0e, 0x4a, 0x65, 0x57, 0xb8, 0x49}}},
+{{{0xab, 0x55, 0x36, 0xc3, 0xec, 0x63, 0x55, 0x11, 0x55, 0xf6, 0xa5, 0xc7, 0x01, 0x5f, 0xfe, 0x79, 0xd8, 0x0a, 0xf7, 0x03, 0xd8, 0x98, 0x99, 0xf5, 0xd0, 0x00, 0x54, 0x6b, 0x66, 0x28, 0xf5, 0x25}} ,
+ {{0x7a, 0x8d, 0xa1, 0x5d, 0x70, 0x5d, 0x51, 0x27, 0xee, 0x30, 0x65, 0x56, 0x95, 0x46, 0xde, 0xbd, 0x03, 0x75, 0xb4, 0x57, 0x59, 0x89, 0xeb, 0x02, 0x9e, 0xcc, 0x89, 0x19, 0xa7, 0xcb, 0x17, 0x67}}},
+{{{0x6a, 0xeb, 0xfc, 0x9a, 0x9a, 0x10, 0xce, 0xdb, 0x3a, 0x1c, 0x3c, 0x6a, 0x9d, 0xea, 0x46, 0xbc, 0x45, 0x49, 0xac, 0xe3, 0x41, 0x12, 0x7c, 0xf0, 0xf7, 0x4f, 0xf9, 0xf7, 0xff, 0x2c, 0x89, 0x04}} ,
+ {{0x30, 0x31, 0x54, 0x1a, 0x46, 0xca, 0xe6, 0xc6, 0xcb, 0xe2, 0xc3, 0xc1, 0x8b, 0x75, 0x81, 0xbe, 0xee, 0xf8, 0xa3, 0x11, 0x1c, 0x25, 0xa3, 0xa7, 0x35, 0x51, 0x55, 0xe2, 0x25, 0xaa, 0xe2, 0x3a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xb4, 0x48, 0x10, 0x9f, 0x8a, 0x09, 0x76, 0xfa, 0xf0, 0x7a, 0xb0, 0x70, 0xf7, 0x83, 0x80, 0x52, 0x84, 0x2b, 0x26, 0xa2, 0xc4, 0x5d, 0x4f, 0xba, 0xb1, 0xc8, 0x40, 0x0d, 0x78, 0x97, 0xc4, 0x60}} ,
+ {{0xd4, 0xb1, 0x6c, 0x08, 0xc7, 0x40, 0x38, 0x73, 0x5f, 0x0b, 0xf3, 0x76, 0x5d, 0xb2, 0xa5, 0x2f, 0x57, 0x57, 0x07, 0xed, 0x08, 0xa2, 0x6c, 0x4f, 0x08, 0x02, 0xb5, 0x0e, 0xee, 0x44, 0xfa, 0x22}}},
+{{{0x0f, 0x00, 0x3f, 0xa6, 0x04, 0x19, 0x56, 0x65, 0x31, 0x7f, 0x8b, 0xeb, 0x0d, 0xe1, 0x47, 0x89, 0x97, 0x16, 0x53, 0xfa, 0x81, 0xa7, 0xaa, 0xb2, 0xbf, 0x67, 0xeb, 0x72, 0x60, 0x81, 0x0d, 0x48}} ,
+ {{0x7e, 0x13, 0x33, 0xcd, 0xa8, 0x84, 0x56, 0x1e, 0x67, 0xaf, 0x6b, 0x43, 0xac, 0x17, 0xaf, 0x16, 0xc0, 0x52, 0x99, 0x49, 0x5b, 0x87, 0x73, 0x7e, 0xb5, 0x43, 0xda, 0x6b, 0x1d, 0x0f, 0x2d, 0x55}}},
+{{{0xe9, 0x58, 0x1f, 0xff, 0x84, 0x3f, 0x93, 0x1c, 0xcb, 0xe1, 0x30, 0x69, 0xa5, 0x75, 0x19, 0x7e, 0x14, 0x5f, 0xf8, 0xfc, 0x09, 0xdd, 0xa8, 0x78, 0x9d, 0xca, 0x59, 0x8b, 0xd1, 0x30, 0x01, 0x13}} ,
+ {{0xff, 0x76, 0x03, 0xc5, 0x4b, 0x89, 0x99, 0x70, 0x00, 0x59, 0x70, 0x9c, 0xd5, 0xd9, 0x11, 0x89, 0x5a, 0x46, 0xfe, 0xef, 0xdc, 0xd9, 0x55, 0x2b, 0x45, 0xa7, 0xb0, 0x2d, 0xfb, 0x24, 0xc2, 0x29}}},
+{{{0x38, 0x06, 0xf8, 0x0b, 0xac, 0x82, 0xc4, 0x97, 0x2b, 0x90, 0xe0, 0xf7, 0xa8, 0xab, 0x6c, 0x08, 0x80, 0x66, 0x90, 0x46, 0xf7, 0x26, 0x2d, 0xf8, 0xf1, 0xc4, 0x6b, 0x4a, 0x82, 0x98, 0x8e, 0x37}} ,
+ {{0x8e, 0xb4, 0xee, 0xb8, 0xd4, 0x3f, 0xb2, 0x1b, 0xe0, 0x0a, 0x3d, 0x75, 0x34, 0x28, 0xa2, 0x8e, 0xc4, 0x92, 0x7b, 0xfe, 0x60, 0x6e, 0x6d, 0xb8, 0x31, 0x1d, 0x62, 0x0d, 0x78, 0x14, 0x42, 0x11}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x5e, 0xa8, 0xd8, 0x04, 0x9b, 0x73, 0xc9, 0xc9, 0xdc, 0x0d, 0x73, 0xbf, 0x0a, 0x0a, 0x73, 0xff, 0x18, 0x1f, 0x9c, 0x51, 0xaa, 0xc6, 0xf1, 0x83, 0x25, 0xfd, 0xab, 0xa3, 0x11, 0xd3, 0x01, 0x24}} ,
+ {{0x4d, 0xe3, 0x7e, 0x38, 0x62, 0x5e, 0x64, 0xbb, 0x2b, 0x53, 0xb5, 0x03, 0x68, 0xc4, 0xf2, 0x2b, 0x5a, 0x03, 0x32, 0x99, 0x4a, 0x41, 0x9a, 0xe1, 0x1a, 0xae, 0x8c, 0x48, 0xf3, 0x24, 0x32, 0x65}}},
+{{{0xe8, 0xdd, 0xad, 0x3a, 0x8c, 0xea, 0xf4, 0xb3, 0xb2, 0xe5, 0x73, 0xf2, 0xed, 0x8b, 0xbf, 0xed, 0xb1, 0x0c, 0x0c, 0xfb, 0x2b, 0xf1, 0x01, 0x48, 0xe8, 0x26, 0x03, 0x8e, 0x27, 0x4d, 0x96, 0x72}} ,
+ {{0xc8, 0x09, 0x3b, 0x60, 0xc9, 0x26, 0x4d, 0x7c, 0xf2, 0x9c, 0xd4, 0xa1, 0x3b, 0x26, 0xc2, 0x04, 0x33, 0x44, 0x76, 0x3c, 0x02, 0xbb, 0x11, 0x42, 0x0c, 0x22, 0xb7, 0xc6, 0xe1, 0xac, 0xb4, 0x0e}}},
+{{{0x6f, 0x85, 0xe7, 0xef, 0xde, 0x67, 0x30, 0xfc, 0xbf, 0x5a, 0xe0, 0x7b, 0x7a, 0x2a, 0x54, 0x6b, 0x5d, 0x62, 0x85, 0xa1, 0xf8, 0x16, 0x88, 0xec, 0x61, 0xb9, 0x96, 0xb5, 0xef, 0x2d, 0x43, 0x4d}} ,
+ {{0x7c, 0x31, 0x33, 0xcc, 0xe4, 0xcf, 0x6c, 0xff, 0x80, 0x47, 0x77, 0xd1, 0xd8, 0xe9, 0x69, 0x97, 0x98, 0x7f, 0x20, 0x57, 0x1d, 0x1d, 0x4f, 0x08, 0x27, 0xc8, 0x35, 0x57, 0x40, 0xc6, 0x21, 0x0c}}},
+{{{0xd2, 0x8e, 0x9b, 0xfa, 0x42, 0x8e, 0xdf, 0x8f, 0xc7, 0x86, 0xf9, 0xa4, 0xca, 0x70, 0x00, 0x9d, 0x21, 0xbf, 0xec, 0x57, 0x62, 0x30, 0x58, 0x8c, 0x0d, 0x35, 0xdb, 0x5d, 0x8b, 0x6a, 0xa0, 0x5a}} ,
+ {{0xc1, 0x58, 0x7c, 0x0d, 0x20, 0xdd, 0x11, 0x26, 0x5f, 0x89, 0x3b, 0x97, 0x58, 0xf8, 0x8b, 0xe3, 0xdf, 0x32, 0xe2, 0xfc, 0xd8, 0x67, 0xf2, 0xa5, 0x37, 0x1e, 0x6d, 0xec, 0x7c, 0x27, 0x20, 0x79}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xd0, 0xe9, 0xc0, 0xfa, 0x95, 0x45, 0x23, 0x96, 0xf1, 0x2c, 0x79, 0x25, 0x14, 0xce, 0x40, 0x14, 0x44, 0x2c, 0x36, 0x50, 0xd9, 0x63, 0x56, 0xb7, 0x56, 0x3b, 0x9e, 0xa7, 0xef, 0x89, 0xbb, 0x0e}} ,
+ {{0xce, 0x7f, 0xdc, 0x0a, 0xcc, 0x82, 0x1c, 0x0a, 0x78, 0x71, 0xe8, 0x74, 0x8d, 0x01, 0x30, 0x0f, 0xa7, 0x11, 0x4c, 0xdf, 0x38, 0xd7, 0xa7, 0x0d, 0xf8, 0x48, 0x52, 0x00, 0x80, 0x7b, 0x5f, 0x0e}}},
+{{{0x25, 0x83, 0xe6, 0x94, 0x7b, 0x81, 0xb2, 0x91, 0xae, 0x0e, 0x05, 0xc9, 0xa3, 0x68, 0x2d, 0xd9, 0x88, 0x25, 0x19, 0x2a, 0x61, 0x61, 0x21, 0x97, 0x15, 0xa1, 0x35, 0xa5, 0x46, 0xc8, 0xa2, 0x0e}} ,
+ {{0x1b, 0x03, 0x0d, 0x8b, 0x5a, 0x1b, 0x97, 0x4b, 0xf2, 0x16, 0x31, 0x3d, 0x1f, 0x33, 0xa0, 0x50, 0x3a, 0x18, 0xbe, 0x13, 0xa1, 0x76, 0xc1, 0xba, 0x1b, 0xf1, 0x05, 0x7b, 0x33, 0xa8, 0x82, 0x3b}}},
+{{{0xba, 0x36, 0x7b, 0x6d, 0xa9, 0xea, 0x14, 0x12, 0xc5, 0xfa, 0x91, 0x00, 0xba, 0x9b, 0x99, 0xcc, 0x56, 0x02, 0xe9, 0xa0, 0x26, 0x40, 0x66, 0x8c, 0xc4, 0xf8, 0x85, 0x33, 0x68, 0xe7, 0x03, 0x20}} ,
+ {{0x50, 0x5b, 0xff, 0xa9, 0xb2, 0xf1, 0xf1, 0x78, 0xcf, 0x14, 0xa4, 0xa9, 0xfc, 0x09, 0x46, 0x94, 0x54, 0x65, 0x0d, 0x9c, 0x5f, 0x72, 0x21, 0xe2, 0x97, 0xa5, 0x2d, 0x81, 0xce, 0x4a, 0x5f, 0x79}}},
+{{{0x3d, 0x5f, 0x5c, 0xd2, 0xbc, 0x7d, 0x77, 0x0e, 0x2a, 0x6d, 0x22, 0x45, 0x84, 0x06, 0xc4, 0xdd, 0xc6, 0xa6, 0xc6, 0xd7, 0x49, 0xad, 0x6d, 0x87, 0x91, 0x0e, 0x3a, 0x67, 0x1d, 0x2c, 0x1d, 0x56}} ,
+ {{0xfe, 0x7a, 0x74, 0xcf, 0xd4, 0xd2, 0xe5, 0x19, 0xde, 0xd0, 0xdb, 0x70, 0x23, 0x69, 0xe6, 0x6d, 0xec, 0xec, 0xcc, 0x09, 0x33, 0x6a, 0x77, 0xdc, 0x6b, 0x22, 0x76, 0x5d, 0x92, 0x09, 0xac, 0x2d}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x23, 0x15, 0x17, 0xeb, 0xd3, 0xdb, 0x12, 0x5e, 0x01, 0xf0, 0x91, 0xab, 0x2c, 0x41, 0xce, 0xac, 0xed, 0x1b, 0x4b, 0x2d, 0xbc, 0xdb, 0x17, 0x66, 0x89, 0x46, 0xad, 0x4b, 0x1e, 0x6f, 0x0b, 0x14}} ,
+ {{0x11, 0xce, 0xbf, 0xb6, 0x77, 0x2d, 0x48, 0x22, 0x18, 0x4f, 0xa3, 0x5d, 0x4a, 0xb0, 0x70, 0x12, 0x3e, 0x54, 0xd7, 0xd8, 0x0e, 0x2b, 0x27, 0xdc, 0x53, 0xff, 0xca, 0x8c, 0x59, 0xb3, 0x4e, 0x44}}},
+{{{0x07, 0x76, 0x61, 0x0f, 0x66, 0xb2, 0x21, 0x39, 0x7e, 0xc0, 0xec, 0x45, 0x28, 0x82, 0xa1, 0x29, 0x32, 0x44, 0x35, 0x13, 0x5e, 0x61, 0x5e, 0x54, 0xcb, 0x7c, 0xef, 0xf6, 0x41, 0xcf, 0x9f, 0x0a}} ,
+ {{0xdd, 0xf9, 0xda, 0x84, 0xc3, 0xe6, 0x8a, 0x9f, 0x24, 0xd2, 0x96, 0x5d, 0x39, 0x6f, 0x58, 0x8c, 0xc1, 0x56, 0x93, 0xab, 0xb5, 0x79, 0x3b, 0xd2, 0xa8, 0x73, 0x16, 0xed, 0xfa, 0xb4, 0x2f, 0x73}}},
+{{{0x8b, 0xb1, 0x95, 0xe5, 0x92, 0x50, 0x35, 0x11, 0x76, 0xac, 0xf4, 0x4d, 0x24, 0xc3, 0x32, 0xe6, 0xeb, 0xfe, 0x2c, 0x87, 0xc4, 0xf1, 0x56, 0xc4, 0x75, 0x24, 0x7a, 0x56, 0x85, 0x5a, 0x3a, 0x13}} ,
+ {{0x0d, 0x16, 0xac, 0x3c, 0x4a, 0x58, 0x86, 0x3a, 0x46, 0x7f, 0x6c, 0xa3, 0x52, 0x6e, 0x37, 0xe4, 0x96, 0x9c, 0xe9, 0x5c, 0x66, 0x41, 0x67, 0xe4, 0xfb, 0x79, 0x0c, 0x05, 0xf6, 0x64, 0xd5, 0x7c}}},
+{{{0x28, 0xc1, 0xe1, 0x54, 0x73, 0xf2, 0xbf, 0x76, 0x74, 0x19, 0x19, 0x1b, 0xe4, 0xb9, 0xa8, 0x46, 0x65, 0x73, 0xf3, 0x77, 0x9b, 0x29, 0x74, 0x5b, 0xc6, 0x89, 0x6c, 0x2c, 0x7c, 0xf8, 0xb3, 0x0f}} ,
+ {{0xf7, 0xd5, 0xe9, 0x74, 0x5d, 0xb8, 0x25, 0x16, 0xb5, 0x30, 0xbc, 0x84, 0xc5, 0xf0, 0xad, 0xca, 0x12, 0x28, 0xbc, 0x9d, 0xd4, 0xfa, 0x82, 0xe6, 0xe3, 0xbf, 0xa2, 0x15, 0x2c, 0xd4, 0x34, 0x10}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x61, 0xb1, 0x46, 0xba, 0x0e, 0x31, 0xa5, 0x67, 0x6c, 0x7f, 0xd6, 0xd9, 0x27, 0x85, 0x0f, 0x79, 0x14, 0xc8, 0x6c, 0x2f, 0x5f, 0x5b, 0x9c, 0x35, 0x3d, 0x38, 0x86, 0x77, 0x65, 0x55, 0x6a, 0x7b}} ,
+ {{0xd3, 0xb0, 0x3a, 0x66, 0x60, 0x1b, 0x43, 0xf1, 0x26, 0x58, 0x99, 0x09, 0x8f, 0x2d, 0xa3, 0x14, 0x71, 0x85, 0xdb, 0xed, 0xf6, 0x26, 0xd5, 0x61, 0x9a, 0x73, 0xac, 0x0e, 0xea, 0xac, 0xb7, 0x0c}}},
+{{{0x5e, 0xf4, 0xe5, 0x17, 0x0e, 0x10, 0x9f, 0xe7, 0x43, 0x5f, 0x67, 0x5c, 0xac, 0x4b, 0xe5, 0x14, 0x41, 0xd2, 0xbf, 0x48, 0xf5, 0x14, 0xb0, 0x71, 0xc6, 0x61, 0xc1, 0xb2, 0x70, 0x58, 0xd2, 0x5a}} ,
+ {{0x2d, 0xba, 0x16, 0x07, 0x92, 0x94, 0xdc, 0xbd, 0x50, 0x2b, 0xc9, 0x7f, 0x42, 0x00, 0xba, 0x61, 0xed, 0xf8, 0x43, 0xed, 0xf5, 0xf9, 0x40, 0x60, 0xb2, 0xb0, 0x82, 0xcb, 0xed, 0x75, 0xc7, 0x65}}},
+{{{0x80, 0xba, 0x0d, 0x09, 0x40, 0xa7, 0x39, 0xa6, 0x67, 0x34, 0x7e, 0x66, 0xbe, 0x56, 0xfb, 0x53, 0x78, 0xc4, 0x46, 0xe8, 0xed, 0x68, 0x6c, 0x7f, 0xce, 0xe8, 0x9f, 0xce, 0xa2, 0x64, 0x58, 0x53}} ,
+ {{0xe8, 0xc1, 0xa9, 0xc2, 0x7b, 0x59, 0x21, 0x33, 0xe2, 0x43, 0x73, 0x2b, 0xac, 0x2d, 0xc1, 0x89, 0x3b, 0x15, 0xe2, 0xd5, 0xc0, 0x97, 0x8a, 0xfd, 0x6f, 0x36, 0x33, 0xb7, 0xb9, 0xc3, 0x88, 0x09}}},
+{{{0xd0, 0xb6, 0x56, 0x30, 0x5c, 0xae, 0xb3, 0x75, 0x44, 0xa4, 0x83, 0x51, 0x6e, 0x01, 0x65, 0xef, 0x45, 0x76, 0xe6, 0xf5, 0xa2, 0x0d, 0xd4, 0x16, 0x3b, 0x58, 0x2f, 0xf2, 0x2f, 0x36, 0x18, 0x3f}} ,
+ {{0xfd, 0x2f, 0xe0, 0x9b, 0x1e, 0x8c, 0xc5, 0x18, 0xa9, 0xca, 0xd4, 0x2b, 0x35, 0xb6, 0x95, 0x0a, 0x9f, 0x7e, 0xfb, 0xc4, 0xef, 0x88, 0x7b, 0x23, 0x43, 0xec, 0x2f, 0x0d, 0x0f, 0x7a, 0xfc, 0x5c}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x8d, 0xd2, 0xda, 0xc7, 0x44, 0xd6, 0x7a, 0xdb, 0x26, 0x7d, 0x1d, 0xb8, 0xe1, 0xde, 0x9d, 0x7a, 0x7d, 0x17, 0x7e, 0x1c, 0x37, 0x04, 0x8d, 0x2d, 0x7c, 0x5e, 0x18, 0x38, 0x1e, 0xaf, 0xc7, 0x1b}} ,
+ {{0x33, 0x48, 0x31, 0x00, 0x59, 0xf6, 0xf2, 0xca, 0x0f, 0x27, 0x1b, 0x63, 0x12, 0x7e, 0x02, 0x1d, 0x49, 0xc0, 0x5d, 0x79, 0x87, 0xef, 0x5e, 0x7a, 0x2f, 0x1f, 0x66, 0x55, 0xd8, 0x09, 0xd9, 0x61}}},
+{{{0x54, 0x83, 0x02, 0x18, 0x82, 0x93, 0x99, 0x07, 0xd0, 0xa7, 0xda, 0xd8, 0x75, 0x89, 0xfa, 0xf2, 0xd9, 0xa3, 0xb8, 0x6b, 0x5a, 0x35, 0x28, 0xd2, 0x6b, 0x59, 0xc2, 0xf8, 0x45, 0xe2, 0xbc, 0x06}} ,
+ {{0x65, 0xc0, 0xa3, 0x88, 0x51, 0x95, 0xfc, 0x96, 0x94, 0x78, 0xe8, 0x0d, 0x8b, 0x41, 0xc9, 0xc2, 0x58, 0x48, 0x75, 0x10, 0x2f, 0xcd, 0x2a, 0xc9, 0xa0, 0x6d, 0x0f, 0xdd, 0x9c, 0x98, 0x26, 0x3d}}},
+{{{0x2f, 0x66, 0x29, 0x1b, 0x04, 0x89, 0xbd, 0x7e, 0xee, 0x6e, 0xdd, 0xb7, 0x0e, 0xef, 0xb0, 0x0c, 0xb4, 0xfc, 0x7f, 0xc2, 0xc9, 0x3a, 0x3c, 0x64, 0xef, 0x45, 0x44, 0xaf, 0x8a, 0x90, 0x65, 0x76}} ,
+ {{0xa1, 0x4c, 0x70, 0x4b, 0x0e, 0xa0, 0x83, 0x70, 0x13, 0xa4, 0xaf, 0xb8, 0x38, 0x19, 0x22, 0x65, 0x09, 0xb4, 0x02, 0x4f, 0x06, 0xf8, 0x17, 0xce, 0x46, 0x45, 0xda, 0x50, 0x7c, 0x8a, 0xd1, 0x4e}}},
+{{{0xf7, 0xd4, 0x16, 0x6c, 0x4e, 0x95, 0x9d, 0x5d, 0x0f, 0x91, 0x2b, 0x52, 0xfe, 0x5c, 0x34, 0xe5, 0x30, 0xe6, 0xa4, 0x3b, 0xf3, 0xf3, 0x34, 0x08, 0xa9, 0x4a, 0xa0, 0xb5, 0x6e, 0xb3, 0x09, 0x0a}} ,
+ {{0x26, 0xd9, 0x5e, 0xa3, 0x0f, 0xeb, 0xa2, 0xf3, 0x20, 0x3b, 0x37, 0xd4, 0xe4, 0x9e, 0xce, 0x06, 0x3d, 0x53, 0xed, 0xae, 0x2b, 0xeb, 0xb6, 0x24, 0x0a, 0x11, 0xa3, 0x0f, 0xd6, 0x7f, 0xa4, 0x3a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xdb, 0x9f, 0x2c, 0xfc, 0xd6, 0xb2, 0x1e, 0x2e, 0x52, 0x7a, 0x06, 0x87, 0x2d, 0x86, 0x72, 0x2b, 0x6d, 0x90, 0x77, 0x46, 0x43, 0xb5, 0x7a, 0xf8, 0x60, 0x7d, 0x91, 0x60, 0x5b, 0x9d, 0x9e, 0x07}} ,
+ {{0x97, 0x87, 0xc7, 0x04, 0x1c, 0x38, 0x01, 0x39, 0x58, 0xc7, 0x85, 0xa3, 0xfc, 0x64, 0x00, 0x64, 0x25, 0xa2, 0xbf, 0x50, 0x94, 0xca, 0x26, 0x31, 0x45, 0x0a, 0x24, 0xd2, 0x51, 0x29, 0x51, 0x16}}},
+{{{0x4d, 0x4a, 0xd7, 0x98, 0x71, 0x57, 0xac, 0x7d, 0x8b, 0x37, 0xbd, 0x63, 0xff, 0x87, 0xb1, 0x49, 0x95, 0x20, 0x7c, 0xcf, 0x7c, 0x59, 0xc4, 0x91, 0x9c, 0xef, 0xd0, 0xdb, 0x60, 0x09, 0x9d, 0x46}} ,
+ {{0xcb, 0x78, 0x94, 0x90, 0xe4, 0x45, 0xb3, 0xf6, 0xd9, 0xf6, 0x57, 0x74, 0xd5, 0xf8, 0x83, 0x4f, 0x39, 0xc9, 0xbd, 0x88, 0xc2, 0x57, 0x21, 0x1f, 0x24, 0x32, 0x68, 0xf8, 0xc7, 0x21, 0x5f, 0x0b}}},
+{{{0x2a, 0x36, 0x68, 0xfc, 0x5f, 0xb6, 0x4f, 0xa5, 0xe3, 0x9d, 0x24, 0x2f, 0xc0, 0x93, 0x61, 0xcf, 0xf8, 0x0a, 0xed, 0xe1, 0xdb, 0x27, 0xec, 0x0e, 0x14, 0x32, 0x5f, 0x8e, 0xa1, 0x62, 0x41, 0x16}} ,
+ {{0x95, 0x21, 0x01, 0xce, 0x95, 0x5b, 0x0e, 0x57, 0xc7, 0xb9, 0x62, 0xb5, 0x28, 0xca, 0x11, 0xec, 0xb4, 0x46, 0x06, 0x73, 0x26, 0xff, 0xfb, 0x66, 0x7d, 0xee, 0x5f, 0xb2, 0x56, 0xfd, 0x2a, 0x08}}},
+{{{0x92, 0x67, 0x77, 0x56, 0xa1, 0xff, 0xc4, 0xc5, 0x95, 0xf0, 0xe3, 0x3a, 0x0a, 0xca, 0x94, 0x4d, 0x9e, 0x7e, 0x3d, 0xb9, 0x6e, 0xb6, 0xb0, 0xce, 0xa4, 0x30, 0x89, 0x99, 0xe9, 0xad, 0x11, 0x59}} ,
+ {{0xf6, 0x48, 0x95, 0xa1, 0x6f, 0x5f, 0xb7, 0xa5, 0xbb, 0x30, 0x00, 0x1c, 0xd2, 0x8a, 0xd6, 0x25, 0x26, 0x1b, 0xb2, 0x0d, 0x37, 0x6a, 0x05, 0xf4, 0x9d, 0x3e, 0x17, 0x2a, 0x43, 0xd2, 0x3a, 0x06}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x32, 0x99, 0x93, 0xd1, 0x9a, 0x72, 0xf3, 0xa9, 0x16, 0xbd, 0xb4, 0x4c, 0xdd, 0xf9, 0xd4, 0xb2, 0x64, 0x9a, 0xd3, 0x05, 0xe4, 0xa3, 0x73, 0x1c, 0xcb, 0x7e, 0x57, 0x67, 0xff, 0x04, 0xb3, 0x10}} ,
+ {{0xb9, 0x4b, 0xa4, 0xad, 0xd0, 0x6d, 0x61, 0x23, 0xb4, 0xaf, 0x34, 0xa9, 0xaa, 0x65, 0xec, 0xd9, 0x69, 0xe3, 0x85, 0xcd, 0xcc, 0xe7, 0xb0, 0x9b, 0x41, 0xc1, 0x1c, 0xf9, 0xa0, 0xfa, 0xb7, 0x13}}},
+{{{0x04, 0xfd, 0x88, 0x3c, 0x0c, 0xd0, 0x09, 0x52, 0x51, 0x4f, 0x06, 0x19, 0xcc, 0xc3, 0xbb, 0xde, 0x80, 0xc5, 0x33, 0xbc, 0xf9, 0xf3, 0x17, 0x36, 0xdd, 0xc6, 0xde, 0xe8, 0x9b, 0x5d, 0x79, 0x1b}} ,
+ {{0x65, 0x0a, 0xbe, 0x51, 0x57, 0xad, 0x50, 0x79, 0x08, 0x71, 0x9b, 0x07, 0x95, 0x8f, 0xfb, 0xae, 0x4b, 0x38, 0xba, 0xcf, 0x53, 0x2a, 0x86, 0x1e, 0xc0, 0x50, 0x5c, 0x67, 0x1b, 0xf6, 0x87, 0x6c}}},
+{{{0x4f, 0x00, 0xb2, 0x66, 0x55, 0xed, 0x4a, 0xed, 0x8d, 0xe1, 0x66, 0x18, 0xb2, 0x14, 0x74, 0x8d, 0xfd, 0x1a, 0x36, 0x0f, 0x26, 0x5c, 0x8b, 0x89, 0xf3, 0xab, 0xf2, 0xf3, 0x24, 0x67, 0xfd, 0x70}} ,
+ {{0xfd, 0x4e, 0x2a, 0xc1, 0x3a, 0xca, 0x8f, 0x00, 0xd8, 0xec, 0x74, 0x67, 0xef, 0x61, 0xe0, 0x28, 0xd0, 0x96, 0xf4, 0x48, 0xde, 0x81, 0xe3, 0xef, 0xdc, 0xaa, 0x7d, 0xf3, 0xb6, 0x55, 0xa6, 0x65}}},
+{{{0xeb, 0xcb, 0xc5, 0x70, 0x91, 0x31, 0x10, 0x93, 0x0d, 0xc8, 0xd0, 0xef, 0x62, 0xe8, 0x6f, 0x82, 0xe3, 0x69, 0x3d, 0x91, 0x7f, 0x31, 0xe1, 0x26, 0x35, 0x3c, 0x4a, 0x2f, 0xab, 0xc4, 0x9a, 0x5e}} ,
+ {{0xab, 0x1b, 0xb5, 0xe5, 0x2b, 0xc3, 0x0e, 0x29, 0xb0, 0xd0, 0x73, 0xe6, 0x4f, 0x64, 0xf2, 0xbc, 0xe4, 0xe4, 0xe1, 0x9a, 0x52, 0x33, 0x2f, 0xbd, 0xcc, 0x03, 0xee, 0x8a, 0xfa, 0x00, 0x5f, 0x50}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xf6, 0xdb, 0x0d, 0x22, 0x3d, 0xb5, 0x14, 0x75, 0x31, 0xf0, 0x81, 0xe2, 0xb9, 0x37, 0xa2, 0xa9, 0x84, 0x11, 0x9a, 0x07, 0xb5, 0x53, 0x89, 0x78, 0xa9, 0x30, 0x27, 0xa1, 0xf1, 0x4e, 0x5c, 0x2e}} ,
+ {{0x8b, 0x00, 0x54, 0xfb, 0x4d, 0xdc, 0xcb, 0x17, 0x35, 0x40, 0xff, 0xb7, 0x8c, 0xfe, 0x4a, 0xe4, 0x4e, 0x99, 0x4e, 0xa8, 0x74, 0x54, 0x5d, 0x5c, 0x96, 0xa3, 0x12, 0x55, 0x36, 0x31, 0x17, 0x5c}}},
+{{{0xce, 0x24, 0xef, 0x7b, 0x86, 0xf2, 0x0f, 0x77, 0xe8, 0x5c, 0x7d, 0x87, 0x38, 0x2d, 0xef, 0xaf, 0xf2, 0x8c, 0x72, 0x2e, 0xeb, 0xb6, 0x55, 0x4b, 0x6e, 0xf1, 0x4e, 0x8a, 0x0e, 0x9a, 0x6c, 0x4c}} ,
+ {{0x25, 0xea, 0x86, 0xc2, 0xd1, 0x4f, 0xb7, 0x3e, 0xa8, 0x5c, 0x8d, 0x66, 0x81, 0x25, 0xed, 0xc5, 0x4c, 0x05, 0xb9, 0xd8, 0xd6, 0x70, 0xbe, 0x73, 0x82, 0xe8, 0xa1, 0xe5, 0x1e, 0x71, 0xd5, 0x26}}},
+{{{0x4e, 0x6d, 0xc3, 0xa7, 0x4f, 0x22, 0x45, 0x26, 0xa2, 0x7e, 0x16, 0xf7, 0xf7, 0x63, 0xdc, 0x86, 0x01, 0x2a, 0x71, 0x38, 0x5c, 0x33, 0xc3, 0xce, 0x30, 0xff, 0xf9, 0x2c, 0x91, 0x71, 0x8a, 0x72}} ,
+ {{0x8c, 0x44, 0x09, 0x28, 0xd5, 0x23, 0xc9, 0x8f, 0xf3, 0x84, 0x45, 0xc6, 0x9a, 0x5e, 0xff, 0xd2, 0xc7, 0x57, 0x93, 0xa3, 0xc1, 0x69, 0xdd, 0x62, 0x0f, 0xda, 0x5c, 0x30, 0x59, 0x5d, 0xe9, 0x4c}}},
+{{{0x92, 0x7e, 0x50, 0x27, 0x72, 0xd7, 0x0c, 0xd6, 0x69, 0x96, 0x81, 0x35, 0x84, 0x94, 0x35, 0x8b, 0x6c, 0xaa, 0x62, 0x86, 0x6e, 0x1c, 0x15, 0xf3, 0x6c, 0xb3, 0xff, 0x65, 0x1b, 0xa2, 0x9b, 0x59}} ,
+ {{0xe2, 0xa9, 0x65, 0x88, 0xc4, 0x50, 0xfa, 0xbb, 0x3b, 0x6e, 0x5f, 0x44, 0x01, 0xca, 0x97, 0xd4, 0xdd, 0xf6, 0xcd, 0x3f, 0x3f, 0xe5, 0x97, 0x67, 0x2b, 0x8c, 0x66, 0x0f, 0x35, 0x9b, 0xf5, 0x07}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xf1, 0x59, 0x27, 0xd8, 0xdb, 0x5a, 0x11, 0x5e, 0x82, 0xf3, 0x38, 0xff, 0x1c, 0xed, 0xfe, 0x3f, 0x64, 0x54, 0x3f, 0x7f, 0xd1, 0x81, 0xed, 0xef, 0x65, 0xc5, 0xcb, 0xfd, 0xe1, 0x80, 0xcd, 0x11}} ,
+ {{0xe0, 0xdb, 0x22, 0x28, 0xe6, 0xff, 0x61, 0x9d, 0x41, 0x14, 0x2d, 0x3b, 0x26, 0x22, 0xdf, 0xf1, 0x34, 0x81, 0xe9, 0x45, 0xee, 0x0f, 0x98, 0x8b, 0xa6, 0x3f, 0xef, 0xf7, 0x43, 0x19, 0xf1, 0x43}}},
+{{{0xee, 0xf3, 0x00, 0xa1, 0x50, 0xde, 0xc0, 0xb6, 0x01, 0xe3, 0x8c, 0x3c, 0x4d, 0x31, 0xd2, 0xb0, 0x58, 0xcd, 0xed, 0x10, 0x4a, 0x7a, 0xef, 0x80, 0xa9, 0x19, 0x32, 0xf3, 0xd8, 0x33, 0x8c, 0x06}} ,
+ {{0xcb, 0x7d, 0x4f, 0xff, 0x30, 0xd8, 0x12, 0x3b, 0x39, 0x1c, 0x06, 0xf9, 0x4c, 0x34, 0x35, 0x71, 0xb5, 0x16, 0x94, 0x67, 0xdf, 0xee, 0x11, 0xde, 0xa4, 0x1d, 0x88, 0x93, 0x35, 0xa9, 0x32, 0x10}}},
+{{{0xe9, 0xc3, 0xbc, 0x7b, 0x5c, 0xfc, 0xb2, 0xf9, 0xc9, 0x2f, 0xe5, 0xba, 0x3a, 0x0b, 0xab, 0x64, 0x38, 0x6f, 0x5b, 0x4b, 0x93, 0xda, 0x64, 0xec, 0x4d, 0x3d, 0xa0, 0xf5, 0xbb, 0xba, 0x47, 0x48}} ,
+ {{0x60, 0xbc, 0x45, 0x1f, 0x23, 0xa2, 0x3b, 0x70, 0x76, 0xe6, 0x97, 0x99, 0x4f, 0x77, 0x54, 0x67, 0x30, 0x9a, 0xe7, 0x66, 0xd6, 0xcd, 0x2e, 0x51, 0x24, 0x2c, 0x42, 0x4a, 0x11, 0xfe, 0x6f, 0x7e}}},
+{{{0x87, 0xc0, 0xb1, 0xf0, 0xa3, 0x6f, 0x0c, 0x93, 0xa9, 0x0a, 0x72, 0xef, 0x5c, 0xbe, 0x65, 0x35, 0xa7, 0x6a, 0x4e, 0x2c, 0xbf, 0x21, 0x23, 0xe8, 0x2f, 0x97, 0xc7, 0x3e, 0xc8, 0x17, 0xac, 0x1e}} ,
+ {{0x7b, 0xef, 0x21, 0xe5, 0x40, 0xcc, 0x1e, 0xdc, 0xd6, 0xbd, 0x97, 0x7a, 0x7c, 0x75, 0x86, 0x7a, 0x25, 0x5a, 0x6e, 0x7c, 0xe5, 0x51, 0x3c, 0x1b, 0x5b, 0x82, 0x9a, 0x07, 0x60, 0xa1, 0x19, 0x04}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x96, 0x88, 0xa6, 0xab, 0x8f, 0xe3, 0x3a, 0x49, 0xf8, 0xfe, 0x34, 0xe7, 0x6a, 0xb2, 0xfe, 0x40, 0x26, 0x74, 0x57, 0x4c, 0xf6, 0xd4, 0x99, 0xce, 0x5d, 0x7b, 0x2f, 0x67, 0xd6, 0x5a, 0xe4, 0x4e}} ,
+ {{0x5c, 0x82, 0xb3, 0xbd, 0x55, 0x25, 0xf6, 0x6a, 0x93, 0xa4, 0x02, 0xc6, 0x7d, 0x5c, 0xb1, 0x2b, 0x5b, 0xff, 0xfb, 0x56, 0xf8, 0x01, 0x41, 0x90, 0xc6, 0xb6, 0xac, 0x4f, 0xfe, 0xa7, 0x41, 0x70}}},
+{{{0xdb, 0xfa, 0x9b, 0x2c, 0xd4, 0x23, 0x67, 0x2c, 0x8a, 0x63, 0x6c, 0x07, 0x26, 0x48, 0x4f, 0xc2, 0x03, 0xd2, 0x53, 0x20, 0x28, 0xed, 0x65, 0x71, 0x47, 0xa9, 0x16, 0x16, 0x12, 0xbc, 0x28, 0x33}} ,
+ {{0x39, 0xc0, 0xfa, 0xfa, 0xcd, 0x33, 0x43, 0xc7, 0x97, 0x76, 0x9b, 0x93, 0x91, 0x72, 0xeb, 0xc5, 0x18, 0x67, 0x4c, 0x11, 0xf0, 0xf4, 0xe5, 0x73, 0xb2, 0x5c, 0x1b, 0xc2, 0x26, 0x3f, 0xbf, 0x2b}}},
+{{{0x86, 0xe6, 0x8c, 0x1d, 0xdf, 0xca, 0xfc, 0xd5, 0xf8, 0x3a, 0xc3, 0x44, 0x72, 0xe6, 0x78, 0x9d, 0x2b, 0x97, 0xf8, 0x28, 0x45, 0xb4, 0x20, 0xc9, 0x2a, 0x8c, 0x67, 0xaa, 0x11, 0xc5, 0x5b, 0x2f}} ,
+ {{0x17, 0x0f, 0x86, 0x52, 0xd7, 0x9d, 0xc3, 0x44, 0x51, 0x76, 0x32, 0x65, 0xb4, 0x37, 0x81, 0x99, 0x46, 0x37, 0x62, 0xed, 0xcf, 0x64, 0x9d, 0x72, 0x40, 0x7a, 0x4c, 0x0b, 0x76, 0x2a, 0xfb, 0x56}}},
+{{{0x33, 0xa7, 0x90, 0x7c, 0xc3, 0x6f, 0x17, 0xa5, 0xa0, 0x67, 0x72, 0x17, 0xea, 0x7e, 0x63, 0x14, 0x83, 0xde, 0xc1, 0x71, 0x2d, 0x41, 0x32, 0x7a, 0xf3, 0xd1, 0x2b, 0xd8, 0x2a, 0xa6, 0x46, 0x36}} ,
+ {{0xac, 0xcc, 0x6b, 0x7c, 0xf9, 0xb8, 0x8b, 0x08, 0x5c, 0xd0, 0x7d, 0x8f, 0x73, 0xea, 0x20, 0xda, 0x86, 0xca, 0x00, 0xc7, 0xad, 0x73, 0x4d, 0xe9, 0xe8, 0xa9, 0xda, 0x1f, 0x03, 0x06, 0xdd, 0x24}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x9c, 0xb2, 0x61, 0x0a, 0x98, 0x2a, 0xa5, 0xd7, 0xee, 0xa9, 0xac, 0x65, 0xcb, 0x0a, 0x1e, 0xe2, 0xbe, 0xdc, 0x85, 0x59, 0x0f, 0x9c, 0xa6, 0x57, 0x34, 0xa5, 0x87, 0xeb, 0x7b, 0x1e, 0x0c, 0x3c}} ,
+ {{0x2f, 0xbd, 0x84, 0x63, 0x0d, 0xb5, 0xa0, 0xf0, 0x4b, 0x9e, 0x93, 0xc6, 0x34, 0x9a, 0x34, 0xff, 0x73, 0x19, 0x2f, 0x6e, 0x54, 0x45, 0x2c, 0x92, 0x31, 0x76, 0x34, 0xf1, 0xb2, 0x26, 0xe8, 0x74}}},
+{{{0x0a, 0x67, 0x90, 0x6d, 0x0c, 0x4c, 0xcc, 0xc0, 0xe6, 0xbd, 0xa7, 0x5e, 0x55, 0x8c, 0xcd, 0x58, 0x9b, 0x11, 0xa2, 0xbb, 0x4b, 0xb1, 0x43, 0x04, 0x3c, 0x55, 0xed, 0x23, 0xfe, 0xcd, 0xb1, 0x53}} ,
+ {{0x05, 0xfb, 0x75, 0xf5, 0x01, 0xaf, 0x38, 0x72, 0x58, 0xfc, 0x04, 0x29, 0x34, 0x7a, 0x67, 0xa2, 0x08, 0x50, 0x6e, 0xd0, 0x2b, 0x73, 0xd5, 0xb8, 0xe4, 0x30, 0x96, 0xad, 0x45, 0xdf, 0xa6, 0x5c}}},
+{{{0x0d, 0x88, 0x1a, 0x90, 0x7e, 0xdc, 0xd8, 0xfe, 0xc1, 0x2f, 0x5d, 0x67, 0xee, 0x67, 0x2f, 0xed, 0x6f, 0x55, 0x43, 0x5f, 0x87, 0x14, 0x35, 0x42, 0xd3, 0x75, 0xae, 0xd5, 0xd3, 0x85, 0x1a, 0x76}} ,
+ {{0x87, 0xc8, 0xa0, 0x6e, 0xe1, 0xb0, 0xad, 0x6a, 0x4a, 0x34, 0x71, 0xed, 0x7c, 0xd6, 0x44, 0x03, 0x65, 0x4a, 0x5c, 0x5c, 0x04, 0xf5, 0x24, 0x3f, 0xb0, 0x16, 0x5e, 0x8c, 0xb2, 0xd2, 0xc5, 0x20}}},
+{{{0x98, 0x83, 0xc2, 0x37, 0xa0, 0x41, 0xa8, 0x48, 0x5c, 0x5f, 0xbf, 0xc8, 0xfa, 0x24, 0xe0, 0x59, 0x2c, 0xbd, 0xf6, 0x81, 0x7e, 0x88, 0xe6, 0xca, 0x04, 0xd8, 0x5d, 0x60, 0xbb, 0x74, 0xa7, 0x0b}} ,
+ {{0x21, 0x13, 0x91, 0xbf, 0x77, 0x7a, 0x33, 0xbc, 0xe9, 0x07, 0x39, 0x0a, 0xdd, 0x7d, 0x06, 0x10, 0x9a, 0xee, 0x47, 0x73, 0x1b, 0x15, 0x5a, 0xfb, 0xcd, 0x4d, 0xd0, 0xd2, 0x3a, 0x01, 0xba, 0x54}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x48, 0xd5, 0x39, 0x4a, 0x0b, 0x20, 0x6a, 0x43, 0xa0, 0x07, 0x82, 0x5e, 0x49, 0x7c, 0xc9, 0x47, 0xf1, 0x7c, 0x37, 0xb9, 0x23, 0xef, 0x6b, 0x46, 0x45, 0x8c, 0x45, 0x76, 0xdf, 0x14, 0x6b, 0x6e}} ,
+ {{0x42, 0xc9, 0xca, 0x29, 0x4c, 0x76, 0x37, 0xda, 0x8a, 0x2d, 0x7c, 0x3a, 0x58, 0xf2, 0x03, 0xb4, 0xb5, 0xb9, 0x1a, 0x13, 0x2d, 0xde, 0x5f, 0x6b, 0x9d, 0xba, 0x52, 0xc9, 0x5d, 0xb3, 0xf3, 0x30}}},
+{{{0x4c, 0x6f, 0xfe, 0x6b, 0x0c, 0x62, 0xd7, 0x48, 0x71, 0xef, 0xb1, 0x85, 0x79, 0xc0, 0xed, 0x24, 0xb1, 0x08, 0x93, 0x76, 0x8e, 0xf7, 0x38, 0x8e, 0xeb, 0xfe, 0x80, 0x40, 0xaf, 0x90, 0x64, 0x49}} ,
+ {{0x4a, 0x88, 0xda, 0xc1, 0x98, 0x44, 0x3c, 0x53, 0x4e, 0xdb, 0x4b, 0xb9, 0x12, 0x5f, 0xcd, 0x08, 0x04, 0xef, 0x75, 0xe7, 0xb1, 0x3a, 0xe5, 0x07, 0xfa, 0xca, 0x65, 0x7b, 0x72, 0x10, 0x64, 0x7f}}},
+{{{0x3d, 0x81, 0xf0, 0xeb, 0x16, 0xfd, 0x58, 0x33, 0x8d, 0x7c, 0x1a, 0xfb, 0x20, 0x2c, 0x8a, 0xee, 0x90, 0xbb, 0x33, 0x6d, 0x45, 0xe9, 0x8e, 0x99, 0x85, 0xe1, 0x08, 0x1f, 0xc5, 0xf1, 0xb5, 0x46}} ,
+ {{0xe4, 0xe7, 0x43, 0x4b, 0xa0, 0x3f, 0x2b, 0x06, 0xba, 0x17, 0xae, 0x3d, 0xe6, 0xce, 0xbd, 0xb8, 0xed, 0x74, 0x11, 0x35, 0xec, 0x96, 0xfe, 0x31, 0xe3, 0x0e, 0x7a, 0x4e, 0xc9, 0x1d, 0xcb, 0x20}}},
+{{{0xe0, 0x67, 0xe9, 0x7b, 0xdb, 0x96, 0x5c, 0xb0, 0x32, 0xd0, 0x59, 0x31, 0x90, 0xdc, 0x92, 0x97, 0xac, 0x09, 0x38, 0x31, 0x0f, 0x7e, 0xd6, 0x5d, 0xd0, 0x06, 0xb6, 0x1f, 0xea, 0xf0, 0x5b, 0x07}} ,
+ {{0x81, 0x9f, 0xc7, 0xde, 0x6b, 0x41, 0x22, 0x35, 0x14, 0x67, 0x77, 0x3e, 0x90, 0x81, 0xb0, 0xd9, 0x85, 0x4c, 0xca, 0x9b, 0x3f, 0x04, 0x59, 0xd6, 0xaa, 0x17, 0xc3, 0x88, 0x34, 0x37, 0xba, 0x43}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x4c, 0xb6, 0x69, 0xc8, 0x81, 0x95, 0x94, 0x33, 0x92, 0x34, 0xe9, 0x3c, 0x84, 0x0d, 0x3d, 0x5a, 0x37, 0x9c, 0x22, 0xa0, 0xaa, 0x65, 0xce, 0xb4, 0xc2, 0x2d, 0x66, 0x67, 0x02, 0xff, 0x74, 0x10}} ,
+ {{0x22, 0xb0, 0xd5, 0xe6, 0xc7, 0xef, 0xb1, 0xa7, 0x13, 0xda, 0x60, 0xb4, 0x80, 0xc1, 0x42, 0x7d, 0x10, 0x70, 0x97, 0x04, 0x4d, 0xda, 0x23, 0x89, 0xc2, 0x0e, 0x68, 0xcb, 0xde, 0xe0, 0x9b, 0x29}}},
+{{{0x33, 0xfe, 0x42, 0x2a, 0x36, 0x2b, 0x2e, 0x36, 0x64, 0x5c, 0x8b, 0xcc, 0x81, 0x6a, 0x15, 0x08, 0xa1, 0x27, 0xe8, 0x57, 0xe5, 0x78, 0x8e, 0xf2, 0x58, 0x19, 0x12, 0x42, 0xae, 0xc4, 0x63, 0x3e}} ,
+ {{0x78, 0x96, 0x9c, 0xa7, 0xca, 0x80, 0xae, 0x02, 0x85, 0xb1, 0x7c, 0x04, 0x5c, 0xc1, 0x5b, 0x26, 0xc1, 0xba, 0xed, 0xa5, 0x59, 0x70, 0x85, 0x8c, 0x8c, 0xe8, 0x87, 0xac, 0x6a, 0x28, 0x99, 0x35}}},
+{{{0x9f, 0x04, 0x08, 0x28, 0xbe, 0x87, 0xda, 0x80, 0x28, 0x38, 0xde, 0x9f, 0xcd, 0xe4, 0xe3, 0x62, 0xfb, 0x2e, 0x46, 0x8d, 0x01, 0xb3, 0x06, 0x51, 0xd4, 0x19, 0x3b, 0x11, 0xfa, 0xe2, 0xad, 0x1e}} ,
+ {{0xa0, 0x20, 0x99, 0x69, 0x0a, 0xae, 0xa3, 0x70, 0x4e, 0x64, 0x80, 0xb7, 0x85, 0x9c, 0x87, 0x54, 0x43, 0x43, 0x55, 0x80, 0x6d, 0x8d, 0x7c, 0xa9, 0x64, 0xca, 0x6c, 0x2e, 0x21, 0xd8, 0xc8, 0x6c}}},
+{{{0x91, 0x4a, 0x07, 0xad, 0x08, 0x75, 0xc1, 0x4f, 0xa4, 0xb2, 0xc3, 0x6f, 0x46, 0x3e, 0xb1, 0xce, 0x52, 0xab, 0x67, 0x09, 0x54, 0x48, 0x6b, 0x6c, 0xd7, 0x1d, 0x71, 0x76, 0xcb, 0xff, 0xdd, 0x31}} ,
+ {{0x36, 0x88, 0xfa, 0xfd, 0xf0, 0x36, 0x6f, 0x07, 0x74, 0x88, 0x50, 0xd0, 0x95, 0x38, 0x4a, 0x48, 0x2e, 0x07, 0x64, 0x97, 0x11, 0x76, 0x01, 0x1a, 0x27, 0x4d, 0x8e, 0x25, 0x9a, 0x9b, 0x1c, 0x22}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xbe, 0x57, 0xbd, 0x0e, 0x0f, 0xac, 0x5e, 0x76, 0xa3, 0x71, 0xad, 0x2b, 0x10, 0x45, 0x02, 0xec, 0x59, 0xd5, 0x5d, 0xa9, 0x44, 0xcc, 0x25, 0x4c, 0xb3, 0x3c, 0x5b, 0x69, 0x07, 0x55, 0x26, 0x6b}} ,
+ {{0x30, 0x6b, 0xd4, 0xa7, 0x51, 0x29, 0xe3, 0xf9, 0x7a, 0x75, 0x2a, 0x82, 0x2f, 0xd6, 0x1d, 0x99, 0x2b, 0x80, 0xd5, 0x67, 0x1e, 0x15, 0x9d, 0xca, 0xfd, 0xeb, 0xac, 0x97, 0x35, 0x09, 0x7f, 0x3f}}},
+{{{0x35, 0x0d, 0x34, 0x0a, 0xb8, 0x67, 0x56, 0x29, 0x20, 0xf3, 0x19, 0x5f, 0xe2, 0x83, 0x42, 0x73, 0x53, 0xa8, 0xc5, 0x02, 0x19, 0x33, 0xb4, 0x64, 0xbd, 0xc3, 0x87, 0x8c, 0xd7, 0x76, 0xed, 0x25}} ,
+ {{0x47, 0x39, 0x37, 0x76, 0x0d, 0x1d, 0x0c, 0xf5, 0x5a, 0x6d, 0x43, 0x88, 0x99, 0x15, 0xb4, 0x52, 0x0f, 0x2a, 0xb3, 0xb0, 0x3f, 0xa6, 0xb3, 0x26, 0xb3, 0xc7, 0x45, 0xf5, 0x92, 0x5f, 0x9b, 0x17}}},
+{{{0x9d, 0x23, 0xbd, 0x15, 0xfe, 0x52, 0x52, 0x15, 0x26, 0x79, 0x86, 0xba, 0x06, 0x56, 0x66, 0xbb, 0x8c, 0x2e, 0x10, 0x11, 0xd5, 0x4a, 0x18, 0x52, 0xda, 0x84, 0x44, 0xf0, 0x3e, 0xe9, 0x8c, 0x35}} ,
+ {{0xad, 0xa0, 0x41, 0xec, 0xc8, 0x4d, 0xb9, 0xd2, 0x6e, 0x96, 0x4e, 0x5b, 0xc5, 0xc2, 0xa0, 0x1b, 0xcf, 0x0c, 0xbf, 0x17, 0x66, 0x57, 0xc1, 0x17, 0x90, 0x45, 0x71, 0xc2, 0xe1, 0x24, 0xeb, 0x27}}},
+{{{0x2c, 0xb9, 0x42, 0xa4, 0xaf, 0x3b, 0x42, 0x0e, 0xc2, 0x0f, 0xf2, 0xea, 0x83, 0xaf, 0x9a, 0x13, 0x17, 0xb0, 0xbd, 0x89, 0x17, 0xe3, 0x72, 0xcb, 0x0e, 0x76, 0x7e, 0x41, 0x63, 0x04, 0x88, 0x71}} ,
+ {{0x75, 0x78, 0x38, 0x86, 0x57, 0xdd, 0x9f, 0xee, 0x54, 0x70, 0x65, 0xbf, 0xf1, 0x2c, 0xe0, 0x39, 0x0d, 0xe3, 0x89, 0xfd, 0x8e, 0x93, 0x4f, 0x43, 0xdc, 0xd5, 0x5b, 0xde, 0xf9, 0x98, 0xe5, 0x7b}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xe7, 0x3b, 0x65, 0x11, 0xdf, 0xb2, 0xf2, 0x63, 0x94, 0x12, 0x6f, 0x5c, 0x9e, 0x77, 0xc1, 0xb6, 0xd8, 0xab, 0x58, 0x7a, 0x1d, 0x95, 0x73, 0xdd, 0xe7, 0xe3, 0x6f, 0xf2, 0x03, 0x1d, 0xdb, 0x76}} ,
+ {{0xae, 0x06, 0x4e, 0x2c, 0x52, 0x1b, 0xbc, 0x5a, 0x5a, 0xa5, 0xbe, 0x27, 0xbd, 0xeb, 0xe1, 0x14, 0x17, 0x68, 0x26, 0x07, 0x03, 0xd1, 0x18, 0x0b, 0xdf, 0xf1, 0x06, 0x5c, 0xa6, 0x1b, 0xb9, 0x24}}},
+{{{0xc5, 0x66, 0x80, 0x13, 0x0e, 0x48, 0x8c, 0x87, 0x31, 0x84, 0xb4, 0x60, 0xed, 0xc5, 0xec, 0xb6, 0xc5, 0x05, 0x33, 0x5f, 0x2f, 0x7d, 0x40, 0xb6, 0x32, 0x1d, 0x38, 0x74, 0x1b, 0xf1, 0x09, 0x3d}} ,
+ {{0xd4, 0x69, 0x82, 0xbc, 0x8d, 0xf8, 0x34, 0x36, 0x75, 0x55, 0x18, 0x55, 0x58, 0x3c, 0x79, 0xaf, 0x26, 0x80, 0xab, 0x9b, 0x95, 0x00, 0xf1, 0xcb, 0xda, 0xc1, 0x9f, 0xf6, 0x2f, 0xa2, 0xf4, 0x45}}},
+{{{0x17, 0xbe, 0xeb, 0x85, 0xed, 0x9e, 0xcd, 0x56, 0xf5, 0x17, 0x45, 0x42, 0xb4, 0x1f, 0x44, 0x4c, 0x05, 0x74, 0x15, 0x47, 0x00, 0xc6, 0x6a, 0x3d, 0x24, 0x09, 0x0d, 0x58, 0xb1, 0x42, 0xd7, 0x04}} ,
+ {{0x8d, 0xbd, 0xa3, 0xc4, 0x06, 0x9b, 0x1f, 0x90, 0x58, 0x60, 0x74, 0xb2, 0x00, 0x3b, 0x3c, 0xd2, 0xda, 0x82, 0xbb, 0x10, 0x90, 0x69, 0x92, 0xa9, 0xb4, 0x30, 0x81, 0xe3, 0x7c, 0xa8, 0x89, 0x45}}},
+{{{0x3f, 0xdc, 0x05, 0xcb, 0x41, 0x3c, 0xc8, 0x23, 0x04, 0x2c, 0x38, 0x99, 0xe3, 0x68, 0x55, 0xf9, 0xd3, 0x32, 0xc7, 0xbf, 0xfa, 0xd4, 0x1b, 0x5d, 0xde, 0xdc, 0x10, 0x42, 0xc0, 0x42, 0xd9, 0x75}} ,
+ {{0x2d, 0xab, 0x35, 0x4e, 0x87, 0xc4, 0x65, 0x97, 0x67, 0x24, 0xa4, 0x47, 0xad, 0x3f, 0x8e, 0xf3, 0xcb, 0x31, 0x17, 0x77, 0xc5, 0xe2, 0xd7, 0x8f, 0x3c, 0xc1, 0xcd, 0x56, 0x48, 0xc1, 0x6c, 0x69}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x14, 0xae, 0x5f, 0x88, 0x7b, 0xa5, 0x90, 0xdf, 0x10, 0xb2, 0x8b, 0x5e, 0x24, 0x17, 0xc3, 0xa3, 0xd4, 0x0f, 0x92, 0x61, 0x1a, 0x19, 0x5a, 0xad, 0x76, 0xbd, 0xd8, 0x1c, 0xdd, 0xe0, 0x12, 0x6d}} ,
+ {{0x8e, 0xbd, 0x70, 0x8f, 0x02, 0xa3, 0x24, 0x4d, 0x5a, 0x67, 0xc4, 0xda, 0xf7, 0x20, 0x0f, 0x81, 0x5b, 0x7a, 0x05, 0x24, 0x67, 0x83, 0x0b, 0x2a, 0x80, 0xe7, 0xfd, 0x74, 0x4b, 0x9e, 0x5c, 0x0d}}},
+{{{0x94, 0xd5, 0x5f, 0x1f, 0xa2, 0xfb, 0xeb, 0xe1, 0x07, 0x34, 0xf8, 0x20, 0xad, 0x81, 0x30, 0x06, 0x2d, 0xa1, 0x81, 0x95, 0x36, 0xcf, 0x11, 0x0b, 0xaf, 0xc1, 0x2b, 0x9a, 0x6c, 0x55, 0xc1, 0x16}} ,
+ {{0x36, 0x4f, 0xf1, 0x5e, 0x74, 0x35, 0x13, 0x28, 0xd7, 0x11, 0xcf, 0xb8, 0xde, 0x93, 0xb3, 0x05, 0xb8, 0xb5, 0x73, 0xe9, 0xeb, 0xad, 0x19, 0x1e, 0x89, 0x0f, 0x8b, 0x15, 0xd5, 0x8c, 0xe3, 0x23}}},
+{{{0x33, 0x79, 0xe7, 0x18, 0xe6, 0x0f, 0x57, 0x93, 0x15, 0xa0, 0xa7, 0xaa, 0xc4, 0xbf, 0x4f, 0x30, 0x74, 0x95, 0x5e, 0x69, 0x4a, 0x5b, 0x45, 0xe4, 0x00, 0xeb, 0x23, 0x74, 0x4c, 0xdf, 0x6b, 0x45}} ,
+ {{0x97, 0x29, 0x6c, 0xc4, 0x42, 0x0b, 0xdd, 0xc0, 0x29, 0x5c, 0x9b, 0x34, 0x97, 0xd0, 0xc7, 0x79, 0x80, 0x63, 0x74, 0xe4, 0x8e, 0x37, 0xb0, 0x2b, 0x7c, 0xe8, 0x68, 0x6c, 0xc3, 0x82, 0x97, 0x57}}},
+{{{0x22, 0xbe, 0x83, 0xb6, 0x4b, 0x80, 0x6b, 0x43, 0x24, 0x5e, 0xef, 0x99, 0x9b, 0xa8, 0xfc, 0x25, 0x8d, 0x3b, 0x03, 0x94, 0x2b, 0x3e, 0xe7, 0x95, 0x76, 0x9b, 0xcc, 0x15, 0xdb, 0x32, 0xe6, 0x66}} ,
+ {{0x84, 0xf0, 0x4a, 0x13, 0xa6, 0xd6, 0xfa, 0x93, 0x46, 0x07, 0xf6, 0x7e, 0x5c, 0x6d, 0x5e, 0xf6, 0xa6, 0xe7, 0x48, 0xf0, 0x06, 0xea, 0xff, 0x90, 0xc1, 0xcc, 0x4c, 0x19, 0x9c, 0x3c, 0x4e, 0x53}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x2a, 0x50, 0xe3, 0x07, 0x15, 0x59, 0xf2, 0x8b, 0x81, 0xf2, 0xf3, 0xd3, 0x6c, 0x99, 0x8c, 0x70, 0x67, 0xec, 0xcc, 0xee, 0x9e, 0x59, 0x45, 0x59, 0x7d, 0x47, 0x75, 0x69, 0xf5, 0x24, 0x93, 0x5d}} ,
+ {{0x6a, 0x4f, 0x1b, 0xbe, 0x6b, 0x30, 0xcf, 0x75, 0x46, 0xe3, 0x7b, 0x9d, 0xfc, 0xcd, 0xd8, 0x5c, 0x1f, 0xb4, 0xc8, 0xe2, 0x24, 0xec, 0x1a, 0x28, 0x05, 0x32, 0x57, 0xfd, 0x3c, 0x5a, 0x98, 0x10}}},
+{{{0xa3, 0xdb, 0xf7, 0x30, 0xd8, 0xc2, 0x9a, 0xe1, 0xd3, 0xce, 0x22, 0xe5, 0x80, 0x1e, 0xd9, 0xe4, 0x1f, 0xab, 0xc0, 0x71, 0x1a, 0x86, 0x0e, 0x27, 0x99, 0x5b, 0xfa, 0x76, 0x99, 0xb0, 0x08, 0x3c}} ,
+ {{0x2a, 0x93, 0xd2, 0x85, 0x1b, 0x6a, 0x5d, 0xa6, 0xee, 0xd1, 0xd1, 0x33, 0xbd, 0x6a, 0x36, 0x73, 0x37, 0x3a, 0x44, 0xb4, 0xec, 0xa9, 0x7a, 0xde, 0x83, 0x40, 0xd7, 0xdf, 0x28, 0xba, 0xa2, 0x30}}},
+{{{0xd3, 0xb5, 0x6d, 0x05, 0x3f, 0x9f, 0xf3, 0x15, 0x8d, 0x7c, 0xca, 0xc9, 0xfc, 0x8a, 0x7c, 0x94, 0xb0, 0x63, 0x36, 0x9b, 0x78, 0xd1, 0x91, 0x1f, 0x93, 0xd8, 0x57, 0x43, 0xde, 0x76, 0xa3, 0x43}} ,
+ {{0x9b, 0x35, 0xe2, 0xa9, 0x3d, 0x32, 0x1e, 0xbb, 0x16, 0x28, 0x70, 0xe9, 0x45, 0x2f, 0x8f, 0x70, 0x7f, 0x08, 0x7e, 0x53, 0xc4, 0x7a, 0xbf, 0xf7, 0xe1, 0xa4, 0x6a, 0xd8, 0xac, 0x64, 0x1b, 0x11}}},
+{{{0xb2, 0xeb, 0x47, 0x46, 0x18, 0x3e, 0x1f, 0x99, 0x0c, 0xcc, 0xf1, 0x2c, 0xe0, 0xe7, 0x8f, 0xe0, 0x01, 0x7e, 0x65, 0xb8, 0x0c, 0xd0, 0xfb, 0xc8, 0xb9, 0x90, 0x98, 0x33, 0x61, 0x3b, 0xd8, 0x27}} ,
+ {{0xa0, 0xbe, 0x72, 0x3a, 0x50, 0x4b, 0x74, 0xab, 0x01, 0xc8, 0x93, 0xc5, 0xe4, 0xc7, 0x08, 0x6c, 0xb4, 0xca, 0xee, 0xeb, 0x8e, 0xd7, 0x4e, 0x26, 0xc6, 0x1d, 0xe2, 0x71, 0xaf, 0x89, 0xa0, 0x2a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x98, 0x0b, 0xe4, 0xde, 0xdb, 0xa8, 0xfa, 0x82, 0x74, 0x06, 0x52, 0x6d, 0x08, 0x52, 0x8a, 0xff, 0x62, 0xc5, 0x6a, 0x44, 0x0f, 0x51, 0x8c, 0x1f, 0x6e, 0xb6, 0xc6, 0x2c, 0x81, 0xd3, 0x76, 0x46}} ,
+ {{0xf4, 0x29, 0x74, 0x2e, 0x80, 0xa7, 0x1a, 0x8f, 0xf6, 0xbd, 0xd6, 0x8e, 0xbf, 0xc1, 0x95, 0x2a, 0xeb, 0xa0, 0x7f, 0x45, 0xa0, 0x50, 0x14, 0x05, 0xb1, 0x57, 0x4c, 0x74, 0xb7, 0xe2, 0x89, 0x7d}}},
+{{{0x07, 0xee, 0xa7, 0xad, 0xb7, 0x09, 0x0b, 0x49, 0x4e, 0xbf, 0xca, 0xe5, 0x21, 0xe6, 0xe6, 0xaf, 0xd5, 0x67, 0xf3, 0xce, 0x7e, 0x7c, 0x93, 0x7b, 0x5a, 0x10, 0x12, 0x0e, 0x6c, 0x06, 0x11, 0x75}} ,
+ {{0xd5, 0xfc, 0x86, 0xa3, 0x3b, 0xa3, 0x3e, 0x0a, 0xfb, 0x0b, 0xf7, 0x36, 0xb1, 0x5b, 0xda, 0x70, 0xb7, 0x00, 0xa7, 0xda, 0x88, 0x8f, 0x84, 0xa8, 0xbc, 0x1c, 0x39, 0xb8, 0x65, 0xf3, 0x4d, 0x60}}},
+{{{0x96, 0x9d, 0x31, 0xf4, 0xa2, 0xbe, 0x81, 0xb9, 0xa5, 0x59, 0x9e, 0xba, 0x07, 0xbe, 0x74, 0x58, 0xd8, 0xeb, 0xc5, 0x9f, 0x3d, 0xd1, 0xf4, 0xae, 0xce, 0x53, 0xdf, 0x4f, 0xc7, 0x2a, 0x89, 0x4d}} ,
+ {{0x29, 0xd8, 0xf2, 0xaa, 0xe9, 0x0e, 0xf7, 0x2e, 0x5f, 0x9d, 0x8a, 0x5b, 0x09, 0xed, 0xc9, 0x24, 0x22, 0xf4, 0x0f, 0x25, 0x8f, 0x1c, 0x84, 0x6e, 0x34, 0x14, 0x6c, 0xea, 0xb3, 0x86, 0x5d, 0x04}}},
+{{{0x07, 0x98, 0x61, 0xe8, 0x6a, 0xd2, 0x81, 0x49, 0x25, 0xd5, 0x5b, 0x18, 0xc7, 0x35, 0x52, 0x51, 0xa4, 0x46, 0xad, 0x18, 0x0d, 0xc9, 0x5f, 0x18, 0x91, 0x3b, 0xb4, 0xc0, 0x60, 0x59, 0x8d, 0x66}} ,
+ {{0x03, 0x1b, 0x79, 0x53, 0x6e, 0x24, 0xae, 0x57, 0xd9, 0x58, 0x09, 0x85, 0x48, 0xa2, 0xd3, 0xb5, 0xe2, 0x4d, 0x11, 0x82, 0xe6, 0x86, 0x3c, 0xe9, 0xb1, 0x00, 0x19, 0xc2, 0x57, 0xf7, 0x66, 0x7a}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x0f, 0xe3, 0x89, 0x03, 0xd7, 0x22, 0x95, 0x9f, 0xca, 0xb4, 0x8d, 0x9e, 0x6d, 0x97, 0xff, 0x8d, 0x21, 0x59, 0x07, 0xef, 0x03, 0x2d, 0x5e, 0xf8, 0x44, 0x46, 0xe7, 0x85, 0x80, 0xc5, 0x89, 0x50}} ,
+ {{0x8b, 0xd8, 0x53, 0x86, 0x24, 0x86, 0x29, 0x52, 0x01, 0xfa, 0x20, 0xc3, 0x4e, 0x95, 0xcb, 0xad, 0x7b, 0x34, 0x94, 0x30, 0xb7, 0x7a, 0xfa, 0x96, 0x41, 0x60, 0x2b, 0xcb, 0x59, 0xb9, 0xca, 0x50}}},
+{{{0xc2, 0x5b, 0x9b, 0x78, 0x23, 0x1b, 0x3a, 0x88, 0x94, 0x5f, 0x0a, 0x9b, 0x98, 0x2b, 0x6e, 0x53, 0x11, 0xf6, 0xff, 0xc6, 0x7d, 0x42, 0xcc, 0x02, 0x80, 0x40, 0x0d, 0x1e, 0xfb, 0xaf, 0x61, 0x07}} ,
+ {{0xb0, 0xe6, 0x2f, 0x81, 0x70, 0xa1, 0x2e, 0x39, 0x04, 0x7c, 0xc4, 0x2c, 0x87, 0x45, 0x4a, 0x5b, 0x69, 0x97, 0xac, 0x6d, 0x2c, 0x10, 0x42, 0x7c, 0x3b, 0x15, 0x70, 0x60, 0x0e, 0x11, 0x6d, 0x3a}}},
+{{{0x9b, 0x18, 0x80, 0x5e, 0xdb, 0x05, 0xbd, 0xc6, 0xb7, 0x3c, 0xc2, 0x40, 0x4d, 0x5d, 0xce, 0x97, 0x8a, 0x34, 0x15, 0xab, 0x28, 0x5d, 0x10, 0xf0, 0x37, 0x0c, 0xcc, 0x16, 0xfa, 0x1f, 0x33, 0x0d}} ,
+ {{0x19, 0xf9, 0x35, 0xaa, 0x59, 0x1a, 0x0c, 0x5c, 0x06, 0xfc, 0x6a, 0x0b, 0x97, 0x53, 0x36, 0xfc, 0x2a, 0xa5, 0x5a, 0x9b, 0x30, 0xef, 0x23, 0xaf, 0x39, 0x5d, 0x9a, 0x6b, 0x75, 0x57, 0x48, 0x0b}}},
+{{{0x26, 0xdc, 0x76, 0x3b, 0xfc, 0xf9, 0x9c, 0x3f, 0x89, 0x0b, 0x62, 0x53, 0xaf, 0x83, 0x01, 0x2e, 0xbc, 0x6a, 0xc6, 0x03, 0x0d, 0x75, 0x2a, 0x0d, 0xe6, 0x94, 0x54, 0xcf, 0xb3, 0xe5, 0x96, 0x25}} ,
+ {{0xfe, 0x82, 0xb1, 0x74, 0x31, 0x8a, 0xa7, 0x6f, 0x56, 0xbd, 0x8d, 0xf4, 0xe0, 0x94, 0x51, 0x59, 0xde, 0x2c, 0x5a, 0xf4, 0x84, 0x6b, 0x4a, 0x88, 0x93, 0xc0, 0x0c, 0x9a, 0xac, 0xa7, 0xa0, 0x68}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x25, 0x0d, 0xd6, 0xc7, 0x23, 0x47, 0x10, 0xad, 0xc7, 0x08, 0x5c, 0x87, 0x87, 0x93, 0x98, 0x18, 0xb8, 0xd3, 0x9c, 0xac, 0x5a, 0x3d, 0xc5, 0x75, 0xf8, 0x49, 0x32, 0x14, 0xcc, 0x51, 0x96, 0x24}} ,
+ {{0x65, 0x9c, 0x5d, 0xf0, 0x37, 0x04, 0xf0, 0x34, 0x69, 0x2a, 0xf0, 0xa5, 0x64, 0xca, 0xde, 0x2b, 0x5b, 0x15, 0x10, 0xd2, 0xab, 0x06, 0xdd, 0xc4, 0xb0, 0xb6, 0x5b, 0xc1, 0x17, 0xdf, 0x8f, 0x02}}},
+{{{0xbd, 0x59, 0x3d, 0xbf, 0x5c, 0x31, 0x44, 0x2c, 0x32, 0x94, 0x04, 0x60, 0x84, 0x0f, 0xad, 0x00, 0xb6, 0x8f, 0xc9, 0x1d, 0xcc, 0x5c, 0xa2, 0x49, 0x0e, 0x50, 0x91, 0x08, 0x9a, 0x43, 0x55, 0x05}} ,
+ {{0x5d, 0x93, 0x55, 0xdf, 0x9b, 0x12, 0x19, 0xec, 0x93, 0x85, 0x42, 0x9e, 0x66, 0x0f, 0x9d, 0xaf, 0x99, 0xaf, 0x26, 0x89, 0xbc, 0x61, 0xfd, 0xff, 0xce, 0x4b, 0xf4, 0x33, 0x95, 0xc9, 0x35, 0x58}}},
+{{{0x12, 0x55, 0xf9, 0xda, 0xcb, 0x44, 0xa7, 0xdc, 0x57, 0xe2, 0xf9, 0x9a, 0xe6, 0x07, 0x23, 0x60, 0x54, 0xa7, 0x39, 0xa5, 0x9b, 0x84, 0x56, 0x6e, 0xaa, 0x8b, 0x8f, 0xb0, 0x2c, 0x87, 0xaf, 0x67}} ,
+ {{0x00, 0xa9, 0x4c, 0xb2, 0x12, 0xf8, 0x32, 0xa8, 0x7a, 0x00, 0x4b, 0x49, 0x32, 0xba, 0x1f, 0x5d, 0x44, 0x8e, 0x44, 0x7a, 0xdc, 0x11, 0xfb, 0x39, 0x08, 0x57, 0x87, 0xa5, 0x12, 0x42, 0x93, 0x0e}}},
+{{{0x17, 0xb4, 0xae, 0x72, 0x59, 0xd0, 0xaa, 0xa8, 0x16, 0x8b, 0x63, 0x11, 0xb3, 0x43, 0x04, 0xda, 0x0c, 0xa8, 0xb7, 0x68, 0xdd, 0x4e, 0x54, 0xe7, 0xaf, 0x5d, 0x5d, 0x05, 0x76, 0x36, 0xec, 0x0d}} ,
+ {{0x6d, 0x7c, 0x82, 0x32, 0x38, 0x55, 0x57, 0x74, 0x5b, 0x7d, 0xc3, 0xc4, 0xfb, 0x06, 0x29, 0xf0, 0x13, 0x55, 0x54, 0xc6, 0xa7, 0xdc, 0x4c, 0x9f, 0x98, 0x49, 0x20, 0xa8, 0xc3, 0x8d, 0xfa, 0x48}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x87, 0x47, 0x9d, 0xe9, 0x25, 0xd5, 0xe3, 0x47, 0x78, 0xdf, 0x85, 0xa7, 0x85, 0x5e, 0x7a, 0x4c, 0x5f, 0x79, 0x1a, 0xf3, 0xa2, 0xb2, 0x28, 0xa0, 0x9c, 0xdd, 0x30, 0x40, 0xd4, 0x38, 0xbd, 0x28}} ,
+ {{0xfc, 0xbb, 0xd5, 0x78, 0x6d, 0x1d, 0xd4, 0x99, 0xb4, 0xaa, 0x44, 0x44, 0x7a, 0x1b, 0xd8, 0xfe, 0xb4, 0x99, 0xb9, 0xcc, 0xe7, 0xc4, 0xd3, 0x3a, 0x73, 0x83, 0x41, 0x5c, 0x40, 0xd7, 0x2d, 0x55}}},
+{{{0x26, 0xe1, 0x7b, 0x5f, 0xe5, 0xdc, 0x3f, 0x7d, 0xa1, 0xa7, 0x26, 0x44, 0x22, 0x23, 0xc0, 0x8f, 0x7d, 0xf1, 0xb5, 0x11, 0x47, 0x7b, 0x19, 0xd4, 0x75, 0x6f, 0x1e, 0xa5, 0x27, 0xfe, 0xc8, 0x0e}} ,
+ {{0xd3, 0x11, 0x3d, 0xab, 0xef, 0x2c, 0xed, 0xb1, 0x3d, 0x7c, 0x32, 0x81, 0x6b, 0xfe, 0xf8, 0x1c, 0x3c, 0x7b, 0xc0, 0x61, 0xdf, 0xb8, 0x75, 0x76, 0x7f, 0xaa, 0xd8, 0x93, 0xaf, 0x3d, 0xe8, 0x3d}}},
+{{{0xfd, 0x5b, 0x4e, 0x8d, 0xb6, 0x7e, 0x82, 0x9b, 0xef, 0xce, 0x04, 0x69, 0x51, 0x52, 0xff, 0xef, 0xa0, 0x52, 0xb5, 0x79, 0x17, 0x5e, 0x2f, 0xde, 0xd6, 0x3c, 0x2d, 0xa0, 0x43, 0xb4, 0x0b, 0x19}} ,
+ {{0xc0, 0x61, 0x48, 0x48, 0x17, 0xf4, 0x9e, 0x18, 0x51, 0x2d, 0xea, 0x2f, 0xf2, 0xf2, 0xe0, 0xa3, 0x14, 0xb7, 0x8b, 0x3a, 0x30, 0xf5, 0x81, 0xc1, 0x5d, 0x71, 0x39, 0x62, 0x55, 0x1f, 0x60, 0x5a}}},
+{{{0xe5, 0x89, 0x8a, 0x76, 0x6c, 0xdb, 0x4d, 0x0a, 0x5b, 0x72, 0x9d, 0x59, 0x6e, 0x63, 0x63, 0x18, 0x7c, 0xe3, 0xfa, 0xe2, 0xdb, 0xa1, 0x8d, 0xf4, 0xa5, 0xd7, 0x16, 0xb2, 0xd0, 0xb3, 0x3f, 0x39}} ,
+ {{0xce, 0x60, 0x09, 0x6c, 0xf5, 0x76, 0x17, 0x24, 0x80, 0x3a, 0x96, 0xc7, 0x94, 0x2e, 0xf7, 0x6b, 0xef, 0xb5, 0x05, 0x96, 0xef, 0xd3, 0x7b, 0x51, 0xda, 0x05, 0x44, 0x67, 0xbc, 0x07, 0x21, 0x4e}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xe9, 0x73, 0x6f, 0x21, 0xb9, 0xde, 0x22, 0x7d, 0xeb, 0x97, 0x31, 0x10, 0xa3, 0xea, 0xe1, 0xc6, 0x37, 0xeb, 0x8f, 0x43, 0x58, 0xde, 0x41, 0x64, 0x0e, 0x3e, 0x07, 0x99, 0x3d, 0xf1, 0xdf, 0x1e}} ,
+ {{0xf8, 0xad, 0x43, 0xc2, 0x17, 0x06, 0xe2, 0xe4, 0xa9, 0x86, 0xcd, 0x18, 0xd7, 0x78, 0xc8, 0x74, 0x66, 0xd2, 0x09, 0x18, 0xa5, 0xf1, 0xca, 0xa6, 0x62, 0x92, 0xc1, 0xcb, 0x00, 0xeb, 0x42, 0x2e}}},
+{{{0x7b, 0x34, 0x24, 0x4c, 0xcf, 0x38, 0xe5, 0x6c, 0x0a, 0x01, 0x2c, 0x22, 0x0b, 0x24, 0x38, 0xad, 0x24, 0x7e, 0x19, 0xf0, 0x6c, 0xf9, 0x31, 0xf4, 0x35, 0x11, 0xf6, 0x46, 0x33, 0x3a, 0x23, 0x59}} ,
+ {{0x20, 0x0b, 0xa1, 0x08, 0x19, 0xad, 0x39, 0x54, 0xea, 0x3e, 0x23, 0x09, 0xb6, 0xe2, 0xd2, 0xbc, 0x4d, 0xfc, 0x9c, 0xf0, 0x13, 0x16, 0x22, 0x3f, 0xb9, 0xd2, 0x11, 0x86, 0x90, 0x55, 0xce, 0x3c}}},
+{{{0xc4, 0x0b, 0x4b, 0x62, 0x99, 0x37, 0x84, 0x3f, 0x74, 0xa2, 0xf9, 0xce, 0xe2, 0x0b, 0x0f, 0x2a, 0x3d, 0xa3, 0xe3, 0xdb, 0x5a, 0x9d, 0x93, 0xcc, 0xa5, 0xef, 0x82, 0x91, 0x1d, 0xe6, 0x6c, 0x68}} ,
+ {{0xa3, 0x64, 0x17, 0x9b, 0x8b, 0xc8, 0x3a, 0x61, 0xe6, 0x9d, 0xc6, 0xed, 0x7b, 0x03, 0x52, 0x26, 0x9d, 0x3a, 0xb3, 0x13, 0xcc, 0x8a, 0xfd, 0x2c, 0x1a, 0x1d, 0xed, 0x13, 0xd0, 0x55, 0x57, 0x0e}}},
+{{{0x1a, 0xea, 0xbf, 0xfd, 0x4a, 0x3c, 0x8e, 0xec, 0x29, 0x7e, 0x77, 0x77, 0x12, 0x99, 0xd7, 0x84, 0xf9, 0x55, 0x7f, 0xf1, 0x8b, 0xb4, 0xd2, 0x95, 0xa3, 0x8d, 0xf0, 0x8a, 0xa7, 0xeb, 0x82, 0x4b}} ,
+ {{0x2c, 0x28, 0xf4, 0x3a, 0xf6, 0xde, 0x0a, 0xe0, 0x41, 0x44, 0x23, 0xf8, 0x3f, 0x03, 0x64, 0x9f, 0xc3, 0x55, 0x4c, 0xc6, 0xc1, 0x94, 0x1c, 0x24, 0x5d, 0x5f, 0x92, 0x45, 0x96, 0x57, 0x37, 0x14}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xc1, 0xcd, 0x90, 0x66, 0xb9, 0x76, 0xa0, 0x5b, 0xa5, 0x85, 0x75, 0x23, 0xf9, 0x89, 0xa5, 0x82, 0xb2, 0x6f, 0xb1, 0xeb, 0xc4, 0x69, 0x6f, 0x18, 0x5a, 0xed, 0x94, 0x3d, 0x9d, 0xd9, 0x2c, 0x1a}} ,
+ {{0x35, 0xb0, 0xe6, 0x73, 0x06, 0xb7, 0x37, 0xe0, 0xf8, 0xb0, 0x22, 0xe8, 0xd2, 0xed, 0x0b, 0xef, 0xe6, 0xc6, 0x5a, 0x99, 0x9e, 0x1a, 0x9f, 0x04, 0x97, 0xe4, 0x4d, 0x0b, 0xbe, 0xba, 0x44, 0x40}}},
+{{{0xc1, 0x56, 0x96, 0x91, 0x5f, 0x1f, 0xbb, 0x54, 0x6f, 0x88, 0x89, 0x0a, 0xb2, 0xd6, 0x41, 0x42, 0x6a, 0x82, 0xee, 0x14, 0xaa, 0x76, 0x30, 0x65, 0x0f, 0x67, 0x39, 0xa6, 0x51, 0x7c, 0x49, 0x24}} ,
+ {{0x35, 0xa3, 0x78, 0xd1, 0x11, 0x0f, 0x75, 0xd3, 0x70, 0x46, 0xdb, 0x20, 0x51, 0xcb, 0x92, 0x80, 0x54, 0x10, 0x74, 0x36, 0x86, 0xa9, 0xd7, 0xa3, 0x08, 0x78, 0xf1, 0x01, 0x29, 0xf8, 0x80, 0x3b}}},
+{{{0xdb, 0xa7, 0x9d, 0x9d, 0xbf, 0xa0, 0xcc, 0xed, 0x53, 0xa2, 0xa2, 0x19, 0x39, 0x48, 0x83, 0x19, 0x37, 0x58, 0xd1, 0x04, 0x28, 0x40, 0xf7, 0x8a, 0xc2, 0x08, 0xb7, 0xa5, 0x42, 0xcf, 0x53, 0x4c}} ,
+ {{0xa7, 0xbb, 0xf6, 0x8e, 0xad, 0xdd, 0xf7, 0x90, 0xdd, 0x5f, 0x93, 0x89, 0xae, 0x04, 0x37, 0xe6, 0x9a, 0xb7, 0xe8, 0xc0, 0xdf, 0x16, 0x2a, 0xbf, 0xc4, 0x3a, 0x3c, 0x41, 0xd5, 0x89, 0x72, 0x5a}}},
+{{{0x1f, 0x96, 0xff, 0x34, 0x2c, 0x13, 0x21, 0xcb, 0x0a, 0x89, 0x85, 0xbe, 0xb3, 0x70, 0x9e, 0x1e, 0xde, 0x97, 0xaf, 0x96, 0x30, 0xf7, 0x48, 0x89, 0x40, 0x8d, 0x07, 0xf1, 0x25, 0xf0, 0x30, 0x58}} ,
+ {{0x1e, 0xd4, 0x93, 0x57, 0xe2, 0x17, 0xe7, 0x9d, 0xab, 0x3c, 0x55, 0x03, 0x82, 0x2f, 0x2b, 0xdb, 0x56, 0x1e, 0x30, 0x2e, 0x24, 0x47, 0x6e, 0xe6, 0xff, 0x33, 0x24, 0x2c, 0x75, 0x51, 0xd4, 0x67}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0x2b, 0x06, 0xd9, 0xa1, 0x5d, 0xe1, 0xf4, 0xd1, 0x1e, 0x3c, 0x9a, 0xc6, 0x29, 0x2b, 0x13, 0x13, 0x78, 0xc0, 0xd8, 0x16, 0x17, 0x2d, 0x9e, 0xa9, 0xc9, 0x79, 0x57, 0xab, 0x24, 0x91, 0x92, 0x19}} ,
+ {{0x69, 0xfb, 0xa1, 0x9c, 0xa6, 0x75, 0x49, 0x7d, 0x60, 0x73, 0x40, 0x42, 0xc4, 0x13, 0x0a, 0x95, 0x79, 0x1e, 0x04, 0x83, 0x94, 0x99, 0x9b, 0x1e, 0x0c, 0xe8, 0x1f, 0x54, 0xef, 0xcb, 0xc0, 0x52}}},
+{{{0x14, 0x89, 0x73, 0xa1, 0x37, 0x87, 0x6a, 0x7a, 0xcf, 0x1d, 0xd9, 0x2e, 0x1a, 0x67, 0xed, 0x74, 0xc0, 0xf0, 0x9c, 0x33, 0xdd, 0xdf, 0x08, 0xbf, 0x7b, 0xd1, 0x66, 0xda, 0xe6, 0xc9, 0x49, 0x08}} ,
+ {{0xe9, 0xdd, 0x5e, 0x55, 0xb0, 0x0a, 0xde, 0x21, 0x4c, 0x5a, 0x2e, 0xd4, 0x80, 0x3a, 0x57, 0x92, 0x7a, 0xf1, 0xc4, 0x2c, 0x40, 0xaf, 0x2f, 0xc9, 0x92, 0x03, 0xe5, 0x5a, 0xbc, 0xdc, 0xf4, 0x09}}},
+{{{0xf3, 0xe1, 0x2b, 0x7c, 0x05, 0x86, 0x80, 0x93, 0x4a, 0xad, 0xb4, 0x8f, 0x7e, 0x99, 0x0c, 0xfd, 0xcd, 0xef, 0xd1, 0xff, 0x2c, 0x69, 0x34, 0x13, 0x41, 0x64, 0xcf, 0x3b, 0xd0, 0x90, 0x09, 0x1e}} ,
+ {{0x9d, 0x45, 0xd6, 0x80, 0xe6, 0x45, 0xaa, 0xf4, 0x15, 0xaa, 0x5c, 0x34, 0x87, 0x99, 0xa2, 0x8c, 0x26, 0x84, 0x62, 0x7d, 0xb6, 0x29, 0xc0, 0x52, 0xea, 0xf5, 0x81, 0x18, 0x0f, 0x35, 0xa9, 0x0e}}},
+{{{0xe7, 0x20, 0x72, 0x7c, 0x6d, 0x94, 0x5f, 0x52, 0x44, 0x54, 0xe3, 0xf1, 0xb2, 0xb0, 0x36, 0x46, 0x0f, 0xae, 0x92, 0xe8, 0x70, 0x9d, 0x6e, 0x79, 0xb1, 0xad, 0x37, 0xa9, 0x5f, 0xc0, 0xde, 0x03}} ,
+ {{0x15, 0x55, 0x37, 0xc6, 0x1c, 0x27, 0x1c, 0x6d, 0x14, 0x4f, 0xca, 0xa4, 0xc4, 0x88, 0x25, 0x46, 0x39, 0xfc, 0x5a, 0xe5, 0xfe, 0x29, 0x11, 0x69, 0xf5, 0x72, 0x84, 0x4d, 0x78, 0x9f, 0x94, 0x15}}},
+{{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
+{{{0xec, 0xd3, 0xff, 0x57, 0x0b, 0xb0, 0xb2, 0xdc, 0xf8, 0x4f, 0xe2, 0x12, 0xd5, 0x36, 0xbe, 0x6b, 0x09, 0x43, 0x6d, 0xa3, 0x4d, 0x90, 0x2d, 0xb8, 0x74, 0xe8, 0x71, 0x45, 0x19, 0x8b, 0x0c, 0x6a}} ,
+ {{0xb8, 0x42, 0x1c, 0x03, 0xad, 0x2c, 0x03, 0x8e, 0xac, 0xd7, 0x98, 0x29, 0x13, 0xc6, 0x02, 0x29, 0xb5, 0xd4, 0xe7, 0xcf, 0xcc, 0x8b, 0x83, 0xec, 0x35, 0xc7, 0x9c, 0x74, 0xb7, 0xad, 0x85, 0x5f}}},
+{{{0x78, 0x84, 0xe1, 0x56, 0x45, 0x69, 0x68, 0x5a, 0x4f, 0xb8, 0xb1, 0x29, 0xff, 0x33, 0x03, 0x31, 0xb7, 0xcb, 0x96, 0x25, 0xe6, 0xe6, 0x41, 0x98, 0x1a, 0xbb, 0x03, 0x56, 0xf2, 0xb2, 0x91, 0x34}} ,
+ {{0x2c, 0x6c, 0xf7, 0x66, 0xa4, 0x62, 0x6b, 0x39, 0xb3, 0xba, 0x65, 0xd3, 0x1c, 0xf8, 0x11, 0xaa, 0xbe, 0xdc, 0x80, 0x59, 0x87, 0xf5, 0x7b, 0xe5, 0xe3, 0xb3, 0x3e, 0x39, 0xda, 0xbe, 0x88, 0x09}}},
+{{{0x8b, 0xf1, 0xa0, 0xf5, 0xdc, 0x29, 0xb4, 0xe2, 0x07, 0xc6, 0x7a, 0x00, 0xd0, 0x89, 0x17, 0x51, 0xd4, 0xbb, 0xd4, 0x22, 0xea, 0x7e, 0x7d, 0x7c, 0x24, 0xea, 0xf2, 0xe8, 0x22, 0x12, 0x95, 0x06}} ,
+ {{0xda, 0x7c, 0xa4, 0x0c, 0xf4, 0xba, 0x6e, 0xe1, 0x89, 0xb5, 0x59, 0xca, 0xf1, 0xc0, 0x29, 0x36, 0x09, 0x44, 0xe2, 0x7f, 0xd1, 0x63, 0x15, 0x99, 0xea, 0x25, 0xcf, 0x0c, 0x9d, 0xc0, 0x44, 0x6f}}},
+{{{0x1d, 0x86, 0x4e, 0xcf, 0xf7, 0x37, 0x10, 0x25, 0x8f, 0x12, 0xfb, 0x19, 0xfb, 0xe0, 0xed, 0x10, 0xc8, 0xe2, 0xf5, 0x75, 0xb1, 0x33, 0xc0, 0x96, 0x0d, 0xfb, 0x15, 0x6c, 0x0d, 0x07, 0x5f, 0x05}} ,
+ {{0x69, 0x3e, 0x47, 0x97, 0x2c, 0xaf, 0x52, 0x7c, 0x78, 0x83, 0xad, 0x1b, 0x39, 0x82, 0x2f, 0x02, 0x6f, 0x47, 0xdb, 0x2a, 0xb0, 0xe1, 0x91, 0x99, 0x55, 0xb8, 0x99, 0x3a, 0xa0, 0x44, 0x11, 0x51}}}
+};
+
+static inline void p1p1_to_p2(ge25519_p2 *r, const ge25519_p1p1 *p)
+{
+ fe25519_mul(&r->x, &p->x, &p->t);
+ fe25519_mul(&r->y, &p->y, &p->z);
+ fe25519_mul(&r->z, &p->z, &p->t);
+}
+
+static inline void p1p1_to_p2_2(ge25519_p3 *r, const ge25519_p1p1 *p)
+{
+ fe25519_mul(&r->x, &p->x, &p->t);
+ fe25519_mul(&r->y, &p->y, &p->z);
+ fe25519_mul(&r->z, &p->z, &p->t);
+}
+
+static inline void p1p1_to_p3(ge25519_p3 *r, const ge25519_p1p1 *p)
+{
+ p1p1_to_p2_2(r, p);
+ fe25519_mul(&r->t, &p->x, &p->y);
+}
+
+static void ge25519_mixadd2(ge25519_p3 *r, const ge25519_aff *q)
+{
+ fe25519 a,b,t1,t2,c,d,e,f,g,h,qt;
+ fe25519_mul(&qt, &q->x, &q->y);
+ fe25519_sub(&a, &r->y, &r->x); /* A = (Y1-X1)*(Y2-X2) */
+ fe25519_add(&b, &r->y, &r->x); /* B = (Y1+X1)*(Y2+X2) */
+ fe25519_sub(&t1, &q->y, &q->x);
+ fe25519_add(&t2, &q->y, &q->x);
+ fe25519_mul(&a, &a, &t1);
+ fe25519_mul(&b, &b, &t2);
+ fe25519_sub(&e, &b, &a); /* E = B-A */
+ fe25519_add(&h, &b, &a); /* H = B+A */
+ fe25519_mul(&c, &r->t, &qt); /* C = T1*k*T2 */
+ fe25519_mul(&c, &c, &ge25519_ec2d);
+ fe25519_add(&d, &r->z, &r->z); /* D = Z1*2 */
+ fe25519_sub(&f, &d, &c); /* F = D-C */
+ fe25519_add(&g, &d, &c); /* G = D+C */
+ fe25519_mul(&r->x, &e, &f);
+ fe25519_mul(&r->y, &h, &g);
+ fe25519_mul(&r->z, &g, &f);
+ fe25519_mul(&r->t, &e, &h);
+}
+
+static void add_p1p1(ge25519_p1p1 *r, const ge25519_p3 *p, const ge25519_p3 *q)
+{
+ fe25519 a, b, c, d, t;
+
+ fe25519_sub(&a, &p->y, &p->x); /* A = (Y1-X1)*(Y2-X2) */
+ fe25519_sub(&t, &q->y, &q->x);
+ fe25519_mul(&a, &a, &t);
+ fe25519_add(&b, &p->x, &p->y); /* B = (Y1+X1)*(Y2+X2) */
+ fe25519_add(&t, &q->x, &q->y);
+ fe25519_mul(&b, &b, &t);
+ fe25519_mul(&c, &p->t, &q->t); /* C = T1*k*T2 */
+ fe25519_mul(&c, &c, &ge25519_ec2d);
+ fe25519_mul(&d, &p->z, &q->z); /* D = Z1*2*Z2 */
+ fe25519_add(&d, &d, &d);
+ fe25519_sub(&r->x, &b, &a); /* E = B-A */
+ fe25519_sub(&r->t, &d, &c); /* F = D-C */
+ fe25519_add(&r->z, &d, &c); /* G = D+C */
+ fe25519_add(&r->y, &b, &a); /* H = B+A */
+}
+
+/* See http://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd */
+static void dbl_p1p1(ge25519_p1p1 *r, const ge25519_p2 *p)
+{
+ fe25519 a,b,c,d;
+ fe25519_square(&a, &p->x);
+ fe25519_square(&b, &p->y);
+ fe25519_square(&c, &p->z);
+ fe25519_add(&c, &c, &c);
+ fe25519_neg(&d, &a);
+
+ fe25519_add(&r->x, &p->x, &p->y);
+ fe25519_square(&r->x, &r->x);
+ fe25519_sub(&r->x, &r->x, &a);
+ fe25519_sub(&r->x, &r->x, &b);
+ fe25519_add(&r->z, &d, &b);
+ fe25519_sub(&r->t, &r->z, &c);
+ fe25519_sub(&r->y, &d, &b);
+}
+
+/* Constant-time version of: if(b) r = p */
+static inline void cmov_aff(ge25519_aff *r, const ge25519_aff *p, unsigned char b)
+{
+ fe25519_cmov(&r->x, &p->x, b);
+ fe25519_cmov(&r->y, &p->y, b);
+}
+
+static inline unsigned char equal(signed char b,signed char c)
+{
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ crypto_uint32 y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* 4294967295: yes; 0..254: no */
+ y >>= 31; /* 1: yes; 0: no */
+ return (unsigned char)y;
+}
+
+static inline unsigned char negative(signed char b)
+{
+ unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return (unsigned char)x;
+}
+
+static inline void choose_t(ge25519_aff *t, unsigned long long pos, signed char b)
+{
+ /* constant time */
+ fe25519 v;
+ *t = ge25519_base_multiples_affine[5*pos+0];
+ cmov_aff(t, &ge25519_base_multiples_affine[5*pos+1],equal(b,1) | equal(b,-1));
+ cmov_aff(t, &ge25519_base_multiples_affine[5*pos+2],equal(b,2) | equal(b,-2));
+ cmov_aff(t, &ge25519_base_multiples_affine[5*pos+3],equal(b,3) | equal(b,-3));
+ cmov_aff(t, &ge25519_base_multiples_affine[5*pos+4],equal(b,-4));
+ fe25519_neg(&v, &t->x);
+ fe25519_cmov(&t->x, &v, negative(b));
+}
+
+static inline void setneutral(ge25519 *r)
+{
+ fe25519_setzero(&r->x);
+ fe25519_setone(&r->y);
+ fe25519_setone(&r->z);
+ fe25519_setzero(&r->t);
+}
+
+/* return 0 on success, -1 otherwise */
+static int ge25519_unpackneg_vartime(ge25519_p3 *r, const unsigned char p[32])
+{
+ unsigned char par;
+ fe25519 t, chk, num, den, den2, den4, den6;
+ fe25519_setone(&r->z);
+ par = p[31] >> 7;
+ fe25519_unpack(&r->y, p);
+ fe25519_square(&num, &r->y); /* x = y^2 */
+ fe25519_mul(&den, &num, &ge25519_ecd); /* den = dy^2 */
+ fe25519_sub(&num, &num, &r->z); /* x = y^2-1 */
+ fe25519_add(&den, &r->z, &den); /* den = dy^2+1 */
+
+ /* Computation of sqrt(num/den) */
+ /* 1.: computation of num^((p-5)/8)*den^((7p-35)/8) = (num*den^7)^((p-5)/8) */
+ fe25519_square(&den2, &den);
+ fe25519_square(&den4, &den2);
+ fe25519_mul(&den6, &den4, &den2);
+ fe25519_mul(&t, &den6, &num);
+ fe25519_mul(&t, &t, &den);
+
+ fe25519_pow2523(&t, &t);
+ /* 2. computation of r->x = t * num * den^3 */
+ fe25519_mul(&t, &t, &num);
+ fe25519_mul(&t, &t, &den);
+ fe25519_mul(&t, &t, &den);
+ fe25519_mul(&r->x, &t, &den);
+
+ /* 3. Check whether sqrt computation gave correct result, multiply by sqrt(-1) if not: */
+ fe25519_square(&chk, &r->x);
+ fe25519_mul(&chk, &chk, &den);
+ if (!fe25519_iseq_vartime(&chk, &num))
+ fe25519_mul(&r->x, &r->x, &ge25519_sqrtm1);
+
+ /* 4. Now we have one of the two square roots, except if input was not a square */
+ fe25519_square(&chk, &r->x);
+ fe25519_mul(&chk, &chk, &den);
+ if (!fe25519_iseq_vartime(&chk, &num))
+ return -1;
+
+ /* 5. Choose the desired square root according to parity: */
+ if(fe25519_getparity(&r->x) != (1-par))
+ fe25519_neg(&r->x, &r->x);
+
+ fe25519_mul(&r->t, &r->x, &r->y);
+ return 0;
+}
+
+static inline void ge25519_pack(unsigned char r[32], const ge25519_p3 *p)
+{
+ fe25519 tx, ty, zi;
+ fe25519_invert(&zi, &p->z);
+ fe25519_mul(&tx, &p->x, &zi);
+ fe25519_mul(&ty, &p->y, &zi);
+ fe25519_pack(r, &ty);
+ r[31] ^= fe25519_getparity(&tx) << 7;
+}
+
+#if 0
+static int ge25519_isneutral_vartime(const ge25519_p3 *p)
+{
+ int ret = 1;
+ if(!fe25519_iszero(&p->x)) ret = 0;
+ if(!fe25519_iseq_vartime(&p->y, &p->z)) ret = 0;
+ return ret;
+}
+#endif
+
+/* computes [s1]p1 + [s2]p2 */
+static void ge25519_double_scalarmult_vartime(ge25519_p3 *r, const ge25519_p3 *p1, const sc25519 *s1, const ge25519_p3 *p2, const sc25519 *s2)
+{
+ ge25519_p1p1 tp1p1;
+ ge25519_p3 pre[16];
+ char *pre5 = (char *)(&(pre[5])); // eliminate type punning warning
+ unsigned char b[127];
+ int i;
+
+ /* precomputation s2 s1 */
+ setneutral(pre); /* 00 00 */
+ pre[1] = *p1; /* 00 01 */
+ dbl_p1p1(&tp1p1,(ge25519_p2 *)p1); p1p1_to_p3( &pre[2], &tp1p1); /* 00 10 */
+ add_p1p1(&tp1p1,&pre[1], &pre[2]); p1p1_to_p3( &pre[3], &tp1p1); /* 00 11 */
+ pre[4] = *p2; /* 01 00 */
+ add_p1p1(&tp1p1,&pre[1], &pre[4]); p1p1_to_p3( &pre[5], &tp1p1); /* 01 01 */
+ add_p1p1(&tp1p1,&pre[2], &pre[4]); p1p1_to_p3( &pre[6], &tp1p1); /* 01 10 */
+ add_p1p1(&tp1p1,&pre[3], &pre[4]); p1p1_to_p3( &pre[7], &tp1p1); /* 01 11 */
+ dbl_p1p1(&tp1p1,(ge25519_p2 *)p2); p1p1_to_p3( &pre[8], &tp1p1); /* 10 00 */
+ add_p1p1(&tp1p1,&pre[1], &pre[8]); p1p1_to_p3( &pre[9], &tp1p1); /* 10 01 */
+ dbl_p1p1(&tp1p1,(ge25519_p2 *)pre5); p1p1_to_p3(&pre[10], &tp1p1); /* 10 10 */
+ add_p1p1(&tp1p1,&pre[3], &pre[8]); p1p1_to_p3(&pre[11], &tp1p1); /* 10 11 */
+ add_p1p1(&tp1p1,&pre[4], &pre[8]); p1p1_to_p3(&pre[12], &tp1p1); /* 11 00 */
+ add_p1p1(&tp1p1,&pre[1],&pre[12]); p1p1_to_p3(&pre[13], &tp1p1); /* 11 01 */
+ add_p1p1(&tp1p1,&pre[2],&pre[12]); p1p1_to_p3(&pre[14], &tp1p1); /* 11 10 */
+ add_p1p1(&tp1p1,&pre[3],&pre[12]); p1p1_to_p3(&pre[15], &tp1p1); /* 11 11 */
+
+ sc25519_2interleave2(b,s1,s2);
+
+ /* scalar multiplication */
+ *r = pre[b[126]];
+ for(i=125;i>=0;i--)
+ {
+ dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
+ p1p1_to_p2((ge25519_p2 *) r, &tp1p1);
+ dbl_p1p1(&tp1p1, (ge25519_p2 *)r);
+ if(b[i]!=0)
+ {
+ p1p1_to_p3(r, &tp1p1);
+ add_p1p1(&tp1p1, r, &pre[b[i]]);
+ }
+ if(i != 0) p1p1_to_p2((ge25519_p2 *)r, &tp1p1);
+ else p1p1_to_p3(r, &tp1p1);
+ }
+}
+
+static inline void ge25519_scalarmult_base(ge25519_p3 *r, const sc25519 *s)
+{
+ signed char b[85];
+ int i;
+ ge25519_aff t;
+ sc25519_window3(b,s);
+
+ choose_t((ge25519_aff *)r, 0, b[0]);
+ fe25519_setone(&r->z);
+ fe25519_mul(&r->t, &r->x, &r->y);
+ for(i=1;i<85;i++)
+ {
+ choose_t(&t, (unsigned long long) i, b[i]);
+ ge25519_mixadd2(r, &t);
+ }
+}
+
+static inline void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char *pk, unsigned char *playground, unsigned long long smlen)
+{
+ unsigned long long i;
+
+ for (i = 0;i < 32;++i) playground[i] = sm[i];
+ for (i = 32;i < 64;++i) playground[i] = pk[i-32];
+ for (i = 64;i < smlen;++i) playground[i] = sm[i];
+
+ //crypto_hash_sha512(hram,playground,smlen);
+ SHA512::hash(hram,playground,(unsigned int)smlen);
+}
+
+// This is the original sign and verify code -- the versions in sign() and
+// verify() below the fold are slightly modified in terms of how they behave
+// in relation to the message, but the algorithms are the same.
+
+#if 0
+int crypto_sign_keypair(
+ unsigned char *pk,
+ unsigned char *sk
+ )
+{
+ sc25519 scsk;
+ ge25519 gepk;
+ unsigned char extsk[64];
+ int i;
+
+ randombytes(sk, 32);
+ crypto_hash_sha512(extsk, sk, 32);
+ extsk[0] &= 248;
+ extsk[31] &= 127;
+ extsk[31] |= 64;
+
+ sc25519_from32bytes(&scsk,extsk);
+
+ ge25519_scalarmult_base(&gepk, &scsk);
+ ge25519_pack(pk, &gepk);
+ for(i=0;i<32;i++)
+ sk[32 + i] = pk[i];
+ return 0;
+}
+
+static int crypto_sign(
+ unsigned char *sm,unsigned long long *smlen,
+ const unsigned char *m,unsigned long long mlen,
+ const unsigned char *sk
+ )
+{
+ sc25519 sck, scs, scsk;
+ ge25519 ger;
+ unsigned char r[32];
+ unsigned char s[32];
+ unsigned char extsk[64];
+ unsigned long long i;
+ unsigned char hmg[crypto_hash_sha512_BYTES];
+ unsigned char hram[crypto_hash_sha512_BYTES];
+
+ crypto_hash_sha512(extsk, sk, 32);
+ extsk[0] &= 248;
+ extsk[31] &= 127;
+ extsk[31] |= 64;
+
+ *smlen = mlen+64;
+ for(i=0;i<mlen;i++)
+ sm[64 + i] = m[i];
+ for(i=0;i<32;i++)
+ sm[32 + i] = extsk[32+i];
+
+ crypto_hash_sha512(hmg, sm+32, mlen+32); /* Generate k as h(extsk[32],...,extsk[63],m) */
+
+ /* Computation of R */
+ sc25519_from64bytes(&sck, hmg);
+ ge25519_scalarmult_base(&ger, &sck);
+ ge25519_pack(r, &ger);
+
+ /* Computation of s */
+ for(i=0;i<32;i++)
+ sm[i] = r[i];
+
+ get_hram(hram, sm, sk+32, sm, mlen+64);
+
+ sc25519_from64bytes(&scs, hram);
+ sc25519_from32bytes(&scsk, extsk);
+ sc25519_mul(&scs, &scs, &scsk);
+
+ sc25519_add(&scs, &scs, &sck);
+
+ sc25519_to32bytes(s,&scs); /* cat s */
+ for(i=0;i<32;i++)
+ sm[32 + i] = s[i];
+
+ return 0;
+}
+
+static int crypto_sign_open(
+ unsigned char *m,unsigned long long *mlen,
+ const unsigned char *sm,unsigned long long smlen,
+ const unsigned char *pk
+ )
+{
+ int i, ret;
+ unsigned char t2[32];
+ ge25519 get1, get2;
+ sc25519 schram, scs;
+ unsigned char hram[crypto_hash_sha512_BYTES];
+
+ *mlen = (unsigned long long) -1;
+ if (smlen < 64) return -1;
+
+ if (ge25519_unpackneg_vartime(&get1, pk)) return -1;
+
+ get_hram(hram,sm,pk,m,smlen);
+
+ sc25519_from64bytes(&schram, hram);
+
+ sc25519_from32bytes(&scs, sm+32);
+
+ ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs);
+ ge25519_pack(t2, &get2);
+
+ ret = crypto_verify_32(sm, t2);
+
+ if (!ret)
+ {
+ for(i=0;i<smlen-64;i++)
+ m[i] = sm[i + 64];
+ *mlen = smlen-64;
+ }
+ else
+ {
+ for(i=0;i<smlen-64;i++)
+ m[i] = 0;
+ }
+ return ret;
+}
+#endif // 0
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void *keybuf,unsigned int keylen)
+ throw()
+{
+ unsigned char rawkey[32];
+ unsigned char digest[64];
+
+ crypto_scalarmult(rawkey,mine.data,their.data);
+ SHA512::hash(digest,rawkey,32);
+ for(unsigned int i=0,k=0;i<keylen;) {
+ if (k == 64) {
+ k = 0;
+ SHA512::hash(digest,digest,64);
+ }
+ ((unsigned char *)keybuf)[i++] = digest[k++];
+ }
+}
+
+void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature)
+ throw()
+{
+ sc25519 sck, scs, scsk;
+ ge25519 ger;
+ unsigned char r[32];
+ unsigned char s[32];
+ unsigned char extsk[64];
+ unsigned char hmg[crypto_hash_sha512_BYTES];
+ unsigned char hram[crypto_hash_sha512_BYTES];
+ unsigned char *sig = (unsigned char *)signature;
+ unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
+
+ SHA512::hash(digest,msg,len);
+
+ SHA512::hash(extsk,myPrivate.data + 32,32);
+ extsk[0] &= 248;
+ extsk[31] &= 127;
+ extsk[31] |= 64;
+
+ for(unsigned int i=0;i<32;i++)
+ sig[32 + i] = extsk[32 + i];
+ for(unsigned int i=0;i<32;i++)
+ sig[64 + i] = digest[i];
+
+ SHA512::hash(hmg,sig + 32,64);
+ //crypto_hash_sha512(hmg, sm+32, mlen+32); /* Generate k as h(extsk[32],...,extsk[63],m) */
+
+ /* Computation of R */
+ sc25519_from64bytes(&sck, hmg);
+ ge25519_scalarmult_base(&ger, &sck);
+ ge25519_pack(r, &ger);
+
+ /* Computation of s */
+ for(unsigned int i=0;i<32;i++)
+ sig[i] = r[i];
+
+ get_hram(hram,sig,myPublic.data + 32,sig,96);
+
+ sc25519_from64bytes(&scs, hram);
+ sc25519_from32bytes(&scsk, extsk);
+ sc25519_mul(&scs, &scs, &scsk);
+
+ sc25519_add(&scs, &scs, &sck);
+
+ sc25519_to32bytes(s,&scs); /* cat s */
+ for(unsigned int i=0;i<32;i++)
+ sig[32 + i] = s[i];
+}
+
+bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature)
+ throw()
+{
+ unsigned char t2[32];
+ ge25519 get1, get2;
+ sc25519 schram, scs;
+ unsigned char hram[crypto_hash_sha512_BYTES];
+ unsigned char m[96];
+ unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
+ const unsigned char *sig = (const unsigned char *)signature;
+
+ // First check the message's integrity
+ SHA512::hash(digest,msg,len);
+ if (!Utils::secureEq(sig + 64,digest,32))
+ return false;
+
+ if (ge25519_unpackneg_vartime(&get1,their.data + 32))
+ return false;
+
+ get_hram(hram,sig,their.data + 32,m,96);
+
+ sc25519_from64bytes(&schram, hram);
+
+ sc25519_from32bytes(&scs, sig+32);
+
+ ge25519_double_scalarmult_vartime(&get2, &get1, &schram, &ge25519_base, &scs);
+ ge25519_pack(t2, &get2);
+
+ return Utils::secureEq(sig,t2,32);
+}
+
+void C25519::_calcPubDH(C25519::Pair &kp)
+ throw()
+{
+ // First 32 bytes of pub and priv are the keys for ECDH key
+ // agreement. This generates the public portion from the private.
+ crypto_scalarmult_base(kp.pub.data,kp.priv.data);
+}
+
+void C25519::_calcPubED(C25519::Pair &kp)
+ throw()
+{
+ unsigned char extsk[64];
+ sc25519 scsk;
+ ge25519 gepk;
+
+ // Second 32 bytes of pub and priv are the keys for ed25519
+ // signing and verification.
+ SHA512::hash(extsk,kp.priv.data + 32,32);
+ extsk[0] &= 248;
+ extsk[31] &= 127;
+ extsk[31] |= 64;
+ sc25519_from32bytes(&scsk,extsk);
+ ge25519_scalarmult_base(&gepk,&scsk);
+ ge25519_pack(kp.pub.data + 32,&gepk);
+ // In NaCl, the public key is crammed into the next 32 bytes
+ // of the private key for signing since both keys are required
+ // to sign. In this version we just get it from kp.pub, so we
+ // leave that out of private.
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/C25519.hpp b/zerotierone/node/C25519.hpp
new file mode 100644
index 0000000..b19d969
--- /dev/null
+++ b/zerotierone/node/C25519.hpp
@@ -0,0 +1,213 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_C25519_HPP
+#define ZT_C25519_HPP
+
+#include "Array.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+#define ZT_C25519_PUBLIC_KEY_LEN 64
+#define ZT_C25519_PRIVATE_KEY_LEN 64
+#define ZT_C25519_SIGNATURE_LEN 96
+
+/**
+ * A combined Curve25519 ECDH and Ed25519 signature engine
+ */
+class C25519
+{
+public:
+ /**
+ * Public key (both crypto and signing)
+ */
+ typedef Array<unsigned char,ZT_C25519_PUBLIC_KEY_LEN> Public; // crypto key, signing key (both 32 bytes)
+
+ /**
+ * Private key (both crypto and signing)
+ */
+ typedef Array<unsigned char,ZT_C25519_PRIVATE_KEY_LEN> Private; // crypto key, signing key (both 32 bytes)
+
+ /**
+ * Message signature
+ */
+ typedef Array<unsigned char,ZT_C25519_SIGNATURE_LEN> Signature;
+
+ /**
+ * Public/private key pair
+ */
+ typedef struct {
+ Public pub;
+ Private priv;
+ } Pair;
+
+ /**
+ * Generate a C25519 elliptic curve key pair
+ */
+ static inline Pair generate()
+ throw()
+ {
+ Pair kp;
+ Utils::getSecureRandom(kp.priv.data,(unsigned int)kp.priv.size());
+ _calcPubDH(kp);
+ _calcPubED(kp);
+ return kp;
+ }
+
+ /**
+ * Generate a key pair satisfying a condition
+ *
+ * This begins with a random keypair from a random secret key and then
+ * iteratively increments the random secret until cond(kp) returns true.
+ * This is used to compute key pairs in which the public key, its hash
+ * or some other aspect of it satisfies some condition, such as for a
+ * hashcash criteria.
+ *
+ * @param cond Condition function or function object
+ * @return Key pair where cond(kp) returns true
+ * @tparam F Type of 'cond'
+ */
+ template<typename F>
+ static inline Pair generateSatisfying(F cond)
+ throw()
+ {
+ Pair kp;
+ void *const priv = (void *)kp.priv.data;
+ Utils::getSecureRandom(priv,(unsigned int)kp.priv.size());
+ _calcPubED(kp); // do Ed25519 key -- bytes 32-63 of pub and priv
+ do {
+ ++(((uint64_t *)priv)[1]);
+ --(((uint64_t *)priv)[2]);
+ _calcPubDH(kp); // keep regenerating bytes 0-31 until satisfied
+ } while (!cond(kp));
+ return kp;
+ }
+
+ /**
+ * Perform C25519 ECC key agreement
+ *
+ * Actual key bytes are generated from one or more SHA-512 digests of
+ * the raw result of key agreement.
+ *
+ * @param mine My private key
+ * @param their Their public key
+ * @param keybuf Buffer to fill
+ * @param keylen Number of key bytes to generate
+ */
+ static void agree(const Private &mine,const Public &their,void *keybuf,unsigned int keylen)
+ throw();
+ static inline void agree(const Pair &mine,const Public &their,void *keybuf,unsigned int keylen)
+ throw()
+ {
+ agree(mine.priv,their,keybuf,keylen);
+ }
+
+ /**
+ * Sign a message with a sender's key pair
+ *
+ * This takes the SHA-521 of msg[] and then signs the first 32 bytes of this
+ * digest, returning it and the 64-byte ed25519 signature in signature[].
+ * This results in a signature that verifies both the signer's authenticity
+ * and the integrity of the message.
+ *
+ * This is based on the original ed25519 code from NaCl and the SUPERCOP
+ * cipher benchmark suite, but with the modification that it always
+ * produces a signature of fixed 96-byte length based on the hash of an
+ * arbitrary-length message.
+ *
+ * @param myPrivate My private key
+ * @param myPublic My public key
+ * @param msg Message to sign
+ * @param len Length of message in bytes
+ * @param signature Buffer to fill with signature -- MUST be 96 bytes in length
+ */
+ static void sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len,void *signature)
+ throw();
+ static inline void sign(const Pair &mine,const void *msg,unsigned int len,void *signature)
+ throw()
+ {
+ sign(mine.priv,mine.pub,msg,len,signature);
+ }
+
+ /**
+ * Sign a message with a sender's key pair
+ *
+ * @param myPrivate My private key
+ * @param myPublic My public key
+ * @param msg Message to sign
+ * @param len Length of message in bytes
+ * @return Signature
+ */
+ static inline Signature sign(const Private &myPrivate,const Public &myPublic,const void *msg,unsigned int len)
+ throw()
+ {
+ Signature sig;
+ sign(myPrivate,myPublic,msg,len,sig.data);
+ return sig;
+ }
+ static inline Signature sign(const Pair &mine,const void *msg,unsigned int len)
+ throw()
+ {
+ Signature sig;
+ sign(mine.priv,mine.pub,msg,len,sig.data);
+ return sig;
+ }
+
+ /**
+ * Verify a message's signature
+ *
+ * @param their Public key to verify against
+ * @param msg Message to verify signature integrity against
+ * @param len Length of message in bytes
+ * @param signature 96-byte signature
+ * @return True if signature is valid and the message is authentic and unmodified
+ */
+ static bool verify(const Public &their,const void *msg,unsigned int len,const void *signature)
+ throw();
+
+ /**
+ * Verify a message's signature
+ *
+ * @param their Public key to verify against
+ * @param msg Message to verify signature integrity against
+ * @param len Length of message in bytes
+ * @param signature 96-byte signature
+ * @return True if signature is valid and the message is authentic and unmodified
+ */
+ static inline bool verify(const Public &their,const void *msg,unsigned int len,const Signature &signature)
+ throw()
+ {
+ return verify(their,msg,len,signature.data);
+ }
+
+private:
+ // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
+ // this is the ECDH key
+ static void _calcPubDH(Pair &kp)
+ throw();
+
+ // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
+ // this is the Ed25519 sign/verify key
+ static void _calcPubED(Pair &kp)
+ throw();
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/CertificateOfMembership.cpp b/zerotierone/node/CertificateOfMembership.cpp
new file mode 100644
index 0000000..55537fd
--- /dev/null
+++ b/zerotierone/node/CertificateOfMembership.cpp
@@ -0,0 +1,230 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "CertificateOfMembership.hpp"
+
+namespace ZeroTier {
+
+void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
+{
+ _signedBy.zero();
+
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ if (_qualifiers[i].id == id) {
+ _qualifiers[i].value = value;
+ _qualifiers[i].maxDelta = maxDelta;
+ return;
+ }
+ }
+
+ if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
+ _qualifiers[_qualifierCount].id = id;
+ _qualifiers[_qualifierCount].value = value;
+ _qualifiers[_qualifierCount].maxDelta = maxDelta;
+ ++_qualifierCount;
+ std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
+ }
+}
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+
+std::string CertificateOfMembership::toString() const
+{
+ std::string s;
+
+ s.append("1:"); // COM_UINT64_ED25519
+
+ uint64_t *const buf = new uint64_t[_qualifierCount * 3];
+ try {
+ unsigned int ptr = 0;
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ buf[ptr++] = Utils::hton(_qualifiers[i].id);
+ buf[ptr++] = Utils::hton(_qualifiers[i].value);
+ buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
+ }
+ s.append(Utils::hex(buf,ptr * sizeof(uint64_t)));
+ delete [] buf;
+ } catch ( ... ) {
+ delete [] buf;
+ throw;
+ }
+
+ s.push_back(':');
+
+ s.append(_signedBy.toString());
+
+ if (_signedBy) {
+ s.push_back(':');
+ s.append(Utils::hex(_signature.data,(unsigned int)_signature.size()));
+ }
+
+ return s;
+}
+
+void CertificateOfMembership::fromString(const char *s)
+{
+ _qualifierCount = 0;
+ _signedBy.zero();
+ memset(_signature.data,0,_signature.size());
+
+ if (!*s)
+ return;
+
+ unsigned int colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (!((colonAt == 1)&&(s[0] == '1'))) // COM_UINT64_ED25519?
+ return;
+
+ s += colonAt + 1;
+ colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (colonAt) {
+ const unsigned int buflen = colonAt / 2;
+ char *const buf = new char[buflen];
+ unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen);
+ char *bufptr = buf;
+ try {
+ while (bufactual >= 24) {
+ if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
+ _qualifiers[_qualifierCount].id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ _qualifiers[_qualifierCount].value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ _qualifiers[_qualifierCount].maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ ++_qualifierCount;
+ } else {
+ bufptr += 24;
+ }
+ bufactual -= 24;
+ }
+ } catch ( ... ) {}
+ delete [] buf;
+ }
+
+ if (s[colonAt]) {
+ s += colonAt + 1;
+ colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (colonAt) {
+ char addrbuf[ZT_ADDRESS_LENGTH];
+ if (Utils::unhex(s,colonAt,addrbuf,sizeof(addrbuf)) == ZT_ADDRESS_LENGTH)
+ _signedBy.setTo(addrbuf,ZT_ADDRESS_LENGTH);
+
+ if ((_signedBy)&&(s[colonAt])) {
+ s += colonAt + 1;
+ colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+ if (colonAt) {
+ if (Utils::unhex(s,colonAt,_signature.data,(unsigned int)_signature.size()) != _signature.size())
+ _signedBy.zero();
+ } else {
+ _signedBy.zero();
+ }
+ } else {
+ _signedBy.zero();
+ }
+ }
+ }
+
+ std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
+}
+
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const
+{
+ unsigned int myidx = 0;
+ unsigned int otheridx = 0;
+
+ while (myidx < _qualifierCount) {
+ // Fail if we're at the end of other, since this means the field is
+ // missing.
+ if (otheridx >= other._qualifierCount)
+ return false;
+
+ // Seek to corresponding tuple in other, ignoring tuples that
+ // we may not have. If we run off the end of other, the tuple is
+ // missing. This works because tuples are sorted by ID.
+ while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) {
+ ++otheridx;
+ if (otheridx >= other._qualifierCount)
+ return false;
+ }
+
+ // Compare to determine if the absolute value of the difference
+ // between these two parameters is within our maxDelta.
+ const uint64_t a = _qualifiers[myidx].value;
+ const uint64_t b = other._qualifiers[myidx].value;
+ if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[myidx].maxDelta)
+ return false;
+
+ ++myidx;
+ }
+
+ return true;
+}
+
+bool CertificateOfMembership::sign(const Identity &with)
+{
+ uint64_t *const buf = new uint64_t[_qualifierCount * 3];
+ unsigned int ptr = 0;
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ buf[ptr++] = Utils::hton(_qualifiers[i].id);
+ buf[ptr++] = Utils::hton(_qualifiers[i].value);
+ buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
+ }
+
+ try {
+ _signature = with.sign(buf,ptr * sizeof(uint64_t));
+ _signedBy = with.address();
+ delete [] buf;
+ return true;
+ } catch ( ... ) {
+ _signedBy.zero();
+ delete [] buf;
+ return false;
+ }
+}
+
+bool CertificateOfMembership::verify(const Identity &id) const
+{
+ if (!_signedBy)
+ return false;
+ if (id.address() != _signedBy)
+ return false;
+
+ uint64_t *const buf = new uint64_t[_qualifierCount * 3];
+ unsigned int ptr = 0;
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ buf[ptr++] = Utils::hton(_qualifiers[i].id);
+ buf[ptr++] = Utils::hton(_qualifiers[i].value);
+ buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
+ }
+
+ bool valid = false;
+ try {
+ valid = id.verify(buf,ptr * sizeof(uint64_t),_signature);
+ delete [] buf;
+ } catch ( ... ) {
+ delete [] buf;
+ }
+ return valid;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/CertificateOfMembership.hpp b/zerotierone/node/CertificateOfMembership.hpp
new file mode 100644
index 0000000..43c8c0a
--- /dev/null
+++ b/zerotierone/node/CertificateOfMembership.hpp
@@ -0,0 +1,432 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
+#define ZT_CERTIFICATEOFMEMBERSHIP_HPP
+
+#include <stdint.h>
+#include <string.h>
+
+#include <string>
+#include <stdexcept>
+#include <algorithm>
+
+#include "Constants.hpp"
+#include "Buffer.hpp"
+#include "Address.hpp"
+#include "C25519.hpp"
+#include "Identity.hpp"
+#include "Utils.hpp"
+
+/**
+ * Default window of time for certificate agreement
+ *
+ * Right now we use time for 'revision' so this is the maximum time divergence
+ * between two certs for them to agree. It comes out to five minutes, which
+ * gives a lot of margin for error if the controller hiccups or its clock
+ * drifts but causes de-authorized peers to fall off fast enough.
+ */
+#define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
+
+/**
+ * Maximum number of qualifiers in a COM
+ */
+#define ZT_NETWORK_COM_MAX_QUALIFIERS 16
+
+namespace ZeroTier {
+
+/**
+ * Certificate of network membership
+ *
+ * The COM contains a sorted set of three-element tuples called qualifiers.
+ * These contain an id, a value, and a maximum delta.
+ *
+ * The ID is arbitrary and should be assigned using a scheme that makes
+ * every ID globally unique. IDs beneath 65536 are reserved for global
+ * assignment by ZeroTier Networks.
+ *
+ * The value's meaning is ID-specific and isn't important here. What's
+ * important is the value and the third member of the tuple: the maximum
+ * delta. The maximum delta is the maximum difference permitted between
+ * values for a given ID between certificates for the two certificates to
+ * themselves agree.
+ *
+ * Network membership is checked by checking whether a peer's certificate
+ * agrees with your own. The timestamp provides the fundamental criterion--
+ * each member of a private network must constantly obtain new certificates
+ * often enough to stay within the max delta for this qualifier. But other
+ * criteria could be added in the future for very special behaviors, things
+ * like latitude and longitude for instance.
+ *
+ * This is a memcpy()'able structure and is safe (in a crash sense) to modify
+ * without locks.
+ */
+class CertificateOfMembership
+{
+public:
+ /**
+ * Certificate type codes, used in serialization
+ *
+ * Only one so far, and only one hopefully there shall be for quite some
+ * time.
+ */
+ enum Type
+ {
+ COM_UINT64_ED25519 = 1 // tuples of unsigned 64's signed with Ed25519
+ };
+
+ /**
+ * Reserved qualifier IDs
+ *
+ * IDs below 65536 should be considered reserved for future global
+ * assignment here.
+ *
+ * Addition of new required fields requires that code in hasRequiredFields
+ * be updated as well.
+ */
+ enum ReservedId
+ {
+ /**
+ * Revision number of certificate
+ *
+ * Certificates may differ in revision number by a designated max
+ * delta. Differences wider than this cause certificates not to agree.
+ */
+ COM_RESERVED_ID_REVISION = 0,
+
+ /**
+ * Network ID for which certificate was issued
+ *
+ * maxDelta here is zero, since this must match.
+ */
+ COM_RESERVED_ID_NETWORK_ID = 1,
+
+ /**
+ * ZeroTier address to whom certificate was issued
+ *
+ * maxDelta will be 0xffffffffffffffff here since it's permitted to differ
+ * from peers obviously.
+ */
+ COM_RESERVED_ID_ISSUED_TO = 2
+ };
+
+ /**
+ * Create an empty certificate
+ */
+ CertificateOfMembership() :
+ _qualifierCount(0)
+ {
+ memset(_signature.data,0,_signature.size());
+ }
+
+ CertificateOfMembership(const CertificateOfMembership &c)
+ {
+ memcpy(this,&c,sizeof(CertificateOfMembership));
+ }
+
+ /**
+ * Create from required fields common to all networks
+ *
+ * @param revision Revision number of certificate
+ * @param timestampMaxDelta Maximum variation between timestamps on this net
+ * @param nwid Network ID
+ * @param issuedTo Certificate recipient
+ */
+ CertificateOfMembership(uint64_t revision,uint64_t revisionMaxDelta,uint64_t nwid,const Address &issuedTo)
+ {
+ _qualifiers[0].id = COM_RESERVED_ID_REVISION;
+ _qualifiers[0].value = revision;
+ _qualifiers[0].maxDelta = revisionMaxDelta;
+ _qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
+ _qualifiers[1].value = nwid;
+ _qualifiers[1].maxDelta = 0;
+ _qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO;
+ _qualifiers[2].value = issuedTo.toInt();
+ _qualifiers[2].maxDelta = 0xffffffffffffffffULL;
+ _qualifierCount = 3;
+ memset(_signature.data,0,_signature.size());
+ }
+
+ inline CertificateOfMembership &operator=(const CertificateOfMembership &c)
+ {
+ memcpy(this,&c,sizeof(CertificateOfMembership));
+ return *this;
+ }
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ /**
+ * Create from string-serialized data
+ *
+ * @param s String-serialized COM
+ */
+ CertificateOfMembership(const char *s) { fromString(s); }
+
+ /**
+ * Create from string-serialized data
+ *
+ * @param s String-serialized COM
+ */
+ CertificateOfMembership(const std::string &s) { fromString(s.c_str()); }
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+ /**
+ * Create from binary-serialized COM in buffer
+ *
+ * @param b Buffer to deserialize from
+ * @param startAt Position to start in buffer
+ */
+ template<unsigned int C>
+ CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ deserialize(b,startAt);
+ }
+
+ /**
+ * @return True if there's something here
+ */
+ inline operator bool() const throw() { return (_qualifierCount != 0); }
+
+ /**
+ * Check for presence of all required fields common to all networks
+ *
+ * @return True if all required fields are present
+ */
+ inline bool hasRequiredFields() const
+ {
+ if (_qualifierCount < 3)
+ return false;
+ if (_qualifiers[0].id != COM_RESERVED_ID_REVISION)
+ return false;
+ if (_qualifiers[1].id != COM_RESERVED_ID_NETWORK_ID)
+ return false;
+ if (_qualifiers[2].id != COM_RESERVED_ID_ISSUED_TO)
+ return false;
+ return true;
+ }
+
+ /**
+ * @return Maximum delta for mandatory revision field or 0 if field missing
+ */
+ inline uint64_t revisionMaxDelta() const
+ {
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
+ return _qualifiers[i].maxDelta;
+ }
+ return 0ULL;
+ }
+
+ /**
+ * @return Revision number for this cert
+ */
+ inline uint64_t revision() const
+ {
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
+ return _qualifiers[i].value;
+ }
+ return 0ULL;
+ }
+
+ /**
+ * @return Address to which this cert was issued
+ */
+ inline Address issuedTo() const
+ {
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
+ return Address(_qualifiers[i].value);
+ }
+ return Address();
+ }
+
+ /**
+ * @return Network ID for which this cert was issued
+ */
+ inline uint64_t networkId() const
+ {
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
+ return _qualifiers[i].value;
+ }
+ return 0ULL;
+ }
+
+ /**
+ * Add or update a qualifier in this certificate
+ *
+ * Any signature is invalidated and signedBy is set to null.
+ *
+ * @param id Qualifier ID
+ * @param value Qualifier value
+ * @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
+ */
+ void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta);
+ inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ /**
+ * @return String-serialized representation of this certificate
+ */
+ std::string toString() const;
+
+ /**
+ * Set this certificate equal to the hex-serialized string
+ *
+ * Invalid strings will result in invalid or undefined certificate
+ * contents. These will subsequently fail validation and comparison.
+ * Empty strings will result in an empty certificate.
+ *
+ * @param s String to deserialize
+ */
+ void fromString(const char *s);
+ inline void fromString(const std::string &s) { fromString(s.c_str()); }
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+ /**
+ * Compare two certificates for parameter agreement
+ *
+ * This compares this certificate with the other and returns true if all
+ * paramters in this cert are present in the other and if they agree to
+ * within this cert's max delta value for each given parameter.
+ *
+ * Tuples present in other but not in this cert are ignored, but any
+ * tuples present in this cert but not in other result in 'false'.
+ *
+ * @param other Cert to compare with
+ * @return True if certs agree and 'other' may be communicated with
+ */
+ bool agreesWith(const CertificateOfMembership &other) const;
+
+ /**
+ * Sign this certificate
+ *
+ * @param with Identity to sign with, must include private key
+ * @return True if signature was successful
+ */
+ bool sign(const Identity &with);
+
+ /**
+ * Verify certificate against an identity
+ *
+ * @param id Identity to verify against
+ * @return True if certificate is signed by this identity and verification was successful
+ */
+ bool verify(const Identity &id) const;
+
+ /**
+ * @return True if signed
+ */
+ inline bool isSigned() const throw() { return (_signedBy); }
+
+ /**
+ * @return Address that signed this certificate or null address if none
+ */
+ inline const Address &signedBy() const throw() { return _signedBy; }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ b.append((unsigned char)COM_UINT64_ED25519);
+ b.append((uint16_t)_qualifierCount);
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ b.append(_qualifiers[i].id);
+ b.append(_qualifiers[i].value);
+ b.append(_qualifiers[i].maxDelta);
+ }
+ _signedBy.appendTo(b);
+ if (_signedBy)
+ b.append(_signature.data,(unsigned int)_signature.size());
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+
+ _qualifierCount = 0;
+ _signedBy.zero();
+
+ if (b[p++] != COM_UINT64_ED25519)
+ throw std::invalid_argument("invalid type");
+
+ unsigned int numq = b.template at<uint16_t>(p); p += sizeof(uint16_t);
+ uint64_t lastId = 0;
+ for(unsigned int i=0;i<numq;++i) {
+ const uint64_t qid = b.template at<uint64_t>(p);
+ if (qid < lastId)
+ throw std::invalid_argument("qualifiers not sorted");
+ else lastId = qid;
+ if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
+ _qualifiers[_qualifierCount].id = qid;
+ _qualifiers[_qualifierCount].value = b.template at<uint64_t>(p + 8);
+ _qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
+ p += 24;
+ ++_qualifierCount;
+ } else {
+ throw std::invalid_argument("too many qualifiers");
+ }
+ }
+
+ _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ p += ZT_ADDRESS_LENGTH;
+
+ if (_signedBy) {
+ memcpy(_signature.data,b.field(p,(unsigned int)_signature.size()),_signature.size());
+ p += (unsigned int)_signature.size();
+ }
+
+ return (p - startAt);
+ }
+
+ inline bool operator==(const CertificateOfMembership &c) const
+ throw()
+ {
+ if (_signedBy != c._signedBy)
+ return false;
+ if (_qualifierCount != c._qualifierCount)
+ return false;
+ for(unsigned int i=0;i<_qualifierCount;++i) {
+ const _Qualifier &a = _qualifiers[i];
+ const _Qualifier &b = c._qualifiers[i];
+ if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
+ return false;
+ }
+ return (_signature == c._signature);
+ }
+ inline bool operator!=(const CertificateOfMembership &c) const throw() { return (!(*this == c)); }
+
+private:
+ struct _Qualifier
+ {
+ _Qualifier() : id(0),value(0),maxDelta(0) {}
+ uint64_t id;
+ uint64_t value;
+ uint64_t maxDelta;
+ inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // sort order
+ };
+
+ Address _signedBy;
+ _Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS];
+ unsigned int _qualifierCount;
+ C25519::Signature _signature;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Cluster.cpp b/zerotierone/node/Cluster.cpp
new file mode 100644
index 0000000..f590ad1
--- /dev/null
+++ b/zerotierone/node/Cluster.cpp
@@ -0,0 +1,913 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <map>
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <list>
+#include <stdexcept>
+
+#include "../version.h"
+
+#include "Cluster.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "MulticastGroup.hpp"
+#include "CertificateOfMembership.hpp"
+#include "Salsa20.hpp"
+#include "Poly1305.hpp"
+#include "Identity.hpp"
+#include "Topology.hpp"
+#include "Packet.hpp"
+#include "Switch.hpp"
+#include "Node.hpp"
+#include "Array.hpp"
+
+namespace ZeroTier {
+
+static inline double _dist3d(int x1,int y1,int z1,int x2,int y2,int z2)
+ throw()
+{
+ double dx = ((double)x2 - (double)x1);
+ double dy = ((double)y2 - (double)y1);
+ double dz = ((double)z2 - (double)z1);
+ return sqrt((dx * dx) + (dy * dy) + (dz * dz));
+}
+
+// An entry in _ClusterSendQueue
+struct _ClusterSendQueueEntry
+{
+ uint64_t timestamp;
+ Address fromPeerAddress;
+ Address toPeerAddress;
+ // if we ever support larger transport MTUs this must be increased
+ unsigned char data[ZT_CLUSTER_SEND_QUEUE_DATA_MAX];
+ unsigned int len;
+ bool unite;
+};
+
+// A multi-index map with entry memory pooling -- this allows our queue to
+// be O(log(N)) and is complex enough that it makes the code a lot cleaner
+// to break it out from Cluster.
+class _ClusterSendQueue
+{
+public:
+ _ClusterSendQueue() :
+ _poolCount(0) {}
+ ~_ClusterSendQueue() {} // memory is automatically freed when _chunks is destroyed
+
+ inline void enqueue(uint64_t now,const Address &from,const Address &to,const void *data,unsigned int len,bool unite)
+ {
+ if (len > ZT_CLUSTER_SEND_QUEUE_DATA_MAX)
+ return;
+
+ Mutex::Lock _l(_lock);
+
+ // Delete oldest queue entry for this sender if this enqueue() would take them over the per-sender limit
+ {
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_bySrc.lower_bound(std::pair<Address,_ClusterSendQueueEntry *>(from,(_ClusterSendQueueEntry *)0)));
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator oldest(qi);
+ unsigned long countForSender = 0;
+ while ((qi != _bySrc.end())&&(qi->first == from)) {
+ if (qi->second->timestamp < oldest->second->timestamp)
+ oldest = qi;
+ ++countForSender;
+ ++qi;
+ }
+ if (countForSender >= ZT_CLUSTER_MAX_QUEUE_PER_SENDER) {
+ _byDest.erase(std::pair<Address,_ClusterSendQueueEntry *>(oldest->second->toPeerAddress,oldest->second));
+ _pool[_poolCount++] = oldest->second;
+ _bySrc.erase(oldest);
+ }
+ }
+
+ _ClusterSendQueueEntry *e;
+ if (_poolCount > 0) {
+ e = _pool[--_poolCount];
+ } else {
+ if (_chunks.size() >= ZT_CLUSTER_MAX_QUEUE_CHUNKS)
+ return; // queue is totally full!
+ _chunks.push_back(Array<_ClusterSendQueueEntry,ZT_CLUSTER_QUEUE_CHUNK_SIZE>());
+ e = &(_chunks.back().data[0]);
+ for(unsigned int i=1;i<ZT_CLUSTER_QUEUE_CHUNK_SIZE;++i)
+ _pool[_poolCount++] = &(_chunks.back().data[i]);
+ }
+
+ e->timestamp = now;
+ e->fromPeerAddress = from;
+ e->toPeerAddress = to;
+ memcpy(e->data,data,len);
+ e->len = len;
+ e->unite = unite;
+
+ _bySrc.insert(std::pair<Address,_ClusterSendQueueEntry *>(from,e));
+ _byDest.insert(std::pair<Address,_ClusterSendQueueEntry *>(to,e));
+ }
+
+ inline void expire(uint64_t now)
+ {
+ Mutex::Lock _l(_lock);
+ for(std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_bySrc.begin());qi!=_bySrc.end();) {
+ if ((now - qi->second->timestamp) > ZT_CLUSTER_QUEUE_EXPIRATION) {
+ _byDest.erase(std::pair<Address,_ClusterSendQueueEntry *>(qi->second->toPeerAddress,qi->second));
+ _pool[_poolCount++] = qi->second;
+ _bySrc.erase(qi++);
+ } else ++qi;
+ }
+ }
+
+ /**
+ * Get and dequeue entries for a given destination address
+ *
+ * After use these entries must be returned with returnToPool()!
+ *
+ * @param dest Destination address
+ * @param results Array to fill with results
+ * @param maxResults Size of results[] in pointers
+ * @return Number of actual results returned
+ */
+ inline unsigned int getByDest(const Address &dest,_ClusterSendQueueEntry **results,unsigned int maxResults)
+ {
+ unsigned int count = 0;
+ Mutex::Lock _l(_lock);
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> >::iterator qi(_byDest.lower_bound(std::pair<Address,_ClusterSendQueueEntry *>(dest,(_ClusterSendQueueEntry *)0)));
+ while ((qi != _byDest.end())&&(qi->first == dest)) {
+ _bySrc.erase(std::pair<Address,_ClusterSendQueueEntry *>(qi->second->fromPeerAddress,qi->second));
+ results[count++] = qi->second;
+ if (count == maxResults)
+ break;
+ _byDest.erase(qi++);
+ }
+ return count;
+ }
+
+ /**
+ * Return entries to pool after use
+ *
+ * @param entries Array of entries
+ * @param count Number of entries
+ */
+ inline void returnToPool(_ClusterSendQueueEntry **entries,unsigned int count)
+ {
+ Mutex::Lock _l(_lock);
+ for(unsigned int i=0;i<count;++i)
+ _pool[_poolCount++] = entries[i];
+ }
+
+private:
+ std::list< Array<_ClusterSendQueueEntry,ZT_CLUSTER_QUEUE_CHUNK_SIZE> > _chunks;
+ _ClusterSendQueueEntry *_pool[ZT_CLUSTER_QUEUE_CHUNK_SIZE * ZT_CLUSTER_MAX_QUEUE_CHUNKS];
+ unsigned long _poolCount;
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> > _bySrc;
+ std::set< std::pair<Address,_ClusterSendQueueEntry *> > _byDest;
+ Mutex _lock;
+};
+
+Cluster::Cluster(
+ const RuntimeEnvironment *renv,
+ uint16_t id,
+ const std::vector<InetAddress> &zeroTierPhysicalEndpoints,
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg) :
+ RR(renv),
+ _sendQueue(new _ClusterSendQueue()),
+ _sendFunction(sendFunction),
+ _sendFunctionArg(sendFunctionArg),
+ _addressToLocationFunction(addressToLocationFunction),
+ _addressToLocationFunctionArg(addressToLocationFunctionArg),
+ _x(x),
+ _y(y),
+ _z(z),
+ _id(id),
+ _zeroTierPhysicalEndpoints(zeroTierPhysicalEndpoints),
+ _members(new _Member[ZT_CLUSTER_MAX_MEMBERS]),
+ _lastFlushed(0),
+ _lastCleanedRemotePeers(0),
+ _lastCleanedQueue(0)
+{
+ uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+
+ // Generate master secret by hashing the secret from our Identity key pair
+ RR->identity.sha512PrivateKey(_masterSecret);
+
+ // Generate our inbound message key, which is the master secret XORed with our ID and hashed twice
+ memcpy(stmp,_masterSecret,sizeof(stmp));
+ stmp[0] ^= Utils::hton(id);
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ memcpy(_key,stmp,sizeof(_key));
+ Utils::burn(stmp,sizeof(stmp));
+}
+
+Cluster::~Cluster()
+{
+ Utils::burn(_masterSecret,sizeof(_masterSecret));
+ Utils::burn(_key,sizeof(_key));
+ delete [] _members;
+ delete _sendQueue;
+}
+
+void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
+{
+ Buffer<ZT_CLUSTER_MAX_MESSAGE_LENGTH> dmsg;
+ {
+ // FORMAT: <[16] iv><[8] MAC><... data>
+ if ((len < 24)||(len > ZT_CLUSTER_MAX_MESSAGE_LENGTH))
+ return;
+
+ // 16-byte IV: first 8 bytes XORed with key, last 8 bytes used as Salsa20 64-bit IV
+ char keytmp[32];
+ memcpy(keytmp,_key,32);
+ for(int i=0;i<8;++i)
+ keytmp[i] ^= reinterpret_cast<const char *>(msg)[i];
+ Salsa20 s20(keytmp,256,reinterpret_cast<const char *>(msg) + 8);
+ Utils::burn(keytmp,sizeof(keytmp));
+
+ // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
+ char polykey[ZT_POLY1305_KEY_LEN];
+ memset(polykey,0,sizeof(polykey));
+ s20.encrypt12(polykey,polykey,sizeof(polykey));
+
+ // Compute 16-byte MAC
+ char mac[ZT_POLY1305_MAC_LEN];
+ Poly1305::compute(mac,reinterpret_cast<const char *>(msg) + 24,len - 24,polykey);
+
+ // Check first 8 bytes of MAC against 64-bit MAC in stream
+ if (!Utils::secureEq(mac,reinterpret_cast<const char *>(msg) + 16,8))
+ return;
+
+ // Decrypt!
+ dmsg.setSize(len - 24);
+ s20.decrypt12(reinterpret_cast<const char *>(msg) + 24,const_cast<void *>(dmsg.data()),dmsg.size());
+ }
+
+ if (dmsg.size() < 4)
+ return;
+ const uint16_t fromMemberId = dmsg.at<uint16_t>(0);
+ unsigned int ptr = 2;
+ if (fromMemberId == _id) // sanity check: we don't talk to ourselves
+ return;
+ const uint16_t toMemberId = dmsg.at<uint16_t>(ptr);
+ ptr += 2;
+ if (toMemberId != _id) // sanity check: message not for us?
+ return;
+
+ { // make sure sender is actually considered a member
+ Mutex::Lock _l3(_memberIds_m);
+ if (std::find(_memberIds.begin(),_memberIds.end(),fromMemberId) == _memberIds.end())
+ return;
+ }
+
+ try {
+ while (ptr < dmsg.size()) {
+ const unsigned int mlen = dmsg.at<uint16_t>(ptr); ptr += 2;
+ const unsigned int nextPtr = ptr + mlen;
+ if (nextPtr > dmsg.size())
+ break;
+
+ int mtype = -1;
+ try {
+ switch((StateMessageType)(mtype = (int)dmsg[ptr++])) {
+ default:
+ break;
+
+ case CLUSTER_MESSAGE_ALIVE: {
+ _Member &m = _members[fromMemberId];
+ Mutex::Lock mlck(m.lock);
+ ptr += 7; // skip version stuff, not used yet
+ m.x = dmsg.at<int32_t>(ptr); ptr += 4;
+ m.y = dmsg.at<int32_t>(ptr); ptr += 4;
+ m.z = dmsg.at<int32_t>(ptr); ptr += 4;
+ ptr += 8; // skip local clock, not used
+ m.load = dmsg.at<uint64_t>(ptr); ptr += 8;
+ m.peers = dmsg.at<uint64_t>(ptr); ptr += 8;
+ ptr += 8; // skip flags, unused
+#ifdef ZT_TRACE
+ std::string addrs;
+#endif
+ unsigned int physicalAddressCount = dmsg[ptr++];
+ m.zeroTierPhysicalEndpoints.clear();
+ for(unsigned int i=0;i<physicalAddressCount;++i) {
+ m.zeroTierPhysicalEndpoints.push_back(InetAddress());
+ ptr += m.zeroTierPhysicalEndpoints.back().deserialize(dmsg,ptr);
+ if (!(m.zeroTierPhysicalEndpoints.back())) {
+ m.zeroTierPhysicalEndpoints.pop_back();
+ }
+#ifdef ZT_TRACE
+ else {
+ if (addrs.length() > 0)
+ addrs.push_back(',');
+ addrs.append(m.zeroTierPhysicalEndpoints.back().toString());
+ }
+#endif
+ }
+#ifdef ZT_TRACE
+ if ((RR->node->now() - m.lastReceivedAliveAnnouncement) >= ZT_CLUSTER_TIMEOUT) {
+ TRACE("[%u] I'm alive! peers close to %d,%d,%d can be redirected to: %s",(unsigned int)fromMemberId,m.x,m.y,m.z,addrs.c_str());
+ }
+#endif
+ m.lastReceivedAliveAnnouncement = RR->node->now();
+ } break;
+
+ case CLUSTER_MESSAGE_HAVE_PEER: {
+ Identity id;
+ ptr += id.deserialize(dmsg,ptr);
+ if (id) {
+ RR->topology->saveIdentity(id);
+
+ {
+ Mutex::Lock _l(_remotePeers_m);
+ _remotePeers[std::pair<Address,unsigned int>(id.address(),(unsigned int)fromMemberId)] = RR->node->now();
+ }
+
+ _ClusterSendQueueEntry *q[16384]; // 16384 is "tons"
+ unsigned int qc = _sendQueue->getByDest(id.address(),q,16384);
+ for(unsigned int i=0;i<qc;++i)
+ this->sendViaCluster(q[i]->fromPeerAddress,q[i]->toPeerAddress,q[i]->data,q[i]->len,q[i]->unite);
+ _sendQueue->returnToPool(q,qc);
+
+ TRACE("[%u] has %s (retried %u queued sends)",(unsigned int)fromMemberId,id.address().toString().c_str(),qc);
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_WANT_PEER: {
+ const Address zeroTierAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ SharedPtr<Peer> peer(RR->topology->getPeerNoCache(zeroTierAddress));
+ if ( (peer) && (peer->hasClusterOptimalPath(RR->node->now())) ) {
+ Buffer<1024> buf;
+ peer->identity().serialize(buf);
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size());
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_REMOTE_PACKET: {
+ const unsigned int plen = dmsg.at<uint16_t>(ptr); ptr += 2;
+ if (plen) {
+ Packet remotep(dmsg.field(ptr,plen),plen); ptr += plen;
+ //TRACE("remote %s from %s via %u (%u bytes)",Packet::verbString(remotep.verb()),remotep.source().toString().c_str(),fromMemberId,plen);
+ switch(remotep.verb()) {
+ case Packet::VERB_WHOIS: _doREMOTE_WHOIS(fromMemberId,remotep); break;
+ case Packet::VERB_MULTICAST_GATHER: _doREMOTE_MULTICAST_GATHER(fromMemberId,remotep); break;
+ default: break; // ignore things we don't care about across cluster
+ }
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_PROXY_UNITE: {
+ const Address localPeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const Address remotePeerAddress(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const unsigned int numRemotePeerPaths = dmsg[ptr++];
+ InetAddress remotePeerPaths[256]; // size is 8-bit, so 256 is max
+ for(unsigned int i=0;i<numRemotePeerPaths;++i)
+ ptr += remotePeerPaths[i].deserialize(dmsg,ptr);
+
+ TRACE("[%u] requested that we unite local %s with remote %s",(unsigned int)fromMemberId,localPeerAddress.toString().c_str(),remotePeerAddress.toString().c_str());
+
+ const uint64_t now = RR->node->now();
+ SharedPtr<Peer> localPeer(RR->topology->getPeerNoCache(localPeerAddress));
+ if ((localPeer)&&(numRemotePeerPaths > 0)) {
+ InetAddress bestLocalV4,bestLocalV6;
+ localPeer->getBestActiveAddresses(now,bestLocalV4,bestLocalV6);
+
+ InetAddress bestRemoteV4,bestRemoteV6;
+ for(unsigned int i=0;i<numRemotePeerPaths;++i) {
+ if ((bestRemoteV4)&&(bestRemoteV6))
+ break;
+ switch(remotePeerPaths[i].ss_family) {
+ case AF_INET:
+ if (!bestRemoteV4)
+ bestRemoteV4 = remotePeerPaths[i];
+ break;
+ case AF_INET6:
+ if (!bestRemoteV6)
+ bestRemoteV6 = remotePeerPaths[i];
+ break;
+ }
+ }
+
+ Packet rendezvousForLocal(localPeerAddress,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ rendezvousForLocal.append((uint8_t)0);
+ remotePeerAddress.appendTo(rendezvousForLocal);
+
+ Buffer<2048> rendezvousForRemote;
+ remotePeerAddress.appendTo(rendezvousForRemote);
+ rendezvousForRemote.append((uint8_t)Packet::VERB_RENDEZVOUS);
+ rendezvousForRemote.addSize(2); // space for actual packet payload length
+ rendezvousForRemote.append((uint8_t)0); // flags == 0
+ localPeerAddress.appendTo(rendezvousForRemote);
+
+ bool haveMatch = false;
+ if ((bestLocalV6)&&(bestRemoteV6)) {
+ haveMatch = true;
+
+ rendezvousForLocal.append((uint16_t)bestRemoteV6.port());
+ rendezvousForLocal.append((uint8_t)16);
+ rendezvousForLocal.append(bestRemoteV6.rawIpData(),16);
+
+ rendezvousForRemote.append((uint16_t)bestLocalV6.port());
+ rendezvousForRemote.append((uint8_t)16);
+ rendezvousForRemote.append(bestLocalV6.rawIpData(),16);
+ rendezvousForRemote.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 16));
+ } else if ((bestLocalV4)&&(bestRemoteV4)) {
+ haveMatch = true;
+
+ rendezvousForLocal.append((uint16_t)bestRemoteV4.port());
+ rendezvousForLocal.append((uint8_t)4);
+ rendezvousForLocal.append(bestRemoteV4.rawIpData(),4);
+
+ rendezvousForRemote.append((uint16_t)bestLocalV4.port());
+ rendezvousForRemote.append((uint8_t)4);
+ rendezvousForRemote.append(bestLocalV4.rawIpData(),4);
+ rendezvousForRemote.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(9 + 4));
+ }
+
+ if (haveMatch) {
+ {
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,rendezvousForRemote.data(),rendezvousForRemote.size());
+ }
+ RR->sw->send(rendezvousForLocal,true,0);
+ }
+ }
+ } break;
+
+ case CLUSTER_MESSAGE_PROXY_SEND: {
+ const Address rcpt(dmsg.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH;
+ const Packet::Verb verb = (Packet::Verb)dmsg[ptr++];
+ const unsigned int len = dmsg.at<uint16_t>(ptr); ptr += 2;
+ Packet outp(rcpt,RR->identity.address(),verb);
+ outp.append(dmsg.field(ptr,len),len); ptr += len;
+ RR->sw->send(outp,true,0);
+ //TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len);
+ } break;
+ }
+ } catch ( ... ) {
+ TRACE("invalid message of size %u type %d (inner decode), discarding",mlen,mtype);
+ // drop invalids
+ }
+
+ ptr = nextPtr;
+ }
+ } catch ( ... ) {
+ TRACE("invalid message (outer loop), discarding");
+ // drop invalids
+ }
+}
+
+void Cluster::broadcastHavePeer(const Identity &id)
+{
+ Buffer<1024> buf;
+ id.serialize(buf);
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_HAVE_PEER,buf.data(),buf.size());
+ }
+}
+
+void Cluster::sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite)
+{
+ if (len > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check
+ return;
+
+ const uint64_t now = RR->node->now();
+
+ uint64_t mostRecentTs = 0;
+ unsigned int mostRecentMemberId = 0xffffffff;
+ {
+ Mutex::Lock _l2(_remotePeers_m);
+ std::map< std::pair<Address,unsigned int>,uint64_t >::const_iterator rpe(_remotePeers.lower_bound(std::pair<Address,unsigned int>(toPeerAddress,0)));
+ for(;;) {
+ if ((rpe == _remotePeers.end())||(rpe->first.first != toPeerAddress))
+ break;
+ else if (rpe->second > mostRecentTs) {
+ mostRecentTs = rpe->second;
+ mostRecentMemberId = rpe->first.second;
+ }
+ ++rpe;
+ }
+ }
+
+ const uint64_t age = now - mostRecentTs;
+ if (age >= (ZT_PEER_ACTIVITY_TIMEOUT / 3)) {
+ const bool enqueueAndWait = ((age >= ZT_PEER_ACTIVITY_TIMEOUT)||(mostRecentMemberId > 0xffff));
+
+ // Poll everyone with WANT_PEER if the age of our most recent entry is
+ // approaching expiration (or has expired, or does not exist).
+ char tmp[ZT_ADDRESS_LENGTH];
+ toPeerAddress.copyTo(tmp,ZT_ADDRESS_LENGTH);
+ {
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_WANT_PEER,tmp,ZT_ADDRESS_LENGTH);
+ }
+ }
+
+ // If there isn't a good place to send via, then enqueue this for retrying
+ // later and return after having broadcasted a WANT_PEER.
+ if (enqueueAndWait) {
+ TRACE("sendViaCluster %s -> %s enqueueing to wait for HAVE_PEER",fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str());
+ _sendQueue->enqueue(now,fromPeerAddress,toPeerAddress,data,len,unite);
+ return;
+ }
+ }
+
+ Buffer<1024> buf;
+ if (unite) {
+ InetAddress v4,v6;
+ if (fromPeerAddress) {
+ SharedPtr<Peer> fromPeer(RR->topology->getPeerNoCache(fromPeerAddress));
+ if (fromPeer)
+ fromPeer->getBestActiveAddresses(now,v4,v6);
+ }
+ uint8_t addrCount = 0;
+ if (v4)
+ ++addrCount;
+ if (v6)
+ ++addrCount;
+ if (addrCount) {
+ toPeerAddress.appendTo(buf);
+ fromPeerAddress.appendTo(buf);
+ buf.append(addrCount);
+ if (v4)
+ v4.serialize(buf);
+ if (v6)
+ v6.serialize(buf);
+ }
+ }
+
+ {
+ Mutex::Lock _l2(_members[mostRecentMemberId].lock);
+ if (buf.size() > 0)
+ _send(mostRecentMemberId,CLUSTER_MESSAGE_PROXY_UNITE,buf.data(),buf.size());
+
+ for(std::vector<InetAddress>::const_iterator i1(_zeroTierPhysicalEndpoints.begin());i1!=_zeroTierPhysicalEndpoints.end();++i1) {
+ for(std::vector<InetAddress>::const_iterator i2(_members[mostRecentMemberId].zeroTierPhysicalEndpoints.begin());i2!=_members[mostRecentMemberId].zeroTierPhysicalEndpoints.end();++i2) {
+ if (i1->ss_family == i2->ss_family) {
+ TRACE("sendViaCluster relaying %u bytes from %s to %s by way of %u (%s->%s)",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId,i1->toString().c_str(),i2->toString().c_str());
+ RR->node->putPacket(*i1,*i2,data,len);
+ return;
+ }
+ }
+ }
+
+ TRACE("sendViaCluster relaying %u bytes from %s to %s by way of %u failed: no common endpoints with the same address family!",len,fromPeerAddress.toString().c_str(),toPeerAddress.toString().c_str(),(unsigned int)mostRecentMemberId);
+ return;
+ }
+}
+
+void Cluster::sendDistributedQuery(const Packet &pkt)
+{
+ Buffer<4096> buf;
+ buf.append((uint16_t)pkt.size());
+ buf.append(pkt.data(),pkt.size());
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+ _send(*mid,CLUSTER_MESSAGE_REMOTE_PACKET,buf.data(),buf.size());
+ }
+}
+
+void Cluster::doPeriodicTasks()
+{
+ const uint64_t now = RR->node->now();
+
+ if ((now - _lastFlushed) >= ZT_CLUSTER_FLUSH_PERIOD) {
+ _lastFlushed = now;
+
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ Mutex::Lock _l2(_members[*mid].lock);
+
+ if ((now - _members[*mid].lastAnnouncedAliveTo) >= ((ZT_CLUSTER_TIMEOUT / 2) - 1000)) {
+ _members[*mid].lastAnnouncedAliveTo = now;
+
+ Buffer<2048> alive;
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_MAJOR);
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_MINOR);
+ alive.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ alive.append((uint8_t)ZT_PROTO_VERSION);
+ if (_addressToLocationFunction) {
+ alive.append((int32_t)_x);
+ alive.append((int32_t)_y);
+ alive.append((int32_t)_z);
+ } else {
+ alive.append((int32_t)0);
+ alive.append((int32_t)0);
+ alive.append((int32_t)0);
+ }
+ alive.append((uint64_t)now);
+ alive.append((uint64_t)0); // TODO: compute and send load average
+ alive.append((uint64_t)RR->topology->countActive(now));
+ alive.append((uint64_t)0); // unused/reserved flags
+ alive.append((uint8_t)_zeroTierPhysicalEndpoints.size());
+ for(std::vector<InetAddress>::const_iterator pe(_zeroTierPhysicalEndpoints.begin());pe!=_zeroTierPhysicalEndpoints.end();++pe)
+ pe->serialize(alive);
+ _send(*mid,CLUSTER_MESSAGE_ALIVE,alive.data(),alive.size());
+ }
+
+ _flush(*mid);
+ }
+ }
+
+ if ((now - _lastCleanedRemotePeers) >= (ZT_PEER_ACTIVITY_TIMEOUT * 2)) {
+ _lastCleanedRemotePeers = now;
+
+ Mutex::Lock _l(_remotePeers_m);
+ for(std::map< std::pair<Address,unsigned int>,uint64_t >::iterator rp(_remotePeers.begin());rp!=_remotePeers.end();) {
+ if ((now - rp->second) >= ZT_PEER_ACTIVITY_TIMEOUT)
+ _remotePeers.erase(rp++);
+ else ++rp;
+ }
+ }
+
+ if ((now - _lastCleanedQueue) >= ZT_CLUSTER_QUEUE_EXPIRATION) {
+ _lastCleanedQueue = now;
+ _sendQueue->expire(now);
+ }
+}
+
+void Cluster::addMember(uint16_t memberId)
+{
+ if ((memberId >= ZT_CLUSTER_MAX_MEMBERS)||(memberId == _id))
+ return;
+
+ Mutex::Lock _l2(_members[memberId].lock);
+
+ {
+ Mutex::Lock _l(_memberIds_m);
+ if (std::find(_memberIds.begin(),_memberIds.end(),memberId) != _memberIds.end())
+ return;
+ _memberIds.push_back(memberId);
+ std::sort(_memberIds.begin(),_memberIds.end());
+ }
+
+ _members[memberId].clear();
+
+ // Generate this member's message key from the master and its ID
+ uint16_t stmp[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+ memcpy(stmp,_masterSecret,sizeof(stmp));
+ stmp[0] ^= Utils::hton(memberId);
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ SHA512::hash(stmp,stmp,sizeof(stmp));
+ memcpy(_members[memberId].key,stmp,sizeof(_members[memberId].key));
+ Utils::burn(stmp,sizeof(stmp));
+
+ // Prepare q
+ _members[memberId].q.clear();
+ char iv[16];
+ Utils::getSecureRandom(iv,16);
+ _members[memberId].q.append(iv,16);
+ _members[memberId].q.addSize(8); // room for MAC
+ _members[memberId].q.append((uint16_t)_id);
+ _members[memberId].q.append((uint16_t)memberId);
+}
+
+void Cluster::removeMember(uint16_t memberId)
+{
+ Mutex::Lock _l(_memberIds_m);
+ std::vector<uint16_t> newMemberIds;
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ if (*mid != memberId)
+ newMemberIds.push_back(*mid);
+ }
+ _memberIds = newMemberIds;
+}
+
+bool Cluster::findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload)
+{
+ if (_addressToLocationFunction) {
+ // Pick based on location if it can be determined
+ int px = 0,py = 0,pz = 0;
+ if (_addressToLocationFunction(_addressToLocationFunctionArg,reinterpret_cast<const struct sockaddr_storage *>(&peerPhysicalAddress),&px,&py,&pz) == 0) {
+ TRACE("no geolocation data for %s",peerPhysicalAddress.toIpString().c_str());
+ return false;
+ }
+
+ // Find member closest to this peer
+ const uint64_t now = RR->node->now();
+ std::vector<InetAddress> best;
+ const double currentDistance = _dist3d(_x,_y,_z,px,py,pz);
+ double bestDistance = (offload ? 2147483648.0 : currentDistance);
+ unsigned int bestMember = _id;
+ {
+ Mutex::Lock _l(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ _Member &m = _members[*mid];
+ Mutex::Lock _ml(m.lock);
+
+ // Consider member if it's alive and has sent us a location and one or more physical endpoints to send peers to
+ if ( ((now - m.lastReceivedAliveAnnouncement) < ZT_CLUSTER_TIMEOUT) && ((m.x != 0)||(m.y != 0)||(m.z != 0)) && (m.zeroTierPhysicalEndpoints.size() > 0) ) {
+ const double mdist = _dist3d(m.x,m.y,m.z,px,py,pz);
+ if (mdist < bestDistance) {
+ bestDistance = mdist;
+ bestMember = *mid;
+ best = m.zeroTierPhysicalEndpoints;
+ }
+ }
+ }
+ }
+
+ // Redirect to a closer member if it has a ZeroTier endpoint address in the same ss_family
+ for(std::vector<InetAddress>::const_iterator a(best.begin());a!=best.end();++a) {
+ if (a->ss_family == peerPhysicalAddress.ss_family) {
+ TRACE("%s at [%d,%d,%d] is %f from us but %f from %u, can redirect to %s",peerAddress.toString().c_str(),px,py,pz,currentDistance,bestDistance,bestMember,a->toString().c_str());
+ redirectTo = *a;
+ return true;
+ }
+ }
+ TRACE("%s at [%d,%d,%d] is %f from us, no better endpoints found",peerAddress.toString().c_str(),px,py,pz,currentDistance);
+ return false;
+ } else {
+ // TODO: pick based on load if no location info?
+ return false;
+ }
+}
+
+void Cluster::status(ZT_ClusterStatus &status) const
+{
+ const uint64_t now = RR->node->now();
+ memset(&status,0,sizeof(ZT_ClusterStatus));
+
+ status.myId = _id;
+
+ {
+ ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]);
+ s->id = _id;
+ s->alive = 1;
+ s->x = _x;
+ s->y = _y;
+ s->z = _z;
+ s->load = 0; // TODO
+ s->peers = RR->topology->countActive(now);
+ for(std::vector<InetAddress>::const_iterator ep(_zeroTierPhysicalEndpoints.begin());ep!=_zeroTierPhysicalEndpoints.end();++ep) {
+ if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check
+ break;
+ memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage));
+ }
+ }
+
+ {
+ Mutex::Lock _l1(_memberIds_m);
+ for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+ if (status.clusterSize >= ZT_CLUSTER_MAX_MEMBERS) // sanity check
+ break;
+
+ _Member &m = _members[*mid];
+ Mutex::Lock ml(m.lock);
+
+ ZT_ClusterMemberStatus *const s = &(status.members[status.clusterSize++]);
+ s->id = *mid;
+ s->msSinceLastHeartbeat = (unsigned int)std::min((uint64_t)(~((unsigned int)0)),(now - m.lastReceivedAliveAnnouncement));
+ s->alive = (s->msSinceLastHeartbeat < ZT_CLUSTER_TIMEOUT) ? 1 : 0;
+ s->x = m.x;
+ s->y = m.y;
+ s->z = m.z;
+ s->load = m.load;
+ s->peers = m.peers;
+ for(std::vector<InetAddress>::const_iterator ep(m.zeroTierPhysicalEndpoints.begin());ep!=m.zeroTierPhysicalEndpoints.end();++ep) {
+ if (s->numZeroTierPhysicalEndpoints >= ZT_CLUSTER_MAX_ZT_PHYSICAL_ADDRESSES) // sanity check
+ break;
+ memcpy(&(s->zeroTierPhysicalEndpoints[s->numZeroTierPhysicalEndpoints++]),&(*ep),sizeof(struct sockaddr_storage));
+ }
+ }
+ }
+}
+
+void Cluster::_send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len)
+{
+ if ((len + 3) > (ZT_CLUSTER_MAX_MESSAGE_LENGTH - (24 + 2 + 2))) // sanity check
+ return;
+ _Member &m = _members[memberId];
+ // assumes m.lock is locked!
+ if ((m.q.size() + len + 3) > ZT_CLUSTER_MAX_MESSAGE_LENGTH)
+ _flush(memberId);
+ m.q.append((uint16_t)(len + 1));
+ m.q.append((uint8_t)type);
+ m.q.append(msg,len);
+}
+
+void Cluster::_flush(uint16_t memberId)
+{
+ _Member &m = _members[memberId];
+ // assumes m.lock is locked!
+ if (m.q.size() > (24 + 2 + 2)) { // 16-byte IV + 8-byte MAC + 2 byte from-member-ID + 2 byte to-member-ID
+ // Create key from member's key and IV
+ char keytmp[32];
+ memcpy(keytmp,m.key,32);
+ for(int i=0;i<8;++i)
+ keytmp[i] ^= m.q[i];
+ Salsa20 s20(keytmp,256,m.q.field(8,8));
+ Utils::burn(keytmp,sizeof(keytmp));
+
+ // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
+ char polykey[ZT_POLY1305_KEY_LEN];
+ memset(polykey,0,sizeof(polykey));
+ s20.encrypt12(polykey,polykey,sizeof(polykey));
+
+ // Encrypt m.q in place
+ s20.encrypt12(reinterpret_cast<const char *>(m.q.data()) + 24,const_cast<char *>(reinterpret_cast<const char *>(m.q.data())) + 24,m.q.size() - 24);
+
+ // Add MAC for authentication (encrypt-then-MAC)
+ char mac[ZT_POLY1305_MAC_LEN];
+ Poly1305::compute(mac,reinterpret_cast<const char *>(m.q.data()) + 24,m.q.size() - 24,polykey);
+ memcpy(m.q.field(16,8),mac,8);
+
+ // Send!
+ _sendFunction(_sendFunctionArg,memberId,m.q.data(),m.q.size());
+
+ // Prepare for more
+ m.q.clear();
+ char iv[16];
+ Utils::getSecureRandom(iv,16);
+ m.q.append(iv,16);
+ m.q.addSize(8); // room for MAC
+ m.q.append((uint16_t)_id); // from member ID
+ m.q.append((uint16_t)memberId); // to member ID
+ }
+}
+
+void Cluster::_doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep)
+{
+ if (remotep.payloadLength() >= ZT_ADDRESS_LENGTH) {
+ Identity queried(RR->topology->getIdentity(Address(remotep.payload(),ZT_ADDRESS_LENGTH)));
+ if (queried) {
+ Buffer<1024> routp;
+ remotep.source().appendTo(routp);
+ routp.append((uint8_t)Packet::VERB_OK);
+ routp.addSize(2); // space for length
+ routp.append((uint8_t)Packet::VERB_WHOIS);
+ routp.append(remotep.packetId());
+ queried.serialize(routp);
+ routp.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3));
+
+ TRACE("responding to remote WHOIS from %s @ %u with identity of %s",remotep.source().toString().c_str(),(unsigned int)fromMemberId,queried.address().toString().c_str());
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size());
+ }
+ }
+}
+
+void Cluster::_doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep)
+{
+ const uint64_t nwid = remotep.at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
+ const MulticastGroup mg(MAC(remotep.field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),remotep.at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI));
+ unsigned int gatherLimit = remotep.at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT);
+ const Address remotePeerAddress(remotep.source());
+
+ if (gatherLimit) {
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH> routp;
+ remotePeerAddress.appendTo(routp);
+ routp.append((uint8_t)Packet::VERB_OK);
+ routp.addSize(2); // space for length
+ routp.append((uint8_t)Packet::VERB_MULTICAST_GATHER);
+ routp.append(remotep.packetId());
+ routp.append(nwid);
+ mg.mac().appendTo(routp);
+ routp.append((uint32_t)mg.adi());
+
+ if (gatherLimit > ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5))
+ gatherLimit = ((ZT_CLUSTER_MAX_MESSAGE_LENGTH - 80) / 5);
+ if (RR->mc->gather(remotePeerAddress,nwid,mg,routp,gatherLimit)) {
+ routp.setAt<uint16_t>(ZT_ADDRESS_LENGTH + 1,(uint16_t)(routp.size() - ZT_ADDRESS_LENGTH - 3));
+
+ TRACE("responding to remote MULTICAST_GATHER from %s @ %u with %u bytes",remotePeerAddress.toString().c_str(),(unsigned int)fromMemberId,routp.size());
+ Mutex::Lock _l2(_members[fromMemberId].lock);
+ _send(fromMemberId,CLUSTER_MESSAGE_PROXY_SEND,routp.data(),routp.size());
+ }
+ }
+}
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
diff --git a/zerotierone/node/Cluster.hpp b/zerotierone/node/Cluster.hpp
new file mode 100644
index 0000000..dafbf42
--- /dev/null
+++ b/zerotierone/node/Cluster.hpp
@@ -0,0 +1,406 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_CLUSTER_HPP
+#define ZT_CLUSTER_HPP
+
+#ifdef ZT_ENABLE_CLUSTER
+
+#include <map>
+
+#include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
+#include "Address.hpp"
+#include "InetAddress.hpp"
+#include "SHA512.hpp"
+#include "Utils.hpp"
+#include "Buffer.hpp"
+#include "Mutex.hpp"
+#include "SharedPtr.hpp"
+#include "Hashtable.hpp"
+#include "Packet.hpp"
+#include "SharedPtr.hpp"
+
+/**
+ * Timeout for cluster members being considered "alive"
+ *
+ * A cluster member is considered dead and will no longer have peers
+ * redirected to it if we have not heard a heartbeat in this long.
+ */
+#define ZT_CLUSTER_TIMEOUT 5000
+
+/**
+ * Desired period between doPeriodicTasks() in milliseconds
+ */
+#define ZT_CLUSTER_PERIODIC_TASK_PERIOD 20
+
+/**
+ * How often to flush outgoing message queues (maximum interval)
+ */
+#define ZT_CLUSTER_FLUSH_PERIOD ZT_CLUSTER_PERIODIC_TASK_PERIOD
+
+/**
+ * Maximum number of queued outgoing packets per sender address
+ */
+#define ZT_CLUSTER_MAX_QUEUE_PER_SENDER 16
+
+/**
+ * Expiration time for send queue entries
+ */
+#define ZT_CLUSTER_QUEUE_EXPIRATION 3000
+
+/**
+ * Chunk size for allocating queue entries
+ *
+ * Queue entries are allocated in chunks of this many and are added to a pool.
+ * ZT_CLUSTER_MAX_QUEUE_GLOBAL must be evenly divisible by this.
+ */
+#define ZT_CLUSTER_QUEUE_CHUNK_SIZE 32
+
+/**
+ * Maximum number of chunks to ever allocate
+ *
+ * This is a global sanity limit to prevent resource exhaustion attacks. It
+ * works out to about 600mb of RAM. You'll never see this on a normal edge
+ * node. We're unlikely to see this on a root server unless someone is DOSing
+ * us. In that case cluster relaying will be affected but other functions
+ * should continue to operate normally.
+ */
+#define ZT_CLUSTER_MAX_QUEUE_CHUNKS 8194
+
+/**
+ * Max data per queue entry
+ */
+#define ZT_CLUSTER_SEND_QUEUE_DATA_MAX 1500
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class MulticastGroup;
+class Peer;
+class Identity;
+
+// Internal class implemented inside Cluster.cpp
+class _ClusterSendQueue;
+
+/**
+ * Multi-homing cluster state replication and packet relaying
+ *
+ * Multi-homing means more than one node sharing the same ZeroTier identity.
+ * There is nothing in the protocol to prevent this, but to make it work well
+ * requires the devices sharing an identity to cooperate and share some
+ * information.
+ *
+ * There are three use cases we want to fulfill:
+ *
+ * (1) Multi-homing of root servers with handoff for efficient routing,
+ * HA, and load balancing across many commodity nodes.
+ * (2) Multi-homing of network controllers for the same reason.
+ * (3) Multi-homing of nodes on virtual networks, such as domain servers
+ * and other important endpoints.
+ *
+ * These use cases are in order of escalating difficulty. The initial
+ * version of Cluster is aimed at satisfying the first, though you are
+ * free to try #2 and #3.
+ */
+class Cluster
+{
+public:
+ /**
+ * State message types
+ */
+ enum StateMessageType
+ {
+ CLUSTER_MESSAGE_NOP = 0,
+
+ /**
+ * This cluster member is alive:
+ * <[2] version minor>
+ * <[2] version major>
+ * <[2] version revision>
+ * <[1] protocol version>
+ * <[4] X location (signed 32-bit)>
+ * <[4] Y location (signed 32-bit)>
+ * <[4] Z location (signed 32-bit)>
+ * <[8] local clock at this member>
+ * <[8] load average>
+ * <[8] number of peers>
+ * <[8] flags (currently unused, must be zero)>
+ * <[1] number of preferred ZeroTier endpoints>
+ * <[...] InetAddress(es) of preferred ZeroTier endpoint(s)>
+ *
+ * Cluster members constantly broadcast an alive heartbeat and will only
+ * receive peer redirects if they've done so within the timeout.
+ */
+ CLUSTER_MESSAGE_ALIVE = 1,
+
+ /**
+ * Cluster member has this peer:
+ * <[...] serialized identity of peer>
+ *
+ * This is typically sent in response to WANT_PEER but can also be pushed
+ * to prepopulate if this makes sense.
+ */
+ CLUSTER_MESSAGE_HAVE_PEER = 2,
+
+ /**
+ * Cluster member wants this peer:
+ * <[5] ZeroTier address of peer>
+ *
+ * Members that have a direct link to this peer will respond with
+ * HAVE_PEER.
+ */
+ CLUSTER_MESSAGE_WANT_PEER = 3,
+
+ /**
+ * A remote packet that we should also possibly respond to:
+ * <[2] 16-bit length of remote packet>
+ * <[...] remote packet payload>
+ *
+ * Cluster members may relay requests by relaying the request packet.
+ * These may include requests such as WHOIS and MULTICAST_GATHER. The
+ * packet must be already decrypted, decompressed, and authenticated.
+ *
+ * This can only be used for small request packets as per the cluster
+ * message size limit, but since these are the only ones in question
+ * this is fine.
+ *
+ * If a response is generated it is sent via PROXY_SEND.
+ */
+ CLUSTER_MESSAGE_REMOTE_PACKET = 4,
+
+ /**
+ * Request that VERB_RENDEZVOUS be sent to a peer that we have:
+ * <[5] ZeroTier address of peer on recipient's side>
+ * <[5] ZeroTier address of peer on sender's side>
+ * <[1] 8-bit number of sender's peer's active path addresses>
+ * <[...] series of serialized InetAddresses of sender's peer's paths>
+ *
+ * This requests that we perform NAT-t introduction between a peer that
+ * we have and one on the sender's side. The sender furnishes contact
+ * info for its peer, and we send VERB_RENDEZVOUS to both sides: to ours
+ * directly and with PROXY_SEND to theirs.
+ */
+ CLUSTER_MESSAGE_PROXY_UNITE = 5,
+
+ /**
+ * Request that a cluster member send a packet to a locally-known peer:
+ * <[5] ZeroTier address of recipient>
+ * <[1] packet verb>
+ * <[2] length of packet payload>
+ * <[...] packet payload>
+ *
+ * This differs from RELAY in that it requests the receiving cluster
+ * member to actually compose a ZeroTier Packet from itself to the
+ * provided recipient. RELAY simply says "please forward this blob."
+ * RELAY is used to implement peer-to-peer relaying with RENDEZVOUS,
+ * while PROXY_SEND is used to implement proxy sending (which right
+ * now is only used to send RENDEZVOUS).
+ */
+ CLUSTER_MESSAGE_PROXY_SEND = 6,
+
+ /**
+ * Replicate a network config for a network we belong to:
+ * <[8] 64-bit network ID>
+ * <[2] 16-bit length of network config>
+ * <[...] serialized network config>
+ *
+ * This is used by clusters to avoid every member having to query
+ * for the same netconf for networks all members belong to.
+ *
+ * TODO: not implemented yet!
+ */
+ CLUSTER_MESSAGE_NETWORK_CONFIG = 7
+ };
+
+ /**
+ * Construct a new cluster
+ */
+ Cluster(
+ const RuntimeEnvironment *renv,
+ uint16_t id,
+ const std::vector<InetAddress> &zeroTierPhysicalEndpoints,
+ int32_t x,
+ int32_t y,
+ int32_t z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg);
+
+ ~Cluster();
+
+ /**
+ * @return This cluster member's ID
+ */
+ inline uint16_t id() const throw() { return _id; }
+
+ /**
+ * Handle an incoming intra-cluster message
+ *
+ * @param data Message data
+ * @param len Message length (max: ZT_CLUSTER_MAX_MESSAGE_LENGTH)
+ */
+ void handleIncomingStateMessage(const void *msg,unsigned int len);
+
+ /**
+ * Broadcast that we have a given peer
+ *
+ * This should be done when new peers are first contacted.
+ *
+ * @param id Identity of peer
+ */
+ void broadcastHavePeer(const Identity &id);
+
+ /**
+ * Send this packet via another node in this cluster if another node has this peer
+ *
+ * This is used in the outgoing packet and relaying logic in Switch to
+ * relay packets to other cluster members. It isn't PROXY_SEND-- that is
+ * used internally in Cluster to send responses to peer queries.
+ *
+ * @param fromPeerAddress Source peer address (if known, should be NULL for fragments)
+ * @param toPeerAddress Destination peer address
+ * @param data Packet or packet fragment data
+ * @param len Length of packet or fragment
+ * @param unite If true, also request proxy unite across cluster
+ */
+ void sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite);
+
+ /**
+ * Send a distributed query to other cluster members
+ *
+ * Some queries such as WHOIS or MULTICAST_GATHER need a response from other
+ * cluster members. Replies (if any) will be sent back to the peer via
+ * PROXY_SEND across the cluster.
+ *
+ * @param pkt Packet to distribute
+ */
+ void sendDistributedQuery(const Packet &pkt);
+
+ /**
+ * Call every ~ZT_CLUSTER_PERIODIC_TASK_PERIOD milliseconds.
+ */
+ void doPeriodicTasks();
+
+ /**
+ * Add a member ID to this cluster
+ *
+ * @param memberId Member ID
+ */
+ void addMember(uint16_t memberId);
+
+ /**
+ * Remove a member ID from this cluster
+ *
+ * @param memberId Member ID to remove
+ */
+ void removeMember(uint16_t memberId);
+
+ /**
+ * Find a better cluster endpoint for this peer (if any)
+ *
+ * @param redirectTo InetAddress to be set to a better endpoint (if there is one)
+ * @param peerAddress Address of peer to (possibly) redirect
+ * @param peerPhysicalAddress Physical address of peer's current best path (where packet was most recently received or getBestPath()->address())
+ * @param offload Always redirect if possible -- can be used to offload peers during shutdown
+ * @return True if redirectTo was set to a new address, false if redirectTo was not modified
+ */
+ bool findBetterEndpoint(InetAddress &redirectTo,const Address &peerAddress,const InetAddress &peerPhysicalAddress,bool offload);
+
+ /**
+ * Fill out ZT_ClusterStatus structure (from core API)
+ *
+ * @param status Reference to structure to hold result (anything there is replaced)
+ */
+ void status(ZT_ClusterStatus &status) const;
+
+private:
+ void _send(uint16_t memberId,StateMessageType type,const void *msg,unsigned int len);
+ void _flush(uint16_t memberId);
+
+ void _doREMOTE_WHOIS(uint64_t fromMemberId,const Packet &remotep);
+ void _doREMOTE_MULTICAST_GATHER(uint64_t fromMemberId,const Packet &remotep);
+
+ // These are initialized in the constructor and remain immutable ------------
+ uint16_t _masterSecret[ZT_SHA512_DIGEST_LEN / sizeof(uint16_t)];
+ unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
+ const RuntimeEnvironment *RR;
+ _ClusterSendQueue *const _sendQueue;
+ void (*_sendFunction)(void *,unsigned int,const void *,unsigned int);
+ void *_sendFunctionArg;
+ int (*_addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *);
+ void *_addressToLocationFunctionArg;
+ const int32_t _x;
+ const int32_t _y;
+ const int32_t _z;
+ const uint16_t _id;
+ const std::vector<InetAddress> _zeroTierPhysicalEndpoints;
+ // end immutable fields -----------------------------------------------------
+
+ struct _Member
+ {
+ unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
+
+ uint64_t lastReceivedAliveAnnouncement;
+ uint64_t lastAnnouncedAliveTo;
+
+ uint64_t load;
+ uint64_t peers;
+ int32_t x,y,z;
+
+ std::vector<InetAddress> zeroTierPhysicalEndpoints;
+
+ Buffer<ZT_CLUSTER_MAX_MESSAGE_LENGTH> q;
+
+ Mutex lock;
+
+ inline void clear()
+ {
+ lastReceivedAliveAnnouncement = 0;
+ lastAnnouncedAliveTo = 0;
+ load = 0;
+ peers = 0;
+ x = 0;
+ y = 0;
+ z = 0;
+ zeroTierPhysicalEndpoints.clear();
+ q.clear();
+ }
+
+ _Member() { this->clear(); }
+ ~_Member() { Utils::burn(key,sizeof(key)); }
+ };
+ _Member *const _members;
+
+ std::vector<uint16_t> _memberIds;
+ Mutex _memberIds_m;
+
+ std::map< std::pair<Address,unsigned int>,uint64_t > _remotePeers; // we need ordered behavior and lower_bound here
+ Mutex _remotePeers_m;
+
+ uint64_t _lastFlushed;
+ uint64_t _lastCleanedRemotePeers;
+ uint64_t _lastCleanedQueue;
+};
+
+} // namespace ZeroTier
+
+#endif // ZT_ENABLE_CLUSTER
+
+#endif
diff --git a/zerotierone/node/Constants.hpp b/zerotierone/node/Constants.hpp
new file mode 100644
index 0000000..dc36b3a
--- /dev/null
+++ b/zerotierone/node/Constants.hpp
@@ -0,0 +1,396 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_CONSTANTS_HPP
+#define ZT_CONSTANTS_HPP
+
+#include "../include/ZeroTierOne.h"
+
+//
+// This include file also auto-detects and canonicalizes some environment
+// information defines:
+//
+// __LINUX__
+// __APPLE__
+// __BSD__ (OSX also defines this)
+// __UNIX_LIKE__ (Linux, BSD, etc.)
+// __WINDOWS__
+//
+// Also makes sure __BYTE_ORDER is defined reasonably.
+//
+
+// Hack: make sure __GCC__ is defined on old GCC compilers
+#ifndef __GCC__
+#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+#define __GCC__
+#endif
+#endif
+
+#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
+#ifndef __LINUX__
+#define __LINUX__
+#endif
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#include <endian.h>
+#endif
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#ifndef __BSD__
+#define __BSD__
+#endif
+#include <machine/endian.h>
+#endif
+
+// Defined this macro to disable "type punning" on a number of targets that
+// have issues with unaligned memory access.
+#if defined(__arm__) || defined(__ARMEL__) || (defined(__APPLE__) && ( (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0)) || (defined(TARGET_OS_WATCH) && (TARGET_OS_WATCH != 0)) || (defined(TARGET_IPHONE_SIMULATOR) && (TARGET_IPHONE_SIMULATOR != 0)) ) )
+#ifndef ZT_NO_TYPE_PUNNING
+#define ZT_NO_TYPE_PUNNING
+#endif
+#endif
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#ifndef __UNIX_LIKE__
+#define __UNIX_LIKE__
+#endif
+#ifndef __BSD__
+#define __BSD__
+#endif
+#include <machine/endian.h>
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER _BYTE_ORDER
+#define __LITTLE_ENDIAN _LITTLE_ENDIAN
+#define __BIG_ENDIAN _BIG_ENDIAN
+#endif
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef __WINDOWS__
+#define __WINDOWS__
+#endif
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#pragma warning(disable : 4290)
+#pragma warning(disable : 4996)
+#pragma warning(disable : 4101)
+#undef __UNIX_LIKE__
+#undef __BSD__
+#define ZT_PATH_SEPARATOR '\\'
+#define ZT_PATH_SEPARATOR_S "\\"
+#define ZT_EOL_S "\r\n"
+#include <WinSock2.h>
+#include <Windows.h>
+#endif
+
+// Assume little endian if not defined
+#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
+#undef __BYTE_ORDER
+#undef __LITTLE_ENDIAN
+#undef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#define __BYTE_ORDER 1234
+#endif
+
+#ifdef __UNIX_LIKE__
+#define ZT_PATH_SEPARATOR '/'
+#define ZT_PATH_SEPARATOR_S "/"
+#define ZT_EOL_S "\n"
+#endif
+
+#ifndef __BYTE_ORDER
+#include <endian.h>
+#endif
+
+/**
+ * Length of a ZeroTier address in bytes
+ */
+#define ZT_ADDRESS_LENGTH 5
+
+/**
+ * Length of a hexadecimal ZeroTier address
+ */
+#define ZT_ADDRESS_LENGTH_HEX 10
+
+/**
+ * Addresses beginning with this byte are reserved for the joy of in-band signaling
+ */
+#define ZT_ADDRESS_RESERVED_PREFIX 0xff
+
+/**
+ * Default payload MTU for UDP packets
+ *
+ * In the future we might support UDP path MTU discovery, but for now we
+ * set a maximum that is equal to 1500 minus 8 (for PPPoE overhead, common
+ * in some markets) minus 48 (IPv6 UDP overhead).
+ */
+#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444
+
+/**
+ * Default MTU used for Ethernet tap device
+ */
+#define ZT_IF_MTU ZT_MAX_MTU
+
+/**
+ * Maximum number of packet fragments we'll support
+ *
+ * The actual spec allows 16, but this is the most we'll support right
+ * now. Packets with more than this many fragments are dropped.
+ */
+#define ZT_MAX_PACKET_FRAGMENTS 4
+
+/**
+ * Size of RX queue
+ *
+ * This is about 2mb, and can be decreased for small devices. A queue smaller
+ * than about 4 is probably going to cause a lot of lost packets.
+ */
+#define ZT_RX_QUEUE_SIZE 64
+
+/**
+ * RX queue entries older than this do not "exist"
+ */
+#define ZT_RX_QUEUE_EXPIRE 4000
+
+/**
+ * Length of secret key in bytes -- 256-bit -- do not change
+ */
+#define ZT_PEER_SECRET_KEY_LENGTH 32
+
+/**
+ * How often Topology::clean() and Network::clean() and similar are called, in ms
+ */
+#define ZT_HOUSEKEEPING_PERIOD 120000
+
+/**
+ * Overriding granularity for timer tasks to prevent CPU-intensive thrashing on every packet
+ */
+#define ZT_CORE_TIMER_TASK_GRANULARITY 500
+
+/**
+ * How long to remember peer records in RAM if they haven't been used
+ */
+#define ZT_PEER_IN_MEMORY_EXPIRATION 600000
+
+/**
+ * Delay between WHOIS retries in ms
+ */
+#define ZT_WHOIS_RETRY_DELAY 1000
+
+/**
+ * Maximum identity WHOIS retries (each attempt tries consulting a different peer)
+ */
+#define ZT_MAX_WHOIS_RETRIES 3
+
+/**
+ * Transmit queue entry timeout
+ */
+#define ZT_TRANSMIT_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1))
+
+/**
+ * Receive queue entry timeout
+ */
+#define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1))
+
+/**
+ * Maximum number of ZT hops allowed (this is not IP hops/TTL)
+ *
+ * The protocol allows up to 7, but we limit it to something smaller.
+ */
+#define ZT_RELAY_MAX_HOPS 3
+
+/**
+ * Expire time for multicast 'likes' and indirect multicast memberships in ms
+ */
+#define ZT_MULTICAST_LIKE_EXPIRE 600000
+
+/**
+ * Delay between explicit MULTICAST_GATHER requests for a given multicast channel
+ */
+#define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10)
+
+/**
+ * Timeout for outgoing multicasts
+ *
+ * This is how long we wait for explicit or implicit gather results.
+ */
+#define ZT_MULTICAST_TRANSMIT_TIMEOUT 5000
+
+/**
+ * Default maximum number of peers to address with a single multicast (if unspecified in network config)
+ */
+#define ZT_MULTICAST_DEFAULT_LIMIT 32
+
+/**
+ * How frequently to send a zero-byte UDP keepalive packet
+ *
+ * There are NATs with timeouts as short as 20 seconds, so this turns out
+ * to be needed.
+ */
+#define ZT_NAT_KEEPALIVE_DELAY 19000
+
+/**
+ * Delay between scans of the topology active peer DB for peers that need ping
+ *
+ * This is also how often pings will be retried to upstream peers (relays, roots)
+ * constantly until something is heard.
+ */
+#define ZT_PING_CHECK_INVERVAL 9500
+
+/**
+ * Delay between ordinary case pings of direct links
+ */
+#define ZT_PEER_DIRECT_PING_DELAY 60000
+
+/**
+ * Timeout for overall peer activity (measured from last receive)
+ */
+#define ZT_PEER_ACTIVITY_TIMEOUT 500000
+
+/**
+ * Timeout for path activity
+ */
+#define ZT_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
+
+/**
+ * No answer timeout to trigger dead path detection
+ */
+#define ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT 2000
+
+/**
+ * Probation threshold after which a path becomes dead
+ */
+#define ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION 3
+
+/**
+ * Delay between requests for updated network autoconf information
+ *
+ * Don't lengthen this as it affects things like QoS / uptime monitoring
+ * via ZeroTier Central. This is the heartbeat, basically.
+ */
+#define ZT_NETWORK_AUTOCONF_DELAY 60000
+
+/**
+ * Minimum interval between attempts by relays to unite peers
+ *
+ * When a relay gets a packet destined for another peer, it sends both peers
+ * a RENDEZVOUS message no more than this often. This instructs the peers
+ * to attempt NAT-t and gives each the other's corresponding IP:port pair.
+ */
+#define ZT_MIN_UNITE_INTERVAL 30000
+
+/**
+ * Delay between initial direct NAT-t packet and more aggressive techniques
+ *
+ * This may also be a delay before sending the first packet if we determine
+ * that we should wait for the remote to initiate rendezvous first.
+ */
+#define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000
+
+/**
+ * How long (max) to remember network certificates of membership?
+ *
+ * This only applies to networks we don't belong to.
+ */
+#define ZT_PEER_NETWORK_COM_EXPIRATION 3600000
+
+/**
+ * Sanity limit on maximum bridge routes
+ *
+ * If the number of bridge routes exceeds this, we cull routes from the
+ * bridges with the most MACs behind them until it doesn't. This is a
+ * sanity limit to prevent memory-filling DOS attacks, nothing more. No
+ * physical LAN has anywhere even close to this many nodes. Note that this
+ * does not limit the size of ZT virtual LANs, only bridge routing.
+ */
+#define ZT_MAX_BRIDGE_ROUTES 67108864
+
+/**
+ * If there is no known route, spam to up to this many active bridges
+ */
+#define ZT_MAX_BRIDGE_SPAM 16
+
+/**
+ * Interval between direct path pushes in milliseconds
+ */
+#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
+
+/**
+ * Time horizon for push direct paths cutoff
+ */
+#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000
+
+/**
+ * Maximum number of direct path pushes within cutoff time
+ *
+ * This limits response to PUSH_DIRECT_PATHS to CUTOFF_LIMIT responses
+ * per CUTOFF_TIME milliseconds per peer to prevent this from being
+ * useful for DOS amplification attacks.
+ */
+#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
+
+/**
+ * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
+ */
+#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
+
+/**
+ * Enable support for old Dictionary based network configs
+ */
+#define ZT_SUPPORT_OLD_STYLE_NETCONF 1
+
+/**
+ * A test pseudo-network-ID that can be joined
+ *
+ * Joining this network ID will result in a network with no IP addressing
+ * and default parameters. No network configuration master will be consulted
+ * and instead a static config will be used. This is used in built-in testnet
+ * scenarios and can also be used for external testing.
+ *
+ * This is an impossible real network ID since 0xff is a reserved address
+ * prefix.
+ */
+#define ZT_TEST_NETWORK_ID 0xffffffffffffffffULL
+
+/**
+ * Desired buffer size for UDP sockets (used in service and osdep but defined here)
+ */
+#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
+#define ZT_UDP_DESIRED_BUF_SIZE 1048576
+#else
+#define ZT_UDP_DESIRED_BUF_SIZE 131072
+#endif
+
+/* Ethernet frame types that might be relevant to us */
+#define ZT_ETHERTYPE_IPV4 0x0800
+#define ZT_ETHERTYPE_ARP 0x0806
+#define ZT_ETHERTYPE_RARP 0x8035
+#define ZT_ETHERTYPE_ATALK 0x809b
+#define ZT_ETHERTYPE_AARP 0x80f3
+#define ZT_ETHERTYPE_IPX_A 0x8137
+#define ZT_ETHERTYPE_IPX_B 0x8138
+#define ZT_ETHERTYPE_IPV6 0x86dd
+
+#endif
diff --git a/zerotierone/node/DeferredPackets.cpp b/zerotierone/node/DeferredPackets.cpp
new file mode 100644
index 0000000..192b407
--- /dev/null
+++ b/zerotierone/node/DeferredPackets.cpp
@@ -0,0 +1,100 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Constants.hpp"
+#include "DeferredPackets.hpp"
+#include "IncomingPacket.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
+
+namespace ZeroTier {
+
+DeferredPackets::DeferredPackets(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _waiting(0),
+ _die(false)
+{
+}
+
+DeferredPackets::~DeferredPackets()
+{
+ _q_m.lock();
+ _die = true;
+ _q_m.unlock();
+
+ for(;;) {
+ _q_s.post();
+
+ _q_m.lock();
+ if (_waiting <= 0) {
+ _q_m.unlock();
+ break;
+ } else {
+ _q_m.unlock();
+ }
+ }
+}
+
+bool DeferredPackets::enqueue(IncomingPacket *pkt)
+{
+ {
+ Mutex::Lock _l(_q_m);
+ if (_q.size() >= ZT_DEFFEREDPACKETS_MAX)
+ return false;
+ _q.push_back(*pkt);
+ }
+ _q_s.post();
+ return true;
+}
+
+int DeferredPackets::process()
+{
+ std::list<IncomingPacket> pkt;
+
+ _q_m.lock();
+
+ if (_die) {
+ _q_m.unlock();
+ return -1;
+ }
+
+ while (_q.empty()) {
+ ++_waiting;
+ _q_m.unlock();
+ _q_s.wait();
+ _q_m.lock();
+ --_waiting;
+ if (_die) {
+ _q_m.unlock();
+ return -1;
+ }
+ }
+
+ // Move item from _q list to a dummy list here to avoid copying packet
+ pkt.splice(pkt.end(),_q,_q.begin());
+
+ _q_m.unlock();
+
+ try {
+ pkt.front().tryDecode(RR,true);
+ } catch ( ... ) {} // drop invalids
+
+ return 1;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/DeferredPackets.hpp b/zerotierone/node/DeferredPackets.hpp
new file mode 100644
index 0000000..a985539
--- /dev/null
+++ b/zerotierone/node/DeferredPackets.hpp
@@ -0,0 +1,85 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_DEFERREDPACKETS_HPP
+#define ZT_DEFERREDPACKETS_HPP
+
+#include <list>
+
+#include "Constants.hpp"
+#include "SharedPtr.hpp"
+#include "Mutex.hpp"
+#include "DeferredPackets.hpp"
+#include "BinarySemaphore.hpp"
+
+/**
+ * Maximum number of deferred packets
+ */
+#define ZT_DEFFEREDPACKETS_MAX 256
+
+namespace ZeroTier {
+
+class IncomingPacket;
+class RuntimeEnvironment;
+
+/**
+ * Deferred packets
+ *
+ * IncomingPacket can defer its decoding this way by enqueueing itself here.
+ * When this is done, deferredDecode() is called later. This is done for
+ * operations that may be expensive to allow them to potentially be handled
+ * in the background or rate limited to maintain quality of service for more
+ * routine operations.
+ */
+class DeferredPackets
+{
+public:
+ DeferredPackets(const RuntimeEnvironment *renv);
+ ~DeferredPackets();
+
+ /**
+ * Enqueue a packet
+ *
+ * @param pkt Packet to process later (possibly in the background)
+ * @return False if queue is full
+ */
+ bool enqueue(IncomingPacket *pkt);
+
+ /**
+ * Wait for and then process a deferred packet
+ *
+ * If we are shutting down (in destructor), this returns -1 and should
+ * not be called again. Otherwise it returns the number of packets
+ * processed.
+ *
+ * @return Number processed or -1 if shutting down
+ */
+ int process();
+
+private:
+ std::list<IncomingPacket> _q;
+ const RuntimeEnvironment *const RR;
+ volatile int _waiting;
+ volatile bool _die;
+ Mutex _q_m;
+ BinarySemaphore _q_s;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Dictionary.cpp b/zerotierone/node/Dictionary.cpp
new file mode 100644
index 0000000..b334066
--- /dev/null
+++ b/zerotierone/node/Dictionary.cpp
@@ -0,0 +1,245 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Dictionary.hpp"
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+
+#include "C25519.hpp"
+#include "Identity.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+Dictionary::iterator Dictionary::find(const std::string &key)
+{
+ for(iterator i(begin());i!=end();++i) {
+ if (i->first == key)
+ return i;
+ }
+ return end();
+}
+Dictionary::const_iterator Dictionary::find(const std::string &key) const
+{
+ for(const_iterator i(begin());i!=end();++i) {
+ if (i->first == key)
+ return i;
+ }
+ return end();
+}
+
+bool Dictionary::getBoolean(const std::string &key,bool dfl) const
+{
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ if (e->second.length() < 1)
+ return dfl;
+ switch(e->second[0]) {
+ case '1':
+ case 't':
+ case 'T':
+ case 'y':
+ case 'Y':
+ return true;
+ }
+ return false;
+}
+
+std::string &Dictionary::operator[](const std::string &key)
+{
+ for(iterator i(begin());i!=end();++i) {
+ if (i->first == key)
+ return i->second;
+ }
+ push_back(std::pair<std::string,std::string>(key,std::string()));
+ std::sort(begin(),end());
+ for(iterator i(begin());i!=end();++i) {
+ if (i->first == key)
+ return i->second;
+ }
+ return front().second; // should be unreachable!
+}
+
+std::string Dictionary::toString() const
+{
+ std::string s;
+ for(const_iterator kv(begin());kv!=end();++kv) {
+ _appendEsc(kv->first.data(),(unsigned int)kv->first.length(),s);
+ s.push_back('=');
+ _appendEsc(kv->second.data(),(unsigned int)kv->second.length(),s);
+ s.append(ZT_EOL_S);
+ }
+ return s;
+}
+
+void Dictionary::updateFromString(const char *s,unsigned int maxlen)
+{
+ bool escapeState = false;
+ std::string keyBuf;
+ std::string *element = &keyBuf;
+ const char *end = s + maxlen;
+ while ((*s)&&(s < end)) {
+ if (escapeState) {
+ escapeState = false;
+ switch(*s) {
+ case '0':
+ element->push_back((char)0);
+ break;
+ case 'r':
+ element->push_back('\r');
+ break;
+ case 'n':
+ element->push_back('\n');
+ break;
+ default:
+ element->push_back(*s);
+ break;
+ }
+ } else {
+ if (*s == '\\') {
+ escapeState = true;
+ } else if (*s == '=') {
+ if (element == &keyBuf)
+ element = &((*this)[keyBuf]);
+ } else if ((*s == '\r')||(*s == '\n')) {
+ if ((element == &keyBuf)&&(keyBuf.length() > 0))
+ (*this)[keyBuf];
+ keyBuf = "";
+ element = &keyBuf;
+ } else element->push_back(*s);
+ }
+ ++s;
+ }
+ if ((element == &keyBuf)&&(keyBuf.length() > 0))
+ (*this)[keyBuf];
+}
+
+void Dictionary::fromString(const char *s,unsigned int maxlen)
+{
+ clear();
+ updateFromString(s,maxlen);
+}
+
+void Dictionary::eraseKey(const std::string &key)
+{
+ for(iterator i(begin());i!=end();++i) {
+ if (i->first == key) {
+ this->erase(i);
+ return;
+ }
+ }
+}
+
+bool Dictionary::sign(const Identity &id,uint64_t now)
+{
+ try {
+ // Sign identity and timestamp fields too. If there's an existing
+ // signature, _mkSigBuf() ignores it.
+ char nows[32];
+ Utils::snprintf(nows,sizeof(nows),"%llx",(unsigned long long)now);
+ (*this)[ZT_DICTIONARY_SIGNATURE_IDENTITY] = id.toString(false);
+ (*this)[ZT_DICTIONARY_SIGNATURE_TIMESTAMP] = nows;
+
+ // Create a blob to hash and sign from fields in sorted order
+ std::string buf;
+ _mkSigBuf(buf);
+
+ // Add signature field
+ C25519::Signature sig(id.sign(buf.data(),(unsigned int)buf.length()));
+ (*this)[ZT_DICTIONARY_SIGNATURE] = Utils::hex(sig.data,(unsigned int)sig.size());
+
+ return true;
+ } catch ( ... ) {
+ // Probably means identity has no secret key field
+ removeSignature();
+ return false;
+ }
+}
+
+bool Dictionary::verify(const Identity &id) const
+{
+ try {
+ std::string buf;
+ _mkSigBuf(buf);
+ const_iterator sig(find(ZT_DICTIONARY_SIGNATURE));
+ if (sig == end())
+ return false;
+ std::string sigbin(Utils::unhex(sig->second));
+ return id.verify(buf.data(),(unsigned int)buf.length(),sigbin.data(),(unsigned int)sigbin.length());
+ } catch ( ... ) {
+ return false;
+ }
+}
+
+uint64_t Dictionary::signatureTimestamp() const
+{
+ const_iterator ts(find(ZT_DICTIONARY_SIGNATURE_TIMESTAMP));
+ if (ts == end())
+ return 0;
+ return Utils::hexStrToU64(ts->second.c_str());
+}
+
+void Dictionary::_mkSigBuf(std::string &buf) const
+{
+ unsigned long pairs = 0;
+ for(const_iterator i(begin());i!=end();++i) {
+ if (i->first != ZT_DICTIONARY_SIGNATURE) {
+ buf.append(i->first);
+ buf.push_back('=');
+ buf.append(i->second);
+ buf.push_back('\0');
+ ++pairs;
+ }
+ }
+ buf.push_back((char)0xff);
+ buf.push_back((char)((pairs >> 24) & 0xff)); // pad with number of key/value pairs at end
+ buf.push_back((char)((pairs >> 16) & 0xff));
+ buf.push_back((char)((pairs >> 8) & 0xff));
+ buf.push_back((char)(pairs & 0xff));
+}
+
+void Dictionary::_appendEsc(const char *data,unsigned int len,std::string &to)
+{
+ for(unsigned int i=0;i<len;++i) {
+ switch(data[i]) {
+ case 0:
+ to.append("\\0");
+ break;
+ case '\r':
+ to.append("\\r");
+ break;
+ case '\n':
+ to.append("\\n");
+ break;
+ case '\\':
+ to.append("\\\\");
+ break;
+ case '=':
+ to.append("\\=");
+ break;
+ default:
+ to.push_back(data[i]);
+ break;
+ }
+ }
+}
+
+} // namespace ZeroTier
+
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
diff --git a/zerotierone/node/Dictionary.hpp b/zerotierone/node/Dictionary.hpp
new file mode 100644
index 0000000..d4cdd23
--- /dev/null
+++ b/zerotierone/node/Dictionary.hpp
@@ -0,0 +1,280 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_DICTIONARY_HPP
+#define ZT_DICTIONARY_HPP
+
+#include "Constants.hpp"
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <algorithm>
+
+#include "Utils.hpp"
+
+// Three fields are added/updated by sign()
+#define ZT_DICTIONARY_SIGNATURE "~!ed25519"
+#define ZT_DICTIONARY_SIGNATURE_IDENTITY "~!sigid"
+#define ZT_DICTIONARY_SIGNATURE_TIMESTAMP "~!sigts"
+
+namespace ZeroTier {
+
+class Identity;
+
+/**
+ * Simple key/value dictionary with string serialization
+ *
+ * The serialization format is a flat key=value with backslash escape.
+ * It does not support comments or other syntactic complexities. It is
+ * human-readable if the keys and values in the dictionary are also
+ * human-readable. Otherwise it might contain unprintable characters.
+ *
+ * Keys beginning with "~!" are reserved for signature data fields.
+ *
+ * It's stored as a simple vector and can be linearly scanned or
+ * binary searched. Dictionaries are only used for very small things
+ * outside the core loop, so this is not a significant performance
+ * issue and it reduces memory use and code footprint.
+ */
+class Dictionary : public std::vector< std::pair<std::string,std::string> >
+{
+public:
+ Dictionary() {}
+
+ /**
+ * @param s String-serialized dictionary
+ * @param maxlen Maximum length of buffer
+ */
+ Dictionary(const char *s,unsigned int maxlen) { fromString(s,maxlen); }
+
+ /**
+ * @param s String-serialized dictionary
+ */
+ Dictionary(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
+
+ iterator find(const std::string &key);
+ const_iterator find(const std::string &key) const;
+
+ /**
+ * Get a key, returning a default if not present
+ *
+ * @param key Key to look up
+ * @param dfl Default if not present
+ * @return Value or default
+ */
+ inline const std::string &get(const std::string &key,const std::string &dfl) const
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ return e->second;
+ }
+
+ /**
+ * @param key Key to get
+ * @param dfl Default boolean result if key not found or empty (default: false)
+ * @return Boolean value of key
+ */
+ bool getBoolean(const std::string &key,bool dfl = false) const;
+
+ /**
+ * @param key Key to get
+ * @param dfl Default value if not present (default: 0)
+ * @return Value converted to unsigned 64-bit int or 0 if not found
+ */
+ inline uint64_t getUInt(const std::string &key,uint64_t dfl = 0) const
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ return Utils::strToU64(e->second.c_str());
+ }
+
+ /**
+ * @param key Key to get
+ * @param dfl Default value if not present (default: 0)
+ * @return Value converted to unsigned 64-bit int or 0 if not found
+ */
+ inline uint64_t getHexUInt(const std::string &key,uint64_t dfl = 0) const
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ return Utils::hexStrToU64(e->second.c_str());
+ }
+
+ /**
+ * @param key Key to get
+ * @param dfl Default value if not present (default: 0)
+ * @return Value converted to signed 64-bit int or 0 if not found
+ */
+ inline int64_t getInt(const std::string &key,int64_t dfl = 0) const
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ return Utils::strTo64(e->second.c_str());
+ }
+
+ std::string &operator[](const std::string &key);
+
+ /**
+ * @param key Key to set
+ * @param value String value
+ */
+ inline void set(const std::string &key,const char *value)
+ {
+ (*this)[key] = value;
+ }
+
+ /**
+ * @param key Key to set
+ * @param value String value
+ */
+ inline void set(const std::string &key,const std::string &value)
+ {
+ (*this)[key] = value;
+ }
+
+ /**
+ * @param key Key to set
+ * @param value Boolean value
+ */
+ inline void set(const std::string &key,bool value)
+ {
+ (*this)[key] = ((value) ? "1" : "0");
+ }
+
+ /**
+ * @param key Key to set
+ * @param value Integer value
+ */
+ inline void set(const std::string &key,uint64_t value)
+ {
+ char tmp[24];
+ Utils::snprintf(tmp,sizeof(tmp),"%llu",(unsigned long long)value);
+ (*this)[key] = tmp;
+ }
+
+ /**
+ * @param key Key to set
+ * @param value Integer value
+ */
+ inline void set(const std::string &key,int64_t value)
+ {
+ char tmp[24];
+ Utils::snprintf(tmp,sizeof(tmp),"%lld",(long long)value);
+ (*this)[key] = tmp;
+ }
+
+ /**
+ * @param key Key to set
+ * @param value Integer value
+ */
+ inline void setHex(const std::string &key,uint64_t value)
+ {
+ char tmp[24];
+ Utils::snprintf(tmp,sizeof(tmp),"%llx",(unsigned long long)value);
+ (*this)[key] = tmp;
+ }
+
+ /**
+ * @param key Key to check
+ * @return True if dictionary contains key
+ */
+ inline bool contains(const std::string &key) const { return (find(key) != end()); }
+
+ /**
+ * @return String-serialized dictionary
+ */
+ std::string toString() const;
+
+ /**
+ * Clear and initialize from a string
+ *
+ * @param s String-serialized dictionary
+ * @param maxlen Maximum length of string buffer
+ */
+ void fromString(const char *s,unsigned int maxlen);
+ inline void fromString(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
+ void updateFromString(const char *s,unsigned int maxlen);
+ inline void update(const char *s,unsigned int maxlen) { updateFromString(s, maxlen); }
+ inline void update(const std::string &s) { updateFromString(s.c_str(),(unsigned int)s.length()); }
+
+ /**
+ * @return True if this dictionary is cryptographically signed
+ */
+ inline bool hasSignature() const { return (find(ZT_DICTIONARY_SIGNATURE) != end()); }
+
+ /**
+ * @return Signing identity in string-serialized format or empty string if none
+ */
+ inline std::string signingIdentity() const { return get(ZT_DICTIONARY_SIGNATURE_IDENTITY,std::string()); }
+
+ /**
+ * @return Signature timestamp in milliseconds since epoch or 0 if none
+ */
+ uint64_t signatureTimestamp() const;
+
+ /**
+ * @param key Key to erase
+ */
+ void eraseKey(const std::string &key);
+
+ /**
+ * Remove any signature from this dictionary
+ */
+ inline void removeSignature()
+ {
+ eraseKey(ZT_DICTIONARY_SIGNATURE);
+ eraseKey(ZT_DICTIONARY_SIGNATURE_IDENTITY);
+ eraseKey(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
+ }
+
+ /**
+ * Add or update signature fields with a signature of all other keys and values
+ *
+ * @param with Identity to sign with (must have secret key)
+ * @param now Current time
+ * @return True on success
+ */
+ bool sign(const Identity &id,uint64_t now);
+
+ /**
+ * Verify signature against an identity
+ *
+ * @param id Identity to verify against
+ * @return True if signature verification OK
+ */
+ bool verify(const Identity &id) const;
+
+private:
+ void _mkSigBuf(std::string &buf) const;
+ static void _appendEsc(const char *data,unsigned int len,std::string &to);
+};
+
+} // namespace ZeroTier
+
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+#endif
diff --git a/zerotierone/node/Hashtable.hpp b/zerotierone/node/Hashtable.hpp
new file mode 100644
index 0000000..f06b223
--- /dev/null
+++ b/zerotierone/node/Hashtable.hpp
@@ -0,0 +1,415 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_HASHTABLE_HPP
+#define ZT_HASHTABLE_HPP
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <stdexcept>
+#include <vector>
+#include <utility>
+#include <algorithm>
+
+namespace ZeroTier {
+
+/**
+ * A minimal hash table implementation for the ZeroTier core
+ *
+ * This is not a drop-in replacement for STL containers, and has several
+ * limitations. Keys can be uint64_t or an object, and if the latter they
+ * must implement a method called hashCode() that returns an unsigned long
+ * value that is evenly distributed.
+ */
+template<typename K,typename V>
+class Hashtable
+{
+private:
+ struct _Bucket
+ {
+ _Bucket(const K &k,const V &v) : k(k),v(v) {}
+ _Bucket(const K &k) : k(k),v() {}
+ _Bucket(const _Bucket &b) : k(b.k),v(b.v) {}
+ inline _Bucket &operator=(const _Bucket &b) { k = b.k; v = b.v; return *this; }
+ K k;
+ V v;
+ _Bucket *next; // must be set manually for each _Bucket
+ };
+
+public:
+ /**
+ * A simple forward iterator (different from STL)
+ *
+ * It's safe to erase the last key, but not others. Don't use set() since that
+ * may rehash and invalidate the iterator. Note the erasing the key will destroy
+ * the targets of the pointers returned by next().
+ */
+ class Iterator
+ {
+ public:
+ /**
+ * @param ht Hash table to iterate over
+ */
+ Iterator(Hashtable &ht) :
+ _idx(0),
+ _ht(&ht),
+ _b(ht._t[0])
+ {
+ }
+
+ /**
+ * @param kptr Pointer to set to point to next key
+ * @param vptr Pointer to set to point to next value
+ * @return True if kptr and vptr are set, false if no more entries
+ */
+ inline bool next(K *&kptr,V *&vptr)
+ {
+ for(;;) {
+ if (_b) {
+ kptr = &(_b->k);
+ vptr = &(_b->v);
+ _b = _b->next;
+ return true;
+ }
+ ++_idx;
+ if (_idx >= _ht->_bc)
+ return false;
+ _b = _ht->_t[_idx];
+ }
+ }
+
+ private:
+ unsigned long _idx;
+ Hashtable *_ht;
+ _Bucket *_b;
+ };
+ friend class Hashtable::Iterator;
+
+ /**
+ * @param bc Initial capacity in buckets (default: 128, must be nonzero)
+ */
+ Hashtable(unsigned long bc = 128) :
+ _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * bc))),
+ _bc(bc),
+ _s(0)
+ {
+ if (!_t)
+ throw std::bad_alloc();
+ for(unsigned long i=0;i<bc;++i)
+ _t[i] = (_Bucket *)0;
+ }
+
+ Hashtable(const Hashtable<K,V> &ht) :
+ _t(reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * ht._bc))),
+ _bc(ht._bc),
+ _s(ht._s)
+ {
+ if (!_t)
+ throw std::bad_alloc();
+ for(unsigned long i=0;i<_bc;++i)
+ _t[i] = (_Bucket *)0;
+ for(unsigned long i=0;i<_bc;++i) {
+ const _Bucket *b = ht._t[i];
+ while (b) {
+ _Bucket *nb = new _Bucket(*b);
+ nb->next = _t[i];
+ _t[i] = nb;
+ b = b->next;
+ }
+ }
+ }
+
+ ~Hashtable()
+ {
+ this->clear();
+ ::free(_t);
+ }
+
+ inline Hashtable &operator=(const Hashtable<K,V> &ht)
+ {
+ this->clear();
+ if (ht._s) {
+ for(unsigned long i=0;i<ht._bc;++i) {
+ const _Bucket *b = ht._t[i];
+ while (b) {
+ this->set(b->k,b->v);
+ b = b->next;
+ }
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Erase all entries
+ */
+ inline void clear()
+ {
+ if (_s) {
+ for(unsigned long i=0;i<_bc;++i) {
+ _Bucket *b = _t[i];
+ while (b) {
+ _Bucket *const nb = b->next;
+ delete b;
+ b = nb;
+ }
+ _t[i] = (_Bucket *)0;
+ }
+ _s = 0;
+ }
+ }
+
+ /**
+ * @return Vector of all keys
+ */
+ inline typename std::vector<K> keys() const
+ {
+ typename std::vector<K> k;
+ if (_s) {
+ k.reserve(_s);
+ for(unsigned long i=0;i<_bc;++i) {
+ _Bucket *b = _t[i];
+ while (b) {
+ k.push_back(b->k);
+ b = b->next;
+ }
+ }
+ }
+ return k;
+ }
+
+ /**
+ * Append all keys (in unspecified order) to the supplied vector or list
+ *
+ * @param v Vector, list, or other compliant container
+ * @tparam Type of V (generally inferred)
+ */
+ template<typename C>
+ inline void appendKeys(C &v) const
+ {
+ if (_s) {
+ for(unsigned long i=0;i<_bc;++i) {
+ _Bucket *b = _t[i];
+ while (b) {
+ v.push_back(b->k);
+ b = b->next;
+ }
+ }
+ }
+ }
+
+ /**
+ * @return Vector of all entries (pairs of K,V)
+ */
+ inline typename std::vector< std::pair<K,V> > entries() const
+ {
+ typename std::vector< std::pair<K,V> > k;
+ if (_s) {
+ k.reserve(_s);
+ for(unsigned long i=0;i<_bc;++i) {
+ _Bucket *b = _t[i];
+ while (b) {
+ k.push_back(std::pair<K,V>(b->k,b->v));
+ b = b->next;
+ }
+ }
+ }
+ return k;
+ }
+
+ /**
+ * @param k Key
+ * @return Pointer to value or NULL if not found
+ */
+ inline V *get(const K &k)
+ {
+ _Bucket *b = _t[_hc(k) % _bc];
+ while (b) {
+ if (b->k == k)
+ return &(b->v);
+ b = b->next;
+ }
+ return (V *)0;
+ }
+ inline const V *get(const K &k) const { return const_cast<Hashtable *>(this)->get(k); }
+
+ /**
+ * @param k Key to check
+ * @return True if key is present
+ */
+ inline bool contains(const K &k) const
+ {
+ _Bucket *b = _t[_hc(k) % _bc];
+ while (b) {
+ if (b->k == k)
+ return true;
+ b = b->next;
+ }
+ return false;
+ }
+
+ /**
+ * @param k Key
+ * @return True if value was present
+ */
+ inline bool erase(const K &k)
+ {
+ const unsigned long bidx = _hc(k) % _bc;
+ _Bucket *lastb = (_Bucket *)0;
+ _Bucket *b = _t[bidx];
+ while (b) {
+ if (b->k == k) {
+ if (lastb)
+ lastb->next = b->next;
+ else _t[bidx] = b->next;
+ delete b;
+ --_s;
+ return true;
+ }
+ lastb = b;
+ b = b->next;
+ }
+ return false;
+ }
+
+ /**
+ * @param k Key
+ * @param v Value
+ * @return Reference to value in table
+ */
+ inline V &set(const K &k,const V &v)
+ {
+ const unsigned long h = _hc(k);
+ unsigned long bidx = h % _bc;
+
+ _Bucket *b = _t[bidx];
+ while (b) {
+ if (b->k == k) {
+ b->v = v;
+ return b->v;
+ }
+ b = b->next;
+ }
+
+ if (_s >= _bc) {
+ _grow();
+ bidx = h % _bc;
+ }
+
+ b = new _Bucket(k,v);
+ b->next = _t[bidx];
+ _t[bidx] = b;
+ ++_s;
+ return b->v;
+ }
+
+ /**
+ * @param k Key
+ * @return Value, possibly newly created
+ */
+ inline V &operator[](const K &k)
+ {
+ const unsigned long h = _hc(k);
+ unsigned long bidx = h % _bc;
+
+ _Bucket *b = _t[bidx];
+ while (b) {
+ if (b->k == k)
+ return b->v;
+ b = b->next;
+ }
+
+ if (_s >= _bc) {
+ _grow();
+ bidx = h % _bc;
+ }
+
+ b = new _Bucket(k);
+ b->next = _t[bidx];
+ _t[bidx] = b;
+ ++_s;
+ return b->v;
+ }
+
+ /**
+ * @return Number of entries
+ */
+ inline unsigned long size() const throw() { return _s; }
+
+ /**
+ * @return True if table is empty
+ */
+ inline bool empty() const throw() { return (_s == 0); }
+
+private:
+ template<typename O>
+ static inline unsigned long _hc(const O &obj)
+ {
+ return obj.hashCode();
+ }
+ static inline unsigned long _hc(const uint64_t i)
+ {
+ /* NOTE: this assumes that 'i' is evenly distributed, which is the case for
+ * packet IDs and network IDs -- the two use cases in ZT for uint64_t keys.
+ * These values are also greater than 0xffffffff so they'll map onto a full
+ * bucket count just fine no matter what happens. Normally you'd want to
+ * hash an integer key index in a hash table. */
+ return (unsigned long)i;
+ }
+ static inline unsigned long _hc(const uint32_t i)
+ {
+ return ((unsigned long)i * (unsigned long)0x9e3779b1);
+ }
+ static inline unsigned long _hc(const uint16_t i)
+ {
+ return ((unsigned long)i * (unsigned long)0x9e3779b1);
+ }
+
+ inline void _grow()
+ {
+ const unsigned long nc = _bc * 2;
+ _Bucket **nt = reinterpret_cast<_Bucket **>(::malloc(sizeof(_Bucket *) * nc));
+ if (nt) {
+ for(unsigned long i=0;i<nc;++i)
+ nt[i] = (_Bucket *)0;
+ for(unsigned long i=0;i<_bc;++i) {
+ _Bucket *b = _t[i];
+ while (b) {
+ _Bucket *const nb = b->next;
+ const unsigned long nidx = _hc(b->k) % nc;
+ b->next = nt[nidx];
+ nt[nidx] = b;
+ b = nb;
+ }
+ }
+ ::free(_t);
+ _t = nt;
+ _bc = nc;
+ }
+ }
+
+ _Bucket **_t;
+ unsigned long _bc;
+ unsigned long _s;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Identity.cpp b/zerotierone/node/Identity.cpp
new file mode 100644
index 0000000..6f89a1e
--- /dev/null
+++ b/zerotierone/node/Identity.cpp
@@ -0,0 +1,190 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "Constants.hpp"
+#include "Identity.hpp"
+#include "SHA512.hpp"
+#include "Salsa20.hpp"
+#include "Utils.hpp"
+
+// These can't be changed without a new identity type. They define the
+// parameters of the hashcash hashing/searching algorithm.
+
+#define ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN 17
+#define ZT_IDENTITY_GEN_MEMORY 2097152
+
+namespace ZeroTier {
+
+// A memory-hard composition of SHA-512 and Salsa20 for hashcash hashing
+static inline void _computeMemoryHardHash(const void *publicKey,unsigned int publicKeyBytes,void *digest,void *genmem)
+{
+ // Digest publicKey[] to obtain initial digest
+ SHA512::hash(digest,publicKey,publicKeyBytes);
+
+ // Initialize genmem[] using Salsa20 in a CBC-like configuration since
+ // ordinary Salsa20 is randomly seekable. This is good for a cipher
+ // but is not what we want for sequential memory-harndess.
+ memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
+ Salsa20 s20(digest,256,(char *)digest + 32);
+ s20.encrypt20((char *)genmem,(char *)genmem,64);
+ for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
+ unsigned long k = i - 64;
+ *((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k));
+ *((uint64_t *)((char *)genmem + i + 8)) = *((uint64_t *)((char *)genmem + k + 8));
+ *((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16));
+ *((uint64_t *)((char *)genmem + i + 24)) = *((uint64_t *)((char *)genmem + k + 24));
+ *((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32));
+ *((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40));
+ *((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48));
+ *((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56));
+ s20.encrypt20((char *)genmem + i,(char *)genmem + i,64);
+ }
+
+ // Render final digest using genmem as a lookup table
+ for(unsigned long i=0;i<(ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) {
+ unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (64 / sizeof(uint64_t)));
+ unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (ZT_IDENTITY_GEN_MEMORY / sizeof(uint64_t)));
+ uint64_t tmp = ((uint64_t *)genmem)[idx2];
+ ((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1];
+ ((uint64_t *)digest)[idx1] = tmp;
+ s20.encrypt20(digest,digest,64);
+ }
+}
+
+// Hashcash generation halting condition -- halt when first byte is less than
+// threshold value.
+struct _Identity_generate_cond
+{
+ _Identity_generate_cond() throw() {}
+ _Identity_generate_cond(unsigned char *sb,char *gm) throw() : digest(sb),genmem(gm) {}
+ inline bool operator()(const C25519::Pair &kp) const
+ throw()
+ {
+ _computeMemoryHardHash(kp.pub.data,(unsigned int)kp.pub.size(),digest,genmem);
+ return (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN);
+ }
+ unsigned char *digest;
+ char *genmem;
+};
+
+void Identity::generate()
+{
+ unsigned char digest[64];
+ char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
+
+ C25519::Pair kp;
+ do {
+ kp = C25519::generateSatisfying(_Identity_generate_cond(digest,genmem));
+ _address.setTo(digest + 59,ZT_ADDRESS_LENGTH); // last 5 bytes are address
+ } while (_address.isReserved());
+
+ _publicKey = kp.pub;
+ if (!_privateKey)
+ _privateKey = new C25519::Private();
+ *_privateKey = kp.priv;
+
+ delete [] genmem;
+}
+
+bool Identity::locallyValidate() const
+{
+ if (_address.isReserved())
+ return false;
+
+ unsigned char digest[64];
+ char *genmem = new char[ZT_IDENTITY_GEN_MEMORY];
+ _computeMemoryHardHash(_publicKey.data,(unsigned int)_publicKey.size(),digest,genmem);
+ delete [] genmem;
+
+ unsigned char addrb[5];
+ _address.copyTo(addrb,5);
+
+ return (
+ (digest[0] < ZT_IDENTITY_GEN_HASHCASH_FIRST_BYTE_LESS_THAN)&&
+ (digest[59] == addrb[0])&&
+ (digest[60] == addrb[1])&&
+ (digest[61] == addrb[2])&&
+ (digest[62] == addrb[3])&&
+ (digest[63] == addrb[4]));
+}
+
+std::string Identity::toString(bool includePrivate) const
+{
+ std::string r;
+
+ r.append(_address.toString());
+ r.append(":0:"); // 0 == IDENTITY_TYPE_C25519
+ r.append(Utils::hex(_publicKey.data,(unsigned int)_publicKey.size()));
+ if ((_privateKey)&&(includePrivate)) {
+ r.push_back(':');
+ r.append(Utils::hex(_privateKey->data,(unsigned int)_privateKey->size()));
+ }
+
+ return r;
+}
+
+bool Identity::fromString(const char *str)
+{
+ if (!str)
+ return false;
+
+ char *saveptr = (char *)0;
+ char tmp[1024];
+ if (!Utils::scopy(tmp,sizeof(tmp),str))
+ return false;
+
+ delete _privateKey;
+ _privateKey = (C25519::Private *)0;
+
+ int fno = 0;
+ for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) {
+ switch(fno++) {
+ case 0:
+ _address = Address(f);
+ if (_address.isReserved())
+ return false;
+ break;
+ case 1:
+ if ((f[0] != '0')||(f[1]))
+ return false;
+ break;
+ case 2:
+ if (Utils::unhex(f,_publicKey.data,(unsigned int)_publicKey.size()) != _publicKey.size())
+ return false;
+ break;
+ case 3:
+ _privateKey = new C25519::Private();
+ if (Utils::unhex(f,_privateKey->data,(unsigned int)_privateKey->size()) != _privateKey->size())
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ if (fno < 3)
+ return false;
+
+ return true;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Identity.hpp b/zerotierone/node/Identity.hpp
new file mode 100644
index 0000000..e19c498
--- /dev/null
+++ b/zerotierone/node/Identity.hpp
@@ -0,0 +1,318 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_IDENTITY_HPP
+#define ZT_IDENTITY_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+#include "Constants.hpp"
+#include "Array.hpp"
+#include "Utils.hpp"
+#include "Address.hpp"
+#include "C25519.hpp"
+#include "Buffer.hpp"
+#include "SHA512.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A ZeroTier identity
+ *
+ * An identity consists of a public key, a 40-bit ZeroTier address computed
+ * from that key in a collision-resistant fashion, and a self-signature.
+ *
+ * The address derivation algorithm makes it computationally very expensive to
+ * search for a different public key that duplicates an existing address. (See
+ * code for deriveAddress() for this algorithm.)
+ */
+class Identity
+{
+public:
+ /**
+ * Identity types
+ */
+ enum Type
+ {
+ IDENTITY_TYPE_C25519 = 0
+ };
+
+ Identity() :
+ _privateKey((C25519::Private *)0)
+ {
+ }
+
+ Identity(const Identity &id) :
+ _address(id._address),
+ _publicKey(id._publicKey),
+ _privateKey((id._privateKey) ? new C25519::Private(*(id._privateKey)) : (C25519::Private *)0)
+ {
+ }
+
+ Identity(const char *str)
+ throw(std::invalid_argument) :
+ _privateKey((C25519::Private *)0)
+ {
+ if (!fromString(str))
+ throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str);
+ }
+
+ Identity(const std::string &str)
+ throw(std::invalid_argument) :
+ _privateKey((C25519::Private *)0)
+ {
+ if (!fromString(str))
+ throw std::invalid_argument(std::string("invalid string-serialized identity: ") + str);
+ }
+
+ template<unsigned int C>
+ Identity(const Buffer<C> &b,unsigned int startAt = 0) :
+ _privateKey((C25519::Private *)0)
+ {
+ deserialize(b,startAt);
+ }
+
+ ~Identity()
+ {
+ delete _privateKey;
+ }
+
+ inline Identity &operator=(const Identity &id)
+ {
+ _address = id._address;
+ _publicKey = id._publicKey;
+ if (id._privateKey) {
+ if (!_privateKey)
+ _privateKey = new C25519::Private();
+ *_privateKey = *(id._privateKey);
+ } else {
+ delete _privateKey;
+ _privateKey = (C25519::Private *)0;
+ }
+ return *this;
+ }
+
+ /**
+ * Generate a new identity (address, key pair)
+ *
+ * This is a time consuming operation.
+ */
+ void generate();
+
+ /**
+ * Check the validity of this identity's pairing of key to address
+ *
+ * @return True if validation check passes
+ */
+ bool locallyValidate() const;
+
+ /**
+ * @return True if this identity contains a private key
+ */
+ inline bool hasPrivate() const throw() { return (_privateKey != (C25519::Private *)0); }
+
+ /**
+ * Compute the SHA512 hash of our private key (if we have one)
+ *
+ * @param sha Buffer to receive SHA512 (MUST be ZT_SHA512_DIGEST_LEN (64) bytes in length)
+ * @return True on success, false if no private key
+ */
+ inline bool sha512PrivateKey(void *sha) const
+ {
+ if (_privateKey) {
+ SHA512::hash(sha,_privateKey->data,ZT_C25519_PRIVATE_KEY_LEN);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Sign a message with this identity (private key required)
+ *
+ * @param data Data to sign
+ * @param len Length of data
+ */
+ inline C25519::Signature sign(const void *data,unsigned int len) const
+ throw(std::runtime_error)
+ {
+ if (_privateKey)
+ return C25519::sign(*_privateKey,_publicKey,data,len);
+ throw std::runtime_error("sign() requires a private key");
+ }
+
+ /**
+ * Verify a message signature against this identity
+ *
+ * @param data Data to check
+ * @param len Length of data
+ * @param signature Signature bytes
+ * @param siglen Length of signature in bytes
+ * @return True if signature validates and data integrity checks
+ */
+ inline bool verify(const void *data,unsigned int len,const void *signature,unsigned int siglen) const
+ {
+ if (siglen != ZT_C25519_SIGNATURE_LEN)
+ return false;
+ return C25519::verify(_publicKey,data,len,signature);
+ }
+
+ /**
+ * Verify a message signature against this identity
+ *
+ * @param data Data to check
+ * @param len Length of data
+ * @param signature Signature
+ * @return True if signature validates and data integrity checks
+ */
+ inline bool verify(const void *data,unsigned int len,const C25519::Signature &signature) const
+ {
+ return C25519::verify(_publicKey,data,len,signature);
+ }
+
+ /**
+ * Shortcut method to perform key agreement with another identity
+ *
+ * This identity must have a private key. (Check hasPrivate())
+ *
+ * @param id Identity to agree with
+ * @param key Result parameter to fill with key bytes
+ * @param klen Length of key in bytes
+ * @return Was agreement successful?
+ */
+ inline bool agree(const Identity &id,void *key,unsigned int klen) const
+ {
+ if (_privateKey) {
+ C25519::agree(*_privateKey,id._publicKey,key,klen);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return Identity type
+ */
+ inline Type type() const throw() { return IDENTITY_TYPE_C25519; }
+
+ /**
+ * @return This identity's address
+ */
+ inline const Address &address() const throw() { return _address; }
+
+ /**
+ * Serialize this identity (binary)
+ *
+ * @param b Destination buffer to append to
+ * @param includePrivate If true, include private key component (if present) (default: false)
+ * @throws std::out_of_range Buffer too small
+ */
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b,bool includePrivate = false) const
+ {
+ _address.appendTo(b);
+ b.append((unsigned char)IDENTITY_TYPE_C25519);
+ b.append(_publicKey.data,(unsigned int)_publicKey.size());
+ if ((_privateKey)&&(includePrivate)) {
+ b.append((unsigned char)_privateKey->size());
+ b.append(_privateKey->data,(unsigned int)_privateKey->size());
+ } else b.append((unsigned char)0);
+ }
+
+ /**
+ * Deserialize a binary serialized identity
+ *
+ * If an exception is thrown, the Identity object is left in an undefined
+ * state and should not be used.
+ *
+ * @param b Buffer containing serialized data
+ * @param startAt Index within buffer of serialized data (default: 0)
+ * @return Length of serialized data read from buffer
+ * @throws std::out_of_range Serialized data invalid
+ * @throws std::invalid_argument Serialized data invalid
+ */
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ delete _privateKey;
+ _privateKey = (C25519::Private *)0;
+
+ unsigned int p = startAt;
+
+ _address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ p += ZT_ADDRESS_LENGTH;
+
+ if (b[p++] != IDENTITY_TYPE_C25519)
+ throw std::invalid_argument("unsupported identity type");
+
+ memcpy(_publicKey.data,b.field(p,(unsigned int)_publicKey.size()),(unsigned int)_publicKey.size());
+ p += (unsigned int)_publicKey.size();
+
+ unsigned int privateKeyLength = (unsigned int)b[p++];
+ if (privateKeyLength) {
+ if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN)
+ throw std::invalid_argument("invalid private key");
+ _privateKey = new C25519::Private();
+ memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
+ p += ZT_C25519_PRIVATE_KEY_LEN;
+ }
+
+ return (p - startAt);
+ }
+
+ /**
+ * Serialize to a more human-friendly string
+ *
+ * @param includePrivate If true, include private key (if it exists)
+ * @return ASCII string representation of identity
+ */
+ std::string toString(bool includePrivate) const;
+
+ /**
+ * Deserialize a human-friendly string
+ *
+ * Note: validation is for the format only. The locallyValidate() method
+ * must be used to check signature and address/key correspondence.
+ *
+ * @param str String to deserialize
+ * @return True if deserialization appears successful
+ */
+ bool fromString(const char *str);
+ inline bool fromString(const std::string &str) { return fromString(str.c_str()); }
+
+ /**
+ * @return True if this identity contains something
+ */
+ inline operator bool() const throw() { return (_address); }
+
+ inline bool operator==(const Identity &id) const throw() { return ((_address == id._address)&&(_publicKey == id._publicKey)); }
+ inline bool operator<(const Identity &id) const throw() { return ((_address < id._address)||((_address == id._address)&&(_publicKey < id._publicKey))); }
+ inline bool operator!=(const Identity &id) const throw() { return !(*this == id); }
+ inline bool operator>(const Identity &id) const throw() { return (id < *this); }
+ inline bool operator<=(const Identity &id) const throw() { return !(id < *this); }
+ inline bool operator>=(const Identity &id) const throw() { return !(*this < id); }
+
+private:
+ Address _address;
+ C25519::Public _publicKey;
+ C25519::Private *_privateKey;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/IncomingPacket.cpp b/zerotierone/node/IncomingPacket.cpp
new file mode 100644
index 0000000..9e0226b
--- /dev/null
+++ b/zerotierone/node/IncomingPacket.cpp
@@ -0,0 +1,1349 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "../version.h"
+#include "../include/ZeroTierOne.h"
+
+#include "Constants.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "IncomingPacket.hpp"
+#include "Topology.hpp"
+#include "Switch.hpp"
+#include "Peer.hpp"
+#include "NetworkController.hpp"
+#include "SelfAwareness.hpp"
+#include "Salsa20.hpp"
+#include "SHA512.hpp"
+#include "World.hpp"
+#include "Cluster.hpp"
+#include "Node.hpp"
+#include "DeferredPackets.hpp"
+
+namespace ZeroTier {
+
+bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
+{
+ const Address sourceAddress(source());
+ try {
+ if ((cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
+ // Unencrypted HELLOs require some potentially expensive verification, so
+ // do this in the background if background processing is enabled.
+ if ((RR->dpEnabled > 0)&&(!deferred)) {
+ RR->dp->enqueue(this);
+ return true; // 'handled' via deferring to background thread(s)
+ } else {
+ // A null pointer for peer to _doHELLO() tells it to run its own
+ // special internal authentication logic. This is done for unencrypted
+ // HELLOs to learn new identities, etc.
+ SharedPtr<Peer> tmp;
+ return _doHELLO(RR,tmp);
+ }
+ }
+
+ SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
+ if (peer) {
+ if (!dearmor(peer->key())) {
+ TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
+ return true;
+ }
+ if (!uncompress()) {
+ TRACE("dropped packet from %s(%s), compressed data invalid",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ const Packet::Verb v = verb();
+ //TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
+ switch(v) {
+ //case Packet::VERB_NOP:
+ default: // ignore unknown verbs, but if they pass auth check they are "received"
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP);
+ return true;
+
+ case Packet::VERB_HELLO: return _doHELLO(RR,peer);
+ case Packet::VERB_ERROR: return _doERROR(RR,peer);
+ case Packet::VERB_OK: return _doOK(RR,peer);
+ case Packet::VERB_WHOIS: return _doWHOIS(RR,peer);
+ case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,peer);
+ case Packet::VERB_FRAME: return _doFRAME(RR,peer);
+ case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,peer);
+ case Packet::VERB_ECHO: return _doECHO(RR,peer);
+ case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
+ case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(RR,peer);
+ case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer);
+ case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer);
+ case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer);
+ case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer);
+ case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer);
+ case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer);
+ case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer);
+ case Packet::VERB_REQUEST_PROOF_OF_WORK: return _doREQUEST_PROOF_OF_WORK(RR,peer);
+ }
+ } else {
+ RR->sw->requestWhois(sourceAddress);
+ return false;
+ }
+ } catch ( ... ) {
+ // Exceptions are more informatively caught in _do...() handlers but
+ // this outer try/catch will catch anything else odd.
+ TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+}
+
+bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB];
+ const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID);
+ const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE];
+
+ //TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
+
+ switch(errorCode) {
+
+ case Packet::ERROR_OBJ_NOT_FOUND:
+ if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
+ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
+ if ((network)&&(network->controller() == peer->address()))
+ network->setNotFound();
+ }
+ break;
+
+ case Packet::ERROR_UNSUPPORTED_OPERATION:
+ if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
+ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
+ if ((network)&&(network->controller() == peer->address()))
+ network->setNotFound();
+ }
+ break;
+
+ case Packet::ERROR_IDENTITY_COLLISION:
+ if (RR->topology->isRoot(peer->identity()))
+ RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
+ break;
+
+ case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
+ /* Note: certificates are public so it's safe to push them to anyone
+ * who asks. We won't communicate unless we also get a certificate
+ * from the remote that agrees. */
+ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
+ if ((network)&&(network->hasConfig())&&(network->config().com)) {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
+ network->config().com.serialize(outp);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } break;
+
+ case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
+ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
+ if ((network)&&(network->controller() == peer->address()))
+ network->setAccessDenied();
+ } break;
+
+ case Packet::ERROR_UNWANTED_MULTICAST: {
+ uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
+ MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
+ TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",nwid,peer->address().toString().c_str(),mg.toString().c_str());
+ RR->mc->remove(nwid,mg,peer->address());
+ } break;
+
+ default: break;
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb);
+ } catch ( ... ) {
+ TRACE("dropped ERROR from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer)
+{
+ /* Note: this is the only packet ever sent in the clear, and it's also
+ * the only packet that we authenticate via a different path. Authentication
+ * occurs here and is based on the validity of the identity and the
+ * integrity of the packet's MAC, but it must be done after we check
+ * the identity since HELLO is a mechanism for learning new identities
+ * in the first place. */
+
+ try {
+ const uint64_t pid = packetId();
+ const Address fromAddress(source());
+ const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
+ const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
+ const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
+ const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
+ const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
+
+ Identity id;
+ InetAddress externalSurfaceAddress;
+ uint64_t worldId = ZT_WORLD_ID_NULL;
+ uint64_t worldTimestamp = 0;
+ {
+ unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
+ if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info
+ ptr += externalSurfaceAddress.deserialize(*this,ptr);
+ if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps
+ worldId = at<uint64_t>(ptr); ptr += 8;
+ worldTimestamp = at<uint64_t>(ptr);
+ }
+ }
+
+ if (protoVersion < ZT_PROTO_VERSION_MIN) {
+ TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+ if (fromAddress != id.address()) {
+ TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ if (!peer) { // peer == NULL is the normal case here
+ peer = RR->topology->getPeer(id.address());
+ if (peer) {
+ // We already have an identity with this address -- check for collisions
+
+ if (peer->identity() != id) {
+ // Identity is different from the one we already have -- address collision
+
+ unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
+ if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
+ if (dearmor(key)) { // ensure packet is authentic, otherwise drop
+ TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_HELLO);
+ outp.append((uint64_t)pid);
+ outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
+ outp.armor(key,true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } else {
+ TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ } else {
+ TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+
+ return true;
+ } else {
+ // Identity is the same as the one we already have -- check packet integrity
+
+ if (!dearmor(peer->key())) {
+ TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ // Continue at // VALID
+ }
+ } else {
+ // We don't already have an identity with this address -- validate and learn it
+
+ // Check identity proof of work
+ if (!id.locallyValidate()) {
+ TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ // Check packet integrity and authentication
+ SharedPtr<Peer> newPeer(new Peer(RR,RR->identity,id));
+ if (!dearmor(newPeer->key())) {
+ TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+ peer = RR->topology->addPeer(newPeer);
+
+ // Continue at // VALID
+ }
+
+ // VALID -- if we made it here, packet passed identity and authenticity checks!
+ }
+
+ if (externalSurfaceAddress)
+ RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isRoot(id),RR->node->now());
+
+ Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_HELLO);
+ outp.append((uint64_t)pid);
+ outp.append((uint64_t)timestamp);
+ outp.append((unsigned char)ZT_PROTO_VERSION);
+ outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
+ outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
+ outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ if (protoVersion >= 5) {
+ _remoteAddress.serialize(outp);
+ } else {
+ /* LEGACY COMPATIBILITY HACK:
+ *
+ * For a while now (since 1.0.3), ZeroTier has recognized changes in
+ * its network environment empirically by examining its external network
+ * address as reported by trusted peers. In versions prior to 1.1.0
+ * (protocol version < 5), they did this by saving a snapshot of this
+ * information (in SelfAwareness.hpp) keyed by reporting device ID and
+ * address type.
+ *
+ * This causes problems when clustering is combined with symmetric NAT.
+ * Symmetric NAT remaps ports, so different endpoints in a cluster will
+ * report back different exterior addresses. Since the old code keys
+ * this by device ID and not sending physical address and compares the
+ * entire address including port, it constantly thinks its external
+ * surface is changing and resets connections when talking to a cluster.
+ *
+ * In new code we key by sending physical address and device and we also
+ * take the more conservative position of only interpreting changes in
+ * IP address (neglecting port) as a change in network topology that
+ * necessitates a reset. But we can make older clients work here by
+ * nulling out the port field. Since this info is only used for empirical
+ * detection of link changes, it doesn't break anything else.
+ */
+ InetAddress tmpa(_remoteAddress);
+ tmpa.setPort(0);
+ tmpa.serialize(outp);
+ }
+
+ if ((worldId != ZT_WORLD_ID_NULL)&&(RR->topology->worldTimestamp() > worldTimestamp)&&(worldId == RR->topology->worldId())) {
+ World w(RR->topology->world());
+ const unsigned int sizeAt = outp.size();
+ outp.addSize(2); // make room for 16-bit size field
+ w.serialize(outp,false);
+ outp.setAt<uint16_t>(sizeAt,(uint16_t)(outp.size() - (sizeAt + 2)));
+ } else {
+ outp.append((uint16_t)0); // no world update needed
+ }
+
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+
+ peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
+ peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB];
+ const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID);
+
+ //TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
+
+ switch(inReVerb) {
+
+ case Packet::VERB_HELLO: {
+ const unsigned int latency = std::min((unsigned int)(RR->node->now() - at<uint64_t>(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP)),(unsigned int)0xffff);
+ const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION];
+ const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION];
+ const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION];
+ const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION);
+
+ if (vProto < ZT_PROTO_VERSION_MIN) {
+ TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ const bool trusted = RR->topology->isRoot(peer->identity());
+
+ InetAddress externalSurfaceAddress;
+ unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2;
+ if (ptr < size()) // ZeroTier One < 1.0.3 did not include this field
+ ptr += externalSurfaceAddress.deserialize(*this,ptr);
+ if ((trusted)&&((ptr + 2) <= size())) { // older versions also did not include this field, and right now we only use if from a root
+ World worldUpdate;
+ const unsigned int worldLen = at<uint16_t>(ptr); ptr += 2;
+ if (worldLen > 0) {
+ World w;
+ w.deserialize(*this,ptr);
+ RR->topology->worldUpdateIfValid(w);
+ }
+ }
+
+ TRACE("%s(%s): OK(HELLO), version %u.%u.%u, latency %u, reported external address %s",source().toString().c_str(),_remoteAddress.toString().c_str(),vMajor,vMinor,vRevision,latency,((externalSurfaceAddress) ? externalSurfaceAddress.toString().c_str() : "(none)"));
+
+ peer->addDirectLatencyMeasurment(latency);
+ peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
+
+ if (externalSurfaceAddress)
+ RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,trusted,RR->node->now());
+ } break;
+
+ case Packet::VERB_WHOIS: {
+ if (RR->topology->isRoot(peer->identity())) {
+ const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
+ // Right now we can skip this since OK(WHOIS) is only accepted from
+ // roots. In the future it should be done if we query less trusted
+ // sources.
+ //if (id.locallyValidate())
+ RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
+ }
+ } break;
+
+ case Packet::VERB_NETWORK_CONFIG_REQUEST: {
+ const SharedPtr<Network> nw(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
+ if ((nw)&&(nw->controller() == peer->address())) {
+ const unsigned int nclen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
+ if (nclen) {
+ nw->setConfiguration(field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,nclen),nclen,true);
+ TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
+ }
+ }
+ } break;
+
+ //case Packet::VERB_ECHO: {
+ //} break;
+
+ case Packet::VERB_MULTICAST_GATHER: {
+ const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
+ const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
+ TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),size());
+ const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
+ RR->mc->addMultiple(RR->node->now(),nwid,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS));
+ } break;
+
+ case Packet::VERB_MULTICAST_FRAME: {
+ const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS];
+ const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID);
+ const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI));
+
+ //TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),nwid,mg.toString().c_str(),flags);
+
+ unsigned int offset = 0;
+
+ if ((flags & 0x01) != 0) {
+ // OK(MULTICAST_FRAME) includes certificate of membership update
+ CertificateOfMembership com;
+ offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
+ peer->validateAndSetNetworkMembershipCertificate(nwid,com);
+ }
+
+ if ((flags & 0x02) != 0) {
+ // OK(MULTICAST_FRAME) includes implicit gather results
+ offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
+ unsigned int totalKnown = at<uint32_t>(offset); offset += 4;
+ unsigned int count = at<uint16_t>(offset); offset += 2;
+ RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown);
+ }
+ } break;
+
+ default: break;
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb);
+ } catch ( ... ) {
+ TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ if (payloadLength() == ZT_ADDRESS_LENGTH) {
+ Identity queried(RR->topology->getIdentity(Address(payload(),ZT_ADDRESS_LENGTH)));
+ if (queried) {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_WHOIS);
+ outp.append(packetId());
+ queried.serialize(outp,false);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } else {
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->sendDistributedQuery(*this);
+#endif
+ }
+ } else {
+ TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ if (RR->topology->isUpstream(peer->identity())) {
+ const Address with(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ const SharedPtr<Peer> withPeer(RR->topology->getPeer(with));
+ if (withPeer) {
+ const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
+ const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
+ if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP);
+
+ InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
+ TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
+ if (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,atAddr))
+ RR->sw->rendezvous(withPeer,_localAddress,atAddr);
+ } else {
+ TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ } else {
+ RR->sw->requestWhois(with);
+ TRACE("ignored RENDEZVOUS from %s(%s) to meet unknown peer %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),with.toString().c_str());
+ }
+ } else {
+ TRACE("ignored RENDEZVOUS from %s(%s): not a root server or a network relay",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ } catch ( ... ) {
+ TRACE("dropped RENDEZVOUS from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)));
+ if (network) {
+ if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
+ if (!network->isAllowed(peer)) {
+ TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id());
+ _sendErrorNeedCertificate(RR,peer,network->id());
+ return true;
+ }
+
+ const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
+ if (!network->config().permitsEtherType(etherType)) {
+ TRACE("dropped FRAME from %s(%s): ethertype %.4x not allowed on %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id());
+ return true;
+ }
+
+ const unsigned int payloadLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
+ RR->node->putFrame(network->id(),network->userPtr(),MAC(peer->address(),network->id()),network->mac(),etherType,0,field(ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,payloadLen),payloadLen);
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP);
+ } else {
+ TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
+ }
+ } catch ( ... ) {
+ TRACE("dropped FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID)));
+ if (network) {
+ if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
+ const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS];
+
+ unsigned int comLen = 0;
+ if ((flags & 0x01) != 0) {
+ CertificateOfMembership com;
+ comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
+ peer->validateAndSetNetworkMembershipCertificate(network->id(),com);
+ }
+
+ if (!network->isAllowed(peer)) {
+ TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
+ _sendErrorNeedCertificate(RR,peer,network->id());
+ return true;
+ }
+
+ // Everything after flags must be adjusted based on the length
+ // of the certificate, if there was one...
+
+ const unsigned int etherType = at<uint16_t>(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
+ if (!network->config().permitsEtherType(etherType)) {
+ TRACE("dropped EXT_FRAME from %s(%s): ethertype %.4x not allowed on network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned int)etherType,(unsigned long long)network->id());
+ return true;
+ }
+
+ const MAC to(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO);
+ const MAC from(field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
+
+ if (to.isMulticast()) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: destination is multicast, must use MULTICAST_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
+ return true;
+ }
+
+ if ((!from)||(from.isMulticast())||(from == network->mac())) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
+ return true;
+ }
+
+ if (from != MAC(peer->address(),network->id())) {
+ if (network->config().permitsBridging(peer->address())) {
+ network->learnBridgeRoute(from,peer->address());
+ } else {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
+ return true;
+ }
+ } else if (to != network->mac()) {
+ if (!network->config().permitsBridging(RR->identity.address())) {
+ TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
+ return true;
+ }
+ }
+
+ const unsigned int payloadLen = size() - (comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD);
+ RR->node->putFrame(network->id(),network->userPtr(),from,to,etherType,0,field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,payloadLen),payloadLen);
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP);
+ } else {
+ TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
+ }
+ } catch ( ... ) {
+ TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t pid = packetId();
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_ECHO);
+ outp.append((uint64_t)pid);
+ if (size() > ZT_PACKET_IDX_PAYLOAD)
+ outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t now = RR->node->now();
+
+ // Iterate through 18-byte network,MAC,ADI tuples
+ for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
+ const uint64_t nwid = at<uint64_t>(ptr);
+ const MulticastGroup group(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14));
+ RR->mc->add(now,nwid,group,peer->address());
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ CertificateOfMembership com;
+
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+ while (ptr < size()) {
+ ptr += com.deserialize(*this,ptr);
+ peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com);
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
+
+ const unsigned int metaDataLength = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
+ const uint8_t *metaDataBytes = (const uint8_t *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength);
+
+ NetworkConfigRequestMetaData metaData;
+ bool haveNewStyleMetaData = false;
+ for(unsigned int i=0;i<metaDataLength;++i) {
+ if ((metaDataBytes[i] == 0)&&(i < (metaDataLength - 2))) {
+ haveNewStyleMetaData = true;
+ break;
+ }
+ }
+ if (haveNewStyleMetaData) {
+ Buffer<4096> md(metaDataBytes,metaDataLength);
+ metaData.deserialize(md,0); // the meta-data deserializer automatically skips old-style meta-data
+ } else {
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ const Dictionary oldStyleMetaData((const char *)metaDataBytes,metaDataLength);
+ metaData.majorVersion = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0);
+ metaData.minorVersion = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0);
+ metaData.revision = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0);
+#endif
+ }
+
+ //const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL;
+
+ const unsigned int h = hops();
+ const uint64_t pid = packetId();
+ peer->received(_localAddress,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP);
+
+ if (RR->localNetworkController) {
+ Buffer<8194> netconf;
+ switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) {
+
+ case NetworkController::NETCONF_QUERY_OK: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append(nwid);
+ outp.append((uint16_t)netconf.size());
+ outp.append(netconf.data(),(unsigned int)netconf.size());
+ outp.compress();
+ outp.armor(peer->key(),true);
+ if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check
+ //TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length());
+ } else {
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } break;
+
+ case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } break;
+
+ case NetworkController::NETCONF_QUERY_ACCESS_DENIED: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } break;
+
+ case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR:
+ // TRACE("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str());
+ break;
+
+ case NetworkController::NETCONF_QUERY_IGNORE:
+ break;
+
+ default:
+ TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()");
+ break;
+
+ }
+ } else {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } catch ( ... ) {
+ TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+ while ((ptr + 8) <= size()) {
+ uint64_t nwid = at<uint64_t>(ptr);
+ SharedPtr<Network> nw(RR->node->network(nwid));
+ if ((nw)&&(peer->address() == nw->controller()))
+ nw->requestConfiguration();
+ ptr += 8;
+ }
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
+ const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI));
+ const unsigned int gatherLimit = at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT);
+
+ //TRACE("<<MC %s(%s) GATHER up to %u in %.16llx/%s",source().toString().c_str(),_remoteAddress.toString().c_str(),gatherLimit,nwid,mg.toString().c_str());
+
+ if (gatherLimit) {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
+ outp.append(packetId());
+ outp.append(nwid);
+ mg.mac().appendTo(outp);
+ outp.append((uint32_t)mg.adi());
+ const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
+ if (gatheredLocally) {
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+
+#ifdef ZT_ENABLE_CLUSTER
+ if ((RR->cluster)&&(gatheredLocally < gatherLimit))
+ RR->cluster->sendDistributedQuery(*this);
+#endif
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID);
+ const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS];
+
+ const SharedPtr<Network> network(RR->node->network(nwid));
+ if (network) {
+ // Offset -- size of optional fields added to position of later fields
+ unsigned int offset = 0;
+
+ if ((flags & 0x01) != 0) {
+ CertificateOfMembership com;
+ offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
+ peer->validateAndSetNetworkMembershipCertificate(nwid,com);
+ }
+
+ // Check membership after we've read any included COM, since
+ // that cert might be what we needed.
+ if (!network->isAllowed(peer)) {
+ TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id());
+ _sendErrorNeedCertificate(RR,peer,network->id());
+ return true;
+ }
+
+ unsigned int gatherLimit = 0;
+ if ((flags & 0x02) != 0) {
+ gatherLimit = at<uint32_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT);
+ offset += 4;
+ }
+
+ MAC from;
+ if ((flags & 0x04) != 0) {
+ from.setTo(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC,6),6);
+ offset += 6;
+ } else {
+ from.fromAddress(peer->address(),nwid);
+ }
+
+ const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at<uint32_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI));
+ const unsigned int etherType = at<uint16_t>(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
+ const unsigned int payloadLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME);
+
+ //TRACE("<<MC FRAME %.16llx/%s from %s@%s flags %.2x length %u",nwid,to.toString().c_str(),from.toString().c_str(),peer->address().toString().c_str(),flags,payloadLen);
+
+ if ((payloadLen > 0)&&(payloadLen <= ZT_IF_MTU)) {
+ if (!to.mac().isMulticast()) {
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
+ return true;
+ }
+ if ((!from)||(from.isMulticast())||(from == network->mac())) {
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
+ return true;
+ }
+
+ if (from != MAC(peer->address(),network->id())) {
+ if (network->config().permitsBridging(peer->address())) {
+ network->learnBridgeRoute(from,peer->address());
+ } else {
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
+ return true;
+ }
+ }
+
+ RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,payloadLen),payloadLen);
+ }
+
+ if (gatherLimit) {
+ Packet outp(source(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME);
+ outp.append(packetId());
+ outp.append(nwid);
+ to.mac().appendTo(outp);
+ outp.append((uint32_t)to.adi());
+ outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
+ if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ }
+ } // else ignore -- not a member of this network
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const uint64_t now = RR->node->now();
+
+ // First, subject this to a rate limit
+ if (!peer->shouldRespondToDirectPathPush(now)) {
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ }
+
+ // Second, limit addresses by scope and type
+ uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6
+ memset(countPerScope,0,sizeof(countPerScope));
+
+ unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
+
+ while (count--) { // if ptr overflows Buffer will throw
+ // TODO: some flags are not yet implemented
+
+ unsigned int flags = (*this)[ptr++];
+ unsigned int extLen = at<uint16_t>(ptr); ptr += 2;
+ ptr += extLen; // unused right now
+ unsigned int addrType = (*this)[ptr++];
+ unsigned int addrLen = (*this)[ptr++];
+
+ switch(addrType) {
+ case 4: {
+ InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
+
+ bool redundant = false;
+ if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
+ peer->setClusterOptimalPathForAddressFamily(a);
+ } else {
+ redundant = peer->hasActivePathTo(now,a);
+ }
+
+ if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
+ if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
+ TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
+ peer->sendHELLO(InetAddress(),a,now);
+ } else {
+ TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
+ }
+ }
+ } break;
+ case 6: {
+ InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
+
+ bool redundant = false;
+ if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
+ peer->setClusterOptimalPathForAddressFamily(a);
+ } else {
+ redundant = peer->hasActivePathTo(now,a);
+ }
+
+ if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
+ if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
+ TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
+ peer->sendHELLO(InetAddress(),a,now);
+ } else {
+ TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
+ }
+ }
+ } break;
+ }
+ ptr += addrLen;
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ SharedPtr<Peer> originator(RR->topology->getPeer(originatorAddress));
+ if (!originator) {
+ RR->sw->requestWhois(originatorAddress);
+ return false;
+ }
+
+ const unsigned int flags = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 5);
+ const uint64_t timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7);
+ const uint64_t testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 15);
+
+ // Tracks total length of variable length fields, initialized to originator credential length below
+ unsigned int vlf;
+
+ // Originator credentials
+ const unsigned int originatorCredentialLength = vlf = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23);
+ uint64_t originatorCredentialNetworkId = 0;
+ if (originatorCredentialLength >= 1) {
+ switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) {
+ case 0x01: { // 64-bit network ID, originator must be controller
+ if (originatorCredentialLength >= 9)
+ originatorCredentialNetworkId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 26);
+ } break;
+ default: break;
+ }
+ }
+
+ // Add length of "additional fields," which are currently unused
+ vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 25 + vlf);
+
+ // Verify signature -- only tests signed by their originators are allowed
+ const unsigned int signatureLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 27 + vlf);
+ if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str());
+ return true;
+ }
+ vlf += signatureLength;
+
+ // Save this length so we can copy the immutable parts of this test
+ // into the one we send along to next hops.
+ const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
+
+ // Get previous hop's credential, if any
+ const unsigned int previousHopCredentialLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
+ CertificateOfMembership previousHopCom;
+ if (previousHopCredentialLength >= 1) {
+ switch((*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]) {
+ case 0x01: { // network certificate of membership for previous hop
+ const unsigned int phcl = previousHopCom.deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 32 + vlf);
+ if (phcl != (previousHopCredentialLength - 1)) {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): previous hop COM invalid (%u != %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),phcl,(previousHopCredentialLength - 1));
+ return true;
+ }
+ } break;
+ default: break;
+ }
+ }
+ vlf += previousHopCredentialLength;
+
+ // Check credentials (signature already verified)
+ NetworkConfig originatorCredentialNetworkConfig;
+ if (originatorCredentialNetworkId) {
+ if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) {
+ SharedPtr<Network> nw(RR->node->network(originatorCredentialNetworkId));
+ if ((nw)&&(nw->hasConfig())) {
+ originatorCredentialNetworkConfig = nw->config();
+ if ( ( (originatorCredentialNetworkConfig.isPublic()) || (peer->address() == originatorAddress) || ((originatorCredentialNetworkConfig.com)&&(previousHopCom)&&(originatorCredentialNetworkConfig.com.agreesWith(previousHopCom))) ) ) {
+ TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str());
+ return true;
+ }
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+ return true;
+ }
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID as credential, is not controller for %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+ return true;
+ }
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str());
+ return true;
+ }
+
+ const uint64_t now = RR->node->now();
+
+ unsigned int breadth = 0;
+ Address nextHop[256]; // breadth is a uin8_t, so this is the max
+ InetAddress nextHopBestPathAddress[256];
+ unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf;
+ if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) {
+ // unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]
+ breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf];
+ for(unsigned int h=0;h<breadth;++h) {
+ nextHop[h].setTo(field(remainingHopsPtr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ remainingHopsPtr += ZT_ADDRESS_LENGTH;
+ SharedPtr<Peer> nhp(RR->topology->getPeer(nextHop[h]));
+ if (nhp) {
+ Path *const rp = nhp->getBestPath(now);
+ if (rp)
+ nextHopBestPathAddress[h] = rp->address();
+ }
+ }
+ }
+
+ // Report back to originator, depending on flags and whether we are last hop
+ if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) {
+ Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT);
+ outp.append((uint64_t)timestamp);
+ outp.append((uint64_t)testId);
+ outp.append((uint64_t)0); // field reserved for future use
+ outp.append((uint8_t)ZT_VENDOR_ZEROTIER);
+ outp.append((uint8_t)ZT_PROTO_VERSION);
+ outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR);
+ outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR);
+ outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
+ outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
+ outp.append((uint16_t)0); // error code, currently unused
+ outp.append((uint64_t)0); // flags, currently unused
+ outp.append((uint64_t)packetId());
+ peer->address().appendTo(outp);
+ outp.append((uint8_t)hops());
+ _localAddress.serialize(outp);
+ _remoteAddress.serialize(outp);
+ outp.append((uint16_t)0); // no additional fields
+ outp.append((uint8_t)breadth);
+ for(unsigned int h=0;h<breadth;++h) {
+ nextHop[h].appendTo(outp);
+ nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress
+ }
+ RR->sw->send(outp,true,0);
+ }
+
+ // If there are next hops, forward the test along through the graph
+ if (breadth > 0) {
+ Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
+ outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature);
+ const unsigned int previousHopCredentialPos = outp.size();
+ outp.append((uint16_t)0); // no previous hop credentials: default
+ if ((originatorCredentialNetworkConfig)&&(!originatorCredentialNetworkConfig.isPublic())&&(originatorCredentialNetworkConfig.com)) {
+ outp.append((uint8_t)0x01); // COM
+ originatorCredentialNetworkConfig.com.serialize(outp);
+ outp.setAt<uint16_t>(previousHopCredentialPos,(uint16_t)(outp.size() - (previousHopCredentialPos + 2)));
+ }
+ if (remainingHopsPtr < size())
+ outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
+
+ for(unsigned int h=0;h<breadth;++h) {
+ if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid
+ outp.newInitializationVector();
+ outp.setDestination(nextHop[h]);
+ RR->sw->send(outp,true,originatorCredentialNetworkId);
+ }
+ }
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP);
+ } catch ( ... ) {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ ZT_CircuitTestReport report;
+ memset(&report,0,sizeof(report));
+
+ report.current = peer->address().toInt();
+ report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
+ report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
+ report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
+ report.remoteTimestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 16);
+ report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
+ report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
+ report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
+ report.errorCode = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 34);
+ report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]);
+ report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25];
+ report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26];
+ report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27];
+ report.revision = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 28);
+ report.platform = (enum ZT_Platform)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 30);
+ report.architecture = (enum ZT_Architecture)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 32);
+
+ const unsigned int receivedOnLocalAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58);
+ const unsigned int receivedFromRemoteAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen);
+
+ unsigned int nhptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen;
+ nhptr += at<uint16_t>(nhptr) + 2; // add "additional field" length, which right now will be zero
+
+ report.nextHopCount = (*this)[nhptr++];
+ if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible
+ report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH;
+ for(unsigned int h=0;h<report.nextHopCount;++h) {
+ report.nextHops[h].address = Address(field(nhptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); nhptr += ZT_ADDRESS_LENGTH;
+ nhptr += reinterpret_cast<InetAddress *>(&(report.nextHops[h].physicalAddress))->deserialize(*this,nhptr);
+ }
+
+ RR->node->postCircuitTestReport(&report);
+ } catch ( ... ) {
+ TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
+{
+ try {
+ // Right now this is only allowed from root servers -- may be allowed from controllers and relays later.
+ if (RR->topology->isRoot(peer->identity())) {
+ const uint64_t pid = packetId();
+ const unsigned int difficulty = (*this)[ZT_PACKET_IDX_PAYLOAD + 1];
+ const unsigned int challengeLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 2);
+ if (challengeLength > ZT_PROTO_MAX_PACKET_LENGTH)
+ return true; // sanity check, drop invalid size
+ const unsigned char *challenge = field(ZT_PACKET_IDX_PAYLOAD + 4,challengeLength);
+
+ switch((*this)[ZT_PACKET_IDX_PAYLOAD]) {
+
+ // Salsa20/12+SHA512 hashcash
+ case 0x01: {
+ if (difficulty <= 14) {
+ unsigned char result[16];
+ computeSalsa2012Sha512ProofOfWork(difficulty,challenge,challengeLength,result);
+ TRACE("PROOF_OF_WORK computed for %s: difficulty==%u, challengeLength==%u, result: %.16llx%.16llx",peer->address().toString().c_str(),difficulty,challengeLength,Utils::ntoh(*(reinterpret_cast<const uint64_t *>(result))),Utils::ntoh(*(reinterpret_cast<const uint64_t *>(result + 8))));
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK);
+ outp.append(pid);
+ outp.append((uint16_t)sizeof(result));
+ outp.append(result,sizeof(result));
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } else {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } break;
+
+ default:
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ break;
+ }
+
+ peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP);
+ } else {
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ } catch ( ... ) {
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+ }
+ return true;
+}
+
+void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16])
+{
+ unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
+ char candidatebuf[ZT_PROTO_MAX_PACKET_LENGTH + 256];
+ unsigned char shabuf[ZT_SHA512_DIGEST_LEN];
+ const uint64_t s20iv = 0; // zero IV for Salsa20
+ char *const candidate = (char *)(( ((uintptr_t)&(candidatebuf[0])) | 0xf ) + 1); // align to 16-byte boundary to ensure that uint64_t type punning of initial nonce is okay
+ Salsa20 s20;
+ unsigned int d;
+ unsigned char *p;
+
+ Utils::getSecureRandom(candidate,16);
+ memcpy(candidate + 16,challenge,challengeLength);
+
+ if (difficulty > 512)
+ difficulty = 512; // sanity check
+
+try_salsa2012sha512_again:
+ ++*(reinterpret_cast<volatile uint64_t *>(candidate));
+
+ SHA512::hash(shabuf,candidate,16 + challengeLength);
+ s20.init(shabuf,256,&s20iv);
+ memset(salsabuf,0,sizeof(salsabuf));
+ s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf));
+ SHA512::hash(shabuf,salsabuf,sizeof(salsabuf));
+
+ d = difficulty;
+ p = shabuf;
+ while (d >= 8) {
+ if (*(p++))
+ goto try_salsa2012sha512_again;
+ d -= 8;
+ }
+ if (d > 0) {
+ if ( ((((unsigned int)*p) << d) & 0xff00) != 0 )
+ goto try_salsa2012sha512_again;
+ }
+
+ memcpy(result,candidate,16);
+}
+
+bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16])
+{
+ unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
+ char candidate[ZT_PROTO_MAX_PACKET_LENGTH + 256];
+ unsigned char shabuf[ZT_SHA512_DIGEST_LEN];
+ const uint64_t s20iv = 0; // zero IV for Salsa20
+ Salsa20 s20;
+ unsigned int d;
+ unsigned char *p;
+
+ if (difficulty > 512)
+ difficulty = 512; // sanity check
+
+ memcpy(candidate,proposedResult,16);
+ memcpy(candidate + 16,challenge,challengeLength);
+
+ SHA512::hash(shabuf,candidate,16 + challengeLength);
+ s20.init(shabuf,256,&s20iv);
+ memset(salsabuf,0,sizeof(salsabuf));
+ s20.encrypt12(salsabuf,salsabuf,sizeof(salsabuf));
+ SHA512::hash(shabuf,salsabuf,sizeof(salsabuf));
+
+ d = difficulty;
+ p = shabuf;
+ while (d >= 8) {
+ if (*(p++))
+ return false;
+ d -= 8;
+ }
+ if (d > 0) {
+ if ( ((((unsigned int)*p) << d) & 0xff00) != 0 )
+ return false;
+ }
+
+ return true;
+}
+
+void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid)
+{
+ Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)verb());
+ outp.append(packetId());
+ outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/IncomingPacket.hpp b/zerotierone/node/IncomingPacket.hpp
new file mode 100644
index 0000000..96e46c0
--- /dev/null
+++ b/zerotierone/node/IncomingPacket.hpp
@@ -0,0 +1,195 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_INCOMINGPACKET_HPP
+#define ZT_INCOMINGPACKET_HPP
+
+#include <stdexcept>
+
+#include "Packet.hpp"
+#include "InetAddress.hpp"
+#include "Utils.hpp"
+#include "MulticastGroup.hpp"
+#include "Peer.hpp"
+
+/*
+ * The big picture:
+ *
+ * tryDecode gets called for a given fully-assembled packet until it returns
+ * true or the packet's time to live has been exceeded, in which case it is
+ * discarded as failed decode. Any exception thrown by tryDecode also causes
+ * the packet to be discarded.
+ *
+ * Thus a return of false from tryDecode() indicates that it should be called
+ * again. Logic is very simple as to when, and it's in doAnythingWaitingForPeer
+ * in Switch. This might be expanded to be more fine grained in the future.
+ *
+ * A return value of true indicates that the packet is done. tryDecode must
+ * never be called again after that.
+ */
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class Network;
+
+/**
+ * Subclass of packet that handles the decoding of it
+ */
+class IncomingPacket : public Packet
+{
+public:
+ IncomingPacket() :
+ Packet(),
+ _receiveTime(0),
+ _localAddress(),
+ _remoteAddress()
+ {
+ }
+
+ IncomingPacket(const IncomingPacket &p)
+ {
+ // All fields including InetAddress are memcpy'able
+ memcpy(this,&p,sizeof(IncomingPacket));
+ }
+
+ /**
+ * Create a new packet-in-decode
+ *
+ * @param data Packet data
+ * @param len Packet length
+ * @param localAddress Local interface address
+ * @param remoteAddress Address from which packet came
+ * @param now Current time
+ * @throws std::out_of_range Range error processing packet
+ */
+ IncomingPacket(const void *data,unsigned int len,const InetAddress &localAddress,const InetAddress &remoteAddress,uint64_t now) :
+ Packet(data,len),
+ _receiveTime(now),
+ _localAddress(localAddress),
+ _remoteAddress(remoteAddress)
+ {
+ }
+
+ inline IncomingPacket &operator=(const IncomingPacket &p)
+ {
+ // All fields including InetAddress are memcpy'able
+ memcpy(this,&p,sizeof(IncomingPacket));
+ return *this;
+ }
+
+ /**
+ * Init packet-in-decode in place
+ *
+ * @param data Packet data
+ * @param len Packet length
+ * @param localAddress Local interface address
+ * @param remoteAddress Address from which packet came
+ * @param now Current time
+ * @throws std::out_of_range Range error processing packet
+ */
+ inline void init(const void *data,unsigned int len,const InetAddress &localAddress,const InetAddress &remoteAddress,uint64_t now)
+ {
+ copyFrom(data,len);
+ _receiveTime = now;
+ _localAddress = localAddress;
+ _remoteAddress = remoteAddress;
+ }
+
+ /**
+ * Attempt to decode this packet
+ *
+ * Note that this returns 'true' if processing is complete. This says nothing
+ * about whether the packet was valid. A rejection is 'complete.'
+ *
+ * Once true is returned, this must not be called again. The packet's state
+ * may no longer be valid. The only exception is deferred decoding. In this
+ * case true is returned to indicate to the normal decode path that it is
+ * finished with the packet. The packet will have added itself to the
+ * deferred queue and will expect tryDecode() to be called one more time
+ * with deferred set to true.
+ *
+ * Deferred decoding is performed by DeferredPackets.cpp and should not be
+ * done elsewhere. Under deferred decoding packets only get one shot and
+ * so the return value of tryDecode() is ignored.
+ *
+ * @param RR Runtime environment
+ * @param deferred If true, this is a deferred decode and the return is ignored
+ * @return True if decoding and processing is complete, false if caller should try again
+ */
+ bool tryDecode(const RuntimeEnvironment *RR,bool deferred);
+
+ /**
+ * @return Time of packet receipt / start of decode
+ */
+ inline uint64_t receiveTime() const throw() { return _receiveTime; }
+
+ /**
+ * Compute the Salsa20/12+SHA512 proof of work function
+ *
+ * @param difficulty Difficulty in bits (max: 64)
+ * @param challenge Challenge string
+ * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH)
+ * @param result Buffer to fill with 16-byte result
+ */
+ static void computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16]);
+
+ /**
+ * Verify the result of Salsa20/12+SHA512 proof of work
+ *
+ * @param difficulty Difficulty in bits (max: 64)
+ * @param challenge Challenge bytes
+ * @param challengeLength Length of challenge in bytes (max allowed: ZT_PROTO_MAX_PACKET_LENGTH)
+ * @param proposedResult Result supplied by client
+ * @return True if result is valid
+ */
+ static bool testSalsa2012Sha512ProofOfWorkResult(unsigned int difficulty,const void *challenge,unsigned int challengeLength,const unsigned char proposedResult[16]);
+
+private:
+ // These are called internally to handle packet contents once it has
+ // been authenticated, decrypted, decompressed, and classified.
+ bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer); // can be called with NULL peer, while all others cannot
+ bool _doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+ bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
+
+ // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to communicate
+ void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid);
+
+ uint64_t _receiveTime;
+ InetAddress _localAddress;
+ InetAddress _remoteAddress;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/InetAddress.cpp b/zerotierone/node/InetAddress.cpp
new file mode 100644
index 0000000..dca772e
--- /dev/null
+++ b/zerotierone/node/InetAddress.cpp
@@ -0,0 +1,446 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+const InetAddress InetAddress::LO4((const void *)("\x7f\x00\x00\x01"),4,0);
+const InetAddress InetAddress::LO6((const void *)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"),16,0);
+
+InetAddress::IpScope InetAddress::ipScope() const
+ throw()
+{
+ switch(ss_family) {
+
+ case AF_INET: {
+ const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
+ switch(ip >> 24) {
+ case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
+ case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
+ case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
+ case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
+ case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
+ case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
+ case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
+ case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
+ case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
+ case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
+ case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
+ case 0x2c: return IP_SCOPE_PSEUDOPRIVATE; // 44.0.0.0/8 (Amateur Radio)
+ case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
+ case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
+ case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
+ case 0x64:
+ if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_SHARED; // 100.64.0.0/10
+ break;
+ case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
+ case 0xa9:
+ if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
+ break;
+ case 0xac:
+ if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12
+ break;
+ case 0xc0:
+ if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
+ break;
+ case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
+ }
+ switch(ip >> 28) {
+ case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
+ case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
+ }
+ return IP_SCOPE_GLOBAL;
+ } break;
+
+ case AF_INET6: {
+ const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ if ((ip[0] & 0xf0) == 0xf0) {
+ if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8
+ if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
+ unsigned int k = 2;
+ while ((!ip[k])&&(k < 15)) ++k;
+ if ((k == 15)&&(ip[15] == 0x01))
+ return IP_SCOPE_LOOPBACK; // fe80::1/128
+ else return IP_SCOPE_LINK_LOCAL; // fe80::/10
+ }
+ if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7
+ }
+ unsigned int k = 0;
+ while ((!ip[k])&&(k < 15)) ++k;
+ if (k == 15) { // all 0's except last byte
+ if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128
+ if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128
+ }
+ return IP_SCOPE_GLOBAL;
+ } break;
+
+ }
+
+ return IP_SCOPE_NONE;
+}
+
+void InetAddress::set(const std::string &ip,unsigned int port)
+ throw()
+{
+ memset(this,0,sizeof(InetAddress));
+ if (ip.find(':') != std::string::npos) {
+ struct sockaddr_in6 *sin6 = reinterpret_cast<struct sockaddr_in6 *>(this);
+ ss_family = AF_INET6;
+ sin6->sin6_port = Utils::hton((uint16_t)port);
+ if (inet_pton(AF_INET6,ip.c_str(),(void *)&(sin6->sin6_addr.s6_addr)) <= 0)
+ memset(this,0,sizeof(InetAddress));
+ } else {
+ struct sockaddr_in *sin = reinterpret_cast<struct sockaddr_in *>(this);
+ ss_family = AF_INET;
+ sin->sin_port = Utils::hton((uint16_t)port);
+ if (inet_pton(AF_INET,ip.c_str(),(void *)&(sin->sin_addr.s_addr)) <= 0)
+ memset(this,0,sizeof(InetAddress));
+ }
+}
+
+void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
+ throw()
+{
+ memset(this,0,sizeof(InetAddress));
+ if (ipLen == 4) {
+ uint32_t ipb[1];
+ memcpy(ipb,ipBytes,4);
+ ss_family = AF_INET;
+ reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
+ reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
+ } else if (ipLen == 16) {
+ ss_family = AF_INET6;
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16);
+ reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
+ }
+}
+
+std::string InetAddress::toString() const
+{
+ char buf[128];
+ switch(ss_family) {
+ case AF_INET:
+ Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d/%d",
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[0],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[1],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[2],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[3],
+ (int)Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port))
+ );
+ return std::string(buf);
+ case AF_INET6:
+ Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%d",
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[0]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[1]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[2]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[3]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[4]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[5]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[6]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[7]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[8]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[9]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[10]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[11]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[12]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[13]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[14]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[15]),
+ (int)Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port))
+ );
+ return std::string(buf);
+ }
+ return std::string();
+}
+
+std::string InetAddress::toIpString() const
+{
+ char buf[128];
+ switch(ss_family) {
+ case AF_INET:
+ Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d",
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[0],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[1],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[2],
+ (int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[3]
+ );
+ return std::string(buf);
+ case AF_INET6:
+ Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[0]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[1]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[2]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[3]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[4]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[5]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[6]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[7]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[8]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[9]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[10]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[11]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[12]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[13]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[14]),
+ (int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[15])
+ );
+ return std::string(buf);
+ }
+ return std::string();
+}
+
+void InetAddress::fromString(const std::string &ipSlashPort)
+{
+ const std::size_t slashAt = ipSlashPort.find('/');
+ if (slashAt == std::string::npos) {
+ set(ipSlashPort,0);
+ } else {
+ long p = strtol(ipSlashPort.substr(slashAt+1).c_str(),(char **)0,10);
+ if ((p > 0)&&(p <= 0xffff))
+ set(ipSlashPort.substr(0,slashAt),(unsigned int)p);
+ else set(ipSlashPort.substr(0,slashAt),0);
+ }
+}
+
+InetAddress InetAddress::netmask() const
+{
+ InetAddress r(*this);
+ switch(r.ss_family) {
+ case AF_INET:
+ reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+ break;
+ case AF_INET6: {
+ uint64_t nm[2];
+ const unsigned int bits = netmaskBits();
+ nm[0] = Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
+ nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
+ } break;
+ }
+ return r;
+}
+
+InetAddress InetAddress::broadcast() const
+{
+ if (ss_family == AF_INET) {
+ InetAddress r(*this);
+ reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+ return r;
+ }
+ return InetAddress();
+}
+
+InetAddress InetAddress::network() const
+{
+ InetAddress r(*this);
+ switch(r.ss_family) {
+ case AF_INET:
+ reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+ break;
+ case AF_INET6: {
+ uint64_t nm[2];
+ const unsigned int bits = netmaskBits();
+ memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
+ nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
+ nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
+ } break;
+ }
+ return r;
+}
+
+bool InetAddress::containsAddress(const InetAddress &addr) const
+{
+ if (addr.ss_family == ss_family) {
+ switch(ss_family) {
+ case AF_INET: {
+ const unsigned int bits = netmaskBits();
+ return ( (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) >> (32 - bits)) );
+ }
+ case AF_INET6: {
+ const InetAddress mask(netmask());
+ const uint8_t *m = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&mask)->sin6_addr.s6_addr);
+ const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr);
+ const uint8_t *b = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ for(unsigned int i=0;i<16;++i) {
+ if ((a[i] & m[i]) != b[i])
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool InetAddress::isNetwork() const
+ throw()
+{
+ switch(ss_family) {
+ case AF_INET: {
+ unsigned int bits = netmaskBits();
+ if (bits <= 0)
+ return false;
+ if (bits >= 32)
+ return false;
+ uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
+ return ((ip & (0xffffffff >> bits)) == 0);
+ }
+ case AF_INET6: {
+ unsigned int bits = netmaskBits();
+ if (bits <= 0)
+ return false;
+ if (bits >= 128)
+ return false;
+ const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ unsigned int p = bits / 8;
+ if ((ip[p++] & (0xff >> (bits % 8))) != 0)
+ return false;
+ while (p < 16) {
+ if (ip[p++])
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool InetAddress::operator==(const InetAddress &a) const
+ throw()
+{
+ if (ss_family == a.ss_family) {
+ switch(ss_family) {
+ case AF_INET:
+ return (
+ (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port)&&
+ (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr));
+ break;
+ case AF_INET6:
+ return (
+ (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port)&&
+ (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo)&&
+ (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0)&&
+ (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id));
+ break;
+ default:
+ return (memcmp(this,&a,sizeof(InetAddress)) == 0);
+ }
+ }
+ return false;
+}
+
+bool InetAddress::operator<(const InetAddress &a) const
+ throw()
+{
+ if (ss_family < a.ss_family)
+ return true;
+ else if (ss_family == a.ss_family) {
+ switch(ss_family) {
+ case AF_INET:
+ if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port)
+ return true;
+ else if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_port == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_port) {
+ if (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr < reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr)
+ return true;
+ }
+ break;
+ case AF_INET6:
+ if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port)
+ return true;
+ else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_port) {
+ if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo)
+ return true;
+ else if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_flowinfo == reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_flowinfo) {
+ if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) < 0)
+ return true;
+ else if (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0) {
+ if (reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_scope_id < reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_scope_id)
+ return true;
+ }
+ }
+ }
+ break;
+ default:
+ return (memcmp(this,&a,sizeof(InetAddress)) < 0);
+ }
+ }
+ return false;
+}
+
+InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
+ throw()
+{
+ struct sockaddr_in6 sin6;
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr.s6_addr[0] = 0xfe;
+ sin6.sin6_addr.s6_addr[1] = 0x80;
+ sin6.sin6_addr.s6_addr[2] = 0x00;
+ sin6.sin6_addr.s6_addr[3] = 0x00;
+ sin6.sin6_addr.s6_addr[4] = 0x00;
+ sin6.sin6_addr.s6_addr[5] = 0x00;
+ sin6.sin6_addr.s6_addr[6] = 0x00;
+ sin6.sin6_addr.s6_addr[7] = 0x00;
+ sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
+ sin6.sin6_addr.s6_addr[9] = mac[1];
+ sin6.sin6_addr.s6_addr[10] = mac[2];
+ sin6.sin6_addr.s6_addr[11] = 0xff;
+ sin6.sin6_addr.s6_addr[12] = 0xfe;
+ sin6.sin6_addr.s6_addr[13] = mac[3];
+ sin6.sin6_addr.s6_addr[14] = mac[4];
+ sin6.sin6_addr.s6_addr[15] = mac[5];
+ sin6.sin6_port = Utils::hton((uint16_t)64);
+ return InetAddress(sin6);
+}
+
+InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
+ throw()
+{
+ InetAddress r;
+ struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr.s6_addr[0] = 0xfd;
+ sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
+ sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48);
+ sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40);
+ sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32);
+ sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24);
+ sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16);
+ sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8);
+ sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid;
+ sin6->sin6_addr.s6_addr[9] = 0x99;
+ sin6->sin6_addr.s6_addr[10] = 0x93;
+ sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32);
+ sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24);
+ sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16);
+ sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
+ sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
+ sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
+ return r;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/InetAddress.hpp b/zerotierone/node/InetAddress.hpp
new file mode 100644
index 0000000..b60a5a3
--- /dev/null
+++ b/zerotierone/node/InetAddress.hpp
@@ -0,0 +1,506 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_INETADDRESS_HPP
+#define ZT_INETADDRESS_HPP
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
+#include "Utils.hpp"
+#include "MAC.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Maximum integer value of enum IpScope
+ */
+#define ZT_INETADDRESS_MAX_SCOPE 7
+
+/**
+ * Extends sockaddr_storage with friendly C++ methods
+ *
+ * This is basically a "mixin" for sockaddr_storage. It adds methods and
+ * operators, but does not modify the structure. This can be cast to/from
+ * sockaddr_storage and used interchangeably. DO NOT change this by e.g.
+ * adding non-static fields, since much code depends on this identity.
+ */
+struct InetAddress : public sockaddr_storage
+{
+ /**
+ * Loopback IPv4 address (no port)
+ */
+ static const InetAddress LO4;
+
+ /**
+ * Loopback IPV6 address (no port)
+ */
+ static const InetAddress LO6;
+
+ /**
+ * IP address scope
+ *
+ * Note that these values are in ascending order of path preference and
+ * MUST remain that way or Path must be changed to reflect. Also be sure
+ * to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
+ */
+ enum IpScope
+ {
+ IP_SCOPE_NONE = 0, // NULL or not an IP address
+ IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs
+ IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
+ IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted"
+ IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others)
+ IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL
+ IP_SCOPE_SHARED = 6, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT
+ IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
+ };
+
+ InetAddress() throw() { memset(this,0,sizeof(InetAddress)); }
+ InetAddress(const InetAddress &a) throw() { memcpy(this,&a,sizeof(InetAddress)); }
+ InetAddress(const InetAddress *a) throw() { memcpy(this,a,sizeof(InetAddress)); }
+ InetAddress(const struct sockaddr_storage &ss) throw() { *this = ss; }
+ InetAddress(const struct sockaddr_storage *ss) throw() { *this = ss; }
+ InetAddress(const struct sockaddr &sa) throw() { *this = sa; }
+ InetAddress(const struct sockaddr *sa) throw() { *this = sa; }
+ InetAddress(const struct sockaddr_in &sa) throw() { *this = sa; }
+ InetAddress(const struct sockaddr_in *sa) throw() { *this = sa; }
+ InetAddress(const struct sockaddr_in6 &sa) throw() { *this = sa; }
+ InetAddress(const struct sockaddr_in6 *sa) throw() { *this = sa; }
+ InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) throw() { this->set(ipBytes,ipLen,port); }
+ InetAddress(const uint32_t ipv4,unsigned int port) throw() { this->set(&ipv4,4,port); }
+ InetAddress(const std::string &ip,unsigned int port) throw() { this->set(ip,port); }
+ InetAddress(const std::string &ipSlashPort) throw() { this->fromString(ipSlashPort); }
+ InetAddress(const char *ipSlashPort) throw() { this->fromString(std::string(ipSlashPort)); }
+
+ inline InetAddress &operator=(const InetAddress &a)
+ throw()
+ {
+ if (&a != this)
+ memcpy(this,&a,sizeof(InetAddress));
+ return *this;
+ }
+
+ inline InetAddress &operator=(const InetAddress *a)
+ throw()
+ {
+ if (a != this)
+ memcpy(this,a,sizeof(InetAddress));
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_storage &ss)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(&ss) != this)
+ memcpy(this,&ss,sizeof(InetAddress));
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_storage *ss)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(ss) != this)
+ memcpy(this,ss,sizeof(InetAddress));
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_in &sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,&sa,sizeof(struct sockaddr_in));
+ }
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_in *sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,sa,sizeof(struct sockaddr_in));
+ }
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_in6 &sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,&sa,sizeof(struct sockaddr_in6));
+ }
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr_in6 *sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ memcpy(this,sa,sizeof(struct sockaddr_in6));
+ }
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr &sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(&sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ switch(sa.sa_family) {
+ case AF_INET:
+ memcpy(this,&sa,sizeof(struct sockaddr_in));
+ break;
+ case AF_INET6:
+ memcpy(this,&sa,sizeof(struct sockaddr_in6));
+ break;
+ }
+ }
+ return *this;
+ }
+
+ inline InetAddress &operator=(const struct sockaddr *sa)
+ throw()
+ {
+ if (reinterpret_cast<const InetAddress *>(sa) != this) {
+ memset(this,0,sizeof(InetAddress));
+ switch(sa->sa_family) {
+ case AF_INET:
+ memcpy(this,sa,sizeof(struct sockaddr_in));
+ break;
+ case AF_INET6:
+ memcpy(this,sa,sizeof(struct sockaddr_in6));
+ break;
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * @return IP scope classification (e.g. loopback, link-local, private, global)
+ */
+ IpScope ipScope() const
+ throw();
+
+ /**
+ * Set from a string-format IP and a port
+ *
+ * @param ip IP address in V4 or V6 ASCII notation
+ * @param port Port or 0 for none
+ */
+ void set(const std::string &ip,unsigned int port)
+ throw();
+
+ /**
+ * Set from a raw IP and port number
+ *
+ * @param ipBytes Bytes of IP address in network byte order
+ * @param ipLen Length of IP address: 4 or 16
+ * @param port Port number or 0 for none
+ */
+ void set(const void *ipBytes,unsigned int ipLen,unsigned int port)
+ throw();
+
+ /**
+ * Set the port component
+ *
+ * @param port Port, 0 to 65535
+ */
+ inline void setPort(unsigned int port)
+ throw()
+ {
+ switch(ss_family) {
+ case AF_INET:
+ reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
+ break;
+ case AF_INET6:
+ reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
+ break;
+ }
+ }
+
+ /**
+ * @return ASCII IP/port format representation
+ */
+ std::string toString() const;
+
+ /**
+ * @return IP portion only, in ASCII string format
+ */
+ std::string toIpString() const;
+
+ /**
+ * @param ipSlashPort ASCII IP/port format notation
+ */
+ void fromString(const std::string &ipSlashPort);
+
+ /**
+ * @return Port or 0 if no port component defined
+ */
+ inline unsigned int port() const
+ throw()
+ {
+ switch(ss_family) {
+ case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
+ case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port));
+ default: return 0;
+ }
+ }
+
+ /**
+ * Alias for port()
+ *
+ * This just aliases port() to make code more readable when netmask bits
+ * are stuffed there, as they are in Network, EthernetTap, and a few other
+ * spots.
+ *
+ * @return Netmask bits
+ */
+ inline unsigned int netmaskBits() const throw() { return port(); }
+
+ /**
+ * Alias for port()
+ *
+ * This just aliases port() because for gateways we use this field to
+ * store the gateway metric.
+ *
+ * @return Gateway metric
+ */
+ inline unsigned int metric() const throw() { return port(); }
+
+ /**
+ * Construct a full netmask as an InetAddress
+ *
+ * @return Netmask such as 255.255.255.0 if this address is /24 (port field will be unchanged)
+ */
+ InetAddress netmask() const;
+
+ /**
+ * Constructs a broadcast address from a network/netmask address
+ *
+ * This is only valid for IPv4 and will return a NULL InetAddress for other
+ * address families.
+ *
+ * @return Broadcast address (only IP portion is meaningful)
+ */
+ InetAddress broadcast() const;
+
+ /**
+ * Return the network -- a.k.a. the IP ANDed with the netmask
+ *
+ * @return Network e.g. 10.0.1.0/24 from 10.0.1.200/24
+ */
+ InetAddress network() const;
+
+ /**
+ * Test whether this IP/netmask contains this address
+ *
+ * @param addr Address to check
+ * @return True if this IP/netmask (route) contains this address
+ */
+ bool containsAddress(const InetAddress &addr) const;
+
+ /**
+ * @return True if this is an IPv4 address
+ */
+ inline bool isV4() const throw() { return (ss_family == AF_INET); }
+
+ /**
+ * @return True if this is an IPv6 address
+ */
+ inline bool isV6() const throw() { return (ss_family == AF_INET6); }
+
+ /**
+ * @return pointer to raw address bytes or NULL if not available
+ */
+ inline const void *rawIpData() const
+ throw()
+ {
+ switch(ss_family) {
+ case AF_INET: return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
+ case AF_INET6: return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ default: return 0;
+ }
+ }
+
+ /**
+ * Performs an IP-only comparison or, if that is impossible, a memcmp()
+ *
+ * @param a InetAddress to compare again
+ * @return True if only IP portions are equal (false for non-IP or null addresses)
+ */
+ inline bool ipsEqual(const InetAddress &a) const
+ {
+ if (ss_family == a.ss_family) {
+ if (ss_family == AF_INET)
+ return (reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const struct sockaddr_in *>(&a)->sin_addr.s_addr);
+ if (ss_family == AF_INET6)
+ return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr,16) == 0);
+ return (memcmp(this,&a,sizeof(InetAddress)) == 0);
+ }
+ return false;
+ }
+
+ /**
+ * Set to null/zero
+ */
+ inline void zero() throw() { memset(this,0,sizeof(InetAddress)); }
+
+ /**
+ * Check whether this is a network/route rather than an IP assignment
+ *
+ * A network is an IP/netmask where everything after the netmask is
+ * zero e.g. 10.0.0.0/8.
+ *
+ * @return True if everything after netmask bits is zero
+ */
+ bool isNetwork() const
+ throw();
+
+ /**
+ * @return True if address family is non-zero
+ */
+ inline operator bool() const throw() { return (ss_family != 0); }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ // This is used in the protocol and must be the same as describe in places
+ // like VERB_HELLO in Packet.hpp.
+ switch(ss_family) {
+ case AF_INET:
+ b.append((uint8_t)0x04);
+ b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4);
+ b.append((uint16_t)port()); // just in case sin_port != uint16_t
+ return;
+ case AF_INET6:
+ b.append((uint8_t)0x06);
+ b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
+ b.append((uint16_t)port()); // just in case sin_port != uint16_t
+ return;
+ default:
+ b.append((uint8_t)0);
+ return;
+ }
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ memset(this,0,sizeof(InetAddress));
+ unsigned int p = startAt;
+ switch(b[p++]) {
+ case 0:
+ return 1;
+ case 0x01:
+ // TODO: Ethernet address (but accept for forward compatibility)
+ return 7;
+ case 0x02:
+ // TODO: Bluetooth address (but accept for forward compatibility)
+ return 7;
+ case 0x03:
+ // TODO: Other address types (but accept for forward compatibility)
+ // These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc.
+ return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
+ case 0x04:
+ ss_family = AF_INET;
+ memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
+ reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
+ break;
+ case 0x06:
+ ss_family = AF_INET6;
+ memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
+ reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
+ break;
+ default:
+ throw std::invalid_argument("invalid serialized InetAddress");
+ }
+ return (p - startAt);
+ }
+
+ bool operator==(const InetAddress &a) const throw();
+ bool operator<(const InetAddress &a) const throw();
+ inline bool operator!=(const InetAddress &a) const throw() { return !(*this == a); }
+ inline bool operator>(const InetAddress &a) const throw() { return (a < *this); }
+ inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); }
+ inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); }
+
+ /**
+ * @param mac MAC address seed
+ * @return IPv6 link-local address
+ */
+ static InetAddress makeIpv6LinkLocal(const MAC &mac)
+ throw();
+
+ /**
+ * Compute private IPv6 unicast address from network ID and ZeroTier address
+ *
+ * This generates a private unicast IPv6 address that is mostly compliant
+ * with the letter of RFC4193 and certainly compliant in spirit.
+ *
+ * RFC4193 specifies a format of:
+ *
+ * | 7 bits |1| 40 bits | 16 bits | 64 bits |
+ * | Prefix |L| Global ID | Subnet ID | Interface ID |
+ *
+ * The 'L' bit is set to 1, yielding an address beginning with 0xfd. Then
+ * the network ID is filled into the global ID, subnet ID, and first byte
+ * of the "interface ID" field. Since the first 40 bits of the network ID
+ * is the unique ZeroTier address of its controller, this makes a very
+ * good random global ID. Since network IDs have 24 more bits, we let it
+ * overflow into the interface ID.
+ *
+ * After that we pad with two bytes: 0x99, 0x93, namely the default ZeroTier
+ * port in hex.
+ *
+ * Finally we fill the remaining 40 bits of the interface ID field with
+ * the 40-bit unique ZeroTier device ID of the network member.
+ *
+ * This yields a valid RFC4193 address with a random global ID, a
+ * meaningful subnet ID, and a unique interface ID, all mappable back onto
+ * ZeroTier space.
+ *
+ * This in turn could allow us, on networks numbered this way, to emulate
+ * IPv6 NDP and eliminate all multicast. This could be beneficial for
+ * small devices and huge networks, e.g. IoT applications.
+ *
+ * The returned address is given an odd prefix length of /88, since within
+ * a given network only the last 40 bits (device ID) are variable. This
+ * is a bit unusual but as far as we know should not cause any problems with
+ * any non-braindead IPv6 stack.
+ *
+ * @param nwid 64-bit network ID
+ * @param zeroTierAddress 40-bit device address (in least significant 40 bits, highest 24 bits ignored)
+ * @return IPv6 private unicast address with /88 netmask
+ */
+ static InetAddress makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
+ throw();
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/MAC.hpp b/zerotierone/node/MAC.hpp
new file mode 100644
index 0000000..95623f1
--- /dev/null
+++ b/zerotierone/node/MAC.hpp
@@ -0,0 +1,264 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_MAC_HPP
+#define ZT_MAC_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "Constants.hpp"
+#include "Utils.hpp"
+#include "Address.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+/**
+ * 48-byte Ethernet MAC address
+ */
+class MAC
+{
+public:
+ MAC() throw() : _m(0ULL) {}
+ MAC(const MAC &m) throw() : _m(m._m) {}
+
+ MAC(const unsigned char a,const unsigned char b,const unsigned char c,const unsigned char d,const unsigned char e,const unsigned char f) throw() :
+ _m( ((((uint64_t)a) & 0xffULL) << 40) |
+ ((((uint64_t)b) & 0xffULL) << 32) |
+ ((((uint64_t)c) & 0xffULL) << 24) |
+ ((((uint64_t)d) & 0xffULL) << 16) |
+ ((((uint64_t)e) & 0xffULL) << 8) |
+ (((uint64_t)f) & 0xffULL) ) {}
+
+ MAC(const char *s) throw() { fromString(s); }
+ MAC(const std::string &s) throw() { fromString(s.c_str()); }
+
+ MAC(const void *bits,unsigned int len) throw() { setTo(bits,len); }
+
+ MAC(const Address &ztaddr,uint64_t nwid) throw() { fromAddress(ztaddr,nwid); }
+
+ MAC(const uint64_t m) throw() : _m(m & 0xffffffffffffULL) {}
+
+ /**
+ * @return MAC in 64-bit integer
+ */
+ inline uint64_t toInt() const throw() { return _m; }
+
+ /**
+ * Set MAC to zero
+ */
+ inline void zero() { _m = 0ULL; }
+
+ /**
+ * @return True if MAC is non-zero
+ */
+ inline operator bool() const throw() { return (_m != 0ULL); }
+
+ /**
+ * @param bits Raw MAC in big-endian byte order
+ * @param len Length, must be >= 6 or result is zero
+ */
+ inline void setTo(const void *bits,unsigned int len)
+ throw()
+ {
+ if (len < 6) {
+ _m = 0ULL;
+ return;
+ }
+ const unsigned char *b = (const unsigned char *)bits;
+ _m = ((((uint64_t)*b) & 0xff) << 40); ++b;
+ _m |= ((((uint64_t)*b) & 0xff) << 32); ++b;
+ _m |= ((((uint64_t)*b) & 0xff) << 24); ++b;
+ _m |= ((((uint64_t)*b) & 0xff) << 16); ++b;
+ _m |= ((((uint64_t)*b) & 0xff) << 8); ++b;
+ _m |= (((uint64_t)*b) & 0xff);
+ }
+
+ /**
+ * @param buf Destination buffer for MAC in big-endian byte order
+ * @param len Length of buffer, must be >= 6 or nothing is copied
+ */
+ inline void copyTo(void *buf,unsigned int len) const
+ throw()
+ {
+ if (len < 6)
+ return;
+ unsigned char *b = (unsigned char *)buf;
+ *(b++) = (unsigned char)((_m >> 40) & 0xff);
+ *(b++) = (unsigned char)((_m >> 32) & 0xff);
+ *(b++) = (unsigned char)((_m >> 24) & 0xff);
+ *(b++) = (unsigned char)((_m >> 16) & 0xff);
+ *(b++) = (unsigned char)((_m >> 8) & 0xff);
+ *b = (unsigned char)(_m & 0xff);
+ }
+
+ /**
+ * Append to a buffer in big-endian byte order
+ *
+ * @param b Buffer to append to
+ */
+ template<unsigned int C>
+ inline void appendTo(Buffer<C> &b) const
+ throw(std::out_of_range)
+ {
+ unsigned char *p = (unsigned char *)b.appendField(6);
+ *(p++) = (unsigned char)((_m >> 40) & 0xff);
+ *(p++) = (unsigned char)((_m >> 32) & 0xff);
+ *(p++) = (unsigned char)((_m >> 24) & 0xff);
+ *(p++) = (unsigned char)((_m >> 16) & 0xff);
+ *(p++) = (unsigned char)((_m >> 8) & 0xff);
+ *p = (unsigned char)(_m & 0xff);
+ }
+
+ /**
+ * @return True if this is broadcast (all 0xff)
+ */
+ inline bool isBroadcast() const throw() { return (_m == 0xffffffffffffULL); }
+
+ /**
+ * @return True if this is a multicast MAC
+ */
+ inline bool isMulticast() const throw() { return ((_m & 0x010000000000ULL) != 0ULL); }
+
+ /**
+ * @param True if this is a locally-administered MAC
+ */
+ inline bool isLocallyAdministered() const throw() { return ((_m & 0x020000000000ULL) != 0ULL); }
+
+ /**
+ * @param s Hex MAC, with or without : delimiters
+ */
+ inline void fromString(const char *s)
+ {
+ char tmp[8];
+ for(int i=0;i<6;++i)
+ tmp[i] = (char)0;
+ Utils::unhex(s,tmp,6);
+ setTo(tmp,6);
+ }
+
+ /**
+ * @return MAC address in standard :-delimited hex format
+ */
+ inline std::string toString() const
+ {
+ char tmp[24];
+ toString(tmp,sizeof(tmp));
+ return std::string(tmp);
+ }
+
+ /**
+ * @param buf Buffer to contain human-readable MAC
+ * @param len Length of buffer
+ */
+ inline void toString(char *buf,unsigned int len) const
+ {
+ Utils::snprintf(buf,len,"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)(*this)[0],(int)(*this)[1],(int)(*this)[2],(int)(*this)[3],(int)(*this)[4],(int)(*this)[5]);
+ }
+
+ /**
+ * Set this MAC to a MAC derived from an address and a network ID
+ *
+ * @param ztaddr ZeroTier address
+ * @param nwid 64-bit network ID
+ */
+ inline void fromAddress(const Address &ztaddr,uint64_t nwid)
+ throw()
+ {
+ uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40;
+ m |= ztaddr.toInt(); // a is 40 bits
+ m ^= ((nwid >> 8) & 0xff) << 32;
+ m ^= ((nwid >> 16) & 0xff) << 24;
+ m ^= ((nwid >> 24) & 0xff) << 16;
+ m ^= ((nwid >> 32) & 0xff) << 8;
+ m ^= (nwid >> 40) & 0xff;
+ _m = m;
+ }
+
+ /**
+ * Get the ZeroTier address for this MAC on this network (assuming no bridging of course, basic unicast)
+ *
+ * This just XORs the next-lest-significant 5 bytes of the network ID again to unmask.
+ *
+ * @param nwid Network ID
+ */
+ inline Address toAddress(uint64_t nwid) const
+ throw()
+ {
+ uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address
+ a ^= ((nwid >> 8) & 0xff) << 32; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it
+ a ^= ((nwid >> 16) & 0xff) << 24;
+ a ^= ((nwid >> 24) & 0xff) << 16;
+ a ^= ((nwid >> 32) & 0xff) << 8;
+ a ^= (nwid >> 40) & 0xff;
+ return Address(a);
+ }
+
+ /**
+ * @param nwid Network ID
+ * @return First octet of MAC for this network
+ */
+ static inline unsigned char firstOctetForNetwork(uint64_t nwid)
+ throw()
+ {
+ unsigned char a = ((unsigned char)(nwid & 0xfe) | 0x02); // locally administered, not multicast, from LSB of network ID
+ return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux
+ }
+
+ /**
+ * @param i Value from 0 to 5 (inclusive)
+ * @return Byte at said position (address interpreted in big-endian order)
+ */
+ inline unsigned char operator[](unsigned int i) const throw() { return (unsigned char)((_m >> (40 - (i * 8))) & 0xff); }
+
+ /**
+ * @return 6, which is the number of bytes in a MAC, for container compliance
+ */
+ inline unsigned int size() const throw() { return 6; }
+
+ inline unsigned long hashCode() const throw() { return (unsigned long)_m; }
+
+ inline MAC &operator=(const MAC &m)
+ throw()
+ {
+ _m = m._m;
+ return *this;
+ }
+ inline MAC &operator=(const uint64_t m)
+ throw()
+ {
+ _m = m;
+ return *this;
+ }
+
+ inline bool operator==(const MAC &m) const throw() { return (_m == m._m); }
+ inline bool operator!=(const MAC &m) const throw() { return (_m != m._m); }
+ inline bool operator<(const MAC &m) const throw() { return (_m < m._m); }
+ inline bool operator<=(const MAC &m) const throw() { return (_m <= m._m); }
+ inline bool operator>(const MAC &m) const throw() { return (_m > m._m); }
+ inline bool operator>=(const MAC &m) const throw() { return (_m >= m._m); }
+
+private:
+ uint64_t _m;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/MulticastGroup.hpp b/zerotierone/node/MulticastGroup.hpp
new file mode 100644
index 0000000..dbf3899
--- /dev/null
+++ b/zerotierone/node/MulticastGroup.hpp
@@ -0,0 +1,158 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_MULTICASTGROUP_HPP
+#define ZT_MULTICASTGROUP_HPP
+
+#include <stdint.h>
+
+#include <string>
+
+#include "MAC.hpp"
+#include "InetAddress.hpp"
+
+namespace ZeroTier {
+
+/**
+ * A multicast group composed of a multicast MAC and a 32-bit ADI field
+ *
+ * ADI stands for additional distinguishing information. ADI is primarily for
+ * adding additional information to broadcast (ff:ff:ff:ff:ff:ff) memberships,
+ * since straight-up broadcast won't scale. Right now it's zero except for
+ * IPv4 ARP, where it holds the IPv4 address itself to make ARP into a
+ * selective multicast query that can scale.
+ *
+ * In the future we might add some kind of plugin architecture that can add
+ * ADI for things like mDNS (multicast DNS) to improve the selectivity of
+ * those protocols.
+ *
+ * MulticastGroup behaves as an immutable value object.
+ */
+class MulticastGroup
+{
+public:
+ MulticastGroup()
+ throw() :
+ _mac(),
+ _adi(0)
+ {
+ }
+
+ MulticastGroup(const MAC &m,uint32_t a)
+ throw() :
+ _mac(m),
+ _adi(a)
+ {
+ }
+
+ MulticastGroup(const char *s)
+ {
+ fromString(s);
+ }
+
+ MulticastGroup(const std::string &s)
+ {
+ fromString(s.c_str());
+ }
+
+ /**
+ * Derive the multicast group used for address resolution (ARP/NDP) for an IP
+ *
+ * @param ip IP address (port field is ignored)
+ * @return Multicat group for ARP/NDP
+ */
+ static inline MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip)
+ throw()
+ {
+ if (ip.isV4()) {
+ // IPv4 wants broadcast MACs, so we shove the V4 address itself into
+ // the Multicast Group ADI field. Making V4 ARP work is basically why
+ // ADI was added, as well as handling other things that want mindless
+ // Ethernet broadcast to all.
+ return MulticastGroup(MAC(0xffffffffffffULL),Utils::ntoh(*((const uint32_t *)ip.rawIpData())));
+ } else if (ip.isV6()) {
+ // IPv6 is better designed in this respect. We can compute the IPv6
+ // multicast address directly from the IP address, and it gives us
+ // 24 bits of uniqueness. Collisions aren't likely to be common enough
+ // to care about.
+ const unsigned char *a = (const unsigned char *)ip.rawIpData();
+ return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
+ }
+ return MulticastGroup();
+ }
+
+ /**
+ * @return Human readable string representing this group (MAC/ADI in hex)
+ */
+ inline std::string toString() const
+ {
+ char buf[64];
+ Utils::snprintf(buf,sizeof(buf),"%.2x%.2x%.2x%.2x%.2x%.2x/%.8lx",(unsigned int)_mac[0],(unsigned int)_mac[1],(unsigned int)_mac[2],(unsigned int)_mac[3],(unsigned int)_mac[4],(unsigned int)_mac[5],(unsigned long)_adi);
+ return std::string(buf);
+ }
+
+ /**
+ * Parse a human-readable multicast group
+ *
+ * @param s Multicast group in hex MAC/ADI format
+ */
+ inline void fromString(const char *s)
+ {
+ char hex[17];
+ unsigned int hexlen = 0;
+ while ((*s)&&(*s != '/')&&(hexlen < (sizeof(hex) - 1)))
+ hex[hexlen++] = *s;
+ hex[hexlen] = (char)0;
+ _mac.fromString(hex);
+ _adi = (*s == '/') ? (uint32_t)Utils::hexStrToULong(s + 1) : (uint32_t)0;
+ }
+
+ /**
+ * @return Multicast address
+ */
+ inline const MAC &mac() const throw() { return _mac; }
+
+ /**
+ * @return Additional distinguishing information
+ */
+ inline uint32_t adi() const throw() { return _adi; }
+
+ inline unsigned long hashCode() const throw() { return (_mac.hashCode() ^ (unsigned long)_adi); }
+
+ inline bool operator==(const MulticastGroup &g) const throw() { return ((_mac == g._mac)&&(_adi == g._adi)); }
+ inline bool operator!=(const MulticastGroup &g) const throw() { return ((_mac != g._mac)||(_adi != g._adi)); }
+ inline bool operator<(const MulticastGroup &g) const throw()
+ {
+ if (_mac < g._mac)
+ return true;
+ else if (_mac == g._mac)
+ return (_adi < g._adi);
+ return false;
+ }
+ inline bool operator>(const MulticastGroup &g) const throw() { return (g < *this); }
+ inline bool operator<=(const MulticastGroup &g) const throw() { return !(g < *this); }
+ inline bool operator>=(const MulticastGroup &g) const throw() { return !(*this < g); }
+
+private:
+ MAC _mac;
+ uint32_t _adi;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Multicaster.cpp b/zerotierone/node/Multicaster.cpp
new file mode 100644
index 0000000..1dfa67d
--- /dev/null
+++ b/zerotierone/node/Multicaster.cpp
@@ -0,0 +1,369 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <algorithm>
+
+#include "Constants.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "SharedPtr.hpp"
+#include "Multicaster.hpp"
+#include "Topology.hpp"
+#include "Switch.hpp"
+#include "Packet.hpp"
+#include "Peer.hpp"
+#include "C25519.hpp"
+#include "CertificateOfMembership.hpp"
+#include "Node.hpp"
+
+namespace ZeroTier {
+
+Multicaster::Multicaster(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _groups(1024),
+ _groups_m()
+{
+}
+
+Multicaster::~Multicaster()
+{
+}
+
+void Multicaster::addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown)
+{
+ const unsigned char *p = (const unsigned char *)addresses;
+ const unsigned char *e = p + (5 * count);
+ Mutex::Lock _l(_groups_m);
+ MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)];
+ while (p != e) {
+ _add(now,nwid,mg,gs,Address(p,5));
+ p += 5;
+ }
+}
+
+void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &member)
+{
+ Mutex::Lock _l(_groups_m);
+ MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
+ if (s) {
+ for(std::vector<MulticastGroupMember>::iterator m(s->members.begin());m!=s->members.end();++m) {
+ if (m->address == member) {
+ s->members.erase(m);
+ break;
+ }
+ }
+ }
+}
+
+unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const
+{
+ unsigned char *p;
+ unsigned int added = 0,i,k,rptr,totalKnown = 0;
+ uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2];
+
+ if (!limit)
+ return 0;
+ else if (limit > 0xffff)
+ limit = 0xffff;
+
+ const unsigned int totalAt = appendTo.size();
+ appendTo.addSize(4); // sizeof(uint32_t)
+ const unsigned int addedAt = appendTo.size();
+ appendTo.addSize(2); // sizeof(uint16_t)
+
+ { // Return myself if I am a member of this group
+ SharedPtr<Network> network(RR->node->network(nwid));
+ if ((network)&&(network->subscribedToMulticastGroup(mg,true))) {
+ RR->identity.address().appendTo(appendTo);
+ ++totalKnown;
+ ++added;
+ }
+ }
+
+ Mutex::Lock _l(_groups_m);
+
+ const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
+ if ((s)&&(!s->members.empty())) {
+ totalKnown += (unsigned int)s->members.size();
+
+ // Members are returned in random order so that repeated gather queries
+ // will return different subsets of a large multicast group.
+ k = 0;
+ while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) {
+ rptr = (unsigned int)RR->node->prng();
+
+restart_member_scan:
+ a = s->members[rptr % (unsigned int)s->members.size()].address.toInt();
+ for(i=0;i<k;++i) {
+ if (picked[i] == a) {
+ ++rptr;
+ goto restart_member_scan;
+ }
+ }
+ picked[k++] = a;
+
+ if (queryingPeer.toInt() != a) { // do not return the peer that is making the request as a result
+ p = (unsigned char *)appendTo.appendField(ZT_ADDRESS_LENGTH);
+ *(p++) = (unsigned char)((a >> 32) & 0xff);
+ *(p++) = (unsigned char)((a >> 24) & 0xff);
+ *(p++) = (unsigned char)((a >> 16) & 0xff);
+ *(p++) = (unsigned char)((a >> 8) & 0xff);
+ *p = (unsigned char)(a & 0xff);
+ ++added;
+ }
+ }
+ }
+
+ appendTo.setAt(totalAt,(uint32_t)totalKnown);
+ appendTo.setAt(addedAt,(uint16_t)added);
+
+ //TRACE("..MC Multicaster::gather() attached %u of %u peers for %.16llx/%s (2)",n,(unsigned int)(gs->second.members.size() - skipped),nwid,mg.toString().c_str());
+
+ return added;
+}
+
+std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const
+{
+ std::vector<Address> ls;
+ Mutex::Lock _l(_groups_m);
+ const MulticastGroupStatus *s = _groups.get(Multicaster::Key(nwid,mg));
+ if (!s)
+ return ls;
+ for(std::vector<MulticastGroupMember>::const_reverse_iterator m(s->members.rbegin());m!=s->members.rend();++m) {
+ ls.push_back(m->address);
+ if (ls.size() >= limit)
+ break;
+ }
+ return ls;
+}
+
+void Multicaster::send(
+ const CertificateOfMembership *com,
+ unsigned int limit,
+ uint64_t now,
+ uint64_t nwid,
+ const std::vector<Address> &alwaysSendTo,
+ const MulticastGroup &mg,
+ const MAC &src,
+ unsigned int etherType,
+ const void *data,
+ unsigned int len)
+{
+ unsigned long idxbuf[8194];
+ unsigned long *indexes = idxbuf;
+
+ try {
+ Mutex::Lock _l(_groups_m);
+ MulticastGroupStatus &gs = _groups[Multicaster::Key(nwid,mg)];
+
+ if (!gs.members.empty()) {
+ // Allocate a memory buffer if group is monstrous
+ if (gs.members.size() > (sizeof(idxbuf) / sizeof(unsigned long)))
+ indexes = new unsigned long[gs.members.size()];
+
+ // Generate a random permutation of member indexes
+ for(unsigned long i=0;i<gs.members.size();++i)
+ indexes[i] = i;
+ for(unsigned long i=(unsigned long)gs.members.size()-1;i>0;--i) {
+ unsigned long j = (unsigned long)RR->node->prng() % (i + 1);
+ unsigned long tmp = indexes[j];
+ indexes[j] = indexes[i];
+ indexes[i] = tmp;
+ }
+ }
+
+ if (gs.members.size() >= limit) {
+ // Skip queue if we already have enough members to complete the send operation
+ OutboundMulticast out;
+
+ out.init(
+ RR,
+ now,
+ nwid,
+ com,
+ limit,
+ 1, // we'll still gather a little from peers to keep multicast list fresh
+ src,
+ mg,
+ etherType,
+ data,
+ len);
+
+ unsigned int count = 0;
+
+ for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
+ if (*ast != RR->identity.address()) {
+ out.sendOnly(RR,*ast); // optimization: don't use dedup log if it's a one-pass send
+ if (++count >= limit)
+ break;
+ }
+ }
+
+ unsigned long idx = 0;
+ while ((count < limit)&&(idx < gs.members.size())) {
+ Address ma(gs.members[indexes[idx++]].address);
+ if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
+ out.sendOnly(RR,ma); // optimization: don't use dedup log if it's a one-pass send
+ ++count;
+ }
+ }
+ } else {
+ unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
+
+ if ((gs.members.empty())||((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY)) {
+ gs.lastExplicitGather = now;
+ SharedPtr<Peer> explicitGatherPeers[2];
+ explicitGatherPeers[0] = RR->topology->getBestRoot();
+ explicitGatherPeers[1] = RR->topology->getPeer(Network::controllerFor(nwid));
+ for(unsigned int k=0;k<2;++k) {
+ const SharedPtr<Peer> &p = explicitGatherPeers[k];
+ if (!p)
+ continue;
+ //TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str());
+
+ const CertificateOfMembership *com = (CertificateOfMembership *)0;
+ {
+ SharedPtr<Network> nw(RR->node->network(nwid));
+ if ((nw)&&(nw->hasConfig())&&(nw->config().com)&&(nw->config().isPrivate())&&(p->needsOurNetworkMembershipCertificate(nwid,now,true)))
+ com = &(nw->config().com);
+ }
+
+ Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
+ outp.append(nwid);
+ outp.append((uint8_t)(com ? 0x01 : 0x00));
+ mg.mac().appendTo(outp);
+ outp.append((uint32_t)mg.adi());
+ outp.append((uint32_t)gatherLimit);
+ if (com)
+ com->serialize(outp);
+ RR->sw->send(outp,true,0);
+ }
+ gatherLimit = 0;
+ }
+
+ gs.txQueue.push_back(OutboundMulticast());
+ OutboundMulticast &out = gs.txQueue.back();
+
+ out.init(
+ RR,
+ now,
+ nwid,
+ com,
+ limit,
+ gatherLimit,
+ src,
+ mg,
+ etherType,
+ data,
+ len);
+
+ unsigned int count = 0;
+
+ for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
+ if (*ast != RR->identity.address()) {
+ out.sendAndLog(RR,*ast);
+ if (++count >= limit)
+ break;
+ }
+ }
+
+ unsigned long idx = 0;
+ while ((count < limit)&&(idx < gs.members.size())) {
+ Address ma(gs.members[indexes[idx++]].address);
+ if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),ma) == alwaysSendTo.end()) {
+ out.sendAndLog(RR,ma);
+ ++count;
+ }
+ }
+ }
+ } catch ( ... ) {} // this is a sanity check to catch any failures and make sure indexes[] still gets deleted
+
+ // Free allocated memory buffer if any
+ if (indexes != idxbuf)
+ delete [] indexes;
+}
+
+void Multicaster::clean(uint64_t now)
+{
+ Mutex::Lock _l(_groups_m);
+
+ Multicaster::Key *k = (Multicaster::Key *)0;
+ MulticastGroupStatus *s = (MulticastGroupStatus *)0;
+ Hashtable<Multicaster::Key,MulticastGroupStatus>::Iterator mm(_groups);
+ while (mm.next(k,s)) {
+ for(std::list<OutboundMulticast>::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) {
+ if ((tx->expired(now))||(tx->atLimit()))
+ s->txQueue.erase(tx++);
+ else ++tx;
+ }
+
+ unsigned long count = 0;
+ {
+ std::vector<MulticastGroupMember>::iterator reader(s->members.begin());
+ std::vector<MulticastGroupMember>::iterator writer(reader);
+ while (reader != s->members.end()) {
+ if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) {
+ *writer = *reader;
+ ++writer;
+ ++count;
+ }
+ ++reader;
+ }
+ }
+
+ if (count) {
+ s->members.resize(count);
+ } else if (s->txQueue.empty()) {
+ _groups.erase(*k);
+ } else {
+ s->members.clear();
+ }
+ }
+}
+
+void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
+{
+ // assumes _groups_m is locked
+
+ // Do not add self -- even if someone else returns it
+ if (member == RR->identity.address())
+ return;
+
+ for(std::vector<MulticastGroupMember>::iterator m(gs.members.begin());m!=gs.members.end();++m) {
+ if (m->address == member) {
+ m->timestamp = now;
+ return;
+ }
+ }
+
+ gs.members.push_back(MulticastGroupMember(member,now));
+
+ //TRACE("..MC %s joined multicast group %.16llx/%s via %s",member.toString().c_str(),nwid,mg.toString().c_str(),((learnedFrom) ? learnedFrom.toString().c_str() : "(direct)"));
+
+ for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
+ if (tx->atLimit())
+ gs.txQueue.erase(tx++);
+ else {
+ tx->sendIfNew(RR,member);
+ if (tx->atLimit())
+ gs.txQueue.erase(tx++);
+ else ++tx;
+ }
+ }
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Multicaster.hpp b/zerotierone/node/Multicaster.hpp
new file mode 100644
index 0000000..c43c8d9
--- /dev/null
+++ b/zerotierone/node/Multicaster.hpp
@@ -0,0 +1,194 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_MULTICASTER_HPP
+#define ZT_MULTICASTER_HPP
+
+#include <stdint.h>
+#include <string.h>
+
+#include <map>
+#include <vector>
+#include <list>
+
+#include "Constants.hpp"
+#include "Hashtable.hpp"
+#include "Address.hpp"
+#include "MAC.hpp"
+#include "MulticastGroup.hpp"
+#include "OutboundMulticast.hpp"
+#include "Utils.hpp"
+#include "Mutex.hpp"
+#include "NonCopyable.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class CertificateOfMembership;
+class Packet;
+
+/**
+ * Database of known multicast peers within a network
+ */
+class Multicaster : NonCopyable
+{
+private:
+ struct Key
+ {
+ Key() : nwid(0),mg() {}
+ Key(uint64_t n,const MulticastGroup &g) : nwid(n),mg(g) {}
+
+ uint64_t nwid;
+ MulticastGroup mg;
+
+ inline bool operator==(const Key &k) const throw() { return ((nwid == k.nwid)&&(mg == k.mg)); }
+ inline unsigned long hashCode() const throw() { return (mg.hashCode() ^ (unsigned long)(nwid ^ (nwid >> 32))); }
+ };
+
+ struct MulticastGroupMember
+ {
+ MulticastGroupMember() {}
+ MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
+
+ Address address;
+ uint64_t timestamp; // time of last notification
+ };
+
+ struct MulticastGroupStatus
+ {
+ MulticastGroupStatus() : lastExplicitGather(0) {}
+
+ uint64_t lastExplicitGather;
+ std::list<OutboundMulticast> txQueue; // pending outbound multicasts
+ std::vector<MulticastGroupMember> members; // members of this group
+ };
+
+public:
+ Multicaster(const RuntimeEnvironment *renv);
+ ~Multicaster();
+
+ /**
+ * Add or update a member in a multicast group
+ *
+ * @param now Current time
+ * @param nwid Network ID
+ * @param mg Multicast group
+ * @param member New member address
+ */
+ inline void add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &member)
+ {
+ Mutex::Lock _l(_groups_m);
+ _add(now,nwid,mg,_groups[Multicaster::Key(nwid,mg)],member);
+ }
+
+ /**
+ * Add multiple addresses from a binary array of 5-byte address fields
+ *
+ * It's up to the caller to check bounds on the array before calling this.
+ *
+ * @param now Current time
+ * @param nwid Network ID
+ * @param mg Multicast group
+ * @param addresses Raw binary addresses in big-endian format, as a series of 5-byte fields
+ * @param count Number of addresses
+ * @param totalKnown Total number of known addresses as reported by peer
+ */
+ void addMultiple(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const void *addresses,unsigned int count,unsigned int totalKnown);
+
+ /**
+ * Remove a multicast group member (if present)
+ *
+ * @param nwid Network ID
+ * @param mg Multicast group
+ * @param member Member to unsubscribe
+ */
+ void remove(uint64_t nwid,const MulticastGroup &mg,const Address &member);
+
+ /**
+ * Append gather results to a packet by choosing registered multicast recipients at random
+ *
+ * This appends the following fields to the packet:
+ * <[4] 32-bit total number of known members in this multicast group>
+ * <[2] 16-bit number of members enumerated in this packet>
+ * <[...] series of 5-byte ZeroTier addresses of enumerated members>
+ *
+ * If zero is returned, the first two fields will still have been appended.
+ *
+ * @param queryingPeer Peer asking for gather (to skip in results)
+ * @param nwid Network ID
+ * @param mg Multicast group
+ * @param appendTo Packet to append to
+ * @param limit Maximum number of 5-byte addresses to append
+ * @return Number of addresses appended
+ * @throws std::out_of_range Buffer overflow writing to packet
+ */
+ unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const;
+
+ /**
+ * Get subscribers to a multicast group
+ *
+ * @param nwid Network ID
+ * @param mg Multicast group
+ */
+ std::vector<Address> getMembers(uint64_t nwid,const MulticastGroup &mg,unsigned int limit) const;
+
+ /**
+ * Send a multicast
+ *
+ * @param com Certificate of membership to include or NULL for none
+ * @param limit Multicast limit
+ * @param now Current time
+ * @param nwid Network ID
+ * @param alwaysSendTo Send to these peers first and even if not included in subscriber list
+ * @param mg Multicast group
+ * @param src Source Ethernet MAC address or NULL to skip in packet and compute from ZT address (non-bridged mode)
+ * @param etherType Ethernet frame type
+ * @param data Packet data
+ * @param len Length of packet data
+ */
+ void send(
+ const CertificateOfMembership *com,
+ unsigned int limit,
+ uint64_t now,
+ uint64_t nwid,
+ const std::vector<Address> &alwaysSendTo,
+ const MulticastGroup &mg,
+ const MAC &src,
+ unsigned int etherType,
+ const void *data,
+ unsigned int len);
+
+ /**
+ * Clean up and resort database
+ *
+ * @param RR Runtime environment
+ * @param now Current time
+ */
+ void clean(uint64_t now);
+
+private:
+ void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
+
+ const RuntimeEnvironment *RR;
+ Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
+ Mutex _groups_m;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Mutex.hpp b/zerotierone/node/Mutex.hpp
new file mode 100644
index 0000000..d451ede
--- /dev/null
+++ b/zerotierone/node/Mutex.hpp
@@ -0,0 +1,186 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_MUTEX_HPP
+#define ZT_MUTEX_HPP
+
+#include "Constants.hpp"
+#include "NonCopyable.hpp"
+
+#ifdef __UNIX_LIKE__
+
+#include <stdlib.h>
+#include <pthread.h>
+
+namespace ZeroTier {
+
+class Mutex : NonCopyable
+{
+public:
+ Mutex()
+ throw()
+ {
+ pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0);
+ }
+
+ ~Mutex()
+ {
+ pthread_mutex_destroy(&_mh);
+ }
+
+ inline void lock()
+ throw()
+ {
+ pthread_mutex_lock(&_mh);
+ }
+
+ inline void unlock()
+ throw()
+ {
+ pthread_mutex_unlock(&_mh);
+ }
+
+ inline void lock() const
+ throw()
+ {
+ (const_cast <Mutex *> (this))->lock();
+ }
+
+ inline void unlock() const
+ throw()
+ {
+ (const_cast <Mutex *> (this))->unlock();
+ }
+
+ /**
+ * Uses C++ contexts and constructor/destructor to lock/unlock automatically
+ */
+ class Lock : NonCopyable
+ {
+ public:
+ Lock(Mutex &m)
+ throw() :
+ _m(&m)
+ {
+ m.lock();
+ }
+
+ Lock(const Mutex &m)
+ throw() :
+ _m(const_cast<Mutex *>(&m))
+ {
+ _m->lock();
+ }
+
+ ~Lock()
+ {
+ _m->unlock();
+ }
+
+ private:
+ Mutex *const _m;
+ };
+
+private:
+ pthread_mutex_t _mh;
+};
+
+} // namespace ZeroTier
+
+#endif // Apple / Linux
+
+#ifdef __WINDOWS__
+
+#include <stdlib.h>
+#include <Windows.h>
+
+namespace ZeroTier {
+
+class Mutex : NonCopyable
+{
+public:
+ Mutex()
+ throw()
+ {
+ InitializeCriticalSection(&_cs);
+ }
+
+ ~Mutex()
+ {
+ DeleteCriticalSection(&_cs);
+ }
+
+ inline void lock()
+ throw()
+ {
+ EnterCriticalSection(&_cs);
+ }
+
+ inline void unlock()
+ throw()
+ {
+ LeaveCriticalSection(&_cs);
+ }
+
+ inline void lock() const
+ throw()
+ {
+ (const_cast <Mutex *> (this))->lock();
+ }
+
+ inline void unlock() const
+ throw()
+ {
+ (const_cast <Mutex *> (this))->unlock();
+ }
+
+ class Lock : NonCopyable
+ {
+ public:
+ Lock(Mutex &m)
+ throw() :
+ _m(&m)
+ {
+ m.lock();
+ }
+
+ Lock(const Mutex &m)
+ throw() :
+ _m(const_cast<Mutex *>(&m))
+ {
+ _m->lock();
+ }
+
+ ~Lock()
+ {
+ _m->unlock();
+ }
+
+ private:
+ Mutex *const _m;
+ };
+
+private:
+ CRITICAL_SECTION _cs;
+};
+
+} // namespace ZeroTier
+
+#endif // _WIN32
+
+#endif
diff --git a/zerotierone/node/Network.cpp b/zerotierone/node/Network.cpp
new file mode 100644
index 0000000..c1c3414
--- /dev/null
+++ b/zerotierone/node/Network.cpp
@@ -0,0 +1,513 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "Constants.hpp"
+#include "Network.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Switch.hpp"
+#include "Packet.hpp"
+#include "Buffer.hpp"
+#include "NetworkController.hpp"
+#include "Node.hpp"
+
+#include "../version.h"
+
+namespace ZeroTier {
+
+const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0);
+
+Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
+ RR(renv),
+ _uPtr(uptr),
+ _id(nwid),
+ _mac(renv->identity.address(),nwid),
+ _enabled(true),
+ _portInitialized(false),
+ _lastConfigUpdate(0),
+ _destroyed(false),
+ _netconfFailure(NETCONF_FAILURE_NONE),
+ _portError(0)
+{
+ char confn[128],mcdbn[128];
+ Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id);
+ Utils::snprintf(mcdbn,sizeof(mcdbn),"networks.d/%.16llx.mcerts",_id);
+
+ // These files are no longer used, so clean them.
+ RR->node->dataStoreDelete(mcdbn);
+
+ if (_id == ZT_TEST_NETWORK_ID) {
+ applyConfiguration(NetworkConfig::createTestNetworkConfig(RR->identity.address()));
+
+ // Save a one-byte CR to persist membership in the test network
+ RR->node->dataStorePut(confn,"\n",1,false);
+ } else {
+ bool gotConf = false;
+ try {
+ std::string conf(RR->node->dataStoreGet(confn));
+ if (conf.length()) {
+ this->setConfiguration((const void *)conf.data(),(unsigned int)conf.length(),false);
+ _lastConfigUpdate = 0; // we still want to re-request a new config from the network
+ gotConf = true;
+ }
+ } catch ( ... ) {} // ignore invalids, we'll re-request
+
+ if (!gotConf) {
+ // Save a one-byte CR to persist membership while we request a real netconf
+ RR->node->dataStorePut(confn,"\n",1,false);
+ }
+ }
+
+ if (!_portInitialized) {
+ ZT_VirtualNetworkConfig ctmp;
+ _externalConfig(&ctmp);
+ _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
+ _portInitialized = true;
+ }
+}
+
+Network::~Network()
+{
+ ZT_VirtualNetworkConfig ctmp;
+ _externalConfig(&ctmp);
+
+ char n[128];
+ if (_destroyed) {
+ RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
+ Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
+ RR->node->dataStoreDelete(n);
+ } else {
+ RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp);
+ }
+}
+
+bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const
+{
+ Mutex::Lock _l(_lock);
+ if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
+ return true;
+ else if (includeBridgedGroups)
+ return _multicastGroupsBehindMe.contains(mg);
+ else return false;
+}
+
+void Network::multicastSubscribe(const MulticastGroup &mg)
+{
+ {
+ Mutex::Lock _l(_lock);
+ if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
+ return;
+ _myMulticastGroups.push_back(mg);
+ std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end());
+ }
+ _announceMulticastGroups();
+}
+
+void Network::multicastUnsubscribe(const MulticastGroup &mg)
+{
+ Mutex::Lock _l(_lock);
+ std::vector<MulticastGroup> nmg;
+ for(std::vector<MulticastGroup>::const_iterator i(_myMulticastGroups.begin());i!=_myMulticastGroups.end();++i) {
+ if (*i != mg)
+ nmg.push_back(*i);
+ }
+ if (nmg.size() != _myMulticastGroups.size())
+ _myMulticastGroups.swap(nmg);
+}
+
+bool Network::tryAnnounceMulticastGroupsTo(const SharedPtr<Peer> &peer)
+{
+ Mutex::Lock _l(_lock);
+ if (
+ (_isAllowed(peer)) ||
+ (peer->address() == this->controller()) ||
+ (RR->topology->isRoot(peer->identity()))
+ ) {
+ _announceMulticastGroupsTo(peer,_allMulticastGroups());
+ return true;
+ }
+ return false;
+}
+
+bool Network::applyConfiguration(const NetworkConfig &conf)
+{
+ if (_destroyed) // sanity check
+ return false;
+ try {
+ if ((conf.networkId == _id)&&(conf.issuedTo == RR->identity.address())) {
+ ZT_VirtualNetworkConfig ctmp;
+ bool portInitialized;
+ {
+ Mutex::Lock _l(_lock);
+ _config = conf;
+ _lastConfigUpdate = RR->node->now();
+ _netconfFailure = NETCONF_FAILURE_NONE;
+ _externalConfig(&ctmp);
+ portInitialized = _portInitialized;
+ _portInitialized = true;
+ }
+ _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,(portInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
+ return true;
+ } else {
+ TRACE("ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address)",(unsigned long long)_id);
+ }
+ } catch (std::exception &exc) {
+ TRACE("ignored invalid configuration for network %.16llx (%s)",(unsigned long long)_id,exc.what());
+ } catch ( ... ) {
+ TRACE("ignored invalid configuration for network %.16llx (unknown exception)",(unsigned long long)_id);
+ }
+ return false;
+}
+
+int Network::setConfiguration(const void *confBytes,unsigned int confLen,bool saveToDisk)
+{
+ try {
+ if (confLen <= 1)
+ return 0;
+
+ NetworkConfig newConfig;
+
+ // Find the length of any string-serialized old-style Dictionary,
+ // including its terminating NULL (if any). If this is before
+ // the end of the config, that tells us there is a new-style
+ // binary config which is preferred.
+ unsigned int dictLen = 0;
+ while (dictLen < confLen) {
+ if (!(reinterpret_cast<const uint8_t *>(confBytes)[dictLen++]))
+ break;
+ }
+
+ if (dictLen < (confLen - 2)) {
+ Buffer<8194> tmp(reinterpret_cast<const uint8_t *>(confBytes) + dictLen,confLen - dictLen);
+ newConfig.deserialize(tmp,0);
+ } else {
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ newConfig.fromDictionary(reinterpret_cast<const char *>(confBytes),confLen); // throws if invalid
+#else
+ return 0;
+#endif
+ }
+
+ if (!newConfig)
+ return 0;
+
+ {
+ Mutex::Lock _l(_lock);
+ if (_config == newConfig)
+ return 1; // OK config, but duplicate of what we already have
+ }
+
+ if (applyConfiguration(newConfig)) {
+ if (saveToDisk) {
+ char n[128];
+ Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
+ RR->node->dataStorePut(n,confBytes,confLen,true);
+ }
+ return 2; // OK and configuration has changed
+ }
+ } catch ( ... ) {
+ TRACE("ignored invalid configuration for network %.16llx",(unsigned long long)_id);
+ }
+ return 0;
+}
+
+void Network::requestConfiguration()
+{
+ if (_id == ZT_TEST_NETWORK_ID) // pseudo-network-ID, uses locally generated static config
+ return;
+
+ if (controller() == RR->identity.address()) {
+ if (RR->localNetworkController) {
+ Buffer<8194> tmp;
+ switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,NetworkConfigRequestMetaData(),tmp)) {
+ case NetworkController::NETCONF_QUERY_OK:
+ this->setConfiguration(tmp.data(),tmp.size(),true);
+ return;
+ case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND:
+ this->setNotFound();
+ return;
+ case NetworkController::NETCONF_QUERY_ACCESS_DENIED:
+ this->setAccessDenied();
+ return;
+ default:
+ return;
+ }
+ } else {
+ this->setNotFound();
+ return;
+ }
+ }
+
+ TRACE("requesting netconf for network %.16llx from controller %s",(unsigned long long)_id,controller().toString().c_str());
+
+ NetworkConfigRequestMetaData metaData;
+ metaData.initWithDefaults();
+ Buffer<4096> mds;
+ metaData.serialize(mds); // this always includes legacy fields to support old controllers
+
+ Packet outp(controller(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append((uint64_t)_id);
+ outp.append((uint16_t)mds.size());
+ outp.append(mds.data(),mds.size());
+ outp.append((_config) ? (uint64_t)_config.revision : (uint64_t)0);
+ RR->sw->send(outp,true,0);
+}
+
+void Network::clean()
+{
+ const uint64_t now = RR->node->now();
+ Mutex::Lock _l(_lock);
+
+ if (_destroyed)
+ return;
+
+ {
+ Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe);
+ MulticastGroup *mg = (MulticastGroup *)0;
+ uint64_t *ts = (uint64_t *)0;
+ while (i.next(mg,ts)) {
+ if ((now - *ts) > (ZT_MULTICAST_LIKE_EXPIRE * 2))
+ _multicastGroupsBehindMe.erase(*mg);
+ }
+ }
+}
+
+void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
+{
+ Mutex::Lock _l(_lock);
+ _remoteBridgeRoutes[mac] = addr;
+
+ // Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
+ while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
+ Hashtable< Address,unsigned long > counts;
+ Address maxAddr;
+ unsigned long maxCount = 0;
+
+ MAC *m = (MAC *)0;
+ Address *a = (Address *)0;
+
+ // Find the address responsible for the most entries
+ {
+ Hashtable<MAC,Address>::Iterator i(_remoteBridgeRoutes);
+ while (i.next(m,a)) {
+ const unsigned long c = ++counts[*a];
+ if (c > maxCount) {
+ maxCount = c;
+ maxAddr = *a;
+ }
+ }
+ }
+
+ // Kill this address from our table, since it's most likely spamming us
+ {
+ Hashtable<MAC,Address>::Iterator i(_remoteBridgeRoutes);
+ while (i.next(m,a)) {
+ if (*a == maxAddr)
+ _remoteBridgeRoutes.erase(*m);
+ }
+ }
+ }
+}
+
+void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
+{
+ Mutex::Lock _l(_lock);
+ const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size();
+ _multicastGroupsBehindMe.set(mg,now);
+ if (tmp != _multicastGroupsBehindMe.size())
+ _announceMulticastGroups();
+}
+
+void Network::setEnabled(bool enabled)
+{
+ Mutex::Lock _l(_lock);
+ if (_enabled != enabled) {
+ _enabled = enabled;
+ ZT_VirtualNetworkConfig ctmp;
+ _externalConfig(&ctmp);
+ _portError = RR->node->configureVirtualNetworkPort(_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE,&ctmp);
+ }
+}
+
+void Network::destroy()
+{
+ Mutex::Lock _l(_lock);
+ _enabled = false;
+ _destroyed = true;
+}
+
+ZT_VirtualNetworkStatus Network::_status() const
+{
+ // assumes _lock is locked
+ if (_portError)
+ return ZT_NETWORK_STATUS_PORT_ERROR;
+ switch(_netconfFailure) {
+ case NETCONF_FAILURE_ACCESS_DENIED:
+ return ZT_NETWORK_STATUS_ACCESS_DENIED;
+ case NETCONF_FAILURE_NOT_FOUND:
+ return ZT_NETWORK_STATUS_NOT_FOUND;
+ case NETCONF_FAILURE_NONE:
+ return ((_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION);
+ default:
+ return ZT_NETWORK_STATUS_PORT_ERROR;
+ }
+}
+
+void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
+{
+ // assumes _lock is locked
+ ec->nwid = _id;
+ ec->mac = _mac.toInt();
+ if (_config)
+ Utils::scopy(ec->name,sizeof(ec->name),_config.name);
+ else ec->name[0] = (char)0;
+ ec->status = _status();
+ ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
+ ec->mtu = ZT_IF_MTU;
+ ec->dhcp = 0;
+ std::vector<Address> ab(_config.activeBridges());
+ ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0;
+ ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0;
+ ec->portError = _portError;
+ ec->enabled = (_enabled) ? 1 : 0;
+ ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0;
+
+ ec->multicastSubscriptionCount = std::min((unsigned int)_myMulticastGroups.size(),(unsigned int)ZT_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS);
+ for(unsigned int i=0;i<ec->multicastSubscriptionCount;++i) {
+ ec->multicastSubscriptions[i].mac = _myMulticastGroups[i].mac().toInt();
+ ec->multicastSubscriptions[i].adi = _myMulticastGroups[i].adi();
+ }
+
+ ec->assignedAddressCount = 0;
+ for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
+ if (i < _config.staticIpCount) {
+ memcpy(&(ec->assignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage));
+ ++ec->assignedAddressCount;
+ } else {
+ memset(&(ec->assignedAddresses[i]),0,sizeof(struct sockaddr_storage));
+ }
+ }
+}
+
+bool Network::_isAllowed(const SharedPtr<Peer> &peer) const
+{
+ // Assumes _lock is locked
+ try {
+ if (!_config)
+ return false;
+ if (_config.isPublic())
+ return true;
+ return ((_config.com)&&(peer->networkMembershipCertificatesAgree(_id,_config.com)));
+ } catch (std::exception &exc) {
+ TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer->address().toString().c_str(),exc.what());
+ } catch ( ... ) {
+ TRACE("isAllowed() check failed for peer %s: unexpected exception: unknown exception",peer->address().toString().c_str());
+ }
+ return false; // default position on any failure
+}
+
+class _MulticastAnnounceAll
+{
+public:
+ _MulticastAnnounceAll(const RuntimeEnvironment *renv,Network *nw) :
+ _now(renv->node->now()),
+ _controller(nw->controller()),
+ _network(nw),
+ _anchors(nw->config().anchors()),
+ _rootAddresses(renv->topology->rootAddresses())
+ {}
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p)
+ {
+ if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed
+ (p->address() == _controller) ||
+ (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ||
+ (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) {
+ peers.push_back(p);
+ }
+ }
+ std::vector< SharedPtr<Peer> > peers;
+private:
+ const uint64_t _now;
+ const Address _controller;
+ Network *const _network;
+ const std::vector<Address> _anchors;
+ const std::vector<Address> _rootAddresses;
+};
+void Network::_announceMulticastGroups()
+{
+ // Assumes _lock is locked
+ std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
+ _MulticastAnnounceAll gpfunc(RR,this);
+ RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc);
+ for(std::vector< SharedPtr<Peer> >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i)
+ _announceMulticastGroupsTo(*i,allMulticastGroups);
+}
+
+void Network::_announceMulticastGroupsTo(const SharedPtr<Peer> &peer,const std::vector<MulticastGroup> &allMulticastGroups) const
+{
+ // Assumes _lock is locked
+
+ // We push COMs ahead of MULTICAST_LIKE since they're used for access control -- a COM is a public
+ // credential so "over-sharing" isn't really an issue (and we only do so with roots).
+ if ((_config)&&(_config.com)&&(!_config.isPublic())&&(peer->needsOurNetworkMembershipCertificate(_id,RR->node->now(),true))) {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
+ _config.com.serialize(outp);
+ RR->sw->send(outp,true,0);
+ }
+
+ {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+
+ for(std::vector<MulticastGroup>::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) {
+ if ((outp.size() + 18) >= ZT_UDP_DEFAULT_PAYLOAD_MTU) {
+ RR->sw->send(outp,true,0);
+ outp.reset(peer->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+ }
+
+ // network ID, MAC, ADI
+ outp.append((uint64_t)_id);
+ mg->mac().appendTo(outp);
+ outp.append((uint32_t)mg->adi());
+ }
+
+ if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH)
+ RR->sw->send(outp,true,0);
+ }
+}
+
+std::vector<MulticastGroup> Network::_allMulticastGroups() const
+{
+ // Assumes _lock is locked
+
+ std::vector<MulticastGroup> mgs;
+ mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
+ mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
+ _multicastGroupsBehindMe.appendKeys(mgs);
+ if ((_config)&&(_config.enableBroadcast()))
+ mgs.push_back(Network::BROADCAST);
+ std::sort(mgs.begin(),mgs.end());
+ mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end());
+
+ return mgs;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Network.hpp b/zerotierone/node/Network.hpp
new file mode 100644
index 0000000..9d280fb
--- /dev/null
+++ b/zerotierone/node/Network.hpp
@@ -0,0 +1,353 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NETWORK_HPP
+#define ZT_NETWORK_HPP
+
+#include <stdint.h>
+
+#include "../include/ZeroTierOne.h"
+
+#include <string>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+
+#include "Constants.hpp"
+#include "NonCopyable.hpp"
+#include "Hashtable.hpp"
+#include "Address.hpp"
+#include "Mutex.hpp"
+#include "SharedPtr.hpp"
+#include "AtomicCounter.hpp"
+#include "MulticastGroup.hpp"
+#include "MAC.hpp"
+#include "Dictionary.hpp"
+#include "Multicaster.hpp"
+#include "NetworkConfig.hpp"
+#include "CertificateOfMembership.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class Peer;
+class _MulticastAnnounceAll;
+
+/**
+ * A virtual LAN
+ */
+class Network : NonCopyable
+{
+ friend class SharedPtr<Network>;
+ friend class _MulticastAnnounceAll; // internal function object
+
+public:
+ /**
+ * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
+ */
+ static const MulticastGroup BROADCAST;
+
+ /**
+ * Construct a new network
+ *
+ * Note that init() should be called immediately after the network is
+ * constructed to actually configure the port.
+ *
+ * @param renv Runtime environment
+ * @param nwid Network ID
+ * @param uptr Arbitrary pointer used by externally-facing API (for user use)
+ */
+ Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr);
+
+ ~Network();
+
+ /**
+ * @return Network ID
+ */
+ inline uint64_t id() const throw() { return _id; }
+
+ /**
+ * @return Address of network's controller (most significant 40 bits of ID)
+ */
+ inline Address controller() const throw() { return Address(_id >> 24); }
+
+ /**
+ * @param nwid Network ID
+ * @return Address of network's controller
+ */
+ static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); }
+
+ /**
+ * @return Multicast group memberships for this network's port (local, not learned via bridging)
+ */
+ inline std::vector<MulticastGroup> multicastGroups() const
+ {
+ Mutex::Lock _l(_lock);
+ return _myMulticastGroups;
+ }
+
+ /**
+ * @return All multicast groups including learned groups that are behind any bridges we're attached to
+ */
+ inline std::vector<MulticastGroup> allMulticastGroups() const
+ {
+ Mutex::Lock _l(_lock);
+ return _allMulticastGroups();
+ }
+
+ /**
+ * @param mg Multicast group
+ * @param includeBridgedGroups If true, also include any groups we've learned via bridging
+ * @return True if this network endpoint / peer is a member
+ */
+ bool subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const;
+
+ /**
+ * Subscribe to a multicast group
+ *
+ * @param mg New multicast group
+ */
+ void multicastSubscribe(const MulticastGroup &mg);
+
+ /**
+ * Unsubscribe from a multicast group
+ *
+ * @param mg Multicast group
+ */
+ void multicastUnsubscribe(const MulticastGroup &mg);
+
+ /**
+ * Announce multicast groups to a peer if that peer is authorized on this network
+ *
+ * @param peer Peer to try to announce multicast groups to
+ * @return True if peer was authorized and groups were announced
+ */
+ bool tryAnnounceMulticastGroupsTo(const SharedPtr<Peer> &peer);
+
+ /**
+ * Apply a NetworkConfig to this network
+ *
+ * @param conf Configuration in NetworkConfig form
+ * @return True if configuration was accepted
+ */
+ bool applyConfiguration(const NetworkConfig &conf);
+
+ /**
+ * Set or update this network's configuration
+ *
+ * @param confBytes Network configuration in old-style Dictionary or new-style serialized format
+ * @param confLen Length of network configuration in bytes
+ * @param saveToDisk IF true (default), write config to disk
+ * @return 0 -- rejected, 1 -- accepted but not new, 2 -- accepted new config
+ */
+ int setConfiguration(const void *confBytes,unsigned int confLen,bool saveToDisk);
+
+ /**
+ * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
+ */
+ inline void setAccessDenied()
+ {
+ Mutex::Lock _l(_lock);
+ _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
+ }
+
+ /**
+ * Set netconf failure to 'not found' -- called by PacketDecider when controller reports this
+ */
+ inline void setNotFound()
+ {
+ Mutex::Lock _l(_lock);
+ _netconfFailure = NETCONF_FAILURE_NOT_FOUND;
+ }
+
+ /**
+ * Causes this network to request an updated configuration from its master node now
+ */
+ void requestConfiguration();
+
+ /**
+ * @param peer Peer to check
+ * @return True if peer is allowed to communicate on this network
+ */
+ inline bool isAllowed(const SharedPtr<Peer> &peer) const
+ {
+ Mutex::Lock _l(_lock);
+ return _isAllowed(peer);
+ }
+
+ /**
+ * Perform cleanup and possibly save state
+ */
+ void clean();
+
+ /**
+ * @return Time of last updated configuration or 0 if none
+ */
+ inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; }
+
+ /**
+ * @return Status of this network
+ */
+ inline ZT_VirtualNetworkStatus status() const
+ {
+ Mutex::Lock _l(_lock);
+ return _status();
+ }
+
+ /**
+ * @param ec Buffer to fill with externally-visible network configuration
+ */
+ inline void externalConfig(ZT_VirtualNetworkConfig *ec) const
+ {
+ Mutex::Lock _l(_lock);
+ _externalConfig(ec);
+ }
+
+ /**
+ * Get current network config
+ *
+ * This returns a const reference to the network config in place, which is safe
+ * to concurrently access but *may* change during access. Normally this isn't a
+ * problem, but if it is use configCopy().
+ *
+ * @return Network configuration (may be a null config if we don't have one yet)
+ */
+ inline const NetworkConfig &config() const { return _config; }
+
+ /**
+ * @return A thread-safe copy of our NetworkConfig instead of a const reference
+ */
+ inline NetworkConfig configCopy() const
+ {
+ Mutex::Lock _l(_lock);
+ return _config;
+ }
+
+ /**
+ * @return True if this network has a valid config
+ */
+ inline bool hasConfig() const { return (_config); }
+
+ /**
+ * @return Ethernet MAC address for this network's local interface
+ */
+ inline const MAC &mac() const throw() { return _mac; }
+
+ /**
+ * Find the node on this network that has this MAC behind it (if any)
+ *
+ * @param mac MAC address
+ * @return ZeroTier address of bridge to this MAC
+ */
+ inline Address findBridgeTo(const MAC &mac) const
+ {
+ Mutex::Lock _l(_lock);
+ const Address *const br = _remoteBridgeRoutes.get(mac);
+ if (br)
+ return *br;
+ return Address();
+ }
+
+ /**
+ * Set a bridge route
+ *
+ * @param mac MAC address of destination
+ * @param addr Bridge this MAC is reachable behind
+ */
+ void learnBridgeRoute(const MAC &mac,const Address &addr);
+
+ /**
+ * Learn a multicast group that is bridged to our tap device
+ *
+ * @param mg Multicast group
+ * @param now Current time
+ */
+ void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now);
+
+ /**
+ * @return True if traffic on this network's tap is enabled
+ */
+ inline bool enabled() const throw() { return _enabled; }
+
+ /**
+ * @param enabled Should traffic be allowed on this network?
+ */
+ void setEnabled(bool enabled);
+
+ /**
+ * Destroy this network
+ *
+ * This causes the network to disable itself, destroy its tap device, and on
+ * delete to delete all trace of itself on disk and remove any persistent tap
+ * device instances. Call this when a network is being removed from the system.
+ */
+ void destroy();
+
+ /**
+ * @return Pointer to user PTR (modifiable user ptr used in API)
+ */
+ inline void **userPtr() throw() { return &_uPtr; }
+
+ inline bool operator==(const Network &n) const throw() { return (_id == n._id); }
+ inline bool operator!=(const Network &n) const throw() { return (_id != n._id); }
+ inline bool operator<(const Network &n) const throw() { return (_id < n._id); }
+ inline bool operator>(const Network &n) const throw() { return (_id > n._id); }
+ inline bool operator<=(const Network &n) const throw() { return (_id <= n._id); }
+ inline bool operator>=(const Network &n) const throw() { return (_id >= n._id); }
+
+private:
+ ZT_VirtualNetworkStatus _status() const;
+ void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
+ bool _isAllowed(const SharedPtr<Peer> &peer) const;
+ void _announceMulticastGroups();
+ void _announceMulticastGroupsTo(const SharedPtr<Peer> &peer,const std::vector<MulticastGroup> &allMulticastGroups) const;
+ std::vector<MulticastGroup> _allMulticastGroups() const;
+
+ const RuntimeEnvironment *RR;
+ void *_uPtr;
+ uint64_t _id;
+ MAC _mac; // local MAC address
+ volatile bool _enabled;
+ volatile bool _portInitialized;
+
+ std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap)
+ Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
+ Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
+
+ NetworkConfig _config;
+ volatile uint64_t _lastConfigUpdate;
+
+ volatile bool _destroyed;
+
+ enum {
+ NETCONF_FAILURE_NONE,
+ NETCONF_FAILURE_ACCESS_DENIED,
+ NETCONF_FAILURE_NOT_FOUND,
+ NETCONF_FAILURE_INIT_FAILED
+ } _netconfFailure;
+ volatile int _portError; // return value from port config callback
+
+ Mutex _lock;
+
+ AtomicCounter __refCount;
+};
+
+} // naemspace ZeroTier
+
+#endif
diff --git a/zerotierone/node/NetworkConfig.cpp b/zerotierone/node/NetworkConfig.cpp
new file mode 100644
index 0000000..58a48fa
--- /dev/null
+++ b/zerotierone/node/NetworkConfig.cpp
@@ -0,0 +1,180 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+
+#include "NetworkConfig.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+
+void NetworkConfig::fromDictionary(const char *ds,unsigned int dslen)
+{
+ static const std::string zero("0");
+ static const std::string one("1");
+
+ Dictionary d(ds,dslen);
+
+ memset(this,0,sizeof(NetworkConfig));
+
+ // NOTE: d.get(name) throws if not found, d.get(name,default) returns default
+
+ networkId = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,"0").c_str());
+ if (!networkId)
+ throw std::invalid_argument("configuration contains zero network ID");
+
+ timestamp = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,"0").c_str());
+ revision = Utils::hexStrToU64(d.get(ZT_NETWORKCONFIG_DICT_KEY_REVISION,"1").c_str()); // older controllers don't send this, so default to 1
+ issuedTo = Address(d.get(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,"0"));
+
+ multicastLimit = Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,zero).c_str());
+ if (multicastLimit == 0) multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT;
+
+ flags |= ((Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING,zero).c_str()) != 0) ? ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING : 0);
+ flags |= ((Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST,one).c_str()) != 0) ? ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST : 0);
+
+ this->type = (Utils::hexStrToUInt(d.get(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE,one).c_str()) != 0) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
+
+ std::string nametmp(d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,""));
+ for(unsigned long i=0;((i<ZT_MAX_NETWORK_SHORT_NAME_LENGTH)&&(i<nametmp.length()));++i)
+ name[i] = (char)nametmp[i];
+ // we zeroed the entire structure above and _name is ZT_MAX_NETWORK_SHORT_NAME_LENGTH+1, so it will always null-terminate
+
+ std::vector<std::string> activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) {
+ if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields
+ Address tmp(*a);
+ if (!tmp.isReserved()) {
+ uint64_t specialist = tmp.toInt();
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((specialists[i] & 0xffffffffffULL) == specialist) {
+ specialists[i] |= ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE;
+ specialist = 0;
+ break;
+ }
+ }
+ if ((specialist)&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS))
+ specialists[specialistCount++] = specialist | ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE;
+ }
+ }
+ }
+
+ std::string ipAddrs(d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC,std::string()));
+ {
+ std::string v6s(d.get(ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC,std::string()));
+ if (v6s.length()) {
+ if (ipAddrs.length())
+ ipAddrs.push_back(',');
+ ipAddrs.append(v6s);
+ }
+ }
+ std::vector<std::string> ipAddrsSplit(Utils::split(ipAddrs.c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator ipstr(ipAddrsSplit.begin());ipstr!=ipAddrsSplit.end();++ipstr) {
+ InetAddress addr(*ipstr);
+ switch(addr.ss_family) {
+ case AF_INET:
+ if ((!addr.netmaskBits())||(addr.netmaskBits() > 32))
+ continue;
+ break;
+ case AF_INET6:
+ if ((!addr.netmaskBits())||(addr.netmaskBits() > 128))
+ continue;
+ break;
+ default: // ignore unrecognized address types or junk/empty fields
+ continue;
+ }
+ if (!addr.isNetwork()) {
+ if ((staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)&&(std::find(&(staticIps[0]),&(staticIps[staticIpCount]),addr) == &(staticIps[staticIpCount])))
+ staticIps[staticIpCount++] = addr;
+ }
+ }
+ std::sort(&(staticIps[0]),&(staticIps[staticIpCount]));
+
+ /* Old versions don't support gateways anyway, so ignore this in old netconfs
+ std::vector<std::string> gatewaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS,"").c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator gwstr(gatewaysSplit.begin());gwstr!=gatewaysSplit.end();++gwstr) {
+ InetAddress gw(*gwstr);
+ if ((gw)&&(_gatewayCount < ZT_MAX_NETWORK_GATEWAYS)&&(std::find(&(_gateways[0]),&(_gateways[_gatewayCount]),gw) == &(_gateways[_gatewayCount])))
+ _gateways[_gatewayCount++] = gw;
+ }
+ std::sort(&(_gateways[0]),&(_gateways[_gatewayCount]));
+ */
+
+ std::vector<std::string> relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) {
+ if (r->length() >= ZT_ADDRESS_LENGTH_HEX) {
+ Address zt(r->substr(0,ZT_ADDRESS_LENGTH_HEX).c_str());
+ InetAddress phy[2];
+ unsigned int phyCount = 0;
+ const std::size_t semi(r->find(';'));
+ if ((semi > ZT_ADDRESS_LENGTH_HEX)&&(semi < (r->length() - 2))) {
+ std::vector<std::string> phySplit(Utils::split(r->substr(semi+1).c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator p(phySplit.begin());((p!=phySplit.end())&&(phyCount < 2));++p) {
+ phy[phyCount] = InetAddress(*p);
+ if (phy[phyCount])
+ ++phyCount;
+ else phy[phyCount].zero();
+ }
+ }
+
+ uint64_t specialist = zt.toInt();
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((specialists[i] & 0xffffffffffULL) == specialist) {
+ specialists[i] |= ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY;
+ specialist = 0;
+ break;
+ }
+ }
+
+ if ((specialist)&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS))
+ specialists[specialistCount++] = specialist | ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY;
+
+ if ((phy[0])&&(pinnedCount < ZT_MAX_NETWORK_PINNED)) {
+ pinned[pinnedCount].zt = zt;
+ pinned[pinnedCount].phy = phy[0];
+ ++pinnedCount;
+ }
+ if ((phy[1])&&(pinnedCount < ZT_MAX_NETWORK_PINNED)) {
+ pinned[pinnedCount].zt = zt;
+ pinned[pinnedCount].phy = phy[0];
+ ++pinnedCount;
+ }
+ }
+ }
+
+ std::vector<std::string> ets(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES,"").c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator et(ets.begin());et!=ets.end();++et) {
+ unsigned int et2 = Utils::hexStrToUInt(et->c_str()) & 0xffff;
+ if ((ruleCount + 1) < ZT_MAX_NETWORK_RULES) {
+ if (et2) {
+ rules[ruleCount].t = ZT_NETWORK_RULE_MATCH_ETHERTYPE;
+ rules[ruleCount].v.etherType = (uint16_t)et2;
+ ++ruleCount;
+ }
+ rules[ruleCount++].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
+ }
+ }
+
+ this->com.fromString(d.get(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP,std::string()));
+}
+
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/NetworkConfig.hpp b/zerotierone/node/NetworkConfig.hpp
new file mode 100644
index 0000000..a7ed77b
--- /dev/null
+++ b/zerotierone/node/NetworkConfig.hpp
@@ -0,0 +1,750 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NETWORKCONFIG_HPP
+#define ZT_NETWORKCONFIG_HPP
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <vector>
+#include <stdexcept>
+#include <algorithm>
+
+#include "../include/ZeroTierOne.h"
+
+#include "Constants.hpp"
+#include "Buffer.hpp"
+#include "InetAddress.hpp"
+#include "MulticastGroup.hpp"
+#include "Address.hpp"
+#include "CertificateOfMembership.hpp"
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+#include "Dictionary.hpp"
+#include <string>
+#endif
+
+/**
+ * Flag: allow passive bridging (experimental)
+ */
+#define ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING 0x0001
+
+/**
+ * Flag: enable broadcast
+ */
+#define ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST 0x0002
+
+/**
+ * Device is a network preferred relay
+ */
+#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY 0x0000010000000000ULL
+
+/**
+ * Device is an active bridge
+ */
+#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL
+
+/**
+ * An anchor is a device that is willing to be one and has been online/stable for a long time on this network
+ */
+#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL
+
+namespace ZeroTier {
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+
+// Fields for meta-data sent with network config requests
+#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv"
+#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv"
+#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION "revv"
+
+// These dictionary keys are short so they don't take up much room in
+// netconf response packets.
+
+// integer(hex)[,integer(hex),...]
+#define ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES "et"
+// network ID
+#define ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID "nwid"
+// integer(hex)
+#define ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP "ts"
+// integer(hex)
+#define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r"
+// address of member
+#define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id"
+// integer(hex)
+#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT "ml"
+// 0/1
+#define ZT_NETWORKCONFIG_DICT_KEY_PRIVATE "p"
+// text
+#define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
+// text
+#define ZT_NETWORKCONFIG_DICT_KEY_DESC "d"
+// IP/bits[,IP/bits,...]
+// Note that IPs that end in all zeroes are routes with no assignment in them.
+#define ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC "v4s"
+// IP/bits[,IP/bits,...]
+// Note that IPs that end in all zeroes are routes with no assignment in them.
+#define ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC "v6s"
+// serialized CertificateOfMembership
+#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP "com"
+// 0/1
+#define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST "eb"
+// 0/1
+#define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING "pb"
+// node[,node,...]
+#define ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES "ab"
+// node;IP/port[,node;IP/port]
+#define ZT_NETWORKCONFIG_DICT_KEY_RELAYS "rl"
+// IP/metric[,IP/metric,...]
+#define ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS "gw"
+
+#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
+
+/**
+ * Network configuration received from network controller nodes
+ *
+ * This is a memcpy()'able structure and is safe (in a crash sense) to modify
+ * without locks.
+ */
+class NetworkConfig
+{
+public:
+ /**
+ * Network preferred relay with optional physical endpoint addresses
+ *
+ * This is used by the convenience relays() method.
+ */
+ struct Relay
+ {
+ Address address;
+ InetAddress phy4,phy6;
+ };
+
+ /**
+ * Create an instance of a NetworkConfig for the test network ID
+ *
+ * The test network ID is defined as ZT_TEST_NETWORK_ID. This is a
+ * "fake" network with no real controller and default options.
+ *
+ * @param self This node's ZT address
+ * @return Configuration for test network ID
+ */
+ static inline NetworkConfig createTestNetworkConfig(const Address &self)
+ {
+ NetworkConfig nc;
+
+ nc.networkId = ZT_TEST_NETWORK_ID;
+ nc.timestamp = 1;
+ nc.revision = 1;
+ nc.issuedTo = self;
+ nc.multicastLimit = ZT_MULTICAST_DEFAULT_LIMIT;
+ nc.flags = ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
+ nc.type = ZT_NETWORK_TYPE_PUBLIC;
+
+ nc.rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
+ nc.ruleCount = 1;
+
+ Utils::snprintf(nc.name,sizeof(nc.name),"ZT_TEST_NETWORK");
+
+ // Make up a V4 IP from 'self' in the 10.0.0.0/8 range -- no
+ // guarantee of uniqueness but collisions are unlikely.
+ uint32_t ip = (uint32_t)((self.toInt() & 0x00ffffff) | 0x0a000000); // 10.x.x.x
+ if ((ip & 0x000000ff) == 0x000000ff) ip ^= 0x00000001; // but not ending in .255
+ if ((ip & 0x000000ff) == 0x00000000) ip ^= 0x00000001; // or .0
+ nc.staticIps[0] = InetAddress(Utils::hton(ip),8);
+
+ // Assign an RFC4193-compliant IPv6 address -- will never collide
+ nc.staticIps[1] = InetAddress::makeIpv6rfc4193(ZT_TEST_NETWORK_ID,self.toInt());
+
+ nc.staticIpCount = 2;
+
+ return nc;
+ }
+
+ NetworkConfig()
+ {
+ memset(this,0,sizeof(NetworkConfig));
+ }
+
+ NetworkConfig(const NetworkConfig &nc)
+ {
+ memcpy(this,&nc,sizeof(NetworkConfig));
+ }
+
+ inline NetworkConfig &operator=(const NetworkConfig &nc)
+ {
+ memcpy(this,&nc,sizeof(NetworkConfig));
+ return *this;
+ }
+
+ /**
+ * @param etherType Ethernet frame type to check
+ * @return True if allowed on this network
+ */
+ inline bool permitsEtherType(unsigned int etherType) const
+ {
+ unsigned int et = 0;
+ for(unsigned int i=0;i<ruleCount;++i) {
+ ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f);
+ if (rt == ZT_NETWORK_RULE_MATCH_ETHERTYPE) {
+ et = rules[i].v.etherType;
+ } else if (rt == ZT_NETWORK_RULE_ACTION_ACCEPT) {
+ if ((!et)||(et == etherType))
+ return true;
+ et = 0;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return True if passive bridging is allowed (experimental)
+ */
+ inline bool allowPassiveBridging() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); }
+
+ /**
+ * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
+ */
+ inline bool enableBroadcast() const throw() { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
+
+ /**
+ * @return Network type is public (no access control)
+ */
+ inline bool isPublic() const throw() { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
+
+ /**
+ * @return Network type is private (certificate access control)
+ */
+ inline bool isPrivate() const throw() { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
+
+ /**
+ * @return ZeroTier addresses of devices on this network designated as active bridges
+ */
+ inline std::vector<Address> activeBridges() const
+ {
+ std::vector<Address> r;
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
+ r.push_back(Address(specialists[i]));
+ }
+ return r;
+ }
+
+ /**
+ * @return ZeroTier addresses of "anchor" devices on this network
+ */
+ inline std::vector<Address> anchors() const
+ {
+ std::vector<Address> r;
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
+ r.push_back(Address(specialists[i]));
+ }
+ return r;
+ }
+
+ /**
+ * Get pinned physical address for a given ZeroTier address, if any
+ *
+ * @param zt ZeroTier address
+ * @param af Address family (e.g. AF_INET) or 0 for the first we find of any type
+ * @return Physical address, if any
+ */
+ inline InetAddress findPinnedAddress(const Address &zt,unsigned int af) const
+ {
+ for(unsigned int i=0;i<pinnedCount;++i) {
+ if (pinned[i].zt == zt) {
+ if ((af == 0)||((unsigned int)pinned[i].phy.ss_family == af))
+ return pinned[i].phy;
+ }
+ }
+ return InetAddress();
+ }
+
+ /**
+ * This gets network preferred relays with their static physical address if one is defined
+ *
+ * @return Network-preferred relays for this network (if none, only roots will be used)
+ */
+ inline std::vector<Relay> relays() const
+ {
+ std::vector<Relay> r;
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY) != 0) {
+ r.push_back(Relay());
+ r.back().address = specialists[i];
+ r.back().phy4 = findPinnedAddress(r.back().address,AF_INET);
+ r.back().phy6 = findPinnedAddress(r.back().address,AF_INET6);
+ }
+ }
+ return r;
+ }
+
+ /**
+ * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
+ * @return True if this network allows bridging
+ */
+ inline bool permitsBridging(const Address &fromPeer) const
+ {
+ if ((flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0)
+ return true;
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Iterate through relays efficiently
+ *
+ * @param ptr Value-result parameter -- start by initializing with zero, then call until return is null
+ * @return Address of relay or NULL if no more
+ */
+ Address nextRelay(unsigned int &ptr) const
+ {
+ while (ptr < specialistCount) {
+ if ((specialists[ptr] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY) != 0) {
+ return Address(specialists[ptr]);
+ }
+ ++ptr;
+ }
+ return Address();
+ }
+
+ /**
+ * @param zt ZeroTier address
+ * @return True if this address is a relay
+ */
+ bool isRelay(const Address &zt) const
+ {
+ for(unsigned int i=0;i<specialistCount;++i) {
+ if ((zt == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_NETWORK_PREFERRED_RELAY) != 0))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return True if this network config is non-NULL
+ */
+ inline operator bool() const throw() { return (networkId != 0); }
+
+ inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
+ inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ b.append((uint16_t)1); // version
+
+ b.append((uint64_t)networkId);
+ b.append((uint64_t)timestamp);
+ b.append((uint64_t)revision);
+ issuedTo.appendTo(b);
+ b.append((uint32_t)multicastLimit);
+ b.append((uint32_t)flags);
+ b.append((uint8_t)type);
+
+ unsigned int nl = (unsigned int)strlen(name);
+ if (nl > 255) nl = 255; // sanity check
+ b.append((uint8_t)nl);
+ b.append((const void *)name,nl);
+
+ b.append((uint16_t)specialistCount);
+ for(unsigned int i=0;i<specialistCount;++i)
+ b.append((uint64_t)specialists[i]);
+
+ b.append((uint16_t)routeCount);
+ for(unsigned int i=0;i<routeCount;++i) {
+ reinterpret_cast<const InetAddress *>(&(routes[i].target))->serialize(b);
+ reinterpret_cast<const InetAddress *>(&(routes[i].via))->serialize(b);
+ }
+
+ b.append((uint16_t)staticIpCount);
+ for(unsigned int i=0;i<staticIpCount;++i)
+ staticIps[i].serialize(b);
+
+ b.append((uint16_t)pinnedCount);
+ for(unsigned int i=0;i<pinnedCount;++i) {
+ pinned[i].zt.appendTo(b);
+ pinned[i].phy.serialize(b);
+ }
+
+ b.append((uint16_t)ruleCount);
+ for(unsigned int i=0;i<ruleCount;++i) {
+ b.append((uint8_t)rules[i].t);
+ switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f)) {
+ //case ZT_NETWORK_RULE_ACTION_DROP:
+ //case ZT_NETWORK_RULE_ACTION_ACCEPT:
+ default:
+ b.append((uint8_t)0);
+ break;
+ case ZT_NETWORK_RULE_ACTION_TEE:
+ case ZT_NETWORK_RULE_ACTION_REDIRECT:
+ case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
+ case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
+ b.append((uint8_t)5);
+ Address(rules[i].v.zt).appendTo(b);
+ break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_ID:
+ b.append((uint8_t)2);
+ b.append((uint16_t)rules[i].v.vlanId);
+ break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
+ b.append((uint8_t)1);
+ b.append((uint8_t)rules[i].v.vlanPcp);
+ break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
+ b.append((uint8_t)1);
+ b.append((uint8_t)rules[i].v.vlanDei);
+ break;
+ case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
+ b.append((uint8_t)2);
+ b.append((uint16_t)rules[i].v.etherType);
+ break;
+ case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_MAC_DEST:
+ b.append((uint8_t)6);
+ b.append(rules[i].v.mac,6);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
+ b.append((uint8_t)5);
+ b.append(&(rules[i].v.ipv4.ip),4);
+ b.append((uint8_t)rules[i].v.ipv4.mask);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
+ b.append((uint8_t)17);
+ b.append(rules[i].v.ipv6.ip,16);
+ b.append((uint8_t)rules[i].v.ipv6.mask);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_TOS:
+ b.append((uint8_t)1);
+ b.append((uint8_t)rules[i].v.ipTos);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
+ b.append((uint8_t)1);
+ b.append((uint8_t)rules[i].v.ipProtocol);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
+ case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
+ b.append((uint8_t)4);
+ b.append((uint16_t)rules[i].v.port[0]);
+ b.append((uint16_t)rules[i].v.port[1]);
+ break;
+ case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
+ b.append((uint8_t)8);
+ b.append((uint64_t)rules[i].v.characteristics);
+ break;
+ case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
+ b.append((uint8_t)4);
+ b.append((uint16_t)rules[i].v.frameSize[0]);
+ b.append((uint16_t)rules[i].v.frameSize[1]);
+ break;
+ case ZT_NETWORK_RULE_MATCH_TCP_RELATIVE_SEQUENCE_NUMBER_RANGE:
+ b.append((uint8_t)8);
+ b.append((uint32_t)rules[i].v.tcpseq[0]);
+ b.append((uint32_t)rules[i].v.tcpseq[1]);
+ break;
+ }
+ }
+
+ this->com.serialize(b);
+
+ b.append((uint16_t)0); // extended bytes, currently 0 since unused
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ memset(this,0,sizeof(NetworkConfig));
+
+ unsigned int p = startAt;
+
+ if (b.template at<uint16_t>(p) != 1)
+ throw std::invalid_argument("unrecognized version");
+ p += 2;
+
+ networkId = b.template at<uint64_t>(p); p += 8;
+ timestamp = b.template at<uint64_t>(p); p += 8;
+ revision = b.template at<uint64_t>(p); p += 8;
+ issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
+ multicastLimit = (unsigned int)b.template at<uint32_t>(p); p += 4;
+ flags = (unsigned int)b.template at<uint32_t>(p); p += 4;
+ type = (ZT_VirtualNetworkType)b[p++];
+
+ unsigned int nl = (unsigned int)b[p++];
+ memcpy(this->name,b.field(p,nl),std::min(nl,(unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH));
+ p += nl;
+ // _name will always be null terminated since field size is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1
+
+ specialistCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
+ if (specialistCount > ZT_MAX_NETWORK_SPECIALISTS)
+ throw std::invalid_argument("overflow (specialists)");
+ for(unsigned int i=0;i<specialistCount;++i) {
+ specialists[i] = b.template at<uint64_t>(p); p += 8;
+ }
+
+ routeCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
+ if (routeCount > ZT_MAX_NETWORK_ROUTES)
+ throw std::invalid_argument("overflow (routes)");
+ for(unsigned int i=0;i<routeCount;++i) {
+ p += reinterpret_cast<InetAddress *>(&(routes[i].target))->deserialize(b,p);
+ p += reinterpret_cast<InetAddress *>(&(routes[i].via))->deserialize(b,p);
+ }
+
+ staticIpCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
+ if (staticIpCount > ZT_MAX_ZT_ASSIGNED_ADDRESSES)
+ throw std::invalid_argument("overflow (static IPs)");
+ for(unsigned int i=0;i<staticIpCount;++i) {
+ p += staticIps[i].deserialize(b,p);
+ }
+
+ pinnedCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
+ if (pinnedCount > ZT_MAX_NETWORK_PINNED)
+ throw std::invalid_argument("overflow (static addresses)");
+ for(unsigned int i=0;i<pinnedCount;++i) {
+ pinned[i].zt.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
+ p += pinned[i].phy.deserialize(b,p);
+ }
+
+ ruleCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
+ if (ruleCount > ZT_MAX_NETWORK_RULES)
+ throw std::invalid_argument("overflow (rules)");
+ for(unsigned int i=0;i<ruleCount;++i) {
+ rules[i].t = (uint8_t)b[p++];
+ unsigned int rlen = (unsigned int)b[p++];
+ switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x7f)) {
+ //case ZT_NETWORK_RULE_ACTION_DROP:
+ //case ZT_NETWORK_RULE_ACTION_ACCEPT:
+ default:
+ break;
+ case ZT_NETWORK_RULE_ACTION_TEE:
+ case ZT_NETWORK_RULE_ACTION_REDIRECT:
+ case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
+ case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: {
+ Address tmp;
+ tmp.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
+ rules[i].v.zt = tmp.toInt();
+ } break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_ID:
+ rules[i].v.vlanId = b.template at<uint16_t>(p);
+ break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
+ rules[i].v.vlanPcp = (uint8_t)b[p];
+ break;
+ case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
+ rules[i].v.vlanDei = (uint8_t)b[p];
+ break;
+ case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
+ rules[i].v.etherType = b.template at<uint16_t>(p);
+ break;
+ case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_MAC_DEST:
+ memcpy(rules[i].v.mac,b.field(p,6),6);
+ break;
+ case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
+ memcpy(&(rules[i].v.ipv4.ip),b.field(p,4),4);
+ rules[i].v.ipv4.mask = (uint8_t)b[p+4];
+ break;
+ case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
+ case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
+ memcpy(rules[i].v.ipv6.ip,b.field(p,16),16);
+ rules[i].v.ipv6.mask = (uint8_t)b[p+16];
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_TOS:
+ rules[i].v.ipTos = (uint8_t)b[p];
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
+ rules[i].v.ipProtocol = (uint8_t)b[p];
+ break;
+ case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
+ case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
+ rules[i].v.port[0] = b.template at<uint16_t>(p);
+ rules[i].v.port[1] = b.template at<uint16_t>(p+2);
+ break;
+ case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
+ rules[i].v.characteristics = b.template at<uint64_t>(p);
+ break;
+ case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
+ rules[i].v.frameSize[0] = b.template at<uint16_t>(p);
+ rules[i].v.frameSize[1] = b.template at<uint16_t>(p+2);
+ break;
+ case ZT_NETWORK_RULE_MATCH_TCP_RELATIVE_SEQUENCE_NUMBER_RANGE:
+ rules[i].v.tcpseq[0] = b.template at<uint32_t>(p);
+ rules[i].v.tcpseq[1] = b.template at<uint32_t>(p + 4);
+ break;
+ }
+ p += rlen;
+ }
+
+ p += this->com.deserialize(b,p);
+
+ p += b.template at<uint16_t>(p) + 2;
+
+ return (p - startAt);
+ }
+
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ void fromDictionary(const char *ds,unsigned int dslen);
+#endif
+
+ /*
+ inline void dump() const
+ {
+ printf("networkId==%.16llx\n",networkId);
+ printf("timestamp==%llu\n",timestamp);
+ printf("revision==%llu\n",revision);
+ printf("issuedTo==%.10llx\n",issuedTo.toInt());
+ printf("multicastLimit==%u\n",multicastLimit);
+ printf("flags=%.8lx\n",(unsigned long)flags);
+ printf("specialistCount==%u\n",specialistCount);
+ for(unsigned int i=0;i<specialistCount;++i)
+ printf(" specialists[%u]==%.16llx\n",i,specialists[i]);
+ printf("routeCount==%u\n",routeCount);
+ for(unsigned int i=0;i<routeCount;++i) {
+ printf(" routes[i].target==%s\n",reinterpret_cast<const struct sockaddr_storage *>(&(routes[i].target))->toString().c_str());
+ printf(" routes[i].via==%s\n",reinterpret_cast<const struct sockaddr_storage *>(&(routes[i].via))->toString().c_str());
+ }
+ printf("staticIpCount==%u\n",staticIpCount);
+ for(unsigned int i=0;i<staticIpCount;++i)
+ printf(" staticIps[i]==%s\n",staticIps[i].toString().c_str());
+ printf("pinnedCount==%u\n",pinnedCount);
+ for(unsigned int i=0;i<pinnedCount;++i) {
+ printf(" pinned[i].zt==%s\n",pinned[i].zt->toString().c_str());
+ printf(" pinned[i].phy==%s\n",pinned[i].zt->toString().c_str());
+ }
+ printf("ruleCount==%u\n",ruleCount);
+ printf("name==%s\n",name);
+ printf("com==%s\n",com.toString().c_str());
+ }
+ */
+
+ /**
+ * Network ID that this configuration applies to
+ */
+ uint64_t networkId;
+
+ /**
+ * Controller-side time of config generation/issue
+ */
+ uint64_t timestamp;
+
+ /**
+ * Controller-side revision counter for this configuration
+ */
+ uint64_t revision;
+
+ /**
+ * Address of device to which this config is issued
+ */
+ Address issuedTo;
+
+ /**
+ * Maximum number of recipients per multicast (not including active bridges)
+ */
+ unsigned int multicastLimit;
+
+ /**
+ * Flags (32-bit)
+ */
+ unsigned int flags;
+
+ /**
+ * Number of specialists
+ */
+ unsigned int specialistCount;
+
+ /**
+ * Number of routes
+ */
+ unsigned int routeCount;
+
+ /**
+ * Number of ZT-managed static IP assignments
+ */
+ unsigned int staticIpCount;
+
+ /**
+ * Number of pinned devices (devices with physical address hints)
+ */
+ unsigned int pinnedCount;
+
+ /**
+ * Number of rule table entries
+ */
+ unsigned int ruleCount;
+
+ /**
+ * Specialist devices
+ *
+ * For each entry the least significant 40 bits are the device's ZeroTier
+ * address and the most significant 24 bits are flags indicating its role.
+ */
+ uint64_t specialists[ZT_MAX_NETWORK_SPECIALISTS];
+
+ /**
+ * Statically defined "pushed" routes (including default gateways)
+ */
+ ZT_VirtualNetworkRoute routes[ZT_MAX_NETWORK_ROUTES];
+
+ /**
+ * Static IP assignments
+ */
+ InetAddress staticIps[ZT_MAX_ZT_ASSIGNED_ADDRESSES];
+
+ /**
+ * Pinned devices with physical address hints
+ *
+ * These can be used to specify a physical address where a given device
+ * can be reached. It's usually used with network relays (specialists).
+ */
+ struct {
+ Address zt;
+ InetAddress phy;
+ } pinned[ZT_MAX_NETWORK_PINNED];
+
+ /**
+ * Rules table
+ */
+ ZT_VirtualNetworkRule rules[ZT_MAX_NETWORK_RULES];
+
+ /**
+ * Network type (currently just public or private)
+ */
+ ZT_VirtualNetworkType type;
+
+ /**
+ * Network short name or empty string if not defined
+ */
+ char name[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1];
+
+ /**
+ * Certficiate of membership (for private networks)
+ */
+ CertificateOfMembership com;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/NetworkConfigRequestMetaData.hpp b/zerotierone/node/NetworkConfigRequestMetaData.hpp
new file mode 100644
index 0000000..2516e5e
--- /dev/null
+++ b/zerotierone/node/NetworkConfigRequestMetaData.hpp
@@ -0,0 +1,196 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NETWORKCONFIGREQUESTMETADATA_HPP
+#define ZT_NETWORKCONFIGREQUESTMETADATA_HPP
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Constants.hpp"
+#include "NetworkConfig.hpp"
+#include "Buffer.hpp"
+#include "Packet.hpp"
+
+#include "../version.h"
+
+/**
+ * Maximum length of the auth field (including terminating NULL, since it's a C-style string)
+ *
+ * Actual max length not including NULL is this minus one.
+ */
+#define ZT_NETWORK_CONFIG_REQUEST_METADATA_MAX_AUTH_LENGTH 2048
+
+namespace ZeroTier {
+
+/**
+ * Network configuration request meta data
+ */
+class NetworkConfigRequestMetaData
+{
+public:
+ /**
+ * Construct an empty meta-data object with zero/null values
+ */
+ NetworkConfigRequestMetaData()
+ {
+ memset(this,0,sizeof(NetworkConfigRequestMetaData));
+ }
+
+ /**
+ * Initialize with defaults from this node's config and version
+ */
+ inline void initWithDefaults()
+ {
+ memset(this,0,sizeof(NetworkConfigRequestMetaData));
+ vendor = ZT_VENDOR_ZEROTIER;
+ platform = ZT_PLATFORM_UNSPECIFIED;
+ architecture = ZT_ARCHITECTURE_UNSPECIFIED;
+ majorVersion = ZEROTIER_ONE_VERSION_MAJOR;
+ minorVersion = ZEROTIER_ONE_VERSION_MINOR;
+ revision = ZEROTIER_ONE_VERSION_REVISION;
+ protocolVersion = ZT_PROTO_VERSION;
+ }
+
+ /**
+ * Zero/null everything
+ */
+ inline void clear()
+ {
+ memset(this,0,sizeof(NetworkConfigRequestMetaData));
+ }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ /* Unlike network config we always send the old fields. Newer network
+ * controllers will detect the presence of the new serialized data by
+ * detecting extra data after the terminating NULL. But always sending
+ * these maintains backward compatibility with old controllers. This
+ * appends a terminating NULL which seperates the old legacy meta-data
+ * from the new packed binary format that we send after. */
+ b.appendCString("majv=" ZEROTIER_ONE_VERSION_MAJOR_S_HEX "\nminv=" ZEROTIER_ONE_VERSION_MINOR_S_HEX "\nrevv=" ZEROTIER_ONE_VERSION_REVISION_S_HEX "\n");
+
+ b.append((uint16_t)1); // serialization version
+
+ b.append((uint64_t)buildId);
+ b.append((uint64_t)flags);
+ b.append((uint16_t)vendor);
+ b.append((uint16_t)platform);
+ b.append((uint16_t)architecture);
+ b.append((uint16_t)majorVersion);
+ b.append((uint16_t)minorVersion);
+ b.append((uint16_t)revision);
+ b.append((uint16_t)protocolVersion);
+
+ const unsigned int tl = strlen(auth);
+ b.append((uint16_t)tl);
+ b.append((const void *)auth,tl);
+
+ b.append((uint16_t)0); // extended bytes, currently 0 since unused
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ memset(this,0,sizeof(NetworkConfigRequestMetaData));
+
+ unsigned int p = startAt;
+
+ // Seek past old style meta-data
+ while (b[p]) ++p;
+ ++p;
+
+ if (b.template at<uint16_t>(p) != 1)
+ throw std::invalid_argument("unrecognized version");
+ p += 2;
+
+ buildId = b.template at<uint64_t>(p); p += 8;
+ flags = b.template at<uint64_t>(p); p += 8;
+ vendor = (ZT_Vendor)b.template at<uint16_t>(p); p += 2;
+ platform = (ZT_Platform)b.template at<uint16_t>(p); p += 2;
+ architecture = (ZT_Architecture)b.template at<uint16_t>(p); p += 2;
+ majorVersion = b.template at<uint16_t>(p); p += 2;
+ minorVersion = b.template at<uint16_t>(p); p += 2;
+ revision = b.template at<uint16_t>(p); p += 2;
+ protocolVersion = b.template at<uint16_t>(p); p += 2;
+
+ const unsigned int tl = b.template at<uint16_t>(p); p += 2;
+ memcpy(auth,b.field(p,tl),std::max(tl,(unsigned int)(ZT_NETWORK_CONFIG_REQUEST_METADATA_MAX_AUTH_LENGTH - 1)));
+ p += tl;
+
+ p += b.template at<uint16_t>(p) + 2;
+
+ return (p - startAt);
+ }
+
+ /**
+ * Authentication data (e.g. bearer=<token>) as a C-style string (always null terminated)
+ */
+ char auth[ZT_NETWORK_CONFIG_REQUEST_METADATA_MAX_AUTH_LENGTH];
+
+ /**
+ * Build ID (currently unused, must be 0)
+ */
+ uint64_t buildId;
+
+ /**
+ * Flags (currently unused, must be 0)
+ */
+ uint64_t flags;
+
+ /**
+ * ZeroTier vendor or 0 for unspecified
+ */
+ ZT_Vendor vendor;
+
+ /**
+ * ZeroTier platform or 0 for unspecified
+ */
+ ZT_Platform platform;
+
+ /**
+ * ZeroTier architecture or 0 for unspecified
+ */
+ ZT_Architecture architecture;
+
+ /**
+ * ZeroTier software major version
+ */
+ unsigned int majorVersion;
+
+ /**
+ * ZeroTier software minor version
+ */
+ unsigned int minorVersion;
+
+ /**
+ * ZeroTier software revision
+ */
+ unsigned int revision;
+
+ /**
+ * ZeroTier protocol version
+ */
+ unsigned int protocolVersion;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/NetworkController.hpp b/zerotierone/node/NetworkController.hpp
new file mode 100644
index 0000000..4ab6403
--- /dev/null
+++ b/zerotierone/node/NetworkController.hpp
@@ -0,0 +1,84 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NETWORKCONFIGMASTER_HPP
+#define ZT_NETWORKCONFIGMASTER_HPP
+
+#include <stdint.h>
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Address.hpp"
+#include "Identity.hpp"
+#include "NetworkConfigRequestMetaData.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+
+/**
+ * Interface for network controller implementations
+ */
+class NetworkController
+{
+public:
+ /**
+ * Return value of doNetworkConfigRequest
+ */
+ enum ResultCode
+ {
+ NETCONF_QUERY_OK = 0,
+ NETCONF_QUERY_OBJECT_NOT_FOUND = 1,
+ NETCONF_QUERY_ACCESS_DENIED = 2,
+ NETCONF_QUERY_INTERNAL_SERVER_ERROR = 3,
+ NETCONF_QUERY_IGNORE = 4
+ };
+
+ NetworkController() {}
+ virtual ~NetworkController() {}
+
+ /**
+ * Handle a network config request, sending replies if necessary
+ *
+ * This call is permitted to block, and may be called concurrently from more
+ * than one thread. Implementations must use locks if needed.
+ *
+ * On internal server errors, the 'error' field in result can be filled in
+ * to indicate the error.
+ *
+ * @param fromAddr Originating wire address or null address if packet is not direct (or from self)
+ * @param signingId Identity that should be used to sign results -- must include private key
+ * @param identity Originating peer ZeroTier identity
+ * @param nwid 64-bit network ID
+ * @param metaData Meta-data bundled with request (if any)
+ * @param result Buffer to receive serialized network configuration data (any existing data in buffer is preserved)
+ * @return Returns NETCONF_QUERY_OK if result dictionary is valid, or an error code on error
+ */
+ virtual NetworkController::ResultCode doNetworkConfigRequest(
+ const InetAddress &fromAddr,
+ const Identity &signingId,
+ const Identity &identity,
+ uint64_t nwid,
+ const NetworkConfigRequestMetaData &metaData,
+ Buffer<8194> &result) = 0;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Node.cpp b/zerotierone/node/Node.cpp
new file mode 100644
index 0000000..bedbba9
--- /dev/null
+++ b/zerotierone/node/Node.cpp
@@ -0,0 +1,1031 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "../version.h"
+
+#include "Constants.hpp"
+#include "Node.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "NetworkController.hpp"
+#include "Switch.hpp"
+#include "Multicaster.hpp"
+#include "Topology.hpp"
+#include "Buffer.hpp"
+#include "Packet.hpp"
+#include "Address.hpp"
+#include "Identity.hpp"
+#include "SelfAwareness.hpp"
+#include "Cluster.hpp"
+#include "DeferredPackets.hpp"
+
+const struct sockaddr_storage ZT_SOCKADDR_NULL = {0};
+
+namespace ZeroTier {
+
+/****************************************************************************/
+/* Public Node interface (C++, exposed via CAPI bindings) */
+/****************************************************************************/
+
+Node::Node(
+ uint64_t now,
+ void *uptr,
+ ZT_DataStoreGetFunction dataStoreGetFunction,
+ ZT_DataStorePutFunction dataStorePutFunction,
+ ZT_WirePacketSendFunction wirePacketSendFunction,
+ ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
+ ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
+ ZT_EventCallback eventCallback) :
+ _RR(this),
+ RR(&_RR),
+ _uPtr(uptr),
+ _dataStoreGetFunction(dataStoreGetFunction),
+ _dataStorePutFunction(dataStorePutFunction),
+ _wirePacketSendFunction(wirePacketSendFunction),
+ _virtualNetworkFrameFunction(virtualNetworkFrameFunction),
+ _virtualNetworkConfigFunction(virtualNetworkConfigFunction),
+ _pathCheckFunction(pathCheckFunction),
+ _eventCallback(eventCallback),
+ _networks(),
+ _networks_m(),
+ _prngStreamPtr(0),
+ _now(now),
+ _lastPingCheck(0),
+ _lastHousekeepingRun(0)
+{
+ _online = false;
+
+ // Use Salsa20 alone as a high-quality non-crypto PRNG
+ {
+ char foo[32];
+ Utils::getSecureRandom(foo,32);
+ _prng.init(foo,256,foo);
+ memset(_prngStream,0,sizeof(_prngStream));
+ _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
+ }
+
+ {
+ std::string idtmp(dataStoreGet("identity.secret"));
+ if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) {
+ TRACE("identity.secret not found, generating...");
+ RR->identity.generate();
+ idtmp = RR->identity.toString(true);
+ if (!dataStorePut("identity.secret",idtmp,true))
+ throw std::runtime_error("unable to write identity.secret");
+ }
+ RR->publicIdentityStr = RR->identity.toString(false);
+ RR->secretIdentityStr = RR->identity.toString(true);
+ idtmp = dataStoreGet("identity.public");
+ if (idtmp != RR->publicIdentityStr) {
+ if (!dataStorePut("identity.public",RR->publicIdentityStr,false))
+ throw std::runtime_error("unable to write identity.public");
+ }
+ }
+
+ try {
+ RR->sw = new Switch(RR);
+ RR->mc = new Multicaster(RR);
+ RR->topology = new Topology(RR);
+ RR->sa = new SelfAwareness(RR);
+ RR->dp = new DeferredPackets(RR);
+ } catch ( ... ) {
+ delete RR->dp;
+ delete RR->sa;
+ delete RR->topology;
+ delete RR->mc;
+ delete RR->sw;
+ throw;
+ }
+
+ postEvent(ZT_EVENT_UP);
+}
+
+Node::~Node()
+{
+ Mutex::Lock _l(_networks_m);
+
+ _networks.clear(); // ensure that networks are destroyed before shutdow
+
+ RR->dpEnabled = 0;
+ delete RR->dp;
+ delete RR->sa;
+ delete RR->topology;
+ delete RR->mc;
+ delete RR->sw;
+#ifdef ZT_ENABLE_CLUSTER
+ delete RR->cluster;
+#endif
+}
+
+ZT_ResultCode Node::processWirePacket(
+ uint64_t now,
+ const struct sockaddr_storage *localAddress,
+ const struct sockaddr_storage *remoteAddress,
+ const void *packetData,
+ unsigned int packetLength,
+ volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ _now = now;
+ RR->sw->onRemotePacket(*(reinterpret_cast<const InetAddress *>(localAddress)),*(reinterpret_cast<const InetAddress *>(remoteAddress)),packetData,packetLength);
+ return ZT_RESULT_OK;
+}
+
+ZT_ResultCode Node::processVirtualNetworkFrame(
+ uint64_t now,
+ uint64_t nwid,
+ uint64_t sourceMac,
+ uint64_t destMac,
+ unsigned int etherType,
+ unsigned int vlanId,
+ const void *frameData,
+ unsigned int frameLength,
+ volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ _now = now;
+ SharedPtr<Network> nw(this->network(nwid));
+ if (nw) {
+ RR->sw->onLocalEthernet(nw,MAC(sourceMac),MAC(destMac),etherType,vlanId,frameData,frameLength);
+ return ZT_RESULT_OK;
+ } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
+}
+
+class _PingPeersThatNeedPing
+{
+public:
+ _PingPeersThatNeedPing(const RuntimeEnvironment *renv,uint64_t now,const std::vector<NetworkConfig::Relay> &relays) :
+ lastReceiveFromUpstream(0),
+ RR(renv),
+ _now(now),
+ _relays(relays),
+ _world(RR->topology->world())
+ {
+ }
+
+ uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay
+
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p)
+ {
+ bool upstream = false;
+ InetAddress stableEndpoint4,stableEndpoint6;
+
+ // If this is a world root, pick (if possible) both an IPv4 and an IPv6 stable endpoint to use if link isn't currently alive.
+ for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
+ if (r->identity == p->identity()) {
+ upstream = true;
+ for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)r->stableEndpoints.size();++k) {
+ const InetAddress &addr = r->stableEndpoints[ptr++ % r->stableEndpoints.size()];
+ if (!stableEndpoint4) {
+ if (addr.ss_family == AF_INET)
+ stableEndpoint4 = addr;
+ }
+ if (!stableEndpoint6) {
+ if (addr.ss_family == AF_INET6)
+ stableEndpoint6 = addr;
+ }
+ }
+ break;
+ }
+ }
+
+ if (!upstream) {
+ // If I am a root server, only ping other root servers -- roots don't ping "down"
+ // since that would just be a waste of bandwidth and could potentially cause route
+ // flapping in Cluster mode.
+ if (RR->topology->amRoot())
+ return;
+
+ // Check for network preferred relays, also considered 'upstream' and thus always
+ // pinged to keep links up. If they have stable addresses we will try them there.
+ for(std::vector<NetworkConfig::Relay>::const_iterator r(_relays.begin());r!=_relays.end();++r) {
+ if (r->address == p->address()) {
+ stableEndpoint4 = r->phy4;
+ stableEndpoint6 = r->phy6;
+ upstream = true;
+ break;
+ }
+ }
+ }
+
+ if (upstream) {
+ // "Upstream" devices are roots and relays and get special treatment -- they stay alive
+ // forever and we try to keep (if available) both IPv4 and IPv6 channels open to them.
+ bool needToContactIndirect = true;
+ if (p->doPingAndKeepalive(_now,AF_INET)) {
+ needToContactIndirect = false;
+ } else {
+ if (stableEndpoint4) {
+ needToContactIndirect = false;
+ p->sendHELLO(InetAddress(),stableEndpoint4,_now);
+ }
+ }
+ if (p->doPingAndKeepalive(_now,AF_INET6)) {
+ needToContactIndirect = false;
+ } else {
+ if (stableEndpoint6) {
+ needToContactIndirect = false;
+ p->sendHELLO(InetAddress(),stableEndpoint6,_now);
+ }
+ }
+
+ if (needToContactIndirect) {
+ // If this is an upstream and we have no stable endpoint for either IPv4 or IPv6,
+ // send a NOP indirectly if possible to see if we can get to this peer in any
+ // way whatsoever. This will e.g. find network preferred relays that lack
+ // stable endpoints by using root servers.
+ Packet outp(p->address(),RR->identity.address(),Packet::VERB_NOP);
+ RR->sw->send(outp,true,0);
+ }
+
+ lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
+ } else if (p->activelyTransferringFrames(_now)) {
+ // Normal nodes get their preferred link kept alive if the node has generated frame traffic recently
+ p->doPingAndKeepalive(_now,0);
+ }
+ }
+
+private:
+ const RuntimeEnvironment *RR;
+ uint64_t _now;
+ const std::vector<NetworkConfig::Relay> &_relays;
+ World _world;
+};
+
+ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ _now = now;
+ Mutex::Lock bl(_backgroundTasksLock);
+
+ unsigned long timeUntilNextPingCheck = ZT_PING_CHECK_INVERVAL;
+ const uint64_t timeSinceLastPingCheck = now - _lastPingCheck;
+ if (timeSinceLastPingCheck >= ZT_PING_CHECK_INVERVAL) {
+ try {
+ _lastPingCheck = now;
+
+ // Get relays and networks that need config without leaving the mutex locked
+ std::vector< NetworkConfig::Relay > networkRelays;
+ std::vector< SharedPtr<Network> > needConfig;
+ {
+ Mutex::Lock _l(_networks_m);
+ for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
+ if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig())) {
+ needConfig.push_back(n->second);
+ }
+ if (n->second->hasConfig()) {
+ std::vector<NetworkConfig::Relay> r(n->second->config().relays());
+ networkRelays.insert(networkRelays.end(),r.begin(),r.end());
+ }
+ }
+ }
+
+ // Request updated configuration for networks that need it
+ for(std::vector< SharedPtr<Network> >::const_iterator n(needConfig.begin());n!=needConfig.end();++n)
+ (*n)->requestConfiguration();
+
+ // Do pings and keepalives
+ _PingPeersThatNeedPing pfunc(RR,now,networkRelays);
+ RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc);
+
+ // Update online status, post status change as event
+ const bool oldOnline = _online;
+ _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot()));
+ if (oldOnline != _online)
+ postEvent(_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+ } else {
+ timeUntilNextPingCheck -= (unsigned long)timeSinceLastPingCheck;
+ }
+
+ if ((now - _lastHousekeepingRun) >= ZT_HOUSEKEEPING_PERIOD) {
+ try {
+ _lastHousekeepingRun = now;
+ RR->topology->clean(now);
+ RR->sa->clean(now);
+ RR->mc->clean(now);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+ }
+
+ try {
+#ifdef ZT_ENABLE_CLUSTER
+ // If clustering is enabled we have to call cluster->doPeriodicTasks() very often, so we override normal timer deadline behavior
+ if (RR->cluster) {
+ RR->sw->doTimerTasks(now);
+ RR->cluster->doPeriodicTasks();
+ *nextBackgroundTaskDeadline = now + ZT_CLUSTER_PERIODIC_TASK_PERIOD; // this is really short so just tick at this rate
+ } else {
+#endif
+ *nextBackgroundTaskDeadline = now + (uint64_t)std::max(std::min(timeUntilNextPingCheck,RR->sw->doTimerTasks(now)),(unsigned long)ZT_CORE_TIMER_TASK_GRANULARITY);
+#ifdef ZT_ENABLE_CLUSTER
+ }
+#endif
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+
+ return ZT_RESULT_OK;
+}
+
+ZT_ResultCode Node::join(uint64_t nwid,void *uptr)
+{
+ Mutex::Lock _l(_networks_m);
+ SharedPtr<Network> nw = _network(nwid);
+ if(!nw)
+ _networks.push_back(std::pair< uint64_t,SharedPtr<Network> >(nwid,SharedPtr<Network>(new Network(RR,nwid,uptr))));
+ std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<>
+ return ZT_RESULT_OK;
+}
+
+ZT_ResultCode Node::leave(uint64_t nwid,void **uptr)
+{
+ std::vector< std::pair< uint64_t,SharedPtr<Network> > > newn;
+ Mutex::Lock _l(_networks_m);
+ for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
+ if (n->first != nwid)
+ newn.push_back(*n);
+ else {
+ if (uptr)
+ *uptr = n->second->userPtr();
+ n->second->destroy();
+ }
+ }
+ _networks.swap(newn);
+ return ZT_RESULT_OK;
+}
+
+ZT_ResultCode Node::multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
+{
+ SharedPtr<Network> nw(this->network(nwid));
+ if (nw) {
+ nw->multicastSubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
+ return ZT_RESULT_OK;
+ } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
+}
+
+ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
+{
+ SharedPtr<Network> nw(this->network(nwid));
+ if (nw) {
+ nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup),(uint32_t)(multicastAdi & 0xffffffff)));
+ return ZT_RESULT_OK;
+ } else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
+}
+
+uint64_t Node::address() const
+{
+ return RR->identity.address().toInt();
+}
+
+void Node::status(ZT_NodeStatus *status) const
+{
+ status->address = RR->identity.address().toInt();
+ status->worldId = RR->topology->worldId();
+ status->worldTimestamp = RR->topology->worldTimestamp();
+ status->publicIdentity = RR->publicIdentityStr.c_str();
+ status->secretIdentity = RR->secretIdentityStr.c_str();
+ status->online = _online ? 1 : 0;
+}
+
+ZT_PeerList *Node::peers() const
+{
+ std::vector< std::pair< Address,SharedPtr<Peer> > > peers(RR->topology->allPeers());
+ std::sort(peers.begin(),peers.end());
+
+ char *buf = (char *)::malloc(sizeof(ZT_PeerList) + (sizeof(ZT_Peer) * peers.size()));
+ if (!buf)
+ return (ZT_PeerList *)0;
+ ZT_PeerList *pl = (ZT_PeerList *)buf;
+ pl->peers = (ZT_Peer *)(buf + sizeof(ZT_PeerList));
+
+ pl->peerCount = 0;
+ for(std::vector< std::pair< Address,SharedPtr<Peer> > >::iterator pi(peers.begin());pi!=peers.end();++pi) {
+ ZT_Peer *p = &(pl->peers[pl->peerCount++]);
+ p->address = pi->second->address().toInt();
+ p->lastUnicastFrame = pi->second->lastUnicastFrame();
+ p->lastMulticastFrame = pi->second->lastMulticastFrame();
+ if (pi->second->remoteVersionKnown()) {
+ p->versionMajor = pi->second->remoteVersionMajor();
+ p->versionMinor = pi->second->remoteVersionMinor();
+ p->versionRev = pi->second->remoteVersionRevision();
+ } else {
+ p->versionMajor = -1;
+ p->versionMinor = -1;
+ p->versionRev = -1;
+ }
+ p->latency = pi->second->latency();
+ p->role = RR->topology->isRoot(pi->second->identity()) ? ZT_PEER_ROLE_ROOT : ZT_PEER_ROLE_LEAF;
+
+ std::vector<Path> paths(pi->second->paths());
+ Path *bestPath = pi->second->getBestPath(_now);
+ p->pathCount = 0;
+ for(std::vector<Path>::iterator path(paths.begin());path!=paths.end();++path) {
+ memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
+ p->paths[p->pathCount].lastSend = path->lastSend();
+ p->paths[p->pathCount].lastReceive = path->lastReceived();
+ p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
+ p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
+ ++p->pathCount;
+ }
+ }
+
+ return pl;
+}
+
+ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const
+{
+ Mutex::Lock _l(_networks_m);
+ SharedPtr<Network> nw = _network(nwid);
+ if(nw) {
+ ZT_VirtualNetworkConfig *nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig));
+ nw->externalConfig(nc);
+ return nc;
+ }
+ return (ZT_VirtualNetworkConfig *)0;
+}
+
+ZT_VirtualNetworkList *Node::networks() const
+{
+ Mutex::Lock _l(_networks_m);
+
+ char *buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * _networks.size()));
+ if (!buf)
+ return (ZT_VirtualNetworkList *)0;
+ ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf;
+ nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
+
+ nl->networkCount = 0;
+ for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n)
+ n->second->externalConfig(&(nl->networks[nl->networkCount++]));
+
+ return nl;
+}
+
+void Node::freeQueryResult(void *qr)
+{
+ if (qr)
+ ::free(qr);
+}
+
+int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr)
+{
+ if (Path::isAddressValidForPath(*(reinterpret_cast<const InetAddress *>(addr)))) {
+ Mutex::Lock _l(_directPaths_m);
+ if (std::find(_directPaths.begin(),_directPaths.end(),*(reinterpret_cast<const InetAddress *>(addr))) == _directPaths.end()) {
+ _directPaths.push_back(*(reinterpret_cast<const InetAddress *>(addr)));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void Node::clearLocalInterfaceAddresses()
+{
+ Mutex::Lock _l(_directPaths_m);
+ _directPaths.clear();
+}
+
+void Node::setNetconfMaster(void *networkControllerInstance)
+{
+ RR->localNetworkController = reinterpret_cast<NetworkController *>(networkControllerInstance);
+}
+
+ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
+{
+ if (test->hopCount > 0) {
+ try {
+ Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
+ RR->identity.address().appendTo(outp);
+ outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02));
+ outp.append((uint64_t)test->timestamp);
+ outp.append((uint64_t)test->testId);
+ outp.append((uint16_t)0); // originator credential length, updated later
+ if (test->credentialNetworkId) {
+ outp.append((uint8_t)0x01);
+ outp.append((uint64_t)test->credentialNetworkId);
+ outp.setAt<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9);
+ }
+ outp.append((uint16_t)0);
+ C25519::Signature sig(RR->identity.sign(reinterpret_cast<const char *>(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD));
+ outp.append((uint16_t)sig.size());
+ outp.append(sig.data,(unsigned int)sig.size());
+ outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator
+ for(unsigned int h=1;h<test->hopCount;++h) {
+ outp.append((uint8_t)0);
+ outp.append((uint8_t)(test->hops[h].breadth & 0xff));
+ for(unsigned int a=0;a<test->hops[h].breadth;++a)
+ Address(test->hops[h].addresses[a]).appendTo(outp);
+ }
+
+ for(unsigned int a=0;a<test->hops[0].breadth;++a) {
+ outp.newInitializationVector();
+ outp.setDestination(Address(test->hops[0].addresses[a]));
+ RR->sw->send(outp,true,0);
+ }
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet
+ }
+ }
+
+ {
+ test->_internalPtr = reinterpret_cast<void *>(reportCallback);
+ Mutex::Lock _l(_circuitTests_m);
+ if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end())
+ _circuitTests.push_back(test);
+ }
+
+ return ZT_RESULT_OK;
+}
+
+void Node::circuitTestEnd(ZT_CircuitTest *test)
+{
+ Mutex::Lock _l(_circuitTests_m);
+ for(;;) {
+ std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test));
+ if (ct == _circuitTests.end())
+ break;
+ else _circuitTests.erase(ct);
+ }
+}
+
+ZT_ResultCode Node::clusterInit(
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ return ZT_RESULT_ERROR_BAD_PARAMETER;
+
+ std::vector<InetAddress> eps;
+ for(unsigned int i=0;i<numZeroTierPhysicalEndpoints;++i)
+ eps.push_back(InetAddress(zeroTierPhysicalEndpoints[i]));
+ std::sort(eps.begin(),eps.end());
+ RR->cluster = new Cluster(RR,myId,eps,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg);
+
+ return ZT_RESULT_OK;
+#else
+ return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION;
+#endif
+}
+
+ZT_ResultCode Node::clusterAddMember(unsigned int memberId)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (!RR->cluster)
+ return ZT_RESULT_ERROR_BAD_PARAMETER;
+ RR->cluster->addMember((uint16_t)memberId);
+ return ZT_RESULT_OK;
+#else
+ return ZT_RESULT_ERROR_UNSUPPORTED_OPERATION;
+#endif
+}
+
+void Node::clusterRemoveMember(unsigned int memberId)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->removeMember((uint16_t)memberId);
+#endif
+}
+
+void Node::clusterHandleIncomingMessage(const void *msg,unsigned int len)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->handleIncomingStateMessage(msg,len);
+#endif
+}
+
+void Node::clusterStatus(ZT_ClusterStatus *cs)
+{
+ if (!cs)
+ return;
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->status(*cs);
+ else
+#endif
+ memset(cs,0,sizeof(ZT_ClusterStatus));
+}
+
+void Node::backgroundThreadMain()
+{
+ ++RR->dpEnabled;
+ for(;;) {
+ try {
+ if (RR->dp->process() < 0)
+ break;
+ } catch ( ... ) {} // sanity check -- should not throw
+ }
+ --RR->dpEnabled;
+}
+
+/****************************************************************************/
+/* Node methods used only within node/ */
+/****************************************************************************/
+
+std::string Node::dataStoreGet(const char *name)
+{
+ char buf[1024];
+ std::string r;
+ unsigned long olen = 0;
+ do {
+ long n = _dataStoreGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,name,buf,sizeof(buf),(unsigned long)r.length(),&olen);
+ if (n <= 0)
+ return std::string();
+ r.append(buf,n);
+ } while (r.length() < olen);
+ return r;
+}
+
+bool Node::shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress)
+{
+ if (!Path::isAddressValidForPath(remoteAddress))
+ return false;
+
+ {
+ Mutex::Lock _l(_networks_m);
+ for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
+ if (i->second->hasConfig()) {
+ for(unsigned int k=0;k<i->second->config().staticIpCount;++k) {
+ if (i->second->config().staticIps[k].containsAddress(remoteAddress))
+ return false;
+ }
+ }
+ }
+ }
+
+ if (_pathCheckFunction)
+ return (_pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,reinterpret_cast<const struct sockaddr_storage *>(&localAddress),reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0);
+ else return true;
+}
+
+#ifdef ZT_TRACE
+void Node::postTrace(const char *module,unsigned int line,const char *fmt,...)
+{
+ static Mutex traceLock;
+
+ va_list ap;
+ char tmp1[1024],tmp2[1024],tmp3[256];
+
+ Mutex::Lock _l(traceLock);
+
+ time_t now = (time_t)(_now / 1000ULL);
+#ifdef __WINDOWS__
+ ctime_s(tmp3,sizeof(tmp3),&now);
+ char *nowstr = tmp3;
+#else
+ char *nowstr = ctime_r(&now,tmp3);
+#endif
+ unsigned long nowstrlen = (unsigned long)strlen(nowstr);
+ if (nowstr[nowstrlen-1] == '\n')
+ nowstr[--nowstrlen] = (char)0;
+ if (nowstr[nowstrlen-1] == '\r')
+ nowstr[--nowstrlen] = (char)0;
+
+ va_start(ap,fmt);
+ vsnprintf(tmp2,sizeof(tmp2),fmt,ap);
+ va_end(ap);
+ tmp2[sizeof(tmp2)-1] = (char)0;
+
+ Utils::snprintf(tmp1,sizeof(tmp1),"[%s] %s:%u %s",nowstr,module,line,tmp2);
+ postEvent(ZT_EVENT_TRACE,tmp1);
+}
+#endif // ZT_TRACE
+
+uint64_t Node::prng()
+{
+ unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t)));
+ if (!p)
+ _prng.encrypt12(_prngStream,_prngStream,sizeof(_prngStream));
+ return _prngStream[p];
+}
+
+void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
+{
+ std::vector< ZT_CircuitTest * > toNotify;
+ {
+ Mutex::Lock _l(_circuitTests_m);
+ for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) {
+ if ((*i)->testId == report->testId)
+ toNotify.push_back(*i);
+ }
+ }
+ for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i)
+ (reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
+}
+
+} // namespace ZeroTier
+
+/****************************************************************************/
+/* CAPI bindings */
+/****************************************************************************/
+
+extern "C" {
+
+enum ZT_ResultCode ZT_Node_new(
+ ZT_Node **node,
+ void *uptr,
+ uint64_t now,
+ ZT_DataStoreGetFunction dataStoreGetFunction,
+ ZT_DataStorePutFunction dataStorePutFunction,
+ ZT_WirePacketSendFunction wirePacketSendFunction,
+ ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
+ ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
+ ZT_EventCallback eventCallback)
+{
+ *node = (ZT_Node *)0;
+ try {
+ *node = reinterpret_cast<ZT_Node *>(new ZeroTier::Node(now,uptr,dataStoreGetFunction,dataStorePutFunction,wirePacketSendFunction,virtualNetworkFrameFunction,virtualNetworkConfigFunction,pathCheckFunction,eventCallback));
+ return ZT_RESULT_OK;
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch (std::runtime_error &exc) {
+ return ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+void ZT_Node_delete(ZT_Node *node)
+{
+ try {
+ delete (reinterpret_cast<ZeroTier::Node *>(node));
+ } catch ( ... ) {}
+}
+
+enum ZT_ResultCode ZT_Node_processWirePacket(
+ ZT_Node *node,
+ uint64_t now,
+ const struct sockaddr_storage *localAddress,
+ const struct sockaddr_storage *remoteAddress,
+ const void *packetData,
+ unsigned int packetLength,
+ volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->processWirePacket(now,localAddress,remoteAddress,packetData,packetLength,nextBackgroundTaskDeadline);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_OK; // "OK" since invalid packets are simply dropped, but the system is still up
+ }
+}
+
+enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame(
+ ZT_Node *node,
+ uint64_t now,
+ uint64_t nwid,
+ uint64_t sourceMac,
+ uint64_t destMac,
+ unsigned int etherType,
+ unsigned int vlanId,
+ const void *frameData,
+ unsigned int frameLength,
+ volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->processVirtualNetworkFrame(now,nwid,sourceMac,destMac,etherType,vlanId,frameData,frameLength,nextBackgroundTaskDeadline);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->processBackgroundTasks(now,nextBackgroundTaskDeadline);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->join(nwid,uptr);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_leave(ZT_Node *node,uint64_t nwid,void **uptr)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->leave(nwid,uptr);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->multicastSubscribe(nwid,multicastGroup,multicastAdi);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->multicastUnsubscribe(nwid,multicastGroup,multicastAdi);
+ } catch (std::bad_alloc &exc) {
+ return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+uint64_t ZT_Node_address(ZT_Node *node)
+{
+ return reinterpret_cast<ZeroTier::Node *>(node)->address();
+}
+
+void ZT_Node_status(ZT_Node *node,ZT_NodeStatus *status)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->status(status);
+ } catch ( ... ) {}
+}
+
+ZT_PeerList *ZT_Node_peers(ZT_Node *node)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->peers();
+ } catch ( ... ) {
+ return (ZT_PeerList *)0;
+ }
+}
+
+ZT_VirtualNetworkConfig *ZT_Node_networkConfig(ZT_Node *node,uint64_t nwid)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->networkConfig(nwid);
+ } catch ( ... ) {
+ return (ZT_VirtualNetworkConfig *)0;
+ }
+}
+
+ZT_VirtualNetworkList *ZT_Node_networks(ZT_Node *node)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->networks();
+ } catch ( ... ) {
+ return (ZT_VirtualNetworkList *)0;
+ }
+}
+
+void ZT_Node_freeQueryResult(ZT_Node *node,void *qr)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->freeQueryResult(qr);
+ } catch ( ... ) {}
+}
+
+int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->addLocalInterfaceAddress(addr);
+ } catch ( ... ) {
+ return 0;
+ }
+}
+
+void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clearLocalInterfaceAddresses();
+ } catch ( ... ) {}
+}
+
+void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->setNetconfMaster(networkControllerInstance);
+ } catch ( ... ) {}
+}
+
+enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->circuitTestBegin(test,reportCallback);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->circuitTestEnd(test);
+ } catch ( ... ) {}
+}
+
+enum ZT_ResultCode ZT_Node_clusterInit(
+ ZT_Node *node,
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->clusterInit(myId,zeroTierPhysicalEndpoints,numZeroTierPhysicalEndpoints,x,y,z,sendFunction,sendFunctionArg,addressToLocationFunction,addressToLocationFunctionArg);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+enum ZT_ResultCode ZT_Node_clusterAddMember(ZT_Node *node,unsigned int memberId)
+{
+ try {
+ return reinterpret_cast<ZeroTier::Node *>(node)->clusterAddMember(memberId);
+ } catch ( ... ) {
+ return ZT_RESULT_FATAL_ERROR_INTERNAL;
+ }
+}
+
+void ZT_Node_clusterRemoveMember(ZT_Node *node,unsigned int memberId)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterRemoveMember(memberId);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned int len)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterHandleIncomingMessage(msg,len);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->clusterStatus(cs);
+ } catch ( ... ) {}
+}
+
+void ZT_Node_backgroundThreadMain(ZT_Node *node)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->backgroundThreadMain();
+ } catch ( ... ) {}
+}
+
+void ZT_version(int *major,int *minor,int *revision)
+{
+ if (major) *major = ZEROTIER_ONE_VERSION_MAJOR;
+ if (minor) *minor = ZEROTIER_ONE_VERSION_MINOR;
+ if (revision) *revision = ZEROTIER_ONE_VERSION_REVISION;
+}
+
+} // extern "C"
diff --git a/zerotierone/node/Node.hpp b/zerotierone/node/Node.hpp
new file mode 100644
index 0000000..6ac23ca
--- /dev/null
+++ b/zerotierone/node/Node.hpp
@@ -0,0 +1,319 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NODE_HPP
+#define ZT_NODE_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <map>
+
+#include "Constants.hpp"
+
+#include "../include/ZeroTierOne.h"
+
+#include "RuntimeEnvironment.hpp"
+#include "InetAddress.hpp"
+#include "Mutex.hpp"
+#include "MAC.hpp"
+#include "Network.hpp"
+#include "Path.hpp"
+#include "Salsa20.hpp"
+
+#undef TRACE
+#ifdef ZT_TRACE
+#define TRACE(f,...) RR->node->postTrace(__FILE__,__LINE__,f,##__VA_ARGS__)
+#else
+#define TRACE(f,...) {}
+#endif
+
+namespace ZeroTier {
+
+/**
+ * Implementation of Node object as defined in CAPI
+ *
+ * The pointer returned by ZT_Node_new() is an instance of this class.
+ */
+class Node
+{
+public:
+ Node(
+ uint64_t now,
+ void *uptr,
+ ZT_DataStoreGetFunction dataStoreGetFunction,
+ ZT_DataStorePutFunction dataStorePutFunction,
+ ZT_WirePacketSendFunction wirePacketSendFunction,
+ ZT_VirtualNetworkFrameFunction virtualNetworkFrameFunction,
+ ZT_VirtualNetworkConfigFunction virtualNetworkConfigFunction,
+ ZT_PathCheckFunction pathCheckFunction,
+ ZT_EventCallback eventCallback);
+
+ ~Node();
+
+ // Public API Functions ----------------------------------------------------
+
+ ZT_ResultCode processWirePacket(
+ uint64_t now,
+ const struct sockaddr_storage *localAddress,
+ const struct sockaddr_storage *remoteAddress,
+ const void *packetData,
+ unsigned int packetLength,
+ volatile uint64_t *nextBackgroundTaskDeadline);
+ ZT_ResultCode processVirtualNetworkFrame(
+ uint64_t now,
+ uint64_t nwid,
+ uint64_t sourceMac,
+ uint64_t destMac,
+ unsigned int etherType,
+ unsigned int vlanId,
+ const void *frameData,
+ unsigned int frameLength,
+ volatile uint64_t *nextBackgroundTaskDeadline);
+ ZT_ResultCode processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline);
+ ZT_ResultCode join(uint64_t nwid,void *uptr);
+ ZT_ResultCode leave(uint64_t nwid,void **uptr);
+ ZT_ResultCode multicastSubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
+ ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
+ uint64_t address() const;
+ void status(ZT_NodeStatus *status) const;
+ ZT_PeerList *peers() const;
+ ZT_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
+ ZT_VirtualNetworkList *networks() const;
+ void freeQueryResult(void *qr);
+ int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
+ void clearLocalInterfaceAddresses();
+ void setNetconfMaster(void *networkControllerInstance);
+ ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *));
+ void circuitTestEnd(ZT_CircuitTest *test);
+ ZT_ResultCode clusterInit(
+ unsigned int myId,
+ const struct sockaddr_storage *zeroTierPhysicalEndpoints,
+ unsigned int numZeroTierPhysicalEndpoints,
+ int x,
+ int y,
+ int z,
+ void (*sendFunction)(void *,unsigned int,const void *,unsigned int),
+ void *sendFunctionArg,
+ int (*addressToLocationFunction)(void *,const struct sockaddr_storage *,int *,int *,int *),
+ void *addressToLocationFunctionArg);
+ ZT_ResultCode clusterAddMember(unsigned int memberId);
+ void clusterRemoveMember(unsigned int memberId);
+ void clusterHandleIncomingMessage(const void *msg,unsigned int len);
+ void clusterStatus(ZT_ClusterStatus *cs);
+ void backgroundThreadMain();
+
+ // Internal functions ------------------------------------------------------
+
+ /**
+ * Convenience threadMain() for easy background thread launch
+ *
+ * This allows background threads to be launched with Thread::start
+ * that will run against this node.
+ */
+ inline void threadMain() throw() { this->backgroundThreadMain(); }
+
+ /**
+ * @return Time as of last call to run()
+ */
+ inline uint64_t now() const throw() { return _now; }
+
+ /**
+ * Enqueue a ZeroTier message to be sent
+ *
+ * @param localAddress Local address
+ * @param addr Destination address
+ * @param data Packet data
+ * @param len Packet length
+ * @param ttl Desired TTL (default: 0 for unchanged/default TTL)
+ * @return True if packet appears to have been sent
+ */
+ inline bool putPacket(const InetAddress &localAddress,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
+ {
+ return (_wirePacketSendFunction(
+ reinterpret_cast<ZT_Node *>(this),
+ _uPtr,
+ reinterpret_cast<const struct sockaddr_storage *>(&localAddress),
+ reinterpret_cast<const struct sockaddr_storage *>(&addr),
+ data,
+ len,
+ ttl) == 0);
+ }
+
+ /**
+ * Enqueue a frame to be injected into a tap device (port)
+ *
+ * @param nwid Network ID
+ * @param nuptr Network user ptr
+ * @param source Source MAC
+ * @param dest Destination MAC
+ * @param etherType 16-bit ethernet type
+ * @param vlanId VLAN ID or 0 if none
+ * @param data Frame data
+ * @param len Frame length
+ */
+ inline void putFrame(uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
+ {
+ _virtualNetworkFrameFunction(
+ reinterpret_cast<ZT_Node *>(this),
+ _uPtr,
+ nwid,
+ nuptr,
+ source.toInt(),
+ dest.toInt(),
+ etherType,
+ vlanId,
+ data,
+ len);
+ }
+
+ /**
+ * @param localAddress Local address
+ * @param remoteAddress Remote address
+ * @return True if path should be used
+ */
+ bool shouldUsePathForZeroTierTraffic(const InetAddress &localAddress,const InetAddress &remoteAddress);
+
+ inline SharedPtr<Network> network(uint64_t nwid) const
+ {
+ Mutex::Lock _l(_networks_m);
+ return _network(nwid);
+ }
+
+ inline bool belongsToNetwork(uint64_t nwid) const
+ {
+ Mutex::Lock _l(_networks_m);
+ for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
+ if (i->first == nwid)
+ return true;
+ }
+ return false;
+ }
+
+ inline std::vector< SharedPtr<Network> > allNetworks() const
+ {
+ std::vector< SharedPtr<Network> > nw;
+ Mutex::Lock _l(_networks_m);
+ nw.reserve(_networks.size());
+ for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i)
+ nw.push_back(i->second);
+ return nw;
+ }
+
+ /**
+ * @return Potential direct paths to me a.k.a. local interface addresses
+ */
+ inline std::vector<InetAddress> directPaths() const
+ {
+ Mutex::Lock _l(_directPaths_m);
+ return _directPaths;
+ }
+
+ inline bool dataStorePut(const char *name,const void *data,unsigned int len,bool secure) { return (_dataStorePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,name,data,len,(int)secure) == 0); }
+ inline bool dataStorePut(const char *name,const std::string &data,bool secure) { return dataStorePut(name,(const void *)data.data(),(unsigned int)data.length(),secure); }
+ inline void dataStoreDelete(const char *name) { _dataStorePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,name,(const void *)0,0,0); }
+ std::string dataStoreGet(const char *name);
+
+ /**
+ * Post an event to the external user
+ *
+ * @param ev Event type
+ * @param md Meta-data (default: NULL/none)
+ */
+ inline void postEvent(ZT_Event ev,const void *md = (const void *)0) { _eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,ev,md); }
+
+ /**
+ * Update virtual network port configuration
+ *
+ * @param nwid Network ID
+ * @param nuptr Network user ptr
+ * @param op Configuration operation
+ * @param nc Network configuration
+ */
+ inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,nwid,nuptr,op,nc); }
+
+ /**
+ * @return True if we appear to be online
+ */
+ inline bool online() const throw() { return _online; }
+
+#ifdef ZT_TRACE
+ void postTrace(const char *module,unsigned int line,const char *fmt,...);
+#endif
+
+ /**
+ * @return Next 64-bit random number (not for cryptographic use)
+ */
+ uint64_t prng();
+
+ /**
+ * Post a circuit test report to any listeners for a given test ID
+ *
+ * @param report Report (includes test ID)
+ */
+ void postCircuitTestReport(const ZT_CircuitTestReport *report);
+
+private:
+ inline SharedPtr<Network> _network(uint64_t nwid) const
+ {
+ // assumes _networks_m is locked
+ for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
+ if (i->first == nwid)
+ return i->second;
+ }
+ return SharedPtr<Network>();
+ }
+
+ RuntimeEnvironment _RR;
+ RuntimeEnvironment *RR;
+
+ void *_uPtr; // _uptr (lower case) is reserved in Visual Studio :P
+
+ ZT_DataStoreGetFunction _dataStoreGetFunction;
+ ZT_DataStorePutFunction _dataStorePutFunction;
+ ZT_WirePacketSendFunction _wirePacketSendFunction;
+ ZT_VirtualNetworkFrameFunction _virtualNetworkFrameFunction;
+ ZT_VirtualNetworkConfigFunction _virtualNetworkConfigFunction;
+ ZT_PathCheckFunction _pathCheckFunction;
+ ZT_EventCallback _eventCallback;
+
+ std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks;
+ Mutex _networks_m;
+
+ std::vector< ZT_CircuitTest * > _circuitTests;
+ Mutex _circuitTests_m;
+
+ std::vector<InetAddress> _directPaths;
+ Mutex _directPaths_m;
+
+ Mutex _backgroundTasksLock;
+
+ unsigned int _prngStreamPtr;
+ Salsa20 _prng;
+ uint64_t _prngStream[16]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream
+
+ uint64_t _now;
+ uint64_t _lastPingCheck;
+ uint64_t _lastHousekeepingRun;
+ bool _online;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/NonCopyable.hpp b/zerotierone/node/NonCopyable.hpp
new file mode 100644
index 0000000..6d4daa8
--- /dev/null
+++ b/zerotierone/node/NonCopyable.hpp
@@ -0,0 +1,38 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_NONCOPYABLE_HPP__
+#define ZT_NONCOPYABLE_HPP__
+
+namespace ZeroTier {
+
+/**
+ * A simple concept that belongs in the C++ language spec
+ */
+class NonCopyable
+{
+protected:
+ NonCopyable() throw() {}
+private:
+ NonCopyable(const NonCopyable&);
+ const NonCopyable& operator=(const NonCopyable&);
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/OutboundMulticast.cpp b/zerotierone/node/OutboundMulticast.cpp
new file mode 100644
index 0000000..eea1132
--- /dev/null
+++ b/zerotierone/node/OutboundMulticast.cpp
@@ -0,0 +1,113 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Constants.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "OutboundMulticast.hpp"
+#include "Switch.hpp"
+#include "Network.hpp"
+#include "CertificateOfMembership.hpp"
+#include "Node.hpp"
+
+namespace ZeroTier {
+
+void OutboundMulticast::init(
+ const RuntimeEnvironment *RR,
+ uint64_t timestamp,
+ uint64_t nwid,
+ const CertificateOfMembership *com,
+ unsigned int limit,
+ unsigned int gatherLimit,
+ const MAC &src,
+ const MulticastGroup &dest,
+ unsigned int etherType,
+ const void *payload,
+ unsigned int len)
+{
+ _timestamp = timestamp;
+ _nwid = nwid;
+ _limit = limit;
+
+ uint8_t flags = 0;
+ if (gatherLimit) flags |= 0x02;
+ if (src) flags |= 0x04;
+
+ /*
+ TRACE(">>MC %.16llx INIT %.16llx/%s limit %u gatherLimit %u from %s to %s length %u com==%d",
+ (unsigned long long)this,
+ nwid,
+ dest.toString().c_str(),
+ limit,
+ gatherLimit,
+ (src) ? src.toString().c_str() : MAC(RR->identity.address(),nwid).toString().c_str(),
+ dest.toString().c_str(),
+ len,
+ (com) ? 1 : 0);
+ */
+
+ _packetNoCom.setSource(RR->identity.address());
+ _packetNoCom.setVerb(Packet::VERB_MULTICAST_FRAME);
+ _packetNoCom.append((uint64_t)nwid);
+ _packetNoCom.append(flags);
+ if (gatherLimit) _packetNoCom.append((uint32_t)gatherLimit);
+ if (src) src.appendTo(_packetNoCom);
+ dest.mac().appendTo(_packetNoCom);
+ _packetNoCom.append((uint32_t)dest.adi());
+ _packetNoCom.append((uint16_t)etherType);
+ _packetNoCom.append(payload,len);
+ _packetNoCom.compress();
+
+ if (com) {
+ _haveCom = true;
+ flags |= 0x01;
+
+ _packetWithCom.setSource(RR->identity.address());
+ _packetWithCom.setVerb(Packet::VERB_MULTICAST_FRAME);
+ _packetWithCom.append((uint64_t)nwid);
+ _packetWithCom.append(flags);
+ com->serialize(_packetWithCom);
+ if (gatherLimit) _packetWithCom.append((uint32_t)gatherLimit);
+ if (src) src.appendTo(_packetWithCom);
+ dest.mac().appendTo(_packetWithCom);
+ _packetWithCom.append((uint32_t)dest.adi());
+ _packetWithCom.append((uint16_t)etherType);
+ _packetWithCom.append(payload,len);
+ _packetWithCom.compress();
+ } else _haveCom = false;
+}
+
+void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr)
+{
+ if (_haveCom) {
+ SharedPtr<Peer> peer(RR->topology->getPeer(toAddr));
+ if ( (!peer) || (peer->needsOurNetworkMembershipCertificate(_nwid,RR->node->now(),true)) ) {
+ //TRACE(">>MC %.16llx -> %s (with COM)",(unsigned long long)this,toAddr.toString().c_str());
+ _packetWithCom.newInitializationVector();
+ _packetWithCom.setDestination(toAddr);
+ RR->sw->send(_packetWithCom,true,_nwid);
+ return;
+ }
+ }
+
+ //TRACE(">>MC %.16llx -> %s (without COM)",(unsigned long long)this,toAddr.toString().c_str());
+ _packetNoCom.newInitializationVector();
+ _packetNoCom.setDestination(toAddr);
+ RR->sw->send(_packetNoCom,true,_nwid);
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/OutboundMulticast.hpp b/zerotierone/node/OutboundMulticast.hpp
new file mode 100644
index 0000000..3818172
--- /dev/null
+++ b/zerotierone/node/OutboundMulticast.hpp
@@ -0,0 +1,145 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_OUTBOUNDMULTICAST_HPP
+#define ZT_OUTBOUNDMULTICAST_HPP
+
+#include <stdint.h>
+
+#include <vector>
+#include <algorithm>
+
+#include "Constants.hpp"
+#include "MAC.hpp"
+#include "MulticastGroup.hpp"
+#include "Address.hpp"
+#include "Packet.hpp"
+
+namespace ZeroTier {
+
+class CertificateOfMembership;
+class RuntimeEnvironment;
+
+/**
+ * An outbound multicast packet
+ *
+ * This object isn't guarded by a mutex; caller must synchronize access.
+ */
+class OutboundMulticast
+{
+public:
+ /**
+ * Create an uninitialized outbound multicast
+ *
+ * It must be initialized with init().
+ */
+ OutboundMulticast() {}
+
+ /**
+ * Initialize outbound multicast
+ *
+ * @param RR Runtime environment
+ * @param timestamp Creation time
+ * @param nwid Network ID
+ * @param com Certificate of membership or NULL if none available
+ * @param limit Multicast limit for desired number of packets to send
+ * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none
+ * @param src Source MAC address of frame or NULL to imply compute from sender ZT address
+ * @param dest Destination multicast group (MAC + ADI)
+ * @param etherType 16-bit Ethernet type ID
+ * @param payload Data
+ * @param len Length of data
+ * @throws std::out_of_range Data too large to fit in a MULTICAST_FRAME
+ */
+ void init(
+ const RuntimeEnvironment *RR,
+ uint64_t timestamp,
+ uint64_t nwid,
+ const CertificateOfMembership *com,
+ unsigned int limit,
+ unsigned int gatherLimit,
+ const MAC &src,
+ const MulticastGroup &dest,
+ unsigned int etherType,
+ const void *payload,
+ unsigned int len);
+
+ /**
+ * @return Multicast creation time
+ */
+ inline uint64_t timestamp() const throw() { return _timestamp; }
+
+ /**
+ * @param now Current time
+ * @return True if this multicast is expired (has exceeded transmit timeout)
+ */
+ inline bool expired(uint64_t now) const throw() { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
+
+ /**
+ * @return True if this outbound multicast has been sent to enough peers
+ */
+ inline bool atLimit() const throw() { return (_alreadySentTo.size() >= _limit); }
+
+ /**
+ * Just send without checking log
+ *
+ * @param RR Runtime environment
+ * @param toAddr Destination address
+ */
+ void sendOnly(const RuntimeEnvironment *RR,const Address &toAddr);
+
+ /**
+ * Just send and log but do not check sent log
+ *
+ * @param RR Runtime environment
+ * @param toAddr Destination address
+ */
+ inline void sendAndLog(const RuntimeEnvironment *RR,const Address &toAddr)
+ {
+ _alreadySentTo.push_back(toAddr);
+ sendOnly(RR,toAddr);
+ }
+
+ /**
+ * Try to send this to a given peer if it hasn't been sent to them already
+ *
+ * @param RR Runtime environment
+ * @param toAddr Destination address
+ * @return True if address is new and packet was sent to switch, false if duplicate
+ */
+ inline bool sendIfNew(const RuntimeEnvironment *RR,const Address &toAddr)
+ {
+ if (std::find(_alreadySentTo.begin(),_alreadySentTo.end(),toAddr) == _alreadySentTo.end()) {
+ sendAndLog(RR,toAddr);
+ return true;
+ } else return false;
+ }
+
+private:
+ uint64_t _timestamp;
+ uint64_t _nwid;
+ unsigned int _limit;
+ Packet _packetNoCom;
+ Packet _packetWithCom;
+ std::vector<Address> _alreadySentTo;
+ bool _haveCom;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Packet.cpp b/zerotierone/node/Packet.cpp
new file mode 100644
index 0000000..3330a92
--- /dev/null
+++ b/zerotierone/node/Packet.cpp
@@ -0,0 +1,157 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Packet.hpp"
+
+namespace ZeroTier {
+
+const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+//#ifdef ZT_TRACE
+
+const char *Packet::verbString(Verb v)
+ throw()
+{
+ switch(v) {
+ case VERB_NOP: return "NOP";
+ case VERB_HELLO: return "HELLO";
+ case VERB_ERROR: return "ERROR";
+ case VERB_OK: return "OK";
+ case VERB_WHOIS: return "WHOIS";
+ case VERB_RENDEZVOUS: return "RENDEZVOUS";
+ case VERB_FRAME: return "FRAME";
+ case VERB_EXT_FRAME: return "EXT_FRAME";
+ case VERB_ECHO: return "ECHO";
+ case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
+ case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
+ case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
+ case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
+ case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
+ case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
+ case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
+ case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
+ case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";
+ case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK";
+ }
+ return "(unknown)";
+}
+
+const char *Packet::errorString(ErrorCode e)
+ throw()
+{
+ switch(e) {
+ case ERROR_NONE: return "NONE";
+ case ERROR_INVALID_REQUEST: return "INVALID_REQUEST";
+ case ERROR_BAD_PROTOCOL_VERSION: return "BAD_PROTOCOL_VERSION";
+ case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND";
+ case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION";
+ case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION";
+ case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE";
+ case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED";
+ case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST";
+ }
+ return "(unknown)";
+}
+
+//#endif // ZT_TRACE
+
+void Packet::armor(const void *key,bool encryptPayload)
+{
+ unsigned char mangledKey[32];
+ unsigned char macKey[32];
+ unsigned char mac[16];
+ const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
+
+ // Set flag now, since it affects key mangle function
+ setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE);
+
+ _salsa20MangleKey((const unsigned char *)key,mangledKey);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/);
+
+ // MAC key is always the first 32 bytes of the Salsa20 key stream
+ // This is the same construction DJB's NaCl library uses
+ s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
+
+ if (encryptPayload)
+ s20.encrypt12(payload,payload,payloadLen);
+
+ Poly1305::compute(mac,payload,payloadLen,macKey);
+ memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
+}
+
+bool Packet::dearmor(const void *key)
+{
+ unsigned char mangledKey[32];
+ unsigned char macKey[32];
+ unsigned char mac[16];
+ const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
+ unsigned int cs = cipher();
+
+ if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) {
+ _salsa20MangleKey((const unsigned char *)key,mangledKey);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8)/*,ZT_PROTO_SALSA20_ROUNDS*/);
+
+ s20.encrypt12(ZERO_KEY,macKey,sizeof(macKey));
+ Poly1305::compute(mac,payload,payloadLen,macKey);
+ if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8))
+ return false;
+
+ if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
+ s20.decrypt12(payload,payload,payloadLen);
+
+ return true;
+ } else return false; // unrecognized cipher suite
+}
+
+bool Packet::compress()
+{
+ unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH * 2];
+ if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 32))) {
+ int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD);
+ int cl = LZ4_compress((const char *)field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)pl),(char *)buf,pl);
+ if ((cl > 0)&&(cl < pl)) {
+ (*this)[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
+ setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD);
+ memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)cl),buf,cl);
+ return true;
+ }
+ }
+ (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
+ return false;
+}
+
+bool Packet::uncompress()
+{
+ unsigned char buf[ZT_PROTO_MAX_PACKET_LENGTH];
+ if ((compressed())&&(size() >= ZT_PROTO_MIN_PACKET_LENGTH)) {
+ if (size() > ZT_PACKET_IDX_PAYLOAD) {
+ unsigned int compLen = size() - ZT_PACKET_IDX_PAYLOAD;
+ int ucl = LZ4_decompress_safe((const char *)field(ZT_PACKET_IDX_PAYLOAD,compLen),(char *)buf,compLen,sizeof(buf));
+ if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) {
+ setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD);
+ memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl);
+ } else return false;
+ }
+ (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
+ }
+ return true;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Packet.hpp b/zerotierone/node/Packet.hpp
new file mode 100644
index 0000000..b367ec6
--- /dev/null
+++ b/zerotierone/node/Packet.hpp
@@ -0,0 +1,1342 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_N_PACKET_HPP
+#define ZT_N_PACKET_HPP
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <string>
+#include <iostream>
+
+#include "Constants.hpp"
+
+#include "Address.hpp"
+#include "Poly1305.hpp"
+#include "Salsa20.hpp"
+#include "Utils.hpp"
+#include "Buffer.hpp"
+
+#include "../ext/lz4/lz4.h"
+
+/**
+ * Protocol version -- incremented only for major changes
+ *
+ * 1 - 0.2.0 ... 0.2.5
+ * 2 - 0.3.0 ... 0.4.5
+ * + Added signature and originating peer to multicast frame
+ * + Double size of multicast frame bloom filter
+ * 3 - 0.5.0 ... 0.6.0
+ * + Yet another multicast redesign
+ * + New crypto completely changes key agreement cipher
+ * 4 - 0.6.0 ... 1.0.6
+ * + New identity format based on hashcash design
+ * 5 - 1.1.0 ... CURRENT
+ * + Supports circuit test, proof of work, and echo
+ * + Supports in-band world (root server definition) updates
+ * + Clustering! (Though this will work with protocol v4 clients.)
+ * + Otherwise backward compatible with protocol v4
+ */
+#define ZT_PROTO_VERSION 5
+
+/**
+ * Minimum supported protocol version
+ */
+#define ZT_PROTO_VERSION_MIN 4
+
+/**
+ * Maximum hop count allowed by packet structure (3 bits, 0-7)
+ *
+ * This is a protocol constant. It's the maximum allowed by the length
+ * of the hop counter -- three bits. See node/Constants.hpp for the
+ * pragmatic forwarding limit, which is typically lower.
+ */
+#define ZT_PROTO_MAX_HOPS 7
+
+/**
+ * Cipher suite: Curve25519/Poly1305/Salsa20/12/NOCRYPT
+ *
+ * This specifies Poly1305 MAC using a 32-bit key derived from the first
+ * 32 bytes of a Salsa20/12 keystream as in the Salsa20/12 cipher suite,
+ * but the payload is not encrypted. This is currently only used to send
+ * HELLO since that's the public key specification packet and must be
+ * sent in the clear. Key agreement is performed using Curve25519 elliptic
+ * curve Diffie-Hellman.
+ */
+#define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE 0
+
+/**
+ * Cipher suite: Curve25519/Poly1305/Salsa20/12
+ *
+ * This specifies Poly1305 using the first 32 bytes of a Salsa20/12 key
+ * stream as its one-time-use key followed by payload encryption with
+ * the remaining Salsa20/12 key stream. Key agreement is performed using
+ * Curve25519 elliptic curve Diffie-Hellman.
+ */
+#define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1
+
+/**
+ * DEPRECATED payload encrypted flag, will be removed for re-use soon.
+ *
+ * This has been replaced by the two-bit cipher suite selection field where
+ * a value of 0 indicates unencrypted (but authenticated) messages.
+ */
+#define ZT_PROTO_FLAG_ENCRYPTED 0x80
+
+/**
+ * Header flag indicating that a packet is fragmented
+ *
+ * If this flag is set, the receiver knows to expect more than one fragment.
+ * See Packet::Fragment for details.
+ */
+#define ZT_PROTO_FLAG_FRAGMENTED 0x40
+
+/**
+ * Verb flag indicating payload is compressed with LZ4
+ */
+#define ZT_PROTO_VERB_FLAG_COMPRESSED 0x80
+
+/**
+ * Rounds used for Salsa20 encryption in ZT
+ *
+ * Discussion:
+ *
+ * DJB (Salsa20's designer) designed Salsa20 with a significant margin of 20
+ * rounds, but has said repeatedly that 12 is likely sufficient. So far (as of
+ * July 2015) there are no published attacks against 12 rounds, let alone 20.
+ *
+ * In cryptography, a "break" means something different from what it means in
+ * common discussion. If a cipher is 256 bits strong and someone finds a way
+ * to reduce key search to 254 bits, this constitues a "break" in the academic
+ * literature. 254 bits is still far beyond what can be leveraged to accomplish
+ * a "break" as most people would understand it -- the actual decryption and
+ * reading of traffic.
+ *
+ * Nevertheless, "attacks only get better" as cryptographers like to say. As
+ * a result, they recommend not using anything that's shown any weakness even
+ * if that weakness is so far only meaningful to academics. It may be a sign
+ * of a deeper problem.
+ *
+ * So why choose a lower round count?
+ *
+ * Turns out the speed difference is nontrivial. On a Macbook Pro (Core i3) 20
+ * rounds of SSE-optimized Salsa20 achieves ~508mb/sec/core, while 12 rounds
+ * hits ~832mb/sec/core. ZeroTier is designed for multiple objectives:
+ * security, simplicity, and performance. In this case a deference was made
+ * for performance.
+ *
+ * Meta discussion:
+ *
+ * The cipher is not the thing you should be paranoid about.
+ *
+ * I'll qualify that. If the cipher is known to be weak, like RC4, or has a
+ * key size that is too small, like DES, then yes you should worry about
+ * the cipher.
+ *
+ * But if the cipher is strong and your adversary is anyone other than the
+ * intelligence apparatus of a major superpower, you are fine in that
+ * department.
+ *
+ * Go ahead. Search for the last ten vulnerabilities discovered in SSL. Not
+ * a single one involved the breaking of a cipher. Now broaden your search.
+ * Look for issues with SSH, IPSec, etc. The only cipher-related issues you
+ * will find might involve the use of RC4 or MD5, algorithms with known
+ * issues or small key/digest sizes. But even weak ciphers are difficult to
+ * exploit in the real world -- you usually need a lot of data and a lot of
+ * compute time. No, virtually EVERY security vulnerability you will find
+ * involves a problem with the IMPLEMENTATION not with the cipher.
+ *
+ * A flaw in ZeroTier's protocol or code is incredibly, unbelievably
+ * more likely than a flaw in Salsa20 or any other cipher or cryptographic
+ * primitive it uses. We're talking odds of dying in a car wreck vs. odds of
+ * being personally impacted on the head by a meteorite. Nobody without a
+ * billion dollar budget is going to break into your network by actually
+ * cracking Salsa20/12 (or even /8) in the field.
+ *
+ * So stop worrying about the cipher unless you are, say, the Kremlin and your
+ * adversary is the NSA and the GCHQ. In that case... well that's above my
+ * pay grade. I'll just say defense in depth.
+ */
+#define ZT_PROTO_SALSA20_ROUNDS 12
+
+/**
+ * PUSH_DIRECT_PATHS flag: forget path
+ */
+#define ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH 0x01
+
+/**
+ * PUSH_DIRECT_PATHS flag: cluster redirect
+ */
+#define ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT 0x02
+
+// Field indexes in packet header
+#define ZT_PACKET_IDX_IV 0
+#define ZT_PACKET_IDX_DEST 8
+#define ZT_PACKET_IDX_SOURCE 13
+#define ZT_PACKET_IDX_FLAGS 18
+#define ZT_PACKET_IDX_MAC 19
+#define ZT_PACKET_IDX_VERB 27
+#define ZT_PACKET_IDX_PAYLOAD 28
+
+/**
+ * Packet buffer size (can be changed)
+ *
+ * The current value is big enough for ZT_MAX_PACKET_FRAGMENTS, the pragmatic
+ * packet fragment limit, times the default UDP MTU. Most packets won't be
+ * this big.
+ */
+#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_UDP_DEFAULT_PAYLOAD_MTU)
+
+/**
+ * Minimum viable packet length (a.k.a. header length)
+ */
+#define ZT_PROTO_MIN_PACKET_LENGTH ZT_PACKET_IDX_PAYLOAD
+
+// Indexes of fields in fragment header
+#define ZT_PACKET_FRAGMENT_IDX_PACKET_ID 0
+#define ZT_PACKET_FRAGMENT_IDX_DEST 8
+#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR 13
+#define ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO 14
+#define ZT_PACKET_FRAGMENT_IDX_HOPS 15
+#define ZT_PACKET_FRAGMENT_IDX_PAYLOAD 16
+
+/**
+ * Magic number found at ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR
+ */
+#define ZT_PACKET_FRAGMENT_INDICATOR ZT_ADDRESS_RESERVED_PREFIX
+
+/**
+ * Minimum viable fragment length
+ */
+#define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD
+
+// Field incides for parsing verbs -------------------------------------------
+
+// Some verbs have variable-length fields. Those aren't fully defined here
+// yet-- instead they are parsed using relative indexes in IncomingPacket.
+// See their respective handler functions.
+
+#define ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION + 1)
+#define ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION + 1)
+#define ZT_PROTO_VERB_HELLO_IDX_REVISION (ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION + 1)
+#define ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP (ZT_PROTO_VERB_HELLO_IDX_REVISION + 2)
+#define ZT_PROTO_VERB_HELLO_IDX_IDENTITY (ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP + 8)
+
+#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_ERROR_IDX_IN_RE_VERB + 1)
+#define ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE (ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID + 8)
+#define ZT_PROTO_VERB_ERROR_IDX_PAYLOAD (ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE + 1)
+
+#define ZT_PROTO_VERB_OK_IDX_IN_RE_VERB (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID (ZT_PROTO_VERB_OK_IDX_IN_RE_VERB + 1)
+#define ZT_PROTO_VERB_OK_IDX_PAYLOAD (ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID + 8)
+
+#define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
+
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1)
+
+#define ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE + 2)
+
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID 8
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS (ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID + ZT_PROTO_VERB_EXT_FRAME_LEN_NETWORK_ID)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS 1
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_COM (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_TO (ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS + ZT_PROTO_VERB_EXT_FRAME_LEN_FLAGS)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_TO 6
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_FROM (ZT_PROTO_VERB_EXT_FRAME_IDX_TO + ZT_PROTO_VERB_EXT_FRAME_LEN_TO)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_FROM 6
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_EXT_FRAME_IDX_FROM + ZT_PROTO_VERB_EXT_FRAME_LEN_FROM)
+#define ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE 2
+#define ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD (ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE + ZT_PROTO_VERB_EXT_FRAME_LEN_ETHERTYPE)
+
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2)
+
+#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC + 6)
+#define ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI + 4)
+
+// Note: COM, GATHER_LIMIT, and SOURCE_MAC are optional, and so are specified without size
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_GATHER_LIMIT (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_SOURCE_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FLAGS + 1)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC + 6)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI + 4)
+#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE + 2)
+
+#define ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP + 8)
+#define ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION + 1)
+#define ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION (ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION + 1)
+#define ZT_PROTO_VERB_HELLO__OK__IDX_REVISION (ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION + 1)
+
+#define ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
+
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN + 2)
+
+#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC + 6)
+#define ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI + 4)
+
+#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID (ZT_PROTO_VERB_OK_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID + 8)
+#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC + 6)
+#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI + 4)
+#define ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS (ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS + 1)
+
+// ---------------------------------------------------------------------------
+
+namespace ZeroTier {
+
+/**
+ * ZeroTier packet
+ *
+ * Packet format:
+ * <[8] 64-bit random packet ID and crypto initialization vector>
+ * <[5] destination ZT address>
+ * <[5] source ZT address>
+ * <[1] flags/cipher/hops>
+ * <[8] 64-bit MAC>
+ * [... -- begin encryption envelope -- ...]
+ * <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)>
+ * [... verb-specific payload ...]
+ *
+ * Packets smaller than 28 bytes are invalid and silently discarded.
+ *
+ * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher
+ * selection allowing up to 7 cipher suites, F is outside-envelope flags,
+ * and H is hop count.
+ *
+ * The three-bit hop count is the only part of a packet that is mutable in
+ * transit without invalidating the MAC. All other bits in the packet are
+ * immutable. This is because intermediate nodes can increment the hop
+ * count up to 7 (protocol max).
+ *
+ * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever
+ * sent in the clear, as it's the "here is my public key" message.
+ */
+class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH>
+{
+public:
+ /**
+ * A packet fragment
+ *
+ * Fragments are sent if a packet is larger than UDP MTU. The first fragment
+ * is sent with its normal header with the fragmented flag set. Remaining
+ * fragments are sent this way.
+ *
+ * The fragmented bit indicates that there is at least one fragment. Fragments
+ * themselves contain the total, so the receiver must "learn" this from the
+ * first fragment it receives.
+ *
+ * Fragments are sent with the following format:
+ * <[8] packet ID of packet whose fragment this belongs to>
+ * <[5] destination ZT address>
+ * <[1] 0xff, a reserved address, signals that this isn't a normal packet>
+ * <[1] total fragments (most significant 4 bits), fragment no (LS 4 bits)>
+ * <[1] ZT hop count (top 5 bits unused and must be zero)>
+ * <[...] fragment data>
+ *
+ * The protocol supports a maximum of 16 fragments. If a fragment is received
+ * before its main packet header, it should be cached for a brief period of
+ * time to see if its parent arrives. Loss of any fragment constitutes packet
+ * loss; there is no retransmission mechanism. The receiver must wait for full
+ * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if
+ * fragments are corrupt, the MAC will fail for the whole assembled packet.)
+ */
+ class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH>
+ {
+ public:
+ Fragment() :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
+ {
+ }
+
+ template<unsigned int C2>
+ Fragment(const Buffer<C2> &b)
+ throw(std::out_of_range) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
+ {
+ }
+
+ Fragment(const void *data,unsigned int len) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
+ {
+ }
+
+ /**
+ * Initialize from a packet
+ *
+ * @param p Original assembled packet
+ * @param fragStart Start of fragment (raw index in packet data)
+ * @param fragLen Length of fragment in bytes
+ * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
+ * @param fragTotal Total number of fragments (including 0)
+ * @throws std::out_of_range Packet size would exceed buffer
+ */
+ Fragment(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
+ throw(std::out_of_range)
+ {
+ init(p,fragStart,fragLen,fragNo,fragTotal);
+ }
+
+ /**
+ * Initialize from a packet
+ *
+ * @param p Original assembled packet
+ * @param fragStart Start of fragment (raw index in packet data)
+ * @param fragLen Length of fragment in bytes
+ * @param fragNo Which fragment (>= 1, since 0 is Packet with end chopped off)
+ * @param fragTotal Total number of fragments (including 0)
+ * @throws std::out_of_range Packet size would exceed buffer
+ */
+ inline void init(const Packet &p,unsigned int fragStart,unsigned int fragLen,unsigned int fragNo,unsigned int fragTotal)
+ throw(std::out_of_range)
+ {
+ if ((fragStart + fragLen) > p.size())
+ throw std::out_of_range("Packet::Fragment: tried to construct fragment of packet past its length");
+ setSize(fragLen + ZT_PROTO_MIN_FRAGMENT_LENGTH);
+
+ // NOTE: this copies both the IV/packet ID and the destination address.
+ memcpy(field(ZT_PACKET_FRAGMENT_IDX_PACKET_ID,13),p.field(ZT_PACKET_IDX_IV,13),13);
+
+ (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] = ZT_PACKET_FRAGMENT_INDICATOR;
+ (*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO] = (char)(((fragTotal & 0xf) << 4) | (fragNo & 0xf));
+ (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = 0;
+
+ memcpy(field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,fragLen),p.field(fragStart,fragLen),fragLen);
+ }
+
+ /**
+ * Get this fragment's destination
+ *
+ * @return Destination ZT address
+ */
+ inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
+
+ /**
+ * @return True if fragment is of a valid length
+ */
+ inline bool lengthValid() const { return (size() >= ZT_PACKET_FRAGMENT_IDX_PAYLOAD); }
+
+ /**
+ * @return ID of packet this is a fragment of
+ */
+ inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_FRAGMENT_IDX_PACKET_ID); }
+
+ /**
+ * @return Total number of fragments in packet
+ */
+ inline unsigned int totalFragments() const { return (((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) >> 4) & 0xf); }
+
+ /**
+ * @return Fragment number of this fragment
+ */
+ inline unsigned int fragmentNumber() const { return ((unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_NO]) & 0xf); }
+
+ /**
+ * @return Fragment ZT hop count
+ */
+ inline unsigned int hops() const { return (unsigned int)((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]); }
+
+ /**
+ * Increment this packet's hop count
+ */
+ inline void incrementHops()
+ {
+ (*this)[ZT_PACKET_FRAGMENT_IDX_HOPS] = (((*this)[ZT_PACKET_FRAGMENT_IDX_HOPS]) + 1) & ZT_PROTO_MAX_HOPS;
+ }
+
+ /**
+ * @return Length of payload in bytes
+ */
+ inline unsigned int payloadLength() const { return ((size() > ZT_PACKET_FRAGMENT_IDX_PAYLOAD) ? (size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD) : 0); }
+
+ /**
+ * @return Raw packet payload
+ */
+ inline const unsigned char *payload() const
+ {
+ return field(ZT_PACKET_FRAGMENT_IDX_PAYLOAD,size() - ZT_PACKET_FRAGMENT_IDX_PAYLOAD);
+ }
+ };
+
+ /**
+ * ZeroTier protocol verbs
+ */
+ enum Verb /* Max value: 32 (5 bits) */
+ {
+ /**
+ * No operation (ignored, no reply)
+ */
+ VERB_NOP = 0,
+
+ /**
+ * Announcement of a node's existence:
+ * <[1] protocol version>
+ * <[1] software major version>
+ * <[1] software minor version>
+ * <[2] software revision>
+ * <[8] timestamp (ms since epoch)>
+ * <[...] binary serialized identity (see Identity)>
+ * <[1] destination address type>
+ * [<[...] destination address>]
+ * <[8] 64-bit world ID of current world>
+ * <[8] 64-bit timestamp of current world>
+ *
+ * This is the only message that ever must be sent in the clear, since it
+ * is used to push an identity to a new peer.
+ *
+ * The destination address is the wire address to which this packet is
+ * being sent, and in OK is *also* the destination address of the OK
+ * packet. This can be used by the receiver to detect NAT, learn its real
+ * external address if behind NAT, and detect changes to its external
+ * address that require re-establishing connectivity.
+ *
+ * Destination address types and formats (not all of these are used now):
+ * 0x00 - None -- no destination address data present
+ * 0x01 - Ethernet address -- format: <[6] Ethernet MAC>
+ * 0x04 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port>
+ * 0x06 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port>
+ *
+ * OK payload:
+ * <[8] timestamp (echoed from original HELLO)>
+ * <[1] protocol version (of responder)>
+ * <[1] software major version (of responder)>
+ * <[1] software minor version (of responder)>
+ * <[2] software revision (of responder)>
+ * <[1] destination address type (for this OK, not copied from HELLO)>
+ * [<[...] destination address>]
+ * <[2] 16-bit length of world update or 0 if none>
+ * [[...] world update]
+ *
+ * ERROR has no payload.
+ */
+ VERB_HELLO = 1,
+
+ /**
+ * Error response:
+ * <[1] in-re verb>
+ * <[8] in-re packet ID>
+ * <[1] error code>
+ * <[...] error-dependent payload>
+ */
+ VERB_ERROR = 2,
+
+ /**
+ * Success response:
+ * <[1] in-re verb>
+ * <[8] in-re packet ID>
+ * <[...] request-specific payload>
+ */
+ VERB_OK = 3,
+
+ /**
+ * Query an identity by address:
+ * <[5] address to look up>
+ *
+ * OK response payload:
+ * <[...] binary serialized identity>
+ *
+ * If querying a cluster, duplicate OK responses may occasionally occur.
+ * These should be discarded.
+ *
+ * If the address is not found, no response is generated. WHOIS requests
+ * will time out much like ARP requests and similar do in L2.
+ */
+ VERB_WHOIS = 4,
+
+ /**
+ * Meet another node at a given protocol address:
+ * <[1] flags (unused, currently 0)>
+ * <[5] ZeroTier address of peer that might be found at this address>
+ * <[2] 16-bit protocol address port>
+ * <[1] protocol address length (4 for IPv4, 16 for IPv6)>
+ * <[...] protocol address (network byte order)>
+ *
+ * This is sent by a relaying node to initiate NAT traversal between two
+ * peers that are communicating by way of indirect relay. The relay will
+ * send this to both peers at the same time on a periodic basis, telling
+ * each where it might find the other on the network.
+ *
+ * Upon receipt a peer sends HELLO to establish a direct link.
+ *
+ * Nodes should implement rate control, limiting the rate at which they
+ * respond to these packets to prevent their use in DDOS attacks. Nodes
+ * may also ignore these messages if a peer is not known or is not being
+ * actively communicated with.
+ *
+ * Unfortunately the physical address format in this message pre-dates
+ * InetAddress's serialization format. :( ZeroTier is four years old and
+ * yes we've accumulated a tiny bit of cruft here and there.
+ *
+ * No OK or ERROR is generated.
+ */
+ VERB_RENDEZVOUS = 5,
+
+ /**
+ * ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
+ * <[8] 64-bit network ID>
+ * <[2] 16-bit ethertype>
+ * <[...] ethernet payload>
+ *
+ * MAC addresses are derived from the packet's source and destination
+ * ZeroTier addresses. This is a shortened EXT_FRAME that elides full
+ * Ethernet framing and other optional flags and features when they
+ * are not necessary.
+ *
+ * ERROR may be generated if a membership certificate is needed for a
+ * closed network. Payload will be network ID.
+ */
+ VERB_FRAME = 6,
+
+ /**
+ * Full Ethernet frame with MAC addressing and optional fields:
+ * <[8] 64-bit network ID>
+ * <[1] flags>
+ * [<[...] certificate of network membership>]
+ * <[6] destination MAC or all zero for destination node>
+ * <[6] source MAC or all zero for node of origin>
+ * <[2] 16-bit ethertype>
+ * <[...] ethernet payload>
+ *
+ * Flags:
+ * 0x01 - Certificate of network membership is attached
+ *
+ * An extended frame carries full MAC addressing, making them a
+ * superset of VERB_FRAME. They're used for bridging or when we
+ * want to attach a certificate since FRAME does not support that.
+ *
+ * Multicast frames may not be sent as EXT_FRAME.
+ *
+ * ERROR may be generated if a membership certificate is needed for a
+ * closed network. Payload will be network ID.
+ */
+ VERB_EXT_FRAME = 7,
+
+ /**
+ * ECHO request (a.k.a. ping):
+ * <[...] arbitrary payload>
+ *
+ * This generates OK with a copy of the transmitted payload. No ERROR
+ * is generated. Response to ECHO requests is optional and ECHO may be
+ * ignored if a node detects a possible flood.
+ */
+ VERB_ECHO = 8,
+
+ /**
+ * Announce interest in multicast group(s):
+ * <[8] 64-bit network ID>
+ * <[6] multicast Ethernet address>
+ * <[4] multicast additional distinguishing information (ADI)>
+ * [... additional tuples of network/address/adi ...]
+ *
+ * LIKEs may be sent to any peer, though a good implementation should
+ * restrict them to peers on the same network they're for and to network
+ * controllers and root servers. In the current network, root servers
+ * will provide the service of final multicast cache.
+ *
+ * It is recommended that NETWORK_MEMBERSHIP_CERTIFICATE pushes be sent
+ * along with MULTICAST_LIKE when pushing LIKEs to peers that do not
+ * share a network membership (such as root servers), since this can be
+ * used to authenticate GATHER requests and limit responses to peers
+ * authorized to talk on a network. (Should be an optional field here,
+ * but saving one or two packets every five minutes is not worth an
+ * ugly hack or protocol rev.)
+ *
+ * OK/ERROR are not generated.
+ */
+ VERB_MULTICAST_LIKE = 9,
+
+ /**
+ * Network member certificate replication/push:
+ * <[...] serialized certificate of membership>
+ * [ ... additional certificates may follow ...]
+ *
+ * This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may
+ * be pushed at any other time to keep exchanged certificates up to date.
+ *
+ * OK/ERROR are not generated.
+ */
+ VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10,
+
+ /**
+ * Network configuration request:
+ * <[8] 64-bit network ID>
+ * <[2] 16-bit length of request meta-data dictionary>
+ * <[...] string-serialized request meta-data>
+ * [<[8] 64-bit revision of netconf we currently have>]
+ *
+ * This message requests network configuration from a node capable of
+ * providing it. If the optional revision is included, a response is
+ * only generated if there is a newer network configuration available.
+ *
+ * OK response payload:
+ * <[8] 64-bit network ID>
+ * <[2] 16-bit length of network configuration dictionary>
+ * <[...] network configuration dictionary>
+ *
+ * OK returns a Dictionary (string serialized) containing the network's
+ * configuration and IP address assignment information for the querying
+ * node. It also contains a membership certificate that the querying
+ * node can push to other peers to demonstrate its right to speak on
+ * a given network.
+ *
+ * When a new network configuration is received, another config request
+ * should be sent with the new netconf's revision. This confirms receipt
+ * and also causes any subsequent changes to rapidly propagate as this
+ * cycle will repeat until there are no changes. This is optional but
+ * recommended behavior.
+ *
+ * ERROR response payload:
+ * <[8] 64-bit network ID>
+ *
+ * UNSUPPORTED_OPERATION is returned if this service is not supported,
+ * and OBJ_NOT_FOUND if the queried network ID was not found.
+ */
+ VERB_NETWORK_CONFIG_REQUEST = 11,
+
+ /**
+ * Network configuration refresh request:
+ * <[...] array of 64-bit network IDs>
+ *
+ * This can be sent by the network controller to inform a node that it
+ * should now make a NETWORK_CONFIG_REQUEST.
+ *
+ * It does not generate an OK or ERROR message, and is treated only as
+ * a hint to refresh now.
+ */
+ VERB_NETWORK_CONFIG_REFRESH = 12,
+
+ /**
+ * Request endpoints for multicast distribution:
+ * <[8] 64-bit network ID>
+ * <[1] flags>
+ * <[6] MAC address of multicast group being queried>
+ * <[4] 32-bit ADI for multicast group being queried>
+ * <[4] 32-bit requested max number of multicast peers>
+ * [<[...] network certificate of membership>]
+ *
+ * Flags:
+ * 0x01 - Network certificate of membership is attached
+ *
+ * This message asks a peer for additional known endpoints that have
+ * LIKEd a given multicast group. It's sent when the sender wishes
+ * to send multicast but does not have the desired number of recipient
+ * peers.
+ *
+ * More than one OK response can occur if the response is broken up across
+ * multiple packets or if querying a clustered node.
+ *
+ * OK response payload:
+ * <[8] 64-bit network ID>
+ * <[6] MAC address of multicast group being queried>
+ * <[4] 32-bit ADI for multicast group being queried>
+ * [begin gather results -- these same fields can be in OK(MULTICAST_FRAME)]
+ * <[4] 32-bit total number of known members in this multicast group>
+ * <[2] 16-bit number of members enumerated in this packet>
+ * <[...] series of 5-byte ZeroTier addresses of enumerated members>
+ *
+ * ERROR is not generated; queries that return no response are dropped.
+ */
+ VERB_MULTICAST_GATHER = 13,
+
+ /**
+ * Multicast frame:
+ * <[8] 64-bit network ID>
+ * <[1] flags>
+ * [<[...] network certificate of membership>]
+ * [<[4] 32-bit implicit gather limit>]
+ * [<[6] source MAC>]
+ * <[6] destination MAC (multicast address)>
+ * <[4] 32-bit multicast ADI (multicast address extension)>
+ * <[2] 16-bit ethertype>
+ * <[...] ethernet payload>
+ *
+ * Flags:
+ * 0x01 - Network certificate of membership is attached
+ * 0x02 - Implicit gather limit field is present
+ * 0x04 - Source MAC is specified -- otherwise it's computed from sender
+ *
+ * OK and ERROR responses are optional. OK may be generated if there are
+ * implicit gather results or if the recipient wants to send its own
+ * updated certificate of network membership to the sender. ERROR may be
+ * generated if a certificate is needed or if multicasts to this group
+ * are no longer wanted (multicast unsubscribe).
+ *
+ * OK response payload:
+ * <[8] 64-bit network ID>
+ * <[6] MAC address of multicast group>
+ * <[4] 32-bit ADI for multicast group>
+ * <[1] flags>
+ * [<[...] network certficate of membership>]
+ * [<[...] implicit gather results if flag 0x01 is set>]
+ *
+ * OK flags (same bits as request flags):
+ * 0x01 - OK includes certificate of network membership
+ * 0x02 - OK includes implicit gather results
+ *
+ * ERROR response payload:
+ * <[8] 64-bit network ID>
+ * <[6] multicast group MAC>
+ * <[4] 32-bit multicast group ADI>
+ */
+ VERB_MULTICAST_FRAME = 14,
+
+ /**
+ * Push of potential endpoints for direct communication:
+ * <[2] 16-bit number of paths>
+ * <[...] paths>
+ *
+ * Path record format:
+ * <[1] 8-bit path flags>
+ * <[2] length of extended path characteristics or 0 for none>
+ * <[...] extended path characteristics>
+ * <[1] address type>
+ * <[1] address length in bytes>
+ * <[...] address>
+ *
+ * Path record flags:
+ * 0x01 - Forget this path if currently known (not implemented yet)
+ * 0x02 - Cluster redirect -- use this in preference to others
+ *
+ * The receiver may, upon receiving a push, attempt to establish a
+ * direct link to one or more of the indicated addresses. It is the
+ * responsibility of the sender to limit which peers it pushes direct
+ * paths to to those with whom it has a trust relationship. The receiver
+ * must obey any restrictions provided such as exclusivity or blacklists.
+ * OK responses to this message are optional.
+ *
+ * Note that a direct path push does not imply that learned paths can't
+ * be used unless they are blacklisted explicitly or unless flag 0x01
+ * is set.
+ *
+ * Only a subset of this functionality is currently implemented: basic
+ * path pushing and learning. Blacklisting and trust are not fully
+ * implemented yet (encryption is still always used).
+ *
+ * OK and ERROR are not generated.
+ */
+ VERB_PUSH_DIRECT_PATHS = 16,
+
+ /**
+ * Source-routed circuit test message:
+ * <[5] address of originator of circuit test>
+ * <[2] 16-bit flags>
+ * <[8] 64-bit timestamp>
+ * <[8] 64-bit test ID (arbitrary, set by tester)>
+ * <[2] 16-bit originator credential length (includes type)>
+ * [[1] originator credential type (for authorizing test)]
+ * [[...] originator credential]
+ * <[2] 16-bit length of additional fields>
+ * [[...] additional fields]
+ * [ ... end of signed portion of request ... ]
+ * <[2] 16-bit length of signature of request>
+ * <[...] signature of request by originator>
+ * <[2] 16-bit previous hop credential length (including type)>
+ * [[1] previous hop credential type]
+ * [[...] previous hop credential]
+ * <[...] next hop(s) in path>
+ *
+ * Flags:
+ * 0x01 - Report back to originator at middle hops
+ * 0x02 - Report back to originator at last hop
+ *
+ * Originator credential types:
+ * 0x01 - 64-bit network ID for which originator is controller
+ *
+ * Previous hop credential types:
+ * 0x01 - Certificate of network membership
+ *
+ * Path record format:
+ * <[1] 8-bit flags (unused, must be zero)>
+ * <[1] 8-bit breadth (number of next hops)>
+ * <[...] one or more ZeroTier addresses of next hops>
+ *
+ * The circuit test allows a device to send a message that will traverse
+ * the network along a specified path, with each hop optionally reporting
+ * back to the tester via VERB_CIRCUIT_TEST_REPORT.
+ *
+ * Each circuit test packet includes a digital signature by the originator
+ * of the request, as well as a credential by which that originator claims
+ * authorization to perform the test. Currently this signature is ed25519,
+ * but in the future flags might be used to indicate an alternative
+ * algorithm. For example, the originator might be a network controller.
+ * In this case the test might be authorized if the recipient is a member
+ * of a network controlled by it, and if the previous hop(s) are also
+ * members. Each hop may include its certificate of network membership.
+ *
+ * Circuit test paths consist of a series of records. When a node receives
+ * an authorized circuit test, it:
+ *
+ * (1) Reports back to circuit tester as flags indicate
+ * (2) Reads and removes the next hop from the packet's path
+ * (3) Sends the packet along to next hop(s), if any.
+ *
+ * It is perfectly legal for a path to contain the same hop more than
+ * once. In fact, this can be a very useful test to determine if a hop
+ * can be reached bidirectionally and if so what that connectivity looks
+ * like.
+ *
+ * The breadth field in source-routed path records allows a hop to forward
+ * to more than one recipient, allowing the tester to specify different
+ * forms of graph traversal in a test.
+ *
+ * There is no hard limit to the number of hops in a test, but it is
+ * practically limited by the maximum size of a (possibly fragmented)
+ * ZeroTier packet.
+ *
+ * Support for circuit tests is optional. If they are not supported, the
+ * node should respond with an UNSUPPORTED_OPERATION error. If a circuit
+ * test request is not authorized, it may be ignored or reported as
+ * an INVALID_REQUEST. No OK messages are generated, but TEST_REPORT
+ * messages may be sent (see below).
+ *
+ * ERROR packet format:
+ * <[8] 64-bit timestamp (echoed from original>
+ * <[8] 64-bit test ID (echoed from original)>
+ */
+ VERB_CIRCUIT_TEST = 17,
+
+ /**
+ * Circuit test hop report:
+ * <[8] 64-bit timestamp (from original test)>
+ * <[8] 64-bit test ID (from original test)>
+ * <[8] 64-bit reserved field (set to 0, currently unused)>
+ * <[1] 8-bit vendor ID (set to 0, currently unused)>
+ * <[1] 8-bit reporter protocol version>
+ * <[1] 8-bit reporter major version>
+ * <[1] 8-bit reporter minor version>
+ * <[2] 16-bit reporter revision>
+ * <[2] 16-bit reporter OS/platform>
+ * <[2] 16-bit reporter architecture>
+ * <[2] 16-bit error code (set to 0, currently unused)>
+ * <[8] 64-bit report flags (set to 0, currently unused)>
+ * <[8] 64-bit source packet ID>
+ * <[5] upstream ZeroTier address from which test was received>
+ * <[1] 8-bit source packet hop count (ZeroTier hop count)>
+ * <[...] local wire address on which packet was received>
+ * <[...] remote wire address from which packet was received>
+ * <[2] 16-bit length of additional fields>
+ * <[...] additional fields>
+ * <[1] 8-bit number of next hops (breadth)>
+ * <[...] next hop information>
+ *
+ * Next hop information record format:
+ * <[5] ZeroTier address of next hop>
+ * <[...] current best direct path address, if any, 0 if none>
+ *
+ * Circuit test reports can be sent by hops in a circuit test to report
+ * back results. They should include information about the sender as well
+ * as about the paths to which next hops are being sent.
+ *
+ * If a test report is received and no circuit test was sent, it should be
+ * ignored. This message generates no OK or ERROR response.
+ */
+ VERB_CIRCUIT_TEST_REPORT = 18,
+
+ /**
+ * Request proof of work:
+ * <[1] 8-bit proof of work type>
+ * <[1] 8-bit proof of work difficulty>
+ * <[2] 16-bit length of proof of work challenge>
+ * <[...] proof of work challenge>
+ *
+ * This requests that a peer perform a proof of work calucation. It can be
+ * sent by highly trusted peers (e.g. root servers, network controllers)
+ * under suspected denial of service conditions in an attempt to filter
+ * out "non-serious" peers and remain responsive to those proving their
+ * intent to actually communicate.
+ *
+ * If the peer obliges to perform the work, it does so and responds with
+ * an OK containing the result. Otherwise it may ignore the message or
+ * response with an ERROR_INVALID_REQUEST or ERROR_UNSUPPORTED_OPERATION.
+ *
+ * Proof of work type IDs:
+ * 0x01 - Salsa20/12+SHA512 hashcash function
+ *
+ * Salsa20/12+SHA512 is based on the following composite hash function:
+ *
+ * (1) Compute SHA512(candidate)
+ * (2) Use the first 256 bits of the result of #1 as a key to encrypt
+ * 131072 zero bytes with Salsa20/12 (with a zero IV).
+ * (3) Compute SHA512(the result of step #2)
+ * (4) Accept this candiate if the first [difficulty] bits of the result
+ * from step #3 are zero. Otherwise generate a new candidate and try
+ * again.
+ *
+ * This is performed repeatedly on candidates generated by appending the
+ * supplied challenge to an arbitrary nonce until a valid candidate
+ * is found. This chosen prepended nonce is then returned as the result
+ * in OK.
+ *
+ * OK payload:
+ * <[2] 16-bit length of result>
+ * <[...] computed proof of work>
+ *
+ * ERROR has no payload.
+ */
+ VERB_REQUEST_PROOF_OF_WORK = 19
+ };
+
+ /**
+ * Error codes for VERB_ERROR
+ */
+ enum ErrorCode
+ {
+ /* No error, not actually used in transit */
+ ERROR_NONE = 0,
+
+ /* Invalid request */
+ ERROR_INVALID_REQUEST = 1,
+
+ /* Bad/unsupported protocol version */
+ ERROR_BAD_PROTOCOL_VERSION = 2,
+
+ /* Unknown object queried */
+ ERROR_OBJ_NOT_FOUND = 3,
+
+ /* HELLO pushed an identity whose address is already claimed */
+ ERROR_IDENTITY_COLLISION = 4,
+
+ /* Verb or use case not supported/enabled by this node */
+ ERROR_UNSUPPORTED_OPERATION = 5,
+
+ /* Message to private network rejected -- no unexpired certificate on file */
+ ERROR_NEED_MEMBERSHIP_CERTIFICATE = 6,
+
+ /* Tried to join network, but you're not a member */
+ ERROR_NETWORK_ACCESS_DENIED_ = 7, /* extra _ to avoid Windows name conflict */
+
+ /* Multicasts to this group are not wanted */
+ ERROR_UNWANTED_MULTICAST = 8
+ };
+
+//#ifdef ZT_TRACE
+ static const char *verbString(Verb v)
+ throw();
+ static const char *errorString(ErrorCode e)
+ throw();
+//#endif
+
+ template<unsigned int C2>
+ Packet(const Buffer<C2> &b) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
+ {
+ }
+
+ Packet(const void *data,unsigned int len) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
+ {
+ }
+
+ /**
+ * Construct a new empty packet with a unique random packet ID
+ *
+ * Flags and hops will be zero. Other fields and data region are undefined.
+ * Use the header access methods (setDestination() and friends) to fill out
+ * the header. Payload should be appended; initial size is header size.
+ */
+ Packet() :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
+ {
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
+ }
+
+ /**
+ * Make a copy of a packet with a new initialization vector and destination address
+ *
+ * This can be used to take one draft prototype packet and quickly make copies to
+ * encrypt for different destinations.
+ *
+ * @param prototype Prototype packet
+ * @param dest Destination ZeroTier address for new packet
+ */
+ Packet(const Packet &prototype,const Address &dest) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
+ {
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+ setDestination(dest);
+ }
+
+ /**
+ * Construct a new empty packet with a unique random packet ID
+ *
+ * @param dest Destination ZT address
+ * @param source Source ZT address
+ * @param v Verb
+ */
+ Packet(const Address &dest,const Address &source,const Verb v) :
+ Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
+ {
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+ setDestination(dest);
+ setSource(source);
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags and hops
+ setVerb(v);
+ }
+
+ /**
+ * Reset this packet structure for reuse in place
+ *
+ * @param dest Destination ZT address
+ * @param source Source ZT address
+ * @param v Verb
+ */
+ inline void reset(const Address &dest,const Address &source,const Verb v)
+ {
+ setSize(ZT_PROTO_MIN_PACKET_LENGTH);
+ Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
+ setDestination(dest);
+ setSource(source);
+ (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops
+ setVerb(v);
+ }
+
+ /**
+ * Generate a new IV / packet ID in place
+ *
+ * This can be used to re-use a packet buffer multiple times to send
+ * technically different but otherwise identical copies of the same
+ * packet.
+ */
+ inline void newInitializationVector() { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); }
+
+ /**
+ * Set this packet's destination
+ *
+ * @param dest ZeroTier address of destination
+ */
+ inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
+
+ /**
+ * Set this packet's source
+ *
+ * @param source ZeroTier address of source
+ */
+ inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
+
+ /**
+ * Get this packet's destination
+ *
+ * @return Destination ZT address
+ */
+ inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
+
+ /**
+ * Get this packet's source
+ *
+ * @return Source ZT address
+ */
+ inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
+
+ /**
+ * @return True if packet is of valid length
+ */
+ inline bool lengthValid() const { return (size() >= ZT_PROTO_MIN_PACKET_LENGTH); }
+
+ /**
+ * @return True if packet is fragmented (expect fragments)
+ */
+ inline bool fragmented() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0); }
+
+ /**
+ * Set this packet's fragmented flag
+ *
+ * @param f Fragmented flag value
+ */
+ inline void setFragmented(bool f)
+ {
+ if (f)
+ (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_FRAGMENTED;
+ else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_FRAGMENTED);
+ }
+
+ /**
+ * @return True if compressed (result only valid if unencrypted)
+ */
+ inline bool compressed() const { return (((unsigned char)(*this)[ZT_PACKET_IDX_VERB] & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0); }
+
+ /**
+ * @return ZeroTier forwarding hops (0 to 7)
+ */
+ inline unsigned int hops() const { return ((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x07); }
+
+ /**
+ * Increment this packet's hop count
+ */
+ inline void incrementHops()
+ {
+ unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
+ b = (b & 0xf8) | ((b + 1) & 0x07);
+ }
+
+ /**
+ * @return Cipher suite selector: 0 - 7 (see #defines)
+ */
+ inline unsigned int cipher() const
+ {
+ // Note: this uses the new cipher spec field, which is incompatible with <1.0.0 peers
+ return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3);
+ }
+
+ /**
+ * Set this packet's cipher suite
+ */
+ inline void setCipher(unsigned int c)
+ {
+ unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
+ b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
+ // DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
+ if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
+ b |= ZT_PROTO_FLAG_ENCRYPTED;
+ else b &= (~ZT_PROTO_FLAG_ENCRYPTED);
+ }
+
+ /**
+ * Get this packet's unique ID (the IV field interpreted as uint64_t)
+ *
+ * @return Packet ID
+ */
+ inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); }
+
+ /**
+ * Set packet verb
+ *
+ * This also has the side-effect of clearing any verb flags, such as
+ * compressed, and so must only be done during packet composition.
+ *
+ * @param v New packet verb
+ */
+ inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
+
+ /**
+ * @return Packet verb (not including flag bits)
+ */
+ inline Verb verb() const { return (Verb)((*this)[ZT_PACKET_IDX_VERB] & 0x1f); }
+
+ /**
+ * @return Length of packet payload
+ */
+ inline unsigned int payloadLength() const { return ((size() < ZT_PROTO_MIN_PACKET_LENGTH) ? 0 : (size() - ZT_PROTO_MIN_PACKET_LENGTH)); }
+
+ /**
+ * @return Raw packet payload
+ */
+ inline const unsigned char *payload() const { return field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD); }
+
+ /**
+ * Armor packet for transport
+ *
+ * @param key 32-byte key
+ * @param encryptPayload If true, encrypt packet payload, else just MAC
+ */
+ void armor(const void *key,bool encryptPayload);
+
+ /**
+ * Verify and (if encrypted) decrypt packet
+ *
+ * @param key 32-byte key
+ * @return False if packet is invalid or failed MAC authenticity check
+ */
+ bool dearmor(const void *key);
+
+ /**
+ * Attempt to compress payload if not already (must be unencrypted)
+ *
+ * This requires that the payload at least contain the verb byte already
+ * set. The compressed flag in the verb is set if compression successfully
+ * results in a size reduction. If no size reduction occurs, compression
+ * is not done and the flag is left cleared.
+ *
+ * @return True if compression occurred
+ */
+ bool compress();
+
+ /**
+ * Attempt to decompress payload if it is compressed (must be unencrypted)
+ *
+ * If payload is compressed, it is decompressed and the compressed verb
+ * flag is cleared. Otherwise nothing is done and true is returned.
+ *
+ * @return True if data is now decompressed and valid, false on error
+ */
+ bool uncompress();
+
+private:
+ static const unsigned char ZERO_KEY[32];
+
+ /**
+ * Deterministically mangle a 256-bit crypto key based on packet
+ *
+ * This uses extra data from the packet to mangle the secret, giving us an
+ * effective IV that is somewhat more than 64 bits. This is "free" for
+ * Salsa20 since it has negligible key setup time so using a different
+ * key each time is fine.
+ *
+ * @param in Input key (32 bytes)
+ * @param out Output buffer (32 bytes)
+ */
+ inline void _salsa20MangleKey(const unsigned char *in,unsigned char *out) const
+ {
+ const unsigned char *d = (const unsigned char *)data();
+
+ // IV and source/destination addresses. Using the addresses divides the
+ // key space into two halves-- A->B and B->A (since order will change).
+ for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
+ out[i] = in[i] ^ d[i];
+
+ // Flags, but with hop count masked off. Hop count is altered by forwarding
+ // nodes. It's one of the only parts of a packet modifiable by people
+ // without the key.
+ out[18] = in[18] ^ (d[ZT_PACKET_IDX_FLAGS] & 0xf8);
+
+ // Raw packet size in bytes -- thus each packet size defines a new
+ // key space.
+ out[19] = in[19] ^ (unsigned char)(size() & 0xff);
+ out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
+
+ // Rest of raw key is used unchanged
+ for(unsigned int i=21;i<32;++i)
+ out[i] = in[i];
+ }
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Path.cpp b/zerotierone/node/Path.cpp
new file mode 100644
index 0000000..5692af6
--- /dev/null
+++ b/zerotierone/node/Path.cpp
@@ -0,0 +1,34 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Path.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
+
+namespace ZeroTier {
+
+bool Path::send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
+{
+ if (RR->node->putPacket(_localAddress,address(),data,len)) {
+ sent(now);
+ return true;
+ }
+ return false;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Path.hpp b/zerotierone/node/Path.hpp
new file mode 100644
index 0000000..c88c295
--- /dev/null
+++ b/zerotierone/node/Path.hpp
@@ -0,0 +1,365 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_PATH_HPP
+#define ZT_PATH_HPP
+
+#include <stdint.h>
+#include <string.h>
+
+#include <stdexcept>
+#include <algorithm>
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+
+// Note: if you change these flags check the logic below. Some of it depends
+// on these bits being what they are.
+
+/**
+ * Flag indicating that this path is suboptimal
+ *
+ * Clusters set this flag on remote paths if GeoIP or other routing decisions
+ * indicate that a peer should be handed off to another cluster member.
+ */
+#define ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL 0x0001
+
+/**
+ * Flag indicating that this path is optimal
+ *
+ * Peers set this flag on paths that are pushed by a cluster and indicated as
+ * optimal. A second flag is needed since we want to prioritize cluster optimal
+ * paths and de-prioritize sub-optimal paths and for new paths we don't know
+ * which one they are. So we want a trinary state: optimal, suboptimal, unknown.
+ */
+#define ZT_PATH_FLAG_CLUSTER_OPTIMAL 0x0002
+
+/**
+ * Maximum return value of preferenceRank()
+ */
+#define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1)
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+
+/**
+ * Base class for paths
+ *
+ * The base Path class is an immutable value.
+ */
+class Path
+{
+public:
+ Path() :
+ _lastSend(0),
+ _lastPing(0),
+ _lastKeepalive(0),
+ _lastReceived(0),
+ _addr(),
+ _localAddress(),
+ _flags(0),
+ _ipScope(InetAddress::IP_SCOPE_NONE)
+ {
+ }
+
+ Path(const InetAddress &localAddress,const InetAddress &addr) :
+ _lastSend(0),
+ _lastPing(0),
+ _lastKeepalive(0),
+ _lastReceived(0),
+ _addr(addr),
+ _localAddress(localAddress),
+ _flags(0),
+ _ipScope(addr.ipScope())
+ {
+ }
+
+ inline Path &operator=(const Path &p)
+ {
+ if (this != &p)
+ memcpy(this,&p,sizeof(Path));
+ return *this;
+ }
+
+ /**
+ * Called when a packet is sent to this remote path
+ *
+ * This is called automatically by Path::send().
+ *
+ * @param t Time of send
+ */
+ inline void sent(uint64_t t) { _lastSend = t; }
+
+ /**
+ * Called when we've sent a ping or echo
+ *
+ * @param t Time of send
+ */
+ inline void pinged(uint64_t t) { _lastPing = t; }
+
+ /**
+ * Called when we send a NAT keepalive
+ *
+ * @param t Time of send
+ */
+ inline void sentKeepalive(uint64_t t) { _lastKeepalive = t; }
+
+ /**
+ * Called when a packet is received from this remote path
+ *
+ * @param t Time of receive
+ */
+ inline void received(uint64_t t)
+ {
+ _lastReceived = t;
+ _probation = 0;
+ }
+
+ /**
+ * @param now Current time
+ * @return True if this path appears active
+ */
+ inline bool active(uint64_t now) const
+ {
+ return ( ((now - _lastReceived) < ZT_PATH_ACTIVITY_TIMEOUT) && (_probation < ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION) );
+ }
+
+ /**
+ * Send a packet via this path
+ *
+ * @param RR Runtime environment
+ * @param data Packet data
+ * @param len Packet length
+ * @param now Current time
+ * @return True if transport reported success
+ */
+ bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now);
+
+ /**
+ * @return Address of local side of this path or NULL if unspecified
+ */
+ inline const InetAddress &localAddress() const throw() { return _localAddress; }
+
+ /**
+ * @return Time of last send to this path
+ */
+ inline uint64_t lastSend() const throw() { return _lastSend; }
+
+ /**
+ * @return Time we last pinged or dead path checked this link
+ */
+ inline uint64_t lastPing() const throw() { return _lastPing; }
+
+ /**
+ * @return Time of last keepalive
+ */
+ inline uint64_t lastKeepalive() const throw() { return _lastKeepalive; }
+
+ /**
+ * @return Time of last receive from this path
+ */
+ inline uint64_t lastReceived() const throw() { return _lastReceived; }
+
+ /**
+ * @return Physical address
+ */
+ inline const InetAddress &address() const throw() { return _addr; }
+
+ /**
+ * @return IP scope -- faster shortcut for address().ipScope()
+ */
+ inline InetAddress::IpScope ipScope() const throw() { return _ipScope; }
+
+ /**
+ * @param f Valuve of ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL and inverse of ZT_PATH_FLAG_CLUSTER_OPTIMAL (both are changed)
+ */
+ inline void setClusterSuboptimal(bool f)
+ {
+ if (f) {
+ _flags = (_flags | ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) & ~ZT_PATH_FLAG_CLUSTER_OPTIMAL;
+ } else {
+ _flags = (_flags | ZT_PATH_FLAG_CLUSTER_OPTIMAL) & ~ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL;
+ }
+ }
+
+ /**
+ * @return True if ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL is set
+ */
+ inline bool isClusterSuboptimal() const { return ((_flags & ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) != 0); }
+
+ /**
+ * @return True if ZT_PATH_FLAG_CLUSTER_OPTIMAL is set
+ */
+ inline bool isClusterOptimal() const { return ((_flags & ZT_PATH_FLAG_CLUSTER_OPTIMAL) != 0); }
+
+ /**
+ * @return Preference rank, higher == better (will be less than 255)
+ */
+ inline unsigned int preferenceRank() const throw()
+ {
+ /* First, since the scope enum values in InetAddress.hpp are in order of
+ * use preference rank, we take that. Then we multiple by two, yielding
+ * a sequence like 0, 2, 4, 6, etc. Then if it's IPv6 we add one. This
+ * makes IPv6 addresses of a given scope outrank IPv4 addresses of the
+ * same scope -- e.g. 1 outranks 0. This makes us prefer IPv6, but not
+ * if the address scope/class is of a fundamentally lower rank. */
+ return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) );
+ }
+
+ /**
+ * @return This path's overall quality score (higher is better)
+ */
+ inline uint64_t score() const throw()
+ {
+ // This is a little bit convoluted because we try to be branch-free, using multiplication instead of branches for boolean flags
+
+ // Start with the last time this path was active, and add a fudge factor to prevent integer underflow if _lastReceived is 0
+ uint64_t score = _lastReceived + (ZT_PEER_DIRECT_PING_DELAY * (ZT_PEER_DEAD_PATH_DETECTION_MAX_PROBATION + 1));
+
+ // Increase score based on path preference rank, which is based on IP scope and address family
+ score += preferenceRank() * (ZT_PEER_DIRECT_PING_DELAY / ZT_PATH_MAX_PREFERENCE_RANK);
+
+ // Increase score if this is known to be an optimal path to a cluster
+ score += (uint64_t)(_flags & ZT_PATH_FLAG_CLUSTER_OPTIMAL) * (ZT_PEER_DIRECT_PING_DELAY / 2); // /2 because CLUSTER_OPTIMAL is flag 0x0002
+
+ // Decrease score if this is known to be a sub-optimal path to a cluster
+ score -= (uint64_t)(_flags & ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL) * ZT_PEER_DIRECT_PING_DELAY;
+
+ // Penalize for missed ECHO tests in dead path detection
+ score -= (uint64_t)((ZT_PEER_DIRECT_PING_DELAY / 2) * _probation);
+
+ return score;
+ }
+
+ /**
+ * @return True if path is considered reliable (no NAT keepalives etc. are needed)
+ */
+ inline bool reliable() const throw()
+ {
+ if (_addr.ss_family == AF_INET)
+ return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE));
+ return true;
+ }
+
+ /**
+ * @return True if address is non-NULL
+ */
+ inline operator bool() const throw() { return (_addr); }
+
+ /**
+ * Check whether this address is valid for a ZeroTier path
+ *
+ * This checks the address type and scope against address types and scopes
+ * that we currently support for ZeroTier communication.
+ *
+ * @param a Address to check
+ * @return True if address is good for ZeroTier path use
+ */
+ static inline bool isAddressValidForPath(const InetAddress &a)
+ throw()
+ {
+ if ((a.ss_family == AF_INET)||(a.ss_family == AF_INET6)) {
+ switch(a.ipScope()) {
+ /* Note: we don't do link-local at the moment. Unfortunately these
+ * cause several issues. The first is that they usually require a
+ * device qualifier, which we don't handle yet and can't portably
+ * push in PUSH_DIRECT_PATHS. The second is that some OSes assign
+ * these very ephemerally or otherwise strangely. So we'll use
+ * private, pseudo-private, shared (e.g. carrier grade NAT), or
+ * global IP addresses. */
+ case InetAddress::IP_SCOPE_PRIVATE:
+ case InetAddress::IP_SCOPE_PSEUDOPRIVATE:
+ case InetAddress::IP_SCOPE_SHARED:
+ case InetAddress::IP_SCOPE_GLOBAL:
+ if (a.ss_family == AF_INET6) {
+ // TEMPORARY HACK: for now, we are going to blacklist he.net IPv6
+ // tunnels due to very spotty performance and low MTU issues over
+ // these IPv6 tunnel links.
+ const uint8_t *ipd = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&a)->sin6_addr.s6_addr);
+ if ((ipd[0] == 0x20)&&(ipd[1] == 0x01)&&(ipd[2] == 0x04)&&(ipd[3] == 0x70))
+ return false;
+ }
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return Current path probation count (for dead path detect)
+ */
+ inline unsigned int probation() const { return _probation; }
+
+ /**
+ * Increase this path's probation violation count (for dead path detect)
+ */
+ inline void increaseProbation() { ++_probation; }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ b.append((uint8_t)2); // version
+ b.append((uint64_t)_lastSend);
+ b.append((uint64_t)_lastPing);
+ b.append((uint64_t)_lastKeepalive);
+ b.append((uint64_t)_lastReceived);
+ _addr.serialize(b);
+ _localAddress.serialize(b);
+ b.append((uint16_t)_flags);
+ b.append((uint16_t)_probation);
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+ if (b[p++] != 2)
+ throw std::invalid_argument("invalid serialized Path");
+ _lastSend = b.template at<uint64_t>(p); p += 8;
+ _lastPing = b.template at<uint64_t>(p); p += 8;
+ _lastKeepalive = b.template at<uint64_t>(p); p += 8;
+ _lastReceived = b.template at<uint64_t>(p); p += 8;
+ p += _addr.deserialize(b,p);
+ p += _localAddress.deserialize(b,p);
+ _flags = b.template at<uint16_t>(p); p += 2;
+ _probation = b.template at<uint16_t>(p); p += 2;
+ _ipScope = _addr.ipScope();
+ return (p - startAt);
+ }
+
+ inline bool operator==(const Path &p) const { return ((p._addr == _addr)&&(p._localAddress == _localAddress)); }
+ inline bool operator!=(const Path &p) const { return ((p._addr != _addr)||(p._localAddress != _localAddress)); }
+
+private:
+ uint64_t _lastSend;
+ uint64_t _lastPing;
+ uint64_t _lastKeepalive;
+ uint64_t _lastReceived;
+ InetAddress _addr;
+ InetAddress _localAddress;
+ unsigned int _flags;
+ unsigned int _probation;
+ InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Peer.cpp b/zerotierone/node/Peer.cpp
new file mode 100644
index 0000000..cc58100
--- /dev/null
+++ b/zerotierone/node/Peer.cpp
@@ -0,0 +1,558 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../version.h"
+
+#include "Constants.hpp"
+#include "Peer.hpp"
+#include "Node.hpp"
+#include "Switch.hpp"
+#include "Network.hpp"
+#include "SelfAwareness.hpp"
+#include "Cluster.hpp"
+#include "Packet.hpp"
+
+#include <algorithm>
+
+#define ZT_PEER_PATH_SORT_INTERVAL 5000
+
+namespace ZeroTier {
+
+// Used to send varying values for NAT keepalive
+static uint32_t _natKeepaliveBuf = 0;
+
+Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
+ RR(renv),
+ _lastUsed(0),
+ _lastReceive(0),
+ _lastUnicastFrame(0),
+ _lastMulticastFrame(0),
+ _lastAnnouncedTo(0),
+ _lastDirectPathPushSent(0),
+ _lastDirectPathPushReceive(0),
+ _lastPathSort(0),
+ _vProto(0),
+ _vMajor(0),
+ _vMinor(0),
+ _vRevision(0),
+ _id(peerIdentity),
+ _numPaths(0),
+ _latency(0),
+ _directPathPushCutoffCount(0),
+ _networkComs(4),
+ _lastPushedComs(4)
+{
+ if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
+ throw std::runtime_error("new peer identity key agreement failed");
+}
+
+void Peer::received(
+ const InetAddress &localAddr,
+ const InetAddress &remoteAddr,
+ unsigned int hops,
+ uint64_t packetId,
+ Packet::Verb verb,
+ uint64_t inRePacketId,
+ Packet::Verb inReVerb)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ bool suboptimalPath = false;
+ if ((RR->cluster)&&(hops == 0)) {
+ // Note: findBetterEndpoint() is first since we still want to check
+ // for a better endpoint even if we don't actually send a redirect.
+ InetAddress redirectTo;
+ if ( (verb != Packet::VERB_OK) && (verb != Packet::VERB_ERROR) && (verb != Packet::VERB_RENDEZVOUS) && (verb != Packet::VERB_PUSH_DIRECT_PATHS) && (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),remoteAddr,false)) ) {
+ if (_vProto >= 5) {
+ // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS.
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
+ outp.append((uint16_t)1); // count == 1
+ outp.append((uint8_t)ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT); // flags: cluster redirect
+ outp.append((uint16_t)0); // no extensions
+ if (redirectTo.ss_family == AF_INET) {
+ outp.append((uint8_t)4);
+ outp.append((uint8_t)6);
+ outp.append(redirectTo.rawIpData(),4);
+ } else {
+ outp.append((uint8_t)6);
+ outp.append((uint8_t)18);
+ outp.append(redirectTo.rawIpData(),16);
+ }
+ outp.append((uint16_t)redirectTo.port());
+ outp.armor(_key,true);
+ RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+ } else {
+ // For older peers we use RENDEZVOUS to coax them into contacting us elsewhere.
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((uint8_t)0); // no flags
+ RR->identity.address().appendTo(outp);
+ outp.append((uint16_t)redirectTo.port());
+ if (redirectTo.ss_family == AF_INET) {
+ outp.append((uint8_t)4);
+ outp.append(redirectTo.rawIpData(),4);
+ } else {
+ outp.append((uint8_t)16);
+ outp.append(redirectTo.rawIpData(),16);
+ }
+ outp.armor(_key,true);
+ RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+ }
+ suboptimalPath = true;
+ }
+ }
+#endif
+
+ const uint64_t now = RR->node->now();
+ _lastReceive = now;
+ if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME))
+ _lastUnicastFrame = now;
+ else if (verb == Packet::VERB_MULTICAST_FRAME)
+ _lastMulticastFrame = now;
+
+ if (hops == 0) {
+ bool pathIsConfirmed = false;
+ unsigned int np = _numPaths;
+ for(unsigned int p=0;p<np;++p) {
+ if ((_paths[p].address() == remoteAddr)&&(_paths[p].localAddress() == localAddr)) {
+ _paths[p].received(now);
+#ifdef ZT_ENABLE_CLUSTER
+ _paths[p].setClusterSuboptimal(suboptimalPath);
+#endif
+ pathIsConfirmed = true;
+ break;
+ }
+ }
+
+ if ((!pathIsConfirmed)&&(RR->node->shouldUsePathForZeroTierTraffic(localAddr,remoteAddr))) {
+ if (verb == Packet::VERB_OK) {
+
+ Path *slot = (Path *)0;
+ if (np < ZT_MAX_PEER_NETWORK_PATHS) {
+ slot = &(_paths[np++]);
+ } else {
+ uint64_t slotWorstScore = 0xffffffffffffffffULL;
+ for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
+ if (!_paths[p].active(now)) {
+ slot = &(_paths[p]);
+ break;
+ } else {
+ const uint64_t score = _paths[p].score();
+ if (score <= slotWorstScore) {
+ slotWorstScore = score;
+ slot = &(_paths[p]);
+ }
+ }
+ }
+ }
+ if (slot) {
+ *slot = Path(localAddr,remoteAddr);
+ slot->received(now);
+#ifdef ZT_ENABLE_CLUSTER
+ slot->setClusterSuboptimal(suboptimalPath);
+#endif
+ _numPaths = np;
+ }
+
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster)
+ RR->cluster->broadcastHavePeer(_id);
+#endif
+
+ } else {
+
+ TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
+
+ if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
+ outp.armor(_key,true);
+ RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+ } else {
+ sendHELLO(localAddr,remoteAddr,now);
+ }
+
+ }
+ }
+ }
+
+ if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) {
+ _lastAnnouncedTo = now;
+ const std::vector< SharedPtr<Network> > networks(RR->node->allNetworks());
+ for(std::vector< SharedPtr<Network> >::const_iterator n(networks.begin());n!=networks.end();++n)
+ (*n)->tryAnnounceMulticastGroupsTo(SharedPtr<Peer>(this));
+ }
+}
+
+void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl)
+{
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
+ outp.append((unsigned char)ZT_PROTO_VERSION);
+ outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
+ outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
+ outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+ outp.append(now);
+ RR->identity.serialize(outp,false);
+ atAddress.serialize(outp);
+ outp.append((uint64_t)RR->topology->worldId());
+ outp.append((uint64_t)RR->topology->worldTimestamp());
+
+ outp.armor(_key,false); // HELLO is sent in the clear
+ RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size(),ttl);
+}
+
+bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily)
+{
+ Path *p = (Path *)0;
+
+ if (inetAddressFamily != 0) {
+ p = _getBestPath(now,inetAddressFamily);
+ } else {
+ p = _getBestPath(now);
+ }
+
+ if (p) {
+ if ((now - p->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) {
+ //TRACE("PING %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
+ sendHELLO(p->localAddress(),p->address(),now);
+ p->sent(now);
+ p->pinged(now);
+ } else if ( ((now - std::max(p->lastSend(),p->lastKeepalive())) >= ZT_NAT_KEEPALIVE_DELAY) && (!p->reliable()) ) {
+ //TRACE("NAT keepalive %s(%s) after %llums/%llums send/receive inactivity",_id.address().toString().c_str(),p->address().toString().c_str(),now - p->lastSend(),now - p->lastReceived());
+ _natKeepaliveBuf += (uint32_t)((now * 0x9e3779b1) >> 1); // tumble this around to send constantly varying (meaningless) payloads
+ RR->node->putPacket(p->localAddress(),p->address(),&_natKeepaliveBuf,sizeof(_natKeepaliveBuf));
+ p->sentKeepalive(now);
+ } else {
+ //TRACE("no PING or NAT keepalive: addr==%s reliable==%d %llums/%llums send/receive inactivity",p->address().toString().c_str(),(int)p->reliable(),now - p->lastSend(),now - p->lastReceived());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Peer::pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force,bool includePrivatePaths)
+{
+#ifdef ZT_ENABLE_CLUSTER
+ // Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
+ if (RR->cluster)
+ return false;
+#endif
+
+ if (!force) {
+ if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL)
+ return false;
+ else _lastDirectPathPushSent = now;
+ }
+
+ std::vector<InetAddress> pathsToPush;
+
+ std::vector<InetAddress> dps(RR->node->directPaths());
+ for(std::vector<InetAddress>::const_iterator i(dps.begin());i!=dps.end();++i) {
+ if ((includePrivatePaths)||(i->ipScope() == InetAddress::IP_SCOPE_GLOBAL))
+ pathsToPush.push_back(*i);
+ }
+
+ std::vector<InetAddress> sym(RR->sa->getSymmetricNatPredictions());
+ for(unsigned long i=0,added=0;i<sym.size();++i) {
+ InetAddress tmp(sym[(unsigned long)RR->node->prng() % sym.size()]);
+ if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) {
+ pathsToPush.push_back(tmp);
+ if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY)
+ break;
+ }
+ }
+ if (pathsToPush.empty())
+ return false;
+
+#ifdef ZT_TRACE
+ {
+ std::string ps;
+ for(std::vector<InetAddress>::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) {
+ if (ps.length() > 0)
+ ps.push_back(',');
+ ps.append(p->toString());
+ }
+ TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str());
+ }
+#endif
+
+ std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
+ while (p != pathsToPush.end()) {
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
+ outp.addSize(2); // leave room for count
+
+ unsigned int count = 0;
+ while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) {
+ uint8_t addressType = 4;
+ switch(p->ss_family) {
+ case AF_INET:
+ break;
+ case AF_INET6:
+ addressType = 6;
+ break;
+ default: // we currently only push IP addresses
+ ++p;
+ continue;
+ }
+
+ outp.append((uint8_t)0); // no flags
+ outp.append((uint16_t)0); // no extensions
+ outp.append(addressType);
+ outp.append((uint8_t)((addressType == 4) ? 6 : 18));
+ outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
+ outp.append((uint16_t)p->port());
+
+ ++count;
+ ++p;
+ }
+
+ if (count) {
+ outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
+ outp.armor(_key,true);
+ RR->node->putPacket(localAddr,toAddress,outp.data(),outp.size(),0);
+ }
+ }
+
+ return true;
+}
+
+bool Peer::resetWithinScope(InetAddress::IpScope scope,uint64_t now)
+{
+ unsigned int np = _numPaths;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ while (x < np) {
+ if (_paths[x].address().ipScope() == scope) {
+ // Resetting a path means sending a HELLO and then forgetting it. If we
+ // get OK(HELLO) then it will be re-learned.
+ sendHELLO(_paths[x].localAddress(),_paths[x].address(),now);
+ } else {
+ _paths[y++] = _paths[x];
+ }
+ ++x;
+ }
+ _numPaths = y;
+ return (y < np);
+}
+
+void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
+{
+ uint64_t bestV4 = 0,bestV6 = 0;
+ for(unsigned int p=0,np=_numPaths;p<np;++p) {
+ if (_paths[p].active(now)) {
+ uint64_t lr = _paths[p].lastReceived();
+ if (lr) {
+ if (_paths[p].address().isV4()) {
+ if (lr >= bestV4) {
+ bestV4 = lr;
+ v4 = _paths[p].address();
+ }
+ } else if (_paths[p].address().isV6()) {
+ if (lr >= bestV6) {
+ bestV6 = lr;
+ v6 = _paths[p].address();
+ }
+ }
+ }
+ }
+ }
+}
+
+bool Peer::networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const
+{
+ Mutex::Lock _l(_networkComs_m);
+ const _NetworkCom *ourCom = _networkComs.get(nwid);
+ if (ourCom)
+ return ourCom->com.agreesWith(com);
+ return false;
+}
+
+bool Peer::validateAndSetNetworkMembershipCertificate(uint64_t nwid,const CertificateOfMembership &com)
+{
+ // Sanity checks
+ if ((!com)||(com.issuedTo() != _id.address()))
+ return false;
+
+ // Return true if we already have this *exact* COM
+ {
+ Mutex::Lock _l(_networkComs_m);
+ _NetworkCom *ourCom = _networkComs.get(nwid);
+ if ((ourCom)&&(ourCom->com == com))
+ return true;
+ }
+
+ // Check signature, log and return if cert is invalid
+ if (com.signedBy() != Network::controllerFor(nwid)) {
+ TRACE("rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network",(unsigned long long)nwid,com.signedBy().toString().c_str());
+ return false; // invalid signer
+ }
+
+ if (com.signedBy() == RR->identity.address()) {
+
+ // We are the controller: RR->identity.address() == controller() == cert.signedBy()
+ // So, verify that we signed th cert ourself
+ if (!com.verify(RR->identity)) {
+ TRACE("rejected network membership certificate for %.16llx self signed by %s: signature check failed",(unsigned long long)nwid,com.signedBy().toString().c_str());
+ return false; // invalid signature
+ }
+
+ } else {
+
+ SharedPtr<Peer> signer(RR->topology->getPeer(com.signedBy()));
+
+ if (!signer) {
+ // This would be rather odd, since this is our controller... could happen
+ // if we get packets before we've gotten config.
+ RR->sw->requestWhois(com.signedBy());
+ return false; // signer unknown
+ }
+
+ if (!com.verify(signer->identity())) {
+ TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)nwid,com.signedBy().toString().c_str());
+ return false; // invalid signature
+ }
+ }
+
+ // If we made it past all those checks, add or update cert in our cert info store
+ {
+ Mutex::Lock _l(_networkComs_m);
+ _networkComs.set(nwid,_NetworkCom(RR->node->now(),com));
+ }
+
+ return true;
+}
+
+bool Peer::needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime)
+{
+ Mutex::Lock _l(_networkComs_m);
+ uint64_t &lastPushed = _lastPushedComs[nwid];
+ const uint64_t tmp = lastPushed;
+ if (updateLastPushedTime)
+ lastPushed = now;
+ return ((now - tmp) >= (ZT_NETWORK_AUTOCONF_DELAY / 3));
+}
+
+void Peer::clean(uint64_t now)
+{
+ {
+ unsigned int np = _numPaths;
+ unsigned int x = 0;
+ unsigned int y = 0;
+ while (x < np) {
+ if (_paths[x].active(now))
+ _paths[y++] = _paths[x];
+ ++x;
+ }
+ _numPaths = y;
+ }
+
+ {
+ Mutex::Lock _l(_networkComs_m);
+ {
+ uint64_t *k = (uint64_t *)0;
+ _NetworkCom *v = (_NetworkCom *)0;
+ Hashtable< uint64_t,_NetworkCom >::Iterator i(_networkComs);
+ while (i.next(k,v)) {
+ if ( (!RR->node->belongsToNetwork(*k)) && ((now - v->ts) >= ZT_PEER_NETWORK_COM_EXPIRATION) )
+ _networkComs.erase(*k);
+ }
+ }
+ {
+ uint64_t *k = (uint64_t *)0;
+ uint64_t *v = (uint64_t *)0;
+ Hashtable< uint64_t,uint64_t >::Iterator i(_lastPushedComs);
+ while (i.next(k,v)) {
+ if ((now - *v) > (ZT_NETWORK_AUTOCONF_DELAY * 2))
+ _lastPushedComs.erase(*k);
+ }
+ }
+ }
+}
+
+void Peer::_doDeadPathDetection(Path &p,const uint64_t now)
+{
+ /* Dead path detection: if we have sent something to this peer and have not
+ * yet received a reply, double check this path. The majority of outbound
+ * packets including Ethernet frames do generate some kind of reply either
+ * immediately or at some point in the near future. This will occasionally
+ * (every NO_ANSWER_TIMEOUT ms) check paths unnecessarily if traffic that
+ * does not generate a response is being sent such as multicast announcements
+ * or frames belonging to unidirectional UDP protocols, but the cost is very
+ * tiny and the benefit in reliability is very large. This takes care of many
+ * failure modes including crap NATs that forget links and spurious changes
+ * to physical network topology that cannot be otherwise detected.
+ *
+ * Each time we do this we increment a probation counter in the path. This
+ * counter is reset on any packet receive over this path. If it reaches the
+ * MAX_PROBATION threshold the path is considred dead. */
+
+ if (
+ (p.lastSend() > p.lastReceived()) &&
+ ((p.lastSend() - p.lastReceived()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) &&
+ ((now - p.lastPing()) >= ZT_PEER_DEAD_PATH_DETECTION_NO_ANSWER_TIMEOUT) &&
+ (!p.isClusterSuboptimal()) &&
+ (!RR->topology->amRoot())
+ ) {
+ TRACE("%s(%s) does not seem to be answering in a timely manner, checking if dead (probation == %u)",_id.address().toString().c_str(),p.address().toString().c_str(),p.probation());
+
+ if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
+ Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
+ outp.armor(_key,true);
+ p.send(RR,outp.data(),outp.size(),now);
+ p.pinged(now);
+ } else {
+ sendHELLO(p.localAddress(),p.address(),now);
+ p.sent(now);
+ p.pinged(now);
+ }
+
+ p.increaseProbation();
+ }
+}
+
+Path *Peer::_getBestPath(const uint64_t now)
+{
+ Path *bestPath = (Path *)0;
+ uint64_t bestPathScore = 0;
+ for(unsigned int i=0;i<_numPaths;++i) {
+ const uint64_t score = _paths[i].score();
+ if ((score >= bestPathScore)&&(_paths[i].active(now))) {
+ bestPathScore = score;
+ bestPath = &(_paths[i]);
+ }
+ }
+ if (bestPath)
+ _doDeadPathDetection(*bestPath,now);
+ return bestPath;
+}
+
+Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily)
+{
+ Path *bestPath = (Path *)0;
+ uint64_t bestPathScore = 0;
+ for(unsigned int i=0;i<_numPaths;++i) {
+ const uint64_t score = _paths[i].score();
+ if (((int)_paths[i].address().ss_family == inetAddressFamily)&&(score >= bestPathScore)&&(_paths[i].active(now))) {
+ bestPathScore = score;
+ bestPath = &(_paths[i]);
+ }
+ }
+ if (bestPath)
+ _doDeadPathDetection(*bestPath,now);
+ return bestPath;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Peer.hpp b/zerotierone/node/Peer.hpp
new file mode 100644
index 0000000..445535c
--- /dev/null
+++ b/zerotierone/node/Peer.hpp
@@ -0,0 +1,614 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_PEER_HPP
+#define ZT_PEER_HPP
+
+#include <stdint.h>
+
+#include "Constants.hpp"
+
+#include <algorithm>
+#include <utility>
+#include <vector>
+#include <stdexcept>
+
+#include "../include/ZeroTierOne.h"
+
+#include "RuntimeEnvironment.hpp"
+#include "CertificateOfMembership.hpp"
+#include "Path.hpp"
+#include "Address.hpp"
+#include "Utils.hpp"
+#include "Identity.hpp"
+#include "InetAddress.hpp"
+#include "Packet.hpp"
+#include "SharedPtr.hpp"
+#include "AtomicCounter.hpp"
+#include "Hashtable.hpp"
+#include "Mutex.hpp"
+#include "NonCopyable.hpp"
+
+// Very rough computed estimate: (8 + 256 + 80 + (16 * 64) + (128 * 256) + (128 * 16))
+// 1048576 provides tons of headroom -- overflow would just cause peer not to be persisted
+#define ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE 1048576
+
+namespace ZeroTier {
+
+/**
+ * Peer on P2P Network (virtual layer 1)
+ */
+class Peer : NonCopyable
+{
+ friend class SharedPtr<Peer>;
+
+private:
+ Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
+
+public:
+ ~Peer() { Utils::burn(_key,sizeof(_key)); }
+
+ /**
+ * Construct a new peer
+ *
+ * @param renv Runtime environment
+ * @param myIdentity Identity of THIS node (for key agreement)
+ * @param peerIdentity Identity of peer
+ * @throws std::runtime_error Key agreement with peer's identity failed
+ */
+ Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity);
+
+ /**
+ * @return Time peer record was last used in any way
+ */
+ inline uint64_t lastUsed() const throw() { return _lastUsed; }
+
+ /**
+ * Log a use of this peer record (done by Topology when peers are looked up)
+ *
+ * @param now New time of last use
+ */
+ inline void use(uint64_t now) throw() { _lastUsed = now; }
+
+ /**
+ * @return This peer's ZT address (short for identity().address())
+ */
+ inline const Address &address() const throw() { return _id.address(); }
+
+ /**
+ * @return This peer's identity
+ */
+ inline const Identity &identity() const throw() { return _id; }
+
+ /**
+ * Log receipt of an authenticated packet
+ *
+ * This is called by the decode pipe when a packet is proven to be authentic
+ * and appears to be valid.
+ *
+ * @param RR Runtime environment
+ * @param localAddr Local address
+ * @param remoteAddr Internet address of sender
+ * @param hops ZeroTier (not IP) hops
+ * @param packetId Packet ID
+ * @param verb Packet verb
+ * @param inRePacketId Packet ID in reply to (default: none)
+ * @param inReVerb Verb in reply to (for OK/ERROR, default: VERB_NOP)
+ */
+ void received(
+ const InetAddress &localAddr,
+ const InetAddress &remoteAddr,
+ unsigned int hops,
+ uint64_t packetId,
+ Packet::Verb verb,
+ uint64_t inRePacketId = 0,
+ Packet::Verb inReVerb = Packet::VERB_NOP);
+
+ /**
+ * Get the current best direct path to this peer
+ *
+ * @param now Current time
+ * @return Best path or NULL if there are no active direct paths
+ */
+ inline Path *getBestPath(uint64_t now) { return _getBestPath(now); }
+
+ /**
+ * @param now Current time
+ * @param addr Remote address
+ * @return True if we have an active path to this destination
+ */
+ inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const
+ {
+ for(unsigned int p=0;p<_numPaths;++p) {
+ if ((_paths[p].active(now))&&(_paths[p].address() == addr))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set all paths in the same ss_family that are not this one to cluster suboptimal
+ *
+ * Addresses in other families are not affected.
+ *
+ * @param addr Address to make exclusive
+ */
+ inline void setClusterOptimalPathForAddressFamily(const InetAddress &addr)
+ {
+ for(unsigned int p=0;p<_numPaths;++p) {
+ if (_paths[p].address().ss_family == addr.ss_family) {
+ _paths[p].setClusterSuboptimal(_paths[p].address() != addr);
+ }
+ }
+ }
+
+ /**
+ * Send via best path
+ *
+ * @param data Packet data
+ * @param len Packet length
+ * @param now Current time
+ * @return Path used on success or NULL on failure
+ */
+ inline Path *send(const void *data,unsigned int len,uint64_t now)
+ {
+ Path *const bestPath = getBestPath(now);
+ if (bestPath) {
+ if (bestPath->send(RR,data,len,now))
+ return bestPath;
+ }
+ return (Path *)0;
+ }
+
+ /**
+ * Send a HELLO to this peer at a specified physical address
+ *
+ * This does not update any statistics. It's used to send initial HELLOs
+ * for NAT traversal and path verification.
+ *
+ * @param localAddr Local address
+ * @param atAddress Destination address
+ * @param now Current time
+ * @param ttl Desired IP TTL (default: 0 to leave alone)
+ */
+ void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int ttl = 0);
+
+ /**
+ * Send pings or keepalives depending on configured timeouts
+ *
+ * @param now Current time
+ * @param inetAddressFamily Keep this address family alive, or 0 to simply pick current best ignoring family
+ * @return True if at least one direct path seems alive
+ */
+ bool doPingAndKeepalive(uint64_t now,int inetAddressFamily);
+
+ /**
+ * Push direct paths back to self if we haven't done so in the configured timeout
+ *
+ * @param localAddr Local address
+ * @param toAddress Remote address to send push to (usually from path)
+ * @param now Current time
+ * @param force If true, push regardless of rate limit
+ * @param includePrivatePaths If true, include local interface address paths (should only be done to peers with a trust relationship)
+ * @return True if something was actually sent
+ */
+ bool pushDirectPaths(const InetAddress &localAddr,const InetAddress &toAddress,uint64_t now,bool force,bool includePrivatePaths);
+
+ /**
+ * @return All known direct paths to this peer (active or inactive)
+ */
+ inline std::vector<Path> paths() const
+ {
+ std::vector<Path> pp;
+ for(unsigned int p=0,np=_numPaths;p<np;++p)
+ pp.push_back(_paths[p]);
+ return pp;
+ }
+
+ /**
+ * @return Time of last receive of anything, whether direct or relayed
+ */
+ inline uint64_t lastReceive() const throw() { return _lastReceive; }
+
+ /**
+ * @return Time of most recent unicast frame received
+ */
+ inline uint64_t lastUnicastFrame() const throw() { return _lastUnicastFrame; }
+
+ /**
+ * @return Time of most recent multicast frame received
+ */
+ inline uint64_t lastMulticastFrame() const throw() { return _lastMulticastFrame; }
+
+ /**
+ * @return Time of most recent frame of any kind (unicast or multicast)
+ */
+ inline uint64_t lastFrame() const throw() { return std::max(_lastUnicastFrame,_lastMulticastFrame); }
+
+ /**
+ * @return True if this peer has sent us real network traffic recently
+ */
+ inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
+
+ /**
+ * @return Latency in milliseconds or 0 if unknown
+ */
+ inline unsigned int latency() const { return _latency; }
+
+ /**
+ * This computes a quality score for relays and root servers
+ *
+ * If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they
+ * receive the worst possible quality (max unsigned int). Otherwise the
+ * quality is a product of latency and the number of potential missed
+ * pings. This causes roots and relays to switch over a bit faster if they
+ * fail.
+ *
+ * @return Relay quality score computed from latency and other factors, lower is better
+ */
+ inline unsigned int relayQuality(const uint64_t now) const
+ {
+ const uint64_t tsr = now - _lastReceive;
+ if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
+ return (~(unsigned int)0);
+ unsigned int l = _latency;
+ if (!l)
+ l = 0xffff;
+ return (l * (((unsigned int)tsr / (ZT_PEER_DIRECT_PING_DELAY + 1000)) + 1));
+ }
+
+ /**
+ * Update latency with a new direct measurment
+ *
+ * @param l Direct latency measurment in ms
+ */
+ inline void addDirectLatencyMeasurment(unsigned int l)
+ {
+ unsigned int ol = _latency;
+ if ((ol > 0)&&(ol < 10000))
+ _latency = (ol + std::min(l,(unsigned int)65535)) / 2;
+ else _latency = std::min(l,(unsigned int)65535);
+ }
+
+ /**
+ * @param now Current time
+ * @return True if this peer has at least one active direct path
+ */
+ inline bool hasActiveDirectPath(uint64_t now) const
+ {
+ for(unsigned int p=0;p<_numPaths;++p) {
+ if (_paths[p].active(now))
+ return true;
+ }
+ return false;
+ }
+
+#ifdef ZT_ENABLE_CLUSTER
+ /**
+ * @param now Current time
+ * @return True if this peer has at least one active direct path that is not cluster-suboptimal
+ */
+ inline bool hasClusterOptimalPath(uint64_t now) const
+ {
+ for(unsigned int p=0,np=_numPaths;p<np;++p) {
+ if ((_paths[p].active(now))&&(!_paths[p].isClusterSuboptimal()))
+ return true;
+ }
+ return false;
+ }
+#endif
+
+ /**
+ * Reset paths within a given scope
+ *
+ * @param scope IP scope of paths to reset
+ * @param now Current time
+ * @return True if at least one path was forgotten
+ */
+ bool resetWithinScope(InetAddress::IpScope scope,uint64_t now);
+
+ /**
+ * @return 256-bit secret symmetric encryption key
+ */
+ inline const unsigned char *key() const throw() { return _key; }
+
+ /**
+ * Set the currently known remote version of this peer's client
+ *
+ * @param vproto Protocol version
+ * @param vmaj Major version
+ * @param vmin Minor version
+ * @param vrev Revision
+ */
+ inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
+ {
+ _vProto = (uint16_t)vproto;
+ _vMajor = (uint16_t)vmaj;
+ _vMinor = (uint16_t)vmin;
+ _vRevision = (uint16_t)vrev;
+ }
+
+ inline unsigned int remoteVersionProtocol() const throw() { return _vProto; }
+ inline unsigned int remoteVersionMajor() const throw() { return _vMajor; }
+ inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
+ inline unsigned int remoteVersionRevision() const throw() { return _vRevision; }
+
+ inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
+
+ /**
+ * Get most recently active path addresses for IPv4 and/or IPv6
+ *
+ * Note that v4 and v6 are not modified if they are not found, so
+ * initialize these to a NULL address to be able to check.
+ *
+ * @param now Current time
+ * @param v4 Result parameter to receive active IPv4 address, if any
+ * @param v6 Result parameter to receive active IPv6 address, if any
+ */
+ void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
+
+ /**
+ * Check network COM agreement with this peer
+ *
+ * @param nwid Network ID
+ * @param com Another certificate of membership
+ * @return True if supplied COM agrees with ours, false if not or if we don't have one
+ */
+ bool networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const;
+
+ /**
+ * Check the validity of the COM and add/update if valid and new
+ *
+ * @param nwid Network ID
+ * @param com Externally supplied COM
+ */
+ bool validateAndSetNetworkMembershipCertificate(uint64_t nwid,const CertificateOfMembership &com);
+
+ /**
+ * @param nwid Network ID
+ * @param now Current time
+ * @param updateLastPushedTime If true, go ahead and update the last pushed time regardless of return value
+ * @return Whether or not this peer needs another COM push from us
+ */
+ bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime);
+
+ /**
+ * Perform periodic cleaning operations
+ *
+ * @param now Current time
+ */
+ void clean(uint64_t now);
+
+ /**
+ * Update direct path push stats and return true if we should respond
+ *
+ * This is a circuit breaker to make VERB_PUSH_DIRECT_PATHS not particularly
+ * useful as a DDOS amplification attack vector. Otherwise a malicious peer
+ * could send loads of these and cause others to bombard arbitrary IPs with
+ * traffic.
+ *
+ * @param now Current time
+ * @return True if we should respond
+ */
+ inline bool shouldRespondToDirectPathPush(const uint64_t now)
+ {
+ if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
+ ++_directPathPushCutoffCount;
+ else _directPathPushCutoffCount = 0;
+ _lastDirectPathPushReceive = now;
+ return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
+ }
+
+ /**
+ * Find a common set of addresses by which two peers can link, if any
+ *
+ * @param a Peer A
+ * @param b Peer B
+ * @param now Current time
+ * @return Pair: B's address (to send to A), A's address (to send to B)
+ */
+ static inline std::pair<InetAddress,InetAddress> findCommonGround(const Peer &a,const Peer &b,uint64_t now)
+ {
+ std::pair<InetAddress,InetAddress> v4,v6;
+ b.getBestActiveAddresses(now,v4.first,v6.first);
+ a.getBestActiveAddresses(now,v4.second,v6.second);
+ if ((v6.first)&&(v6.second)) // prefer IPv6 if both have it since NAT-t is (almost) unnecessary
+ return v6;
+ else if ((v4.first)&&(v4.second))
+ return v4;
+ else return std::pair<InetAddress,InetAddress>();
+ }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b) const
+ {
+ Mutex::Lock _l(_networkComs_m);
+
+ const unsigned int recSizePos = b.size();
+ b.addSize(4); // space for uint32_t field length
+
+ b.append((uint16_t)1); // version of serialized Peer data
+
+ _id.serialize(b,false);
+
+ b.append((uint64_t)_lastUsed);
+ b.append((uint64_t)_lastReceive);
+ b.append((uint64_t)_lastUnicastFrame);
+ b.append((uint64_t)_lastMulticastFrame);
+ b.append((uint64_t)_lastAnnouncedTo);
+ b.append((uint64_t)_lastDirectPathPushSent);
+ b.append((uint64_t)_lastDirectPathPushReceive);
+ b.append((uint64_t)_lastPathSort);
+ b.append((uint16_t)_vProto);
+ b.append((uint16_t)_vMajor);
+ b.append((uint16_t)_vMinor);
+ b.append((uint16_t)_vRevision);
+ b.append((uint32_t)_latency);
+ b.append((uint16_t)_directPathPushCutoffCount);
+
+ b.append((uint16_t)_numPaths);
+ for(unsigned int i=0;i<_numPaths;++i)
+ _paths[i].serialize(b);
+
+ b.append((uint32_t)_networkComs.size());
+ {
+ uint64_t *k = (uint64_t *)0;
+ _NetworkCom *v = (_NetworkCom *)0;
+ Hashtable<uint64_t,_NetworkCom>::Iterator i(const_cast<Peer *>(this)->_networkComs);
+ while (i.next(k,v)) {
+ b.append((uint64_t)*k);
+ b.append((uint64_t)v->ts);
+ v->com.serialize(b);
+ }
+ }
+
+ b.append((uint32_t)_lastPushedComs.size());
+ {
+ uint64_t *k = (uint64_t *)0;
+ uint64_t *v = (uint64_t *)0;
+ Hashtable<uint64_t,uint64_t>::Iterator i(const_cast<Peer *>(this)->_lastPushedComs);
+ while (i.next(k,v)) {
+ b.append((uint64_t)*k);
+ b.append((uint64_t)*v);
+ }
+ }
+
+ b.template setAt<uint32_t>(recSizePos,(uint32_t)(b.size() - (recSizePos + 4))); // set size
+ }
+
+ /**
+ * Create a new Peer from a serialized instance
+ *
+ * @param renv Runtime environment
+ * @param myIdentity This node's identity
+ * @param b Buffer containing serialized Peer data
+ * @param p Pointer to current position in buffer, will be updated in place as buffer is read (value/result)
+ * @return New instance of Peer or NULL if serialized data was corrupt or otherwise invalid (may also throw an exception via Buffer)
+ */
+ template<unsigned int C>
+ static inline SharedPtr<Peer> deserializeNew(const RuntimeEnvironment *renv,const Identity &myIdentity,const Buffer<C> &b,unsigned int &p)
+ {
+ const unsigned int recSize = b.template at<uint32_t>(p); p += 4;
+ if ((p + recSize) > b.size())
+ return SharedPtr<Peer>(); // size invalid
+ if (b.template at<uint16_t>(p) != 1)
+ return SharedPtr<Peer>(); // version mismatch
+ p += 2;
+
+ Identity npid;
+ p += npid.deserialize(b,p);
+ if (!npid)
+ return SharedPtr<Peer>();
+
+ SharedPtr<Peer> np(new Peer(renv,myIdentity,npid));
+
+ np->_lastUsed = b.template at<uint64_t>(p); p += 8;
+ np->_lastReceive = b.template at<uint64_t>(p); p += 8;
+ np->_lastUnicastFrame = b.template at<uint64_t>(p); p += 8;
+ np->_lastMulticastFrame = b.template at<uint64_t>(p); p += 8;
+ np->_lastAnnouncedTo = b.template at<uint64_t>(p); p += 8;
+ np->_lastDirectPathPushSent = b.template at<uint64_t>(p); p += 8;
+ np->_lastDirectPathPushReceive = b.template at<uint64_t>(p); p += 8;
+ np->_lastPathSort = b.template at<uint64_t>(p); p += 8;
+ np->_vProto = b.template at<uint16_t>(p); p += 2;
+ np->_vMajor = b.template at<uint16_t>(p); p += 2;
+ np->_vMinor = b.template at<uint16_t>(p); p += 2;
+ np->_vRevision = b.template at<uint16_t>(p); p += 2;
+ np->_latency = b.template at<uint32_t>(p); p += 4;
+ np->_directPathPushCutoffCount = b.template at<uint16_t>(p); p += 2;
+
+ const unsigned int numPaths = b.template at<uint16_t>(p); p += 2;
+ for(unsigned int i=0;i<numPaths;++i) {
+ if (i < ZT_MAX_PEER_NETWORK_PATHS) {
+ p += np->_paths[np->_numPaths++].deserialize(b,p);
+ } else {
+ // Skip any paths beyond max, but still read stream
+ Path foo;
+ p += foo.deserialize(b,p);
+ }
+ }
+
+ const unsigned int numNetworkComs = b.template at<uint32_t>(p); p += 4;
+ for(unsigned int i=0;i<numNetworkComs;++i) {
+ _NetworkCom &c = np->_networkComs[b.template at<uint64_t>(p)]; p += 8;
+ c.ts = b.template at<uint64_t>(p); p += 8;
+ p += c.com.deserialize(b,p);
+ }
+
+ const unsigned int numLastPushed = b.template at<uint32_t>(p); p += 4;
+ for(unsigned int i=0;i<numLastPushed;++i) {
+ const uint64_t nwid = b.template at<uint64_t>(p); p += 8;
+ const uint64_t ts = b.template at<uint64_t>(p); p += 8;
+ np->_lastPushedComs.set(nwid,ts);
+ }
+
+ return np;
+ }
+
+private:
+ void _doDeadPathDetection(Path &p,const uint64_t now);
+ Path *_getBestPath(const uint64_t now);
+ Path *_getBestPath(const uint64_t now,int inetAddressFamily);
+
+ unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized
+
+ const RuntimeEnvironment *RR;
+ uint64_t _lastUsed;
+ uint64_t _lastReceive; // direct or indirect
+ uint64_t _lastUnicastFrame;
+ uint64_t _lastMulticastFrame;
+ uint64_t _lastAnnouncedTo;
+ uint64_t _lastDirectPathPushSent;
+ uint64_t _lastDirectPathPushReceive;
+ uint64_t _lastPathSort;
+ uint16_t _vProto;
+ uint16_t _vMajor;
+ uint16_t _vMinor;
+ uint16_t _vRevision;
+ Identity _id;
+ Path _paths[ZT_MAX_PEER_NETWORK_PATHS];
+ unsigned int _numPaths;
+ unsigned int _latency;
+ unsigned int _directPathPushCutoffCount;
+
+ struct _NetworkCom
+ {
+ _NetworkCom() {}
+ _NetworkCom(uint64_t t,const CertificateOfMembership &c) : ts(t),com(c) {}
+ uint64_t ts;
+ CertificateOfMembership com;
+ };
+ Hashtable<uint64_t,_NetworkCom> _networkComs;
+ Hashtable<uint64_t,uint64_t> _lastPushedComs;
+ Mutex _networkComs_m;
+
+ AtomicCounter __refCount;
+};
+
+} // namespace ZeroTier
+
+// Add a swap() for shared ptr's to peers to speed up peer sorts
+namespace std {
+ template<>
+ inline void swap(ZeroTier::SharedPtr<ZeroTier::Peer> &a,ZeroTier::SharedPtr<ZeroTier::Peer> &b)
+ {
+ a.swap(b);
+ }
+}
+
+#endif
diff --git a/zerotierone/node/Poly1305.cpp b/zerotierone/node/Poly1305.cpp
new file mode 100644
index 0000000..b78071f
--- /dev/null
+++ b/zerotierone/node/Poly1305.cpp
@@ -0,0 +1,628 @@
+/*
+20080912
+D. J. Bernstein
+Public domain.
+*/
+
+#include "Constants.hpp"
+#include "Poly1305.hpp"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __WINDOWS__
+#pragma warning(disable: 4146)
+#endif
+
+namespace ZeroTier {
+
+#if 0
+
+// "Naive" implementation, which is slower... might still want this on some older
+// or weird platforms if the later versions have issues.
+
+static inline void add(unsigned int h[17],const unsigned int c[17])
+{
+ unsigned int j;
+ unsigned int u;
+ u = 0;
+ for (j = 0;j < 17;++j) { u += h[j] + c[j]; h[j] = u & 255; u >>= 8; }
+}
+
+static inline void squeeze(unsigned int h[17])
+{
+ unsigned int j;
+ unsigned int u;
+ u = 0;
+ for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
+ u += h[16]; h[16] = u & 3;
+ u = 5 * (u >> 2);
+ for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
+ u += h[16]; h[16] = u;
+}
+
+static const unsigned int minusp[17] = {
+ 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
+} ;
+
+static inline void freeze(unsigned int h[17])
+{
+ unsigned int horig[17];
+ unsigned int j;
+ unsigned int negative;
+ for (j = 0;j < 17;++j) horig[j] = h[j];
+ add(h,minusp);
+ negative = -(h[16] >> 7);
+ for (j = 0;j < 17;++j) h[j] ^= negative & (horig[j] ^ h[j]);
+}
+
+static inline void mulmod(unsigned int h[17],const unsigned int r[17])
+{
+ unsigned int hr[17];
+ unsigned int i;
+ unsigned int j;
+ unsigned int u;
+
+ for (i = 0;i < 17;++i) {
+ u = 0;
+ for (j = 0;j <= i;++j) u += h[j] * r[i - j];
+ for (j = i + 1;j < 17;++j) u += 320 * h[j] * r[i + 17 - j];
+ hr[i] = u;
+ }
+ for (i = 0;i < 17;++i) h[i] = hr[i];
+ squeeze(h);
+}
+
+static inline int crypto_onetimeauth(unsigned char *out,const unsigned char *in,unsigned long long inlen,const unsigned char *k)
+{
+ unsigned int j;
+ unsigned int r[17];
+ unsigned int h[17];
+ unsigned int c[17];
+
+ r[0] = k[0];
+ r[1] = k[1];
+ r[2] = k[2];
+ r[3] = k[3] & 15;
+ r[4] = k[4] & 252;
+ r[5] = k[5];
+ r[6] = k[6];
+ r[7] = k[7] & 15;
+ r[8] = k[8] & 252;
+ r[9] = k[9];
+ r[10] = k[10];
+ r[11] = k[11] & 15;
+ r[12] = k[12] & 252;
+ r[13] = k[13];
+ r[14] = k[14];
+ r[15] = k[15] & 15;
+ r[16] = 0;
+
+ for (j = 0;j < 17;++j) h[j] = 0;
+
+ while (inlen > 0) {
+ for (j = 0;j < 17;++j) c[j] = 0;
+ for (j = 0;(j < 16) && (j < inlen);++j) c[j] = in[j];
+ c[j] = 1;
+ in += j; inlen -= j;
+ add(h,c);
+ mulmod(h,r);
+ }
+
+ freeze(h);
+
+ for (j = 0;j < 16;++j) c[j] = k[j + 16];
+ c[16] = 0;
+ add(h,c);
+ for (j = 0;j < 16;++j) out[j] = h[j];
+ return 0;
+}
+
+void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
+ throw()
+{
+ crypto_onetimeauth((unsigned char *)auth,(const unsigned char *)data,len,(const unsigned char *)key);
+}
+
+#endif
+
+namespace {
+
+typedef struct poly1305_context {
+ size_t aligner;
+ unsigned char opaque[136];
+} poly1305_context;
+
+#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
+
+//////////////////////////////////////////////////////////////////////////////
+// 128-bit implementation for MSC and GCC from Poly1305-donna
+
+#if defined(_MSC_VER)
+ #include <intrin.h>
+
+ typedef struct uint128_t {
+ unsigned long long lo;
+ unsigned long long hi;
+ } uint128_t;
+
+ #define MUL(out, x, y) out.lo = _umul128((x), (y), &out.hi)
+ #define ADD(out, in) { unsigned long long t = out.lo; out.lo += in.lo; out.hi += (out.lo < t) + in.hi; }
+ #define ADDLO(out, in) { unsigned long long t = out.lo; out.lo += in; out.hi += (out.lo < t); }
+ #define SHR(in, shift) (__shiftright128(in.lo, in.hi, (shift)))
+ #define LO(in) (in.lo)
+
+// #define POLY1305_NOINLINE __declspec(noinline)
+#elif defined(__GNUC__)
+ #if defined(__SIZEOF_INT128__)
+ typedef unsigned __int128 uint128_t;
+ #else
+ typedef unsigned uint128_t __attribute__((mode(TI)));
+ #endif
+
+ #define MUL(out, x, y) out = ((uint128_t)x * y)
+ #define ADD(out, in) out += in
+ #define ADDLO(out, in) out += in
+ #define SHR(in, shift) (unsigned long long)(in >> (shift))
+ #define LO(in) (unsigned long long)(in)
+
+// #define POLY1305_NOINLINE __attribute__((noinline))
+#endif
+
+#define poly1305_block_size 16
+
+/* 17 + sizeof(size_t) + 8*sizeof(unsigned long long) */
+typedef struct poly1305_state_internal_t {
+ unsigned long long r[3];
+ unsigned long long h[3];
+ unsigned long long pad[2];
+ size_t leftover;
+ unsigned char buffer[poly1305_block_size];
+ unsigned char final;
+} poly1305_state_internal_t;
+
+/* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in little endian */
+static inline unsigned long long
+U8TO64(const unsigned char *p) {
+ return
+ (((unsigned long long)(p[0] & 0xff) ) |
+ ((unsigned long long)(p[1] & 0xff) << 8) |
+ ((unsigned long long)(p[2] & 0xff) << 16) |
+ ((unsigned long long)(p[3] & 0xff) << 24) |
+ ((unsigned long long)(p[4] & 0xff) << 32) |
+ ((unsigned long long)(p[5] & 0xff) << 40) |
+ ((unsigned long long)(p[6] & 0xff) << 48) |
+ ((unsigned long long)(p[7] & 0xff) << 56));
+}
+
+/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little endian */
+static inline void
+U64TO8(unsigned char *p, unsigned long long v) {
+ p[0] = (v ) & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = (v >> 16) & 0xff;
+ p[3] = (v >> 24) & 0xff;
+ p[4] = (v >> 32) & 0xff;
+ p[5] = (v >> 40) & 0xff;
+ p[6] = (v >> 48) & 0xff;
+ p[7] = (v >> 56) & 0xff;
+}
+
+static inline void
+poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long long t0,t1;
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ t0 = U8TO64(&key[0]);
+ t1 = U8TO64(&key[8]);
+
+ st->r[0] = ( t0 ) & 0xffc0fffffff;
+ st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
+ st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f;
+
+ /* h = 0 */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+
+ /* save pad for later */
+ st->pad[0] = U8TO64(&key[16]);
+ st->pad[1] = U8TO64(&key[24]);
+
+ st->leftover = 0;
+ st->final = 0;
+}
+
+static inline void
+poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
+ const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
+ unsigned long long r0,r1,r2;
+ unsigned long long s1,s2;
+ unsigned long long h0,h1,h2;
+ unsigned long long c;
+ uint128_t d0,d1,d2,d;
+
+ r0 = st->r[0];
+ r1 = st->r[1];
+ r2 = st->r[2];
+
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+
+ s1 = r1 * (5 << 2);
+ s2 = r2 * (5 << 2);
+
+ while (bytes >= poly1305_block_size) {
+ unsigned long long t0,t1;
+
+ /* h += m[i] */
+ t0 = U8TO64(&m[0]);
+ t1 = U8TO64(&m[8]);
+
+ h0 += (( t0 ) & 0xfffffffffff);
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit;
+
+ /* h *= r */
+ MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d);
+ MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d);
+ MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d);
+
+ /* (partial) h %= p */
+ c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff;
+ ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff;
+ ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff;
+ h1 += c;
+
+ m += poly1305_block_size;
+ bytes -= poly1305_block_size;
+ }
+
+ st->h[0] = h0;
+ st->h[1] = h1;
+ st->h[2] = h2;
+}
+
+static inline void
+poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long long h0,h1,h2,c;
+ unsigned long long g0,g1,g2;
+ unsigned long long t0,t1;
+
+ /* process the remaining block */
+ if (st->leftover) {
+ size_t i = st->leftover;
+ st->buffer[i] = 1;
+ for (i = i + 1; i < poly1305_block_size; i++)
+ st->buffer[i] = 0;
+ st->final = 1;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ }
+
+ /* fully carry h */
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+
+ c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff;
+ h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += c;
+
+ /* compute h + -p */
+ g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff;
+ g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff;
+ g2 = h2 + c - ((unsigned long long)1 << 42);
+
+ /* select h if h < p, or h + -p if h >= p */
+ c = (g2 >> ((sizeof(unsigned long long) * 8) - 1)) - 1;
+ g0 &= c;
+ g1 &= c;
+ g2 &= c;
+ c = ~c;
+ h0 = (h0 & c) | g0;
+ h1 = (h1 & c) | g1;
+ h2 = (h2 & c) | g2;
+
+ /* h = (h + pad) */
+ t0 = st->pad[0];
+ t1 = st->pad[1];
+
+ h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff;
+ h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff;
+ h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff;
+
+ /* mac = h % (2^128) */
+ h0 = ((h0 ) | (h1 << 44));
+ h1 = ((h1 >> 20) | (h2 << 24));
+
+ U64TO8(&mac[0], h0);
+ U64TO8(&mac[8], h1);
+
+ /* zero out the state */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->r[0] = 0;
+ st->r[1] = 0;
+ st->r[2] = 0;
+ st->pad[0] = 0;
+ st->pad[1] = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#else
+
+//////////////////////////////////////////////////////////////////////////////
+// More portable 64-bit implementation
+
+#define poly1305_block_size 16
+
+/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
+typedef struct poly1305_state_internal_t {
+ unsigned long r[5];
+ unsigned long h[5];
+ unsigned long pad[4];
+ size_t leftover;
+ unsigned char buffer[poly1305_block_size];
+ unsigned char final;
+} poly1305_state_internal_t;
+
+/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */
+static unsigned long
+U8TO32(const unsigned char *p) {
+ return
+ (((unsigned long)(p[0] & 0xff) ) |
+ ((unsigned long)(p[1] & 0xff) << 8) |
+ ((unsigned long)(p[2] & 0xff) << 16) |
+ ((unsigned long)(p[3] & 0xff) << 24));
+}
+
+/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */
+static void
+U32TO8(unsigned char *p, unsigned long v) {
+ p[0] = (v ) & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = (v >> 16) & 0xff;
+ p[3] = (v >> 24) & 0xff;
+}
+
+static inline void
+poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+
+ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+ st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff;
+ st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03;
+ st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff;
+ st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff;
+ st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
+
+ /* h = 0 */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->h[3] = 0;
+ st->h[4] = 0;
+
+ /* save pad for later */
+ st->pad[0] = U8TO32(&key[16]);
+ st->pad[1] = U8TO32(&key[20]);
+ st->pad[2] = U8TO32(&key[24]);
+ st->pad[3] = U8TO32(&key[28]);
+
+ st->leftover = 0;
+ st->final = 0;
+}
+
+static inline void
+poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
+ const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
+ unsigned long r0,r1,r2,r3,r4;
+ unsigned long s1,s2,s3,s4;
+ unsigned long h0,h1,h2,h3,h4;
+ unsigned long long d0,d1,d2,d3,d4;
+ unsigned long c;
+
+ r0 = st->r[0];
+ r1 = st->r[1];
+ r2 = st->r[2];
+ r3 = st->r[3];
+ r4 = st->r[4];
+
+ s1 = r1 * 5;
+ s2 = r2 * 5;
+ s3 = r3 * 5;
+ s4 = r4 * 5;
+
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+ h3 = st->h[3];
+ h4 = st->h[4];
+
+ while (bytes >= poly1305_block_size) {
+ /* h += m[i] */
+ h0 += (U8TO32(m+ 0) ) & 0x3ffffff;
+ h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff;
+ h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff;
+ h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff;
+ h4 += (U8TO32(m+12) >> 8) | hibit;
+
+ /* h *= r */
+ d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1);
+ d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2);
+ d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3);
+ d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4);
+ d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0);
+
+ /* (partial) h %= p */
+ c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff;
+ d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff;
+ d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff;
+ d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff;
+ d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff;
+ h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ m += poly1305_block_size;
+ bytes -= poly1305_block_size;
+ }
+
+ st->h[0] = h0;
+ st->h[1] = h1;
+ st->h[2] = h2;
+ st->h[3] = h3;
+ st->h[4] = h4;
+}
+
+static inline void
+poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ unsigned long h0,h1,h2,h3,h4,c;
+ unsigned long g0,g1,g2,g3,g4;
+ unsigned long long f;
+ unsigned long mask;
+
+ /* process the remaining block */
+ if (st->leftover) {
+ size_t i = st->leftover;
+ st->buffer[i++] = 1;
+ for (; i < poly1305_block_size; i++)
+ st->buffer[i] = 0;
+ st->final = 1;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ }
+
+ /* fully carry h */
+ h0 = st->h[0];
+ h1 = st->h[1];
+ h2 = st->h[2];
+ h3 = st->h[3];
+ h4 = st->h[4];
+
+ c = h1 >> 26; h1 = h1 & 0x3ffffff;
+ h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+ h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+ h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+ h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+ h1 += c;
+
+ /* compute h + -p */
+ g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
+ g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
+ g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
+ g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
+ g4 = h4 + c - (1 << 26);
+
+ /* select h if h < p, or h + -p if h >= p */
+ mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
+ g0 &= mask;
+ g1 &= mask;
+ g2 &= mask;
+ g3 &= mask;
+ g4 &= mask;
+ mask = ~mask;
+ h0 = (h0 & mask) | g0;
+ h1 = (h1 & mask) | g1;
+ h2 = (h2 & mask) | g2;
+ h3 = (h3 & mask) | g3;
+ h4 = (h4 & mask) | g4;
+
+ /* h = h % (2^128) */
+ h0 = ((h0 ) | (h1 << 26)) & 0xffffffff;
+ h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+ h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+ h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+ /* mac = (h + pad) % (2^128) */
+ f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f;
+ f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f;
+ f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f;
+ f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f;
+
+ U32TO8(mac + 0, h0);
+ U32TO8(mac + 4, h1);
+ U32TO8(mac + 8, h2);
+ U32TO8(mac + 12, h3);
+
+ /* zero out the state */
+ st->h[0] = 0;
+ st->h[1] = 0;
+ st->h[2] = 0;
+ st->h[3] = 0;
+ st->h[4] = 0;
+ st->r[0] = 0;
+ st->r[1] = 0;
+ st->r[2] = 0;
+ st->r[3] = 0;
+ st->r[4] = 0;
+ st->pad[0] = 0;
+ st->pad[1] = 0;
+ st->pad[2] = 0;
+ st->pad[3] = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // MSC/GCC or not
+
+static inline void
+poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
+ poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
+ size_t i;
+
+ /* handle leftover */
+ if (st->leftover) {
+ size_t want = (poly1305_block_size - st->leftover);
+ if (want > bytes)
+ want = bytes;
+ for (i = 0; i < want; i++)
+ st->buffer[st->leftover + i] = m[i];
+ bytes -= want;
+ m += want;
+ st->leftover += want;
+ if (st->leftover < poly1305_block_size)
+ return;
+ poly1305_blocks(st, st->buffer, poly1305_block_size);
+ st->leftover = 0;
+ }
+
+ /* process full blocks */
+ if (bytes >= poly1305_block_size) {
+ size_t want = (bytes & ~(poly1305_block_size - 1));
+ poly1305_blocks(st, m, want);
+ m += want;
+ bytes -= want;
+ }
+
+ /* store leftover */
+ if (bytes) {
+ for (i = 0; i < bytes; i++)
+ st->buffer[st->leftover + i] = m[i];
+ st->leftover += bytes;
+ }
+}
+
+} // anonymous namespace
+
+void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
+ throw()
+{
+ poly1305_context ctx;
+ poly1305_init(&ctx,reinterpret_cast<const unsigned char *>(key));
+ poly1305_update(&ctx,reinterpret_cast<const unsigned char *>(data),(size_t)len);
+ poly1305_finish(&ctx,reinterpret_cast<unsigned char *>(auth));
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Poly1305.hpp b/zerotierone/node/Poly1305.hpp
new file mode 100644
index 0000000..62d5754
--- /dev/null
+++ b/zerotierone/node/Poly1305.hpp
@@ -0,0 +1,55 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_POLY1305_HPP
+#define ZT_POLY1305_HPP
+
+namespace ZeroTier {
+
+#define ZT_POLY1305_KEY_LEN 32
+#define ZT_POLY1305_MAC_LEN 16
+
+/**
+ * Poly1305 one-time authentication code
+ *
+ * This takes a one-time-use 32-byte key and generates a 16-byte message
+ * authentication code. The key must never be re-used for a different
+ * message.
+ *
+ * In Packet this is done by using the first 32 bytes of the stream cipher
+ * keystream as a one-time-use key. These 32 bytes are then discarded and
+ * the packet is encrypted with the next N bytes.
+ */
+class Poly1305
+{
+public:
+ /**
+ * Compute a one-time authentication code
+ *
+ * @param auth Buffer to receive code -- MUST be 16 bytes in length
+ * @param data Data to authenticate
+ * @param len Length of data to authenticate in bytes
+ * @param key 32-byte one-time use key to authenticate data (must not be reused)
+ */
+ static void compute(void *auth,const void *data,unsigned int len,const void *key)
+ throw();
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/RuntimeEnvironment.hpp b/zerotierone/node/RuntimeEnvironment.hpp
new file mode 100644
index 0000000..1f52773
--- /dev/null
+++ b/zerotierone/node/RuntimeEnvironment.hpp
@@ -0,0 +1,98 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_RUNTIMEENVIRONMENT_HPP
+#define ZT_RUNTIMEENVIRONMENT_HPP
+
+#include <string>
+
+#include "Constants.hpp"
+#include "Identity.hpp"
+#include "Mutex.hpp"
+
+namespace ZeroTier {
+
+class NodeConfig;
+class Switch;
+class Topology;
+class Node;
+class Multicaster;
+class NetworkController;
+class SelfAwareness;
+class Cluster;
+class DeferredPackets;
+
+/**
+ * Holds global state for an instance of ZeroTier::Node
+ */
+class RuntimeEnvironment
+{
+public:
+ RuntimeEnvironment(Node *n) :
+ node(n)
+ ,identity()
+ ,localNetworkController((NetworkController *)0)
+ ,sw((Switch *)0)
+ ,mc((Multicaster *)0)
+ ,topology((Topology *)0)
+ ,sa((SelfAwareness *)0)
+ ,dp((DeferredPackets *)0)
+#ifdef ZT_ENABLE_CLUSTER
+ ,cluster((Cluster *)0)
+#endif
+ ,dpEnabled(0)
+ {
+ }
+
+ // Node instance that owns this RuntimeEnvironment
+ Node *const node;
+
+ // This node's identity
+ Identity identity;
+ std::string publicIdentityStr;
+ std::string secretIdentityStr;
+
+ // This is set externally to an instance of this base class
+ NetworkController *localNetworkController;
+
+ /*
+ * Order matters a bit here. These are constructed in this order
+ * and then deleted in the opposite order on Node exit. The order ensures
+ * that things that are needed are there before they're needed.
+ *
+ * These are constant and never null after startup unless indicated.
+ */
+
+ Switch *sw;
+ Multicaster *mc;
+ Topology *topology;
+ SelfAwareness *sa;
+ DeferredPackets *dp;
+
+#ifdef ZT_ENABLE_CLUSTER
+ Cluster *cluster;
+#endif
+
+ // This is set to >0 if background threads are waiting on deferred
+ // packets, otherwise 'dp' should not be used.
+ volatile int dpEnabled;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/SHA512.cpp b/zerotierone/node/SHA512.cpp
new file mode 100644
index 0000000..76737d3
--- /dev/null
+++ b/zerotierone/node/SHA512.cpp
@@ -0,0 +1,352 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SHA512.hpp"
+#include "Utils.hpp"
+
+namespace ZeroTier {
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Code taken from NaCl by D. J. Bernstein and others
+// Public domain
+
+/*
+20080913
+D. J. Bernstein
+Public domain.
+*/
+
+#define uint64 uint64_t
+
+#ifdef ZT_NO_TYPE_PUNNING
+
+static uint64 load_bigendian(const unsigned char *x)
+{
+ return
+ (uint64) (x[7]) \
+ | (((uint64) (x[6])) << 8) \
+ | (((uint64) (x[5])) << 16) \
+ | (((uint64) (x[4])) << 24) \
+ | (((uint64) (x[3])) << 32) \
+ | (((uint64) (x[2])) << 40) \
+ | (((uint64) (x[1])) << 48) \
+ | (((uint64) (x[0])) << 56)
+ ;
+}
+
+static void store_bigendian(unsigned char *x,uint64 u)
+{
+ x[7] = u; u >>= 8;
+ x[6] = u; u >>= 8;
+ x[5] = u; u >>= 8;
+ x[4] = u; u >>= 8;
+ x[3] = u; u >>= 8;
+ x[2] = u; u >>= 8;
+ x[1] = u; u >>= 8;
+ x[0] = u;
+}
+
+#else // !ZT_NO_TYPE_PUNNING
+
+#define load_bigendian(x) Utils::ntoh(*((const uint64_t *)(x)))
+#define store_bigendian(x,u) (*((uint64_t *)(x)) = Utils::hton((u)))
+
+#endif // ZT_NO_TYPE_PUNNING
+
+#define SHR(x,c) ((x) >> (c))
+#define ROTR(x,c) (((x) >> (c)) | ((x) << (64 - (c))))
+
+#define Ch(x,y,z) ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+#define Sigma0(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
+#define Sigma1(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
+#define sigma0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x,7))
+#define sigma1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x,6))
+
+#define M(w0,w14,w9,w1) w0 = sigma1(w14) + w9 + sigma0(w1) + w0;
+
+#define EXPAND \
+ M(w0 ,w14,w9 ,w1 ) \
+ M(w1 ,w15,w10,w2 ) \
+ M(w2 ,w0 ,w11,w3 ) \
+ M(w3 ,w1 ,w12,w4 ) \
+ M(w4 ,w2 ,w13,w5 ) \
+ M(w5 ,w3 ,w14,w6 ) \
+ M(w6 ,w4 ,w15,w7 ) \
+ M(w7 ,w5 ,w0 ,w8 ) \
+ M(w8 ,w6 ,w1 ,w9 ) \
+ M(w9 ,w7 ,w2 ,w10) \
+ M(w10,w8 ,w3 ,w11) \
+ M(w11,w9 ,w4 ,w12) \
+ M(w12,w10,w5 ,w13) \
+ M(w13,w11,w6 ,w14) \
+ M(w14,w12,w7 ,w15) \
+ M(w15,w13,w8 ,w0 )
+
+#define F(w,k) \
+ T1 = h + Sigma1(e) + Ch(e,f,g) + k + w; \
+ T2 = Sigma0(a) + Maj(a,b,c); \
+ h = g; \
+ g = f; \
+ f = e; \
+ e = d + T1; \
+ d = c; \
+ c = b; \
+ b = a; \
+ a = T1 + T2;
+
+static inline int crypto_hashblocks(unsigned char *statebytes,const unsigned char *in,unsigned long long inlen)
+{
+ uint64 state[8];
+ uint64 a;
+ uint64 b;
+ uint64 c;
+ uint64 d;
+ uint64 e;
+ uint64 f;
+ uint64 g;
+ uint64 h;
+ uint64 T1;
+ uint64 T2;
+
+ a = load_bigendian(statebytes + 0); state[0] = a;
+ b = load_bigendian(statebytes + 8); state[1] = b;
+ c = load_bigendian(statebytes + 16); state[2] = c;
+ d = load_bigendian(statebytes + 24); state[3] = d;
+ e = load_bigendian(statebytes + 32); state[4] = e;
+ f = load_bigendian(statebytes + 40); state[5] = f;
+ g = load_bigendian(statebytes + 48); state[6] = g;
+ h = load_bigendian(statebytes + 56); state[7] = h;
+
+ while (inlen >= 128) {
+ uint64 w0 = load_bigendian(in + 0);
+ uint64 w1 = load_bigendian(in + 8);
+ uint64 w2 = load_bigendian(in + 16);
+ uint64 w3 = load_bigendian(in + 24);
+ uint64 w4 = load_bigendian(in + 32);
+ uint64 w5 = load_bigendian(in + 40);
+ uint64 w6 = load_bigendian(in + 48);
+ uint64 w7 = load_bigendian(in + 56);
+ uint64 w8 = load_bigendian(in + 64);
+ uint64 w9 = load_bigendian(in + 72);
+ uint64 w10 = load_bigendian(in + 80);
+ uint64 w11 = load_bigendian(in + 88);
+ uint64 w12 = load_bigendian(in + 96);
+ uint64 w13 = load_bigendian(in + 104);
+ uint64 w14 = load_bigendian(in + 112);
+ uint64 w15 = load_bigendian(in + 120);
+
+ F(w0 ,0x428a2f98d728ae22ULL)
+ F(w1 ,0x7137449123ef65cdULL)
+ F(w2 ,0xb5c0fbcfec4d3b2fULL)
+ F(w3 ,0xe9b5dba58189dbbcULL)
+ F(w4 ,0x3956c25bf348b538ULL)
+ F(w5 ,0x59f111f1b605d019ULL)
+ F(w6 ,0x923f82a4af194f9bULL)
+ F(w7 ,0xab1c5ed5da6d8118ULL)
+ F(w8 ,0xd807aa98a3030242ULL)
+ F(w9 ,0x12835b0145706fbeULL)
+ F(w10,0x243185be4ee4b28cULL)
+ F(w11,0x550c7dc3d5ffb4e2ULL)
+ F(w12,0x72be5d74f27b896fULL)
+ F(w13,0x80deb1fe3b1696b1ULL)
+ F(w14,0x9bdc06a725c71235ULL)
+ F(w15,0xc19bf174cf692694ULL)
+
+ EXPAND
+
+ F(w0 ,0xe49b69c19ef14ad2ULL)
+ F(w1 ,0xefbe4786384f25e3ULL)
+ F(w2 ,0x0fc19dc68b8cd5b5ULL)
+ F(w3 ,0x240ca1cc77ac9c65ULL)
+ F(w4 ,0x2de92c6f592b0275ULL)
+ F(w5 ,0x4a7484aa6ea6e483ULL)
+ F(w6 ,0x5cb0a9dcbd41fbd4ULL)
+ F(w7 ,0x76f988da831153b5ULL)
+ F(w8 ,0x983e5152ee66dfabULL)
+ F(w9 ,0xa831c66d2db43210ULL)
+ F(w10,0xb00327c898fb213fULL)
+ F(w11,0xbf597fc7beef0ee4ULL)
+ F(w12,0xc6e00bf33da88fc2ULL)
+ F(w13,0xd5a79147930aa725ULL)
+ F(w14,0x06ca6351e003826fULL)
+ F(w15,0x142929670a0e6e70ULL)
+
+ EXPAND
+
+ F(w0 ,0x27b70a8546d22ffcULL)
+ F(w1 ,0x2e1b21385c26c926ULL)
+ F(w2 ,0x4d2c6dfc5ac42aedULL)
+ F(w3 ,0x53380d139d95b3dfULL)
+ F(w4 ,0x650a73548baf63deULL)
+ F(w5 ,0x766a0abb3c77b2a8ULL)
+ F(w6 ,0x81c2c92e47edaee6ULL)
+ F(w7 ,0x92722c851482353bULL)
+ F(w8 ,0xa2bfe8a14cf10364ULL)
+ F(w9 ,0xa81a664bbc423001ULL)
+ F(w10,0xc24b8b70d0f89791ULL)
+ F(w11,0xc76c51a30654be30ULL)
+ F(w12,0xd192e819d6ef5218ULL)
+ F(w13,0xd69906245565a910ULL)
+ F(w14,0xf40e35855771202aULL)
+ F(w15,0x106aa07032bbd1b8ULL)
+
+ EXPAND
+
+ F(w0 ,0x19a4c116b8d2d0c8ULL)
+ F(w1 ,0x1e376c085141ab53ULL)
+ F(w2 ,0x2748774cdf8eeb99ULL)
+ F(w3 ,0x34b0bcb5e19b48a8ULL)
+ F(w4 ,0x391c0cb3c5c95a63ULL)
+ F(w5 ,0x4ed8aa4ae3418acbULL)
+ F(w6 ,0x5b9cca4f7763e373ULL)
+ F(w7 ,0x682e6ff3d6b2b8a3ULL)
+ F(w8 ,0x748f82ee5defb2fcULL)
+ F(w9 ,0x78a5636f43172f60ULL)
+ F(w10,0x84c87814a1f0ab72ULL)
+ F(w11,0x8cc702081a6439ecULL)
+ F(w12,0x90befffa23631e28ULL)
+ F(w13,0xa4506cebde82bde9ULL)
+ F(w14,0xbef9a3f7b2c67915ULL)
+ F(w15,0xc67178f2e372532bULL)
+
+ EXPAND
+
+ F(w0 ,0xca273eceea26619cULL)
+ F(w1 ,0xd186b8c721c0c207ULL)
+ F(w2 ,0xeada7dd6cde0eb1eULL)
+ F(w3 ,0xf57d4f7fee6ed178ULL)
+ F(w4 ,0x06f067aa72176fbaULL)
+ F(w5 ,0x0a637dc5a2c898a6ULL)
+ F(w6 ,0x113f9804bef90daeULL)
+ F(w7 ,0x1b710b35131c471bULL)
+ F(w8 ,0x28db77f523047d84ULL)
+ F(w9 ,0x32caab7b40c72493ULL)
+ F(w10,0x3c9ebe0a15c9bebcULL)
+ F(w11,0x431d67c49c100d4cULL)
+ F(w12,0x4cc5d4becb3e42b6ULL)
+ F(w13,0x597f299cfc657e2aULL)
+ F(w14,0x5fcb6fab3ad6faecULL)
+ F(w15,0x6c44198c4a475817ULL)
+
+ a += state[0];
+ b += state[1];
+ c += state[2];
+ d += state[3];
+ e += state[4];
+ f += state[5];
+ g += state[6];
+ h += state[7];
+
+ state[0] = a;
+ state[1] = b;
+ state[2] = c;
+ state[3] = d;
+ state[4] = e;
+ state[5] = f;
+ state[6] = g;
+ state[7] = h;
+
+ in += 128;
+ inlen -= 128;
+ }
+
+ store_bigendian(statebytes + 0,state[0]);
+ store_bigendian(statebytes + 8,state[1]);
+ store_bigendian(statebytes + 16,state[2]);
+ store_bigendian(statebytes + 24,state[3]);
+ store_bigendian(statebytes + 32,state[4]);
+ store_bigendian(statebytes + 40,state[5]);
+ store_bigendian(statebytes + 48,state[6]);
+ store_bigendian(statebytes + 56,state[7]);
+
+ return 0;
+}
+
+#define blocks crypto_hashblocks
+
+static const unsigned char iv[64] = {
+ 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
+ 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
+ 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
+ 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
+ 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
+ 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
+ 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
+ 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
+};
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void SHA512::hash(void *digest,const void *data,unsigned int len)
+{
+ unsigned char h[64];
+ unsigned char padded[256];
+ int i;
+ uint64_t bytes = len;
+
+ const unsigned char *in = (const unsigned char *)data;
+ unsigned int inlen = len;
+
+ for (i = 0;i < 64;++i) h[i] = iv[i];
+
+ blocks(h,in,inlen);
+ in += inlen;
+ inlen &= 127;
+ in -= inlen;
+
+ for (i = 0;i < (int)inlen;++i) padded[i] = in[i];
+ padded[inlen] = 0x80;
+
+ if (inlen < 112) {
+ for (i = inlen + 1;i < 119;++i) padded[i] = 0;
+ padded[119] = (unsigned char)((bytes >> 61) & 0xff);
+ padded[120] = (unsigned char)((bytes >> 53) & 0xff);
+ padded[121] = (unsigned char)((bytes >> 45) & 0xff);
+ padded[122] = (unsigned char)((bytes >> 37) & 0xff);
+ padded[123] = (unsigned char)((bytes >> 29) & 0xff);
+ padded[124] = (unsigned char)((bytes >> 21) & 0xff);
+ padded[125] = (unsigned char)((bytes >> 13) & 0xff);
+ padded[126] = (unsigned char)((bytes >> 5) & 0xff);
+ padded[127] = (unsigned char)((bytes << 3) & 0xff);
+ blocks(h,padded,128);
+ } else {
+ for (i = inlen + 1;i < 247;++i) padded[i] = 0;
+ padded[247] = (unsigned char)((bytes >> 61) & 0xff);
+ padded[248] = (unsigned char)((bytes >> 53) & 0xff);
+ padded[249] = (unsigned char)((bytes >> 45) & 0xff);
+ padded[250] = (unsigned char)((bytes >> 37) & 0xff);
+ padded[251] = (unsigned char)((bytes >> 29) & 0xff);
+ padded[252] = (unsigned char)((bytes >> 21) & 0xff);
+ padded[253] = (unsigned char)((bytes >> 13) & 0xff);
+ padded[254] = (unsigned char)((bytes >> 5) & 0xff);
+ padded[255] = (unsigned char)((bytes << 3) & 0xff);
+ blocks(h,padded,256);
+ }
+
+ for (i = 0;i < 64;++i) ((unsigned char *)digest)[i] = h[i];
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/SHA512.hpp b/zerotierone/node/SHA512.hpp
new file mode 100644
index 0000000..639a7df
--- /dev/null
+++ b/zerotierone/node/SHA512.hpp
@@ -0,0 +1,37 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_SHA512_HPP
+#define ZT_SHA512_HPP
+
+#define ZT_SHA512_DIGEST_LEN 64
+
+namespace ZeroTier {
+
+/**
+ * SHA-512 digest algorithm
+ */
+class SHA512
+{
+public:
+ static void hash(void *digest,const void *data,unsigned int len);
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Salsa20.cpp b/zerotierone/node/Salsa20.cpp
new file mode 100644
index 0000000..3aa19ac
--- /dev/null
+++ b/zerotierone/node/Salsa20.cpp
@@ -0,0 +1,1358 @@
+/*
+ * Based on public domain code available at: http://cr.yp.to/snuffle.html
+ *
+ * Modifications and C-native SSE macro based SSE implementation by
+ * Adam Ierymenko <[email protected]>.
+ *
+ * Since the original was public domain, this is too.
+ */
+
+#include "Constants.hpp"
+#include "Salsa20.hpp"
+
+#define ROTATE(v,c) (((v) << (c)) | ((v) >> (32 - (c))))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) ((uint32_t)((v) + (w)))
+
+// Set up laod/store macros with appropriate endianness (we don't use these in SSE mode)
+#ifndef ZT_SALSA20_SSE
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+#ifdef ZT_NO_TYPE_PUNNING
+// Slower version that does not use type punning
+#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) )
+static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); }
+#else
+// Fast version that just does 32-bit load/store
+#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p))))
+#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v)
+#endif // ZT_NO_TYPE_PUNNING
+
+#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?)
+
+#ifdef __GNUC__
+
+// Use GNUC builtin bswap macros on big-endian machines if available
+#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t *)((const void *)(p))))
+#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = __builtin_bswap32((v))
+
+#else // no __GNUC__
+
+// Otherwise do it the slow, manual way on BE machines
+#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) )
+static inline void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); }
+
+#endif // __GNUC__ or not
+
+#endif // __BYTE_ORDER little or big?
+
+#endif // !ZT_SALSA20_SSE
+
+// Statically compute and define SSE constants
+#ifdef ZT_SALSA20_SSE
+class _s20sseconsts
+{
+public:
+ _s20sseconsts()
+ {
+ maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0));
+ maskHi32 = _mm_slli_epi64(maskLo32, 32);
+ }
+ __m128i maskLo32,maskHi32;
+};
+static const _s20sseconsts _S20SSECONSTANTS;
+#endif
+
+namespace ZeroTier {
+
+void Salsa20::init(const void *key,unsigned int kbits,const void *iv)
+ throw()
+{
+#ifdef ZT_SALSA20_SSE
+ const uint32_t *k = (const uint32_t *)key;
+
+ _state.i[0] = 0x61707865;
+ _state.i[3] = 0x6b206574;
+ _state.i[13] = k[0];
+ _state.i[10] = k[1];
+ _state.i[7] = k[2];
+ _state.i[4] = k[3];
+ if (kbits == 256) {
+ k += 4;
+ _state.i[1] = 0x3320646e;
+ _state.i[2] = 0x79622d32;
+ } else {
+ _state.i[1] = 0x3120646e;
+ _state.i[2] = 0x79622d36;
+ }
+ _state.i[15] = k[0];
+ _state.i[12] = k[1];
+ _state.i[9] = k[2];
+ _state.i[6] = k[3];
+ _state.i[14] = ((const uint32_t *)iv)[0];
+ _state.i[11] = ((const uint32_t *)iv)[1];
+ _state.i[5] = 0;
+ _state.i[8] = 0;
+#else
+ const char *constants;
+ const uint8_t *k = (const uint8_t *)key;
+
+ _state.i[1] = U8TO32_LITTLE(k + 0);
+ _state.i[2] = U8TO32_LITTLE(k + 4);
+ _state.i[3] = U8TO32_LITTLE(k + 8);
+ _state.i[4] = U8TO32_LITTLE(k + 12);
+ if (kbits == 256) { /* recommended */
+ k += 16;
+ constants = "expand 32-byte k";
+ } else { /* kbits == 128 */
+ constants = "expand 16-byte k";
+ }
+ _state.i[5] = U8TO32_LITTLE(constants + 4);
+ _state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0);
+ _state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4);
+ _state.i[8] = 0;
+ _state.i[9] = 0;
+ _state.i[10] = U8TO32_LITTLE(constants + 8);
+ _state.i[11] = U8TO32_LITTLE(k + 0);
+ _state.i[12] = U8TO32_LITTLE(k + 4);
+ _state.i[13] = U8TO32_LITTLE(k + 8);
+ _state.i[14] = U8TO32_LITTLE(k + 12);
+ _state.i[15] = U8TO32_LITTLE(constants + 12);
+ _state.i[0] = U8TO32_LITTLE(constants + 0);
+#endif
+}
+
+void Salsa20::encrypt12(const void *in,void *out,unsigned int bytes)
+ throw()
+{
+ uint8_t tmp[64];
+ const uint8_t *m = (const uint8_t *)in;
+ uint8_t *c = (uint8_t *)out;
+ uint8_t *ctarget = c;
+ unsigned int i;
+
+#ifndef ZT_SALSA20_SSE
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+#endif
+
+ if (!bytes)
+ return;
+
+#ifndef ZT_SALSA20_SSE
+ j0 = _state.i[0];
+ j1 = _state.i[1];
+ j2 = _state.i[2];
+ j3 = _state.i[3];
+ j4 = _state.i[4];
+ j5 = _state.i[5];
+ j6 = _state.i[6];
+ j7 = _state.i[7];
+ j8 = _state.i[8];
+ j9 = _state.i[9];
+ j10 = _state.i[10];
+ j11 = _state.i[11];
+ j12 = _state.i[12];
+ j13 = _state.i[13];
+ j14 = _state.i[14];
+ j15 = _state.i[15];
+#endif
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+
+#ifdef ZT_SALSA20_SSE
+ __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0]));
+ __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1]));
+ __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2]));
+ __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3]));
+ __m128i T;
+ __m128i X0s = X0;
+ __m128i X1s = X1;
+ __m128i X2s = X2;
+ __m128i X3s = X3;
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ X0 = _mm_add_epi32(X0s,X0);
+ X1 = _mm_add_epi32(X1s,X1);
+ X2 = _mm_add_epi32(X2s,X2);
+ X3 = _mm_add_epi32(X3s,X3);
+
+ __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32));
+ __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32));
+ _mm_storeu_ps(reinterpret_cast<float *>(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m))))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 4)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 8)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 12)))));
+
+ if (!(++_state.i[8])) {
+ ++_state.i[5]; // state reordered for SSE
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#else
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+
+ U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0)));
+ U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4)));
+ U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8)));
+ U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12)));
+ U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16)));
+ U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20)));
+ U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24)));
+ U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28)));
+ U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32)));
+ U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36)));
+ U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40)));
+ U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44)));
+ U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48)));
+ U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52)));
+ U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56)));
+ U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60)));
+
+ if (!(++j8)) {
+ ++j9;
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#endif
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ ctarget[i] = c[i];
+ }
+
+#ifndef ZT_SALSA20_SSE
+ _state.i[8] = j8;
+ _state.i[9] = j9;
+#endif
+
+ return;
+ }
+
+ bytes -= 64;
+ c += 64;
+ m += 64;
+ }
+}
+
+void Salsa20::encrypt20(const void *in,void *out,unsigned int bytes)
+ throw()
+{
+ uint8_t tmp[64];
+ const uint8_t *m = (const uint8_t *)in;
+ uint8_t *c = (uint8_t *)out;
+ uint8_t *ctarget = c;
+ unsigned int i;
+
+#ifndef ZT_SALSA20_SSE
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
+ uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
+#endif
+
+ if (!bytes)
+ return;
+
+#ifndef ZT_SALSA20_SSE
+ j0 = _state.i[0];
+ j1 = _state.i[1];
+ j2 = _state.i[2];
+ j3 = _state.i[3];
+ j4 = _state.i[4];
+ j5 = _state.i[5];
+ j6 = _state.i[6];
+ j7 = _state.i[7];
+ j8 = _state.i[8];
+ j9 = _state.i[9];
+ j10 = _state.i[10];
+ j11 = _state.i[11];
+ j12 = _state.i[12];
+ j13 = _state.i[13];
+ j14 = _state.i[14];
+ j15 = _state.i[15];
+#endif
+
+ for (;;) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ tmp[i] = m[i];
+ m = tmp;
+ ctarget = c;
+ c = tmp;
+ }
+
+#ifdef ZT_SALSA20_SSE
+ __m128i X0 = _mm_loadu_si128((const __m128i *)&(_state.v[0]));
+ __m128i X1 = _mm_loadu_si128((const __m128i *)&(_state.v[1]));
+ __m128i X2 = _mm_loadu_si128((const __m128i *)&(_state.v[2]));
+ __m128i X3 = _mm_loadu_si128((const __m128i *)&(_state.v[3]));
+ __m128i T;
+ __m128i X0s = X0;
+ __m128i X1s = X1;
+ __m128i X2s = X2;
+ __m128i X3s = X3;
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ // 2X round -------------------------------------------------------------
+ T = _mm_add_epi32(X0, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X1, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X3, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x93);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x39);
+ T = _mm_add_epi32(X0, X1);
+ X3 = _mm_xor_si128(_mm_xor_si128(X3, _mm_slli_epi32(T, 7)), _mm_srli_epi32(T, 25));
+ T = _mm_add_epi32(X3, X0);
+ X2 = _mm_xor_si128(_mm_xor_si128(X2, _mm_slli_epi32(T, 9)), _mm_srli_epi32(T, 23));
+ T = _mm_add_epi32(X2, X3);
+ X1 = _mm_xor_si128(_mm_xor_si128(X1, _mm_slli_epi32(T, 13)), _mm_srli_epi32(T, 19));
+ T = _mm_add_epi32(X1, X2);
+ X0 = _mm_xor_si128(_mm_xor_si128(X0, _mm_slli_epi32(T, 18)), _mm_srli_epi32(T, 14));
+ X1 = _mm_shuffle_epi32(X1, 0x39);
+ X2 = _mm_shuffle_epi32(X2, 0x4E);
+ X3 = _mm_shuffle_epi32(X3, 0x93);
+
+ X0 = _mm_add_epi32(X0s,X0);
+ X1 = _mm_add_epi32(X1s,X1);
+ X2 = _mm_add_epi32(X2s,X2);
+ X3 = _mm_add_epi32(X3s,X3);
+
+ __m128i k02 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X0, 32), _mm_srli_epi64(X3, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k13 = _mm_shuffle_epi32(_mm_or_si128(_mm_slli_epi64(X1, 32), _mm_srli_epi64(X0, 32)), _MM_SHUFFLE(0, 1, 2, 3));
+ __m128i k20 = _mm_or_si128(_mm_and_si128(X2, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X1, _S20SSECONSTANTS.maskHi32));
+ __m128i k31 = _mm_or_si128(_mm_and_si128(X3, _S20SSECONSTANTS.maskLo32), _mm_and_si128(X2, _S20SSECONSTANTS.maskHi32));
+ _mm_storeu_ps(reinterpret_cast<float *>(c),_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k02,k20),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m))))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 4,_mm_castsi128_ps(_mm_xor_si128(_mm_unpackhi_epi64(k13,k31),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 4)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 8,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k20,k02),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 8)))));
+ _mm_storeu_ps(reinterpret_cast<float *>(c) + 12,_mm_castsi128_ps(_mm_xor_si128(_mm_unpacklo_epi64(k31,k13),_mm_castps_si128(_mm_loadu_ps(reinterpret_cast<const float *>(m) + 12)))));
+
+ if (!(++_state.i[8])) {
+ ++_state.i[5]; // state reordered for SSE
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#else
+ x0 = j0;
+ x1 = j1;
+ x2 = j2;
+ x3 = j3;
+ x4 = j4;
+ x5 = j5;
+ x6 = j6;
+ x7 = j7;
+ x8 = j8;
+ x9 = j9;
+ x10 = j10;
+ x11 = j11;
+ x12 = j12;
+ x13 = j13;
+ x14 = j14;
+ x15 = j15;
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ // 2X round -------------------------------------------------------------
+ x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7));
+ x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9));
+ x12 = XOR(x12,ROTATE(PLUS( x8, x4),13));
+ x0 = XOR( x0,ROTATE(PLUS(x12, x8),18));
+ x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7));
+ x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9));
+ x1 = XOR( x1,ROTATE(PLUS(x13, x9),13));
+ x5 = XOR( x5,ROTATE(PLUS( x1,x13),18));
+ x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7));
+ x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9));
+ x6 = XOR( x6,ROTATE(PLUS( x2,x14),13));
+ x10 = XOR(x10,ROTATE(PLUS( x6, x2),18));
+ x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9));
+ x11 = XOR(x11,ROTATE(PLUS( x7, x3),13));
+ x15 = XOR(x15,ROTATE(PLUS(x11, x7),18));
+ x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7));
+ x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9));
+ x3 = XOR( x3,ROTATE(PLUS( x2, x1),13));
+ x0 = XOR( x0,ROTATE(PLUS( x3, x2),18));
+ x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7));
+ x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9));
+ x4 = XOR( x4,ROTATE(PLUS( x7, x6),13));
+ x5 = XOR( x5,ROTATE(PLUS( x4, x7),18));
+ x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7));
+ x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9));
+ x9 = XOR( x9,ROTATE(PLUS( x8,x11),13));
+ x10 = XOR(x10,ROTATE(PLUS( x9, x8),18));
+ x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7));
+ x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9));
+ x14 = XOR(x14,ROTATE(PLUS(x13,x12),13));
+ x15 = XOR(x15,ROTATE(PLUS(x14,x13),18));
+
+ x0 = PLUS(x0,j0);
+ x1 = PLUS(x1,j1);
+ x2 = PLUS(x2,j2);
+ x3 = PLUS(x3,j3);
+ x4 = PLUS(x4,j4);
+ x5 = PLUS(x5,j5);
+ x6 = PLUS(x6,j6);
+ x7 = PLUS(x7,j7);
+ x8 = PLUS(x8,j8);
+ x9 = PLUS(x9,j9);
+ x10 = PLUS(x10,j10);
+ x11 = PLUS(x11,j11);
+ x12 = PLUS(x12,j12);
+ x13 = PLUS(x13,j13);
+ x14 = PLUS(x14,j14);
+ x15 = PLUS(x15,j15);
+
+ U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0)));
+ U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4)));
+ U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8)));
+ U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12)));
+ U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16)));
+ U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20)));
+ U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24)));
+ U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28)));
+ U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32)));
+ U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36)));
+ U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40)));
+ U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44)));
+ U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48)));
+ U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52)));
+ U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56)));
+ U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60)));
+
+ if (!(++j8)) {
+ ++j9;
+ /* stopping at 2^70 bytes per nonce is user's responsibility */
+ }
+#endif
+
+ if (bytes <= 64) {
+ if (bytes < 64) {
+ for (i = 0;i < bytes;++i)
+ ctarget[i] = c[i];
+ }
+
+#ifndef ZT_SALSA20_SSE
+ _state.i[8] = j8;
+ _state.i[9] = j9;
+#endif
+
+ return;
+ }
+
+ bytes -= 64;
+ c += 64;
+ m += 64;
+ }
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Salsa20.hpp b/zerotierone/node/Salsa20.hpp
new file mode 100644
index 0000000..7e4c1e5
--- /dev/null
+++ b/zerotierone/node/Salsa20.hpp
@@ -0,0 +1,115 @@
+/*
+ * Based on public domain code available at: http://cr.yp.to/snuffle.html
+ *
+ * This therefore is public domain.
+ */
+
+#ifndef ZT_SALSA20_HPP
+#define ZT_SALSA20_HPP
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "Constants.hpp"
+#include "Utils.hpp"
+
+#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || defined(__WINDOWS__))
+#define ZT_SALSA20_SSE 1
+#endif
+
+#ifdef ZT_SALSA20_SSE
+#include <emmintrin.h>
+#endif // ZT_SALSA20_SSE
+
+namespace ZeroTier {
+
+/**
+ * Salsa20 stream cipher
+ */
+class Salsa20
+{
+public:
+ Salsa20() throw() {}
+
+ ~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
+
+ /**
+ * @param key Key bits
+ * @param kbits Number of key bits: 128 or 256 (recommended)
+ * @param iv 64-bit initialization vector
+ */
+ Salsa20(const void *key,unsigned int kbits,const void *iv)
+ throw()
+ {
+ init(key,kbits,iv);
+ }
+
+ /**
+ * Initialize cipher
+ *
+ * @param key Key bits
+ * @param kbits Number of key bits: 128 or 256 (recommended)
+ * @param iv 64-bit initialization vector
+ */
+ void init(const void *key,unsigned int kbits,const void *iv)
+ throw();
+
+ /**
+ * Encrypt data using Salsa20/12
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ void encrypt12(const void *in,void *out,unsigned int bytes)
+ throw();
+
+ /**
+ * Encrypt data using Salsa20/20
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ void encrypt20(const void *in,void *out,unsigned int bytes)
+ throw();
+
+ /**
+ * Decrypt data
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ inline void decrypt12(const void *in,void *out,unsigned int bytes)
+ throw()
+ {
+ encrypt12(in,out,bytes);
+ }
+
+ /**
+ * Decrypt data
+ *
+ * @param in Input data
+ * @param out Output buffer
+ * @param bytes Length of data
+ */
+ inline void decrypt20(const void *in,void *out,unsigned int bytes)
+ throw()
+ {
+ encrypt20(in,out,bytes);
+ }
+
+private:
+ union {
+#ifdef ZT_SALSA20_SSE
+ __m128i v[4];
+#endif // ZT_SALSA20_SSE
+ uint32_t i[16];
+ } _state;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/SelfAwareness.cpp b/zerotierone/node/SelfAwareness.cpp
new file mode 100644
index 0000000..8bed0c5
--- /dev/null
+++ b/zerotierone/node/SelfAwareness.cpp
@@ -0,0 +1,187 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <set>
+#include <vector>
+
+#include "Constants.hpp"
+#include "SelfAwareness.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
+#include "Topology.hpp"
+#include "Packet.hpp"
+#include "Peer.hpp"
+#include "Switch.hpp"
+
+// Entry timeout -- make it fairly long since this is just to prevent stale buildup
+#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 3600000
+
+namespace ZeroTier {
+
+class _ResetWithinScope
+{
+public:
+ _ResetWithinScope(uint64_t now,InetAddress::IpScope scope) :
+ _now(now),
+ _scope(scope) {}
+
+ inline void operator()(Topology &t,const SharedPtr<Peer> &p)
+ {
+ if (p->resetWithinScope(_scope,_now))
+ peersReset.push_back(p);
+ }
+
+ std::vector< SharedPtr<Peer> > peersReset;
+
+private:
+ uint64_t _now;
+ InetAddress::IpScope _scope;
+};
+
+SelfAwareness::SelfAwareness(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _phy(32)
+{
+}
+
+SelfAwareness::~SelfAwareness()
+{
+}
+
+void SelfAwareness::iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now)
+{
+ const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
+
+ if ((scope != reporterPhysicalAddress.ipScope())||(scope == InetAddress::IP_SCOPE_NONE)||(scope == InetAddress::IP_SCOPE_LOOPBACK)||(scope == InetAddress::IP_SCOPE_MULTICAST))
+ return;
+
+ Mutex::Lock _l(_phy_m);
+ PhySurfaceEntry &entry = _phy[PhySurfaceKey(reporter,receivedOnLocalAddress,reporterPhysicalAddress,scope)];
+
+ if ( (trusted) && ((now - entry.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress)) ) {
+ // Changes to external surface reported by trusted peers causes path reset in this scope
+ entry.mySurface = myPhysicalAddress;
+ entry.ts = now;
+ TRACE("physical address %s for scope %u as seen from %s(%s) differs from %s, resetting paths in scope",myPhysicalAddress.toString().c_str(),(unsigned int)scope,reporter.toString().c_str(),reporterPhysicalAddress.toString().c_str(),entry.mySurface.toString().c_str());
+
+ // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing'
+ // due to multiple reports of endpoint change.
+ // Don't use 'entry' after this since hash table gets modified.
+ {
+ Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
+ PhySurfaceKey *k = (PhySurfaceKey *)0;
+ PhySurfaceEntry *e = (PhySurfaceEntry *)0;
+ while (i.next(k,e)) {
+ if ((k->reporterPhysicalAddress != reporterPhysicalAddress)&&(k->scope == scope))
+ _phy.erase(*k);
+ }
+ }
+
+ // Reset all paths within this scope
+ _ResetWithinScope rset(now,(InetAddress::IpScope)scope);
+ RR->topology->eachPeer<_ResetWithinScope &>(rset);
+
+ // Send a NOP to all peers for whom we forgot a path. This will cause direct
+ // links to be re-established if possible, possibly using a root server or some
+ // other relay.
+ for(std::vector< SharedPtr<Peer> >::const_iterator p(rset.peersReset.begin());p!=rset.peersReset.end();++p) {
+ if ((*p)->activelyTransferringFrames(now)) {
+ Packet outp((*p)->address(),RR->identity.address(),Packet::VERB_NOP);
+ RR->sw->send(outp,true,0);
+ }
+ }
+ } else {
+ // Otherwise just update DB to use to determine external surface info
+ entry.mySurface = myPhysicalAddress;
+ entry.ts = now;
+ }
+}
+
+void SelfAwareness::clean(uint64_t now)
+{
+ Mutex::Lock _l(_phy_m);
+ Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
+ PhySurfaceKey *k = (PhySurfaceKey *)0;
+ PhySurfaceEntry *e = (PhySurfaceEntry *)0;
+ while (i.next(k,e)) {
+ if ((now - e->ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
+ _phy.erase(*k);
+ }
+}
+
+std::vector<InetAddress> SelfAwareness::getSymmetricNatPredictions()
+{
+ /* This is based on ideas and strategies found here:
+ * https://tools.ietf.org/html/draft-takeda-symmetric-nat-traversal-00
+ *
+ * In short: a great many symmetric NATs allocate ports sequentially.
+ * This is common on enterprise and carrier grade NATs as well as consumer
+ * devices. This code generates a list of "you might try this" addresses by
+ * extrapolating likely port assignments from currently known external
+ * global IPv4 surfaces. These can then be included in a PUSH_DIRECT_PATHS
+ * message to another peer, causing it to possibly try these addresses and
+ * bust our local symmetric NAT. It works often enough to be worth the
+ * extra bit of code and does no harm in cases where it fails. */
+
+ // Gather unique surfaces indexed by local received-on address and flag
+ // us as behind a symmetric NAT if there is more than one.
+ std::map< InetAddress,std::set<InetAddress> > surfaces;
+ bool symmetric = false;
+ {
+ Mutex::Lock _l(_phy_m);
+ Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
+ PhySurfaceKey *k = (PhySurfaceKey *)0;
+ PhySurfaceEntry *e = (PhySurfaceEntry *)0;
+ while (i.next(k,e)) {
+ if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) {
+ std::set<InetAddress> &s = surfaces[k->receivedOnLocalAddress];
+ s.insert(e->mySurface);
+ symmetric = symmetric||(s.size() > 1);
+ }
+ }
+ }
+
+ // If we appear to be symmetrically NATed, generate and return extrapolations
+ // of those surfaces. Since PUSH_DIRECT_PATHS is sent multiple times, we
+ // probabilistically generate extrapolations of anywhere from +1 to +5 to
+ // increase the odds that it will work "eventually".
+ if (symmetric) {
+ std::vector<InetAddress> r;
+ for(std::map< InetAddress,std::set<InetAddress> >::iterator si(surfaces.begin());si!=surfaces.end();++si) {
+ for(std::set<InetAddress>::iterator i(si->second.begin());i!=si->second.end();++i) {
+ InetAddress ipp(*i);
+ unsigned int p = ipp.port() + 1 + ((unsigned int)RR->node->prng() & 3);
+ if (p >= 65535)
+ p -= 64510; // NATs seldom use ports <=1024 so wrap to 1025
+ ipp.setPort(p);
+ if ((si->second.count(ipp) == 0)&&(std::find(r.begin(),r.end(),ipp) == r.end())) {
+ r.push_back(ipp);
+ }
+ }
+ }
+ return r;
+ }
+
+ return std::vector<InetAddress>();
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/SelfAwareness.hpp b/zerotierone/node/SelfAwareness.hpp
new file mode 100644
index 0000000..06c264a
--- /dev/null
+++ b/zerotierone/node/SelfAwareness.hpp
@@ -0,0 +1,98 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_SELFAWARENESS_HPP
+#define ZT_SELFAWARENESS_HPP
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Hashtable.hpp"
+#include "Address.hpp"
+#include "Mutex.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+
+/**
+ * Tracks changes to this peer's real world addresses
+ */
+class SelfAwareness
+{
+public:
+ SelfAwareness(const RuntimeEnvironment *renv);
+ ~SelfAwareness();
+
+ /**
+ * Called when a trusted remote peer informs us of our external network address
+ *
+ * @param reporter ZeroTier address of reporting peer
+ * @param receivedOnLocalAddress Local address on which report was received
+ * @param reporterPhysicalAddress Physical address that reporting peer seems to have
+ * @param myPhysicalAddress Physical address that peer says we have
+ * @param trusted True if this peer is trusted as an authority to inform us of external address changes
+ * @param now Current time
+ */
+ void iam(const Address &reporter,const InetAddress &receivedOnLocalAddress,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,uint64_t now);
+
+ /**
+ * Clean up database periodically
+ *
+ * @param now Current time
+ */
+ void clean(uint64_t now);
+
+ /**
+ * If we appear to be behind a symmetric NAT, get predictions for possible external endpoints
+ *
+ * @return Symmetric NAT predictions or empty vector if none
+ */
+ std::vector<InetAddress> getSymmetricNatPredictions();
+
+private:
+ struct PhySurfaceKey
+ {
+ Address reporter;
+ InetAddress receivedOnLocalAddress;
+ InetAddress reporterPhysicalAddress;
+ InetAddress::IpScope scope;
+
+ PhySurfaceKey() : reporter(),scope(InetAddress::IP_SCOPE_NONE) {}
+ PhySurfaceKey(const Address &r,const InetAddress &rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalAddress(rol),reporterPhysicalAddress(ra),scope(s) {}
+
+ inline unsigned long hashCode() const throw() { return ((unsigned long)reporter.toInt() + (unsigned long)scope); }
+ inline bool operator==(const PhySurfaceKey &k) const throw() { return ((reporter == k.reporter)&&(receivedOnLocalAddress == k.receivedOnLocalAddress)&&(reporterPhysicalAddress == k.reporterPhysicalAddress)&&(scope == k.scope)); }
+ };
+ struct PhySurfaceEntry
+ {
+ InetAddress mySurface;
+ uint64_t ts;
+
+ PhySurfaceEntry() : mySurface(),ts(0) {}
+ PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t) {}
+ };
+
+ const RuntimeEnvironment *RR;
+
+ Hashtable< PhySurfaceKey,PhySurfaceEntry > _phy;
+ Mutex _phy_m;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/SharedPtr.hpp b/zerotierone/node/SharedPtr.hpp
new file mode 100644
index 0000000..3ff5ed1
--- /dev/null
+++ b/zerotierone/node/SharedPtr.hpp
@@ -0,0 +1,154 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_SHAREDPTR_HPP
+#define ZT_SHAREDPTR_HPP
+
+#include "Mutex.hpp"
+#include "AtomicCounter.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Simple reference counted pointer
+ *
+ * This is an introspective shared pointer. Classes that need to be reference
+ * counted must list this as a 'friend' and must have a private instance of
+ * AtomicCounter called __refCount. They should also have private destructors,
+ * since only this class should delete them.
+ *
+ * Because this is introspective, it is safe to apply to a naked pointer
+ * multiple times provided there is always at least one holding SharedPtr.
+ *
+ * Once C++11 is ubiquitous, this and a few other things like Thread might get
+ * torn out for their standard equivalents.
+ */
+template<typename T>
+class SharedPtr
+{
+public:
+ SharedPtr()
+ throw() :
+ _ptr((T *)0)
+ {
+ }
+
+ SharedPtr(T *obj)
+ throw() :
+ _ptr(obj)
+ {
+ ++obj->__refCount;
+ }
+
+ SharedPtr(const SharedPtr &sp)
+ throw() :
+ _ptr(sp._getAndInc())
+ {
+ }
+
+ ~SharedPtr()
+ {
+ if (_ptr) {
+ if (--_ptr->__refCount <= 0)
+ delete _ptr;
+ }
+ }
+
+ inline SharedPtr &operator=(const SharedPtr &sp)
+ {
+ if (_ptr != sp._ptr) {
+ T *p = sp._getAndInc();
+ if (_ptr) {
+ if (--_ptr->__refCount <= 0)
+ delete _ptr;
+ }
+ _ptr = p;
+ }
+ return *this;
+ }
+
+ /**
+ * Set to a naked pointer and increment its reference count
+ *
+ * This assumes this SharedPtr is NULL and that ptr is not a 'zombie.' No
+ * checks are performed.
+ *
+ * @param ptr Naked pointer to assign
+ */
+ inline void setToUnsafe(T *ptr)
+ {
+ ++ptr->__refCount;
+ _ptr = ptr;
+ }
+
+ /**
+ * Swap with another pointer 'for free' without ref count overhead
+ *
+ * @param with Pointer to swap with
+ */
+ inline void swap(SharedPtr &with)
+ throw()
+ {
+ T *tmp = _ptr;
+ _ptr = with._ptr;
+ with._ptr = tmp;
+ }
+
+ inline operator bool() const throw() { return (_ptr != (T *)0); }
+ inline T &operator*() const throw() { return *_ptr; }
+ inline T *operator->() const throw() { return _ptr; }
+
+ /**
+ * @return Raw pointer to held object
+ */
+ inline T *ptr() const throw() { return _ptr; }
+
+ /**
+ * Set this pointer to null
+ */
+ inline void zero()
+ {
+ if (_ptr) {
+ if (--_ptr->__refCount <= 0)
+ delete _ptr;
+ }
+ _ptr = (T *)0;
+ }
+
+ inline bool operator==(const SharedPtr &sp) const throw() { return (_ptr == sp._ptr); }
+ inline bool operator!=(const SharedPtr &sp) const throw() { return (_ptr != sp._ptr); }
+ inline bool operator>(const SharedPtr &sp) const throw() { return (_ptr > sp._ptr); }
+ inline bool operator<(const SharedPtr &sp) const throw() { return (_ptr < sp._ptr); }
+ inline bool operator>=(const SharedPtr &sp) const throw() { return (_ptr >= sp._ptr); }
+ inline bool operator<=(const SharedPtr &sp) const throw() { return (_ptr <= sp._ptr); }
+
+private:
+ inline T *_getAndInc() const
+ throw()
+ {
+ if (_ptr)
+ ++_ptr->__refCount;
+ return _ptr;
+ }
+
+ T *_ptr;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Switch.cpp b/zerotierone/node/Switch.cpp
new file mode 100644
index 0000000..e7cda1b
--- /dev/null
+++ b/zerotierone/node/Switch.cpp
@@ -0,0 +1,862 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <utility>
+#include <stdexcept>
+
+#include "../version.h"
+#include "../include/ZeroTierOne.h"
+
+#include "Constants.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Switch.hpp"
+#include "Node.hpp"
+#include "InetAddress.hpp"
+#include "Topology.hpp"
+#include "Peer.hpp"
+#include "SelfAwareness.hpp"
+#include "Packet.hpp"
+#include "Cluster.hpp"
+
+namespace ZeroTier {
+
+#ifdef ZT_TRACE
+static const char *etherTypeName(const unsigned int etherType)
+{
+ switch(etherType) {
+ case ZT_ETHERTYPE_IPV4: return "IPV4";
+ case ZT_ETHERTYPE_ARP: return "ARP";
+ case ZT_ETHERTYPE_RARP: return "RARP";
+ case ZT_ETHERTYPE_ATALK: return "ATALK";
+ case ZT_ETHERTYPE_AARP: return "AARP";
+ case ZT_ETHERTYPE_IPX_A: return "IPX_A";
+ case ZT_ETHERTYPE_IPX_B: return "IPX_B";
+ case ZT_ETHERTYPE_IPV6: return "IPV6";
+ }
+ return "UNKNOWN";
+}
+#endif // ZT_TRACE
+
+Switch::Switch(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _lastBeaconResponse(0),
+ _outstandingWhoisRequests(32),
+ _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine
+{
+}
+
+Switch::~Switch()
+{
+}
+
+void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len)
+{
+ try {
+ const uint64_t now = RR->node->now();
+
+ if (len == 13) {
+ /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast
+ * announcements on the LAN to solve the 'same network problem.' We
+ * no longer send these, but we'll listen for them for a while to
+ * locate peers with versions <1.0.4. */
+
+ Address beaconAddr(reinterpret_cast<const char *>(data) + 8,5);
+ if (beaconAddr == RR->identity.address())
+ return;
+ if (!RR->node->shouldUsePathForZeroTierTraffic(localAddr,fromAddr))
+ return;
+ SharedPtr<Peer> peer(RR->topology->getPeer(beaconAddr));
+ if (peer) { // we'll only respond to beacons from known peers
+ if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
+ _lastBeaconResponse = now;
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(localAddr,fromAddr,outp.data(),outp.size());
+ }
+ }
+
+ } else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // min length check is important!
+ if (reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) {
+ // Handle fragment ----------------------------------------------------
+
+ Packet::Fragment fragment(data,len);
+ const Address destination(fragment.destination());
+
+ if (destination != RR->identity.address()) {
+ // Fragment is not for us, so try to relay it
+ if (fragment.hops() < ZT_RELAY_MAX_HOPS) {
+ fragment.incrementHops();
+
+ // Note: we don't bother initiating NAT-t for fragments, since heads will set that off.
+ // It wouldn't hurt anything, just redundant and unnecessary.
+ SharedPtr<Peer> relayTo = RR->topology->getPeer(destination);
+ if ((!relayTo)||(!relayTo->send(fragment.data(),fragment.size(),now))) {
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster) {
+ RR->cluster->sendViaCluster(Address(),destination,fragment.data(),fragment.size(),false);
+ return;
+ }
+#endif
+
+ // Don't know peer or no direct path -- so relay via root server
+ relayTo = RR->topology->getBestRoot();
+ if (relayTo)
+ relayTo->send(fragment.data(),fragment.size(),now);
+ }
+ } else {
+ TRACE("dropped relay [fragment](%s) -> %s, max hops exceeded",fromAddr.toString().c_str(),destination.toString().c_str());
+ }
+ } else {
+ // Fragment looks like ours
+ const uint64_t fragmentPacketId = fragment.packetId();
+ const unsigned int fragmentNumber = fragment.fragmentNumber();
+ const unsigned int totalFragments = fragment.totalFragments();
+
+ if ((totalFragments <= ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber < ZT_MAX_PACKET_FRAGMENTS)&&(fragmentNumber > 0)&&(totalFragments > 1)) {
+ // Fragment appears basically sane. Its fragment number must be
+ // 1 or more, since a Packet with fragmented bit set is fragment 0.
+ // Total fragments must be more than 1, otherwise why are we
+ // seeing a Packet::Fragment?
+
+ Mutex::Lock _l(_rxQueue_m);
+ RXQueueEntry *const rq = _findRXQueueEntry(now,fragmentPacketId);
+
+ if ((!rq->timestamp)||(rq->packetId != fragmentPacketId)) {
+ // No packet found, so we received a fragment without its head.
+ //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str());
+
+ rq->timestamp = now;
+ rq->packetId = fragmentPacketId;
+ rq->frags[fragmentNumber - 1] = fragment;
+ rq->totalFragments = totalFragments; // total fragment count is known
+ rq->haveFragments = 1 << fragmentNumber; // we have only this fragment
+ rq->complete = false;
+ } else if (!(rq->haveFragments & (1 << fragmentNumber))) {
+ // We have other fragments and maybe the head, so add this one and check
+ //TRACE("fragment (%u/%u) of %.16llx from %s",fragmentNumber + 1,totalFragments,fragmentPacketId,fromAddr.toString().c_str());
+
+ rq->frags[fragmentNumber - 1] = fragment;
+ rq->totalFragments = totalFragments;
+
+ if (Utils::countBits(rq->haveFragments |= (1 << fragmentNumber)) == totalFragments) {
+ // We have all fragments -- assemble and process full Packet
+ //TRACE("packet %.16llx is complete, assembling and processing...",fragmentPacketId);
+
+ for(unsigned int f=1;f<totalFragments;++f)
+ rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
+
+ if (rq->frag0.tryDecode(RR,false)) {
+ rq->timestamp = 0; // packet decoded, free entry
+ } else {
+ rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something
+ }
+ }
+ } // else this is a duplicate fragment, ignore
+ }
+ }
+
+ // --------------------------------------------------------------------
+ } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important!
+ // Handle packet head -------------------------------------------------
+
+ // See packet format in Packet.hpp to understand this
+ const uint64_t packetId = (
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[0]) << 56) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[1]) << 48) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[2]) << 40) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[3]) << 32) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[4]) << 24) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[5]) << 16) |
+ (((uint64_t)reinterpret_cast<const uint8_t *>(data)[6]) << 8) |
+ ((uint64_t)reinterpret_cast<const uint8_t *>(data)[7])
+ );
+ const Address destination(reinterpret_cast<const uint8_t *>(data) + 8,ZT_ADDRESS_LENGTH);
+ const Address source(reinterpret_cast<const uint8_t *>(data) + 13,ZT_ADDRESS_LENGTH);
+
+ // Catch this and toss it -- it would never work, but it could happen if we somehow
+ // mistakenly guessed an address we're bound to as a destination for another peer.
+ if (source == RR->identity.address())
+ return;
+
+ //TRACE("<< %.16llx %s -> %s (size: %u)",(unsigned long long)packet->packetId(),source.toString().c_str(),destination.toString().c_str(),packet->size());
+
+ if (destination != RR->identity.address()) {
+ Packet packet(data,len);
+
+ // Packet is not for us, so try to relay it
+ if (packet.hops() < ZT_RELAY_MAX_HOPS) {
+ packet.incrementHops();
+
+ SharedPtr<Peer> relayTo = RR->topology->getPeer(destination);
+ if ((relayTo)&&((relayTo->send(packet.data(),packet.size(),now)))) {
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
+ if ((now - luts) >= ZT_MIN_UNITE_INTERVAL) {
+ luts = now;
+ unite(source,destination);
+ }
+ } else {
+#ifdef ZT_ENABLE_CLUSTER
+ if (RR->cluster) {
+ bool shouldUnite;
+ {
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ uint64_t &luts = _lastUniteAttempt[_LastUniteKey(source,destination)];
+ shouldUnite = ((now - luts) >= ZT_MIN_UNITE_INTERVAL);
+ if (shouldUnite)
+ luts = now;
+ }
+ RR->cluster->sendViaCluster(source,destination,packet.data(),packet.size(),shouldUnite);
+ return;
+ }
+#endif
+ relayTo = RR->topology->getBestRoot(&source,1,true);
+ if (relayTo)
+ relayTo->send(packet.data(),packet.size(),now);
+ }
+ } else {
+ TRACE("dropped relay %s(%s) -> %s, max hops exceeded",packet.source().toString().c_str(),fromAddr.toString().c_str(),destination.toString().c_str());
+ }
+ } else if ((reinterpret_cast<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
+ // Packet is the head of a fragmented packet series
+
+ Mutex::Lock _l(_rxQueue_m);
+ RXQueueEntry *const rq = _findRXQueueEntry(now,packetId);
+
+ if ((!rq->timestamp)||(rq->packetId != packetId)) {
+ // If we have no other fragments yet, create an entry and save the head
+ //TRACE("fragment (0/?) of %.16llx from %s",pid,fromAddr.toString().c_str());
+
+ rq->timestamp = now;
+ rq->packetId = packetId;
+ rq->frag0.init(data,len,localAddr,fromAddr,now);
+ rq->totalFragments = 0;
+ rq->haveFragments = 1;
+ rq->complete = false;
+ } else if (!(rq->haveFragments & 1)) {
+ // If we have other fragments but no head, see if we are complete with the head
+
+ if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) {
+ // We have all fragments -- assemble and process full Packet
+ //TRACE("packet %.16llx is complete, assembling and processing...",pid);
+
+ rq->frag0.init(data,len,localAddr,fromAddr,now);
+ for(unsigned int f=1;f<rq->totalFragments;++f)
+ rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength());
+
+ if (rq->frag0.tryDecode(RR,false)) {
+ rq->timestamp = 0; // packet decoded, free entry
+ } else {
+ rq->complete = true; // set complete flag but leave entry since it probably needs WHOIS or something
+ }
+ } else {
+ // Still waiting on more fragments, but keep the head
+ rq->frag0.init(data,len,localAddr,fromAddr,now);
+ }
+ } // else this is a duplicate head, ignore
+ } else {
+ // Packet is unfragmented, so just process it
+ IncomingPacket packet(data,len,localAddr,fromAddr,now);
+ if (!packet.tryDecode(RR,false)) {
+ Mutex::Lock _l(_rxQueue_m);
+ RXQueueEntry *rq = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]);
+ unsigned long i = ZT_RX_QUEUE_SIZE - 1;
+ while ((i)&&(rq->timestamp)) {
+ RXQueueEntry *tmp = &(_rxQueue[--i]);
+ if (tmp->timestamp < rq->timestamp)
+ rq = tmp;
+ }
+ rq->timestamp = now;
+ rq->packetId = packetId;
+ rq->frag0 = packet;
+ rq->totalFragments = 1;
+ rq->haveFragments = 1;
+ rq->complete = true;
+ }
+ }
+
+ // --------------------------------------------------------------------
+ }
+ }
+ } catch (std::exception &ex) {
+ TRACE("dropped packet from %s: unexpected exception: %s",fromAddr.toString().c_str(),ex.what());
+ } catch ( ... ) {
+ TRACE("dropped packet from %s: unexpected exception: (unknown)",fromAddr.toString().c_str());
+ }
+}
+
+void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
+{
+ if (!network->hasConfig())
+ return;
+
+ // Sanity check -- bridge loop? OS problem?
+ if (to == network->mac())
+ return;
+
+ // Check to make sure this protocol is allowed on this network
+ if (!network->config().permitsEtherType(etherType)) {
+ TRACE("%.16llx: ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),(unsigned long long)network->id());
+ return;
+ }
+
+ // Check if this packet is from someone other than the tap -- i.e. bridged in
+ bool fromBridged = false;
+ if (from != network->mac()) {
+ if (!network->config().permitsBridging(RR->identity.address())) {
+ TRACE("%.16llx: %s -> %s %s not forwarded, bridging disabled or this peer not a bridge",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
+ return;
+ }
+ fromBridged = true;
+ }
+
+ if (to.isMulticast()) {
+ // Destination is a multicast address (including broadcast)
+ MulticastGroup mg(to,0);
+
+ if (to.isBroadcast()) {
+ if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) {
+ /* IPv4 ARP is one of the few special cases that we impose upon what is
+ * otherwise a straightforward Ethernet switch emulation. Vanilla ARP
+ * is dumb old broadcast and simply doesn't scale. ZeroTier multicast
+ * groups have an additional field called ADI (additional distinguishing
+ * information) which was added specifically for ARP though it could
+ * be used for other things too. We then take ARP broadcasts and turn
+ * them into multicasts by stuffing the IP address being queried into
+ * the 32-bit ADI field. In practice this uses our multicast pub/sub
+ * system to implement a kind of extended/distributed ARP table. */
+ mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0));
+ } else if (!network->config().enableBroadcast()) {
+ // Don't transmit broadcasts if this network doesn't want them
+ TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id());
+ return;
+ }
+ } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) {
+ /* IPv6 NDP emulation on ZeroTier-RFC4193 addressed networks! This allows
+ * for multicast-free operation in IPv6 networks, which both improves
+ * performance and is friendlier to mobile and (especially) IoT devices.
+ * In the future there may be a no-multicast build option for embedded
+ * and IoT use and this will be the preferred addressing mode. Note that
+ * it plays nice with our L2 emulation philosophy and even with bridging.
+ * While "real" devices behind the bridge can't have ZT-RFC4193 addresses
+ * themselves, they can look these addresses up with NDP and it will
+ * work just fine. */
+ if ((reinterpret_cast<const uint8_t *>(data)[6] == 0x3a)&&(reinterpret_cast<const uint8_t *>(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation
+ for(unsigned int sipk=0;sipk<network->config().staticIpCount;++sipk) {
+ const InetAddress *sip = &(network->config().staticIps[sipk]);
+ if ((sip->ss_family == AF_INET6)&&(Utils::ntoh((uint16_t)reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_port) == 88)) {
+ const uint8_t *my6 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_addr.s6_addr);
+ if ((my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 == fd__:____:____:____:__99:93__:____:____ / 88
+ const uint8_t *pkt6 = reinterpret_cast<const uint8_t *>(data) + 40 + 8;
+ unsigned int ptr = 0;
+ while (ptr != 11) {
+ if (pkt6[ptr] != my6[ptr])
+ break;
+ ++ptr;
+ }
+ if (ptr == 11) { // /88 matches an assigned address on this network
+ const Address atPeer(pkt6 + ptr,5);
+ if (atPeer != RR->identity.address()) {
+ const MAC atPeerMac(atPeer,network->id());
+ TRACE("ZT-RFC4193 NDP emulation: %.16llx: forging response for %s/%s",network->id(),atPeer.toString().c_str(),atPeerMac.toString().c_str());
+
+ uint8_t adv[72];
+ adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00;
+ adv[4] = 0x00; adv[5] = 0x20;
+ adv[6] = 0x3a; adv[7] = 0xff;
+ for(int i=0;i<16;++i) adv[8 + i] = pkt6[i];
+ for(int i=0;i<16;++i) adv[24 + i] = my6[i];
+ adv[40] = 0x88; adv[41] = 0x00;
+ adv[42] = 0x00; adv[43] = 0x00; // future home of checksum
+ adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00;
+ for(int i=0;i<16;++i) adv[48 + i] = pkt6[i];
+ adv[64] = 0x02; adv[65] = 0x01;
+ adv[66] = atPeerMac[0]; adv[67] = atPeerMac[1]; adv[68] = atPeerMac[2]; adv[69] = atPeerMac[3]; adv[70] = atPeerMac[4]; adv[71] = atPeerMac[5];
+
+ uint16_t pseudo_[36];
+ uint8_t *const pseudo = reinterpret_cast<uint8_t *>(pseudo_);
+ for(int i=0;i<32;++i) pseudo[i] = adv[8 + i];
+ pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20;
+ pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a;
+ for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i];
+ uint32_t checksum = 0;
+ for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]);
+ while ((checksum >> 16)) checksum = (checksum & 0xffff) + (checksum >> 16);
+ checksum = ~checksum;
+ adv[42] = (checksum >> 8) & 0xff;
+ adv[43] = checksum & 0xff;
+
+ RR->node->putFrame(network->id(),network->userPtr(),atPeerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72);
+ return; // stop processing: we have handled this frame with a spoofed local reply so no need to send it anywhere
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Learn multicast groups for bridged-in hosts.
+ * Note that some OSes, most notably Linux, do this for you by learning
+ * multicast addresses on bridge interfaces and subscribing each slave.
+ * But in that case this does no harm, as the sets are just merged. */
+ if (fromBridged)
+ network->learnBridgedMulticastGroup(mg,RR->node->now());
+
+ //TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len);
+
+ RR->mc->send(
+ ((!network->config().isPublic())&&(network->config().com)) ? &(network->config().com) : (const CertificateOfMembership *)0,
+ network->config().multicastLimit,
+ RR->node->now(),
+ network->id(),
+ network->config().activeBridges(),
+ mg,
+ (fromBridged) ? from : MAC(),
+ etherType,
+ data,
+ len);
+
+ return;
+ }
+
+ if (to[0] == MAC::firstOctetForNetwork(network->id())) {
+ // Destination is another ZeroTier peer on the same network
+
+ Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
+ SharedPtr<Peer> toPeer(RR->topology->getPeer(toZT));
+ const bool includeCom = ( (network->config().isPrivate()) && (network->config().com) && ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) );
+ if ((fromBridged)||(includeCom)) {
+ Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME);
+ outp.append(network->id());
+ if (includeCom) {
+ outp.append((unsigned char)0x01); // 0x01 -- COM included
+ network->config().com.serialize(outp);
+ } else {
+ outp.append((unsigned char)0x00);
+ }
+ to.appendTo(outp);
+ from.appendTo(outp);
+ outp.append((uint16_t)etherType);
+ outp.append(data,len);
+ outp.compress();
+ send(outp,true,network->id());
+ } else {
+ Packet outp(toZT,RR->identity.address(),Packet::VERB_FRAME);
+ outp.append(network->id());
+ outp.append((uint16_t)etherType);
+ outp.append(data,len);
+ outp.compress();
+ send(outp,true,network->id());
+ }
+
+ //TRACE("%.16llx: UNICAST: %s -> %s etherType==%s(%.4x) vlanId==%u len==%u fromBridged==%d includeCom==%d",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),etherType,vlanId,len,(int)fromBridged,(int)includeCom);
+
+ return;
+ }
+
+ {
+ // Destination is bridged behind a remote peer
+
+ Address bridges[ZT_MAX_BRIDGE_SPAM];
+ unsigned int numBridges = 0;
+
+ /* Create an array of up to ZT_MAX_BRIDGE_SPAM recipients for this bridged frame. */
+ bridges[0] = network->findBridgeTo(to);
+ std::vector<Address> activeBridges(network->config().activeBridges());
+ if ((bridges[0])&&(bridges[0] != RR->identity.address())&&(network->config().permitsBridging(bridges[0]))) {
+ /* We have a known bridge route for this MAC, send it there. */
+ ++numBridges;
+ } else if (!activeBridges.empty()) {
+ /* If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active
+ * bridges. If someone responds, we'll learn the route. */
+ std::vector<Address>::const_iterator ab(activeBridges.begin());
+ if (activeBridges.size() <= ZT_MAX_BRIDGE_SPAM) {
+ // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all
+ while (ab != activeBridges.end()) {
+ bridges[numBridges++] = *ab;
+ ++ab;
+ }
+ } else {
+ // Otherwise pick a random set of them
+ while (numBridges < ZT_MAX_BRIDGE_SPAM) {
+ if (ab == activeBridges.end())
+ ab = activeBridges.begin();
+ if (((unsigned long)RR->node->prng() % (unsigned long)activeBridges.size()) == 0) {
+ bridges[numBridges++] = *ab;
+ ++ab;
+ } else ++ab;
+ }
+ }
+ }
+
+ for(unsigned int b=0;b<numBridges;++b) {
+ SharedPtr<Peer> bridgePeer(RR->topology->getPeer(bridges[b]));
+ Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME);
+ outp.append(network->id());
+ if ( (network->config().isPrivate()) && (network->config().com) && ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ) {
+ outp.append((unsigned char)0x01); // 0x01 -- COM included
+ network->config().com.serialize(outp);
+ } else {
+ outp.append((unsigned char)0);
+ }
+ to.appendTo(outp);
+ from.appendTo(outp);
+ outp.append((uint16_t)etherType);
+ outp.append(data,len);
+ outp.compress();
+ send(outp,true,network->id());
+ }
+ }
+}
+
+void Switch::send(const Packet &packet,bool encrypt,uint64_t nwid)
+{
+ if (packet.destination() == RR->identity.address()) {
+ TRACE("BUG: caught attempt to send() to self, ignored");
+ return;
+ }
+
+ //TRACE(">> %s to %s (%u bytes, encrypt==%d, nwid==%.16llx)",Packet::verbString(packet.verb()),packet.destination().toString().c_str(),packet.size(),(int)encrypt,nwid);
+
+ if (!_trySend(packet,encrypt,nwid)) {
+ Mutex::Lock _l(_txQueue_m);
+ _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt,nwid));
+ }
+}
+
+bool Switch::unite(const Address &p1,const Address &p2)
+{
+ if ((p1 == RR->identity.address())||(p2 == RR->identity.address()))
+ return false;
+ SharedPtr<Peer> p1p = RR->topology->getPeer(p1);
+ if (!p1p)
+ return false;
+ SharedPtr<Peer> p2p = RR->topology->getPeer(p2);
+ if (!p2p)
+ return false;
+
+ const uint64_t now = RR->node->now();
+
+ std::pair<InetAddress,InetAddress> cg(Peer::findCommonGround(*p1p,*p2p,now));
+ if ((!(cg.first))||(cg.first.ipScope() != cg.second.ipScope()))
+ return false;
+
+ TRACE("unite: %s(%s) <> %s(%s)",p1.toString().c_str(),cg.second.toString().c_str(),p2.toString().c_str(),cg.first.toString().c_str());
+
+ /* Tell P1 where to find P2 and vice versa, sending the packets to P1 and
+ * P2 in randomized order in terms of which gets sent first. This is done
+ * since in a few cases NAT-t can be sensitive to slight timing differences
+ * in terms of when the two peers initiate. Normally this is accounted for
+ * by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but
+ * given that relay are hosted on cloud providers this can in some
+ * cases have a few ms of latency between packet departures. By randomizing
+ * the order we make each attempted NAT-t favor one or the other going
+ * first, meaning if it doesn't succeed the first time it might the second
+ * and so forth. */
+ unsigned int alt = (unsigned int)RR->node->prng() & 1;
+ unsigned int completed = alt + 2;
+ while (alt != completed) {
+ if ((alt & 1) == 0) {
+ // Tell p1 where to find p2.
+ Packet outp(p1,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
+ p2.appendTo(outp);
+ outp.append((uint16_t)cg.first.port());
+ if (cg.first.isV6()) {
+ outp.append((unsigned char)16);
+ outp.append(cg.first.rawIpData(),16);
+ } else {
+ outp.append((unsigned char)4);
+ outp.append(cg.first.rawIpData(),4);
+ }
+ outp.armor(p1p->key(),true);
+ p1p->send(outp.data(),outp.size(),now);
+ } else {
+ // Tell p2 where to find p1.
+ Packet outp(p2,RR->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
+ p1.appendTo(outp);
+ outp.append((uint16_t)cg.second.port());
+ if (cg.second.isV6()) {
+ outp.append((unsigned char)16);
+ outp.append(cg.second.rawIpData(),16);
+ } else {
+ outp.append((unsigned char)4);
+ outp.append(cg.second.rawIpData(),4);
+ }
+ outp.armor(p2p->key(),true);
+ p2p->send(outp.data(),outp.size(),now);
+ }
+ ++alt; // counts up and also flips LSB
+ }
+
+ return true;
+}
+
+void Switch::rendezvous(const SharedPtr<Peer> &peer,const InetAddress &localAddr,const InetAddress &atAddr)
+{
+ TRACE("sending NAT-t message to %s(%s)",peer->address().toString().c_str(),atAddr.toString().c_str());
+ const uint64_t now = RR->node->now();
+ peer->sendHELLO(localAddr,atAddr,now,2); // first attempt: send low-TTL packet to 'open' local NAT
+ {
+ Mutex::Lock _l(_contactQueue_m);
+ _contactQueue.push_back(ContactQueueEntry(peer,now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY,localAddr,atAddr));
+ }
+}
+
+void Switch::requestWhois(const Address &addr)
+{
+ bool inserted = false;
+ {
+ Mutex::Lock _l(_outstandingWhoisRequests_m);
+ WhoisRequest &r = _outstandingWhoisRequests[addr];
+ if (r.lastSent) {
+ r.retries = 0; // reset retry count if entry already existed, but keep waiting and retry again after normal timeout
+ } else {
+ r.lastSent = RR->node->now();
+ inserted = true;
+ }
+ }
+ if (inserted)
+ _sendWhoisRequest(addr,(const Address *)0,0);
+}
+
+void Switch::doAnythingWaitingForPeer(const SharedPtr<Peer> &peer)
+{
+ { // cancel pending WHOIS since we now know this peer
+ Mutex::Lock _l(_outstandingWhoisRequests_m);
+ _outstandingWhoisRequests.erase(peer->address());
+ }
+
+ { // finish processing any packets waiting on peer's public key / identity
+ Mutex::Lock _l(_rxQueue_m);
+ unsigned long i = ZT_RX_QUEUE_SIZE;
+ while (i) {
+ RXQueueEntry *rq = &(_rxQueue[--i]);
+ if ((rq->timestamp)&&(rq->complete)) {
+ if (rq->frag0.tryDecode(RR,false))
+ rq->timestamp = 0;
+ }
+ }
+ }
+
+ { // finish sending any packets waiting on peer's public key / identity
+ Mutex::Lock _l(_txQueue_m);
+ for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) {
+ if (txi->dest == peer->address()) {
+ if (_trySend(txi->packet,txi->encrypt,txi->nwid))
+ _txQueue.erase(txi++);
+ else ++txi;
+ } else ++txi;
+ }
+ }
+}
+
+unsigned long Switch::doTimerTasks(uint64_t now)
+{
+ unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum
+
+ { // Iterate through NAT traversal strategies for entries in contact queue
+ Mutex::Lock _l(_contactQueue_m);
+ for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) {
+ if (now >= qi->fireAtTime) {
+ if (!qi->peer->pushDirectPaths(qi->localAddr,qi->inaddr,now,true,false))
+ qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now);
+ _contactQueue.erase(qi++);
+ continue;
+ /* Old symmetric NAT buster code, obsoleted by port prediction alg in SelfAwareness but left around for now in case we revert
+ if (qi->strategyIteration == 0) {
+ // First strategy: send packet directly to destination
+ qi->peer->sendHELLO(qi->localAddr,qi->inaddr,now);
+ } else if (qi->strategyIteration <= 3) {
+ // Strategies 1-3: try escalating ports for symmetric NATs that remap sequentially
+ InetAddress tmpaddr(qi->inaddr);
+ int p = (int)qi->inaddr.port() + qi->strategyIteration;
+ if (p > 65535)
+ p -= 64511;
+ tmpaddr.setPort((unsigned int)p);
+ qi->peer->sendHELLO(qi->localAddr,tmpaddr,now);
+ } else {
+ // All strategies tried, expire entry
+ _contactQueue.erase(qi++);
+ continue;
+ }
+ ++qi->strategyIteration;
+ qi->fireAtTime = now + ZT_NAT_T_TACTICAL_ESCALATION_DELAY;
+ nextDelay = std::min(nextDelay,(unsigned long)ZT_NAT_T_TACTICAL_ESCALATION_DELAY);
+ */
+ } else {
+ nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now));
+ }
+ ++qi; // if qi was erased, loop will have continued before here
+ }
+ }
+
+ { // Retry outstanding WHOIS requests
+ Mutex::Lock _l(_outstandingWhoisRequests_m);
+ Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests);
+ Address *a = (Address *)0;
+ WhoisRequest *r = (WhoisRequest *)0;
+ while (i.next(a,r)) {
+ const unsigned long since = (unsigned long)(now - r->lastSent);
+ if (since >= ZT_WHOIS_RETRY_DELAY) {
+ if (r->retries >= ZT_MAX_WHOIS_RETRIES) {
+ TRACE("WHOIS %s timed out",a->toString().c_str());
+ _outstandingWhoisRequests.erase(*a);
+ } else {
+ r->lastSent = now;
+ r->peersConsulted[r->retries] = _sendWhoisRequest(*a,r->peersConsulted,r->retries);
+ ++r->retries;
+ TRACE("WHOIS %s (retry %u)",a->toString().c_str(),r->retries);
+ nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY);
+ }
+ } else {
+ nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since);
+ }
+ }
+ }
+
+ { // Time out TX queue packets that never got WHOIS lookups or other info.
+ Mutex::Lock _l(_txQueue_m);
+ for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) {
+ if (_trySend(txi->packet,txi->encrypt,txi->nwid))
+ _txQueue.erase(txi++);
+ else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) {
+ TRACE("TX %s -> %s timed out",txi->packet.source().toString().c_str(),txi->packet.destination().toString().c_str());
+ _txQueue.erase(txi++);
+ } else ++txi;
+ }
+ }
+
+ { // Remove really old last unite attempt entries to keep table size controlled
+ Mutex::Lock _l(_lastUniteAttempt_m);
+ Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt);
+ _LastUniteKey *k = (_LastUniteKey *)0;
+ uint64_t *v = (uint64_t *)0;
+ while (i.next(k,v)) {
+ if ((now - *v) >= (ZT_MIN_UNITE_INTERVAL * 8))
+ _lastUniteAttempt.erase(*k);
+ }
+ }
+
+ return nextDelay;
+}
+
+Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted)
+{
+ SharedPtr<Peer> root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
+ if (root) {
+ Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS);
+ addr.appendTo(outp);
+ outp.armor(root->key(),true);
+ if (root->send(outp.data(),outp.size(),RR->node->now()))
+ return root->address();
+ }
+ return Address();
+}
+
+bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
+{
+ SharedPtr<Peer> peer(RR->topology->getPeer(packet.destination()));
+
+ if (peer) {
+ const uint64_t now = RR->node->now();
+
+ SharedPtr<Network> network;
+ if (nwid) {
+ network = RR->node->network(nwid);
+ if ((!network)||(!network->hasConfig()))
+ return false; // we probably just left this network, let its packets die
+ }
+
+ Path *viaPath = peer->getBestPath(now);
+ SharedPtr<Peer> relay;
+
+ if (!viaPath) {
+ if (network) {
+ unsigned int bestq = ~((unsigned int)0); // max unsigned int since quality is lower==better
+ unsigned int ptr = 0;
+ for(;;) {
+ const Address raddr(network->config().nextRelay(ptr));
+ if (raddr) {
+ SharedPtr<Peer> rp(RR->topology->getPeer(raddr));
+ if (rp) {
+ const unsigned int q = rp->relayQuality(now);
+ if (q < bestq) {
+ bestq = q;
+ rp.swap(relay);
+ }
+ }
+ } else break;
+ }
+ }
+
+ if (!relay)
+ relay = RR->topology->getBestRoot();
+
+ if ( (!relay) || (!(viaPath = relay->getBestPath(now))) )
+ return false;
+ }
+ // viaPath will not be null if we make it here
+
+ // Push possible direct paths to us if we are relaying
+ if (relay) {
+ peer->pushDirectPaths(viaPath->localAddress(),viaPath->address(),now,false,( (network)&&(network->isAllowed(peer)) ));
+ viaPath->sent(now);
+ }
+
+ Packet tmp(packet);
+
+ unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU);
+ tmp.setFragmented(chunkSize < tmp.size());
+
+ tmp.armor(peer->key(),encrypt);
+
+ if (viaPath->send(RR,tmp.data(),chunkSize,now)) {
+ if (chunkSize < tmp.size()) {
+ // Too big for one packet, fragment the rest
+ unsigned int fragStart = chunkSize;
+ unsigned int remaining = tmp.size() - chunkSize;
+ unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
+ if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining)
+ ++fragsRemaining;
+ unsigned int totalFragments = fragsRemaining + 1;
+
+ for(unsigned int fno=1;fno<totalFragments;++fno) {
+ chunkSize = std::min(remaining,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH));
+ Packet::Fragment frag(tmp,fragStart,chunkSize,fno,totalFragments);
+ viaPath->send(RR,frag.data(),frag.size(),now);
+ fragStart += chunkSize;
+ remaining -= chunkSize;
+ }
+ }
+
+ return true;
+ }
+ } else {
+ requestWhois(packet.destination());
+ }
+ return false;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Switch.hpp b/zerotierone/node/Switch.hpp
new file mode 100644
index 0000000..ce4f00a
--- /dev/null
+++ b/zerotierone/node/Switch.hpp
@@ -0,0 +1,268 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_N_SWITCH_HPP
+#define ZT_N_SWITCH_HPP
+
+#include <map>
+#include <set>
+#include <vector>
+#include <list>
+
+#include "Constants.hpp"
+#include "Mutex.hpp"
+#include "MAC.hpp"
+#include "NonCopyable.hpp"
+#include "Packet.hpp"
+#include "Utils.hpp"
+#include "InetAddress.hpp"
+#include "Topology.hpp"
+#include "Array.hpp"
+#include "Network.hpp"
+#include "SharedPtr.hpp"
+#include "IncomingPacket.hpp"
+#include "Hashtable.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+class Peer;
+
+/**
+ * Core of the distributed Ethernet switch and protocol implementation
+ *
+ * This class is perhaps a bit misnamed, but it's basically where everything
+ * meets. Transport-layer ZT packets come in here, as do virtual network
+ * packets from tap devices, and this sends them where they need to go and
+ * wraps/unwraps accordingly. It also handles queues and timeouts and such.
+ */
+class Switch : NonCopyable
+{
+public:
+ Switch(const RuntimeEnvironment *renv);
+ ~Switch();
+
+ /**
+ * Called when a packet is received from the real network
+ *
+ * @param localAddr Local interface address
+ * @param fromAddr Internet IP address of origin
+ * @param data Packet data
+ * @param len Packet length
+ */
+ void onRemotePacket(const InetAddress &localAddr,const InetAddress &fromAddr,const void *data,unsigned int len);
+
+ /**
+ * Called when a packet comes from a local Ethernet tap
+ *
+ * @param network Which network's TAP did this packet come from?
+ * @param from Originating MAC address
+ * @param to Destination MAC address
+ * @param etherType Ethernet packet type
+ * @param vlanId VLAN ID or 0 if none
+ * @param data Ethernet payload
+ * @param len Frame length
+ */
+ void onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
+
+ /**
+ * Send a packet to a ZeroTier address (destination in packet)
+ *
+ * The packet must be fully composed with source and destination but not
+ * yet encrypted. If the destination peer is known the packet
+ * is sent immediately. Otherwise it is queued and a WHOIS is dispatched.
+ *
+ * The packet may be compressed. Compression isn't done here.
+ *
+ * Needless to say, the packet's source must be this node. Otherwise it
+ * won't be encrypted right. (This is not used for relaying.)
+ *
+ * The network ID should only be specified for frames and other actual
+ * network traffic. Other traffic such as controller requests and regular
+ * protocol messages should specify zero.
+ *
+ * @param packet Packet to send
+ * @param encrypt Encrypt packet payload? (always true except for HELLO)
+ * @param nwid Related network ID or 0 if message is not in-network traffic
+ */
+ void send(const Packet &packet,bool encrypt,uint64_t nwid);
+
+ /**
+ * Send RENDEZVOUS to two peers to permit them to directly connect
+ *
+ * This only works if both peers are known, with known working direct
+ * links to this peer. The best link for each peer is sent to the other.
+ *
+ * @param p1 One of two peers (order doesn't matter)
+ * @param p2 Second of pair
+ */
+ bool unite(const Address &p1,const Address &p2);
+
+ /**
+ * Attempt NAT traversal to peer at a given physical address
+ *
+ * @param peer Peer to contact
+ * @param localAddr Local interface address
+ * @param atAddr Address of peer
+ */
+ void rendezvous(const SharedPtr<Peer> &peer,const InetAddress &localAddr,const InetAddress &atAddr);
+
+ /**
+ * Request WHOIS on a given address
+ *
+ * @param addr Address to look up
+ */
+ void requestWhois(const Address &addr);
+
+ /**
+ * Run any processes that are waiting for this peer's identity
+ *
+ * Called when we learn of a peer's identity from HELLO, OK(WHOIS), etc.
+ *
+ * @param peer New peer
+ */
+ void doAnythingWaitingForPeer(const SharedPtr<Peer> &peer);
+
+ /**
+ * Perform retries and other periodic timer tasks
+ *
+ * This can return a very long delay if there are no pending timer
+ * tasks. The caller should cap this comparatively vs. other values.
+ *
+ * @param now Current time
+ * @return Number of milliseconds until doTimerTasks() should be run again
+ */
+ unsigned long doTimerTasks(uint64_t now);
+
+private:
+ Address _sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted);
+ bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid);
+
+ const RuntimeEnvironment *const RR;
+ uint64_t _lastBeaconResponse;
+
+ // Outstanding WHOIS requests and how many retries they've undergone
+ struct WhoisRequest
+ {
+ WhoisRequest() : lastSent(0),retries(0) {}
+ uint64_t lastSent;
+ Address peersConsulted[ZT_MAX_WHOIS_RETRIES]; // by retry
+ unsigned int retries; // 0..ZT_MAX_WHOIS_RETRIES
+ };
+ Hashtable< Address,WhoisRequest > _outstandingWhoisRequests;
+ Mutex _outstandingWhoisRequests_m;
+
+ // Packets waiting for WHOIS replies or other decode info or missing fragments
+ struct RXQueueEntry
+ {
+ RXQueueEntry() : timestamp(0) {}
+ uint64_t timestamp; // 0 if entry is not in use
+ uint64_t packetId;
+ IncomingPacket frag0; // head of packet
+ Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any)
+ unsigned int totalFragments; // 0 if only frag0 received, waiting for frags
+ uint32_t haveFragments; // bit mask, LSB to MSB
+ bool complete; // if true, packet is complete
+ };
+ RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE];
+ Mutex _rxQueue_m;
+
+ /* Returns the matching or oldest entry. Caller must check timestamp and
+ * packet ID to determine which. */
+ inline RXQueueEntry *_findRXQueueEntry(uint64_t now,uint64_t packetId)
+ {
+ RXQueueEntry *rq;
+ RXQueueEntry *oldest = &(_rxQueue[ZT_RX_QUEUE_SIZE - 1]);
+ unsigned long i = ZT_RX_QUEUE_SIZE;
+ while (i) {
+ rq = &(_rxQueue[--i]);
+ if ((rq->packetId == packetId)&&(rq->timestamp))
+ return rq;
+ if ((now - rq->timestamp) >= ZT_RX_QUEUE_EXPIRE)
+ rq->timestamp = 0;
+ if (rq->timestamp < oldest->timestamp)
+ oldest = rq;
+ }
+ return oldest;
+ }
+
+ // ZeroTier-layer TX queue entry
+ struct TXQueueEntry
+ {
+ TXQueueEntry() {}
+ TXQueueEntry(Address d,uint64_t ct,const Packet &p,bool enc,uint64_t nw) :
+ dest(d),
+ creationTime(ct),
+ nwid(nw),
+ packet(p),
+ encrypt(enc) {}
+
+ Address dest;
+ uint64_t creationTime;
+ uint64_t nwid;
+ Packet packet; // unencrypted/unMAC'd packet -- this is done at send time
+ bool encrypt;
+ };
+ std::list< TXQueueEntry > _txQueue;
+ Mutex _txQueue_m;
+
+ // Tracks sending of VERB_RENDEZVOUS to relaying peers
+ struct _LastUniteKey
+ {
+ _LastUniteKey() : x(0),y(0) {}
+ _LastUniteKey(const Address &a1,const Address &a2)
+ {
+ if (a1 > a2) {
+ x = a2.toInt();
+ y = a1.toInt();
+ } else {
+ x = a1.toInt();
+ y = a2.toInt();
+ }
+ }
+ inline unsigned long hashCode() const throw() { return ((unsigned long)x ^ (unsigned long)y); }
+ inline bool operator==(const _LastUniteKey &k) const throw() { return ((x == k.x)&&(y == k.y)); }
+ uint64_t x,y;
+ };
+ Hashtable< _LastUniteKey,uint64_t > _lastUniteAttempt; // key is always sorted in ascending order, for set-like behavior
+ Mutex _lastUniteAttempt_m;
+
+ // Active attempts to contact remote peers, including state of multi-phase NAT traversal
+ struct ContactQueueEntry
+ {
+ ContactQueueEntry() {}
+ ContactQueueEntry(const SharedPtr<Peer> &p,uint64_t ft,const InetAddress &laddr,const InetAddress &a) :
+ peer(p),
+ fireAtTime(ft),
+ inaddr(a),
+ localAddr(laddr),
+ strategyIteration(0) {}
+
+ SharedPtr<Peer> peer;
+ uint64_t fireAtTime;
+ InetAddress inaddr;
+ InetAddress localAddr;
+ unsigned int strategyIteration;
+ };
+ std::list<ContactQueueEntry> _contactQueue;
+ Mutex _contactQueue_m;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Topology.cpp b/zerotierone/node/Topology.cpp
new file mode 100644
index 0000000..4105eae
--- /dev/null
+++ b/zerotierone/node/Topology.cpp
@@ -0,0 +1,363 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Constants.hpp"
+#include "Topology.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Node.hpp"
+#include "Network.hpp"
+#include "NetworkConfig.hpp"
+#include "Buffer.hpp"
+
+namespace ZeroTier {
+
+// 2015-11-16 -- The Fabulous Four (should have named them after Beatles!)
+//#define ZT_DEFAULT_WORLD_LENGTH 494
+//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x11,0x70,0xb2,0xfb,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x80,0x31,0xa4,0x65,0x95,0x45,0x06,0x1c,0xfb,0xc2,0x4e,0x5d,0xe7,0x0a,0x40,0x7a,0x97,0xce,0x36,0xa2,0x3d,0x05,0xca,0x87,0xc7,0x59,0x27,0x5c,0x8b,0x0d,0x4c,0xb4,0xbb,0x26,0x2f,0x77,0x17,0x5e,0xb7,0x4d,0xb8,0xd3,0xb4,0xe9,0x23,0x5d,0xcc,0xa2,0x71,0xa8,0xdf,0xf1,0x23,0xa3,0xb2,0x66,0x74,0xea,0xe5,0xdc,0x8d,0xef,0xd3,0x0a,0xa9,0xac,0xcb,0xda,0x93,0xbd,0x6c,0xcd,0x43,0x1d,0xa7,0x98,0x6a,0xde,0x70,0xc0,0xc6,0x1c,0xaf,0xf0,0xfd,0x7f,0x8a,0xb9,0x76,0x13,0xe1,0xde,0x4f,0xf3,0xd6,0x13,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09};
+
+// 2015-11-20 -- Alice and Bob are live, and we're now IPv6 dual-stack!
+//#define ZT_DEFAULT_WORLD_LENGTH 792
+//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0x26,0x6f,0x7c,0x8a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0xe8,0x0a,0xf5,0xbc,0xf8,0x3d,0x97,0xcd,0xc3,0xf8,0xe2,0x41,0x16,0x42,0x0f,0xc7,0x76,0x8e,0x07,0xf3,0x7e,0x9e,0x7d,0x1b,0xb3,0x23,0x21,0x79,0xce,0xb9,0xd0,0xcb,0xb5,0x94,0x7b,0x89,0x21,0x57,0x72,0xf6,0x70,0xa1,0xdd,0x67,0x38,0xcf,0x45,0x45,0xc2,0x8d,0x46,0xec,0x00,0x2c,0xe0,0x2a,0x63,0x3f,0x63,0x8d,0x33,0x08,0x51,0x07,0x77,0x81,0x5b,0x32,0x49,0xae,0x87,0x89,0xcf,0x31,0xaa,0x41,0xf1,0x52,0x97,0xdc,0xa2,0x55,0xe1,0x4a,0x6e,0x3c,0x04,0xf0,0x4f,0x8a,0x0e,0xe9,0xca,0xec,0x24,0x30,0x04,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09};
+
+// 2015-12-17 -- Old New York root is dead, old SF still alive
+//#define ZT_DEFAULT_WORLD_LENGTH 732
+//static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x51,0xb1,0x7e,0x39,0x9d,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x8a,0xca,0xf2,0x3d,0x71,0x2e,0xc2,0x39,0x45,0x66,0xb3,0xe9,0x39,0x79,0xb1,0x55,0xc4,0xa9,0xfc,0xbc,0xfc,0x55,0xaf,0x8a,0x2f,0x38,0xc8,0xcd,0xe9,0x02,0x5b,0x86,0xa9,0x72,0xf7,0x16,0x00,0x35,0xb7,0x84,0xc9,0xfc,0xe4,0xfa,0x96,0x8b,0xf4,0x1e,0xba,0x60,0x9f,0x85,0x14,0xc2,0x07,0x4b,0xfd,0xd1,0x6c,0x19,0x69,0xd3,0xf9,0x09,0x9c,0x9d,0xe3,0xb9,0x8f,0x11,0x78,0x71,0xa7,0x4a,0x05,0xd8,0xcc,0x60,0xa2,0x06,0x66,0x9f,0x47,0xc2,0x71,0xb8,0x54,0x80,0x9c,0x45,0x16,0x10,0xa9,0xd0,0xbd,0xf7,0x03,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x02,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0xc5,0xf0,0x01,0x27,0x09};
+
+// 2016-01-13 -- Old San Francisco 1.0.1 root is dead, now we're just on Alice and Bob!
+#define ZT_DEFAULT_WORLD_LENGTH 634
+static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x52,0x3c,0x32,0x50,0x1a,0xb8,0xb3,0x88,0xa4,0x69,0x22,0x14,0x91,0xaa,0x9a,0xcd,0x66,0xcc,0x76,0x4c,0xde,0xfd,0x56,0x03,0x9f,0x10,0x67,0xae,0x15,0xe6,0x9c,0x6f,0xb4,0x2d,0x7b,0x55,0x33,0x0e,0x3f,0xda,0xac,0x52,0x9c,0x07,0x92,0xfd,0x73,0x40,0xa6,0xaa,0x21,0xab,0xa8,0xa4,0x89,0xfd,0xae,0xa4,0x4a,0x39,0xbf,0x2d,0x00,0x65,0x9a,0xc9,0xc8,0x18,0xeb,0x4a,0xf7,0x86,0xa8,0x40,0xd6,0x52,0xea,0xae,0x9e,0x7a,0xbf,0x4c,0x97,0x66,0xab,0x2d,0x6f,0xaf,0xc9,0x2b,0x3a,0xff,0xed,0xd6,0x30,0x3e,0xc4,0x6a,0x65,0xf2,0xbd,0x83,0x52,0xf5,0x40,0xe9,0xcc,0x0d,0x6e,0x89,0x3f,0x9a,0xa0,0xb8,0xdf,0x42,0xd2,0x2f,0x84,0xe6,0x03,0x26,0x0f,0xa8,0xe3,0xcc,0x05,0x05,0x03,0xef,0x12,0x80,0x0d,0xce,0x3e,0xb6,0x58,0x3b,0x1f,0xa8,0xad,0xc7,0x25,0xf9,0x43,0x71,0xa7,0x5c,0x9a,0xc7,0xe1,0xa3,0xb8,0x88,0xd0,0x71,0x6c,0x94,0x99,0x73,0x41,0x0b,0x1b,0x48,0x84,0x02,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x0c,0x04,0xbc,0xa6,0x5e,0xb1,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x02,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x7d,0x00,0x01,0x27,0x09,0x04,0x9a,0x42,0xc5,0x21,0x27,0x09,0x06,0x2c,0x0f,0xf8,0x50,0x01,0x54,0x01,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x27,0x09,0x04,0x9f,0xcb,0x61,0xab,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,0x54,0x60,0x01,0x27,0x09,0x04,0xa9,0x39,0x8f,0x68,0x27,0x09,0x06,0x26,0x07,0xf0,0xd0,0x1d,0x01,0x00,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x27,0x09,0x04,0x6b,0xaa,0xc5,0x0e,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x00,0xe0,0x01,0x27,0x09,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09,0x06,0x24,0x00,0x61,0x80,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0xb7,0x40,0x01,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x0c,0x04,0x2d,0x20,0xc6,0x82,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x64,0x00,0x81,0xc3,0x54,0x00,0x00,0xff,0xfe,0x18,0x1d,0x61,0x27,0x09,0x04,0x2e,0x65,0xa0,0xf9,0x27,0x09,0x06,0x2a,0x03,0xb0,0xc0,0x00,0x03,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x6a,0x30,0x01,0x27,0x09,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x68,0x00,0x83,0xa4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x27,0x09,0x04,0x2d,0x20,0xf6,0xb3,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x58,0x00,0x8b,0xf8,0x54,0x00,0x00,0xff,0xfe,0x15,0xb3,0x9a,0x27,0x09,0x04,0x2d,0x20,0xf8,0x57,0x27,0x09,0x06,0x20,0x01,0x19,0xf0,0x70,0x00,0x9b,0xc9,0x54,0x00,0x00,0xff,0xfe,0x15,0xc4,0xf5,0x27,0x09,0x04,0x9f,0xcb,0x02,0x9a,0x27,0x09,0x06,0x26,0x04,0xa8,0x80,0x0c,0xad,0x00,0xd0,0x00,0x00,0x00,0x00,0x00,0x26,0x70,0x01,0x27,0x09};
+
+Topology::Topology(const RuntimeEnvironment *renv) :
+ RR(renv),
+ _amRoot(false)
+{
+ std::string alls(RR->node->dataStoreGet("peers.save"));
+ const uint8_t *all = reinterpret_cast<const uint8_t *>(alls.data());
+ RR->node->dataStoreDelete("peers.save");
+
+ Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *deserializeBuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
+ unsigned int ptr = 0;
+ while ((ptr + 4) < alls.size()) {
+ try {
+ const unsigned int reclen = ( // each Peer serialized record is prefixed by a record length
+ ((((unsigned int)all[ptr]) & 0xff) << 24) |
+ ((((unsigned int)all[ptr + 1]) & 0xff) << 16) |
+ ((((unsigned int)all[ptr + 2]) & 0xff) << 8) |
+ (((unsigned int)all[ptr + 3]) & 0xff)
+ );
+ unsigned int pos = 0;
+ deserializeBuf->copyFrom(all + ptr,reclen + 4);
+ SharedPtr<Peer> p(Peer::deserializeNew(RR,RR->identity,*deserializeBuf,pos));
+ ptr += pos;
+ if (!p)
+ break; // stop if invalid records
+ if (p->address() != RR->identity.address())
+ _peers.set(p->address(),p);
+ } catch ( ... ) {
+ break; // stop if invalid records
+ }
+ }
+ delete deserializeBuf;
+
+ clean(RR->node->now());
+
+ std::string dsWorld(RR->node->dataStoreGet("world"));
+ World cachedWorld;
+ if (dsWorld.length() > 0) {
+ try {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp(dsWorld.data(),(unsigned int)dsWorld.length());
+ cachedWorld.deserialize(dswtmp,0);
+ } catch ( ... ) {
+ cachedWorld = World(); // clear if cached world is invalid
+ }
+ }
+ World defaultWorld;
+ {
+ Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
+ defaultWorld.deserialize(wtmp,0); // throws on error, which would indicate a bad static variable up top
+ }
+ if (cachedWorld.shouldBeReplacedBy(defaultWorld,false)) {
+ _setWorld(defaultWorld);
+ if (dsWorld.length() > 0)
+ RR->node->dataStoreDelete("world");
+ } else _setWorld(cachedWorld);
+}
+
+Topology::~Topology()
+{
+ Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *pbuf = 0;
+ try {
+ pbuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
+ std::string all;
+
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+ while (i.next(a,p)) {
+ if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) {
+ pbuf->clear();
+ try {
+ (*p)->serialize(*pbuf);
+ try {
+ all.append((const char *)pbuf->data(),pbuf->size());
+ } catch ( ... ) {
+ return; // out of memory? just skip
+ }
+ } catch ( ... ) {} // peer too big? shouldn't happen, but it so skip
+ }
+ }
+
+ RR->node->dataStorePut("peers.save",all,true);
+
+ delete pbuf;
+ } catch ( ... ) {
+ delete pbuf;
+ }
+}
+
+SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
+{
+#ifdef ZT_TRACE
+ if ((!peer)||(peer->address() == RR->identity.address())) {
+ if (!peer)
+ fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add NULL peer" ZT_EOL_S);
+ else fprintf(stderr,"FATAL BUG: addPeer() caught attempt to add peer for self" ZT_EOL_S);
+ abort();
+ }
+#endif
+
+ SharedPtr<Peer> np;
+ {
+ Mutex::Lock _l(_lock);
+ SharedPtr<Peer> &hp = _peers[peer->address()];
+ if (!hp)
+ hp = peer;
+ np = hp;
+ }
+
+ np->use(RR->node->now());
+ saveIdentity(np->identity());
+
+ return np;
+}
+
+SharedPtr<Peer> Topology::getPeer(const Address &zta)
+{
+ if (zta == RR->identity.address()) {
+ TRACE("BUG: ignored attempt to getPeer() for self, returned NULL");
+ return SharedPtr<Peer>();
+ }
+
+ {
+ Mutex::Lock _l(_lock);
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap) {
+ (*ap)->use(RR->node->now());
+ return *ap;
+ }
+ }
+
+ try {
+ Identity id(_getIdentity(zta));
+ if (id) {
+ SharedPtr<Peer> np(new Peer(RR,RR->identity,id));
+ {
+ Mutex::Lock _l(_lock);
+ SharedPtr<Peer> &ap = _peers[zta];
+ if (!ap)
+ ap.swap(np);
+ ap->use(RR->node->now());
+ return ap;
+ }
+ }
+ } catch ( ... ) {
+ fprintf(stderr,"EXCEPTION in getPeer() part 2\n");
+ abort();
+ } // invalid identity on disk?
+
+ return SharedPtr<Peer>();
+}
+
+Identity Topology::getIdentity(const Address &zta)
+{
+ {
+ Mutex::Lock _l(_lock);
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap)
+ return (*ap)->identity();
+ }
+ return _getIdentity(zta);
+}
+
+void Topology::saveIdentity(const Identity &id)
+{
+ if (id) {
+ char p[128];
+ Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)id.address().toInt());
+ RR->node->dataStorePut(p,id.toString(false),false);
+ }
+}
+
+SharedPtr<Peer> Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
+{
+ const uint64_t now = RR->node->now();
+ Mutex::Lock _l(_lock);
+
+ if (_amRoot) {
+ /* If I am a root server, the "best" root server is the one whose address
+ * is numerically greater than mine (with wrap at top of list). This
+ * causes packets searching for a route to pretty much literally
+ * circumnavigate the globe rather than bouncing between just two. */
+
+ for(unsigned long p=0;p<_rootAddresses.size();++p) {
+ if (_rootAddresses[p] == RR->identity.address()) {
+ for(unsigned long q=1;q<_rootAddresses.size();++q) {
+ const SharedPtr<Peer> *const nextsn = _peers.get(_rootAddresses[(p + q) % _rootAddresses.size()]);
+ if ((nextsn)&&((*nextsn)->hasActiveDirectPath(now))) {
+ (*nextsn)->use(now);
+ return *nextsn;
+ }
+ }
+ break;
+ }
+ }
+
+ } else {
+ /* If I am not a root server, the best root server is the active one with
+ * the lowest quality score. (lower == better) */
+
+ unsigned int bestQualityOverall = ~((unsigned int)0);
+ unsigned int bestQualityNotAvoid = ~((unsigned int)0);
+ const SharedPtr<Peer> *bestOverall = (const SharedPtr<Peer> *)0;
+ const SharedPtr<Peer> *bestNotAvoid = (const SharedPtr<Peer> *)0;
+
+ for(std::vector< SharedPtr<Peer> >::const_iterator r(_rootPeers.begin());r!=_rootPeers.end();++r) {
+ bool avoiding = false;
+ for(unsigned int i=0;i<avoidCount;++i) {
+ if (avoid[i] == (*r)->address()) {
+ avoiding = true;
+ break;
+ }
+ }
+ const unsigned int q = (*r)->relayQuality(now);
+ if (q <= bestQualityOverall) {
+ bestQualityOverall = q;
+ bestOverall = &(*r);
+ }
+ if ((!avoiding)&&(q <= bestQualityNotAvoid)) {
+ bestQualityNotAvoid = q;
+ bestNotAvoid = &(*r);
+ }
+ }
+
+ if (bestNotAvoid) {
+ (*bestNotAvoid)->use(now);
+ return *bestNotAvoid;
+ } else if ((!strictAvoid)&&(bestOverall)) {
+ (*bestOverall)->use(now);
+ return *bestOverall;
+ }
+
+ }
+
+ return SharedPtr<Peer>();
+}
+
+bool Topology::isUpstream(const Identity &id) const
+{
+ if (isRoot(id))
+ return true;
+ std::vector< SharedPtr<Network> > nws(RR->node->allNetworks());
+ for(std::vector< SharedPtr<Network> >::const_iterator nw(nws.begin());nw!=nws.end();++nw) {
+ if ((*nw)->config().isRelay(id.address())) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Topology::worldUpdateIfValid(const World &newWorld)
+{
+ Mutex::Lock _l(_lock);
+ if (_world.shouldBeReplacedBy(newWorld,true)) {
+ _setWorld(newWorld);
+ try {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp;
+ newWorld.serialize(dswtmp,false);
+ RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false);
+ } catch ( ... ) {
+ RR->node->dataStoreDelete("world");
+ }
+ return true;
+ }
+ return false;
+}
+
+void Topology::clean(uint64_t now)
+{
+ Mutex::Lock _l(_lock);
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ while (i.next(a,p)) {
+ if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) {
+ _peers.erase(*a);
+ } else {
+ (*p)->clean(now);
+ }
+ }
+}
+
+Identity Topology::_getIdentity(const Address &zta)
+{
+ char p[128];
+ Utils::snprintf(p,sizeof(p),"iddb.d/%.10llx",(unsigned long long)zta.toInt());
+ std::string ids(RR->node->dataStoreGet(p));
+ if (ids.length() > 0) {
+ try {
+ return Identity(ids);
+ } catch ( ... ) {} // ignore invalid IDs
+ }
+ return Identity();
+}
+
+void Topology::_setWorld(const World &newWorld)
+{
+ // assumed _lock is locked (or in constructor)
+ _world = newWorld;
+ _amRoot = false;
+ _rootAddresses.clear();
+ _rootPeers.clear();
+ for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
+ _rootAddresses.push_back(r->identity.address());
+ if (r->identity.address() == RR->identity.address()) {
+ _amRoot = true;
+ } else {
+ SharedPtr<Peer> *rp = _peers.get(r->identity.address());
+ if (rp) {
+ _rootPeers.push_back(*rp);
+ } else {
+ SharedPtr<Peer> newrp(new Peer(RR,RR->identity,r->identity));
+ _peers.set(r->identity.address(),newrp);
+ _rootPeers.push_back(newrp);
+ }
+ }
+ }
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Topology.hpp b/zerotierone/node/Topology.hpp
new file mode 100644
index 0000000..86fbb01
--- /dev/null
+++ b/zerotierone/node/Topology.hpp
@@ -0,0 +1,272 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_TOPOLOGY_HPP
+#define ZT_TOPOLOGY_HPP
+
+#include <stdio.h>
+#include <string.h>
+
+#include <vector>
+#include <stdexcept>
+#include <algorithm>
+#include <utility>
+
+#include "Constants.hpp"
+
+#include "Address.hpp"
+#include "Identity.hpp"
+#include "Peer.hpp"
+#include "Mutex.hpp"
+#include "InetAddress.hpp"
+#include "Hashtable.hpp"
+#include "World.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+
+/**
+ * Database of network topology
+ */
+class Topology
+{
+public:
+ Topology(const RuntimeEnvironment *renv);
+ ~Topology();
+
+ /**
+ * Add a peer to database
+ *
+ * This will not replace existing peers. In that case the existing peer
+ * record is returned.
+ *
+ * @param peer Peer to add
+ * @return New or existing peer (should replace 'peer')
+ */
+ SharedPtr<Peer> addPeer(const SharedPtr<Peer> &peer);
+
+ /**
+ * Get a peer from its address
+ *
+ * @param zta ZeroTier address of peer
+ * @return Peer or NULL if not found
+ */
+ SharedPtr<Peer> getPeer(const Address &zta);
+
+ /**
+ * Get a peer only if it is presently in memory (no disk cache)
+ *
+ * This also does not update the lastUsed() time for peers, which means
+ * that it won't prevent them from falling out of RAM. This is currently
+ * used in the Cluster code to update peer info without forcing all peers
+ * across the entire cluster to remain in memory cache.
+ *
+ * @param zta ZeroTier address
+ */
+ inline SharedPtr<Peer> getPeerNoCache(const Address &zta)
+ {
+ Mutex::Lock _l(_lock);
+ const SharedPtr<Peer> *const ap = _peers.get(zta);
+ if (ap)
+ return *ap;
+ return SharedPtr<Peer>();
+ }
+
+ /**
+ * Get the identity of a peer
+ *
+ * @param zta ZeroTier address of peer
+ * @return Identity or NULL Identity if not found
+ */
+ Identity getIdentity(const Address &zta);
+
+ /**
+ * Cache an identity
+ *
+ * This is done automatically on addPeer(), and so is only useful for
+ * cluster identity replication.
+ *
+ * @param id Identity to cache
+ */
+ void saveIdentity(const Identity &id);
+
+ /**
+ * Get the current favorite root server
+ *
+ * @return Root server with lowest latency or NULL if none
+ */
+ inline SharedPtr<Peer> getBestRoot() { return getBestRoot((const Address *)0,0,false); }
+
+ /**
+ * Get the best root server, avoiding root servers listed in an array
+ *
+ * This will get the best root server (lowest latency, etc.) but will
+ * try to avoid the listed root servers, only using them if no others
+ * are available.
+ *
+ * @param avoid Nodes to avoid
+ * @param avoidCount Number of nodes to avoid
+ * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available
+ * @return Root server or NULL if none available
+ */
+ SharedPtr<Peer> getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid);
+
+ /**
+ * @param id Identity to check
+ * @return True if this is a designated root server in this world
+ */
+ inline bool isRoot(const Identity &id) const
+ {
+ Mutex::Lock _l(_lock);
+ return (std::find(_rootAddresses.begin(),_rootAddresses.end(),id.address()) != _rootAddresses.end());
+ }
+
+ /**
+ * @param id Identity to check
+ * @return True if this is a root server or a network preferred relay from one of our networks
+ */
+ bool isUpstream(const Identity &id) const;
+
+ /**
+ * @return Vector of root server addresses
+ */
+ inline std::vector<Address> rootAddresses() const
+ {
+ Mutex::Lock _l(_lock);
+ return _rootAddresses;
+ }
+
+ /**
+ * @return Current World (copy)
+ */
+ inline World world() const
+ {
+ Mutex::Lock _l(_lock);
+ return _world;
+ }
+
+ /**
+ * @return Current world ID
+ */
+ inline uint64_t worldId() const
+ {
+ return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock
+ }
+
+ /**
+ * @return Current world timestamp
+ */
+ inline uint64_t worldTimestamp() const
+ {
+ return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
+ }
+
+ /**
+ * Validate new world and update if newer and signature is okay
+ *
+ * @param newWorld Potential new world definition revision
+ * @return True if an update actually occurred
+ */
+ bool worldUpdateIfValid(const World &newWorld);
+
+ /**
+ * Clean and flush database
+ */
+ void clean(uint64_t now);
+
+ /**
+ * @param now Current time
+ * @return Number of peers with active direct paths
+ */
+ inline unsigned long countActive(uint64_t now) const
+ {
+ unsigned long cnt = 0;
+ Mutex::Lock _l(_lock);
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ while (i.next(a,p)) {
+ cnt += (unsigned long)((*p)->hasActiveDirectPath(now));
+ }
+ return cnt;
+ }
+
+ /**
+ * Apply a function or function object to all peers
+ *
+ * Note: explicitly template this by reference if you want the object
+ * passed by reference instead of copied.
+ *
+ * Warning: be careful not to use features in these that call any other
+ * methods of Topology that may lock _lock, otherwise a recursive lock
+ * and deadlock or lock corruption may occur.
+ *
+ * @param f Function to apply
+ * @tparam F Function or function object type
+ */
+ template<typename F>
+ inline void eachPeer(F f)
+ {
+ Mutex::Lock _l(_lock);
+ Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
+ Address *a = (Address *)0;
+ SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
+ while (i.next(a,p)) {
+#ifdef ZT_TRACE
+ if (!(*p)) {
+ fprintf(stderr,"FATAL BUG: eachPeer() caught NULL peer for %s -- peer pointers in Topology should NEVER be NULL" ZT_EOL_S,a->toString().c_str());
+ abort();
+ }
+#endif
+ f(*this,*((const SharedPtr<Peer> *)p));
+ }
+ }
+
+ /**
+ * @return All currently active peers by address (unsorted)
+ */
+ inline std::vector< std::pair< Address,SharedPtr<Peer> > > allPeers() const
+ {
+ Mutex::Lock _l(_lock);
+ return _peers.entries();
+ }
+
+ /**
+ * @return True if I am a root server in the current World
+ */
+ inline bool amRoot() const throw() { return _amRoot; }
+
+private:
+ Identity _getIdentity(const Address &zta);
+ void _setWorld(const World &newWorld);
+
+ const RuntimeEnvironment *const RR;
+
+ World _world;
+ Hashtable< Address,SharedPtr<Peer> > _peers;
+ std::vector< Address > _rootAddresses;
+ std::vector< SharedPtr<Peer> > _rootPeers;
+ bool _amRoot;
+
+ Mutex _lock;
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/Utils.cpp b/zerotierone/node/Utils.cpp
new file mode 100644
index 0000000..00aeea3
--- /dev/null
+++ b/zerotierone/node/Utils.cpp
@@ -0,0 +1,283 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "Constants.hpp"
+
+#ifdef __UNIX_LIKE__
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <dirent.h>
+#endif
+
+#ifdef __WINDOWS__
+#include <wincrypt.h>
+#endif
+
+#include "Utils.hpp"
+#include "Mutex.hpp"
+#include "Salsa20.hpp"
+
+namespace ZeroTier {
+
+const char Utils::HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
+
+static void _Utils_doBurn(char *ptr,unsigned int len)
+{
+ for(unsigned int i=0;i<len;++i)
+ ptr[i] = (char)0;
+}
+void (*volatile _Utils_doBurn_ptr)(char *,unsigned int) = _Utils_doBurn;
+void Utils::burn(void *ptr,unsigned int len)
+ throw()
+{
+ // Ridiculous hack: call _doBurn() via a volatile function pointer to
+ // hold down compiler optimizers and beat them mercilessly until they
+ // cry and mumble something about never eliding secure memory zeroing
+ // again.
+ (_Utils_doBurn_ptr)((char *)ptr,len);
+}
+
+std::string Utils::hex(const void *data,unsigned int len)
+{
+ std::string r;
+ r.reserve(len * 2);
+ for(unsigned int i=0;i<len;++i) {
+ r.push_back(HEXCHARS[(((const unsigned char *)data)[i] & 0xf0) >> 4]);
+ r.push_back(HEXCHARS[((const unsigned char *)data)[i] & 0x0f]);
+ }
+ return r;
+}
+
+std::string Utils::unhex(const char *hex,unsigned int maxlen)
+{
+ int n = 1;
+ unsigned char c,b = 0;
+ const char *eof = hex + maxlen;
+ std::string r;
+
+ if (!maxlen)
+ return r;
+
+ while ((c = (unsigned char)*(hex++))) {
+ if ((c >= 48)&&(c <= 57)) { // 0..9
+ if ((n ^= 1))
+ r.push_back((char)(b | (c - 48)));
+ else b = (c - 48) << 4;
+ } else if ((c >= 65)&&(c <= 70)) { // A..F
+ if ((n ^= 1))
+ r.push_back((char)(b | (c - (65 - 10))));
+ else b = (c - (65 - 10)) << 4;
+ } else if ((c >= 97)&&(c <= 102)) { // a..f
+ if ((n ^= 1))
+ r.push_back((char)(b | (c - (97 - 10))));
+ else b = (c - (97 - 10)) << 4;
+ }
+ if (hex == eof)
+ break;
+ }
+
+ return r;
+}
+
+unsigned int Utils::unhex(const char *hex,unsigned int maxlen,void *buf,unsigned int len)
+{
+ int n = 1;
+ unsigned char c,b = 0;
+ unsigned int l = 0;
+ const char *eof = hex + maxlen;
+
+ if (!maxlen)
+ return 0;
+
+ while ((c = (unsigned char)*(hex++))) {
+ if ((c >= 48)&&(c <= 57)) { // 0..9
+ if ((n ^= 1)) {
+ if (l >= len) break;
+ ((unsigned char *)buf)[l++] = (b | (c - 48));
+ } else b = (c - 48) << 4;
+ } else if ((c >= 65)&&(c <= 70)) { // A..F
+ if ((n ^= 1)) {
+ if (l >= len) break;
+ ((unsigned char *)buf)[l++] = (b | (c - (65 - 10)));
+ } else b = (c - (65 - 10)) << 4;
+ } else if ((c >= 97)&&(c <= 102)) { // a..f
+ if ((n ^= 1)) {
+ if (l >= len) break;
+ ((unsigned char *)buf)[l++] = (b | (c - (97 - 10)));
+ } else b = (c - (97 - 10)) << 4;
+ }
+ if (hex == eof)
+ break;
+ }
+
+ return l;
+}
+
+void Utils::getSecureRandom(void *buf,unsigned int bytes)
+{
+ static Mutex globalLock;
+ static Salsa20 s20;
+ static bool s20Initialized = false;
+
+ Mutex::Lock _l(globalLock);
+
+ /* Just for posterity we Salsa20 encrypt the result of whatever system
+ * CSPRNG we use. There have been several bugs at the OS or OS distribution
+ * level in the past that resulted in systematically weak or predictable
+ * keys due to random seeding problems. This mitigates that by grabbing
+ * a bit of extra entropy and further randomizing the result, and comes
+ * at almost no cost and with no real downside if the random source is
+ * good. */
+ if (!s20Initialized) {
+ s20Initialized = true;
+ uint64_t s20Key[4];
+ s20Key[0] = (uint64_t)time(0); // system clock
+ s20Key[1] = (uint64_t)buf; // address of buf
+ s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
+ s20Key[3] = (uint64_t)&s20; // address of s20
+ s20.init(s20Key,256,s20Key);
+ }
+
+#ifdef __WINDOWS__
+
+ static HCRYPTPROV cryptProvider = NULL;
+
+ if (cryptProvider == NULL) {
+ if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
+ exit(1);
+ return;
+ }
+ }
+ if (!CryptGenRandom(cryptProvider,(DWORD)bytes,(BYTE *)buf)) {
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
+ exit(1);
+ }
+
+#else // not __WINDOWS__
+
+ static char randomBuf[131072];
+ static unsigned int randomPtr = sizeof(randomBuf);
+ static int devURandomFd = -1;
+
+ if (devURandomFd <= 0) {
+ devURandomFd = ::open("/dev/urandom",O_RDONLY);
+ if (devURandomFd <= 0) {
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
+ exit(1);
+ return;
+ }
+ }
+
+ for(unsigned int i=0;i<bytes;++i) {
+ if (randomPtr >= sizeof(randomBuf)) {
+ for(;;) {
+ if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
+ ::close(devURandomFd);
+ devURandomFd = ::open("/dev/urandom",O_RDONLY);
+ if (devURandomFd <= 0) {
+ fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to open /dev/urandom\n");
+ exit(1);
+ return;
+ }
+ } else break;
+ }
+ randomPtr = 0;
+ }
+ ((char *)buf)[i] = randomBuf[randomPtr++];
+ }
+
+#endif // __WINDOWS__ or not
+
+ s20.encrypt12(buf,buf,bytes);
+}
+
+std::vector<std::string> Utils::split(const char *s,const char *const sep,const char *esc,const char *quot)
+{
+ std::vector<std::string> fields;
+ std::string buf;
+
+ if (!esc)
+ esc = "";
+ if (!quot)
+ quot = "";
+
+ bool escapeState = false;
+ char quoteState = 0;
+ while (*s) {
+ if (escapeState) {
+ escapeState = false;
+ buf.push_back(*s);
+ } else if (quoteState) {
+ if (*s == quoteState) {
+ quoteState = 0;
+ fields.push_back(buf);
+ buf.clear();
+ } else buf.push_back(*s);
+ } else {
+ const char *quotTmp;
+ if (strchr(esc,*s))
+ escapeState = true;
+ else if ((buf.size() <= 0)&&((quotTmp = strchr(quot,*s))))
+ quoteState = *quotTmp;
+ else if (strchr(sep,*s)) {
+ if (buf.size() > 0) {
+ fields.push_back(buf);
+ buf.clear();
+ } // else skip runs of seperators
+ } else buf.push_back(*s);
+ }
+ ++s;
+ }
+
+ if (buf.size())
+ fields.push_back(buf);
+
+ return fields;
+}
+
+unsigned int Utils::snprintf(char *buf,unsigned int len,const char *fmt,...)
+ throw(std::length_error)
+{
+ va_list ap;
+
+ va_start(ap,fmt);
+ int n = (int)vsnprintf(buf,len,fmt,ap);
+ va_end(ap);
+
+ if ((n >= (int)len)||(n < 0)) {
+ if (len)
+ buf[len - 1] = (char)0;
+ throw std::length_error("buf[] overflow in Utils::snprintf");
+ }
+
+ return (unsigned int)n;
+}
+
+} // namespace ZeroTier
diff --git a/zerotierone/node/Utils.hpp b/zerotierone/node/Utils.hpp
new file mode 100644
index 0000000..3f4cc76
--- /dev/null
+++ b/zerotierone/node/Utils.hpp
@@ -0,0 +1,392 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_UTILS_HPP
+#define ZT_UTILS_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <map>
+
+#include "Constants.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Miscellaneous utility functions and global constants
+ */
+class Utils
+{
+public:
+ /**
+ * Perform a time-invariant binary comparison
+ *
+ * @param a First binary string
+ * @param b Second binary string
+ * @param len Length of strings
+ * @return True if strings are equal
+ */
+ static inline bool secureEq(const void *a,const void *b,unsigned int len)
+ throw()
+ {
+ uint8_t diff = 0;
+ for(unsigned int i=0;i<len;++i)
+ diff |= ( (reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i] );
+ return (diff == 0);
+ }
+
+ /**
+ * Securely zero memory, avoiding compiler optimizations and such
+ */
+ static void burn(void *ptr,unsigned int len)
+ throw();
+
+ /**
+ * Convert binary data to hexadecimal
+ *
+ * @param data Data to convert to hex
+ * @param len Length of data
+ * @return Hexadecimal string
+ */
+ static std::string hex(const void *data,unsigned int len);
+ static inline std::string hex(const std::string &data) { return hex(data.data(),(unsigned int)data.length()); }
+
+ /**
+ * Convert hexadecimal to binary data
+ *
+ * This ignores all non-hex characters, just stepping over them and
+ * continuing. Upper and lower case are supported for letters a-f.
+ *
+ * @param hex Hexadecimal ASCII code (non-hex chars are ignored, stops at zero or maxlen)
+ * @param maxlen Maximum length of hex string buffer
+ * @return Binary data
+ */
+ static std::string unhex(const char *hex,unsigned int maxlen);
+ static inline std::string unhex(const std::string &hex) { return unhex(hex.c_str(),(unsigned int)hex.length()); }
+
+ /**
+ * Convert hexadecimal to binary data
+ *
+ * This ignores all non-hex characters, just stepping over them and
+ * continuing. Upper and lower case are supported for letters a-f.
+ *
+ * @param hex Hexadecimal ASCII
+ * @param maxlen Maximum length of hex string buffer
+ * @param buf Buffer to fill
+ * @param len Length of buffer
+ * @return Number of characters actually written
+ */
+ static unsigned int unhex(const char *hex,unsigned int maxlen,void *buf,unsigned int len);
+ static inline unsigned int unhex(const std::string &hex,void *buf,unsigned int len) { return unhex(hex.c_str(),(unsigned int)hex.length(),buf,len); }
+
+ /**
+ * Generate secure random bytes
+ *
+ * This will try to use whatever OS sources of entropy are available. It's
+ * guarded by an internal mutex so it's thread-safe.
+ *
+ * @param buf Buffer to fill
+ * @param bytes Number of random bytes to generate
+ */
+ static void getSecureRandom(void *buf,unsigned int bytes);
+
+ /**
+ * Split a string by delimiter, with optional escape and quote characters
+ *
+ * @param s String to split
+ * @param sep One or more separators
+ * @param esc Zero or more escape characters
+ * @param quot Zero or more quote characters
+ * @return Vector of tokens
+ */
+ static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot);
+
+ /**
+ * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
+ *
+ * @param str String to split
+ * @param delim Delimiters
+ * @param saveptr Pointer to a char * for temporary reentrant storage
+ */
+ static inline char *stok(char *str,const char *delim,char **saveptr)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return strtok_s(str,delim,saveptr);
+#else
+ return strtok_r(str,delim,saveptr);
+#endif
+ }
+
+ // String to number converters -- defined here to permit portability
+ // ifdefs for platforms that lack some of the strtoXX functions.
+ static inline unsigned int strToUInt(const char *s)
+ throw()
+ {
+ return (unsigned int)strtoul(s,(char **)0,10);
+ }
+ static inline int strToInt(const char *s)
+ throw()
+ {
+ return (int)strtol(s,(char **)0,10);
+ }
+ static inline unsigned long strToULong(const char *s)
+ throw()
+ {
+ return strtoul(s,(char **)0,10);
+ }
+ static inline long strToLong(const char *s)
+ throw()
+ {
+ return strtol(s,(char **)0,10);
+ }
+ static inline unsigned long long strToU64(const char *s)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return (unsigned long long)_strtoui64(s,(char **)0,10);
+#else
+ return strtoull(s,(char **)0,10);
+#endif
+ }
+ static inline long long strTo64(const char *s)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return (long long)_strtoi64(s,(char **)0,10);
+#else
+ return strtoll(s,(char **)0,10);
+#endif
+ }
+ static inline unsigned int hexStrToUInt(const char *s)
+ throw()
+ {
+ return (unsigned int)strtoul(s,(char **)0,16);
+ }
+ static inline int hexStrToInt(const char *s)
+ throw()
+ {
+ return (int)strtol(s,(char **)0,16);
+ }
+ static inline unsigned long hexStrToULong(const char *s)
+ throw()
+ {
+ return strtoul(s,(char **)0,16);
+ }
+ static inline long hexStrToLong(const char *s)
+ throw()
+ {
+ return strtol(s,(char **)0,16);
+ }
+ static inline unsigned long long hexStrToU64(const char *s)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return (unsigned long long)_strtoui64(s,(char **)0,16);
+#else
+ return strtoull(s,(char **)0,16);
+#endif
+ }
+ static inline long long hexStrTo64(const char *s)
+ throw()
+ {
+#ifdef __WINDOWS__
+ return (long long)_strtoi64(s,(char **)0,16);
+#else
+ return strtoll(s,(char **)0,16);
+#endif
+ }
+ static inline double strToDouble(const char *s)
+ throw()
+ {
+ return strtod(s,(char **)0);
+ }
+
+ /**
+ * Perform a safe C string copy
+ *
+ * @param dest Destination buffer
+ * @param len Length of buffer
+ * @param src Source string
+ * @return True on success, false on overflow (buffer will still be 0-terminated)
+ */
+ static inline bool scopy(char *dest,unsigned int len,const char *src)
+ throw()
+ {
+ if (!len)
+ return false; // sanity check
+ char *end = dest + len;
+ while ((*dest++ = *src++)) {
+ if (dest == end) {
+ *(--dest) = (char)0;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Variant of snprintf that is portable and throws an exception
+ *
+ * This just wraps the local implementation whatever it's called, while
+ * performing a few other checks and adding exceptions for overflow.
+ *
+ * @param buf Buffer to write to
+ * @param len Length of buffer in bytes
+ * @param fmt Format string
+ * @param ... Format arguments
+ * @throws std::length_error buf[] too short (buf[] will still be left null-terminated)
+ */
+ static unsigned int snprintf(char *buf,unsigned int len,const char *fmt,...)
+ throw(std::length_error);
+
+ /**
+ * Count the number of bits set in an integer
+ *
+ * @param v 32-bit integer
+ * @return Number of bits set in this integer (0-32)
+ */
+ static inline uint32_t countBits(uint32_t v)
+ throw()
+ {
+ v = v - ((v >> 1) & (uint32_t)0x55555555);
+ v = (v & (uint32_t)0x33333333) + ((v >> 2) & (uint32_t)0x33333333);
+ return ((((v + (v >> 4)) & (uint32_t)0xF0F0F0F) * (uint32_t)0x1010101) >> 24);
+ }
+
+ /**
+ * Check if a memory buffer is all-zero
+ *
+ * @param p Memory to scan
+ * @param len Length of memory
+ * @return True if memory is all zero
+ */
+ static inline bool isZero(const void *p,unsigned int len)
+ throw()
+ {
+ for(unsigned int i=0;i<len;++i) {
+ if (((const unsigned char *)p)[i])
+ return false;
+ }
+ return true;
+ }
+
+ // Byte swappers for big/little endian conversion
+ static inline uint8_t hton(uint8_t n) throw() { return n; }
+ static inline int8_t hton(int8_t n) throw() { return n; }
+ static inline uint16_t hton(uint16_t n) throw() { return htons(n); }
+ static inline int16_t hton(int16_t n) throw() { return (int16_t)htons((uint16_t)n); }
+ static inline uint32_t hton(uint32_t n) throw() { return htonl(n); }
+ static inline int32_t hton(int32_t n) throw() { return (int32_t)htonl((uint32_t)n); }
+ static inline uint64_t hton(uint64_t n)
+ throw()
+ {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if defined(__GNUC__) && (!defined(__OpenBSD__))
+ return __builtin_bswap64(n);
+#else
+ return (
+ ((n & 0x00000000000000FFULL) << 56) |
+ ((n & 0x000000000000FF00ULL) << 40) |
+ ((n & 0x0000000000FF0000ULL) << 24) |
+ ((n & 0x00000000FF000000ULL) << 8) |
+ ((n & 0x000000FF00000000ULL) >> 8) |
+ ((n & 0x0000FF0000000000ULL) >> 24) |
+ ((n & 0x00FF000000000000ULL) >> 40) |
+ ((n & 0xFF00000000000000ULL) >> 56)
+ );
+#endif
+#else
+ return n;
+#endif
+ }
+ static inline int64_t hton(int64_t n) throw() { return (int64_t)hton((uint64_t)n); }
+
+ static inline uint8_t ntoh(uint8_t n) throw() { return n; }
+ static inline int8_t ntoh(int8_t n) throw() { return n; }
+ static inline uint16_t ntoh(uint16_t n) throw() { return ntohs(n); }
+ static inline int16_t ntoh(int16_t n) throw() { return (int16_t)ntohs((uint16_t)n); }
+ static inline uint32_t ntoh(uint32_t n) throw() { return ntohl(n); }
+ static inline int32_t ntoh(int32_t n) throw() { return (int32_t)ntohl((uint32_t)n); }
+ static inline uint64_t ntoh(uint64_t n)
+ throw()
+ {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if defined(__GNUC__) && !defined(__OpenBSD__)
+ return __builtin_bswap64(n);
+#else
+ return (
+ ((n & 0x00000000000000FFULL) << 56) |
+ ((n & 0x000000000000FF00ULL) << 40) |
+ ((n & 0x0000000000FF0000ULL) << 24) |
+ ((n & 0x00000000FF000000ULL) << 8) |
+ ((n & 0x000000FF00000000ULL) >> 8) |
+ ((n & 0x0000FF0000000000ULL) >> 24) |
+ ((n & 0x00FF000000000000ULL) >> 40) |
+ ((n & 0xFF00000000000000ULL) >> 56)
+ );
+#endif
+#else
+ return n;
+#endif
+ }
+ static inline int64_t ntoh(int64_t n) throw() { return (int64_t)ntoh((uint64_t)n); }
+
+ /**
+ * Compare Peer version tuples
+ *
+ * @return -1, 0, or 1 based on whether first tuple is less than, equal to, or greater than second
+ */
+ static inline int compareVersion(unsigned int maj1,unsigned int min1,unsigned int rev1,unsigned int maj2,unsigned int min2,unsigned int rev2)
+ throw()
+ {
+ if (maj1 > maj2)
+ return 1;
+ else if (maj1 < maj2)
+ return -1;
+ else {
+ if (min1 > min2)
+ return 1;
+ else if (min1 < min2)
+ return -1;
+ else {
+ if (rev1 > rev2)
+ return 1;
+ else if (rev1 < rev2)
+ return -1;
+ else return 0;
+ }
+ }
+ }
+
+ /**
+ * Hexadecimal characters 0-f
+ */
+ static const char HEXCHARS[16];
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/zerotierone/node/World.hpp b/zerotierone/node/World.hpp
new file mode 100644
index 0000000..fdada2a
--- /dev/null
+++ b/zerotierone/node/World.hpp
@@ -0,0 +1,232 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ZT_WORLD_HPP
+#define ZT_WORLD_HPP
+
+#include <vector>
+#include <string>
+
+#include "Constants.hpp"
+#include "InetAddress.hpp"
+#include "Identity.hpp"
+#include "Buffer.hpp"
+#include "C25519.hpp"
+
+/**
+ * Maximum number of roots (sanity limit, okay to increase)
+ *
+ * A given root can (through multi-homing) be distributed across any number of
+ * physical endpoints, but having more than one is good to permit total failure
+ * of one root or its withdrawal due to compromise without taking the whole net
+ * down.
+ */
+#define ZT_WORLD_MAX_ROOTS 4
+
+/**
+ * Maximum number of stable endpoints per root (sanity limit, okay to increase)
+ */
+#define ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT 32
+
+/**
+ * The (more than) maximum length of a serialized World
+ */
+#define ZT_WORLD_MAX_SERIALIZED_LENGTH (((1024 + (32 * ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)) * ZT_WORLD_MAX_ROOTS) + ZT_C25519_PUBLIC_KEY_LEN + ZT_C25519_SIGNATURE_LEN + 128)
+
+/**
+ * World ID indicating null / empty World object
+ */
+#define ZT_WORLD_ID_NULL 0
+
+/**
+ * World ID for a test network with ephemeral or temporary roots
+ */
+#define ZT_WORLD_ID_TESTNET 1
+
+/**
+ * World ID for Earth
+ *
+ * This is the ID for the ZeroTier World used on planet Earth. It is unrelated
+ * to the public network 8056c2e21c000001 of the same name. It was chosen
+ * from Earth's approximate distance from the sun in kilometers.
+ */
+#define ZT_WORLD_ID_EARTH 149604618
+
+/**
+ * World ID for Mars -- for future use by SpaceX or others
+ */
+#define ZT_WORLD_ID_MARS 227883110
+
+namespace ZeroTier {
+
+/**
+ * A world definition (formerly known as a root topology)
+ *
+ * Think of a World as a single data center. Within this data center a set
+ * of distributed fault tolerant root servers provide stable anchor points
+ * for a peer to peer network that provides VLAN service. Updates to a world
+ * definition can be published by signing them with the previous revision's
+ * signing key, and should be very infrequent.
+ *
+ * The maximum data center size is approximately 2.5 cubic light seconds,
+ * since many protocols have issues with >5s RTT latencies.
+ *
+ * ZeroTier operates a World for Earth capable of encompassing the planet, its
+ * orbits, the Moon (about 1.3 light seconds), and nearby Lagrange points. A
+ * world ID for Mars and nearby space is defined but not yet used, and a test
+ * world ID is provided for testing purposes.
+ *
+ * If you absolutely must run your own "unofficial" ZeroTier network, please
+ * define your world IDs above 0xffffffff (4294967295). Code to make a World
+ * is in mkworld.cpp in the parent directory and must be edited to change
+ * settings.
+ */
+class World
+{
+public:
+ struct Root
+ {
+ Identity identity;
+ std::vector<InetAddress> stableEndpoints;
+
+ inline bool operator==(const Root &r) const throw() { return ((identity == r.identity)&&(stableEndpoints == r.stableEndpoints)); }
+ inline bool operator!=(const Root &r) const throw() { return (!(*this == r)); }
+ inline bool operator<(const Root &r) const throw() { return (identity < r.identity); } // for sorting
+ };
+
+ /**
+ * Construct an empty / null World
+ */
+ World() :
+ _id(ZT_WORLD_ID_NULL),
+ _ts(0) {}
+
+ /**
+ * @return Root servers for this world and their stable endpoints
+ */
+ inline const std::vector<World::Root> &roots() const throw() { return _roots; }
+
+ /**
+ * @return World unique identifier
+ */
+ inline uint64_t id() const throw() { return _id; }
+
+ /**
+ * @return World definition timestamp
+ */
+ inline uint64_t timestamp() const throw() { return _ts; }
+
+ /**
+ * Check whether a world update should replace this one
+ *
+ * A new world update is valid if it is for the same world ID, is newer,
+ * and is signed by the current world's signing key. If this world object
+ * is null, it can always be updated.
+ *
+ * @param update Candidate update
+ * @param fullSignatureCheck Perform full cryptographic signature check (true == yes, false == skip)
+ * @return True if update is newer than current and is properly signed
+ */
+ inline bool shouldBeReplacedBy(const World &update,bool fullSignatureCheck)
+ {
+ if (_id == ZT_WORLD_ID_NULL)
+ return true;
+ if ((_id == update._id)&&(_ts < update._ts)) {
+ if (fullSignatureCheck) {
+ Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> tmp;
+ update.serialize(tmp,true);
+ return C25519::verify(_updateSigningKey,tmp.data(),tmp.size(),update._signature);
+ } else return true;
+ }
+ return false;
+ }
+
+ /**
+ * @return True if this World is non-empty
+ */
+ inline operator bool() const throw() { return (_id != ZT_WORLD_ID_NULL); }
+
+ template<unsigned int C>
+ inline void serialize(Buffer<C> &b,bool forSign = false) const
+ {
+ if (forSign)
+ b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
+ b.append((uint8_t)0x01); // version -- only one valid value for now
+ b.append((uint64_t)_id);
+ b.append((uint64_t)_ts);
+ b.append(_updateSigningKey.data,ZT_C25519_PUBLIC_KEY_LEN);
+ if (!forSign)
+ b.append(_signature.data,ZT_C25519_SIGNATURE_LEN);
+ b.append((uint8_t)_roots.size());
+ for(std::vector<Root>::const_iterator r(_roots.begin());r!=_roots.end();++r) {
+ r->identity.serialize(b);
+ b.append((uint8_t)r->stableEndpoints.size());
+ for(std::vector<InetAddress>::const_iterator ep(r->stableEndpoints.begin());ep!=r->stableEndpoints.end();++ep)
+ ep->serialize(b);
+ }
+ if (forSign)
+ b.append((uint64_t)0xf7f7f7f7f7f7f7f7ULL);
+ }
+
+ template<unsigned int C>
+ inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+ {
+ unsigned int p = startAt;
+
+ _roots.clear();
+
+ if (b[p++] != 0x01)
+ throw std::invalid_argument("invalid World serialized version");
+
+ _id = b.template at<uint64_t>(p); p += 8;
+ _ts = b.template at<uint64_t>(p); p += 8;
+ memcpy(_updateSigningKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
+ memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
+ unsigned int numRoots = b[p++];
+ if (numRoots > ZT_WORLD_MAX_ROOTS)
+ throw std::invalid_argument("too many roots in World");
+ for(unsigned int k=0;k<numRoots;++k) {
+ _roots.push_back(Root());
+ Root &r = _roots.back();
+ p += r.identity.deserialize(b,p);
+ unsigned int numStableEndpoints = b[p++];
+ if (numStableEndpoints > ZT_WORLD_MAX_STABLE_ENDPOINTS_PER_ROOT)
+ throw std::invalid_argument("too many stable endpoints in World/Root");
+ for(unsigned int kk=0;kk<numStableEndpoints;++kk) {
+ r.stableEndpoints.push_back(InetAddress());
+ p += r.stableEndpoints.back().deserialize(b,p);
+ }
+ }
+
+ return (p - startAt);
+ }
+
+ inline bool operator==(const World &w) const throw() { return ((_id == w._id)&&(_ts == w._ts)&&(_updateSigningKey == w._updateSigningKey)&&(_signature == w._signature)&&(_roots == w._roots)); }
+ inline bool operator!=(const World &w) const throw() { return (!(*this == w)); }
+
+protected:
+ uint64_t _id;
+ uint64_t _ts;
+ C25519::Public _updateSigningKey;
+ C25519::Signature _signature;
+ std::vector<Root> _roots;
+};
+
+} // namespace ZeroTier
+
+#endif